3 Commits

Author SHA1 Message Date
be7e1a69ce docs(website): the spawn atlas API, the admin panel, and the delay-unit trap
Docs half of website #113 (Protocol 3.0 Part C, second website PR).

Carries the atlas rewrite that missed #67: that PR merged before the "derive
from the tree on every boot" commit was pushed, so `edge` currently describes
the build/import-artifact design that was rejected in review, not what shipped
in website #112. It lands here.

New in SPAWN_ATLAS.md: the six public routes and five admin ones, and three
behaviours that read as bugs unless they are written down — an unreadable tree
answers 200 with status "unavailable" rather than 500 (refresh reports outcomes
so boot is never blocked by a bad tree, and the contract is preserved at the
API), setting the ServUO path deliberately does not import, and `points` is a
count while `spawners` is the list.

Also the delay-unit trap: XmlSpawner stores MinDelay/MaxDelay in minutes OR
seconds per record, decided by that record's own DelayInSec flag, so a `5` is
five minutes on one spawner and five seconds on the next. Both are plausible
respawn times, which is what makes it silent. 170 of 6,455 stock spawners are
second-flagged. And PARSER_VERSION, which exists because hashing the tree alone
would strand an install whose maps never change on whatever an older parser
derived.

BACKEND_DESIGN.md gains the routes, the router-map entry, and the parser-version
rule. v3.md marks Part C done and records in 6.3 what the API half found.

api-route-inventory.json refreshed from the live manifest — it had drifted to
200 routes before this PR (real count was 204) and is now 215.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U7CBg11prhLimL9iHSX1bP
2026-07-28 19:51:50 -05:00
9a3e1cc1e7 docs(website): correct the CSP delta to one directive and document the report sink
Companion to website "feat(security): soak the tightened CSP on report-only".

The plan's Phase 1 claimed a two-directive delta, one of which was adding
`form-action 'self'` as "currently absent". It was not absent. The directives
object in app.js does not list it, but the middleware runs `useDefaults: true`
and helmet's default set already supplies it, so production has been serving it
all along. The plan was written from the config rather than from the live
header; the correction, and how it was caught, are now recorded in place rather
than quietly fixed.

That leaves `frame-ancestors 'self'` -> `'none'` as the entire behavioural delta
of the phase. Worth noting that this is also the directive that most justifies a
soak: a frame-ancestors violation is reported by the browser of whoever framed
the site, so it is the only available way to discover a legitimate embed before
an enforcing policy breaks it.

Also documented:

  * POST /api/csp-report -- the same-origin sink report-to/report-uri point at,
    why it is same-origin, why it lives outside /api/v1, both wire formats, the
    Reporting-Endpoints header requirement, and the properties that make an
    unauthenticated public POST safe (always-204, caps, truncation, rate limit).
  * That the sink is scoped to the soak, so the enforce PR must decide
    explicitly whether to retire it or keep a report-to group on the enforced
    policy -- rather than leaving an orphan route behind.
  * The `[csp]` log tag in section 7.5 as the thing to watch during the soak,
    and what silence across one release means.
  * client/vite.config.js already sets `modulePreload: { polyfill: false }`, so
    the plan's inline-polyfill prerequisite was already satisfied.

api-route-inventory.json moves 199 -> 200 for the new route. That is the PR 0
freeze working as intended: the first manifest diff since the baseline is a
deliberate, reviewed one.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-27 15:19:43 -05:00
5de5e19445 docs(website): finalize the API plan — in-place router split, no /api/v2
The API v2 plan is revised down to the work that is actually justified: a CSP
hardening pass and an in-place domain split of the monolithic route wiring.

- Auth merge (httpOnly cookies -> bearer + rotating refresh for every client) is
  removed and re-filed as deferred behind trigger conditions. httpOnly+SameSite
  is the stronger model, session.service.js already unifies cookie and bearer,
  the SSO/PKCE transaction cookies survive any merge, and it dragged the admin
  SSE fetch/ReadableStream rewrite along as a dependency for no user-visible
  payoff. A revival must first spec refresh-token reuse detection and a rollback
  procedure.
- No parallel /api/v2. The URL surface is already grouped by capability, so each
  new router file mounts at the prefix it already owns and every URL stays
  byte-identical. No dual mount, no per-route migration, no v1 retirement; the
  SPA, Discord bot, and Android app are all untouched. API_V2_SKELETON.md is
  marked superseded (kept as the recipe if a versioned API is ever forced).
- The /api/mobile facade and app-version floor are deferred with the revival note
  that it starts as a one-line alias mount, not ~70 hand-written delegates. The
  M11 milestone is dropped from android/PLAN.md.
- Adds PR 0: a generated route manifest, so "every URL is unchanged" is proved by
  a zero-line diff rather than asserted in review. The baseline
  api-route-inventory.json (199 API routes + 2 internal) is committed here and is
  what PR 0's generator must reproduce byte-for-byte.
- Split sequenced as five grouped PRs; CSP fixed to report-only first, then
  enforce (the old plan contradicted itself), with the verified delta being just
  form-action 'self' and frame-ancestors 'none'.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-27 14:31:26 -05:00