Structured decision entries (v1alpha2)

decision.aiwg.io/v1alpha2 permits portable JSON semantic entries in a definition's spec.question, choice option description, ordinal levels, and truth…

Structured decision entries (v1alpha2)

`decision.aiwg.io/v1alpha2` permits portable JSON semantic entries in a definition's `spec.question`, choice option `description`, ordinal `levels`, and truth `trueDescription` / `falseDescription`. The instruction (`question`) must be a nonempty string, object, or array. Criteria may also be `null`. Nested leaves may be JSON strings, finite numbers, booleans, or nulls. Object field names are stable authored names; object insertion order does not affect artifact pins. Arrays retain order. Entry values are passed as JSON values to Jev instructions/criteria and to the tool-free subagent prompt. They are never merged into the transport envelope or used as state, model, artifact pins, credentials, endpoint, acceptance policy, or egress controls.

A definition with any new structured value must have `apiVersion: decision.aiwg.io/v1alpha2`. v1alpha1 continues to accept only its original string fields. The explicit TypeScript converter `convertDecisionDefinitionV1Alpha1` preserves those strings, changes only the API version, and reports old/new digests. Consumers must update ruleset pins when adopting the new definition. There is no implicit upgrade or downgrade. In rollback, keep v1alpha2 artifacts and receipts read-only; use a prior runtime only for previously pinned v1alpha1 work. Never rewrite v1alpha2 data under a v1alpha1 label.

Admission checks run before canonicalization, digesting, or adapter work. Default limits are 256 KiB serialized bytes, depth 32, 4096 total object properties, 4096 array elements per array, 65536 UTF-16 code units per string, 8192 total entries, 1000 ms admission/canonicalization time, and a 4 MiB estimated in-memory representation budget. The memory budget is an explicit admission estimate, not an operating-system RSS guarantee. JSON source parsing rejects duplicate keys; YAML parsing also rejects aliases, duplicate keys, and non-string mapping keys. Cycles, non-JSON values, symbols, accessors, custom prototypes, sparse arrays, unsafe prototype keys, and nonfinite numbers are rejected. Rejections expose reason codes and counts, not source contents. `parseCompressedDecisionJson` bounds both compressed and decompressed bytes before JSON admission. A backend must advertise `structured-entries` for v1alpha2 definitions and return unsupported capability if it cannot preserve the value.

This representation does not move exact computation, policy enforcement, or semantic correctness into a model. Arithmetic, dates, counting, access control, and downstream action authorization remain deterministic code and policy responsibilities. Structured entries provide a representation option; they carry no claim of improved decision accuracy.

Cross-issue version ownership

Contract additionField(s)Required writer versionReader and rollback behavior
D02 structured instruction or criteriondefinition `spec.question`, option `description`, `levels`, `trueDescription` / `falseDescription` as JSON valuesv1alpha2v1alpha1 strings remain readable; v1alpha2 stays read-only under rollback
D04 native batch provenanceresult `spec.attempts[].batch`v1alpha2Reader must preserve batch grouping; never emit it as v1alpha1
D05 admission evidenceresult `spec.attempts[].admission`v1alpha2Reader must preserve admission decisions; never emit them as v1alpha1
D06 context evidenceDecisionResult `spec.context`, RulesetResult `spec.context` and `spec.contextFailure`v1alpha2Reader must preserve plan and usage provenance; never emit it as v1alpha1
D07 native batch receipt referencesresult `spec.batchResult`v1alpha2Reader must preserve batch provenance; never emit it as v1alpha1
D08 acceptance or uncertainty fieldsbinding `primitive-policy` acceptance, result `spec.acceptance`, `uncertainty.calibratedRisk`v1alpha2Reader must preserve new field semantics; no v1alpha1 reinterpretation
D09 calibration pinsresult `spec.calibrationCompatibility`v1alpha2Reader must preserve pin identity; no in-place rewrite
D10 trust projectionsnone in the result schemas yetv1alpha2Reader must preserve projection provenance; no v1alpha1 egress bypass
D15 result-cache caller receiptRulesetResult `spec.cache`v1alpha2Reader must preserve the caller receipt and treat historical attempts as source evidence; never emit it as v1alpha1
D10 projection opt-outRulesetResult `spec.projection`v1alpha2Reader must preserve the host opt-out record; never emit it as v1alpha1
D06/D10 incomplete-context downgradeRulesetResult `status: review`, `reason: insufficient-information`, no `outcome`v1alpha2Reader must not treat the missing outcome as an error; v1alpha1 always requires an outcome for `review`
D30 provider-prefix evidenceresult `spec.attempts[].providerPrefix`v1alpha2Reader must preserve cache evidence; never emit it as v1alpha1

The v1alpha1 `DecisionResult` and `RulesetResult` schemas are the released v2026.9.20 shapes. They have `additionalProperties: false` and none of the result fields above, so `validateDecisionDocument` rejects a v1alpha1 result that carries any of them. Only the v1alpha2 result schemas define these fields. A RulesetResult and its nested evaluations always share one API version. No released version wrote these fields under a v1alpha1 label, so no deprecation window applies. Every v1alpha1 result that a released runtime wrote still validates unchanged.

The evaluator writes v1alpha2 results for every field in this table. It never strips evidence to keep a v1alpha1 label, because the reader rows require that provenance to be preserved. A request writes v1alpha2 when any input artifact is v1alpha2, or when it configures calibration compatibility, `batching`, `batchReceipts`, an enabled `scheduler`, `providerPrefix`, `context`, an enabled `resultCache`, the `projection: { mode: 'unprojected-local' }` opt-out, or a projection policy with `incompleteContext`. This holds even when the ruleset, binding, and definitions are all v1alpha1. The version is decided once per invocation, so every nested result and receipt payload of one invocation carries the same label. A request with none of these options and only v1alpha1 inputs still writes v1alpha1.

`assertDecisionResultWriterVersion` is the result writer gate. `decisionResultV1Alpha2Fields` lists the v1alpha2-only fields present in a result. The gate rejects a v1alpha1-labelled result that carries any of them with a `DecisionValidationError` naming the field, and then validates the document against its schema. The evaluator passes every ruleset result through the gate before returning it. `nextReceipt` passes every newly written receipt `result` and per-decision `evaluations` payload through the gate, and the memory and file receipt stores re-derive each transition with it. `assertDecisionWriterVersion(value, semantic)` remains the generic document-level gate for the named changed semantics. `readDecisionDocumentForRollback` permits frozen inspection of v1alpha2 results and refuses to execute them in rollback mode. The runtime registers v1alpha1 and v1alpha2 schemas for all five artifact kinds. The v1alpha2 ruleset and binding schemas differ from v1alpha1 only where a contract addition needs it, for example D08 `primitive-policy` acceptance. Future additions must extend only the v1alpha2 schemas and types, add a row to this table, and add a v1alpha2 fixture plus a v1alpha1 anti-fixture. `agentic/code/addons/decision-engine/examples/result-category-batch.v1alpha2.json` and `agentic/code/addons/decision-engine/examples/ruleset-result-batch.v1alpha2.json` are the fixtures for the D04–D07 and D30 result fields. `test/unit/decision/result-version.test.ts` derives one v1alpha1 anti-fixture per field from them.

Rollback procedure: stop new v1alpha2 writes; retain v1alpha2 definitions, rulesets, bindings, and result receipts byte-for-byte in protected storage; continue read-only validation and inspection through the dual reader; resume v1alpha1 work only from original v1alpha1 pins and a new invocation ID. No converter rewrites a pinned artifact in place. Any future D07–D10 downgrade must fail explicitly if its field is present, because the v1alpha1 schemas have no representation for it.