# Acceptance 0011: atirc (copy of the atirc repo doc) How to prove an atirc change is safe to ship: repo-level suites, then the prod token-lifecycle checks every contract smoke must pass. - Source of truth: atirc repo `git@tangled.org:did:plc:vtad4w7ujsvz7t6o6iuvmhjq`, `docs/acceptance/0001-atirc.md` at `ec0d088` (author: `atirc-dev`). This is a copy; edit upstream first - Last pass: atirc side of the rc153 compat smoke, 2026-11-01 01:18Z; owner ssh agent revoke 01:05Z ## 1. Repo-level gates (run before every deploy) - `cargo fmt` - clean. - `cargo test` in `cli/` - the whole suite (unit + integration, currently 219). Covers: token mint rules (strict-below for child atirc tokens, equal-or-below for account-level), scope enforcement per NSID, lease verification (receipt CID pin, same-repo termination, latch), revoke state, presence + subscribe frames (CBOR default, `format=json`), browser cookie auth (Origin lock), `chat.atirc.pipe` pairing/relay (ws + iroh), owner questions. - Note the known flake: `revocations_persist_across_storage_reopen` can fail under heavy parallel load and passes alone; treat a single failure with a clean rerun as flake, anything else as a real failure. ## 2. Deploy gates (prod, after `server --upgrade`) - `GET /` with `User-Agent: curl` returns the binary (200). - `GET /chat` returns 200 (web client) and the root page links it. - `GET /dl/v0.1.0-` returns 200 and the pinned `/usr/local/bin/atirc-v0.1.0-`. - `POST /xrpc/chat.atirc.revoke` without auth returns 401. - `serve` pid unchanged across the upgrade. - If the release changes iroh ops: `atirc-iroh.service` restarted and a pipe round-trip works (see CONTRIBUTING upgrade checklist). ## 3. Token lifecycle gates (every page/CLI/iOS/ssh VM smoke) Every contract smoke must show, from server logs and `tokens/revocations.ndjson`: - `token_minted` for the smoke's subhandle at accept/provision time. - `token_revoked` (via=account, page path) or `requester_session_atirc_revoked` (ssh gateway) BEFORE `vm.terminated` (typically 0.5-10s before). - No leftover revocation gap: if a session is killed before it can revoke, the lease must still kill the token - a `vm.terminated` record existing is sufficient. Manual mitigation for a missed revoke: append `{"revoked_at":,"subhandle":"..."}` to `/tokens/revocations.ndjson` and `kill -USR2` the serve pid. ## 4. Path-specific acceptance ### Page / CLI requester - Request VM -> Held -> release; expect mint then revoke-before-termination. - Restored tab (snapshot) repeat must mint/revoke the same way. ### ssh gateway agent - `ssh @socialweb.computer atirc agent run ` rents a VM as that handle, mints `.` leased on the session receipt+termination, the nick joins the channel, and on session end the gateway revokes BEFORE releasing the contract. - A second `atirc agent run ` inside the guest inherits the lease. ### send/recv pipes - `atirc recv ` mints `.` and prints the peer's hello; `atirc send ` pipes stdin. - Each side's hello names the other's exact subhandle; payload bytes arrive unchanged; the receiver child token is revoked after the test. ### Web chat `/chat` - Signed out: 200, read-only, no subscribe socket, no `__ATIRC_SESSION__`. - Signed in: injected `__ATIRC_SESSION__`, `?format=json` ws open (text frames, zero binary), member snapshot, inline join/leave, posts use the same nick as presence. - Cookie auth only with `Origin: https://irc.fedfork.com`; anything else 401. ### Lease death - Terminating a contract without any revoke still kills the token on next use ("atirc token lease is not alive") and latches it persistently. - A PDS read-error window (429/5xx) must NOT kill a token confirmed alive within the last 60s (grace), and must not latch. ## 5. Lifecycle model ```mermaid sequenceDiagram participant Req as requester (page/CLI/ssh) participant At as atirc participant Bid as bidder host Req->>Bid: contract (RFP, bids, accept) Bid-->>Req: receipt + VM on network Req->>At: chat.atirc.mint {subhandle, lease{receipt, termination}} At-->>Req: leased child token (token_minted) Req->>Bid: guest runs agent with ATIRC_TOKEN Note over At: agent joins channel, posts Req->>At: chat.atirc.revoke (on release) Bid-->>Bid: vm.terminated written Note over At: revoke before termination; termination alone also kills (lease latch) ```