Skip to main content

AI Policy Synthesis

Writing a policy JSON by hand is tedious and error-prone. The policy synthesizer lets operators describe the policy in English and returns a structured draft.

Request

curl -X POST https://us-central1.api.nexastudio.io/policies/synthesize \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "For MAD business and first class, 4+ star only, within 15 km, must have 24-hour reception and airport shuttle. No budget chains.",
"context": { "airport": "MAD", "airline": "XX" }
}'

Response

{
"draftUrn": "urn:nexa:policy-draft:abc",
"source": "ai",
"modelVersion": "nexa-policy-synthesizer-v2",
"confidence": 0.92,
"policy": {
"name": "MAD — VIP tiers (AI draft)",
"context": { "airport": "MAD", "airline": "XX" },
"tiers": ["BUSINESS", "FIRST"],
"constraints": {
"minStars": 4,
"maxDistanceKm": 15,
"requiredAmenities": ["24H_RECEPTION", "AIRPORT_SHUTTLE"],
"excludedChains": ["BUDGETCHAIN_PLACEHOLDER"]
},
"mode": "ON_DEMAND",
"autoApproveDemand": false
},
"warnings": [
"Could not resolve 'budget chains' to specific chain IDs — review excludedChains before activating."
]
}

What the synthesizer does (and doesn't)

It does:

  • Map English tier names to Nexa's enum (businessBUSINESS, VIPBUSINESS + FIRST).
  • Infer numeric constraints (4+ starminStars: 4, within 15 kmmaxDistanceKm: 15).
  • Map amenity phrases to the normalized amenity tags.
  • Attach context from the request.
  • Emit warnings for anything ambiguous or not fully resolvable.

It doesn't:

  • Activate the policy. A draft is just a draft.
  • Look up specific hotel chain IDs for exclusion — it flags them in warnings for the operator to resolve.
  • Override explicit operator input. If you pass confidence < threshold, Nexa returns the draft but marks it for review.

Review flow

  1. Operator submits a description → receives a draft.
  2. Ops console renders a diff against the currently-active policy for the same context.
  3. Operator edits fields where warnings exist.
  4. Operator calls POST /policies with the edited payload (or POST /policies/drafts/:urn/promote).
  5. Activation is a separate explicit step — the existing policy stays active until the new one is activated.

How it's powered

The synthesizer is a Nexa Trained Model on Google. Strong at structured JSON output, deployed in the regional residency the tenant is pinned to, and metered as part of the platform subscription — there is no third-party LLM API for the customer to provision.

Prompt structure

Internally the synthesizer is split into:

  • System — policy schema, valid enums (tiers, amenities, payment methods), and strict output rules (JSON only, no prose).
  • Tools — a single emitPolicy tool with the policy JSON schema; the model is forced to call it.
  • User — the operator's description + optional context.

The schema part is large and static → it caches across requests, keeping latency and cost low.

Confidence scoring

Confidence comes from two signals:

  1. Schema match rate — did the model produce a draft that validates cleanly against the policy schema?
  2. Warning count — per-warning penalty on the confidence score.

Below 0.7, Nexa returns the draft but sets requiresReview: true and disables any one-click "promote" actions.

Cost

Synthesis is part of the platform subscription. There is no per-token bill from the customer's side — call it as often as your operators need.

Audit

Every synthesis call writes an audit entry:

  • Operator URN
  • Input description (verbatim)
  • Model version + prompt hash
  • Generated draft URN
  • Confidence + warnings

If an operator promotes the draft without editing, audit ties the promotion back to the originating synthesis call.

Was this helpful?