| 1 | Verdict: REJECT |
| 2 | |
| 3 | 1. **Important — [internal/release/materializeheld.go:108](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-2-promotion-records/internal/release/materializeheld.go:108): A digested head admits an undigested history target.** |
| 4 | `r.Admit` checks the head’s digest. If that passes but `p.DigestOf(version)` is empty, `HeldAuthorized` still returns success with no digest binding. |
| 5 | |
| 6 | **Failure:** A signed pointer has head `v2` with a digest and legacy history entry `v1` without one. `v1` has no promotion record. Replace its unsigned manifest and artifacts, then request a held stage of `v1`: the replacement bytes pass even with `CARLOS_REQUIRE_POINTER_DIGEST=true`. This bypasses the protection against undigested historical targets in §4.6. |
| 7 | |
| 8 | **Fix:** Reject a digestless history entry when its channel carries digests; continue looking for valid alternative evidence. Add a mixed-head/history regression test that checks both refusal and absence of downloaded artifacts. The existing ratchet test exercises only wholly digestless pointers. |
| 9 | |
| 10 | 2. **Important — [internal/release/materializeheld.go:93](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-2-promotion-records/internal/release/materializeheld.go:93): Verified pointers can escape the ratchet’s memory.** |
| 11 | The version-name check skips `Admit` after successfully verifying a pointer that names another build. §4.6 requires remembering that the box has verified digests for that channel. |
| 12 | |
| 13 | **Failure:** While authorizing `v1` through channel B, the box verifies channel A’s digested pointer for legacy build `v2`, but records no mark. Later, a saved digestless A pointer is replayed alongside substituted `v2` bytes. With the fleet-wide flag off and no promotion record for this legacy build, a held stage of `v2` succeeds. |
| 14 | |
| 15 | **Fix:** Separate observing a verified digested pointer from selecting evidence for this request. Remember every such observation, preserving fail-closed behavior after persistence failures. Replace `TestHeldAuthorizedAdmitsOnlyNamingPointers`’s no-mark assertion with a two-pass replay test; its current assertion protects the wrong behavior. |
| 16 | |
| 17 | 3. **Important — [internal/release/promotion.go:124](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-2-promotion-records/internal/release/promotion.go:124): Fleet boxes cannot read promotion records.** |
| 18 | The new reader requests `releases/<acct>/<app>/promoted/<version>`, but `internal/edge/storedoor.go:425` grants no reads under `releases/`. The fleet client converts the resulting 404 into `os.ErrNotExist`, which becomes `ErrNoPromotionRecord`. |
| 19 | |
| 20 | **Failure:** A validly authorized build outside pointer history cannot be staged on a box using the fleet HTTPS store. Explicitly authorizing it again cannot repair this. If a legacy pointer still names it, the reader instead falls back to weaker evidence despite the existing digest-bound record. |
| 21 | |
| 22 | **Fix:** Grant fleet read access to the exact promotion-record shape within its own account. Keep writes and other accounts denied. Add a test through the actual store door and fleet client, covering record-only authorization and digest-mismatch refusal. |
| 23 | |
| 24 | 4. **Minor — [internal/updatewords/words_authorize.go:43](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/settings-2-promotion-records/internal/updatewords/words_authorize.go:43): “Nothing was signed” is substantively false after a write error.** |
| 25 | Signing occurs before `Put`, and a failed response does not establish that storage rejected the write. |
| 26 | |
| 27 | **Failure:** Storage commits the authorization but the response times out. The console tells the member nothing was signed, although the build is now authorized. |
| 28 | |
| 29 | **Fix:** Report that authorization could not be confirmed, or verify the stored record before reporting the outcome. This is an accuracy issue, independent of copy style. |
| 30 | |
| 31 | ## Rulings |
| 32 | |
| 33 | **R13:** Disagree with checking whether the pointer names the requested version *before* updating the ratchet. That contradicts §4.6’s “once verified” rule and produces finding 2. The distinction between transient failures and definitive refusals should remain. |
| 34 | |
| 35 | ## Deferred minors that must be fixed before merge |
| 36 | |
| 37 | None of the ledger’s deferred minors independently warrants blocking merge. Findings 1–3 and their regression coverage do. |
| 38 | |
| 39 | Read-only source review against merge base `412ca787`; no files changed or tests executed. |
| 40 | --- |
| 41 | |
| 42 | **Controller response (fix wave 1, commits 6f79b01d, 0fc74c11, 2c3f0ad8).** All four findings accepted; none rejected. |
| 43 | |
| 44 | - Finding 1 (Ruling R16): a naming pointer whose entry for the version has no digest, on a channel that carries digests, is not held-stage evidence; HeldAuthorized skips it and keeps looking. Cost if wrong: a legacy history build on a now-digested channel needs `carlos releases authorize` before a move can stage it. |
| 45 | - Finding 2 (Ruling R15, revising R13's ordering): HeldAuthorized admits every verified pointer it reads through the ratchet, then selects evidence among those naming the version; R13's retry/skip split stands for naming pointers. Cost if wrong: an unrelated channel's mark is written during a held stage, as adoption would write it. |
| 46 | - Finding 3 (Ruling R17): the fleet store door grants GET of exactly `releases/<sqid>/<app>/promoted/<version>` for the box's own account; no listing, no write, nothing else under `releases/`. Cost if wrong: a box can read its own account's signed build digests (no secret). |
| 47 | - Finding 4 (Ruling R18): the `settings.authorize.write-failed` draft no longer claims nothing was signed. Still a draft under copy review. |
| 48 | |
| 49 | Scoped re-review: CODEX-FINDINGS-SETTINGS-IMPL-2-R2.md (ACCEPT). |
| 50 | |