# Handoff: run 5 reached TaskCompleted, plan machinery is designed and frozen Written 2026-08-28, 06:55 local (02:55 UTC). Read with `BURNIN.md` (the ledger, now current through F42), `PLAN-SPEC-DESIGN.md` (the locked design for the next change), `HANDOFF-2026-08-28-burnin-4.md` (the session before this one), `AUDIT.md` and `CLAUDE.md`. Everything below was observed live unless it says otherwise. ## The headline Run 5 finished. Task `06G4A4F0TFXKZHJE48N05XN1HG`, issue `kami/test-e2e#5`, reached `TaskCompleted` at 06:48 after two defects were found and fixed in the completion tail. ```text frame -> research -> plan -> implement -> review -> done -> finalise -> pushed -> completed ``` Two defects, both live-proven fixed: - **F41**: harness chrome counted as agent progress, so a stalled lease renewed without bound. - **F42**: the result commit refused the completion marker, so completion could never happen. ## Deployed state | Half | Revision | Evidence | |---|---|---| | Worker, workpc systemd | `dcd9af4` | PID 3634937, started 06:47:50, sha256 `25b41562…`, journal prints the revision at startup | | Coordinator, homesrv container | `bcaf0cc` | **stale**, see below | Branch `webui-and-audit-reconciliation`, HEAD `dcd9af4`. ```text revision dcd9af4806376caf091e18f669ab52f1ba0dc9df sha256 25b415629d4a02dca7abe202245ac13f5bdb43b501bc17e371dba75b44f6cebb ``` **Confirm the running worker, not the installed file.** Two restarts silently did not happen tonight. `sudo install` landed the new binary while the old process kept serving from the unlinked inode. `/proc//exe` showed `(deleted)` and the old hash both times. Check `sha256sum /proc/$(systemctl show -p MainPID --value orchestra-worker)/exe`, never just the path. The second missed restart cost run 5 its retry budget: the pre-F42 worker kept failing until the router marked the task `failed`. ## The coordinator is behind, deliberately `2417a39` moved lease TTL to 5 minutes via `domain.LeaseTTL`, and the coordinator issues the initial lease at `internal/router/router.go:318`. That half still runs `bcaf0cc`, so new leases arrive with a 30-minute TTL. Worker renewals send `ttl=300` explicitly, which is why run 5 recovered anyway. Rebuild when convenient, from a detached worktree, never with `docker compose build`: ```text git worktree add --detach /tmp/orchestra-build-dcd9af4 dcd9af4 docker build --build-arg BUILD_REVISION=dcd9af4… -f $T/Dockerfile.api -t orchestra-web-ui-orchestra-api $T docker compose up -d --no-deps orchestra-api ``` ## What this session found ### F41, harness chrome counted as progress The 02:46 renewal was granted against a pane idle since 02:12. Reproduced the worker's stored `progress_sha` byte for byte from the live pane, so the branch taken was `progress != l.ProgressSHA`, not `IsBusy` and not an empty baseline. `PaneProgress` hashed Claude Code's status footer, whose usage percentage, context counter and version notice all move on their own schedule. Fixed in `2417a39`. Live-proven in both directions on the first window after deployment: renewal at 03:13:48, refusal at 03:16:13, expiry at 03:18:43, relaunch at 03:20:14. ### F42, the result commit refused the completion marker `.orchestra/.gitignore` contains `*`, so `.orchestra/done` is ignored, and git refuses an add whose pathspec names an ignored path. The staging step named the marker. Every completion attempt failed, once every five seconds, for 22 minutes. Fixed in `dcd9af4` by excluding the directory rather than the file. Reproduced both forms in a scratch repo on git 2.55.0 before changing anything. ### F18 is now the clear top item Both defects tonight were five-second retry loops whose only trace was the journal, because each identical error overwrote the single `last_error` slot. `health` in the worker state file was `{}` throughout. The bounded recent-observation ring described in the previous handoff is the fix. This session adds a second concrete instance of the cost. ## Where the completion tail stops Proven: review, done recognised, agent confirmed idle, finalise, result branch pushed, `TaskCompleted`. Not proven, and not defects: - **No quality gate ran.** The deployed `test-e2e` project declares only `id`, `machine_affinity`, `repo` and `worktree_root`. - **No PR was opened.** The deployed `config.jsonc` has no `sources` and no `delivery` keys. `internal/provider/gitea_pr.go` implements PR creation, but nothing points this project at a Gitea remote. Submission, human PR review and merge need registry configuration, not code. That is the cheapest remaining burn-in, and it is a config edit plus one task. ## The next change is designed and frozen `PLAN-SPEC-DESIGN.md` holds the operator-approved design for the ACE-FCA plan gap. No implementation exists yet, by explicit instruction: the design must not land while the completion tail is still being observed. Shape, in one paragraph each: - **`plan.md`**, sealed through the existing path and referenced by the existing `t.PlanRef`. 128 KiB total bound, structural validation by required headings and phase blocks, no per-line cap. `DecodePlan` keeps the JSON path for refs already in the CAS. - **Research ids.** `Finding{ID, Claim, Evidence, Confidence}`, unique ids, confidence limited to `fact|inference|assumption`. The schema at `agentctx.go:167` already promises these and the struct drops them today. - **Progress that Orchestra establishes.** The implementer may write only `status: "ready_for_verification"`. The worker reads that phase's automated verification from the accepted plan, runs it, and records `PlanPhaseVerified`. An agent cannot write `verified`. - **Verification allowlist.** Plan commands are argv, executed without a shell, matched against a per-project policy. Absent policy refuses everything. - **Mismatch as a typed request.** `PlanMismatchRequest` supersedes or reopens research and planning. No new agent-askable backward transition. The live proof ladder is in the note. Steps 1 and 3 are the rungs that matter for smaller local models. The implement launch contains the plan verbatim, and a rotated successor still receives it whole with phase state intact. ## Things that will bite - **Verify the running worker binary, not the installed one.** Twice tonight. - **The worker state file is a cache, not truth.** It read `state failed` for run 5 while the coordinator still held the task as leasable. I reported the cache as fact. The coordinator disagreed and was right. - **`rm` and `cp` are interactive in this shell.** A plain `rm` prompts, appears to succeed, and leaves the file. Use `/bin/rm -f` and `install`. - **Another session owns 20-plus uncommitted paths**, including `AUDIT.md`, `deploy/build.sh`, `web/` and `internal/authn/`. Commit by path. Never `git add -A`. - **No network from this sandbox.** `curl` to raw.githubusercontent.com times out. `WebFetch` against a `github.com/blob/...` URL works. - **Secrets are guarded.** Reading `.env` or `printenv` of a token through the shell is blocked. The working recipe is expanding the token inside the container in a single remote command, as `HANDOFF-2026-08-28-burnin-4.md` records. - **`/tmp` is tmpfs with a 10-day sweep.** Check `/tmp/test-e2e` and `/tmp/test-e2e-worktrees` exist before every run. - **Two stale monitors** may still be armed from this session, tailing the worker journal. They are session-local and die with it. ## What I would do next, in order 1. Rebuild `orchestra-api` at `dcd9af4` so the 5-minute TTL applies at issuance. 2. Fix F18 as a bounded observation ring, since two more instances landed tonight. 3. Configure `test-e2e` with a Gitea remote and a quality gate, then run one task to prove submission, human review and merge. 4. Implement `PLAN-SPEC-DESIGN.md` exactly as written, including the allowlist. Steps 1 through 3 are burn-in and observability. Step 4 is the only new behaviour, and its design no longer needs an architecture pass.