Region HA plan 1b-next: Astra round 3 findings (10 resolved, 3 partly, 1 not, 6 new; not ready), unedited
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+50
−0
docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R3.md+50 −0
diff --git a/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R3.md b/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R3.md| new file mode 100644 |
| index 000000000..17f8aced8 |
| --- /dev/null |
| +++ b/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R3.md |
| @@ -0,0 +1,50 @@ |
| +Reviewed `d93c94d0`. **P** below refers to the [implementation plan](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/docs/superpowers/plans/2026-10-07-region-ha-1b-next-relocation.md). **6b** refers to the declared plan on `origin/design-replica-ownership`. |
| + |
| +All 11 embedded patches pass `git apply --check`. Compilation and tests were not reproduced in this read-only sandbox. |
| + |
| +| Prior finding | Disposition | Assessment against rev 3 | |
| +|---|---|---| |
| +| R1-2 — build authority | Resolved | Each builder write now checks claim and installation identity; lease loss cancels the build. | |
| +| R1-4 — former writer’s loss evidence | Resolved | Retained evidence includes the former writer’s last admission and its consequences. | |
| +| R1-5 — immutable files pin | **Partly** | Copying uses retained bytes, but `PreparedFromInstallManifest.Verify` still reads the mutable source manifest at **P:7825–7834**. A late PUT still prevents progress. Verify against the retained control-bucket copy too. | |
| +| R1-9 — release replay after restart | **Partly** | **P:7103** restores the old controller identity without setting `Recover`. 6b’s stop coordinator rejects that identity mismatch before replay (**6b:11975–11976**). Use its authenticated recovery path and preserve the recorded owner’s directory revision. | |
| +| R1-13 — later empty probe | Resolved | Later attempts handle `genselect.ErrEmpty` and use ordinary empty-generation authority. | |
| +| R1-14 — row-case adapter test | Resolved | The incorrect deletion/status expectations are corrected. The replacement test has a separate compilation defect below. | |
| +| R1-16 — exhaustion before selection | Resolved | Both paths check exhaustion before choosing a spare. A different exhaustion boundary fails below. | |
| +| R2-N1 — prepared retry ordering | Resolved | Inherited flags are reset; ordinary retries leave `Prepared` false. | |
| +| R2-N2 — forbidden deletion expectation | Resolved | Existing unexplained rows are retained; assertions use `hold_op`. | |
| +| R2-N3 — descriptor privileges | Resolved as a gated contract | Agent capture is process-local; R3 explicitly requires root’s complete scan. | |
| +| R2-N4 — completed target remains held | **Not resolved** | The clear at **P:8537–8542** is inside the write callback. Before reaching it, serving `Policy.Check` rejects any nonempty hold ([wakepolicy.go:63](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostbox/wakepolicy.go:63)). Provide narrowly scoped authority to clear an obsolete hold before that rejection. | |
| +| R2-N5 — retained controller lifetime | **Partly** | Sweeping is added, but a timed-out close loses the reference needed to finish cleanup; see new finding 2. | |
| +| R2-N6 — three-attempt limit | Resolved | The claim durably counts attempts before invoking R1’s single-attempt probe contract. | |
| +| R2-N7 — discovery completion | Resolved | Qualified discharge now uses `CompleteObligation` semantics. | |
| + |
| +New findings, ranked: |
| + |
| +1. **P1 — Task 9, Steps 1 and 4: identifiers are missing from the declared upstream.** |
| + **P:8529** uses `observed.Claim` at the insertion after `write(owner)`. In 6b, `observed` is declared only inside the earlier `sql.ErrNoRows` block (**6b:7891–7902**), so it is undefined at that insertion. **P:8373** also calls `adapterFixture`, attributed to a 6b fixture that the declared plan does not supply. |
| + **Fix:** read and validate the claim under captured authority at the insertion point, and include the actual test fixture and its methods. |
| + |
| +2. **P2 — Task 7, Step 4: `Finish` forgets a controller before closing it successfully.** |
| + **P:6933–6942** removes the map entry before calling `Close(ctx)`. Main explicitly retains the lifetime lock when closing times out and requires another `Close` call ([controller.go:478](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostexec/controller.go:478)). If the pass expires during cleanup, later sweeps cannot find that controller; another relocation cannot acquire the host’s lock. |
| + **Fix:** retain the entry until closing completes, then conditionally remove that same controller. Test cancellation followed by a successful later sweep and another relocation. |
| + |
| +3. **P2 — Tasks 3/9/10: production construction never supplies the new policy and fence observer.** |
| + `Policy.Relocation` is mandatory for relocation actions (**P:3221–3238**), but its assignments are confined to tests. 6b constructs the policy with only `Inputs`, `Moves` and `Held` (**6b:10887**), then captures `a.Policy.Check` (**6b:10520**). Task 10 supplies neither the relocation policy nor `Reconciler.FenceClosed`, whose default is false (**P:8499**). Executor reconciliation and execution therefore remain refused, and source-fence closure is invisible to row decisions. |
| + **Fix:** define and wire both providers before assembly construction captures the policy, gated on the feature flags. Test production assembly with HA enabled and disabled. |
| + |
| +4. **P2 — Task 9, Step 3: a fenced source cannot write its required hold while it remains executor.** |
| + **P:8485** chooses `holdOnly` only when `op.exec != box`. During `releasing`, the source remains executor after its admission fence closes. It therefore takes the guarded installation path, where the active fence or receipt prevents the callback ([guard.go:144](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostguard/guard.go:144)). This contradicts the `WithLocal` behavior promised by **P:8363**. |
| + **Fix:** use the conditional hold-only path for a source whose admission fence is closed, even while it remains executor. Test with a real durable fence. |
| + |
| +5. **P2 — Tasks 1/5, Step 3: exhaustion cannot stop a terminated target after local installation.** |
| + After two replacements, let the final target journal `local_install` in `installed`, then terminate before probing. **P:5197–5198** calls `MarkStuck`, but **P:1968–1969** refuses precisely that state. Every pass repeats the refusal; the dead target cannot probe, and its fence is never consumed. |
| + **Fix:** define a fence-consuming terminal transition that retains loss evidence, revokes the dead installation’s authority and reaches a safe stuck state without selecting a third replacement. Extend the exhaustion test beyond `starting`. |
| + |
| +6. **P2 — Task 1, Step 3 / Task 5, Step 3: replacement acknowledgement is skipped when leaving `releasing`.** |
| + If the target terminates after the source journals its release, replacement adds a new participant while retaining `releasing` (**P:1891–1892, 1935–1936**). The next worker pass calls `PinAfterRelease`, which advances to `pinning` without checking acknowledgements (**P:1543–1556**). Spec §5.8 requires the replacement to acknowledge before leaving that phase. |
| + **Fix:** require the acknowledgement barrier in the `releasing → pinning` CAS. Test a replacement with its acknowledgement withheld after source release publication. |
| + |
| +I accept the author’s remaining rulings as scoped choices. Rulings **5/21, 9, 17 and 20** remain incompletely implemented for the reasons above. R3’s privilege split and R5’s retained consequences address the earlier requests; the missing production policy wiring needs an explicit implementation or upstream request. |
| + |
| +No files changed. **Verdict: not ready.** |
| \ No newline at end of file |