carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1# Astra review r4: settings-5-surfaces task 8 (tenant change resolves fresh)
2
3Range 5c57c95d..1b603228. Fixed in 3e24809f.
4
5Verdict: REJECT
6
7Reviewed only `5c57c95d..1b603228`, against the brief, report, prior reviews, rev 11, and R25–R27. **Go cannot run here; this is inspection only. No files modified.**
8
9## Findings
10
11### 1. [P2] Ignoring a legacy decision can allow a failed build to wake
12
13**Where:** [internal/host/buildstate.go:672](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-5-surfaces/internal/host/buildstate.go:672).
14
15**Scenario:** A same-tenant manual instance has T installed, a readable build state, and an untagged consumed decision recording `ReasonFailed`, `Detail: T`. There is no separate `RefusalNotUp` record, and the swap planner is disabled.
16
17The new attribution check removes that failure decision. `DecideHeldWake` now returns T with `AskRoot=true` and `Failed=false`. However, [awaitRootDecision](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-5-surfaces/internal/activator/wakecheck.go:193) immediately returns when T is already live; it neither requests nor awaits root. The wake proceeds, and pre-exec revalidation also admits T.
18
19The implementer’s report records the corresponding failed assertion in `TestAFailedInstalledBuildWithNoBuildStateIsHeldFailed`. Automatically tagging fixtures made that test pass, but removed its coverage of the legacy case.
20
21**Fix:** Make an unattributed held-wake decision actually wait for root’s attributed decision, including when the target is already installed. Add an explicitly untagged failed-decision regression through the wake path with no planner. Do not rely on `AskRoot` alone.
22
23### 2. [P2] Equivalent account identities lose same-tenant settings
24
25**Where:** [internal/registry/registry.go:1169](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-5-surfaces/internal/registry/registry.go:1169).
26
27**Scenario:** A legacy row has account `""`, app `km`, and manual or major settings. Re-adding that same app stamps account `bab` and supplies empty settings/build-state columns.
28
29`RouteAccount` treats both account spellings as `bab`; the consumed file remains same-tenant. The new SQL nevertheless identifies a tenant change and clears both columns. Root can adopt the channel head before reconciliation restores the hold. Restoring settings afterward cannot undo that installation.
30
31**Fix:** Compare effective account identities consistently with `RouteAccount`, preserving the columns for equivalent legacy identities. Test `""` ↔ `bab` explicitly, alongside genuine account-only changes with empty incoming settings.
32
33### 3. [P2] The new pre-exec tenant check fails open on a registry read error
34
35**Where:** [internal/host/buildstate.go:527](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-5-surfaces/internal/host/buildstate.go:527).
36
37**Scenario:** B owns the host, A’s consumed file remains, and `reg.Get` fails. Its error is discarded, leaving `rt=nil`; the new foreign-file check is skipped. `b.write` can then merge A’s resolution/completion into B’s durable build state. That object write happens before the registry-copy update, so even a subsequent registry error does not prevent contamination.
38
39The discarded error predates this commit, but the new isolation check depends on that read succeeding.
40
41**Fix:** Return the registry error before any build-state write. Add an injected read-error regression asserting that the durable object remains unchanged. Keep successful “row absent” handling separate from read failure.
42
43## Rulings
44
45- **R26: Partly agree; disagree with the held-wake safety claim.** Preserving untagged bookkeeping in root, pre-exec, and carry avoids losing file-only resolutions and failed completions. Rejecting tagged foreign files is correct. But treating an untagged decision as absent does **not** always hold execution until root responds; finding 1 demonstrates the exception.
46- **R27: Agree with the explicitly accepted migration cost.** A genuine effective-account change invalidates the old attribution, and a file-only completion or resolution can consequently be lost. Keeping the build-state watermark limits that exposure. This does not cover finding 2: `""` → `bab` leaves the effective tenant unchanged.
47
48## Deferred minors triage
49
50- **Raw SQL account comparison:** promote to must-fix, finding 2. The consequence can be an unwanted installation, not merely temporarily missing columns.
51- **Discarded `beforeExec` registry error:** promote to must-fix, finding 3. An unread tenant must not authorize merging hostname-keyed bookkeeping.
52
53The remaining inspected changes are sound:
54
55- For distinct canonical tenants, both SQL columns take incoming values, including empty values. Exact same-tenant preservation and the claim-ownership guard remain intact.
56- Root filters foreign data before both `TargetInput` constructions; `NextConsumed` independently prevents copying foreign bookkeeping.
57- The default-settings fresh write uses `publishConsumed` and its existing lock and route-hold recheck. It introduces no unfenced write; publication failure stops installation.
58- The new tests detect the principal foreign-file and column-carry defects. They do not cover the three findings above. The new default-route scenario also lacks a dedicated move-fence interleaving test, although it uses the existing fenced path.
59
60## Out of scope
61
62- Existing preservation of `good_version`, `good_digest`, `good_demand`, `serving_version`, and other unrelated columns across tenant changes.
63- Cleanup of retired hosts’ consumed files.
64- Copy approval and remaining branch-wide execution gates. Reported test/build results were not independently executed and do not alter this inspection verdict.