Skip to main content
Prerequisites:
There are two ways to run the app locally:
  1. Supabase CLI (below). Best when you’re actively editing Edge Functions, since supabase functions serve watches your TypeScript and reloads on save.
  2. Docker Compose (jump to Self-hosting with Docker). Best for trying the full stack end-to-end without installing Node, Postgres, or the Supabase CLI on your host. Also what the Cypress E2E tests target.
Follow these steps to run Wanderer’s Guide locally on your system.
1

Clone our repository

And navigate to the created wanderers-guide directory.
2

Initialize Supabase locally

Make sure Docker is running and then run the following command:
This will print a few details about the Supabase local setup that will be required later.
3

Populate local database

Go into the data/ folder and run:
Replace <DB_URL> with the value obtained in step 2.
  • It should look something like: postgresql://postgres:postgres@127.0.0.1:54322/postgres
This will create all the tables needed.
4

Set environment variables

In the frontend/ directory, copy .env.local.template to .env.local and replace the placeholder variables in .env.local:
  • Replace <API_URL> and <ANON_KEY> with the values obtained in step 2.
  • For Patreon linking, set VITE_PATREON_CLIENT_ID to the public ID of the v2 application configured below. Never put its secret in a VITE_ variable.
  • [Optional] If you’d like to roll virtual dice, <DDDICE_API_KEY> must be replaced with the API key to dddice
5

Install dependencies

Still in the frontend/ directory, run the following:
CI and Docker use the same lockfile and install command. Keep development dependencies installed when running the content tools or regression tests; their bundler, esbuild, is declared directly in devDependencies.
6

Serve the frontend

Use the following to run the frontend locally:
7

Serve the backend

In another terminal window, under the supabase/ directory, run the following:
8

Complete 🎉

Wanderer’s Guide should now be running locally! You can access it at: http://localhost:5173.To be able to log in, you need to have a user in the local database.

Patreon API v2 configuration

Patreon retired API v1 on October 7, 2026. Register a v2 application under the Wanderer’s Guide creator account in Patreon’s developer portal. Register https://wanderersguide.app/auth/patreon/redirect and each local or self-hosted origin’s /auth/patreon/redirect URL that you intend to use. Set PATREON_V2_CLIENT_ID and PATREON_V2_CLIENT_SECRET as edge-function secrets; set VITE_PATREON_CLIENT_ID to the same public ID before building the frontend. WG’s hosted frontend defaults to its registered v2 public client ID; self-hosts must override it with their own creator application’s ID. Client secrets remain server-only. Keep PATREON_CLIENT_ID and PATREON_CLIENT_SECRET for existing grants. New links record their issuing client so token refresh uses the correct credentials. The Account settings contain a collapsed Patreon section whose header shows the saved connection independently of paid tier. Expand it to view Membership and the explicit Connect to Patreon or Reconnect action. Clicking the section header only opens settings; it does not start OAuth. GM sharing controls remain inside the Patreon section for Game Master members. A connected account without an entitled WG tier remains Non-Patron and receives no paid access from the connection alone. The authorization request needs only identity identity[email]: Patreon returns memberships to the app creator’s campaign without access to unrelated memberships. Release the matching frontend and all functions that import _shared/patreon.ts together, using the repository’s release inventory. Verify a real consenting patron can connect and receive their correct tier before declaring the incident resolved. Fixtures cannot verify client registration, secrets, approved redirects, or whether an existing v1 grant is accepted by v2. Some old grants may require a fresh connection using Reconnect in Account’s Patreon section; provider failures retain stored links and group data while paid operations fail closed. They produce no recovery messages. See Patreon’s migration guide. Regression coverage is included in npm run test:api:boundaries, npm --prefix frontend run test:infra, and frontend/cypress/e2e/login/patreonLinking.cy.ts. Provider requests are mocked; these tests never contact Patreon or use a production patron’s credentials.

Agent workspace

Project instructions and skills are consolidated under .agents/, with the entry point in the repository’s AGENTS.md. The frontend and documentation preview commands are recorded in .agents/launch.json; run them from the repository root. Codex’s Mantine MCP configuration remains in .codex/config.toml. The five Quzzar skills are installed locally from Quzzar/skills, with their source revision in .agents/skill-sources.json and routing in AGENTS.md. Local Git worktrees live under .agents/worktrees/. Historical Claude configuration and local permissions are archived in .agents/legacy/. Both directories are ignored by Git.

Validating content

Use the app’s Zod schemas to check a proposed row or JSON array before submitting it:
The file validator also accepts JSON on stdin. Exit codes are 0 for valid content, 1 for invalid content, and 2 for bad arguments or unreadable JSON. For a read-only scan of stored content, supply SUPABASE_URL (the project’s origin, such as http://127.0.0.1:54321) and SUPABASE_SERVICE_ROLE_KEY in your shell’s environment, then run:
To audit one book across all supported content types, pass its positive content_source.id:
The report records sourceId. The scan includes that book’s content_source row and only content rows whose content_source_id matches it. An unknown source ID fails the scan instead of producing an empty success report. Combine --source-id with --tables to check only selected content types. Keep the service-role key in your secret manager or ignored environment file; never put it in a VITE_ variable, source file, or report. The CLI does not load environment files automatically, discover production credentials, or write to the database. Omit --tables to audit all 13 content tables, including hazards stored in the creature table. Use --tables hazard for a hazard-only scan or validate:content -- hazard to check a proposed hazard row. Use --help to list the available types. The audit reads raw rows, including homebrew rows visible to the supplied credential. It checks their structure, not rules accuracy or whether curators have approved them. Results are written to the ignored frontend/scripts/reports/content-audit.json; --out selects a different path. Treat reports as private because they may identify unpublished content. A complete scan exits 0 when valid or 1 when invalid rows exist. Failed reads, malformed pages, invalid configuration, or report-write failures exit 2; never use an earlier report as evidence that a failed run passed. Pagination uses increasing IDs and continues after short pages, accommodating server page-size caps. Each table is bounded by its starting maximum ID. Concurrent edits and deletions can still affect results: this is a live scan, not a database snapshot. Use a snapshot or quiet database when a reproducible full audit is required. Run the audit CLI regression tests with npm --prefix frontend run test:audit:content. They use a local HTTP fixture and require no database credentials. Run the character rules and item drawer regressions with npm --prefix frontend run test:rules. These bundle the actual operation engine and drawer components against explicit local fixtures; selected rules content comes from the checked-in sanitized data dump. They need no running database or authentication account. Historical content-repair tests explicitly use the reviewed pre-repair Git snapshot through readHistoricalContentRows; ordinary readContentRows calls still read the current checked-in catalog. The shared historical reader verifies the pinned commit, blob identity, byte length, and SHA-256 before parsing it. It never replaces data/data.sql or falls back to a private export. A shallow checkout must fetch the pinned commit declared in scripts/historical-content-fixture.mjs, as CI does. Missing or changed historical inputs fail the test. Current catalog behavior and historical migration coverage are separate requirements. Run node --import=tsx --test scripts/list-id-conditionals.test.mjs from frontend for numeric content-ID membership, unchanged name and mode comparisons, and conditional focus grants through character reload, branch replacement, and removal. Run npm --prefix frontend run test:contribution:authoring for the actual Mantine conditional editor’s source-qualified check controls. It mounts synthetic local content and runs Cypress Electron without a database, account or save endpoint. On headless Linux, use xvfb-run -a before the command. The E2E workflow runs this separately from the Node-only rules suite. The content-repair regressions also verify corrected feat grants, narrowly scoped item metadata repairs, and Spined Shield attack math and equipment lifecycle. The content-selection checks in test:infra cover delayed cross-book innate spell display without expanding the selectable catalog. The Treasure Vault equipment-prose cases in test:rules validate four exact remaster catalog tuples, repeated content links, formula suppression, and preservation of existing saved inventory snapshots. These local fixture comparisons are not a whole-book rules audit or a production database check. Tech Core’s introductory spell checks run with node --import=tsx --test scripts/tech-core-introductory-spells.test.mjs scripts/spell-targets.test.mjs from frontend. They verify the six exact spell records, citations, ranks, repeated links, and automatic Starfinder condition links through the real schema and text renderer, including spell Targets in both content and casting drawers, plus spell, feat, and action Trigger and Cost lines. From the repository root, run node scripts/tech-core-spells-native.mjs --output=/absolute/private/evidence-directory for the isolated PostgreSQL import, conflict, pending-submission, replay, and rollback checks. This reuses the owner-verified fixture and cleans up only the containers it creates. It does not update production or certify the rest of the book. The ordinary E2E stack separately exercises content triggers; this native fixture disables those triggers. Tech Core’s next 76 general spells have a separate finite schema, helper, rendered-field, and ten-occurrence indexing regression suite: node --import=tsx --test scripts/tech-core-general-spells.test.mjs from frontend. The native safety runner uses the current catalog and applies the six introductory spells as prerequisites. To construct its plan without starting containers, run node scripts/tech-core-general-spells-native.mjs --output=/absolute/private/evidence-directory. Add --execute-owned-native for its focused isolated PostgreSQL checks; only the fixture’s own uniquely identified resources are created and cleaned up. The focused matrix has 86 rejection cases and two closed-submission controls, plus positive import, runtime binding, complete readback, rollback and no-op replay checks. --matrix=exhaustive explicitly selects a finite matrix totaling 1,555 rejections; it is not the CI default. Both modes retain exact source and reference guards, including Tech Core’s null source dependency and Tech’s current creature-trait flag. CI runs the focused native batch sequentially after the six-spell native suite. Neither local test plan nor native success establishes a complete book audit or production import; ordinary content-trigger and browser checks remain separate. The broad PF2e matrix is part of test:rules: 1,211 comparisons across 469 engine calculations, grouped into 49 named scenarios and a coverage guard. It loads four official sources from the checked-in dump, uses fixed content identities, and freezes fixtures so one calculation cannot change later inputs. A discrepancy fails the command and CI. It requires no ignored audit exports or local database. To run only that matrix:
These are correlated comparisons, not 1,211 independent user journeys. They cover Fighter, Wizard, Rogue and Monk at selected levels, controlled attributes, condition combinations, armor thresholds, variants, replay and selected skill progression. They do not certify complete legal builds, every class/archetype, every property rune or arbitrary homebrew. Absolute rule examples and condition deltas have separate oracles; a baseline comparison alone cannot establish the correctness of that baseline. The rules suite includes the retained PF2e stress cases for combined typed modifiers, attack attributes, armor potency, speed penalties, deterministic condition derivation, and explicit Drained/Dying/Wounded transitions. The infrastructure suite verifies coupled HP/condition conflicts, including companion levels and lost acknowledgements. The Cypress conditionMath.cy.ts and encounterSync.cy.ts specs exercise these edits through actual sheet and GM controls, local API saves, mobile viewports, reloading, and simulated connection failures. They create and clean up synthetic characters. The sheet spec also holds a required content response, verifies no partial save occurs, then checks nested homebrew variables and binding chains through level changes and reopening. A cyclic homebrew graph must recover quietly without persisting partial math. The fast homebrew tests cover conditional custom Lore, binding order, self-links, repeated assignments, long chains, and companion isolation. Run request recovery, buffered character saves, and worker lifecycle regressions with npm --prefix frontend run test:infra. These exercise the real request manager, save hook, and operation lifecycle with controlled authentication, network, storage, and worker boundaries. They require no running database or production credentials. CI runs these regression suites before the production build. The content selector tests also exercise an already typed search while its catalog is still loading, and verify that removed sources or filtered choices disappear from search results without another keystroke. Timing failures belong in the correctness suite when they can change results. Cache tests hold IndexedDB reads, writes and deletion independently: fresh downloads must continue, and a late cache cannot resurrect content a completed download says is absent. Worker tests include the production four-worker pool, queued companions, rapid owner changes, reversed completions and a worker failure. These are deterministic integration tests with controlled I/O boundaries; Cypress adds the actual browser, worker and API. A passing run is evidence for these behaviors, not a universal clean bill of health or a physical iPhone/Android performance benchmark.

Creating a user

1

Visit Supabase studio

Go to the local supabase studio URL (default http://127.0.0.1:54323)
2

Create internal user record

On the authentication page, create a new user with email and password. Copy the user UID generated.
3

Create public user record

Go to the Table Editor page and select the public_user table.Create a new Public User record by clicking Insert -> Insert row.
  • Make sure to fill in the user_id field with the user UID generated in step 2.
4

Login to Wanderer's Guide

Back in the running Wanderer’s Guide, you can now log in with the email and password you had set.

Self-hosting with Docker

If you’d rather not install Node, Postgres, or the Supabase CLI on your host, the repo ships a docker-compose.yml that bundles the frontend with a self-hosted Supabase stack: Postgres, auth, REST, storage, edge functions, and the Kong gateway. Only Docker is required.
1

Configure environment

Edit .env to set JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, and POSTGRES_PASSWORD.For local testing, the demo values from the Supabase docker example work as a matched set.
Do not use those demo values on a publicly reachable host. Generate fresh keys for any deployment.
2

Bring the stack up

3

Load schema and content data

This wipes and reloads the public schema. Run it only for a disposable local database; back up any local characters or homebrew you want to keep first.
4

(Optional) Open Supabase Studio

Studio is handy for inspecting the DB while developing.
5

Open the app

Visit http://localhost:3000 and sign up with email + password.The DB ships with a trigger (installed by create-db-docker.sh) that auto-creates the matching public_user row, so the manual Studio insert from the Creating a user section is not needed for the docker stack.

Common docker operations

For the full wiring notes, what’s included, and what you’ll have to set up yourself (OAuth providers, SMTP, TLS termination, schema and content seed), see the Docker self-hosting guide.

Running end-to-end tests

Cypress runs against the Docker stack above. With npm run docker:start already running:
cy:e2e bakes in CYPRESS_BASE_URL=http://localhost:3000 and the default test creds (test@wanderersguide.app / test1234). The content/treasure-vault-references.cy.ts catalog-only cases require ANON_KEY in the Cypress process environment, matching the public anonymous JWT used by the local frontend. Cypress maps it to publicAnonKey; CI already supplies it. These cases read public catalog data without creating an account or inventory. Use the public anonymous key, never the service-role key. The Cypress commands preserve existing NODE_OPTIONS and disable synchronous ES module loading for the test process. This lets Cypress 13 load the existing configuration with its TypeScript loader on Node 20. CI uses the same cy:run entry point; application and API runtime options are unchanged. To scope to a single spec:
The characters/calculationRecovery.cy.ts and characters/saveRecovery.cy.ts specs verify worker failure/retry and retained-edit recovery in the rendered app, including desktop and mobile screenshots. Both create and clean up their own local test character. The characters/connectionRecovery.cy.ts spec interrupts real character writes, lets a real committed response exceed the client timeout, and prepares spells at phone width with 4× CPU throttling before interrupting saving and reopening the page. Assertions read the local database through the API as well as the UI. It uses only its own test characters. These scenarios simulate flaky transport, constrained CPU and page lifecycle boundaries, not iOS/Android process eviction or a measured physical-device performance profile. The save-hook regressions also cover uncertain writes, intentional reversions, separate-tab drafts, storage exhaustion, and account changes. Save failures and session expiry stay quiet, including conflicting edits. Conflict cases verify retained local input and the unchanged competing server version through reload, then automatic guarded saving after a background read finds a compatible version. Hook regressions also cover ordinary edits resolving a conflict, remote fields changing while saving is paused, uncertain-write reversions, and repeated-conflict loop guards. The characters/contentRecovery.cy.ts cases verify automatic content recovery without technical error screens or partial saves. Already loaded views keep their last complete library during retries; source changes pause calculations and derived saves until a complete matching replacement arrives. Character reads, drawers and content selectors also retry quietly. App updates never display reload prompts. The characters/contentDownloads.cy.ts regressions delay real feat-catalog responses by 31 seconds and verify class details, sheets, Builder, and PDF/JSON file downloads. They use a private local test account and disable persisted content caching for each visit. Bulk catalog reads allow up to two minutes for transfer and JSON parsing; single-record reads and writes retain their 30-second deadline. Expired reads abort before later retries, while uncertain writes retain their existing recovery behavior. The characters/mobileLoading.cy.ts scenario applies 150 ms latency, 192 KiB/s download throughput, 96 KiB/s upload throughput, and 4x CPU throttling before visiting the app. It creates a fresh account scope, loads a sheet, waits for the actual content cache transaction, and reloads with a delayed freshness check and unavailable catalog endpoints. The cached sheet must become usable without replacement catalog requests. The worker-package regression in test:infra runs the real worker entry point, controller, and content store with network and authentication lookups unavailable. It checks grants, source boundaries, consecutive packages, missing tables, and cleanup after failure. Separate cases cover cross-book references: their existing scoped lookup must still work online and fail clearly when an uncached dependency cannot be downloaded. The real Wizard fixture also exercises its legacy trait-name filter with all network access disabled; duplicate trait names preserve the API’s first-by-ID result across INFO and PAGE while selection lists keep their PAGE source boundaries. Use a production build and preview for startup measurements; development modules have different download behavior. These are controlled Chromium scenarios, not measurements on a physical phone. After npm --prefix frontend run build, run npm --prefix frontend run test:build. This checks the generated service worker and output files: the app shell stays precached, the developer report is excluded, and the optional game-icon chunk is cached after use. Bundle reports are written to frontend/.scratch/bundle-stats.html for local analysis. The first use of a game icon or icon picker can require a download; reopening it can use the runtime cache. The complete icon library is not fetched on an idle timer. The encounter writer regressions run in test:infra. They exercise GM/player races, serialized HP edits, lost acknowledgements, narrow guarded writes, retained drafts, and failure/conflict responses. The encounter keeps unsynced edits visible and retries transport failures quietly. Conflicting writes recheck the remote row every five seconds and resume only when merging is safe; normal GM edits also recheck a paused conflict. Disposing the writer cancels those reads. Forbidden and rejected writes retain their existing guards. All remain silent without recovery messages or conflict-choice controls. Navigating away preserves the versioned local draft when browser storage is available; the campaign does not automatically restore old drafts into encounter controls on a new visit. campaigns/encounterSync.cy.ts creates two confirmed synthetic accounts, joins a real campaign through its join-key API, and tests the actual GM HP control while the player updates the same character independently. It covers typing during polls, Enter/blur deduplication, nested player edits, failed reads/writes, retry, and mobile layout changes. Fixture tasks require SERVICE_ROLE_KEY in the Cypress Node process and refuse non-local HTTP origins. The key is never put in Cypress browser configuration; generated accounts send no email, and cleanup verifies their ownership and removal even after a failed run. The characters/skillProgression.cy.ts spec creates an official Fighter/Skill Mastery fixture through the local API, runs the real operations worker, and checks master Medicine and its earlier expert-increase selector on desktop and mobile. The engine regression suite also covers Medic, repeated mastery, source-level caps, removal/regrant and creature store isolation. The same suite runs in CI on every PR via the e2e workflow. See .github/workflows/e2e.yml.

Running the API tests

Beyond the UI Cypress suite, the Edge Functions have their own Deno-based test harness:
The harness covers the auth-routing flow plus one representative test per pattern (find / create / update / delete / search), so a regression in the shared connect() wrapper or one of those patterns shows up immediately.

Release verification

Run npm run test:release and npm run release:check from the repository root after installing frontend dependencies. CI runs these checks and archives the function/schema manifest. The production content snapshot refreshes weekly or by manual dispatch, independently of code pushes. See Release and recovery for the read-only production gate, including release:verify:functions before schema changes, migration baseline and rollout order. Run npm run test:content:contracts for the checked-in migration input, historical guard and safety-runner regressions. These use local files and bounded models, not a running database, production credentials or private audit exports. Run npm run test:content:native -- --release with Docker running to rehearse the Treasure Vault repairs against the explicit historical sanitized catalog and actual checked-in schema. Its input manifest separately records and verifies the current working-tree catalog and the immutable historical Git input. The historical fixture starts before the repairs so insertion, allocation, rollback, and own-stage checks remain exercised. The ordinary E2E job instead starts from the current dump, installs the actual content triggers, and runs the complete chronology and registered replays. Both modes must pass. The historical native fixture adds only the exact captured Tech Core source and Junk trait immediately before the introductory spell migration. It includes Station only when the captured chronology also contains the general spell batch. Earlier historical ledgers stay unchanged. The supplement retains content triggers and checks full rows, unrelated tuples, sequences, an injected late rollback and exact replay in both owned fixtures. Full schema and role preservation also use the existing postcommit snapshots. These fixture checks do not add or change prerequisites in production. The native runner requires locally available PostgreSQL 15.6 and GoTrue images and a local Docker engine. It creates uniquely owned offline containers without published ports. Each new test PostgreSQL container is limited to 1 GiB of memory, no swap and one CPU, with fresh limit checks recorded in its receipt. These limits apply per container, not to the whole machine; existing containers are unchanged. An out-of-memory or timeout failure remains a failed test. The runner performs a genuine signup and checks the public-user trigger, then tests guarded updates, pending proposals, rollback, read-only checks, saved-copy preservation, exact replay and concurrent writer ordering. It also calls the shared terminal helper as the image’s existing supabase_read_only_user inside a read-only transaction. The verifier has its own direct execution grant; it receives no application or administrator role membership. Receipts record the image tags, observed immutable image IDs and matching Auth binary and health versions. An Auth image reporting an unspecified build version is recorded as such, not as a confirmed runtime semantic version. Version checks retain raw stderr and accept only empty output or the pinned binary’s exact single informational shutdown record. Other diagnostics fail verification. The runner verifies its complete input manifest before and after execution and recomputes the catalog, source and authored-content comparisons from actual database rows. Preservation snapshots hash the complete PostgreSQL binary row, including every live column, generated field, NULL marker and column type. They still read all current public, Auth and proof relations and sequences, capture all roles and memberships, and take a complete schema dump. These binary hashes are compared only within the same owned PostgreSQL 15.6 fixture. The reviewed portable catalog and release fingerprints keep their existing JSON derivation. Only its own containers and anonymous volumes are removed. It does not reset another local stack, access production or certify every possible character build or all authentication and authorization behavior. The sanitized snapshot lacks private curator proposal bodies, so acceptance of those exact private bodies remains untested. An optional output filename saves the receipt without overwriting an existing file. CI runs representative failure cases in a separate content-native job with a 120-minute budget. Each repair retains direct rejection and late rollback coverage. The terminal checks retain representative stale/partial state, pending conflicts, identity/allocation and source/dependency failures. All actual positive migrations, complete preservation snapshots, shared-helper compatibility, permission checks, concurrent writers and alternate allocations still run. The receipt explicitly records reduced negative coverage and never claims an exhaustive pass. It runs the fast contract tests before pulling images or creating a fixture. These include passing the complete captured migration chronology through the alternate allocation guard, so a stale migration count fails immediately. The chronology also checks the exact three-record source correction, its old-helper upgrade, replay, conflicting proposals, partial states and late rollback. Those controls preserve the other catalog rows and saved-item copies. The two reviewed Bagpipes classifications have a separate, complete-pair comparison allowance. It recognizes only their exact approved GENERAL rows and does not change content, hide fields from hashing, or broaden the three-record correction. Mixed or otherwise edited rows remain rejected. Its owned database does not share a runner with the browser/API stack. The ordinary E2E job keeps its two-hour budget and runs independently; both jobs must pass before release. Local fixture limits remain the same. The exhaustive matrix is separate from routine releases. Run npm run test:content:native locally or select exhaustive-content when manually dispatching the E2E workflow. That explicit manual run has a six-hour budget. After the safety step, CI uploads generated receipts, redacted stage logs and dual-ledger hashes to the treasure-vault-native-<commit> artifact. The upload runs even if that step fails and includes only these generated files, not other backups or database dumps. It does not change the test result. Logs record their sequence number and observation time. Every orchestration checkpoint drains all queued byte writes before another owned action, so a timeout artifact retains the observed progress instead of an arbitrarily delayed prefix. Logging failure stops verification and remains a failure while independent owned cleanup still runs. For a focused iteration, append --only-negative=<exact migration filename> (or comma-separated filenames). This narrows only failure-injection cases; all positive migrations, read-only checks, full preservation and replay still run. The receipt records this reduced negative coverage. It cannot be combined with --release, whose representative cases are fixed by the checked-in selection policy. Omit both options for the exhaustive safety suite.

Troubleshooting

This is a common issue when Docker is not running or not properly installed. Make sure Docker is installed and running on your machine.In the case of a Mac or Windows machine, you can try restarting Docker Desktop.
This error indicates that the psql command-line tool for PostgreSQL is not installed or not in your system’s PATH. You can install it by following the instructions on the PostgreSQL website.If you have PostgreSQL installed but still see this error, ensure that the directory containing psql is included in your system’s PATH environment variable.
Curious about how to contribute? Check out our Discord server and GitHub issues!

Infrastructure regression checks

With the local Docker database running and migrations applied, run npm run test:authorization to check denied profile/moderation writes, character ownership, signup and trusted writes. Its synthetic accounts and changes roll back. npm --prefix frontend run test:infra covers cache generations, partial-content failures, account recovery and nested save conflicts. npm run test:release also checks semantic health-probe behavior without reaching production. The optional browser diagnostic intake accepts only bounded categories and a build revision. Vite embeds the Git commit (Render uses RENDER_GIT_COMMIT). Raw error messages, character data and tokens are never part of that request. The shared-ancestry successor adds twelve explicit full-row owners, including Halfling ancestry #7, which was outside the original Treasure Vault ledger. Fast contracts exhaust all 4096 before/after combinations and verify UUIDs using the actual upload function. Native controls exercise partial moves, unrelated fields, pending routes under both identities and either submitted source field, full preservation and exact replay. All 35 controls are required by the independent receipt verifier, including the positive and negative actual feat-count witnesses. The primary runs the actual move after completing the historical digest and alternate allocation comparisons; the alternate runs it at its registered late chronology position before all registered release checks and historical replays. Both retain the original historical row hashes. The complete chronology now has 113 migrations and 106 registered requirements with 69 distinct queries, producing 386 registered replay statements. No historical SQL body or negative coverage is removed.