The documentation half of Phase 11a (website#177, Module-uo#22). Three files,
each carrying one obligation from 6.0b's Phase 11a row.
**MODULE_API.md -> 1.8.0.** A seventh audience ceiling, `admin`, as a child of
`staff`. One addition, no removal, so minor -- every declaration valid under
1.7.0 is valid now and no stored value changes. 2.4's ceiling bullet now names
seven values rather than six, and says the thing a module author actually needs:
`admin` is the ONLY pair in the whole lattice with real containment, so
`permits('staff','admin')` holds and it is the only place `permits` is true
between two values below `authenticated`.
Also corrects two 2.3 rows that were stale rather than wrong: `ctx.inbox.push`
has not thrown since Phase 7, and both members now name the consumer that
actually calls them.
**modules/uo/API.md gains 5**, the full trigger catalogue -- which 6.0b asked for
in as many words ("the full trigger catalogue, its audiences and its ceilings,
not one entry"). The 24 triggers grouped by ceiling with the reason for each
ceiling; the four rows that deliberately do NOT ship with their recorded reasons;
the two that need a patch tier or a v5 overlay; the three things a rule cannot
express and are therefore done in the mapper; the three registered audiences; and
the ingest ORDERING, which is load-bearing rather than incidental.
**BACKEND_DESIGN.md -- the news publish path.** It described a direct
`pushDispatch.publish('news.post', ...)` from the create/publish-post path. That
call is gone: it is an emit through the engagement engine now, so news push rides
a rule, and core seeds that rule disabled. The note says so as an operator-visible
upgrade step, names the separate one-shot settings key and states what did NOT
change -- the announce legs and the post hooks still fire exactly as they did.
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 4 slice 4. BACKEND_DESIGN.md had never been de-UO'd: Phase 3 rewrote core's
code and README, but §5.2's identifier check reads code, not prose, so nothing
ever looked at the design document. It still described 27 shard_* tables, 20 UO
route rows and the shard visibility ladder as core's, a phase after core stopped
being able to serve any of them.
Moved, text unchanged:
BACKEND_DESIGN §3 six shard_* schema sections (226 lines) → modules/uo/SCHEMA.md
BACKEND_DESIGN §4 13 public + 7 admin UO route rows → modules/uo/API.md
BACKEND_DESIGN §6.5 the audience ladder (70 lines) → modules/uo/API.md §4
Core keeps the seam and gains the eight /admin/modules routes it had never
documented. §6.5 becomes "Module-owned audience boundaries": core's security
boundary ends at authentication, roles and the session, and a module that serves
game data brings its own.
Also fixed on the way: users.router.js was still listed as 15 routes (it is 9 —
six went to the extension slot), and the push section still promised
config/shardStreams.js "moves out with it" four slices after it left.
The acceptance table now carries results. Criterion 2 was proved for real against
module-uo v0.3.0 on an empty database, which turned up the uninstall ordering
defect fixed in website#146.
AI disclosure: this contribution was AI-assisted (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
Records the slice that closes the extraction, and adds the two documents phase 3
owed: docs/modules/uo/ and the module-rust dry run.
**The slice found an obligation neither repo had built.** MODULE_API.md §2.8 and
§6.1a settle the OpenAPI fragment in detail — a module ships one, core merges the
fragments of started modules into /api/docs.json. Neither half existed, so the 72
URLs module-uo serves were in no spec at all. §2.8 and §6.1a now record what was
built, including the four things settled while building it: the filename is fixed
rather than declared, a module namespaces what it DEFINES and references core's
shared schemas by core's name, the generator derives its prefixes from the
module's own register() call, and swagger-autogen's diagnostics have to be
captured because it reports a broken annotation and then prints Success.
**§5.3 gains the design decision the frozen manifest actually made:** it is a
SUBTRACTION, not a prefix filter. Generating the manifest without the module and
then with it answers "what does the module serve" AND "did core lose anything",
and the second is the one §1.2 promises to the shipped Android app. A module that
shadowed a core route cannot appear as an addition anywhere.
**BACKEND_DESIGN.md §4.0.1** is new: /api/docs.json is assembled per request, the
two generated artifacts are core's alone, and the route count was still 228.
**docs/modules/** is new, per §2.10 (module documentation aggregates here, not in
module repos): docs/modules/uo/README.md orients a reader on what module-uo
serves, owns and needs from an operator, and links out to the feature docs that
already existed rather than restating them.
**docs/modules/rust-dryrun.md** is phase 3's fourth acceptance criterion. A
written, deliberately unimplemented module for Rust — chosen because it wipes
monthly, runs several servers rather than one shard, identifies by Steam, and
ships RCON so there is no sidecar to write. The contract generalises: same
manifest, same seven registration calls, same schema rules, and six of the UI
kit's seven members wanted by a game with nothing in common with the one the kit
was curated from.
It found one real gap — **a module cannot register an identity provider**, and
"Sign in with Steam" is what a Rust community expects. Recorded as the first
candidate for a future MODULE_API_VERSION bump rather than bolted on: an identity
provider participates in session creation, and §2.7's link-only SSO policy has to
survive it.
Also: website-README.md refreshed from the repo (it was several changes stale),
and three settled decisions added (18-20).
Pairs with Module-uo#6 and website#141.
Co-Authored-By: Claude <noreply@anthropic.com>