Prerequisites:
- Node.js version 19 or higher
- Docker
- Supabase CLI for your OS (follow the instructions here)
- Postgres, need
psql(the client command line)
- Supabase CLI (below). Best when you’re actively editing Edge Functions, since
supabase functions servewatches your TypeScript and reloads on save. - 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.
1
Clone our repository
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 Replace
data/ folder and run:<DB_URL> with the value obtained in step 2.- It should look something like:
postgresql://postgres:postgres@127.0.0.1:54322/postgres
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_IDto the public ID of the v2 application configured below. Never put its secret in aVITE_variable. - [Optional] If you’d like to roll virtual dice,
<DDDICE_API_KEY>must be replaced with the API key to dddice- The API key can be generated by creating a dddice account, visiting “My Account” -> “Developers” and clicking on “Create API Key”
5
Install dependencies
Still in the CI and Docker use the same lockfile and install command. Keep development
dependencies installed when running the content tools or regression tests; their
bundler,
frontend/ directory, run the following: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. Registerhttps://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: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:
content_source.id:
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:
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_idfield 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 adocker-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
.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.2
Bring the stack up
3
Load schema and content data
4
(Optional) Open Supabase Studio
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
Running end-to-end tests
Cypress runs against the Docker stack above. Withnpm 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:
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:connect() wrapper or one of those patterns shows up immediately.
Release verification
Runnpm 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
Error: Cannot connect to the Docker daemon
Error: Cannot connect to the Docker daemon
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.
Error: psql command not found
Error: psql command not found
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, runnpm 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.
