feat(facts): phase 13 - per-game facts, Rust and RunicNPC checked, main green again
All checks were successful
PR checks / checks (pull_request) Successful in 8m25s

platform.json drops the single protocol/bundle/capability list for a
`games` object (uo, rust) plus a `runicnpc` block. checkFacts.mjs loops
the protocol, plugin-protocol, capability and bundle checks over both
games, reads the schema-2 bundles at v2/<game>/current.json, checks each
module's coreApi, and reads RunicNPC's plugin.toml. 41 facts, up from 19;
clears the two that were red on main (Module API 1.17.0, installer
v0.8.0).

D66: the hero, footer and structured data show the Module API only; each
game's protocol and bundle go on that game's pages, and the docs landing
table splits into shared versions plus one column per game.

The re-read section 1 requires found, and this fixes:
- three hard-coded "1.6.0" Module API versions in the module docs
- module-lifecycle saying modules load alphabetically (the loader now
  refuses a second module, W19), and the install pages never mentioning
  the one-module rule
- "there is one module" in five places, now two modules both built
  inside this project; the Integration Kit keeps its draft banner
- the homepage diagram's ServUO/uo-link sub-labels (D63 wording now)

notBuilt drops `second-module` (resolved by Module-Rust's release) and
rewords `multi-module`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-22 08:09:22 -05:00
parent 2971b84d51
commit 9938e71e07
29 changed files with 384 additions and 154 deletions

58
PLAN.md
View File

@@ -237,7 +237,7 @@ Taken by the org lead (Colby Whitlock) on 2026-08-19. Recorded so they are not r
**Decisions after D13 are recorded where they were taken**, in the section describing the phase that
raised them, rather than appended here — a decision is only re-litigated when its reasoning is
somewhere other than the thing it decided. The count of record is **sixty-five**:
somewhere other than the thing it decided. The count of record is **sixty-six**:
| # | Where | What it settled |
|---|---|---|
@@ -255,6 +255,7 @@ somewhere other than the thing it decided. The count of record is **sixty-five**
| D58 | §6, "How phase 12 delivered it" | `node_modules` ships in three layers because Cloudflare refuses a request body over 100 MB, and the workflow counts layers before it pushes |
| D59 | §6, "How phase 12 delivered it" | The container publishes on every interface (amending D55), with `SITE_BIND_ADDR` to narrow it |
| D60–D65 | §16, "The six decisions" | Per-game sidebar groups, RunicNPC inside Rust with its own page, the RunicNPC API carried in full with a drift check, game names allowed but game vocabulary confined, a twelfth check that enforces it (amending D53), Rust screenshots last and from the rigs |
| D66 | §16, "How phase 13 built it" | The hero and footer show the Module API only; a protocol and a bundle belong to a game |
---
@@ -1609,11 +1610,12 @@ a mechanism rather than diligence:
| Fact | Authority |
|---|---|
| Protocol version | `link` `main:sidecar/src/main.rs` → `PROTOCOL_VERSION` |
| Overlay protocol | `servuo-plugins` `main:overlay.toml` → `protocol` |
| Protocol version, per game | the game's sidecar repo (`link`, `Rust-Link`) `main:sidecar/src/main.rs` → `PROTOCOL_VERSION` |
| Plugin protocol, per game | the game's plugin repo (`servuo-plugins`, `Rust-Plugins`) `main:overlay.toml` → `protocol` |
| Module API | `website` `main:server/src/modules/version.js` → `MODULE_API_VERSION` |
| Module capability list | `Module-uo` `main:module.json` → `capabilities` (added in phase 3) |
| Bundle + component pins | `installer` branch `bundles`, **root** `current.json` |
| Module capabilities + `coreApi`, per game | `Module-uo` / `Module-Rust` `main:module.json` (capabilities added in phase 3, both games and `coreApi` in phase 13) |
| Bundle + component pins, per game | `installer` branch `bundles`, **`v2/servuo/current.json`** and **`v2/rust/current.json`** (phase 13; the root `current.json` is the frozen schema-1 manifest) |
| RunicNPC API, floors, required plugins | `runicnpc-rust` `main:plugin.toml`, and the Rust bundle's `npc` block (phase 13) |
| Release versions | Gitea releases API per repo |
Same mechanism and the same intent as the Integration Kit's `checkCoreApi.js`: when the platform
@@ -1974,6 +1976,52 @@ module collects, Steam ids first, before anything is claimed there. `checkTerms.
**Phase 18 — screenshots** (D65), plus the emulator pass for `/app/`'s Rust screens. This is the only
phase that needs the rigs.
### How phase 13 built it
One decision, **D66**, taken 2026-10-22 when the restructure reached the homepage. The count of
record is now **sixty-six**.
**D66 — the hero and the footer show the Module API only.** Both used to read "Protocol 8 · Bundle
2026.09.15", which was a description of the platform while there was one game. There are now two
protocols and two bundles, and neither belongs on the front door. The hero and footer show **Module
API**, the one version every deployment shares. The structured data's `softwareVersion` reads the
same value. Each game's protocol and bundle are on that game's pages, and the docs landing page
splits its table in two: shared versions, then one column per game. The alternative was per-game
chips on the hero ("Ultima Online: protocol 8, bundle … · Rust: protocol 14, bundle …"). It was
declined as busier and as putting game facts on the front door.
**`platform.json` is per game.** `protocol`, `bundle` and `moduleUoCapabilities` are gone. In their
place is a `games` object (`uo` and `rust`, each with its protocol, its sidecar and plugin repos, its
module's capabilities and `coreApi`, and its bundle pins), plus a `runicnpc` block for the plugin's
API version, framework floors and required plugins. `releases` stays flat, so every repository's
release is read the same way. **41 facts** are now checked, up from 19. Checks 1, 2, 4 and 5 loop
over the games, and the bundle reads `v2/<game>/current.json` and refuses anything but schema 2.
**What the re-read found** (§1 obliges a re-read of every page that quotes a changed value):
- **Three hard-coded Module API versions in prose**, all saying 1.6.0, on *The module API* and *The
module manifest*. §12 has forbidden that since phase 1. Nothing caught it because `checkFacts`
guards `platform.json` and not the prose. All three now read `platform.json`. The manifest page's
worked example of a caret range now quotes the two modules' real `coreApi` ranges, which are
checked facts as of this phase.
- ***Module lifecycle* said modules load alphabetically.** That stopped being the whole truth on
2026-09-23, when the installer began refusing a second module, and stopped being true at all on
2026-10-22, when the loader began refusing one (W19). The page now says what the loader does. *Installing
modules* and *Managing modules* had never mentioned the one-module rule at all, and now do.
- **"There is one module" was false in five places.** Those were the `/architecture/` seam drawing and its
"what this does not yet prove", `/community/`, the `/features/` lede, the Game intelligence
summary, and the homepage's list of absences. Each now says two modules exist, both built inside
this project, and that the Integration Kit keeps its draft banner until someone outside does it.
- **The homepage diagram's sub-labels** said "ServUO today" and "uo-link". They became false the day
Rust shipped, so they changed here rather than waiting for phase 17. They now carry D63's wording.
The caption names both games.
**One planned item moved to phase 17.** §16 put the Rust half of `capabilities.mjs`'s *page* coverage
assertion in this phase. But a coverage assertion needs a list of Rust capabilities on a page to
cover, and phase 17 is the phase that writes that list. Phase 13 does the half that has something to
check: `checkFacts` now holds Module-Rust's declared capabilities against `platform.json`, so a
capability the module adds turns this repo red today. The page-side assertion lands with the page.
---
[api]: https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/website/MODULE_API.md