plan: region HA 1a rev 5, answering Astra plan round 4 (LoadWake)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+54
−7
docs/superpowers/plans/2026-10-05-region-ha-1a-foundations.md+37 −7docs/superpowers/plans/CODEX-PLAN-REGION-HA-1A-BRIEF-5.md+17 −0
CI cancelled — superseded by a newer push — run details
diff --git a/docs/superpowers/plans/2026-10-05-region-ha-1a-foundations.md b/docs/superpowers/plans/2026-10-05-region-ha-1a-foundations.md| index 49ef606a4..1496539f1 100644 |
| --- a/docs/superpowers/plans/2026-10-05-region-ha-1a-foundations.md |
| +++ b/docs/superpowers/plans/2026-10-05-region-ha-1a-foundations.md |
| @@ -5440,6 +5440,27 @@ func TestLoadWakeWithNoneReportsNotFound(t *testing.T) { |
| } |
| } |
| +// A manifest that names wake state whose object has gone is lost data, |
| +// not a host without timers. |
| +func TestLoadWakeWithItsObjectMissingIsAnError(t *testing.T) { |
| + ctx, s := context.Background(), release.NewDirStore(t.TempDir()) |
| + p := open(t, s) |
| + if err := StageWake(ctx, p, WakeState{V: 1, Host: "shop.test", NextDue: 5}); err != nil { |
| + t.Fatal(err) |
| + } |
| + commit(t, p) |
| + m, _, err := Load(ctx, s, pfx) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := s.Delete(ctx, pfx+m.Platform[WakeItem].Object); err != nil { |
| + t.Fatal(err) |
| + } |
| + if _, found, err := LoadWake(ctx, s, pfx, m); err == nil || found { |
| + t.Fatalf("found = %v, err = %v; a missing wake object must be an error", found, err) |
| + } |
| +} |
| + |
| func TestImportWakeRefusesAnotherHostsState(t *testing.T) { |
| r := wakeReg(t) |
| seedHost(t, r, "shop.test") |
| @@ -5501,9 +5522,7 @@ package hostfiles |
| import ( |
| "context" |
| "encoding/json" |
| - "errors" |
| "fmt" |
| - "os" |
| "github.com/carlosframework/platform/internal/registry" |
| "github.com/carlosframework/platform/internal/release" |
| @@ -5608,15 +5627,18 @@ func StageWake(ctx context.Context, p *Publisher, ws WakeState) error { |
| return p.StagePlatform(ctx, WakeItem, body) |
| } |
| -// LoadWake reads the wake state a manifest carries. The bool is false when |
| -// it carries none. |
| +// LoadWake reads the wake state a manifest carries. The bool is false only |
| +// when the manifest has no wake entry at all. A manifest that names wake |
| +// state whose object is missing or damaged is an error: that is lost |
| +// timers, not a host with none, and the caller must not install as if it |
| +// were. |
| func LoadWake(ctx context.Context, s release.Store, prefix string, m Manifest) (WakeState, bool, error) { |
| - body, err := ReadPlatform(ctx, s, prefix, m, WakeItem) |
| - if errors.Is(err, os.ErrNotExist) { |
| + if _, ok := m.Platform[WakeItem]; !ok { |
| return WakeState{}, false, nil |
| } |
| + body, err := ReadPlatform(ctx, s, prefix, m, WakeItem) |
| if err != nil { |
| - return WakeState{}, false, err |
| + return WakeState{}, false, fmt.Errorf("hostfiles: the manifest names wake state that cannot be read: %w", err) |
| } |
| var ws WakeState |
| if err := json.Unmarshal(body, &ws); err != nil { |
| @@ -6690,3 +6712,11 @@ Findings are in `CODEX-PLAN-REGION-HA-1A-R3.md`. Round 3 marked every round 2 fi |
| | 2 | P2 Task 5: syncing a directory that vanished under a replacement file | fixed: only directories that still exist as real directories are synced; tested with `a/b/c` becoming `a` | |
| | 3 | P2 Task 7: the held-open test did not need `IN_MODIFY` | fixed: a second write through the same open descriptor must be published | |
| | 4 | P2 Task 7: `-run Watcher` missed one real-inotify test | fixed: the test is renamed so all seven match | |
| + |
| +## Astra plan round 4: dispositions |
| + |
| +Findings are in `CODEX-PLAN-REGION-HA-1A-R4.md`. Round 4 marked every outstanding finding resolved, found no task that uses a later task's identifier, and raised one. |
| + |
| +| # | Finding | Disposition | |
| +|---|---|---| |
| +| 1 | P2 Task 8: wake state named by the manifest but missing its object read as "no wake state" | fixed: `LoadWake` reports absence only when the manifest has no wake entry; any failure to read a named entry is an error; `TestLoadWakeWithItsObjectMissingIsAnError` | |
diff --git a/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1A-BRIEF-5.md b/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1A-BRIEF-5.md| new file mode 100644 |
| index 000000000..0a19cab58 |
| --- /dev/null |
| +++ b/docs/superpowers/plans/CODEX-PLAN-REGION-HA-1A-BRIEF-5.md |
| @@ -0,0 +1,17 @@ |
| +# Review brief: region HA plan 1a (foundations), round 5 |
| + |
| +Read `CODEX-PLAN-REGION-HA-1A-BRIEF-1.md` first: its "Fixed: do not |
| +re-argue" and "What to check" sections still apply, to the plan at the |
| +commit named in the prompt. |
| + |
| +## Round 5 |
| + |
| +This revision answers your round 4 (`CODEX-PLAN-REGION-HA-1A-R4.md`): one |
| +finding, in `LoadWake` (Task 8). The change was dry-run with the wake |
| +tests. Give a disposition for it, then report only new findings that |
| +this change introduces, or anything in the plan that is still unsafe or |
| +would not build. Do not re-raise anything marked resolved in any round. |
| + |
| +## Output |
| + |
| +As round 1. End with a verdict: ready to build, or not ready. |