docs(website): record the landed route manifest and resequence CSP after PR 0 #49

Merged
whitlocktech merged 1 commits from chore/route-manifest into main 2026-07-27 20:00:10 +00:00
Member

What & why

Documentation companion to RunicGateway/website#99 (chore(server): freeze the URL surface with a generated route manifest), which lands PR 0 of the router domain split.

BACKEND_DESIGN.md — new § 4.0, "The authoritative route list"

§ 4's prose tables are orientation for a human reader and can drift. Two generated artifacts cannot, and this section names them and says what each is authoritative for:

Artifact Source of truth for
routes.manifest.json (mirrored as api-route-inventory.json) What URLs exist — introspection-derived, records reality
swagger-output.json What each route means — annotation-derived, documents intent

That split is why the manifest, not Swagger, is the thing PR checks freeze. It also documents routes.guards.json as a review aid that is explicitly not a contract, and records why the manifest excludes the filesystem-conditional static mounts.

§ 2's "Planned change" callout now says the URL freeze is enforced mechanically rather than by review.

API_V2_PLAN.md — PR 0 marked shipped, with its two deviations

  • The optional unauthenticated-status snapshot was tried and dropped, exactly as that section allowed. Against the dead-port mariadb pool the tests use, DB-touching routes sit on the pool's acquire timeout instead of failing fast; a partial sweep had not finished after two minutes. Replaced by a deterministic assertion, straight off the introspected stack, that every /admin/** and /player/** route still carries requireAuth.
  • routes.guards.json is committed and staleness-checked even though a diff in it is not a contract change — an ungenerated review aid rots into a misleading one within a release. The gate is on freshness; the meaning of a guards diff is still "read this", not "justify this".

API_V2_PLAN.md — sequencing corrected: PR 0 now runs before the CSP pair

The plan had CSP report-only → CSP enforce → PR 0. That ordering breaks PR 0's own acceptance test. The CSP report-only PR must stand up a POST /api/csp-report collector for report-to to target — a new URL under /api/**. Landing it first would leave PR 0's generator emitting 200 routes against a 199-route committed baseline, so it could no longer prove itself by reproducing api-route-inventory.json byte-for-byte.

With PR 0 first, the collector shows up as a reviewed, deliberate +1 in the manifest — which is the mechanism working exactly as designed. CSP and the split remain independent otherwise.

api-route-inventory.json is unchanged — and that is the result

The generator reproduced it byte-for-byte on first run. The freeze was already accurate.

How it was tested

Markdown only. Cross-checked every claim against the code in website#99: the 199 + 2 route counts, the generator's scope filter, the guards-file contents, and the --check exit codes in both directions.

Checklist

  • I have read CONTRIBUTING.md.
  • The change builds and existing tests/checks pass locally.
  • I have added or updated tests/docs where it makes sense.
  • My commits are reasonably scoped with clear messages.

AI-assisted contributions (required)

  • No AI tools were used to produce this contribution.
  • AI tools were used. Tool(s): Claude Code (Opus). I have reviewed and understand
    every change, and take responsibility for it. AI-authored commits are
    marked with a Co-Authored-By / Assisted-By trailer.

License

  • I agree that my contribution is licensed under this project's license
    (GNU GPL v3.0 or later), and I have the right to contribute it.
## What & why Documentation companion to **RunicGateway/website#99** (`chore(server): freeze the URL surface with a generated route manifest`), which lands PR 0 of the router domain split. ### `BACKEND_DESIGN.md` — new § 4.0, "The authoritative route list" § 4's prose tables are orientation for a human reader and can drift. Two *generated* artifacts cannot, and this section names them and says what each is authoritative **for**: | Artifact | Source of truth for | |---|---| | `routes.manifest.json` (mirrored as `api-route-inventory.json`) | **What URLs exist** — introspection-derived, records reality | | `swagger-output.json` | **What each route means** — annotation-derived, documents intent | That split is why the manifest, not Swagger, is the thing PR checks freeze. It also documents `routes.guards.json` as a review aid that is explicitly not a contract, and records why the manifest excludes the filesystem-conditional static mounts. § 2's "Planned change" callout now says the URL freeze is enforced mechanically rather than by review. ### `API_V2_PLAN.md` — PR 0 marked shipped, with its two deviations - **The optional unauthenticated-status snapshot was tried and dropped**, exactly as that section allowed. Against the dead-port mariadb pool the tests use, DB-touching routes sit on the pool's acquire timeout instead of failing fast; a partial sweep had not finished after two minutes. Replaced by a deterministic assertion, straight off the introspected stack, that every `/admin/**` and `/player/**` route still carries `requireAuth`. - **`routes.guards.json` is committed and staleness-checked** even though a diff in it is not a contract change — an ungenerated review aid rots into a misleading one within a release. The gate is on freshness; the *meaning* of a guards diff is still "read this", not "justify this". ### `API_V2_PLAN.md` — sequencing corrected: PR 0 now runs before the CSP pair The plan had CSP report-only → CSP enforce → PR 0. That ordering breaks PR 0's own acceptance test. The CSP report-only PR must stand up a `POST /api/csp-report` collector for `report-to` to target — a new URL under `/api/**`. Landing it first would leave PR 0's generator emitting **200** routes against a **199**-route committed baseline, so it could no longer prove itself by reproducing `api-route-inventory.json` byte-for-byte. With PR 0 first, the collector shows up as a reviewed, deliberate `+1` in the manifest — which is the mechanism working exactly as designed. CSP and the split remain independent otherwise. ### `api-route-inventory.json` is unchanged — and that is the result The generator reproduced it byte-for-byte on first run. The freeze was already accurate. ## How it was tested Markdown only. Cross-checked every claim against the code in website#99: the 199 + 2 route counts, the generator's scope filter, the guards-file contents, and the `--check` exit codes in both directions. ## Checklist - [x] I have read [CONTRIBUTING.md](CONTRIBUTING.md). - [x] The change builds and existing tests/checks pass locally. - [x] I have added or updated tests/docs where it makes sense. - [x] My commits are reasonably scoped with clear messages. ## AI-assisted contributions (required) - [ ] No AI tools were used to produce this contribution. - [x] AI tools were used. Tool(s): `Claude Code (Opus)`. I have reviewed and understand every change, and take responsibility for it. AI-authored commits are marked with a `Co-Authored-By` / `Assisted-By` trailer. ## License - [x] I agree that my contribution is licensed under this project's license (**GNU GPL v3.0 or later**), and I have the right to contribute it.
wtclaude added 1 commit 2026-07-27 19:57:39 +00:00
Companion to website PR 0 (chore(server): freeze the URL surface with a
generated route manifest).

BACKEND_DESIGN.md gains § 4.0, naming the two generated artifacts that are
actually authoritative about the API and what each is authoritative *for*: the
manifest records which URLs exist (introspection-derived, reality), the Swagger
spec records what they mean (annotation-derived, intent). The prose tables in
§ 4 are orientation and can drift; those two files cannot. Also documents
routes.guards.json as a review aid that is explicitly not a contract.

API_V2_PLAN.md marks PR 0 shipped and records its two deviations. The optional
unauthenticated-status snapshot was tried and dropped exactly as that section
allowed — against the dead-port mariadb pool the tests use it sits on the acquire
timeout rather than failing fast — replaced by a deterministic assertion that
every /admin/** and /player/** route still carries requireAuth.
routes.guards.json is committed and staleness-checked even though a diff in it
is not a contract change, because an ungenerated review aid rots into a
misleading one.

The sequencing section is corrected: PR 0 now runs before the CSP pair. The CSP
report-only PR must stand up a POST /api/csp-report collector for `report-to` to
target, which is a new URL under /api/**; landing it first would have left PR 0
generating 200 routes against a 199-route baseline, destroying its own acceptance
test. With PR 0 first, the collector appears as a reviewed, deliberate +1 in the
manifest — the mechanism working as intended.

api-route-inventory.json is unchanged, which is the point: the generator
reproduced it byte-for-byte on first run.

Co-Authored-By: Claude <noreply@anthropic.com>
whitlocktech approved these changes 2026-07-27 20:00:03 +00:00
whitlocktech merged commit 9ecfe610de into main 2026-07-27 20:00:10 +00:00
whitlocktech deleted branch chore/route-manifest 2026-07-27 20:00:10 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RunicGateway/docs#49
No description provided.