carlos / platform Public

Region HA plan 1b-next: Astra round 4 findings (7 resolved, 3 partly, 6 new; not ready), unedited

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev c0a67ce4ccf6f3dfe7126cff94fc4d239e1d2034 parent 418daf5
1 file changed, +46 −0
  • docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R4.md +46 −0
diff --git a/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R4.md b/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R4.md
new file mode 100644
index 000000000..5ad1e00e5
--- /dev/null
+++ b/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1BN-R4.md
@@ -0,0 +1,46 @@
+Reviewed `418daf58`. **P** 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`.
+
+| Round 3 finding or partial | Disposition | Assessment against rev 4 |
+|---|---|---|
+| R1-5 — immutable files pin | Resolved | **P:8221–8234** verifies against the retained manifest and its digest. |
+| R1-9 — release replay after restart | **Partly** | Recovery mode and recorded identity are supplied, but the initial request omits `Region` (**P:7470–7472**) while recovery adds it (**P:7752**). Region participates in 6b’s fence identity and receipt validation, preventing exact replay. Populate it initially and preserve it on recovery. |
+| R2-N4 — completed target remains held | Resolved | Serving reconcile can pass an obsolete hold and reach its clear. The new flag-off regression is reported below. |
+| R2-N5 — retained controller lifetime | Resolved for the reported timeout | The entry survives a cancelled close. Durable record clearing remains a separate omission below. |
+| N1 — missing adapter identifiers | **Partly, P1 remains** | `observed` and the fixture are supplied, but **P:9012** calls `f.withExistingRow()` without the string required at **P:8961**. **P:8887** also sets `EmptyInstallationCensus.Guard`, which the declared type does not contain (**6b:8380–8392**). Fix both and populate the census’s actual dependencies. |
+| N2 — premature controller removal | Resolved | **P:7317–7322** deletes the entry only after successful close. |
+| N3 — production provider wiring | **Partly** | **P:9301** captures `a.Reconcile.Box` before 6b initializes it. `OpenProductionClaimAssembly` returns an adapter with an empty box; `Build` sets it later (**6b:11471**). Bind the policy after actor verification and before policy capture. The fence observer also has the new deadlock below. |
+| N4 — fenced source’s hold | Resolved at the decision level | **P:9061–9066** selects the hold-only path for a fenced executor. That path is affected by the new deadlock below. |
+| N5 — exhausted target after local installation | Resolved | The worker uses the fence-consuming terminal transition without selecting another replacement. |
+| N6 — replacement acknowledgement | Resolved | **P:1651–1655** requires acknowledgements before leaving `releasing`. |
+
+New findings, ranked:
+
+1. **P1 — Tasks 3/9/10: the fence observer deadlocks reconciliation.**
+ **P:3517** makes `AdmissionFenced` acquire the host lock. Task 9 calls that observer from `Reconciler.check` (**P:9042**), which also runs inside `Guard.Activate` through `activationReader.Read`. The outer operation already holds the same lock. Task 10 supplies `context.Background()` (**P:9308**), so cancellation cannot end the inner wait. `holdOnly` repeats the problem inside `WithLocal` at **P:9091**.
+ **Fix:** expose the fence observation within the existing locked operation, without reacquiring the lock. Propagate the caller’s context and errors. Test both activation and hold-only reconciliation with the real observer and bounded deadlines.
+
+2. **P2 — Task 3, Step 4: the production policy refuses target probes.**
+ **P:3490–3491** sends every `spawn`, `seed`, and `writer` action to `WakePhase(c, box, false)`. A target in `probing` requires `probe=true`. The declared 6b runtime selects `"spawn"` work for preparation, while [`Selection`](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostbox/work.go:16) carries no probe authority. R1’s runtime dispatch therefore cannot satisfy this later policy check.
+ **Fix:** extend R1 to propagate explicitly scoped probe authority through selected work and the policy. Test a complete target probe through the production policy while ordinary target spawns remain refused.
+
+3. **P2 — Task 8c, Step 3: a fresh target lacks the directory that restore requires.**
+ **P:8451–8454** creates the relocation journal directory, then restores into `cfg.FilesDir(host)`. [`hostfiles.Restore`](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostfiles/restore.go:88) opens an existing directory. Reconcile supplies the row and inventory; 6b’s state-directory preparation occurs during the later probe. A fresh spare with a nonempty files manifest therefore fails before `local_install`.
+ **Fix:** create and inventory the destination directories under the installation’s authority before restoring. Test a target with no existing host directory; an untracked `MkdirAll` would conflict with 6b’s inventory checks.
+
+4. **P2 — Task 8c, Step 3: held release staging has no usable root relay.**
+ **P:8490–8492** returns every `MaterializeHeld` error. Moves Plan 1, Task 7b explicitly returns `ErrStageBlocked` under the production edge service’s filesystem restrictions and requires root staging. Its declared relay authorizer accepts only `moving` and `landing`, using a move source report, so it cannot authorize this relocation.
+ **Fix:** add or request relocation-aware root staging, bound to the operation, executor, installation stamp and release. Verify staging before recording the install receipt, and test with production filesystem restrictions.
+
+5. **P2 — Task 7, Step 4: completed relocations leave durable controller records that block platform updates.**
+ **P:7310–7326** closes the controller and deletes its in-memory entry. [`Controller.Close`](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostexec/controller.go:480) leaves the durable record in `lost`; [`ClearStale`](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/region-ha-1b-next/internal/hostexec/controller.go:554) removes it separately. Neither this plan nor 6b calls that clearing operation. Under spec §5.10, even a `lost` record blocks executable updates.
+ **Fix:** preserve cleanup results, clear the exact discharged record after successful cleanup, and retain retry state across restarts. Add a disk-backed completion test that checks update eligibility. A subsequent nil `Close` is insufficient evidence: repeated calls return nil even after an earlier cleanup error.
+
+6. **P2 — Task 3, Step 4: obsolete-hold clearing changes behavior with HA disabled.**
+ The bypass at **P:3431–3438** is unconditional. A serving reconcile with an obsolete hold now passes even when `Policy.Relocation` is nil—the HA-off configuration. Previously it returned `ErrChanged`. Task 10’s flag-gated wiring cannot prevent this change.
+ **Fix:** gate the bypass on an explicit HA-enabled capability and test the same held serving row with the flag both on and off.
+
+I accept rulings 1–23 as scoped decisions. Ruling 20’s lifecycle remains incompletely implemented. R1 needs the probe-authority contract above; R8 needs an insertion point where the verified box identity is available.
+
+All 11 embedded patches pass `git apply --check`. Compilation and test execution were not reproduced in this read-only sandbox. No files changed.
+
+**Verdict: not ready.**
\ No newline at end of file