* feat(b3-6): coverage floor — script, floors and CI step (S-06)
scripts/coverage-floor.sh reads a Go coverage profile and fails when the
aggregate, or one of the core packages (ws, service, permissions, auth, db),
is below the figure recorded in coverage-floor.json. Statement counts come
from the profile's block lines, not `go tool cover -func`, so the per-package
figures are exact; percentages are truncated to one decimal and compared in
tenths. Exclusions (generated db/dbgen, cmd/) live in the floor file.
Measured with the CI command on this branch's base (origin/dev 75d64dd4):
aggregate 79.1 (11241/14194), auth 90.8, db 79.4, permissions 100.0,
service 67.8, ws 84.5. The plan's starting aggregate was 74.6 (B0 baseline at
an older SHA); the ratchet applies to this PR too, so the floor lands at the
measured figure.
Wired into ci.yml right after the race/coverage test step, on the Linux leg
only: OS-tagged files swap in and out of the build and several tests skip on
Windows, so one leg keeps the figure deterministic. The ratchet rule is in
Server/CLAUDE.md.
--floor <file> and OWNCORD_COVERAGE_FLOOR override the committed floors, so
the negative control needs no edit of the tracked JSON.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo
* docs(b3-6): evidence block for item 1 (coverage floor)
Numbers, RED/GREEN commands and the Linux-leg decision, appended to the
B3-6 section per the item's exit criteria.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo
* fix(b3-6): coverage floor — fail closed on JSON shape, honour --floor anywhere, LC_ALL=C, gate after the last test step
Review findings on item 1.
The floor-file parser now fails closed instead of silently reading less than
the file says. A Prettier-wrapped "exclude" array used to yield zero
exclusions and misreport as a coverage drop; an "exclude" key with no parsed
entries is now exit 2 naming the one-line-array rule. A package entry sharing
a line with the closing brace ("ws": 99.0 }) used to be dropped, so that floor
stopped being enforced; the block now closes after the line is parsed, and an
entry on the "packages": { line is parsed too. Two entries on one line are
exit 2 rather than one silently ignored. All three rules are in the header
comment.
--floor is parsed in any argument position, so `coverage-floor.sh coverage.out
--floor red.json` no longer silently uses the committed floors; an unknown
flag or a second positional argument is a usage message and exit 2.
LC_ALL=C is exported for mawk's locale-dependent decimal handling.
The ci.yml step moves after the deadlock and tag-gated test steps — it still
reads the profile the race step wrote, and still runs only on the ubuntu leg,
but a floor miss no longer hides those steps' results.
Server/CLAUDE.md gains the no-trailing-slash rule for exclusions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo
* fix(b3-6): coverage floor — every package entry must parse, and the five core packages must all be present (Codex P2 on #1453)
A package entry whose value did not match the numeric regex — valid JSON such
as "auth": "90.8" — was silently ignored, and the only completeness check was
"at least one package parsed", so a malformed value quietly removed a floor.
That contradicts the script's own fail-closed contract.
Inside the "packages" block, any line that is not a well-formed
"name": <number> entry (or the block's closing brace) is now exit 2, naming the
line number, the line, and the shape rule. The entry match is anchored, so it
also subsumes the previous "two entries on one line" heuristic.
The five core packages — ws, service, permissions, auth, db — must each have a
parsed floor; a missing one is exit 2 naming it. Extra packages beyond the core
set stay allowed.
Header comment and the plan's evidence block record both rules.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo
* fix(b3-6): coverage floor — floors set from the Linux leg (CI run 33302062524)
The floors were first measured locally on Windows; the gate runs on the ubuntu
leg, and the first CI run of #1453 showed the two legs differ. Each floor is
now the Linux value truncated to one decimal, measured by the gate itself on
the leg that enforces it: aggregate 79.9 (11344/14191), auth 90.8 (418/460),
db 79.3 (1738/2189), permissions 100.0 (94/94), service 67.8 (1204/1775),
ws 86.9 (3271/3763).
The deltas are the ones the pre-merge analysis predicted. ws is higher on Linux
because three EnsureLiveKitBinary tests and one harvest_s5 case skip on Windows,
and that lifts the aggregate with it; db is one statement larger on Linux
(lockfile_unix.go has 11 statements where lockfile_windows.go has 10), which
costs it a tenth. auth, permissions and service carry no OS-conditional code and
are identical on both legs.
The evidence block now carries both columns, cites the run id, and keeps the
74.6 note. Running the new floors against the local Windows profile fails on
aggregate and ws by exactly those deltas, which is expected and is why the gate
is Linux-only.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmiqjgTuov1stBTB6uGkvo
* fix(b3-6): coverage floor — a tenth of headroom where the Linux leg varied run-to-run (ws, aggregate; runs 33302062524 and 33302732286)
Run 33302062524 measured ws at 3271/3763 (86.9); run 33302732286, same commit,
measured 3267/3763 (86.8) and failed the floor set from the first. Four
statements of run-to-run variance in ws under -race — timing-dependent branches
— which moves the aggregate with it (11344 -> 11340). The reviewer's
zero-headroom concern is now evidence rather than a prediction.
Floors are therefore the lowest observed Linux figure, truncated to 0.1, minus
0.1 where the package varied between runs: ws 86.9 -> 86.7, aggregate
79.9 -> 79.8. auth 90.8, db 79.3, permissions 100.0 and service 67.8 are
unchanged — their statement counts are identical in both runs, so they take no
headroom.
Server/CLAUDE.md states that rule next to the ratchet, and notes that a Windows
run reports aggregate and ws under floor by design. The evidence block carries
both runs' covered/total per package, which varied, and the resulting floors.
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.