temporality
Изменить страницу↗
Инженерные документы

Side-effect and event reconciliation (Phase 2 audit)

#Current guarantee

The Kernel persists event intent to kernel_event_outbox before the workflow advances past each ActivityRecordEvent. Outbox rows are unique by (source_id,event_id). The publisher retries Temporality delivery, accepts accepted and repeated, and marks rows delivered only after acknowledgement. Temporality's idempotency key makes same-payload redelivery a semantic no-op; a different payload under the same key is a conflict. This is at-least-once publication with idempotent ingestion, not exactly-once transport.

For a tool side effect, tool.started is committed to the local outbox before ActivityRunTool is scheduled. The workflow configures one attempt for that activity. On a normal returned error it records tool.failed and, for MCP, marks the outcome uncertain. A successful Activity result is held in Temporal history; then tool.completed is enqueued.

#Unresolved crash window

A worker can lose contact after a remote effect commits but before Temporal records the Activity completion. The tool may have executed even though the Activity is retried/timed out and no tool.completed event exists. The outbox can prove intent, not the remote outcome. MCP currently has no generic idempotency/read-after-write contract, and ToolRequest.OperationID is not passed as a standardized idempotency key to every MCP server. Docker command effects are confined to the mounted workspace but are not transactionally rolled back.

Therefore the current policy is: do not automatically retry a consequential operation; preserve tool.started plus failed/uncertain status when observable; require operator reconciliation before repeating. This is not yet a complete reconciliation mechanism: nothing queries the downstream service automatically. The supervisor wall pass does close piles of unverifiable operations on its own — it records best-effort operation.reconciled effect verdicts for every operation in a run's wall and re-triages the run whenever new uncertain operations appear — but those verdicts are the model's most plausible inference, not a read-after-write probe.

#Failure matrix

Boundary Durable before next step Failure interpretation Recovery available
Event record → Kernel PostgreSQL Outbox row No row means workflow cannot safely proceed past that event activity Temporal activity retries up to its configured attempts
PostgreSQL → Temporality Outbox row Projection may lag while local event intent remains Publisher retries; same event ID is idempotent
Before tool Activity tool.started outbox row Intent exists; effect may not have started Inspect Temporal Activity state
During remote MCP effect tool.started; possibly no result Outcome can be uncertain Operator reconciles over operation.reconciled
During sandbox command tool.started; command may have modified workspace Partial workspace effect is possible Inspect workspace, rerun validation, then record a new operation
After Activity completion, before tool.completed enqueue Temporal Activity result Effect/result may exist without semantic completion event Listing surfaces it; operator reconciles

#Implemented (2026-09-25)

The remaining-work list below is now implemented; the design decision along the way was that the ledger is a projection, not a table: the event stream stays the single source of truth, and operation state is derived from tool.* events plus Temporal liveness on demand.

Live drill (2026-09-25, compose stack): a run with KERNEL_FAULT_AFTER_EFFECT=run_command wrote drill-proof.txt in the workspace, recorded tool.failed(effect=uncertain), retried the command under a new operation id (success), and completed. The operator then verified the file, recorded operation.reconciled(effect=occurred) with the workspace file as evidence, and the listing cleared.

#Phase 2 remaining work

The mechanism above is implemented; what remains open on this front: automated downstream read-after-write probes (the supervisor's verdicts are inferences, not probes). Do not call this exactly-once. Do not infer successful execution from an agent-authored final answer.