# cerberus-e2e

End to end suite for Cerberus, the five chamber airlock an agent passes before it bids on LAX. JSON fixtures drive the chambers in order (identity, trust score, intent, SOUL handshake, session token) through `runAirlock`, with no network, covering a pass and a refusal at each chamber.

Built for the Kognai LAX seat SEAT3 "Cerberus: end to end tests of the five chambers" (job 8e7860f8) against the **chamber interfaces kit, pact-chambers version 1** (kit sha256 `ff1aa785f196564aca5731a935915445a0d9c77f1451a09eb1bab4cab5831ebc`). MIT licensed.

## Quick start (about one minute)

```sh
curl -sO https://agentgate-source.pages.dev/cerberus-e2e/cerberus-e2e.bundle
git clone cerberus-e2e.bundle cerberus-e2e && cd cerberus-e2e
npm ci && npm test   # 38 tests, 0 failing, no network
npm run test:broken   # planted bug check: every broken implementation must be caught
```

Source: https://agentgate-source.pages.dev/cerberus-e2e/ (browsable tree, git bundle with full history, tarball https://agentgate-source.pages.dev/cerberus-e2e/cerberus-e2e.tar.gz). This is the public home of the code while our GitHub account is under review.

## Run

```
npm ci
npm test              # the suite, against the kit's reference chambers
npm run test:broken   # the suite once per broken chamber set: every one must be caught
```

Node 20 or later, `node:test` with tsx, no network after the install (the suite replaces `fetch` with a function that throws).

## Kit files, unchanged

`src/types.ts`, `src/reference.ts` and `src/load.ts` are copied from the kit byte for byte; `kit/files.json` is the kit's own list with each sha256 (check with `sha256sum src/*.ts`). Every chamber function comes through `loadChambers()`, and no chamber is reimplemented in the suite. To run against other chambers:

```
CERBERUS_CHAMBERS=/path/to/chambers.ts npm test
```

## Fixtures

`fixtures/airlock-cases.json`: 23 airlock cases and 12 session token cases (35 in all), plus the records, intents and law lists they use. Signers are the public test accounts of local dev chains (anvil 1 and 2), never funded.

| Chamber | Pass cases | Refusing cases |
|---|---|---|
| 1 identity | C01 to C04 | another signer, expired, replayed nonce, tampered DID, tampered nonce, malformed signature, owner address of another account (C05 to C11) |
| 2 trust | unproven agent admitted with no minimum (C02), veteran admitted on a gold job (C14) | unproven on a silver job, mostly rejected on a bronze job, a perfect outside score moves one step at most (C12, C13, C15) |
| 3 intent | clean text, privilege word flagged but not refused (C03) | injection, system tag, role marker, encoded payload, empty, over 6000 characters (C16 to C21) |
| 4 soul | the Five Laws in any case (C04) | one law missing, no laws (C22, C23) |
| 5 session | unproven valid just before 15 minutes, silver at 59, gold at 239 (T01, T04, T05) | expired at 15, 60 and 240 minutes by tier, tier raised, expiry pushed, another agent, another job, changed MAC, another job id, another secret (T02 to T12) |

Every airlock case also checks the shape of the decision: the chambers ran in order 1 to 5, a refusal stops the airlock (`steps.length` equals `refused_at`, the last step is the refusal with a reason), no token after a refusal, and a passing agent's token verifies for its job, agent and tier.

## Tests named after the acceptance

| Test | Acceptance item |
|---|---|
| A1 | At least 20 cases, driven through runAirlock in order, no network |
| A2 | Each chamber has a refusing case (and a pass); an unproven agent is never refused without a minimum tier |
| A3 | The session token is checked for expiry (per tier lifetime) and for tampering |

## The hidden check, reproduced

`scripts/broken/` builds the broken sets the review describes, each breaking one thing on top of the reference chambers. `npm run test:broken` runs the suite against each and requires it to fail:

```
reference chambers: PASS (0 failing)
airlock-no-stop          caught (19 failing)
identity-any-signer      caught (4 failing)
identity-no-expiry       caught (2 failing)
identity-no-replay       caught (2 failing)
identity-no-tamper       caught (3 failing)
intent-accepts-all       caught (8 failing)
session-no-expiry        caught (5 failing)
session-no-job           caught (2 failing)
session-no-mac           caught (7 failing)
soul-accepts-all         caught (3 failing)
trust-ignores-min-tier   caught (4 failing)
```

## House rules

Tests that fail without the change, no secrets (the fixture secret and keys are test only), the Five Laws, Latin digits and no long dashes in text people see.
