Outcome Spec
Status
Canonical spec. Version 0.3. Related artifacts: Synedrix OS - Agent Spec, Synedrix OS Workflow Contract Spec, Synedrix OS Event Taxonomy Standard, Synedrix OS - Agent DB Schema.
Purpose
Defines the canonical outcome envelope — the standard structured JSON type returned by every agent invocation and every workflow execution in Synedrix OS.
Without a shared outcome shape, each domain pack invents its own output structure. Agents that feed downstream agents cannot rely on a consistent contract. Observability and governance layers cannot reason generically about success, failure, confidence, or escalation across different domain packs.
The outcome envelope is intentionally shallow at the top level and extensible in the result field. Every consumer of an outcome — the orchestration layer, the Policy Guard Agent, the Audit and Lineage Agent, the Observability layer — can read status, source, correlation_id, and policy without knowing anything about the domain-specific result payload.
Design principles
- One envelope for agents and workflows. The same shape is returned whether the source is an agent invocation or a workflow execution. The
source.typefield distinguishes them. resultis domain-typed, not domain-aware. The envelope declares that aresultobject exists and references the schema that validates it. The envelope itself imposes no constraints onresultcontent.- Status is the primary routing signal. Orchestration, governance, and error-handling layers branch on
statuswithout parsingresult. qualityis optional and pattern-aware. Present only when an agent produces a measurable confidence signal or an iterative pattern ran. Never required for deterministic steps.policyis always present when policy was evaluated. The Policy Guard Agent’s decision is part of the outcome record — not a side-channel.- Errors are structured, not strings. Each error carries a machine-readable
code, a human-readablemessage, and arecoverableflag. This enables orchestration-layer retry logic without string parsing. - The outcome envelope is the unit of lineage. Lineage links in Neo4j are written as
source_outcome_id → target_outcome_idwith the relation type. Every agent outcome is append-only inagent_invocation_outcomes; workflow outcomes remain append-only inworkflow_outcomes.
Outcome status values
| Status | Meaning | Agent | Workflow |
|---|---|---|---|
success | Completed normally; result is populated | ✅ | ✅ |
partial | Completed with one or more non-fatal sub-failures; result is populated but may be incomplete; errors is non-empty | ✅ | ✅ |
failure | Failed; result is null; errors is non-empty | ✅ | ✅ |
blocked | Blocked by the Policy Guard Agent before execution; result is null; policy.decision is block | ✅ | ✅ |
escalated | Routed to a higher authority (HITL or escalation path) before execution could complete; escalation sub-object is present | ✅ | ✅ |
timeout | Timed out before producing a result; result is null; errors contains a TIMEOUT code entry | ✅ | ✅ |
skipped | Not executed because a prerequisite condition was not met (e.g., a conditional branch was not taken, a quorum was not reached) | ✅ | ✅ |
Invariant: status: success with a non-empty errors array is invalid. Use partial when execution succeeded but sub-steps had non-fatal errors.
Canonical outcome envelope schema
# Synedrix OS — Canonical Outcome Envelope v1.0
# Returned by every agent invocation and every workflow execution.
outcome_id: string # UUID v4. Stable, unique, append-only.
outcome_version: "1.0" # Envelope schema version. Increment on breaking changes.
status: # One of: success | partial | failure | blocked | escalated | timeout | skipped
# Required. Primary routing signal for orchestration, governance, and error-handling.
correlation_id: string # Required. Threads this outcome back to the originating business transaction.
# Propagated from the triggering event or workflow invocation.
# Must match the correlation_id in all events emitted during this invocation.
causation_id: string # Required. The outcome_id or event_id that directly caused this invocation.
# Enables causal chain reconstruction in the Audit and Lineage Agent.
source:
type: agent | workflow # Required.
id: string # Required. agent_id (e.g., os-agt-001) or workflow_id (e.g., WF-COM-001-...).
version: string # Required. SemVer of the agent definition or workflow contract at invocation time.
domain: string # Required. Domain pack ID or "synedrix-os" for OS-owned actors.
result: object | null # Domain-specific structured payload.
# Required when status: success or partial; null otherwise.
# Shape is declared in the agent's output_schema or workflow's output_contract.result_schema.
# Must always be structured JSON — never a plain string, number, or array at the top level.
quality: # Optional. Present for agents with a measurable confidence signal
# or when an iterative/reflect-and-revise execution pattern ran.
confidence: number # 0.0–1.0. Agent's self-assessed or evaluator-assessed confidence in result.
critique_notes: string # Critic agent's feedback. Present when reflect-and-revise pattern ran.
iterations_used: integer # Number of iterations executed. Present when iterative or reflect-and-revise ran.
groundedness_score: number # 0.0–1.0. Retrieved-context groundedness. Present when RAG retrieval was used.
evaluator_agent_id: string # agent_id of the critic agent if reflect-and-revise ran with a separate critic.
errors: array # Present when status is failure, partial, timeout, or blocked.
# Empty array when status is success, escalated, or skipped.
- code: string # Machine-readable error code (e.g., VALIDATION_FAILED, TOOL_TIMEOUT, SCHEMA_ERROR).
message: string # Human-readable description of the error.
field: string # Optional. The specific field or step that failed.
source_agent_id: string # Optional. The agent or step that produced this error (useful in fan-out-fan-in).
recoverable: boolean # Whether the orchestration layer should attempt a retry.
retry_after_ms: integer # Optional. Suggested delay before retry if recoverable: true.
escalation: # Present when status: escalated.
reason: string # Why execution was escalated (e.g., "confidence below threshold", "policy conflict").
escalation_target: string # agent_id of the escalation target (e.g., os-agt-004 for HITL Gateway Agent).
escalation_path_id: string # The escalation_path declared in the agent's authority profile.
policy_rule_triggered: string # Optional. The policy rule that triggered escalation.
hitl_request_id: string # Optional. The HITL approval request ID if escalation is to os-agt-004.
policy: # Present when the Policy Guard Agent (os-agt-002) evaluated this invocation.
# Absent when governance_class: autonomous and no policy gate was executed.
decision: allow | block | escalate # The Policy Guard's binding decision.
policy_rule_triggered: string # The specific rule that drove the decision.
risk_score: number # 0.0–1.0. Risk score assigned by the Policy Guard.
requires_hitl: boolean # Whether the decision requires human-in-the-loop confirmation.
evaluated_at: string # ISO 8601 timestamp of the policy evaluation.
timing:
started_at: string # Required. ISO 8601 UTC timestamp when execution began.
completed_at: string # Required. ISO 8601 UTC timestamp when execution ended (or timed out).
duration_ms: integer # Required. Wall-clock duration in milliseconds.
execution_context: # Optional. Present for workflow outcomes; absent for agent outcomes.
execution_pattern: string # The execution_pattern.primary declared in the workflow contract.
quorum_achieved: string # e.g., "5-of-7". Present when execution_pattern: consensus.
branches_taken: array # Present when execution_pattern: conditional.
sub_workflow_outcomes: array # Present when execution_pattern: hierarchical.
# Array of outcome_ids from child workflow executions.
parallel_task_count: integer # Present when execution_pattern: parallel or fan-out-fan-in.
partial_failure_count: integer # Number of sub-tasks that failed. Present when status: partial.Agent outcome vs. workflow outcome
The same envelope schema applies to both. The differences are in which sub-objects are populated and what result contains.
Agent outcome
source.type: agentresultmatches the agent’scontracts.output_schemaquality.confidenceis populated if the agent declares aconfidence_schemaquality.critique_notesandquality.iterations_usedare populated if the agent ran under areflect-and-reviseexecution patternexecution_contextis absent- Written to
agent_invocation_outcomes(append-only) in Supabase after the invocation’s start row and tool-call records
{
"outcome_id": "a1b2c3d4-...",
"outcome_version": "1.0",
"status": "success",
"correlation_id": "corr-xyz",
"causation_id": "event-abc",
"source": {
"type": "agent",
"id": "os-agt-002",
"version": "1.0.0",
"domain": "synedrix-os"
},
"result": {
"decision": "allow",
"policy_rule_triggered": null,
"risk_score": 0.12
},
"quality": null,
"errors": [],
"escalation": null,
"policy": null,
"timing": {
"started_at": "2026-05-20T10:00:00.000Z",
"completed_at": "2026-05-20T10:00:00.042Z",
"duration_ms": 42
},
"execution_context": null
}Workflow outcome
source.type: workflowresultmatches the workflow contract’soutput_contract.result_schemaqualityis absent unless the workflow is areflect-and-revisepattern and its result carries a quality signalexecution_contextis present and populated with pattern-specific fields- Written to
workflow_outcomes(append-only) in Supabase - Lineage links are written: each agent invocation
outcome_id→ workflowoutcome_idwith relationcontributed-to
{
"outcome_id": "w9x8y7z6-...",
"outcome_version": "1.0",
"status": "partial",
"correlation_id": "corr-xyz",
"causation_id": "event-def",
"source": {
"type": "workflow",
"id": "WF-ART-003-EDITION-ALLOCATION",
"version": "1.1.0",
"domain": "art"
},
"result": {
"allocated_editions": 45,
"skipped_editions": 5,
"allocation_report_id": "rep-001"
},
"quality": null,
"errors": [
{
"code": "PARTIAL_ALLOCATION_FAILURE",
"message": "5 editions could not be allocated due to inventory lock",
"field": "edition_ids[45:50]",
"source_agent_id": "art-agt-003",
"recoverable": true,
"retry_after_ms": 5000
}
],
"escalation": null,
"policy": {
"decision": "allow",
"policy_rule_triggered": null,
"risk_score": 0.08,
"requires_hitl": false,
"evaluated_at": "2026-05-20T10:00:00.100Z"
},
"timing": {
"started_at": "2026-05-20T10:00:00.000Z",
"completed_at": "2026-05-20T10:00:01.850Z",
"duration_ms": 1850
},
"execution_context": {
"execution_pattern": "fan-out-fan-in",
"parallel_task_count": 10,
"partial_failure_count": 5,
"sub_workflow_outcomes": null
}
}Alignment with agent spec contracts
The agent spec (Synedrix OS - Agent Spec) declares contracts with four fields:
contracts:
accepted_inputs_schema: # unchanged — the input side
context_requirements_schema: # unchanged
output_schema: # now declares the shape of outcome.result (not the full outcome)
confidence_schema: # now declares the shape of outcome.quality.confidence (not a top-level field)
emitted_events: # unchanged — events emitted alongside (not part of) the outcome
side_effect_declarations: # unchangedThe outcome envelope wraps the agent’s declared output. contracts.output_schema specifies what goes in outcome.result. contracts.confidence_schema specifies what goes in outcome.quality.confidence. The full outcome envelope is always the same shape regardless of domain.
Alignment with workflow contract fields
The workflow contract spec (Synedrix OS - Workflow Contract Spec) declares an output_contract field. That field should now reference the outcome envelope and declare the result_schema:
output_contract:
result_schema: # Shape of outcome.result for this workflow. Required.
emitted_events: # Events emitted by the workflow alongside the outcome. Required.
outcome_status_on_success: # Expected status value on the normal path: success | partial. Default: success.
partial_failure_conditions: # Conditions under which status: partial is emitted rather than failure.The output_contract field does not redeclare status, errors, timing, policy, or escalation — these are governed by the outcome envelope spec, not by individual workflow contracts.
Persistence rules
| Outcome source | Written to | Key constraint |
|---|---|---|
| Agent invocation start | agent_invocations table (Supabase) | Inserted before execution with immutable identity and start-time fields. |
| Agent terminal outcome | agent_invocation_outcomes table (Supabase) | Exactly one append-only row per invocation; never updated after INSERT. The complete envelope is stored in outcome_envelope, and outcome_id is unique across tenants. |
| Workflow execution | workflow_outcomes table (Supabase) | Append-only. Never updated after INSERT. |
| Lineage | agent_lineage_links (Supabase → Neo4j) | Each outcome_id is a node; relation types: invoked, contributed-to, escalated-to, governed-by. |
workflow_outcomes DDL (normative)
outcome_id MUST be minted via the same server-side minting pattern as agent_invocation_outcomes (Agent DB Schema), including single-claim across both outcome tables. The table is append-only: tenant roles may INSERT only; UPDATE/DELETE denied except retention role under policy.
The outcome_id is the durable identity for lineage. The Audit and Lineage Agent (os-agt-008) queries by outcome_id, correlation_id, and causation_id to reconstruct causal chains.
Observability integration
Every outcome emits a corresponding OS event (conforming to the event envelope in Event Taxonomy Standard):
| Outcome status | Emitted event type |
|---|---|
success | os.outcome.succeeded |
partial | os.outcome.partial |
failure | os.outcome.failed |
blocked | os.outcome.blocked |
escalated | os.outcome.escalated |
timeout | os.outcome.timeout |
skipped | os.outcome.skipped |
The event payload carries the outcome_id, source, correlation_id, status, and duration_ms — not the full result. The Observability layer (Langfuse, PostHog, Grafana) reads these events; the full outcome record is in Supabase.
Invariants
- Every agent invocation and every workflow execution that reaches a terminal state must produce exactly one outcome. An invocation start row exists before execution; if the process is lost, recovery writes one
timeoutoutcome after the configured deadline. agent_invocation_outcomeshas at most one row per(tenant_id, invocation_id).outcome_idis minted with that terminal row, not at invocation start.outcome_idis globally unique and immutable.correlation_idmust be set on every outcome. A missing correlation ID is a lineage gap and a compliance breach.status: successwith a non-emptyerrorsarray is invalid.resultmust be null whenstatusisfailure,blocked,timeout, orskipped.policymust be present whenever the Policy Guard Agent evaluated the invocation.escalationmust be present wheneverstatus: escalated.- The Audit and Lineage Agent (os-agt-008) must never produce an outcome that modifies any other outcome record.
Versioning
- Version: 0.3
- Supersedes: v0.2
Related Documents
Canonical Reference
- Synedrix OS - Consolidated Canonical Reference — Consolidated synthesis.
Agent and Workflow
- Synedrix OS - Agent Spec — Agent contracts;
output_schemaandconfidence_schemadeclare the shape ofoutcome.resultandoutcome.quality.confidence. - Synedrix OS Workflow Contract Spec — Workflow contracts;
output_contract.result_schemadeclares the shape ofoutcome.resultfor workflows.
Governance and Observability
- Synedrix OS Event Taxonomy Standard — Every outcome emits a corresponding
os.outcome.*event conforming to the shared event envelope. - Synedrix OS - Agent DB Schema — Owning inventory mirror for
workflow_outcomes; alsoagent_invocations(immutable starts) andagent_invocation_outcomes(terminal envelopes). - Synedrix OS Observability Metrics Spec — Outcome status, quality scores, and duration_ms feed the canonical observability metric families.
- Synedrix OS - Agent Runtime Policy Spec — Runtime limits (latency_budget_ms, token_budget) govern when
timeoutoutcomes are produced.
Synedrix OS · May 2026