carlos / platform Public

docs: Astra's whole-branch review of readiness round 2, round 1

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 6a81b137d66ef533700a42ae06e1bea85b97b370 parent 4c9bc52
1 file changed, +141 −0
  • docs/superpowers/plans/CODEX-FINDINGS-ZDD-READINESS2.md +141 −0
diff --git a/docs/superpowers/plans/CODEX-FINDINGS-ZDD-READINESS2.md b/docs/superpowers/plans/CODEX-FINDINGS-ZDD-READINESS2.md
new file mode 100644
index 000000000..9e6146f9b
--- /dev/null
+++ b/docs/superpowers/plans/CODEX-FINDINGS-ZDD-READINESS2.md
@@ -0,0 +1,141 @@
+Dormant merge: **ACCEPT WITH FIXES**
+Flag-on for boxes without host claims: **NOT YET SAFE**
+
+Read-only review of `650e6152..4c9bc525`. No files changed or tests run. All repository anchors below refer to `4c9bc525`.
+
+1. **High / Merge — A stopping instance can lose track of its returning sidecar.**
+
+ `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`.
+
+ 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.
+
+ 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.
+
+ **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`.
+
+2. **High / Merge — Two seed-obligation errors release the lease without proving surviving processes gone.**
+
+ 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.
+
+ 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`).
+
+ **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.
+
+3. **High / Flag — I9 does not prove the required stale-grant guarantee.**
+
+ `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.
+
+ 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`).
+
+ 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.
+
+ **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.
+
+4. **Medium / Merge — Manual obligation recovery is not serialized against wakes.**
+
+ 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.
+
+ 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.
+
+ **Smallest fix:** require exclusive maintenance across proof, database deletion, directory sync and obligation removal; resume wakes afterward. Correct deletion order alone is insufficient.
+
+5. **Low / Flag — The literal generation non-repetition proof omits counter exhaustion.**
+
+ `internal/rollout/failures.go:751` and `:756` increment `uint64` without checking overflow. Thus “every subsequent generation is larger” is not an unconditional property.
+
+ This is not a plausible operational exhaustion scenario, but it contradicts the stated hard limit.
+
+ **Smallest fix:** fail closed before exhaustion, including `Snapshot`, and test the boundary. Do not silently wrap under the same book identity.
+
+**1. Plan-review findings 1–12**
+
+| Finding | Disposition | Evidence |
+|---|---|---|
+| 1. Replacement/removal generations | ADDRESSED | Per-app generations; marker replacement and pruning touch them: `internal/rollout/failures.go:898`, `:901`, `:1242`. |
+| 2. Upgrade identity rotation | ADDRESSED | Schema/durability migration rotates identity: `internal/rollout/failures.go:520`. |
+| 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. |
+| 4. Required placement fallback | ADDRESSED | Required starts refuse fallback; final defensive guard: `internal/cgroup/cgroup.go:449`, `:500`, `:538`. |
+| 5. In-flight sidecar start | PARTIAL | Join added at `internal/activator/activator.go:3593`, but finding 1 defeats it. |
+| 6. Successful seed descendants | ADDRESSED | Flag-on successful seeds require descendant proof: `internal/activator/backend_exec.go:1072`. |
+| 7. Independent I9 facts | PARTIAL | Model facts exist, but exemptions weaken the oracle: `internal/rollout/sim_test.go:747`, `:2033`. |
+| 8. Mutation witnesses | ADDRESSED | Real-path mutations and named invariant checks: `internal/rollout/testdata/rolloutsim/mutate.sh:104`, `:160`, `:298`. |
+| 9. Retry transport/restart | ADDRESSED | Separate signed log; legacy restart processing retained: `internal/release/hostretrylog.go:36`; `internal/host/restart.go:944`. |
+| 10. Independent save retries | ADDRESSED | Startup and periodic retry: `internal/host/rolloutdeclined.go:109`, `:324`. |
+| 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. |
+| 12. Factual/environment corrections | PARTIAL | Forwarder fixed at `internal/console/instancepage.go:67`; plan `:26` still contradicts supplied scratch/cache rules. |
+
+**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`).
+
+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.
+
+Tasks 3–7 close their identified implementation gaps, subject to real-box evidence:
+
+- **3–4:** capability/unsaved refusals and shared console eligibility agree (`internal/console/apiretry.go:88`; `instancepage.go:49`).
+- **5:** declined execution pins identity and tier; production installs `BeforeExec` (`internal/activator/backend_exec.go:1685`, `:2952`; `internal/host/agent.go:451`).
+- **6:** success requires the matching clean park, no fence/shutdown, and current scheduler revision (`internal/activator/workerswap.go:195`).
+- **7:** required placement cannot fall through to PID movement (`internal/cgroup/cgroup.go:538`).
+- **8:** remains incomplete through findings 1–2.
+
+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`).
+
+**5. Every ledger ruling**
+
+Line numbers identify rulings in `/home/paulca/.cache/zdd-impl/readiness2/ledger.md`.
+
+| Lines | Position | Reason / condition |
+|---|---|---|
+| 9 | Agree with conditions | Hard rule is correct; findings 3 and 5 prevent certification. |
+| 10 | Agree | Capability-gated signed transport: `internal/console/apiretry.go:88`. |
+| 11 | Agree | Separate rev-18 amendment preserves the binding specification. |
+| 12 | Agree | Own-build recovery is appropriate: `internal/activator/activator.go:2523`. |
+| 13 | Agree with conditions | Authorized stop proof must include finding 1. |
+| 14 | Agree with conditions | Durable obligation is right; close finding 2. |
+| 15 | Agree | Required-placement refusal: `internal/cgroup/cgroup.go:449`. |
+| 16 | Agree | Restart must apply checked grants, not seed-skip them: `internal/host/restart.go:944`. |
+| 17 | Agree | Clean-park qualification: `internal/activator/workerswap.go:195`. |
+| 18 | Agree | Real-box work remains external: roll notes `:455`. |
+| 22 | Agree | Per-app generation matches record scope: `internal/rollout/failures.go:836`. |
+| 23 | Disagree | Calling conflicting cache commands “house rules” does not resolve plan `:26`. |
+| 40 | Agree with conditions | Migration and downgrade protection are sound; restore-path audit remains required (`failures.go:349`, `:520`). |
+| 46 | Agree | Renewal witness matches M14’s actual mutation: `mutate.sh:107`. |
+| 48 | Disagree in part | App-wide facts are right; issuance-as-answer and skipped same-step facts are not sufficient: finding 3. |
+| 50 | Agree | M17’s zero-only bump isolates stale-grant safety from initial-generation liveness (`mutate.sh:131`). |
+| 51 | Agree | Forced sibling health failure is a legitimate witness (`mutate.sh:139`). |
+| 57 | Agree | Historic legacy retries remain quiet while eligible signed retries are processed (`internal/host/restart.go:129`, `:143`). |
+| 64 | Agree | Declined-down wording and shared refusal match behavior (`instancepage.go:49`, `:77`). |
+| 68–69 | Agree | Pinned tier and recorded-build sidecar fallback agree (`backend_exec.go:2952`; `activator.go:2523`). |
+| 74 | Agree | Abandoning non-clean exits preserves the clean-park condition (`workerswap.go:195`). |
+| 80 | Agree with conditions | Placement classification is heuristic; the probe does not prove ancestor permissions (`internal/cgroup/cgroup_linux.go:78`). |
+| 81 | Agree | Single latch decision plus final fallback guard closes the identified race (`internal/cgroup/cgroup.go:445`, `:538`). |
+| 86 | Disagree in part | Whole-host proof/reseeding are sound; calling the lost-sidecar scenario impossible is unsupported by finding 1. |
+| 88 | Agree with conditions | Write-ahead/nested obligations improve recovery; finding 2 remains. |
+| 94 | Agree with conditions | Database-first order is necessary; exclusive recovery is also necessary: finding 4. |
+
+**6. Every deferred minor**
+
+Grouped by ledger entry; every item receives a disposition.
+
+| Ledger entry | Triage |
+|---|---|
+| 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. |
+| 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`). |
+| 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`). |
+| 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. |
+| 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`). |
+| 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`). |
+| 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`). |
+| 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`). |
+| 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.” |
+| 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`). |
+
+**7. Explicit flag-on answer**
+
+**No—even without host claims, this branch is not yet ready to enable `CARLOS_SWAP`.**
+
+The remaining gates are distinct:
+
+- **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.
+- **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.
+- **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).
+
+Real-box success cannot substitute for repairing the cleanup paths or the simulation oracle.
\ No newline at end of file