| 1 | Reviewed `d30a74c2`. No files modified. Findings are based on source inspection; no tests were run. |
| 2 | |
| 3 | 1. **R1-1 — P1 — §7.2: A pipeline change can invalidate the scope decision before promotion.** |
| 4 | |
| 5 | The handler reads the pipeline at [apicli.go:772](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/console/apicli.go:772), where the proposed scope check would run. `PromoteOnLadder` independently reads it again at [release.go:930](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/release.go:930). |
| 6 | |
| 7 | An `edge` credential can pass the first check while no pipeline exists. If an owner then installs a pipeline beginning with `edge`, the second read selects that pipeline and permits a fresh release onto its entry channel. The credential has now written a non-canary pointer on a pipelined app, contrary to R2. Pipeline passkey or approval rules introduced between those reads are also missed: the release primitive checks order, while those rules were evaluated against the earlier snapshot. |
| 8 | |
| 9 | **Correction:** Define the concurrency contract for pipeline changes and pointer writes. Bind authorization and execution to the same pipeline generation, with serialization or equivalent conflict detection covering pipeline updates, promote and rollback. Add a test that installs a pipeline between authorization and execution. |
| 10 | |
| 11 | 2. **R1-2 — P1 — §7.1: The check admits bare `canary`, outside R2’s `canary/*` restriction.** |
| 12 | |
| 13 | `release.Rung("canary")` returns `("canary", true)` at [ladder.go:55](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/ladder.go:55). Consequently, all five proposed checks pass for a pipelined app and a credential holding `canary`. The downstream [PipelinePromotionAllowed](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/pipeline.go:327) also accepts it. Rollback can likewise move an existing bare-canary pointer. |
| 14 | |
| 15 | **Correction:** For pipelined apps, require a valid channel beneath `canary/`, in addition to checking the rung. Test bare `canary` explicitly for both verbs. |
| 16 | |
| 17 | 3. **R1-3 — P2 — §§6, 8: The promised service identity for `auth whoami` has no supported path.** |
| 18 | |
| 19 | [authWhoami](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/auth.go:785) reads the credentials file directly and never calls `resolveMode`. Changing `resolveMode` therefore leaves it reporting the stored person or failing when no file exists. Even if the environment token is passed explicitly, [handleCLIWhoami](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/console/authcli.go:1531) calls `cliUser`; [CLITokenAddress](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/console/authstore.go:515) refuses every service token. |
| 20 | |
| 21 | **Correction:** Specify the service identity endpoint, response fields and CLI resolution path. Reconcile that endpoint with §6’s exhaustive door list. Preserve the person-only gates on account creation and logout rather than widening the shared person resolver. |
| 22 | |
| 23 | 4. **R1-4 — P2 — §§1, 5.2, 7.4: Stable promotion does not have the claimed unconditional, independent refusal.** |
| 24 | |
| 25 | The promote handler refuses stable when there is no pipeline or when stable is outside the pipeline. A pipeline containing `stable` instead enters the declared-channel branch at [apicli.go:813](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/console/apicli.go:813), where only its configured rules apply. [Pipeline validation](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/pipeline.go:255) permits that name without requiring a passkey. Rollback does have an unconditional stable refusal. |
| 26 | |
| 27 | Thus §7.1 would protect deploy credentials, but §7.4’s claimed protection *independent of that function* does not exist for promotion. “A stable promote needs a passkey and always has” and the blanket description of publish’s stable exclusion are also inaccurate. |
| 28 | |
| 29 | **Correction:** Correct those claims and explicitly add the independent stable refusal for deploy principals if that defense is intended. Keep existing roles unchanged, as R1 requires. |
| 30 | |
| 31 | 5. **R1-5 — P2 — §7.1: Hotfix and fast-track are different authorities.** |
| 32 | |
| 33 | The rationale for refusing `hotfix` conflates skipping ladder order with waiving a bake window. [Signer.PromoteOnLadder](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/release.go:945) permits an in-scope scoped signer to skip order using `Hotfix`. The root-only restriction in [signPointer](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/release.go:386) checks `FastTrack`, a separate field. |
| 34 | |
| 35 | **Correction:** Describe the hotfix prohibition as an intentional restriction beyond scoped-key behavior. Retain it if intended, but distinguish order bypass from bake-window waiver and test them separately. |
| 36 | |
| 37 | 6. **R1-6 — P3 — §7.4: Console-mediated deployment can retain box-verified rung limits using existing primitives.** |
| 38 | |
| 39 | The stated exposure from root signing is accurate, but R3 and R4 do not require it. [MintKeyGrant](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/grant.go:80), [ScopedSigner](/home/paulca/amadan.net/carlos/platform/.claude/worktrees/design-deploy-credential/internal/release/signer.go:42), and signer methods for promotion and rollback already exist. The console could mint a short-lived, request-local scoped signer from the credential’s rungs and use it for that write. The runner would still hold only its service token; auditing and serial notification would remain console-mediated. |
| 40 | |
| 41 | **Correction:** Evaluate this alternative explicitly before discarding box-side enforcement. It protects against a missed rung check, though it does not protect against console compromise or independently enforce R2’s pipeline restriction. |
| 42 | |
| 43 | **Verdict: request changes.** |