Decision-Record Schema: A Field-by-Field Template
Most teams that set out to log AI-agent or advisor decisions start by storing the outcome — what was recommended, maybe a timestamp. That shape answers 'what happened' and stops there; it can't answer 'why,' 'what else was considered,' or 'which rule permitted it,' because those fields were never designed into the record in the first place. This template ships a canonical, field-by-field JSON Schema for a decision record built to answer all four — the same structural shape DecisionSynth's own decision episodes use, adoptable directly for a team designing its own decision-logging schema from scratch.
What you walk away with
~20 min · 3 slots · 12 blocks- A canonical JSON Schema for a decision-record event log, ready to adapt into the team's own data pipeline.
- Field-level annotations explaining what each field is for and why it exists as its own field rather than free text.
- An optional evaluation-task record shape, for teams who also want to build known-answer test cases on top of their own decision log.
- A cross-walk to the Decision-Shaped Test Case Design Worksheet and the Agent-Memory Vendor Evaluation Checklist.
Variables
What kind of decisions this schema will log.
Live document preview
Decision-Record Schema — [TEAM_OR_PRODUCT_NAME]
Schema version: 1.0.0 · Domain: [DECISION_DOMAIN]
This schema documents the canonical shape for a decision record. Every decision [TEAM_OR_PRODUCT_NAME] makes — by an AI agent, a human advisor, or a hybrid workflow — should produce one record matching this schema, with the optional QA task record generated alongside it for teams building their own evaluation harness on top.
Every field below maps to a real question an examiner, a client, or a memory-evaluation task would ask after the fact — 'what was decided,' 'why,' 'what else was considered,' 'which rule governed it.' A schema that omits one of these fields can't answer the matching question later, no matter how well the underlying decision was made.
1. Decision episode record
json{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://[TEAM_OR_PRODUCT_NAME]/schemas/decision-episode/v1.0.0.json", "title": "Decision episode — [DECISION_DOMAIN]", "type": "object", "required": [ "episode_id", "schema_version", "subject_ref", "decision_timestamp", "decision_type", "trigger", "governing_rule_refs", "procedural_path", "resolution" ], "properties": { "episode_id": { "type": "string", "description": "Stable, unique id for this decision record" }, "schema_version": { "type": "string", "const": "1.0.0" }, "subject_ref": { "type": "object", "description": "Who or what this decision was made for (a client, a household, an account)", "required": ["subject_id"], "properties": { "subject_id": { "type": "string" }, "subject_kind": { "type": "string", "description": "e.g. 'household', 'account', 'entity'" } } }, "decision_timestamp": { "type": "string", "format": "date-time" }, "decision_type": { "type": "string", "description": "Firm- or product-defined granular type, e.g. 'retirement_contribution_or_roth_conversion'" }, "trigger": { "type": "object", "description": "What prompted this decision to be made at all", "required": ["trigger_kind", "evidence"], "properties": { "trigger_kind": { "type": "string", "description": "e.g. 'client_life_event', 'scheduled_review', 'threshold_breach'" }, "evidence": { "type": "object", "description": "Pointers into the source record proving the trigger — must be re-derivable from underlying data, not asserted" } } }, "governing_rule_refs": { "type": "array", "minItems": 1, "items": { "type": "string" }, "description": "Specific policy or regulatory figures that governed which options were even on the table — cited by key, not described generically" }, "procedural_path": { "type": "object", "description": "What was recommended, and what else was considered", "required": ["options_considered", "recommended_option"], "properties": { "policy_applied": { "type": "string", "description": "Named policy or decision logic applied" }, "options_considered": { "type": "array", "minItems": 2, "items": { "type": "object", "required": ["option", "permitted"], "properties": { "option": { "type": "string" }, "permitted": { "type": "boolean" }, "blocking_refs": { "type": "array", "items": { "type": "string" }, "description": "Rule keys that ruled this option out, when permitted=false" } } } }, "recommended_option": { "type": "string" } } }, "resolution": { "type": "object", "description": "What was actually decided, and why — structurally captured, not free text", "required": ["followed_recommendation", "outcome", "outcome_status"], "properties": { "followed_recommendation": { "type": "boolean" }, "override_reason": { "type": "string", "description": "Required when followed_recommendation=false — the specific, categorized reason" }, "outcome": { "type": "string" }, "outcome_status": { "type": "string", "enum": ["approved", "denied", "escalated_then_approved", "escalated_then_denied"] }, "supervisory_review": { "type": "object", "properties": { "required": { "type": "boolean" }, "reviewer_id": { "type": ["string", "null"] }, "reviewed_at": { "type": ["string", "null"], "format": "date-time" } } } }, "if": { "properties": { "followed_recommendation": { "const": false } } }, "then": { "required": ["override_reason"] } }, "lineage": { "type": "array", "items": { "type": "string" }, "description": "episode_ids of prior decisions for the same subject that this one's context depends on — enables temporal-ordering and precedent-search retrieval later" } } }
2. Evaluation task record (optional)
This second record is optional. It's the shape a known-answer evaluation task takes when generated alongside a decision record — useful for teams who also want to test whether an agent's memory can retrieve the decisions logged with this schema, not just store them.
json{ "title": "Evaluation task, generated alongside a decision episode", "type": "object", "required": ["task_id", "task_type", "question", "answer_key", "evidence_ids"], "properties": { "task_id": { "type": "string" }, "task_type": { "enum": ["direct_recall", "rationale_lookup", "precedent_search", "temporal_ordering", "rule_attribution"] }, "question": { "type": "string" }, "answer_key": { "type": "object", "description": "Typed ground truth pulled directly from the episode record — never hand-written after the fact" }, "evidence_ids": { "type": "array", "items": { "type": "string" } }, "distractor_ids": { "type": "array", "items": { "type": "string" }, "description": "Plausible-but-wrong episode ids for the same subject — retrieval must discriminate" } } }
3. Adoption checklist
- Persist decision_episode records to an append-only, tamper-evident log — this is the record an examiner or a memory-evaluation harness will query against.
- Populate every field from underlying data (the subject's own record, a cited rule) rather than free narrative — a field that can't be traced to a source is a sign the schema, or the workflow producing it, needs fixing.
- Wire any AI agent that recommends or explains decisions to write a matching record for each one, not just a chat log of the interaction.
- Add a validation step that rejects malformed records at write time — a gate failure should be treated as a bug in the producing system, not something to write around.
- If building an eval harness on top, generate the evaluation task record in the same pass as the decision record, so the answer key is known-by-construction rather than a separate hand-labeling step.
A populated decision-episode record used with real clients contains real subject data by definition — apply the firm's data-classification controls accordingly. Test and development environments should use synthetic subjects, not real ones; a synthetic decision corpus built to this same field shape exists specifically to populate a schema like this one cleanly, with zero PII.
Unfilled slots show as [VARIABLE_NAME] so the partial document still reads. Filling in the form on the left substitutes them inline.
What to do with this
Hand this to engineering as the canonical schema for the team's decision-logging pipeline. Validate every produced record against it in CI. Use it as the reference when auditing whether an AI agent's own memory preserves enough structure to answer a rationale or rule-attribution question later — a record that can't populate these fields can't answer those questions no matter how the agent explains itself.
FAQ
Can we remove fields we don't need?
You can, but each field maps to a specific question ('why,' 'what else was considered,' 'which rule') that a compliance reviewer, a client, or a memory-evaluation task will eventually ask. Removing a field means that question becomes unanswerable from this record later — worth deciding deliberately, not by omission.
Does populating this schema require an LLM?
No — every field can be populated deterministically from underlying source data (the subject's own record, a cited rule) or entered directly by a human decision-maker. That's what makes it usable as ground truth for evaluation tasks later, if a team chooses to build that layer on top.
How does this relate to DecisionSynth's own commercial product?
This is the same field shape DecisionSynth's own synthetic decision episodes use — so this template also documents what's inside a purchased decision pack, useful for a team deciding whether to adopt this schema for its own real decisions, purchase a ready-made synthetic corpus in this shape for testing, or both.
What if our decisions don't fit neatly into 'options considered' with a permitted flag?
The options_considered array is deliberately generic — for a decision type with only one real option, it's a one-item array; the permitted flag and blocking_refs only need populating when something was ruled out by a specific rule. Adapt the cardinality to the decision type rather than forcing every decision through the same shape.