Status: Phase 0 contract, Phase 1 Runtime-to-Task lineage, Phase 2A-2C evidence freshness and Compaction coverage, and Phase 3A TaskRun inspection. See issue #948.
Maka already records the facts needed to explain an execution. Runtime Events preserve model and tool interaction facts, AgentRun records operational lifecycle, and Task Events preserve durable task-control decisions. The missing piece is a shared way to reference those facts across subsystem boundaries.
The Execution Identity and Evidence Spine is that reference protocol. It answers:
Which execution, source-log prefix, workspace revision, and target snapshot support this projection or evidence claim?
It is deliberately not a new event log, trace backend, or source of truth.
Phase 0 added a versioned shared contract in @maka/core/execution-evidence, runtime validation, cursor comparison rules, and this ownership audit. At that boundary it did not:
Defining the contract first prevents each integration from inventing a different meaning for identity, coverage, or freshness.
Phase 1 makes the Runtime-to-Task portion concrete:
invocationId while legacy headers remain readable;task_attempt_execution_linked Task Event;TaskRunProjection.executionLineage and each TaskAttempt.executionLineage expose the replayed links;ResultRecord imports produce an honest identity-only link when Runtime coverage is unavailable.Phase 2A binds compact heavy-task evidence back to executor-owned Runtime facts:
toolCallId to immutable Runtime function_call and function_response rows;heavy_task_evidence_provenance_linked Task Event stores only the resulting ExecutionEvidenceRef and inclusive Runtime range;System-created artifacts, external verifier artifacts, and replay-derived Self-check envelopes keep their existing authority records. Phase 2A does not invent a Runtime source for facts that were not durably recorded from a Runtime tool call.
Phase 2B makes accepted heavy-task Self-check freshness replay-derived:
current, stale, or backward-compatible unknown freshness;Phase 2C binds each newly written Compaction checkpoint to the exact ordered Runtime Event projection it summarizes:
maka.compactable_runtime_event_projection.v1 names the session-scoped ordering and filtering policy;Phase 3A makes the TaskRun lineage directly inspectable:
maka eval task-run inspect <taskRunId> --store <root> renders a human-readable TaskRun → Attempt → AgentRun tree;--json emits the versioned maka.task_run_inspect.v1 machine contract from the same read model;The current delivery still does not add AHE lineage, durable recovery modeling for ambiguous external side effects, or the general maka inspect <sessionId|agentRunId|taskRunId> resolver.
The spine references existing authorities instead of copying their facts.
| Authority | Identity today | Owns | Does not own |
|---|---|---|---|
RuntimeEvent | sessionId, invocationId, runId, turnId, id | Canonical model, tool, runtime-content, and terminal interaction facts | Task scheduling or task-level decisions |
AgentRunHeader and AgentRunEvent | sessionId, optional legacy-compatible invocationId, runId, turnId, event id | Operational run lifecycle, status, model resolution, permission, usage, and run-local checkpoints | A second copy of raw Runtime interaction history |
SessionEvent and stored messages | Session and turn-oriented identifiers | Compatibility and UI/session read models | Canonical Runtime history |
TaskEvent | taskRunId, optional event-specific attemptId, event id | Task lifecycle, attempts, policy decisions, evidence envelopes, permissions, and recovery-visible task state | Raw model messages, Tool Calls, or Tool Results already owned by Runtime Events |
TaskRunProjection | Fold of one taskRunId event stream | Current task read model derived from Task Events | Independent facts outside its source Task Events |
| Compaction checkpoints and blocks | Checkpoint/block ids, policy-specific highWaterName and highWaterSeq, explicit Runtime Event ids | Lossy context projections and the source set required to validate those projections | Replacement of canonical Runtime Events or a universal log cursor |
| Self-check records | Task and check-specific identifiers | Bounded completion claims and supporting task evidence | Executor-owned command, output, artifact, or workspace facts |
| AHE exports | Target snapshot and exported trajectory references | A derived evaluation/evolution evidence package | Authority over the Runtime or Task facts it exports |
This gives Maka two principal append-only evidence lanes:
Runtime Event ledger Task Event ledger session / invocation / AgentRun / turn TaskRun / attempt | | +------------- evidence ref ---------------+ | workspace + target snapshot
Task Events may reference a Runtime trajectory. They must not reproduce it. Projections may summarize either ledger, but their trust comes from source coverage that can be checked against the owning ledger.
ExecutionEvidenceRef separates Runtime and Task identity lanes so similarly named runs cannot be confused:
interface ExecutionEvidenceRef { schemaVersion: 'maka.execution_evidence_ref.v1'; execution?: { sessionId: string; invocationId?: string; agentRunId?: string; turnId?: string; }; task?: { taskRunId: string; attemptId?: string; }; runtimeCoverage?: ExecutionLogCoverage; taskCoverage?: ExecutionLogCoverage; workspace?: WorkspaceRevisionRef; target?: TargetSnapshotRef; }
execution.agentRunId maps to the existing AgentRunHeader.runId and RuntimeEvent.runId. The longer cross-ledger name is intentional: agentRunId and taskRunId describe different lifecycles.
The Runtime hierarchy remains:
sessionId > invocationId > agentRunId > turnId
invocationId is the existing durable Runtime spine. agentRunId identifies a concrete execution attempt recorded by AgentRun. Current production paths may assign the same value to both; consumers must not rely on that implementation coincidence.
Only sessionId is required inside an execution identity, and only taskRunId is required inside a task identity. At least one lane must be present. Optional descendants let readers represent legacy or partial knowledge honestly instead of fabricating identifiers.
An ordered cursor has three required coordinates:
interface ExecutionLogCursor { ledger: 'runtime_event' | 'runtime_event_projection' | 'task_event'; streamId: string; sequence: number; eventId?: string; }
The semantics are strict:
sequence is the zero-based append ordinal within one (ledger, streamId) pair.sequence determines order.eventId is an optional audit, lookup, and deduplication pointer. It must never determine order.The planned stream bindings are:
| Ledger | streamId |
|---|---|
runtime_event | execution.agentRunId |
runtime_event_projection | session id, interpreted only with its adjacent projection policy version |
task_event | task.taskRunId |
Canonical Runtime and Task cursors use physical append ordinals. A runtime_event_projection cursor is intentionally different: it is an ordinal in a named, versioned projection whose owner must publish the ordering and filtering policy beside the cursor. Cursors from that projection are therefore incomparable with canonical runtime_event cursors even when their boundary eventId values happen to match. Existing Runtime Event ids remain audit pointers, not ordering fields, and Compaction's legacy highWaterSeq remains a checkpoint-local value rather than a source-log cursor.
For Phase 1 headless lineage, the persisted AgentRun Runtime Event JSONL is the ordered stream. Mutable partial snapshot files are excluded, while every physical JSONL row—including a lifecycle row that may carry partial: true—retains its append position. Those immutable positions are materialized as zero-based cursor sequences. A completed invocation therefore records coverage such as:
TaskRun task-42 / Attempt attempt-2 -> AgentRun run-a: Runtime Events [0..146] -> AgentRun run-b: Runtime Events [0..38] # bounded repair run
The Task Event stores only these references and boundary event ids. Model messages, Tool Calls, Tool Results, and other Runtime facts remain solely in the Runtime Event ledger.
Phase 2A applies the same rule at evidence granularity. A compact Task evidence envelope may display a bounded summary, but its provenance points to the immutable Runtime call/result range that owns the exact request and response. Maka requires the canonical function_response before creating that link; a planned or interrupted call alone is not proof of an executor result.
Phase 2C applies the cursor contract without falsely describing the Compaction input as one AgentRun append log. Compaction operates on the session/model-context Runtime Event projection, so its checkpoint carries runtime_event_projection cursors plus maka.compactable_runtime_event_projection.v1. The policy fixes the projection's ordering/filtering semantics; the boundary ids and source digest then fail closed if replay no longer presents the exact covered prefix. Events after the high-water cursor are returned as explicit successor facts and remain raw in provider-visible context.
Coverage is an inclusive range within one stream:
interface ExecutionLogCoverage { lowWater?: ExecutionLogCursor; highWater: ExecutionLogCursor; eventCount?: number; }
lowWater may be omitted when only a prefix high water is known. eventCount counts observed rows and therefore need not equal the ordinal span when gaps are represented.
const evidence = { schemaVersion: 'maka.execution_evidence_ref.v1', execution: { sessionId: 'session-7', invocationId: 'invocation-12', agentRunId: 'run-12', turnId: 'turn-3', }, task: { taskRunId: 'task-42', attemptId: 'attempt-2', }, runtimeCoverage: { lowWater: { ledger: 'runtime_event', streamId: 'run-12', sequence: 100, eventId: 'runtime-event-100', }, highWater: { ledger: 'runtime_event', streamId: 'run-12', sequence: 246, eventId: 'runtime-event-246', }, eventCount: 147, }, workspace: { kind: 'workspace_snapshot', ref: 'workspace-19', dirty: true, }, target: { snapshotId: 'maka-ahe-abc123', sourceLabel: 'git:abc123', }, } as const;
This object says where evidence came from. It does not assert that the evidence is correct, current, or complete. Those judgments require reading the referenced facts and comparing their source high waters with current ledger and workspace state.
schemaVersion.AHE target v2 exports now carry the shared evidence spine through maka.ahe.execution_lineage.v1. Every current run-result row names its taskRunId and a digest-bound lineage document. That document binds target, Task coverage, Attempts, AgentRuns, and Runtime coverage without copying Runtime facts into Task Events. Payload-safe AgentRun inspection is exported by default; canonical raw Runtime Events remain opt-in. Missing identities, coverage, or source artifacts remain explicit gaps.
Later phases should extend the contract without changing fact ownership:
The guiding invariant is simple:
The evidence spine points to facts. It never becomes another place where those facts are rewritten.