Canonical execution trace and outcome ontology¶
Runtime provenance has one durable shape:
agent_utilities.observability.trace_ontology is the schema authority. Agent execution, workflow
execution, workspace provenance, evaluation, failure mining, placement mining, context compilation,
variant fitness, and skill synthesis consume this same shape. Episode remains a domain-memory type;
it is not an alternate execution-trace schema.
Pydantic Graph execution evidence¶
Runs through the native Pydantic Graph execution paths attach a versioned
GraphExecutionEvidence record to the GraphResponse and persist the same
record on RunTrace. It includes the deterministic topology and
topology/version digests, installed pydantic-graph version, every ordered
scheduler task batch, the flattened node sequence, and checkpoint identifiers
actually returned by the configured checkpoint backend. Parallel task IDs stay
grouped in the transition that scheduled them instead of being flattened into
a fictional serial path.
The transition sequence is scheduler evidence: it proves which tasks were
scheduled and in what batches, but does not by itself claim every task
completed. graph_resume_supported is currently always false. The recorded
Pydantic Graph v2 snapshots are observational mementos and are not accepted as
executable resume tokens. Consumers must not infer resumability from the
presence of graph_checkpoint_ids.
The graph execution span and root agent.run span carry the same identity
digests and node sequence. They also emit one pydantic_graph.transition event
per scheduler batch and one pydantic_graph.checkpoint event per confirmed
checkpoint, so a durable trace and its live OpenTelemetry trace can be
correlated without synthesizing events. Public GraphOS delegation retains the
typed record through the rich run_agent/execute_capability envelope and the
graph_orchestrate MCP response; callers using the default bare-string
contract are unchanged. graph_jobs action=status reads the same durable
fields back from RunTrace and returns graph_transition_sequence as a
structured list.
Identity and privacy¶
Run identifiers are converted to stable opaque references before persistence. Durable traces store
attribution_ref, actor_ref, tenant_ref, correlation_ref, skill_ref, and server_ref; they do
not store the source identity strings. Task, argument, result, error, and feedback text is
metadata-only: durable rows contain keyed opaque references, character counts, and a redaction report,
never the free text itself. Workspace action identifiers also derive from the opaque trace reference,
so a run id, user name, or machine path is not copied into node ids.
Call trace_id(run_id) whenever code needs the durable node id. Do not construct trace:<run_id> or
toolcall:<run_id>:<sequence> directly.
Ordered incremental consumption¶
Every trace, tool call, and outcome has an integer event_sequence/event_cursor. Incremental
consumers use TraceCursor and resume with event_sequence > after_sequence. Each consumer's
greatest fully completed sequence is stored as a TraceConsumerCursor node through
load_trace_cursor/save_trace_cursor; the consumer key is an opaque reference, and no cursor is
written to a local file. Each advancement appends an immutable, sequence-addressed checkpoint and
updates a compatibility head. Readers select the greatest checkpoint, so concurrent hosts cannot
regress the durable cursor even if their mutable-head updates race. Timestamps and opaque
identifiers are display/identity values, never lexical ordering cursors.
Bounded queries conservatively drop the final trace whenever a page fills, because its tool-call rows may be incomplete. The next pass re-reads that trace. A miner advances its graph-resident cursor only after mining, proposal persistence, validation, and policy routing complete without an error; failed batches replay safely.
Outcomes¶
Every runtime writer attaches one stable OutcomeEvaluation id to its RunTrace. The normalized
outcome carries status, bounded reward, success, criteria, feedback digest, and the same event
sequence as its trace. Evaluation and analytics read this edge rather than inferring success from a
different node family.
Querying a run¶
Use graph_jobs action=status with the public run handle. It resolves the opaque trace id and returns
the trace plus ordered tool calls. For direct graph traversal, use the returned trace_id:
MATCH (r:RunTrace {id: $trace_id})-[:USED_TOOL]->(t:ToolCall)
RETURN t.tool_name, t.status, t.sequence
ORDER BY t.sequence
Miners persist only the greatest completed numeric cursor. A failed batch therefore retries without skipping traces, while a successful batch advances deterministically across process restarts.