Files
J3vbandClaude bd397d2bbc feat(b3-7): alpha-shaped dataset — deterministic seed profile and the v1.2.0-alpha.4 snapshot (#1469)
go run ./cmd/seed -confirm-dev -profile alpha fills an empty database with
the plan's dataset: 100 users (1/2/5/92 across the four roles), 12 channels
(10 text + 2 voice; 3 role-override, 2 user-override, 1 archived), 20,000
messages over 30 simulated days on a diurnal curve (exactly 15% in DMs
across 40 pairs), 300 attachment rows (60/10/10/20%, 10KB-5MB), 500
reactions, 30 invites (10 revoked), one disabled plugin row. Deterministic
by construction — fixed seed, fixed clock, constant bcrypt hash, explicit
ids and timestamps, VACUUM INTO as the canonical bytes — and
TestAlphaProfileByteIdentical holds the property (two full runs compared
byte for byte; a schema_versions wall-clock leak was the one leak found,
now pinned by the scrub). Two constants deliberately leave no rows and say
why in the package comment: voice sessions are LiveKit-ephemeral, and the
replay log is empty exactly as on a server restarted for an upgrade.

The committed snapshot (3.2MB, under the 5MB LFS line) is the scrubbed
VACUUM of that profile at the alpha.4 migration set - the schema has not
moved since the tag, so it is a true alpha.4 artifact. scrub.sql beside it
also anonymises a real donated database. db/alpha_snapshot_test.go is the
standing canary: provenance (31 applied migrations), HEAD migrations apply
cleanly, and every promised row count checks out, FTS included. Consumers
(B4 HP-4, B6 upgrade rehearsal, B10 in-place upgrade) are named in the
snapshot README and docs/deployment.md.


Claude-Session: https://claude.ai/code/session_01B8dwVLEihnGZYtH9X631F4

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-31 06:12:09 +00:00

4.8 KiB

OwnCord Server (Go)

Go 1.26, module github.com/J3vb/OwnCord/Server. Key deps: chi (HTTP), koanf (config), sqlc-generated SQLite layer, LiveKit server SDK, coraza WAF, prometheus.

Layout

  • api/ REST handlers · ws/ WebSocket hub · auth/ sessions/TOTP · permissions/ role checks · service/ domain logic shared by both entry points
  • db/ hand-written query wrappers; db/dbgen/ is generated (see db-change)
  • cmd/ executable tooling, one package main per subdirectory — cmd/genprotocol/ regenerates the protocol constants from protocol/schema.json, cmd/seed/ fills a dev database (go run ./cmd/seed -confirm-dev; add -profile alpha for the deterministic B3-7 dataset behind Server/testdata/snapshots/v1.2.0-alpha.4.sqlite — regenerate that snapshot only deliberately, per its README), cmd/dbinventory/ prints the db-importer table for docs/architecture/server-boundaries.md (exits 1 on an unlisted importer). cmd/gendocs/ rewrites the route, table and config-key index blocks in docs/ and must be run as go run -tags otel,wazero ./cmd/gendocs (make docs-verify fails on drift). scripts/ holds shell/JS tooling only; no Go entry point lives there
  • admin/ web admin panel · updater/ self-update + signature verification · plugin/ WASM plugin runtime (-tags wazero) · telemetry/ OTel (-tags otel)
  • syncutil/ lock helpers that gain deadlock detection under -tags deadlock

Gotchas

  • Build tags gate whole files, so all four variants must compile: default, -tags otel, -tags wazero, -tags otel,wazero. Tests must also pass under -race and under -tags deadlock. The ci-check skill has the commands.
  • admin/static/index.html is server-owned, and its invariants are locked from two places: text-level ones from admin/perm_grid_test.go and admin/emoji_section_test.go, execution-level ones from Client/tests/contract/ — Go has no JS engine, so a Go port could only grep. Do not "fix" that split by rewriting the contract test as a regex.
  • ws is the hub: broadcast fan-out, per-client send queues, replay, and voice state all interact under several locks. Sequenced frames share one per-client FIFO because clients ack only max(seq) — a frame that skips the queue, or a seq allocated for a frame that is then dropped, is silently unrecoverable.
  • Prefer the standard library. syncutil exists so lock usage is uniform and detectable; do not hand-roll around it. Server/invariants/ enforces this at go test time; exceptions are greppable via grep -rn "invariant:allow" Server/.
  • Only db/ and service/ import db freely. Any other production file that imports it needs a row in invariants/db_import_boundary.go (DBImportAllow) with a disposition and reason — the B3 inventory, which only shrinks. New persistence goes behind a service, not into a handler.
  • Only permissions/ calls the raw permission bit helpers (HasPerm, HasAnyPerm, HasServerPerm, HasAdmin, EffectivePerms, EffectiveChannelPerms). Everywhere else resolves a permissions.Subject and asks the predicate that owns the property (CanViewChannel, CanAdmitSession, CanSendMessage, CanType, CanJoinVoice, CanModerateVoice) — one predicate per security property, so a call site cannot re-derive half a rule. The residue that predates B2-5 is listed by symbol in invariants/authz_chokepoint.go (AuthzResidueAllow) with a class, a reason, and the exact helper calls it is frozen at — a row is an inventory, not a licence for the function, so a second raw call inside a listed one still fails. That list only shrinks too.

Coverage floor

coverage-floor.json holds the aggregate floor and one floor per core package (ws, service, permissions, auth, db); db/dbgen and cmd/ are excluded there because they are generated or entry points, and an exclusion is spelled without a trailing slash (cmd, not cmd/). CI checks it on the Linux leg, after the test steps that share the job. Locally, from Server/:

go test -race ./... -coverprofile=coverage.out -cover
bash scripts/coverage-floor.sh coverage.out

Ratchet. A floor is the lowest Linux figure observed for that package, truncated to 0.1, minus 0.1 where the package varied between runsws and the aggregate do vary, because a few -race branches in ws are timing-dependent and move four or so statements per run. A PR that raises a figure raises that floor in the same PR; the number in the file is what the branch measured, not a stale one. Nobody lowers a floor without a hold-point (HP) entry recording why. Coverage also differs between the Linux and Windows legs, so the floors track the Linux figure and the check runs only there — on Windows the script will report aggregate and ws under floor, by design.