Reconcile docs with reality; fix module graph, token compare, health #1

Open
kami wants to merge 216 commits from webui-and-audit-reconciliation into master
Showing only changes of commit ab3258833d - Show all commits
+84
View File
@@ -2607,3 +2607,87 @@ inside `lease_expired`.
Runtime proof still owed: force a request the agent will not answer, and read
the release event rather than the worker state file.
## Run 17, 2026-08-29: F62 proven live on `c587f2c`
Task `06G4V20T528ZTER7KZBVGNAYXC`, a five-phase plan
(`3b16b77054b9`) on the deployed pair, coordinator and worker both at
`c587f2c`.
### The trigger was production, not a rig
The rig planned for this run was a state-file lever. It was never needed. The
`implement -> review` phase change asked for a handoff through the ordinary
path (`rotateForPhase`, reason `phase_changed`), and the agent ignored it
because this task's brief instructed it to from phase 4 onward. Nothing touched
tmux, no process was stopped, and the pane stayed open for the whole wait.
```text
12:48:09 implement -> review, handoff requested, reason=phase_changed
12:50:09 TaskLeaseRenewed agent idle, pane capture unchanged
12:52:15 pane input confirmed the single resend, 4m06s after the request
12:52:39 TaskLeaseRenewed
12:55:14 TaskLeaseRenewed
12:57:49 TaskLeaseRenewed
12:58:14 TaskReleased reason=handoff_unanswered failure_class=handoff_unanswered
last_error="handoff requested (phase_changed) and unanswered for 10m5s"
12:59:14 TaskLeased successor leases normally
13:02:20 TaskSubmitted
```
Every assertion the operator set for this rung held:
- the release does not look like an ordinary `lease_expired`: it carries
`reason=handoff_unanswered` and `lifecycle_phase=handoff_unanswered`;
- the idle-renewal rule did not kill the wait: four renewals on an idle pane
with no capture movement, each one the gate would have refused before this
commit;
- the resend preserved the reason the request was first made with;
- exactly one resend, not one per tick;
- the timeout produced the class at `10m5s`, one tick past the bound;
- nothing stale was left: `releases: {}`, no session, no lease, and zero tmux
panes matching the id;
- the next attempt leased 60s later and reached `TaskSubmitted`.
The debt projection classified it with no new code beyond the class mapping:
```text
v1:operational:handoff_unanswered:workpc-claude:lease operational important
"handoff requested (phase_changed) and unanswered for 10m5s"
```
**Inference, not observation.** The resent prompt's text was not captured. That
it carried the `phase_changed` wording rests on the code path and the timing,
not on a pane capture. A future rig should publish a capture across the resend.
### The implement-successor rung missed again, and why
A five-phase plan does not lengthen the implement phase. This one ran 12:45:18
to 12:48:09, about 2m50s, with verifications 20 to 40 seconds apart:
```text
12:45:47 phase-1 12:46:07 phase-2 12:46:32 phase-3
12:47:12 phase-4 12:47:52 phase-5 12:48:09 implement -> review
```
The brief's explicit one-phase-at-a-time requirement was followed, and it
still took under three minutes. Phase count is not the lever; volume of
mechanical work is.
`awaiting_manual_verification` does not hold the phase open either. All five
phases carried that status and the agent moved on regardless.
### The state-file lever cannot be driven with `restart` alone
The documented procedure is stop, edit, start. The unattended sudo rule grants
`install` and `systemctl restart orchestra-worker`, with no `stop` or `start`.
With `restart` only, the running worker's five-second tick save landed between
the edit and the restart, and the edit was gone. Widening the sudoers line is
the fix.
### One cosmetic note
`Session.HandoffRequestedAt` serializes as `0001-01-01T00:00:00Z` when unset,
because `omitempty` does not omit a zero `time.Time`. The worker parses it back
to a zero value and `watchHandoff` starts the clock, so behaviour is correct.
It is the same marshalling trap the operator console hit.