REJECT

1. **P1 — Captured worker builds are unprotected before plan 5.** [internal/release/adopt.go:405](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/zdd-4-release-side/internal/release/adopt.go:405), [internal/activator/workerbuild.go:52](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/zdd-4-release-side/internal/activator/workerbuild.go:52).

   A worker runs A, whose staged files are over six hours old. Two promotions install B then C before the worker converges. Its live link and registry now pin C and B; nothing exported by this branch pins A. The next hourly sweep can delete A. Alternatively, adoption of a re-shipped A can overwrite it because `BoxPins` reports it unreferenced.

   A subsequent crash or `max_run` recycle refuses A through `VerifyStaged`. The exited-worker branch keeps retrying that identity and never reaches convergence, leaving the worker down indefinitely. This happens without any new flag.

   **Smallest fix:** treat worker references as unknown until they are exported, suppressing both destructive restaging and eviction in that state. Alternatively, bring the worker-pin writer and both consumers into this branch. Add a regression covering two repoints followed by sweep/restage and recycle.

2. **P2 — Same-build recycles can prevent convergence indefinitely.** [internal/activator/activator.go:1974](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/zdd-4-release-side/internal/activator/activator.go:1974), [internal/activator/activator.go:2548](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/zdd-4-release-side/internal/activator/activator.go:2548).

   An always-on worker runs A with `max_run=30s`; root installs B. Every recycle correctly respawns A, but also clears `staleSince`. The drift never survives the 90-second `ConvergeGrace`, so B never runs. Frequent crashes produce the same starvation; exited workers skip the drift check entirely. Before this change, their respawn followed the updated live link.

   **Smallest fix:** preserve drift age across recycles of the same build, evaluate drift even when a recycle is due, and give an eligible convergence priority while retaining the convergence budget. Test several recycle intervals after a promotion, not only the first recycle.

3. **P2 — Chained live symlinks hide referenced copies from `BoxPins`.** [internal/release/pins.go:59](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/zdd-4-release-side/internal/release/pins.go:59), [internal/release/staged.go:53](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/zdd-4-release-side/internal/release/staged.go:53).

   With `live/h → /opt/operator-current → versions/v1/app`, and no registry version pin for v1, `BoxPins` records only `/opt/operator-current`. Another host adopting a re-shipped v1 therefore overwrites a copy the live link still references. `ResolveLive` likewise retains the intermediate link, rather than the final executable path. A later digest refusal detects the damage but does not prevent the overwrite.

   **Smallest fix:** resolve the captured target’s remaining symlinks for executable identity and pinning; preserve necessary intermediate-path pins and fail closed when resolution is uncertain. Add a chained-link restage-refusal test. The ledger’s Task 3 symlink minor needs promotion to a pre-merge fix.

### Ledger rulings and deferred items

- **R1, R7, R9:** workflow choices; no implementation objection.
- **R2–R5:** consistent with the binding sections and current code. Preserving cgroup cleanup and the config-admission gate is necessary.
- **R6:** canonical comparison and outage fallback are consistent with the stated contract. This does not establish that the reference set is complete.
- **R8:** reasonable against this base; the later staging integration still needs review.
- **R10:** acceptable. The fixtures still reach the binding refusal and retain their assertions.
- **R11:** the conservative refusal is correct. Its claimed recovery is not guaranteed: a held row is not necessarily adopted by a full pass, and that pass may never stage its requested version. Correct that expectation; do not restore the incomplete-pin overwrite.

Deferred-minor triage:

| Ledger area | Disposition |
|---|---|
| Task 1 | Test-comment wording and missing uppercase rejection test: P3. |
| Task 2 | Lossy-sibling comment is already corrected. Older-sibling reuse test: P3. |
| Task 3 | Chained symlink: finding 3. Relative-link assertion, wording and error wrapping: P3. |
| Task 4 | Empty SHA is already rejected by `validateManifest`, so `CanonicalDemand` returns hold. EqualFold/digest assertion gaps: P3. |
| Task 5 | Parent-directory fsync, reader consolidation, missing branch tests, parse-error wrapping and empty-host-list strictness: P3. |
| Task 6 | Missing-platform diagnostics/test, repeated hashing/logging and held-stage explanation: P3. |
| Task 7 | Ordering comment, generic failure reason and coverage gaps: P3. Host-claim selection and unit-less proof-policy behavior are not new defects. |
| Task 8 | Regular-file and unreadable-target refusals fail closed. Missing failure-path test: P3. |
| Task 9 | Captured-copy loss: finding 1, **must fix**. Coalescing backoff/logging and remaining coverage gaps: P3; add refused-recycle coverage with finding 1. |

Static review only; no files modified and no tests run. `git diff --check 4f26f15c..HEAD` passed.