# Review brief: the deploy credential spec

You are Astra reviewing a design spec independently of its author. Your
output is a findings report, not an edit. Do not modify any file.

## What to read

1. The spec under review:
   `docs/superpowers/specs/2026-10-05-deploy-credential-design.md`.
   §3's rulings R1 to R4 are fixed. Report a mechanism that fails one. Do
   not re-argue one.
2. The code it fits into, in this worktree:
   - `internal/svcrole/svcrole.go` (roles, `Allow`, `Permits`);
   - `internal/console/authcli.go` (`cliRoute` near 411, the route table
     from 470 to 740, how a principal is resolved from a bearer token);
   - `internal/console/svcprincipal.go` (`Principal`,
     `NewServicePrincipal`, rotate, revoke) and
     `internal/console/authstore.go` (the `cli_tokens` schema near 183 to
     255);
   - `internal/console/apicli.go` (`apiAccountAppBy` near 58,
     `handleAPIPromote` near 701, `handleAPIRollback` near 970,
     `handleAPIShip` near 1569);
   - `internal/console/controlplane.go` (`refuseServiceControlPlane`);
   - `internal/console/apiservices.go` and `internal/console/svcpage.go`
     (the two mint doors);
   - `internal/release/ladder.go`, `grant.go`, `signer.go`, `pipeline.go`,
     `serial.go`;
   - the CLI at the repo root: `apimode.go` (`resolveMode`), `auth.go`,
     `services.go`, `canary.go`, and the promote, rollback and ship verbs
     in `cli.go`;
   - `README.md` lines 100 to 185, and `docs/site/cli.md` around 1319 to
     1440.

## What matters most

- **Escapes from the rung scope.** Look for any way a `deploy` credential
  moves a pointer outside its rungs: a channel name `release.Rung` maps
  unexpectedly, the proposal path, a pending approval it can create or
  execute, rollback's own paths, the hotfix flag, a pipelined app whose
  pipeline names a rung, a version-target or tag door, or any other door
  on the §6 list that writes more than the spec says. Check §7.1's order
  and §7.2's placement against the handlers as written.
- **Doors.** Is §6's list complete for `carlos ship`, `promote`,
  `rollback` and `channels` in API mode as the CLI actually calls them?
  Does any door on the list expose or change more than a deploy pipeline
  needs? Is anything missing that makes the CLI fail?
- **Mint and read-back (§5).** Can either mint door bypass the rules? Can
  rotate, or any other write to `cli_tokens`, produce a `deploy` row with
  no rungs or a non-`deploy` row with rungs? Is fail-closed at resolve
  achievable where the spec puts it?
- **Mixed versions (§9).** Is "an old console refuses an unknown role at
  every door" true of `cliRoute` as written? Is there any path that
  resolves a service token without going through `cliRoute`, or treats an
  unknown role as something permissive?
- **The CLI in CI (§8).** Does reading `CARLOS_SERVICE_TOKEN` in
  `resolveMode` collide with anything: the in-instance variable of the
  same name, box-side callers, `carlos auth` verbs, the `--owner` path?
  Is the refusal beside a store variable consistent with the existing
  `--console` ruling?
- **§7.4's trade.** The limit moves from a grant every box verifies to a
  check in the console. Is the exposure stated honestly? Is there a cheap
  way to keep a box-side check that the spec missed, without breaking R3
  or R4?
- **Claims about the code.** Every `file:line` and every "already does"
  claim: check it at this commit. Report each one that is wrong.

## How to report

Number findings R1-1 onward. For each: severity (P1 breaks a trust
guarantee or makes the design unbuildable; P2 a contract or claim defect
to fix before the plan; P3 advisory), the section, the problem, the
evidence with citations, a proposed correction. End with a verdict:
accept, accept with corrections, or request changes. Do not soften, do
not pad, do not restate the spec.

## Round 2

Rev 2 answers your round 1 (`CODEX-FINDINGS-DEPLOY-CREDENTIAL-R1.md`); §15
lists each disposition. Read rev 2 cold, then check:

- Does each accepted finding's fix actually close it, as written?
- §7.2: is "one snapshot, equivalent to promote-then-install" true of
  `PromoteOnLadder` and `Signer.Rollback` as they are? Is there any state a
  `deploy` credential can produce that no serial order produces? Is
  declining full serialization defensible, or does it leave R2 open?
- §7.4: can the console mint and use a request-local grant the way the
  spec says, with `MintKeyGrant`, `ScopedSigner` and `verifyPointer` as
  written? Check the minted-at lower bound, the five-minute lifetime
  against `promoted_at`, history and tag writes that a scoped signer makes
  or cannot make, and whether any box-side verifier rejects a grant it has
  not seen before.
- Anything the rev 2 changes broke that rev 1 had right.

Number findings R2-1 onward. Same severities, same verdict line.

## Round 3

Rev 3 answers your round 2 (`CODEX-FINDINGS-DEPLOY-CREDENTIAL-R2.md`); §15
lists each disposition. R2-1 is accepted in part: the serializability
claim is withdrawn, the hook moves between the pointer read and the
pointer write, and §7.2 states invariant I1 and one window it does not
cover. Whether to close that window is put to Paul in §16 and is not
yours to rule on. What is yours:

- **Is I1 true** of the mechanism as written, for `Signer.Promote` and
  `Signer.Rollback` as they are in this worktree? Give an interleaving
  that breaks (a) or (b) if one exists.
- **Is the uncovered window stated completely?** Give any outcome a
  `deploy` credential can produce that is neither forbidden by I1 nor
  inside the window §7.2 names. Consider first promotes (no pointer, a
  create-only write), the no-op path, rollback's history, the handler's
  proposal path, and conflict handling.
- Does the hook's placement change behaviour for a caller that passes no
  hook?
- Anything rev 3 broke that rev 2 had right, and any wrong citation.

Number findings R3-1 onward. Same severities, same verdict line.

## Round 4

Rev 4 answers your round 3 (`CODEX-FINDINGS-DEPLOY-CREDENTIAL-R3.md`); §15
lists each disposition. I1 is gone. §7.2 now claims two properties, G1 and
G2, and one sentence for what they leave open. Whether to close that gap
is §16, Paul's decision, and not yours to rule on. What is yours:

- **Are G1 and G2 true** of the mechanism as written, for a first promote,
  a replacing promote, a repeat promote and a rollback, against
  `DirStore` and `S3Store` as they are? Give an interleaving that breaks
  either.
- **Is the open sentence complete?** Give any outcome a `deploy`
  credential can produce that G1 and G2 do not forbid and that sentence
  does not describe. A new member of the class the sentence already
  describes is not a finding; say so if that is all you find.
- Are the three hook call points consistent with each other and with the
  handler's own check? Can any path reach a write, a proposal or a
  success response for a `deploy` credential without the hook having run
  on a pipeline read at least as recent as the spec says?
- Is §12's randomized test specified well enough to catch the faults of
  rounds 1 to 3? Would its two mutants fail it?
- Anything rev 4 broke, and any wrong citation.

Number findings R4-1 onward. Same severities, same verdict line.

## Round 5

Rev 5 answers your round 4 (`CODEX-FINDINGS-DEPLOY-CREDENTIAL-R4.md`); §15
lists each disposition. G2 is now stated per backend, and §12's randomized
test asserts G1 and G2 only, on recorded events. The directory store's
cross-handle limit is recorded in §14 as existing and separate; §16 is
still Paul's.

Check that the two round 4 fixes close what you found, that the oracle as
now written is implied by G1 and G2 and that both mutants fail it, and
that rev 5 broke nothing and cites correctly. If you have no finding at P1
or P2, say so and give the verdict.

Number findings R5-1 onward. Same severities, same verdict line.
