Orchestrator-verified completion and A2A#

The trust model#

A step is not done because a worker says so, and especially not because the worker’s process terminated — termination may be a crash. A worker submits evidence of completion (what it ran, exit codes, output, diff). Only the orchestrator (internal/orch.VerifyAndComplete) transitions a task to a terminal done state, after checking that evidence against the step’s actual acceptance criteria:

  • if the step declares a Command, it must exit 0 when re-run

  • if the step declares a FileExists path, it must exist

  • absent either, the step is judgment-only: non-empty evidence output is the best available signal

This is the correctness backbone. Nothing downstream ever depends on a worker’s self-assessment.

A2A vocabulary#

Worker↔orchestrator coordination uses the official a2aproject/a2a-go SDK’s core types (internal/a2a) for vocabulary — a2a.TaskState, a2a.Message — without adopting its heavier server packages. Only the stdlib-only core-types package is imported; a2asrv/a2agrpc/a2apb are not pulled in because there is no network-facing A2A surface today.

Task states used:

State

Meaning

Submitted

Claimed and dispatched; worker hasn’t reported yet

Working

Worker actively executing

InputRequired

The never-block signal — the orchestrator handles it (re-dispatch with an answer, or kill-and-reclaim), never by waiting on a blocked pty

Completed

Orchestrator-verified only; never set from a worker’s self-report or from process termination

A worker submitting evidence via an a2a.Message is a proposal for the orchestrator to verify — never a self-assertion of completion.

Durability#

Evidence and task-state transitions live in the one user-level SQLite database (the a2a_messages table plus the plan/task tables) — the plan DAG’s existing task store is the durable authority, not a second parallel store. The message table is a log of evidence, not an alternate source of truth.

Squads and native fan-out#

For a parallelizable step-group, the orchestrator may fan out multiple worker processes with path/worktree isolation, or — when the bound provider’s capability record declares NativeFanout (see Provider contract) — delegate the whole step-group to one invocation of that provider instead of spawning N Ralph-managed workers. Either way, cost and progress propagate up to the macro TUI through the same store-backed accounting.