Catch the bug only two users can make.
Collision Canary drives two real browser actors at the exact same moment and proves whether its bundled last-seat reference app keeps a simple promise: only one person can claim the final seat. Single-user tests never see this class of bug. It only shows up when two people act on one shared record in the same instant, and one row says yes to both.
Live app: https://collision-canary.vercel.app
Demo video: https://drive.google.com/file/d/1oIxXEDN20dNfqA3UdUEC1QTvWWY8IViM/view?usp=sharing
Live repair cycle: collision proof → verified Kane rerun
- Open the live app and click Run the last-seat test.
- You receive two tokenized actor links, one for Alice and one for Bob.
- Point Kane CLI at both links to drive two real Chrome browsers, or open each link in its own browser.
- Both actors arm, wait at a shared barrier, and claim at the same moment.
- Open the proof. A healthy app shows one winner and one correct rejection. A broken one shows two winners and produces a repair packet.
- Alice and Bob arm against one shared seat.
- A database barrier releases both actors together.
- Each actor runs the claim path, which writes a persisted outcome.
- The evaluator classifies the observed state as satisfied or violated against a declared invariant: at most one actor can claim the seat.
- A violated run produces a redacted repair packet for a local Codex repair. You re-run and prove the fix.
flowchart TB
Kane["Kane CLI<br/>two isolated Chrome sessions"]
Alice["Alice browser"]
Bob["Bob browser"]
Routes["Next.js route handlers"]
Barrier["Shared database barrier"]
Claim["Atomic claim transaction"]
Neon[("Neon Postgres")]
Evaluate["Invariant evaluator"]
Proof["Redacted proof projection"]
Packet["Hashed repair packet"]
Codex["Local Codex adapter"]
Kane --> Alice
Kane --> Bob
Alice -->|"fragment token + bearer auth"| Routes
Bob -->|"fragment token + bearer auth"| Routes
Routes --> Barrier --> Claim
Claim <--> Neon
Neon --> Evaluate --> Proof
Proof -->|"violated run"| Packet --> Codex
Codex -->|"scoped repair and rerun"| Kane
classDef actor fill:#17202b,stroke:#f5b93b,color:#f3f5f7;
classDef app fill:#102a2b,stroke:#34d399,color:#f3f5f7;
classDef db fill:#21183b,stroke:#a78bfa,color:#f3f5f7;
classDef repair fill:#351a28,stroke:#fb7185,color:#f3f5f7;
class Kane,Alice,Bob actor;
class Routes,Barrier,Claim,Evaluate,Proof app;
class Neon db;
class Packet,Codex repair;
Full architecture decisions: docs/ARCHITECTURE.md.
The actor lab at /lab/last-seat is a real browser surface built to be driven by Kane CLI. Each run hands out two tokenized actor URLs. Kane opens them as two independent Chrome sessions and performs the arm and claim steps, so the collision is produced by real browsers against real shared state, not by request mocks. The same lab works if you open the two links by hand.
Run the journey yourself with an authenticated Kane CLI:
bash scripts/kane-last-seat.shIt creates a run, drives Alice and Bob as two parallel Kane browser sessions, and prints the verdict. The healthy result is one winner and one correct rejection.
- Real browsers, driven by Kane, not scripted request mocks.
- Real shared state: one Neon Postgres row and a real transaction decide the winner.
- Evidence-bound repair: a redacted, hashed packet your coding agent can act on, followed by a verified re-run.
Every run is a real database record. Browse recent runs at /runs and open any proof to see the real counts, the verdict, and the reason code.
Next.js 16 (App Router) with React 19, Tailwind v4, Neon Postgres with Drizzle ORM, deployed on Vercel. Kane CLI drives the browser actors. Codex performs local, evidence-bound repairs.
| Route | Purpose |
|---|---|
GET /api/v1/health |
Database readiness |
GET /api/v1/runs |
List recent runs |
POST /api/v1/runs |
Create an isolated run |
POST /api/v1/runs/:runId/actors/:actorKey/arm |
Arm one actor |
GET /api/v1/runs/:runId/actors/:actorKey/barrier |
Read barrier state |
POST /api/v1/runs/:runId/actors/:actorKey/claim |
Attempt the shared claim |
POST /api/v1/runs/:runId/evaluate |
Persist an invariant verdict |
GET /api/v1/runs/:runId/proof |
Read the redacted proof projection |
GET /api/v1/runs/:runId/repair-packet |
Read a violated-run repair packet |
Requirements: Node.js 22+, pnpm 11+, and Neon (PostgreSQL) credentials.
pnpm install
vercel env pull .env.local --environment development
pnpm db:migrate
pnpm exec next dev -p 3001Verify the full flow over HTTP:
COLLISION_CANARY_BASE_URL=http://127.0.0.1:3001 pnpm test:backend-httpThe same verifier can exercise the local failure fixture and repair packet:
COLLISION_CANARY_FAILURE_FIXTURE=true COLLISION_CANARY_BASE_URL=http://127.0.0.1:3001 pnpm test:backend-httpFocused checks: pnpm test:actor-guards, pnpm test:atomic-claims, pnpm test:invariant-evaluator, pnpm test:repair-cycle, pnpm test:public-base-url.
Build a packet from a violated run, apply a local Codex repair, then link the cycle:
pnpm build:repair-packet -- --run <violated-run-id> --out .collision-canary/runs/<run-id>
pnpm repair:codex -- --packet .collision-canary/runs/<run-id>/repair-packet.json --apply
pnpm link:repair-cycle -- --failed-run <violated-run-id> --verified-run <verified-run-id> --packet .collision-canary/runs/<run-id>/repair-packet.jsonThe Codex adapter defaults to dry-run. --apply is an explicit local operation restricted to the backend files named by the packet. It never commits or pushes.
- Neon Postgres is the shared-state authority.
- Actor tokens are scoped and handed off through URL fragments, then sent in
Authorizationheaders. - Production actor URLs use
NEXT_PUBLIC_APP_URLor Vercel's deployment URL, never an untrusted host header. - Proof projections exclude tokens, credentials, and raw request headers.
- Codex execution is local-only and is never imported by a public route.
A proof describes one observed run. It does not claim exhaustive verification of every possible schedule. This release ships one last-seat reference scenario rather than an arbitrary target-app adapter. The local failure fixture is disabled in production, and the production claim path stays atomic even if the fixture variable is present.
Read the system decisions in docs/ARCHITECTURE.md and the visual system in docs/DESIGN.md.
MIT. See LICENSE.
