docs(website): record slice 4, and the §5.2 check as built

MODULE_SYSTEM.md §2.7.1 gains the slice 4 record: the 190 dead lines of UO API
bindings slice 3 left behind (with zero consumers, which is why nothing caught
them), the copy rewrite and why the words stay in code rather than becoming a
config surface, the two settings rows core had no business seeding, and the
check that keeps all of it out. The slice table row is corrected to what
actually moved, and README.md is recorded as deliberately deferred to slice 5
rather than quietly skipped.

The defect gets its own subsection with the SQL, because it is a shape that will
recur: a guard in core and the statement it guards in a fragment run in the wrong
order, since core's schema is replayed in full before any fragment. Verified
against a real MariaDB in all three states, including the pinned-instance case
that makes it a one-shot rather than a re-bump.

MODULE_API.md §5.2 stops describing a grep and describes what was built — four
details promoted to contract because each was wrong first: whole-word matching
(a substring pass flags `defaultImage`, which contains "ultIma"), the
comments-then-strings character walk, grandfathering exemptions that fail the
build when they stop matching, and `git ls-files` over a directory walk.

BACKEND_DESIGN.md's settings table gains the keys a MODULE seeds, and the
ordering rule behind them.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-11 21:55:03 -05:00
parent 1b8c2e4806
commit 472e510f6f
3 changed files with 139 additions and 2 deletions

View File

@@ -1052,6 +1052,29 @@ declare their symbols. It can talk about them in English.
Core's UO-flavoured default copy is dealt with directly instead, as `MODULE_SYSTEM.md` §2.7.1's
slice 4 — a rewrite with its own review, not an exemption.
**Implemented in slice 4** as `scripts/checkModuleIdentifiers.js` / `npm run check:modules`, run as
the first step of the server-tests job. Four details are contract rather than implementation, because
each was wrong in a first attempt:
- **Matching is on whole WORDS.** Names are tokenised on camelCase humps and on `-`/`_`/`.`/`/`, and
compared word by word — so `shardStatus` is a hit and `defaultImage`, which contains the substring
"ultIma", is not. `uo`+`link` and `town`+`crier` match only as adjacent pairs; "link" on its own is
ordinary core vocabulary and a check that forbade it would be ignored within a week.
- **Comments and string bodies are masked in one left-to-right character walk, comments first.** A
comment contains quotes and a string contains `//`; no ordering of regexps gets both right. Masked
rather than deleted, so offsets survive and a route path literal is still findable at its own
position.
- **Grandfathering (§6.5) is exempted by an explicit list naming file, identifier and reason**, and
an entry that matches nothing **fails the build**. Core's `LEGACY_TABLE_PREFIXES` and
`LEGACY_STREAM_IDS`/`LEGACY_LEGS` are maps keyed by module id, so grandfathering cannot be written
down without naming who is grandfathered; that is the only sanctioned reason to add one.
- **The file list comes from `git ls-files`**, not a directory walk: an untracked, gitignored,
operator-supplied data file is not core's source and must not fail anyone's build.
The check has its own test suite. That is not optional here — a boundary check is written when the
boundary is already clean, so it never fires again, and nothing distinguishes "still checking" from
"quietly broken" without cases it is required to reject.
### 5.3 Zero-line route manifest diff (CI, both repos)
`npm run routes:manifest -- --check` in core; the module generates and freezes its own manifest in