# Handoff — orchestra v3 intent/context/workflow foundation Written 2026-08-26. Read this with `CLAUDE.md` and `AUDIT.md`. Everything below was verified with `go build ./... && go vet ./... && go test ./...` passing, 20 test packages, at the end of the session. ## What this session built Eight units, in this order. Each one landed complete with tests before the next started. 1. Human decision events plus a reducer. 2. Source cursors and reconcile-before-launch. 3. Turn-boundary reconciliation for a live lease. 4. `internal/agentctx` as the single renderer. 5. ace-fca phases with sealed artifacts. 6. Federated turn decision, then the trajectory gate. 7. Bounded grilling. 8. Independent review, `task pr` enforcement, then human review reflection. The loop now closes: ``` task → frame → research → plan → implement → ai review → task pr → human review ─┬─ comments → implementation └─ merge → completed ``` ## The invariants that hold, and where they are enforced | Invariant | Enforced at | |---|---| | Human decisions outrank contract, plan, and handoff | `domain.ReduceIntent`, rendering order in `agentctx.Build` | | Supersession is explicit, never inferred from subject | `domain.ReduceIntent` | | Reduction is order-independent and replay-deterministic | `domain.ReduceIntent`, sorted by `(At, ID)` | | No ownership begins without reconciling human input | `Store.PreLease`, called inside `Store.Lease`, the only minter of `TaskLeased` | | Live sessions see corrections at a verified turn boundary | `Coordinator.TurnDecision`, `Coordinator.RemoteTurn` | | One renderer decides what an agent sees | `agentctx.Build`, sole caller of every context section | | A phase reads sealed artifacts, never prior conversations | `agentctx.renderSealed`, phase table | | Leaving research or plan requires a sealed artifact | `Store.Append`, `WorkPhaseChanged` branch | | Only Orchestra changes phase | `operations.AdvanceWorkPhase`, `domain.CanTransitionPhase` | | One question at a time, bounded, with a finite budget | `operations.RequestHumanDecision` | | Review is independent of the implementation | `agentctx.Build` excludes handoff and research in review phase | | Review is bound to one commit | `Task.ReviewTargetSHA`, `Task.ReviewSatisfied` | | Submission requires gate sha == review sha == head sha | `domain.CheckSubmission` | | Submission is idempotent and not completion | `Task.Submitted`, `StateInReview` | | Only the bound pull request can move its task | `operations.ReflectSubmission` | | Completion requires an actual merge | `operations.ReflectSubmission`, `domain.CompletionReceipt` | ## Package map for the new work ``` internal/agentctx/ the only renderer of model-facing context internal/human/ human input, reconciliation, trust, PR observations internal/review/ review evidence, findings, reviewer instructions internal/workphase/ sealed research and plan artifacts internal/domain/ decision.go, decision_request.go, workphase.go, submission.go internal/operations/ workphase.go, trajectory.go, human_decision.go, review.go, submission.go, reflect.go internal/store/ cursor.go, plus projections in store.go internal/provider/ gitea_comments.go, gitea_pr.go ``` New event types, all validated in `domain.ValidateEvent`: `HumanDecisionRecorded`, `HumanDecisionSuperseded`, `WorkPhaseChanged`, `DeferredFindingRecorded`, `ReviewRecorded`, `TaskSubmitted`, `TaskChangesRequested`. New task state: `in_review`. New block reasons: `trajectory_gate`, `human_decision`, `operator_required`. ## Things that will bite the next session - **`bootstrapPrompt` and `taskLaunchPrompt` are gone.** Do not reintroduce a second renderer. `grep 'prompt = ' internal cmd` should only find `handoffPrompt` and `conventionsPrompt` in `internal/herdr`, which request output rather than supply authority. - **`herdr.Session` is no longer comparable with `==`.** It carries `DeliveredDecisions []string`. `cmd/orchestra-worker/main.go:584` uses `reflect.DeepEqual`. - **The reflector must not move behind `PreLease`.** An in-review task cannot be leased, so a pre-lease hook cannot observe the feedback that reopens it. - **`go vet` catches `t.Context()`** because `go.mod` declares go1.22 while the toolchain is newer. Use `context.Background()` in tests. - **Two pre-existing gofmt offenders**, `internal/provider/provider.go` and `internal/webui/webui.go`, are untouched by this work. Ignore them or fix them deliberately. - **The router still swallows lease errors** with a bare `continue` (`internal/router/router.go:197`). That cost real debugging time this session when a `PreLease` refusal looked like "no candidates". ## Deliberate gaps, with reasons - **Turn-boundary reconcile failure is non-fatal.** Recorded in `MonitorHealth.Sessions[id].LastError`, and the turn continues. Blocking would freeze live sessions during a source outage without making their intent less stale. The escalation to `prepare_handoff` after repeated failures is deliberately not built; wait for evidence. - **The federated worker has no turn-decision path of its own.** It reports its locally-evaluated verdict to `POST /v1/federation/turn` and delivers what comes back. It has no `prepare_handoff` escalation either. - **Admission for grilling is stated, not enforced.** Orchestra cannot mechanically tell a repo-answerable question from a real one without another semantic judge. What is enforced: bounds, budget, one-at-a-time, and Orchestra owning the lifecycle. - **Vikunja is not marked in-review on submission.** No Vikunja mutation client exists in this repo. `Task.Submission` holds everything a reflector needs. - **Deferred findings do not become follow-up tasks yet.** `operations.DeferredFindings` lists them; creating tasks is a separate step. - **The review endpoint requires a full-control surface**, so a gated agent surface cannot seal a review. That is the conservative default until capability restrictions land. - **`GiteaPublisher` is untested against a live Gitea.** Its PR create, update, read, and comment paths are shaped from the API docs, not from a live probe. Verify against the real instance before trusting them. ## New configuration `deploy/config.example.jsonc`, per project: ```jsonc "work_phases": ["frame", "research", "plan", "implement", "review"], "trajectory_gate": { "plan_to_implement": "required" }, "human_decisions": { "max_requests_per_task": 6 } ``` `deploy/orchestra.env.example`: ``` ORCHESTRA_HUMAN_RECONCILE=off # disable pre-lease reconciliation ORCHESTRA_PR_BASE=master # pull request base branch ORCHESTRA_REVIEW_ACTORS=kami # who may reopen a submitted task ORCHESTRA_REVIEW_IGNORE_ACTORS=... # bots, always loses ``` Nothing in this session's work changes behaviour on a deployment with no Gitea source configured. Reconciliation, submission publishing, and reflection all stay inert without one. ## Next unit: capability restrictions This is the last item in the build order, and its point is narrow: the workflow exists now, so what remains is stopping an agent from stepping around it. Agent sessions should get: ``` repo read/write tests, build task checkpoint task decision-request task deferred ``` They should not get: ``` vikunja mutation token gitea administrative token direct lifecycle mutation task completion API push or pull-request creation phase transition review sealing submission ``` Orchestra keeps: push policy, pull request creation, task status, session state, decision persistence, phase transitions, review sealing, submission, and completion. Prompt rules stay advisory. The enforcement is capability boundaries plus legal transitions, which is what `internal/authz` already models. Start there: `CapabilityFor` currently gives `mcp` and `maven` `GatedWrite`, and `CanEmit` allows only `ApprovalRequested` at that level. Decide which of the new event types an agent surface may emit, then make the endpoints agree. Two concrete questions to settle first: 1. Should a reviewing agent seal its own review through a gated surface, or should the worker seal it on the agent's behalf? Today it needs full control. 2. Does the harness token surface (`/v1/harness/turn`) need its own capability level, distinct from `mcp`? ## Acceptance proofs worth reading before changing anything - `internal/integration/acefca_test.go` — four proofs: phase boundaries carry authority, the trajectory gate correction outranks the sealed plan, a blocking question resumes with the answer on top, review is independent, and a submitted task is not reassigned. - `internal/integration/reconcile_launch_test.go` — reconciliation is upstream of every agent start, and an unreachable source refuses the lease. - `internal/operations/reflect_test.go` — the full human loop from rejection to merge.