carlos / platform Public
Census approval: pro-6214-service-runs
Approved by Paul (census owner), in session, 2026-10-24, at tip ffe8f40a. Re-sealed onto main 3d7cbe30 with no change to the approved claims.
Ruling census-ruling-pro-6214-service-runs, asked of the census owner on #280 before the merge. Every row already carries it (#369). Branch pro-6214-service-runs. Spec: docs/superpowers/specs/2026-10-24-service-runs-design.md (Linear PRO-6214).
The branch adds a service role, run, so that a server (Tito's Fleet) can start and follow carlos run runs without a person's token. It also adds idempotent run create (Idempotency-Key, recorded in the instance record's run_keys). No root read is added. The console units run in the console (cmd/console serve, user carlos-console), and the root carlos binary does not link internal/console (TestRootBinaryLinksNoConsoleOrMail). The CLI units run in carlos run as its caller.
What you are asked
- Approvals (22): 14 changed units and 8 envelopes. Each changed unit keeps its class and task and reads only the kinds it already read. 13 are
bodychanges. 1 issites:migrateCLIAuthhas one more SQLiteExec, the new index. census-propose wrote these rows intoplan14-root-reads-pro-6214-service-runs.tsv, and their table is under "Approvals" below. - Decisions (6): 5 new units and 1 removed unit. census-propose cannot write these. They are hand-written in
plan14-root-reads-pro-6214-service-runs-decisions.tsv, which loads before the approvals overlay. Each new unit is proposed as accepted legacy at the class of the row it mirrors:
| decision | unit | proposed disposition | mirrors | reads | digest | |---|---|---|---|---|---| | 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 | | 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 | | 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 | | 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 | | 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 | | 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 | |
- Record-write census (9B8): 6 entries re-digested, classes and kinds unchanged (
internal/provision/service_runs_census_test.go, hand-written as 9B8 still requires). They areadmitRun(record-writer,key:SetRecordRun: it passes the key, digest and caller toRunAdmit, and the key is written by the same CAS),handleAPIRunAck,CancelandExpire(refusal codes only),auditRunEnd(nonrecord, the requester line), andregisterCLIRoutes(key-site: the run doors move tosvcrole.Exactly(svcrole.Run), plus one route for the key lookup).RunAdmitnames no census identifier, so it is not a 9B8 site.
The four units that carry authority
The census classes are all accepted legacy, because nothing here is root authority. The branch does grant authority, though, and these four are where it lives:
- The run doors. -
Server.handleAPIRunCreate(approval) and the newServer.handleAPIRunKeyLookup(decision). The follow doorshandleAPIRunGet, cancel, expire andhandleAPIRunAckreach a service only throughrunGate, which has no scanned site and is pinned by theinternal/consoleenvelope. - They admit a service principal only with rolerunand a credential id. The route sets aresvcrole.Exactly(Run), so Admin does not reach them. - A service runs only an argv that starts, word for word, with a prefix its credential was minted with. It sees and acts on only the runs its credential id started; any other answers 404. -on_behalf_ofis recorded on the service's word, shape-checked as an email, and grants nothing. provision.RunAdmit(approval). - Admission and the idempotency dedupe are one compare-and-swap. - Keys are pruned at 24 hours, each caller keeps its newest 32, and a key is stored hashed with its caller. - OnlyRunAdmitassignsRunKeys(TestOnlyRunAdmitWritesRunKeys).- The mint,
Store.claimRawNewServicePrincipalScoped(approval). - It is the only writer of a run credential, and is reached from the two owner-gated mint doors. The API door is registeredsvcrole.Set{}, so no service credential can mint one. - A run credential needs an app and 1 to 32 valid command prefixes. - Every mint draws a freshcredential_id, so a revoked name minted again owns none of the old runs. - The read,
Store.CLIPrincipal(approval). - A run row resolves only with an app, acredential_id, and a command list in the exact canonical form this console writes. Anything else does not resolve: it fails closed.
Seal
The chain ends at main's edge-asset-cache-2 (3d7cbe30): de15b849…7069.
- The decisions overlay adds five frozen declarations:
ec2d8daaec385b34b3be9c8c6430427c082ac36cd40150e1c6f520e20e3da72d. - The approvals overlay re-freezes fourteen:
86570d1326baad6d866b4066b6bf65218434b201fb1f2c05ebc6e3c79f9c5a98.
Both lines are in plan14-root-reads-chain.tsv, after main's.
At the approved tip ffe8f40a the chain ended at sec-host-imdsv2-module (945934f5…6c6a), and the seals were bcad5454…89a2 and b9f9c8c7…975c. Re-sealing changed only seals, fingerprints and the chain order, with one exception: cmd/console/main.go serve, which main's sec-sidecar-create-gate and sec-mail-user-boundary also changed. Its row now carries their two rulings in its inherited basis, and its digest and data-literal offsets moved (@4601,@5702,@5939, still three). Its claim, class and task are the ones approved. The ., cmd/console and internal/console envelopes now also cover main's code.
Re-running make census-propose NAME=pro-6214-service-runs rewrites the section below and replaces this whole file. Restore the sections above after a re-run.
Approvals (written by census-propose)
Ruling census-ruling-pro-6214-service-runs. Every change below keeps the disposition it already has, so it needs an approval, not a decision.
| unit | change | read sites | what changed | |---|---|---|---| | cmd/console/main.go serve | body | unchanged (3) | the console (cmd/console serve, user carlos-console): reads CARLOSRUNKEYS, an environment variable, into Config.RunKeysEnabled; keyed run creates are refused 503 keysnotready unless it is on; the same three /data literals; no read added | | 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 commandnotgranted before any object is written; onbehalfof 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 CARLOSRUNKEYS=on) answers a key the record's runkeys 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 byservice, bycredential, onbehalfof 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) | | 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 runkeys as they are; its one site, run.Open(), a method, moves; no read added | | 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 | | internal/console/apirunsfollow.go Server.runTransitionRefused | body | unchanged (1) | the console (cmd/console serve, user carlos-console): refusal codes only (runstarted, runended and the shared codes); its one site, run.Open() on the record's run state, a method, moves; no read added | | internal/console/authstore.go Store.CLITokens | body | unchanged (1) | the console (cmd/console serve, user carlos-console): its Query also selects clitokens.commands; the same Query site; no read added | | 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 credentialid (newCredentialID); the same Exec site; no read added | | internal/console/svcprincipal.go Store.CLIPrincipal | body | unchanged (2) | the console (cmd/console serve, user carlos-console): AUTHORITY (the credential read): its clitokens QueryRow also selects credentialid and commands; a run row resolves only with an app, a credentialid 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 lastused Exec sites; no read added | | internal/console/svcprincipal.go Store.ServicePrincipals | body | unchanged (1) | the console (cmd/console serve, user carlos-console): its Query also selects clitokens.commands for the account's service listing; the same Query site; no read added | | 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 clitokens.commands and a fresh credentialid on every mint, including a reused revoked name; the same QueryRow and INSERT Exec sites; no read added | | `internal/console/templates/accountsettings.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 | | 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 | | 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 | | 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 clitokenscredentialid; the ALTER loop adds credentialid and commands (TEXT NOT NULL DEFAULT ''); then calls backfillCredentialIDs; additive; no new kind of read |
Envelopes re-pinned: ., cmd/console, internal/console, internal/console/templates, internal/host, internal/provision, internal/runs, internal/svcrole.
Seal: ec2d8daaec385b34b3be9c8c6430427c082ac36cd40150e1c6f520e20e3da72d → 86570d1326baad6d866b4066b6bf65218434b201fb1f2c05ebc6e3c79f9c5a98.
Overlay: internal/provision/testdata/plan14-root-reads-pro-6214-service-runs.tsv, appended to internal/provision/testdata/plan14-root-reads-chain.tsv.