carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1# Census approval: pro-6214-service-runs
2
3Approved by Paul (census owner), in session, 2026-10-24, at tip ffe8f40a. Re-sealed onto main 3d7cbe30 with no change to the approved claims.
4
5Ruling `census-ruling-pro-6214-service-runs`, asked of the census owner on
6#280 before the merge. Every row already carries it (#369). Branch
7`pro-6214-service-runs`. Spec:
8`docs/superpowers/specs/2026-10-24-service-runs-design.md` (Linear PRO-6214).
9
10The branch adds a service role, `run`, so that a server (Tito's Fleet) can
11start and follow `carlos run` runs without a person's token. It also adds
12idempotent run create (`Idempotency-Key`, recorded in the instance record's
13`run_keys`). No root read is added. The console units run in the console
14(`cmd/console serve`, user `carlos-console`), and the root `carlos` binary
15does not link `internal/console` (`TestRootBinaryLinksNoConsoleOrMail`). The
16CLI units run in `carlos run` as its caller.
17
18## What you are asked
19
20- **Approvals (22): 14 changed units and 8 envelopes.** Each changed unit
21 keeps its class and task and reads only the kinds it already read. 13 are
22 `body` changes. 1 is `sites`: `migrateCLIAuth` has one more SQLite `Exec`,
23 the new index. census-propose wrote these rows into
24 `plan14-root-reads-pro-6214-service-runs.tsv`, and their table is under
25 "Approvals" below.
26- **Decisions (6): 5 new units and 1 removed unit.** census-propose cannot
27 write these. They are hand-written in
28 `plan14-root-reads-pro-6214-service-runs-decisions.tsv`, which loads
29 before the approvals overlay. Each new unit is proposed as accepted legacy
30 at the class of the row it mirrors:
31
32 | decision | unit | proposed disposition | mirrors | reads | digest |
33 |---|---|---|---|---|---|
34 | new | `internal/console/apiruns.go` `Server.handleAPIRunKeyLookup` | legacy, accepted-legacy. **Authority: a run door** | `handleAPIRunGet` (census-ruling-carlos-run) | `file:Query@528`, which is `r.URL.Query()` (the key), not a file; then the instance record from the deployment bucket. Writes nothing | `635e57ad…076e` |
35 | new | `internal/console/authstore.go` `Store.backfillCredentialIDs` | legacy, accepted-legacy (J4) | `migrateCLIAuth` (J4 root-input) | `file:Query@62`, `file:Exec@554` on the console's own `cli_tokens`; it sets an id only where none is set | `3fbb21ec…48b5` |
36 | new | `internal/console/authstore.go` `newCredentialID` | legacy, accepted-legacy (J4) | `newStore` (email-signin), `Keymail.sealEnvelope` (console-invite-delivery) | `file:Read@78`, a 16-byte `crypto/rand.Read`: an identity, not a secret | `57049041…0cb5` |
37 | new | `run.go` `runFileSum` | legacy, accepted-legacy | `runMetaFor` (census-ruling-carlos-run) | `file:Open@58` of a `--file` path the caller named, hashed to EOF; only with `--idempotency-key` | `745fa0d0…6991` |
38 | new | `auth.go` `consoleClient.doMultipartHeaders` | legacy, accepted-legacy (J4) | `consoleClient.doMultipartMethod` (J4 root-input) | `file:ReadAll@1418` of the console's response body: `doMultipartMethod`'s body, moved, plus extra request headers that cannot override the content type or the bearer | `4682be87…c17b` |
39 | removed | `auth.go` `consoleClient.doMultipartMethod` | H3 census-ruling removal | zddr3's and email-signin's form | still declared and reads nothing: it calls `doMultipartHeaders` with no headers | |
40
41- **Record-write census (9B8): 6 entries re-digested, classes and kinds
42 unchanged** (`internal/provision/service_runs_census_test.go`, hand-written
43 as 9B8 still requires). They are `admitRun` (record-writer,
44 `key:SetRecordRun`: it passes the key, digest and caller to `RunAdmit`,
45 and the key is written by the same CAS), `handleAPIRunAck`, `Cancel` and
46 `Expire` (refusal codes only), `auditRunEnd` (nonrecord, the requester
47 line), and `registerCLIRoutes` (key-site: the run doors move to
48 `svcrole.Exactly(svcrole.Run)`, plus one route for the key lookup).
49 `RunAdmit` names no census identifier, so it is not a 9B8 site.
50
51## The four units that carry authority
52
53The census classes are all accepted legacy, because nothing here is root
54authority. The branch does grant authority, though, and these four are where
55it lives:
56
571. **The run doors.**
58 - `Server.handleAPIRunCreate` (approval) and the new
59 `Server.handleAPIRunKeyLookup` (decision). The follow doors
60 `handleAPIRunGet`, cancel, expire and `handleAPIRunAck` reach a service
61 only through `runGate`, which has no scanned site and is pinned by the
62 `internal/console` envelope.
63 - They admit a service principal only with role `run` and a credential
64 id. The route sets are `svcrole.Exactly(Run)`, so Admin does not reach
65 them.
66 - A service runs only an argv that starts, word for word, with a prefix
67 its credential was minted with. It sees and acts on only the runs its
68 credential id started; any other answers 404.
69 - `on_behalf_of` is recorded on the service's word, shape-checked as an
70 email, and grants nothing.
712. **`provision.RunAdmit`** (approval).
72 - Admission and the idempotency dedupe are one compare-and-swap.
73 - Keys are pruned at 24 hours, each caller keeps its newest 32, and a
74 key is stored hashed with its caller.
75 - Only `RunAdmit` assigns `RunKeys` (`TestOnlyRunAdmitWritesRunKeys`).
763. **The mint, `Store.claimRawNewServicePrincipalScoped`** (approval).
77 - It is the only writer of a run credential, and is reached from the two
78 owner-gated mint doors. The API door is registered `svcrole.Set{}`, so
79 no service credential can mint one.
80 - A run credential needs an app and 1 to 32 valid command prefixes.
81 - Every mint draws a fresh `credential_id`, so a revoked name minted
82 again owns none of the old runs.
834. **The read, `Store.CLIPrincipal`** (approval).
84 - A run row resolves only with an app, a `credential_id`, and a command
85 list in the exact canonical form this console writes. Anything else
86 does not resolve: it fails closed.
87
88## Seal
89
90The chain ends at main's `edge-asset-cache-2` (3d7cbe30): `de15b849…7069`.
91
92- The decisions overlay adds five frozen declarations:
93 `ec2d8daaec385b34b3be9c8c6430427c082ac36cd40150e1c6f520e20e3da72d`.
94- The approvals overlay re-freezes fourteen:
95 `86570d1326baad6d866b4066b6bf65218434b201fb1f2c05ebc6e3c79f9c5a98`.
96
97Both lines are in `plan14-root-reads-chain.tsv`, after main's.
98
99At the approved tip ffe8f40a the chain ended at `sec-host-imdsv2-module`
100(`945934f5…6c6a`), and the seals were `bcad5454…89a2` and `b9f9c8c7…975c`.
101Re-sealing changed only seals, fingerprints and the chain order, with one
102exception: `cmd/console/main.go` `serve`, which main's sec-sidecar-create-gate
103and sec-mail-user-boundary also changed. Its row now carries their two
104rulings in its inherited basis, and its digest and data-literal offsets
105moved (`@4601,@5702,@5939`, still three). Its claim, class and task are the
106ones approved. The `.`, `cmd/console` and `internal/console` envelopes now
107also cover main's code.
108
109Re-running `make census-propose NAME=pro-6214-service-runs` rewrites the
110section below and replaces this whole file. Restore the sections above
111after a re-run.
112
113## Approvals (written by census-propose)
114
115Ruling `census-ruling-pro-6214-service-runs`. Every change below keeps the disposition it already has, so it needs an approval, not a decision.
116
117| unit | change | read sites | what changed |
118|---|---|---|---|
119| `cmd/console/main.go` `serve` | body | unchanged (3) | the console (cmd/console serve, user carlos-console): reads CARLOS_RUN_KEYS, an environment variable, into Config.RunKeysEnabled; keyed run creates are refused 503 keys_not_ready unless it is on; the same three /data literals; no read added |
120| `internal/console/apiruns.go` `Server.handleAPIRunCreate` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): AUTHORITY (the run doors): also admits a run service (runCaller: role run with a credential id, after the unchanged shared gate and the route's svcrole.Exactly(Run), which Admin does not join); a service's argv must start word for word with one of its granted prefixes (runs.CommandGranted), else 403 command_not_granted before any object is written; on_behalf_of only from a service, one bare email of at most 254 bytes, never checked against membership, granting nothing; a keyed create (Idempotency-Key, only with CARLOS_RUN_KEYS=on) answers a key the record's run_keys holds for this caller before the record refusals and without reading a file (same digest: 202 replayed; another: 409); keyed files must declare and match their sha256; records by_service, by_credential, on_behalf_of and the scoped key hash; an open-run refusal is redacted for another caller's run; refusal codes; its one site is still rec.ActiveRun.Open(), a method, not a file; no read added (the record and request.json from the deployment bucket, as before) |
121| `internal/console/apirunsfollow.go` `Server.handleAPIRunAck` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): AUTHORITY (the run doors, via runGate): a run service acks only its own runs; refusal codes; RunClear unchanged and leaves run_keys as they are; its one site, run.Open(), a method, moves; no read added |
122| `internal/console/apirunsfollow.go` `Server.handleAPIRunGet` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): AUTHORITY (the run doors, via runGate): a run service reaches it only for a run whose request.json records its credential id, any other answering 404 as an unknown id; refusal codes; the same r.URL.Query() site; no read added |
123| `internal/console/apirunsfollow.go` `Server.runTransitionRefused` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): refusal codes only (run_started, run_ended and the shared codes); its one site, run.Open() on the record's run state, a method, moves; no read added |
124| `internal/console/authstore.go` `Store.CLITokens` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): its Query also selects cli_tokens.commands; the same Query site; no read added |
125| `internal/console/authstore.go` `Store.claimRawNewAppToken` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): the legacy app token's INSERT also writes a fresh credential_id (newCredentialID); the same Exec site; no read added |
126| `internal/console/svcprincipal.go` `Store.CLIPrincipal` | body | unchanged (2) | the console (cmd/console serve, user carlos-console): AUTHORITY (the credential read): its cli_tokens QueryRow also selects credential_id and commands; a run row resolves only with an app, a credential_id and a command list that parses, passes runs.CheckCommandPrefixes and is byte-identical to the canonical JSON this console writes, else it does not resolve (fail closed, the deploy rungs rule's twin); any other role carrying commands does not resolve; the same QueryRow and last_used Exec sites; no read added |
127| `internal/console/svcprincipal.go` `Store.ServicePrincipals` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): its Query also selects cli_tokens.commands for the account's service listing; the same Query site; no read added |
128| `internal/console/svcprincipal.go` `Store.claimRawNewServicePrincipalScoped` | body | unchanged (2) | the console (cmd/console serve, user carlos-console): AUTHORITY (the mint): the only writer of a run credential, from the two owner-gated mint doors (POST /api/cli/services/{account}, registered svcrole.Set{} so no service credential reaches it, and the settings page behind serviceOwner); a run credential must name an app and 1 to 32 valid command prefixes, takes no rungs, and other roles may not name commands; stores the list as canonical JSON in cli_tokens.commands and a fresh credential_id on every mint, including a reused revoked name; the same QueryRow and INSERT Exec sites; no read added |
129| `internal/console/templates/account_settings.html` `external` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): embedded UI: a Commands column, the minted line names a run credential's commands, and a commands input on the mint form; markup only; no read added |
130| `internal/provision/run.go` `RunAdmit` | body | unchanged (1) | the console (cmd/console serve, user carlos-console): AUTHORITY (RunAdmit): still applied only by the create door's admitRun through SetRecordRun's unchanged read-CAS-write; prunes run_keys older than 24h on every admission; a keyed admission checks its key before every refusal (same digest: *RunKeyReplay; another: ErrRunKeyReused; neither changes the record); a keyed admission that succeeds appends {key, run_id, digest, caller, at} and keeps each caller's newest 32, in the same write that queues the run; refusals and the queued RunState unchanged; within internal/provision only RunAdmit assigns RunKeys (TestOnlyRunAdmitWritesRunKeys); its one site is still rec.ActiveRun.Open(), a method; no read added |
131| `run.go` `runMetaFor` | body | unchanged (1) | the carlos CLI on the caller's own machine, as that caller: with --idempotency-key it also declares each --file's sha256 (runFileSum, a new unit); the same Stat of the path the caller named; no read added here |
132| `internal/console/authstore.go` `Store.migrateCLIAuth` | sites | +file:Exec | the console (cmd/console serve, user carlos-console): one more Exec of the kind it already makes: SQLite DDL on its own database, the partial unique index cli_tokens_credential_id; the ALTER loop adds credential_id and commands (TEXT NOT NULL DEFAULT ''); then calls backfillCredentialIDs; additive; no new kind of read |
133
134Envelopes re-pinned: `.`, `cmd/console`, `internal/console`, `internal/console/templates`, `internal/host`, `internal/provision`, `internal/runs`, `internal/svcrole`.
135
136Seal: `ec2d8daaec385b34b3be9c8c6430427c082ac36cd40150e1c6f520e20e3da72d` → `86570d1326baad6d866b4066b6bf65218434b201fb1f2c05ebc6e3c79f9c5a98`.
137
138Overlay: `internal/provision/testdata/plan14-root-reads-pro-6214-service-runs.tsv`, appended to `internal/provision/testdata/plan14-root-reads-chain.tsv`.
139