docs(website): record slice 3, and the boot-order defect it created

MODULE_SYSTEM.md §2.7.2 gains the slice 3 write-up: why the id and version are
written out in MODULES (the offline no-op has to be a file read, not a fetch),
the four decisions, and the table of what the smoke proved against the real
v0.3.0 release on a fresh database.

Two sections are corrected rather than extended. §2.5's "declarative module set"
promise did not anticipate that the two install surfaces need a rule about who
wins — the declaration owns the volume, the row owns whether a module runs — and
decision 4's "resolution runs before the server starts" is true of the SCAN, not
of the process: it runs inside start(), which is what buys it the database.

MODULE_API.md §2.6 no longer says the fragments are replayed by ensureSchema().
They are, for every caller except the server, which scans the volume later than
it ensures the schema and so replays them itself. That was a live defect for an
afternoon: it announced itself only as the "no module scan in this process" skip
line, which is correct output for `npm run seed` and means the opposite in a
booting server, and on a database that already had the tables the module started
perfectly. Nothing in the contract moves, so MODULE_API_VERSION is unchanged.

BACKEND_DESIGN.md: the boot sequence in the tree, and MODULES beside the
module_source_hosts setting it installs through.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-12 07:57:21 -05:00
parent 245be5dc91
commit 102ea6db19
3 changed files with 136 additions and 5 deletions

View File

@@ -55,7 +55,8 @@ server/
schema.sql (+) DDL, also auto-run by the MariaDB container
seed.js (+) seed wiki pages, default settings, first admin
src/
server.js bootstrap: ensure schema, then listen on 0.0.0.0
server.js bootstrap: core schema, seed, resolve MODULES, require app, module
schema fragments, module onBoot, then listen on 0.0.0.0
app.js express app + middleware wiring
router/
api.router.js mounts /v1
@@ -285,6 +286,13 @@ fresh install and changing the variable later cannot reach back in and overwrite
an operator chose. Installs are `https`-only, every redirect hop is re-checked against
this list, and an empty value forbids every install rather than allowing every host.
The **`MODULES`** environment variable (MODULE_SYSTEM.md §2.7.2 decision 4) installs through the same
allowlist and the same verification, without a request: each `<id>@<version>=<manifest URL>` entry is
resolved onto the modules volume during boot, between `seedDefaults()` and the `require` of `app.js`
that scans it. It is not a settings row and is not editable from the panel — a deployment declares
what it runs, the panel shows that it did, and neither owns the other: the variable decides what is
on the volume and `installed_modules.state` decides whether a module answers.
**Keys a MODULE seeds into this table.** `settings` is core's, but a module's
schema fragment may `INSERT IGNORE` its own rows into it, and module-uo seeds two:
`game_account_signup` (default `disabled`) and the one-shot migration marker