* test(b3-6): seeded hub simulation and fault-injected transport (items 2 and 3) Server/ws/hub_sim_test.go drives a PCG-seeded interleaving of subscribe, broadcast (global, channel, recipients-scoped, sequenced DM), ack, disconnect and reconnect-transfer over a real Hub with eight headless clients, and a model client checks the per-client FIFO/seq oracle from Server/CLAUDE.md after every step: strictly increasing seq per connection, exact audience delivery (nothing lost, extra or twice), a resume replayed exactly from the watermark to the seq at which registerNow ran, h.seq advancing only for a frame that reached the ring, an evicted watermark refused a replay, and a replaced socket's late teardown reporting replaced=true. The resume step runs reconnectRegister as-is (snapshot and registerNow under one seqMu section) on a goroutine while up to three broadcasts race it; the model recovers the snapshot point from the replay burst, so any interleaving is checkable. OWNCORD_SIM_SEED replays one seed, OWNCORD_SIM_SEEDS (default 20) and OWNCORD_SIM_STEPS (default 200) size a run, and a failure prints the seed, the step, a ready-to-paste replay line and the last steps. The default runs in about 2.3 s under -race; `make sim` runs 10,000 steps per seed. Server/ws/faultconn_test.go is the seeded, deterministic frame transport the simulation reads through: drop, tail cut, duplicate, bounded reorder and an order-preserving lag from its own PCG stream, exported to ws_test through export_test.go as NewFaultConnForTest. The simulation's default wire is a lag plus tail cuts, the one fault a TCP-backed WebSocket really has; the silent drop is the negative control that proves the oracle notices a lost replay. BenchmarkReconnectStorm resumes 50 live clients per op through the same path. newTestHub and its three seed helpers take testing.TB so the benchmark can share them. No production code changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo * docs(b3-6): evidence block for items 2 and 3 (hub simulation, fault transport) Oracle, the RED/GREEN excerpts (inverted assertion, seed replay, drop-all wire, unsynchronized registerNow), wall-clock and benchmark figures, gate results and the epoch-harness decision, under B3-6 in the plan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo * fix(b3-6): hub sim — deterministic topic limiter for exact replay, a floor on the step mix, auth-frame-wins under transfer, wire-seed mixing Review fixes for items 2 and 3. Exact replay. TopicRateLimiter keys its window on time.Now(), so at 10,000 steps the shed boundary was a timing-dependent step and every later seq differed between runs; the printed OWNCORD_SIM_SEED line could not reproduce a failure. FreezeTopicLimiterForTest (export_test.go) swaps the hub's limiter for one whose window never rolls over inside a run, so the shed is a per-channel count. Three more leaks of the scheduler's interleaving into the trajectory surfaced once that was fixed, and are closed the same way — by taking the decision away from the race or making both outcomes read the same: racing frames are pulled into the wire at attach time (queue fill no longer depends on which side of the snapshot they fell), the racing burst is aimed at the resuming client's own audience (a replay-superset frame was read iff it landed before the snapshot), and a resume within the burst's reach of the ring's eviction boundary is not raced (the allocations could evict the watermark before or after the snapshot and pick replay or fallback). Three runs of one seed now print byte-identical stats; what still varies — how many racing seqs land in the replay burst — is printed on its own line and stated in the doc comment. Floor. TestHubSimulation aggregates the per-seed stats and requires every load-bearing transition (the four broadcast kinds, resume, fallback, fresh, cut, kicked, racing-in-replay) at least once across the default run, so a constant change cannot turn the simulation into no-ops with CI green. Its first run found that the overflow kick had become unreachable at 200 steps; the sim's queue is 12 now (production stays 256). Also: the resume step draws active_channel_id as none / the open channel / another channel whether or not the old socket is registered, so registerNow's auth-frame-wins branch runs under the transfer; the wire's PCG takes the seed and (idx<<32|conns) as its two words instead of an arithmetic mix that collided past 131 connections; seedTestUser takes testing.TB like its siblings; the evidence block lists what the simulation does not cover and the -timeout 60m the ten-pass deadlock gate needs, with the same line under Traps carried forward. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo * test(b3-6): hub sim — floor on raced resumes instead of the scheduler-decided key; log when the floor is skipped racing-in-replay was the one floor key the scheduler decides, so a correct hub could in principle fail the floor on a run where no racing seq landed inside a burst. The floor now keys on raced resumes — a resume that got a replay while a burst ran (burst > 0 && ok), which the seed determines — and racing-in-replay stays a printed count. The floor also says so when it is skipped for OWNCORD_SIM_SEED or a shorter seed list instead of returning silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo * test(b3-6): hub sim — raced counts a broadcast allocated while registration was in progress, not the requested burst Codex P2 on #1458: raced incremented on burst > 0, which counted a resume whose goroutine had returned before the first broadcast ran and one whose every channel broadcast the limiter shed, so the floor could pass with no broadcast overlapping a registration. raced now counts a resume where a racing broadcast allocated a seq while the reconnect goroutine had not yet been observed to return (the driver's done handshake, checked after each allocation). That is the scheduler's call, so raced moves off the deterministic stats line and is floored only in aggregate across the 20 default seeds — 179 bursts per run, 178–179 observed overlapping in three measured runs, odds named in the comment and the evidence block. The requested burst stays a printed, seed-determined count (bursts) and is floored as before; the floor logs its totals. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Documentation index
Every document in docs/ is listed here. If it is not on this page it is not
current guidance.
Docs fall into four kinds, and the difference matters when you are deciding whether to trust one: guidance tells you how to do something, reference describes a contract the code actually implements, audits are dated snapshots that were true when written and were never updated, and plans record intent. Read an audit as history, not as status.
Start here
| I want to… | Read |
|---|---|
| Run a server | quick-start.md |
| Deploy for real | deployment.md |
| Contribute a change | contributing.md |
| Understand the system | architecture/ |
| Report a bug | Issues |
| Ask, or suggest an idea | Discussions |
| Report a vulnerability | security.md |
| Know who can read what | trust-model.md |
Guidance
| Document | Covers |
|---|---|
| quick-start.md | Getting a server running with the fewest steps. |
| deployment.md | Production deployment on Windows and Linux. |
| contributing.md | Environment setup, the branch and PR model, coding standards, how to run the checks CI runs. |
| security.md | How to report a vulnerability, and how findings are handled in public vs private. |
| trust-model.md | Who can read what: operator-readable text and files, E2EE media, transport, at rest, what beta does not claim. |
| livekit-setup.md | Standing up the LiveKit SFU for voice and video. |
| port-forwarding.md | Making a server reachable from outside the LAN. |
| tailscale.md | Remote access without port forwarding. |
| mcp-introspect.md | Dev-only MCP server for introspecting a running instance. |
Reference
These describe contracts the code implements. If one disagrees with the code, the code is right and the document is a bug.
| Document | Covers |
|---|---|
| api.md | REST API under /api/v1. |
| protocol.md | WebSocket protocol — frames, sequencing, reconnect. |
| schema.md | SQLite schema and migrations. |
| server-configuration.md | Every server configuration option. |
| credential-storage.md | What the desktop client persists, and where. |
| ../protocol/schema.json | Generated-code source of truth, at the repository root because it is owned by neither side. Server/ws/message_types.go and Client/src/lib/protocolTypes.ts are generated from it — never hand-edit either. See ../protocol/README.md. |
Architecture
architecture/README.md indexes the blueprints and carries the maintenance rule: each blueprint names its source-of-truth files, and a PR touching those updates the blueprint in the same change.
- system-overview.md, server.md, client.md
- data-model.md, websocket.md, voice-e2ee.md
- ux/ — target-state UX spec, per-view states and event→reaction maps
- platform-contracts.md — target-state desktop/browser seam: what has to move behind a contract before the client can run in a browser (B7)
- plugins.md — the experimental WASM plugin boundary: off by default, compiled out of releases, no API promise, what may become a plugin after beta and what never moves
client-architecture.md is a redirect stub; the live document is architecture/client.md.
Audits — dated, not maintained
Point-in-time snapshots. They are not updated as the code moves, and they are deliberately left alone when paths change, so links from commit messages keep resolving. Anything here may be stale; the ledger and the plan index carry current status.
| Audit | Scope |
|---|---|
| audit-2026-08-23-repository-layout.md | Repository layout and contributor experience (RL-01…RL-22). |
| audit-2026-08-23-repository-health.md | Full repository health. |
| audit-2026-08-19.md | Repo health. States "0 open findings" — untrue since; see the ledger. |
| audit-test-coverage-2026-08-19.md | Test audit (T-*, a separate register from the OC-* ledger). |
| audit-2026-08-04-docs-and-coverage.md | Documentation accuracy and UI/UX test coverage. |
| audit-2026-08-04.md | Security review. |
| audit-test-coverage-2026-07-25.md | Test-coverage audit. |
| audit-2026-07-19.md | Architecture and spec-conformance review. |
| audit-2026-04-07.md | First comprehensive audit. |
Plans
plans/README.md indexes every plan with a recorded state — active, partially implemented, design-only, or shipped — and is the authority over a plan's own header, which can drift.
Where status actually lives
Do not read a defect count, or a "what works" claim, out of a document on this page. Status has owners:
| Concern | Source of truth |
|---|---|
| Defect status | .superpowers/findings-ledger.json (FINDINGS.md is rendered from it) |
| Security-sensitive defects | Private GitHub Security Advisories |
| Phase order and gates | plans/repo-health-roadmap-2026-08-23.md |
| Current measured baseline | plans/b0-baseline-2026-08-25.md |
| Generated-code contracts | CLAUDE.md, "Generated code — never hand-edit" |
A CI job checks that documents on this page do not contradict the ledger's
counts. Adding a count to a document means adding it to that check's allow-list
in scripts/check-doc-counts.mjs.