| 1 | Dormant merge: **ACCEPT WITH FIXES** |
| 2 | Flag-on for boxes without host claims: **NOT YET SAFE** |
| 3 | |
| 4 | Read-only review of `650e6152..4c9bc525`. No files changed or tests run. All repository anchors below refer to `4c9bc525`. |
| 5 | |
| 6 | 1. **High / Merge — A stopping instance can lose track of its returning sidecar.** |
| 7 | |
| 8 | `internal/activator/activator.go:4437` clears `sidecarStartDone` before deferred cleanup runs. Sequence: `beginStopLocked` marks stopping; the restart returns and clears the channel; `stop()` reads nil at `:3593`; the returned sidecar is still draining through `stopSidecarNow`. |
| 9 | |
| 10 | Nested instances are particularly exposed: `internal/activator/opset.go:390` skips host-cgroup proof for their layout, while the main process’s stop proves only its own role (`internal/activator/unitproc.go:89`). The lease can therefore be released at `activator.go:3973` while the sidecar remains. |
| 11 | |
| 12 | Even when the join is captured, `stopSidecarNow` merely logs a failed stop (`activator.go:746`), then forgets the returned process. Closing the join is not termination proof. |
| 13 | |
| 14 | **Smallest fix:** retain the join through cleanup, retain any unproven returned sidecar, and require its termination before releasing the lease. Add deterministic tests for the missed-join window and nested `ErrStillRunning`. |
| 15 | |
| 16 | 2. **High / Merge — Two seed-obligation errors release the lease without proving surviving processes gone.** |
| 17 | |
| 18 | A successful flag-off seed may leave a helper running: `internal/activator/backend_exec.go:1072` deliberately skips descendant cleanup. If obligation discharge fails, `:1104` returns an ordinary error; `internal/activator/activator.go:2061` consequently releases the lease. No installed instance exists whose terminal stop will prove that helper gone. |
| 19 | |
| 20 | Likewise, an obligation read error returns without `ErrSeedUnproven` at `backend_exec.go:1286`, causing Restore’s error path to release at `activator.go:1987`. Nested wakes skip the preceding host proof (`internal/activator/opset.go:429`). |
| 21 | |
| 22 | **Smallest fix:** preserve the lease whenever seed termination remains unknown. Attempt proof after discharge failure; classify unreadable obligations conservatively. Test both paths with a surviving process. A subsequent wake’s proof cannot justify an earlier release. |
| 23 | |
| 24 | 3. **High / Flag — I9 does not prove the required stale-grant guarantee.** |
| 25 | |
| 26 | `internal/rollout/sim_test.go:747` considers a failure “answered” by another grant’s **issuance**, recorded at `:1967`, regardless of whether that grant is applied. |
| 27 | |
| 28 | Counterexample: issue G0; begin another hold execution; issue G1; renew the marker with M14’s missing generation bump; deliver G0 first. `answered` sees G1 and suppresses the violation even though G0 cleared the later marker. Delivery is explicitly oldest-first (`:1975`). |
| 29 | |
| 30 | I9 also excludes facts by execution-start time rather than restriction-change order, including all same-step facts (`:2025`, `:2033`). That leaves late outcomes and same-step changes outside the asserted guarantee. |
| 31 | |
| 32 | **Smallest fix:** give the independent model ordered restriction transitions and capture their identity at publication. Check each accepted grant against that state; issuance alone must never discharge a fact. Add deterministic masking, late-outcome and same-step witnesses, then rerun the mutants. |
| 33 | |
| 34 | 4. **Medium / Merge — Manual obligation recovery is not serialized against wakes.** |
| 35 | |
| 36 | The procedure in `docs/superpowers/plans/2026-10-07-zero-downtime-deploys-6-roll-notes.md:424` proves emptiness, deletes database files, then removes the obligation, but never excludes concurrent wakes. |
| 37 | |
| 38 | Between proof and deletion, Restore can discharge the obligation and begin another seed (`internal/activator/backend_exec.go:1281`). The operator can then delete that new seed’s database. |
| 39 | |
| 40 | **Smallest fix:** require exclusive maintenance across proof, database deletion, directory sync and obligation removal; resume wakes afterward. Correct deletion order alone is insufficient. |
| 41 | |
| 42 | 5. **Low / Flag — The literal generation non-repetition proof omits counter exhaustion.** |
| 43 | |
| 44 | `internal/rollout/failures.go:751` and `:756` increment `uint64` without checking overflow. Thus “every subsequent generation is larger” is not an unconditional property. |
| 45 | |
| 46 | This is not a plausible operational exhaustion scenario, but it contradicts the stated hard limit. |
| 47 | |
| 48 | **Smallest fix:** fail closed before exhaustion, including `Snapshot`, and test the boundary. Do not silently wrap under the same book identity. |
| 49 | |
| 50 | **1. Plan-review findings 1–12** |
| 51 | |
| 52 | | Finding | Disposition | Evidence | |
| 53 | |---|---|---| |
| 54 | | 1. Replacement/removal generations | ADDRESSED | Per-app generations; marker replacement and pruning touch them: `internal/rollout/failures.go:898`, `:901`, `:1242`. | |
| 55 | | 2. Upgrade identity rotation | ADDRESSED | Schema/durability migration rotates identity: `internal/rollout/failures.go:520`. | |
| 56 | | 3. Failed seed’s partial database | ADDRESSED | Write-ahead obligation and Restore settlement: `internal/activator/backend_exec.go:1198`, `:1281`. Lease errors remain finding 2. | |
| 57 | | 4. Required placement fallback | ADDRESSED | Required starts refuse fallback; final defensive guard: `internal/cgroup/cgroup.go:449`, `:500`, `:538`. | |
| 58 | | 5. In-flight sidecar start | PARTIAL | Join added at `internal/activator/activator.go:3593`, but finding 1 defeats it. | |
| 59 | | 6. Successful seed descendants | ADDRESSED | Flag-on successful seeds require descendant proof: `internal/activator/backend_exec.go:1072`. | |
| 60 | | 7. Independent I9 facts | PARTIAL | Model facts exist, but exemptions weaken the oracle: `internal/rollout/sim_test.go:747`, `:2033`. | |
| 61 | | 8. Mutation witnesses | ADDRESSED | Real-path mutations and named invariant checks: `internal/rollout/testdata/rolloutsim/mutate.sh:104`, `:160`, `:298`. | |
| 62 | | 9. Retry transport/restart | ADDRESSED | Separate signed log; legacy restart processing retained: `internal/release/hostretrylog.go:36`; `internal/host/restart.go:944`. | |
| 63 | | 10. Independent save retries | ADDRESSED | Startup and periodic retry: `internal/host/rolloutdeclined.go:109`, `:324`. | |
| 64 | | 11. Test committed revision | ADDRESSED | Checkpoint-before-mutation requirement: `docs/superpowers/plans/2026-10-12-zero-downtime-flag-readiness-2.md:29`. Ledger reports checkpointed runs. | |
| 65 | | 12. Factual/environment corrections | PARTIAL | Forwarder fixed at `internal/console/instancepage.go:67`; plan `:26` still contradicts supplied scratch/cache rules. | |
| 66 | |
| 67 | **Hard-limit assessment:** within the non-overflow range and stated file assumptions, I found no additional production mutation missing its generation change. Publication refuses dirty state; acceptance retries the save and refuses remaining dirtiness (`internal/rollout/failures.go:1095`, `:1134`). Reopen uses the highest saved sequence; migration rotates identity (`:511`, `:520`). These are substantial improvements. Certification remains incomplete because of findings 3 and 5 and the unaudited restore/clone assumption (`:349`; roll notes `:379`). |
| 68 | |
| 69 | The M13–M17 mutations exercise real paths: failed-save publication→I10; marker renewal, reopened sequence reuse, old-book grants and sibling-created records→I9. The runner requires the named invariant, not just any failure (`mutate.sh:104`, `:160`, `:298`). Their reported kills demonstrate sensitivity, not completeness of I9. I did not rerun them. The last inspected 3000-seed log showed the baseline passed and mutation checks still progressing. |
| 70 | |
| 71 | Tasks 3–7 close their identified implementation gaps, subject to real-box evidence: |
| 72 | |
| 73 | - **3–4:** capability/unsaved refusals and shared console eligibility agree (`internal/console/apiretry.go:88`; `instancepage.go:49`). |
| 74 | - **5:** declined execution pins identity and tier; production installs `BeforeExec` (`internal/activator/backend_exec.go:1685`, `:2952`; `internal/host/agent.go:451`). |
| 75 | - **6:** success requires the matching clean park, no fence/shutdown, and current scheduler revision (`internal/activator/workerswap.go:195`). |
| 76 | - **7:** required placement cannot fall through to PID movement (`internal/cgroup/cgroup.go:538`). |
| 77 | - **8:** remains incomplete through findings 1–2. |
| 78 | |
| 79 | I found no additional lock-order inversion or direct disk I/O under `Service.mu` in the changed cleanup paths; host proof drops the mutex before I/O (`internal/activator/opset.go:382`). The schema-3 refusal is deliberate local downgrade protection, not an incompatible external wire change (`internal/rollout/failures.go:501`). All seven new member-facing literals carry TODO-COPY markers (`internal/console/apiretry.go:42`, `:45`; `browserretry.go:22`, `:23`; `swapcopy.go:67`, `:72`, `:81`). |
| 80 | |
| 81 | **5. Every ledger ruling** |
| 82 | |
| 83 | Line numbers identify rulings in `/home/paulca/.cache/zdd-impl/readiness2/ledger.md`. |
| 84 | |
| 85 | | Lines | Position | Reason / condition | |
| 86 | |---|---|---| |
| 87 | | 9 | Agree with conditions | Hard rule is correct; findings 3 and 5 prevent certification. | |
| 88 | | 10 | Agree | Capability-gated signed transport: `internal/console/apiretry.go:88`. | |
| 89 | | 11 | Agree | Separate rev-18 amendment preserves the binding specification. | |
| 90 | | 12 | Agree | Own-build recovery is appropriate: `internal/activator/activator.go:2523`. | |
| 91 | | 13 | Agree with conditions | Authorized stop proof must include finding 1. | |
| 92 | | 14 | Agree with conditions | Durable obligation is right; close finding 2. | |
| 93 | | 15 | Agree | Required-placement refusal: `internal/cgroup/cgroup.go:449`. | |
| 94 | | 16 | Agree | Restart must apply checked grants, not seed-skip them: `internal/host/restart.go:944`. | |
| 95 | | 17 | Agree | Clean-park qualification: `internal/activator/workerswap.go:195`. | |
| 96 | | 18 | Agree | Real-box work remains external: roll notes `:455`. | |
| 97 | | 22 | Agree | Per-app generation matches record scope: `internal/rollout/failures.go:836`. | |
| 98 | | 23 | Disagree | Calling conflicting cache commands “house rules” does not resolve plan `:26`. | |
| 99 | | 40 | Agree with conditions | Migration and downgrade protection are sound; restore-path audit remains required (`failures.go:349`, `:520`). | |
| 100 | | 46 | Agree | Renewal witness matches M14’s actual mutation: `mutate.sh:107`. | |
| 101 | | 48 | Disagree in part | App-wide facts are right; issuance-as-answer and skipped same-step facts are not sufficient: finding 3. | |
| 102 | | 50 | Agree | M17’s zero-only bump isolates stale-grant safety from initial-generation liveness (`mutate.sh:131`). | |
| 103 | | 51 | Agree | Forced sibling health failure is a legitimate witness (`mutate.sh:139`). | |
| 104 | | 57 | Agree | Historic legacy retries remain quiet while eligible signed retries are processed (`internal/host/restart.go:129`, `:143`). | |
| 105 | | 64 | Agree | Declined-down wording and shared refusal match behavior (`instancepage.go:49`, `:77`). | |
| 106 | | 68–69 | Agree | Pinned tier and recorded-build sidecar fallback agree (`backend_exec.go:2952`; `activator.go:2523`). | |
| 107 | | 74 | Agree | Abandoning non-clean exits preserves the clean-park condition (`workerswap.go:195`). | |
| 108 | | 80 | Agree with conditions | Placement classification is heuristic; the probe does not prove ancestor permissions (`internal/cgroup/cgroup_linux.go:78`). | |
| 109 | | 81 | Agree | Single latch decision plus final fallback guard closes the identified race (`internal/cgroup/cgroup.go:445`, `:538`). | |
| 110 | | 86 | Disagree in part | Whole-host proof/reseeding are sound; calling the lost-sidecar scenario impossible is unsupported by finding 1. | |
| 111 | | 88 | Agree with conditions | Write-ahead/nested obligations improve recovery; finding 2 remains. | |
| 112 | | 94 | Agree with conditions | Database-first order is necessary; exclusive recovery is also necessary: finding 4. | |
| 113 | |
| 114 | **6. Every deferred minor** |
| 115 | |
| 116 | Grouped by ledger entry; every item receives a disposition. |
| 117 | |
| 118 | | Ledger entry | Triage | |
| 119 | |---|---| |
| 120 | | Task 1, line 41 | **Defer:** randomness failure refusing starts is conservative (`internal/rollout/failures.go:524`). Memory-only simulation concern is superseded by disk-backed seeds (`sim_test.go:504`). “Grants never expire” is already corrected by verification (`internal/release/hostretry.go:75`). **Merge:** resolve the reported `TestACancelledObservationRecordsNothing` and `TestAPointerClearRequeuesBeforeTheNextChannelIsRead` flakes; do not dismiss known failures as scheduling noise. | |
| 121 | | Task 1, line 43 | **Flag:** audit every data-directory copy/restore path and rotate identity. **Defer:** deliberate schema-3 downgrade refusal, with upgrade recovery (roll notes `:370`, `:379`). | |
| 122 | | Task 2, line 52 | **Flag:** obtain final M14/M16/M17 evidence after fixing I9. **Defer:** duplicate reconciled facts are redundant rather than permissive (`sim_test.go:2031`). | |
| 123 | | Task 3, lines 58, 60 | **Defer:** double-counted read errors; missing nil-handler/no-GET test; missing legacy lost-position test; missing history lost-position test; census key-specific coverage. These concern diagnostics or coverage around the checked delivery path (`internal/host/restart.go:129`, `:301`, `:857`). **Merge:** squash intermediate ungreen commits and validate the final tip. | |
| 124 | | Task 5, line 71 | **Defer:** long comment; silent version-mismatch refusal; unreachable nested identity omission; unreachable flat unversioned-link arm; missing real-backend fallback test; refused-seed coverage limited to absent databases. Production hook installation and pinning support this disposition (`internal/host/agent.go:451`; `backend_exec.go:1685`; `activator.go:2523`). | |
| 125 | | Task 6, line 76 | **Defer:** untested shutdown clause, positive control not asserting park, overstated timing comment. The production conjunction is explicit (`internal/activator/workerswap.go:195`). | |
| 126 | | Task 7, line 83 | **Defer:** fixture-only placement misclassification, common-ancestor EACCES diagnostic gap, linking `testing`. None opens required-placement fallback (`internal/cgroup/cgroup_linux.go:66`; `cgroup.go:538`). | |
| 127 | | Task 8, line 89 | **Defer:** claims-path cleared-Seed/ColdRestore gap; pre-existing undelegated flag-off sidecar limitation; approximately 35-second shutdown wait. These do not excuse the separately identified nested-sidecar defect (`internal/activator/opset.go:385`, `:402`; `activator.go:3596`). | |
| 128 | | Task 8, line 91 | **Merge:** unreadable-obligation lease release and successful-seed discharge lease release—finding 2. **Defer:** planted-directory recovery, existing-obligation refusal, pre-existing older-kernel worker/uncontained proof behavior, stale `reapUncontainedStop` plan name (`backend_exec.go:1200`, `:1281`; roll notes `:436`). **Merge:** resolve `TestARetainedCopyIsPublishedBeforeItIsRecorded` flakiness; repeated failures are not “noise.” | |
| 129 | | Task 9, line 96 | **Defer:** successful-but-unproven reseed wording, cosmetic wrapping, preamble omitting separately listed real-box items. Recovery and outstanding checks are described nearby (roll notes `:416`, `:455`). | |
| 130 | |
| 131 | **7. Explicit flag-on answer** |
| 132 | |
| 133 | **No—even without host claims, this branch is not yet ready to enable `CARLOS_SWAP`.** |
| 134 | |
| 135 | The remaining gates are distinct: |
| 136 | |
| 137 | - **Branch fixes:** findings 1–5; correction of the conflicting verification instructions; resolution of reported flaky tests; required final build/test/cross-build gates; and a completed mutation sweep using the repaired I9 on the resulting revision. |
| 138 | - **Contract/operational gates:** Paul’s rev-18 sign-off; the separate copy-review gate; and the restore/clone audit required by the identity proof (`failures.go:349`; roll notes `:379`). Claims-on arming remains excluded as instructed. |
| 139 | - **Real-box proof:** delegated cgroup placement, sibling limits, legacy-parent recovery, live-generation sidecar respawn, unsupported-clone3 refusal, seed/normal-stop helper termination before lease release, nested/root unit control, sidecar fallback, mixed-version retries, unsaved-book recovery, downgrade/clone behavior, outstanding round-1 checks and flagship gates E–G (roll notes `:455` onward). |
| 140 | |
| 141 | Real-box success cannot substitute for repairing the cleanup paths or the simulation oracle. |