#Policy chains

Single policies handle single decisions. Chains turn the engine into a decision pipeline: each step's outcome flows into the next step's inputs, letting you compose classify → score → decide → generate workflows from individually-versioned policies.

POSThttps://aiengine.velgent.com/api/v1/policies/chain

#Why chain instead of one mega-policy

  • Each step is independently authored, tested, and rolled back.
  • The audit log shows the whole chain — operators can see exactly why the engine arrived at the final outcome.
  • You can A/B test individual steps without touching the others.
  • Different modes compose naturally: classify the input, score the classified result, decide an action from the score, generate the communication that explains the decision.

#Request body

FieldTypeRequiredDefaultDescription
chainarray<ChainStep>YesOrdered list of steps to run. 1–10 entries. Each step picks a policy slug and the mode to invoke it in.
inputsobjectNo{}Initial input bag. Available to every step. Each step also sees a chain array (full history of prior outcomes) and a previous shortcut (last step's outcome only) injected into its inputs automatically.
contextobjectNo{}Side-channel metadata. Same semantic as on the single evaluate call.
halt_on"error" | "never"No"error""error" halts the chain at the first non-ok step (default; halted_at tells you which step). "never" runs every step regardless — useful when later steps can still produce useful output even if earlier ones errored.

ChainStep object:

{
  "policy":  "itsm/incident-classify",
  "mode":    "classify",
  "version": null   // optional — pin a specific version for replay
}

#Chain history available to each step

When a step runs, its inputs bag is the original request inputs plus two automatic fields:

inputs = {
  ...originalInputs,
  "chain":    [
    { "slug": "step-1-policy", "mode": "classify", "outcome": {...} },
    { "slug": "step-2-policy", "mode": "score",    "outcome": {...} }
  ],
  "previous": {...}   // shortcut for the most recent step's outcome
}

Policies reference these in their English text directly. A decide policy might read: "Given the classification from previous.primary_label and the score from chain[1].outcome.score, pick the right routing action."

#Response

{
  "request_id": "uuid",
  "steps": [
    { "policy": "itsm/incident-classify", "version": 1, "mode": "classify",
      "status": "ok", "outcome": {...}, "citations": [], "latency_ms": 1500 },
    { "policy": "itsm/incident-score",    "version": 1, "mode": "score",
      "status": "ok", "outcome": {...}, "citations": [], "latency_ms": 1500 },
    { "policy": "itsm/incident-route",    "version": 1, "mode": "decide",
      "status": "ok", "outcome": {...}, "citations": [], "latency_ms": 1200 }
  ],
  "final":            { ... },         // alias for steps[-1].outcome when chain completed
  "halted_at":        null,            // step index where chain stopped, null when complete
  "latency_ms_total": 4200,
  "aggregate":        { ... }          // see Score aggregation
}

The aggregate block is documented separately in Score aggregation.

#Example: ITSM incident triage chain

curl -X POST https://aiengine.velgent.com/api/v1/policies/chain \
  -H "Authorization: Bearer velgent_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "chain": [
      { "policy": "itsm/incident-classify",  "mode": "classify" },
      { "policy": "itsm/incident-score",     "mode": "score" },
      { "policy": "itsm/incident-route",     "mode": "decide" },
      { "policy": "itsm/customer-comms",     "mode": "generate" }
    ],
    "inputs": {
      "short_description": "Payment service returning 500 errors",
      "description":       "~5% of transactions failing since 10:15am",
      "affected_ci":       "payment-svc-prod-01"
    }
  }'

In one call: classify the incident category, score its impact, decide the routing action, and draft the customer-facing comms — each step reading from the previous step's outcome. Total latency typically 6–8 seconds for a four-step chain.

Chain audit trail

Each chain run writes ONE audit_logs row with operation: "policy_chain" plus one policy_evaluations row per resolved step. All share the same request_id, so a single ID drills into the full chain trace.


Next: Graphs → — when some of your steps are independent and can run in parallel.