carlos / platform Public

pro-6214-service-runs

Runs started by a scoped service credential (Linear PRO-6214). Fleet, Tito's back office, needs to run its Classic import and recurring sync through carlos run without a person's token. This amends run spec § 2 ruling 1, for the run role only.

  • Spec: docs/superpowers/specs/2026-10-24-service-runs-design.md
  • Plan: docs/superpowers/plans/2026-10-24-service-runs.md
  • Census card: docs/superpowers/notes/census-proposal-pro-6214-service-runs.md

What changes

  • The run role. Only svcrole.Exactly(Run) reaches it, and Allow(Run) panics, so Admin never reaches a run door.
  • The credential. It is app-bound and carries its own credential_id and its command prefixes: carlos services create --role run --app <app> --commands "import classic,import sync" <name>. Prefixes match word for word and fail closed. A prefix grant also covers every flag after it.
  • Six run doors. Create, get, cancel, expire, ack, and the new GET …/runs?key=. A service sees and acts on its own runs only.
  • The record. Runs record by_service, by_credential, on_behalf_of (as stated by the service) and the scoped idempotency_key.
  • Idempotency-Key. The key is settled in the instance record (run_keys, 24h, 32 per caller) by the same CAS that admits the run. Retries and concurrent twins never run a command twice.
  • The CLI. carlos run --idempotency-key. Run-handler refusals carry stable codes, documented in docs/site/cli.md.

Migration

On console start, cli_tokens gains credential_id and commands, a unique partial index on credential_id, and a one-time idempotent backfill of credential_id for existing service and app rows. The change is additive. An older console treats a run row as an unknown role, so it fails closed.

Landing — what an operator must do

  1. Merge and roll as usual. Roll every console and every box, in all regions, to a build containing this commit. Confirm with carlos system status.
  2. Only then set CARLOS_RUN_KEYS=on on the consoles. Until then, a keyed create answers 503 keys_not_ready. Unkeyed runs, for people and services, work from the roll.
  3. The gate is one-way. Once it is on, never roll a box or console back to a build without run_keys. Its next record write would drop the keys, and a retry could start a second run. If a rollback can't be avoided, set the env off first and stop keyed retries.
  4. Record growth. run_keys adds up to 32 entries (about 230 B each) per distinct caller per instance, pruned at 24h.
  5. Then Tito mints fleet-runs, as an account owner of tito: carlos services create --role run --app titogo --commands "<import prefix>,<sync prefix>" fleet-runs. Grant the narrowest words. Check the COMMANDS column with carlos services ls.
  6. Host-claim consoles still refuse every run, for everyone, until #250.

Review

  • Task reviews on Opus.
  • A whole-branch review by Fable, and another by Astra (gpt-6-astra, high). Every finding is addressed, including F1: a keyed run that the record holds is kept even if its key is gone.
  • Copy approved by Paul on 2026-10-24.
  • Census approved by Paul on 2026-10-24 and recorded on #280. Re-sealed onto main 3d7cbe30 with no change to the approved claims.

Squashed to one commit, 5c7b0fa6.

Commits 0
Discussions 0 0 open
Tasks 0/0 done

Discussions

  • No discussions on this branch yet.

Tasks

  • No tasks yet.

Activity

  • No activity yet.