# Maintaining the API reference

The reader-facing entry points are `README.md`, `index.html`, and `232rgs-api-reference.pdf`. The ZIP is a documentation bundle, not an application checkout. Opening its HTML or PDF requires no server or credentials. Run source-dependent checks below from a full repository checkout.

## Sources and outputs

- Chapter sources: `README.md`, `client-api.md`, `operator-api.md`, `wallet-api.md`, `showcase.md`.
- Route inventory, read from the code by `tools/routes.ts`: every route `buildApp` serves with every optional module configured (the dependency set of `test/unit/route-classification.test.ts`) and the app modules `main.ts` loads (`loadProprietaryModules`, with a stand-in secret), plus the metrics listener (`buildMetricsApp`). PSEI (module P) is proprietary and never open-sourced, so its two routes are left out by name (`PROPRIETARY_ROUTES`): the inventory refuses to build unless both are served, and it drops nothing else.
- Derived for every route by `tools/derive.mjs`:
  - request parameters and bodies: each route gets one probe request through the real app, and every zod schema its handler parses the request's params, query, headers or body with is converted by `z.toJSONSchema` (a `pattern` is dropped where zod names a `format`);
  - the credential check (operator key and scope, console session and permission), the handler's source line and the conditions it is registered under; a request body is required unless the handler parses `request.body ?? {}`, and path parameters a handler merges into the object it parses are left out of that object;
  - from the TypeScript program: every reply the handler sends (status, media type, and the TypeScript type of the body; named types become `D_*` components) and its error codes: the error classes it and the functions it calls throw, four calls deep, mapped through the `setErrorHandler` tables in `apps/rgs/src/app.ts` and `apps/rgs/src/console.ts`. The list is static: it can name an error a branch never reaches, and it misses one an untyped call throws.
- Hand-written:
  - `fragments/client.json`, `operator.json`, `wallet.json`: summaries, descriptions, response schemas and examples of the operations documented in September. Their request schemas are replaced by the derived ones wherever the probe saw the validator, and their examples are validated against them. Where a fragment documents a status, the error codes the handler can also answer with are added beside its schema.
  - `fragments/notes.json`: the summary of every other route (a console route `/operator/console/api/X` without an entry takes the entry of `/operator/v1/backoffice/X`), the request bodies the probe cannot reach (Tequity's signed free-bet bodies, the Alertmanager intake), the rules zod cannot export (`requestRules` and `rulesDescription`: a `refine()` or a check in the handler), and the change actions a route's validator accepts but its handler always refuses (`actionRules`, by `changeScope`).
- Common HTTP behaviour and the documented source commit: `tools/assemble.mjs`.
- Outbound wallet schema source: `operator-wallet.openapi.json`; this is a separate server contract.
- Generated files: `openapi.json`, `source-identity.json`, `route-inventory.json`, `endpoint-index.md`, `field-reference.md`, `index.html`, and the PDF.
- The multiplayer WebSocket is documented as a message protocol, not invented as an ordinary OpenAPI HTTP request.

`test/unit/api-reference-routes.test.ts` (in `npm run test:unit`) fails when a served route is missing from `openapi.json` or the document names a route that is not served. To add a route: read its handler, add its summary to `fragments/notes.json`, set `sourceCommit` in `tools/assemble.mjs` to the commit you document, and regenerate. Assembly checks every selected source file against that commit byte for byte and refuses a document whose operations differ from the inventory. Preserve existing cryptographic domain separators and historical release identities.

## Reproduce documentation checks

At the repository root, with its locked Node dependencies installed:

```bash
mkdir -p .runtime/api-docs-verification
uv pip install --python "$(command -v python3)" --target .runtime/api-docs-python -r docs/api/tools/requirements.txt
node --import tsx docs/api/tools/assemble.mjs
node --import tsx docs/api/tools/check-routes.mjs .runtime/api-docs-verification/routes.json
node --import tsx docs/api/tools/check-replay.mjs .runtime/api-docs-verification/replay.json
PYTHONPATH=.runtime/api-docs-python python3 docs/api/tools/validate.py .runtime/api-docs-verification/documentation.json
PYTHONPATH=.runtime/api-docs-python python3 docs/api/tools/reference.py
PYTHONPATH=.runtime/api-docs-python python3 docs/api/tools/render.py
node --import tsx --test test/unit/api-reference-routes.test.ts
```

`requirements.txt` also pins Pillow, which only `finish-pdf.py` uses; a system Pillow serves as well (2 November 2026: 12.1.1).

`check-routes.mjs` sends every inventory route one request without credentials, with every optional module configured: the credential checks refuse and the database answers no rows. It deliberately prohibits business data. A 500 fails it, except on the open routes that read the database first (`/health/ready`, `/metrics`, `/v1/jackpots/{poolId}`), which the stand-in pool cannot serve. It also checks the five SDK CORS preflights, native CORS exclusion, body-size and media-type boundaries. It is not a successful-play integration test.

`check-replay.mjs` executes the actual replay service with explicit in-memory database/RNG/game fixtures for matched, mismatched, missing-runtime and missing-input branches. Its returned bodies are checked against the OpenAPI schema. It is not a PostgreSQL or game-math integration test.

`validate.py` checks both OpenAPI documents, local schema references, explicit examples, every route observation against the documented response for its status and media type, replay observations, source hashes and local Markdown links. Python's `jsonschema.RefResolver` currently emits a deprecation warning; it does not invalidate successful validation.

## Render and inspect PDF

```bash
google-chrome --headless --disable-gpu --no-pdf-header-footer \
  --user-data-dir="$PWD/.runtime/api-pdf-profile" \
  --print-to-pdf="$PWD/docs/api/232rgs-api-reference.pdf" \
  "file://$PWD/docs/api/index.html"
PYTHONPATH=.runtime/api-docs-python python3 docs/api/tools/finish-pdf.py \
  docs/api/232rgs-api-reference.pdf .runtime/api-docs-verification/pdf-visual
PYTHONPATH=.runtime/api-docs-python python3 docs/api/tools/check-pdf.py \
  docs/api/index.html docs/api/232rgs-api-reference.pdf .runtime/api-docs-verification/pdf.json
```

The cover, title and footer date come from `info.version` in `openapi.json`. `finish-pdf.py` adds numbered footers, checks every text glyph for page-boundary overflow and creates six sample-page images plus a contact sheet. Run it once on a freshly printed PDF. Inspect the images; text coverage alone is not visual QA. `check-pdf.py` checks every source text unit against actual PDF extraction; it excludes only the measured footer margin for cross-page text.

Run the relevant repository unit/integration suites separately. Documentation validation does not certify a release, deploy a service, or exercise a provider's live wallet. Maintainer verification results for the September edition are recorded in `docs/api-documentation-verification-2026-09-21.md` in the repository, separately from the externally shareable API reference.
