# The pre-launch test matrix Every check this project wants green before anything reaches a real zone, in the three tiers it runs in: what an agent can break on one machine, what needs an unadvertised instance on a real zone, and what needs a login in somebody else's system. Each row names the test or scenario that covers it, and says `none` where nothing here does. Tiers are ordered. Nothing in tier 2 starts until tier 1 is green; nothing in tier 3 touches an account that is not disposable. This page is the map, not the gate: the gate is the irreversibles — the DID scheme, the lexicon shapes, the zone, and what is written into other people's servers. A `none` is a row somebody has to do something about, and the two ways to do that are a test and a tier. Moving a row up a tier is the better one: a check that needs a real zone is a check that runs once a week, and a check that runs in this repository runs on every push. ## Tier 1 — local, sandboxed, agent-driven Everything here runs on one machine with stand-ins for the network. The command column is what runs it. ### The harness itself | Check | Command | What covers it | | --- | --- | --- | | An ecosystem replica in one compose file: the reference PDS, an appview, an indigo relay, `goat`, an ACME directory and a resolver for the zone | none | none | | A local TLS and DNS story a foreign resolver accepts: a local CA the replica trusts, so `did:web` resolves over HTTPS | none | `crates/didbot-tls/tests/acme_conformance.rs` drives ACME against an in-process directory; nothing yet issues into a replica | | Local TLS: a `.localhost` zone served from an authority kept per machine, reused across starts, refused for any other zone, and verified by a real client | `cargo test -p didbot-tls` | `crates/didbot-tls/tests/local_authority.rs` completes a handshake against the leaf a zone serves and shows the authority's name constraint refusing one outside `.localhost`; `src/local.rs` covers reuse and the refusal | | Every binary in one scenario over TLS, against one authority, with each zone's port named | `scripts/scenarios.sh` | `crates/didbot/tests/scenarios.rs` starts `didbot-pds` with `--tls local` and drives `didbot`, `didbot-agentd` and a browserless dashboard sign-in over `https` | | Sandboxed agent hosts: several containers, each with the plugin and the daemon | none | none | | A red-team brief handed to agents, with the replica's oracles deciding | none | none | ### Wire and sync | Check | Command | What covers it | | --- | --- | --- | | A relay inverts every commit kind with no MST inversion failures | `cargo test -p didbot --test conformance` | `crates/didbot/tests/conformance/mst_inversion.rs`, against the vectors rather than against a relay | | The stream survives a restart, a snapshot restore, a certificate swap and a reconnect from an old cursor | `cargo test -p didbot-pds --test sequence_restart` and `cargo test -p didbot-tls --test rotation` | the sequence floor and the certificate swap each have a test; a relay's own view of the two does not | | `goat repo export` and verify, for every account state | `cargo test -p didbot --test announce_states` | the states and their events; the export is read by this project's own CAR reader in `crates/didbot-repo/tests/car_framing.rs` | | An appview indexes a provisioned account: profile, self-label, repo status and account events agreeing | none | none | | `getRepo` with `since`, `listBlobs` and `getBlob` round-tripping through a foreign client | `cargo test -p didbot --test conformance` | `crates/didbot/tests/conformance/wire.rs` drives them against the vendored documents, not through a foreign client | ### Identity | Check | Command | What covers it | | --- | --- | --- | | `did:web` and handle resolution for an account, the server's apex, and a tombstoned account | `cargo test -p didbot-identity` | `crates/didbot-identity/tests/spec_conformance.rs` | | A document rewrite, and what a reader does with signatures made before it | none | none | | Server-minted DIDs: one account per correlation key, a deleted DID never reissued, a caller's label ignored | `cargo test -p didbot-pds --test provisioning` | `crates/didbot-pds/tests/provisioning.rs` and `crates/didbot-pds/tests/naming.rs` | ### OAuth | Check | Command | What covers it | | --- | --- | --- | | A full sign-in from a foreign client: push, decision, approval, code, bound token, write, refresh, replay | `cargo test -p didbot-serve --test oauth_account_flow` | the whole flow against the real router, with this project's own client | | Bluesky's own `@atproto/oauth-client-node` signs in to a running server as a public native client and writes before and after a refresh; as a confidential web client it pushes with its key, is refused approval because a browser would carry its code, and is declined | `npm ci --prefix tools/oauth-interop`, then `cargo test -p didbot-serve --test oauth_interop` | `crates/didbot-serve/tests/oauth_interop.rs` runs `tools/oauth-interop/sign-in.mjs` against `didbot-pds` and answers each sign-in as `didbot-agentd` does; without `node` or the installed tree it passes having said so | | The loopback client form, and a client whose metadata is served from a hostile origin | `cargo test -p didbot-serve --test oauth_standard_client` and `--test oauth_interop` | jacquard-oauth's loopback client and `@atproto/oauth-client-node`'s sign in; a hostile origin is not driven | | Scope narrowing: a token cannot write outside its grant, a tightened ceiling narrows the next write | `cargo test -p didbot-serve --test token_scope` | `crates/didbot-serve/tests/token_scope.rs` and `crates/didbot-scope/tests/ceiling_boundary.rs` | | Every scope form the permission spec defines reads without a warning; each other form reads as its warning says, and PAR logs it at `warn` with the client; a never-granted scope is dropped and Leaflet and Tangled sign in | `cargo test -p didbot-scope`, then `cargo test -p didbot-serve --test scope_warnings --test permission_sets --test token_scope` | `crates/didbot-scope/src/tests.rs`, and the three `didbot-serve` suites against the real router | | A scripted agent that approves everything, against the default ceiling | none | none | | A second agent cannot redeem a consent reference it did not receive | `cargo test -p didbot-serve --test oauth_account_flow` | the account check is the credential's, and the flow test drives it from both sides | | Every `bot.did.*` route answers in the shape its document declares | `cargo test -p didbot --test conformance bot_did` | `crates/didbot/tests/conformance/bot_did.rs` | ### Policy and the e-stop | Check | Command | What covers it | | --- | --- | --- | | The operator's repository unreachable at boot, mid-run, and answering empty: no denial is lost | `cargo test -p didbot-serve --test policy_poll_restart` | `crates/didbot-serve/tests/policy_poll_restart.rs` restarts with the operator's repository gone, and the kept set refuses before any poll runs | | One malformed record beside a valid new denial: the valid one binds | `cargo test -p didbot-policy-records` | `crates/didbot-policy-records/tests/last_good_across_builds.rs` covers a revision a later build will not honour beside the one it keeps enforcing; the pairing with a valid new record at another key is not driven | | Policy change latency end to end, measured and published as the poll interval | none | none | | `--pause` and `--revoke` under load: no write lands after the throw, and a restart keeps the stop | `cargo test -p didbot-pds --test freeze_race` and `cargo test -p didbot-pds --test estop_restart` | writes queued behind a judgment when the stop is thrown, and the latch across a restart; not under swarm load | | An ownership lapse: the record deleted, the grace window passed, the self-pause, the record restored | `cargo test -p didbot --test handshake` | `crates/didbot/tests/handshake.rs`, in one process against a stand-in repository | | The dashboard against real servers, in a browser | `DIDBOT_E2E=1 scripts/test-policy-e2e.sh` | a server, the operator's stand-in PDS, the built site and headless Chrome | ### Attestation | Check | Command | What covers it | | --- | --- | --- | | A replayed claim inside the window, after a restart, and after the account it minted was erased | `cargo test -p didbot-serve --test proof_restart` | the spent-proof window across a restart | | A copied node key on a second container, and the honest limit that draws | none | `docs/trust-model.md` states the limit; nothing exercises it | | Clock skew of ten minutes either way: the refusal names skew | none | none | | A node key retired on a running server: the next claim refused, existing contexts locked | none | none | ### Agent hosts | Check | Command | What covers it | | --- | --- | --- | | Real sessions in containers: session start, a fan-out of subagents, and every record authored by the context the hook fired for | none | none | | A daemon restart mid-session, a hook race at startup, a daemon unreachable, and a socket only its owner's uid can reach | `cargo test -p didbot-agentd` | the command line and the configuration; the socket's permissions and the races are not driven | | A hostile in-process subagent acting as its parent | none | `docs/trust-model.md` states the custody limit | | The dispatcher on a host holding only the agent install: the operator verbs are absent and say so | `cargo test -p didbot-dispatch` | `crates/didbot-dispatch/tests/dispatch.rs` | ### Durability, restart and restore | Check | Command | What covers it | | --- | --- | --- | | A kill at every sync boundary under load: every acknowledged write present, no unacknowledged one | `cargo test -p didbot-pds --test durability` and `cargo test -p didbot-pds --test record_heap` | the crash-and-reopen cases, and a power cut after another store's sync of the shared journal; not thousands of them under swarm load | | A restore from a directory copied mid-load: the sequence floor, the relay's view, the blob check | `cargo test -p didbot-pds --test restore` and `cargo test -p didbot-serve --test restore_drill` | the store half and the deployment half | | Compaction, boot time as a function of history, and the refusal at the log budget | `cargo test -p didbot-pds --test write_scale -- --ignored` | the benchmark prints what a write costs as history grows; the boot time and the budget's refusal are not driven | | Pending sign-ins across a restart | none | none | | A binary opening a directory another binary wrote | `cargo test -p didbot-pds --test upgrade` | `crates/didbot-pds/tests/upgrade.rs` | ### Abuse and load | Check | Command | What covers it | | --- | --- | --- | | A create flood and a push flood from many addresses | `cargo test -p didbot-swarm --test decision_bounds` | the decision store's bounds under a real swarm; the address-keyed budgets are unit-tested in `crates/didbot-serve/src/rate_limit.rs` | | A blob flood to the quota | `cargo test -p didbot-pds --test blob_storage` | `crates/didbot-pds/tests/blob_storage.rs` drives the upload path against the quota | | A subscriber that stops reading, with others still on the stream | `cargo test -p didbot --test subscribe_backpressure` | `crates/didbot/tests/subscribe_backpressure.rs` | | A swarm at a thousand and at ten thousand accounts: memory per account, restart time, the account wall | `cargo test -p didbot-pds --test store_cost` | the per-account and per-record cost; the restart time and the wall at ten thousand are not driven | | A swarm behind one address against the per-address budgets | none | none | ### Operations | Check | Command | What covers it | | --- | --- | --- | | An image upgrade against a data directory, a rollback by restore, and the crash-loop brake | `cargo test -p didbot-pds --test upgrade` | the directory half; the brake and the rollback are `docs/operations.md`'s runbook | | Every boot refusal in the operations table, produced on purpose | `cargo test -p didbot-pds --test upgrade`, `cargo test -p didbot-pds --test second_writer` and `cargo test -p didbot-serve --test startup_refusal` | `upgrade.rs` produces the three stamp refusals and `second_writer.rs` the lock; `startup_refusal.rs` refuses `--tls acme` under `.localhost` before the data directory is claimed | | A graceful stop on the signal a deployment sends | `cargo test -p didbot-serve --test graceful_shutdown` | `crates/didbot-serve/tests/graceful_shutdown.rs` | | The ownership scenarios with the real binaries | `scripts/scenarios.sh` | `crates/didbot/tests/scenarios.rs` | ### Vibescrobble | Check | Command | What covers it | | --- | --- | --- | | The index reads a relay's stream and survives a relay and a server restart | none | none | | A scrobble written by a real containerised session appears on the canvas with the right operator and parent | none | none | ## Tier 2 — an unadvertised instance on a real zone A real zone, a real certificate, no announcement, on a zone whose every account will be tombstoned. Nothing here runs from this repository: each row is an operator following `docs/deployment.md` and recording what happened in `docs/conformance.md`. | Check | Where it runs | What covers it | | --- | --- | --- | | `tofu apply` from an empty state, the delegation, the wildcard and apex records, and staging issuance before production | the zone | `crates/didbot-dns/tests/route53_zone.rs` and `crates/didbot-tls/tests/dns01_zone.rs` drive the record writes against a hosted zone that answers like the real one | | The public checkers: pdscheck, the debug tools, the directories, the TLS and header graders | the instance, from outside | none | | Certificate transparency: a monitor subscribed, our own issuance seen and nothing else | the zone | none | | Our own relay in another region crawling over the internet | the instance, from outside | none | | Agent hosts across the internet: hook latency, a daemon behind NAT, real clock skew | a laptop and the instance | none | | A backup and restore drill on real volumes, an image swap, a disk fill, and break-glass reaching the e-stop | the instance | `crates/didbot-pds/tests/restore.rs` drills the store half locally | | A week of background scanning on 443 | the instance | none | | Vibescrobble deployed against the instance | the instance | none | | The whole zone tombstoned, and what a relay and an appview do with it | the zone | none | ## Tier 3 — an external login or an external operator Everything here leaves a record in somebody else's system, so every row uses a throwaway account. | Check | What it needs | What covers it | | --- | --- | --- | | `didbot operate` and the policy site writing against a real personal data server | an account on that server | `crates/didbot/tests/scenarios.rs` drives the command against a stand-in repository | | `bot.did.*` permission sets expanded by somebody else's authorization server | the published schema records, and that server | only an external authorization server can answer this | | An announcement to the network from the disposable zone: admission, the per-host cap, an account visible in a client, and an account signing in to a third-party site | the network | none | | A preference record read against real accounts that publish one | those accounts | none | | A report filed against a disposable account, and what reaches the operator | somebody else's moderation service | none | | What a relay and an appview do when the disposable zone is tombstoned | the network | none |