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
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:
@@ -23,7 +23,7 @@
|
||||
* capability slugs the module actually declares in its `module.json`, and
|
||||
* `assertCapabilityCoverage()` fails the build if the two lists drift apart.
|
||||
*
|
||||
* That closes a real gap. `platform.json` holds `moduleUoCapabilities` and
|
||||
* That closes a real gap. `platform.json` holds `games.uo.module.capabilities` and
|
||||
* `scripts/checkFacts.mjs` re-reads it from the module's manifest on every build — so the
|
||||
* day `module-uo` gains a capability, the JSON goes red and someone updates it. Before this
|
||||
* function, updating the JSON was the end of it and the page kept the old list. Now the
|
||||
@@ -188,8 +188,9 @@ const gameIntelligence = {
|
||||
title: 'Game intelligence',
|
||||
moduleSupplied: true,
|
||||
summary:
|
||||
'Supplied by the installed game module, not by the core site. Today that module is ' +
|
||||
'module-uo, and this is what it publishes from a live shard.',
|
||||
'Supplied by the installed game module, not by the core site. Two modules exist, for ' +
|
||||
'Ultima Online and for Rust; this is what the Ultima Online module publishes from a ' +
|
||||
'live game server, and the Rust module brings its own set in its place.',
|
||||
items: [
|
||||
{
|
||||
label: 'Live server status',
|
||||
@@ -490,7 +491,7 @@ export function assertCapabilityCoverage(declared) {
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`src/data/capabilities.mjs disagrees with platform.json's moduleUoCapabilities:\n` +
|
||||
`src/data/capabilities.mjs disagrees with platform.json's games.uo.module.capabilities:\n` +
|
||||
lines.map((line) => ` - ${line}`).join('\n') +
|
||||
`\n\nUpdate the "Game intelligence" items, or the JSON if the module itself changed.\n`
|
||||
);
|
||||
|
||||
@@ -78,26 +78,18 @@ export const notBuilt = [
|
||||
scope: ['features', 'integrations', 'modules'],
|
||||
title: 'More than one game module at a time',
|
||||
body:
|
||||
'One active module per deployment. The database columns that would scope data to a ' +
|
||||
'module exist and are populated, so the door is not nailed shut, but nothing ' +
|
||||
'exercises them and no interface offers it. A community running two games runs two ' +
|
||||
'deployments.',
|
||||
'One module per deployment, and the site enforces it: it loads one module at boot ' +
|
||||
'and refuses every other, with a message saying so, rather than letting two games ' +
|
||||
'share one site. The database columns that would scope data to a module exist and ' +
|
||||
'are populated, so the door is not nailed shut, but no interface offers it. A ' +
|
||||
'community running two games runs two deployments.',
|
||||
resolvedBy:
|
||||
'Someone needing it. The schema was shaped to keep it possible, which is a different ' +
|
||||
'thing from planning it.',
|
||||
},
|
||||
{
|
||||
id: 'second-module',
|
||||
scope: ['integrations', 'modules'],
|
||||
title: 'A second game module',
|
||||
body:
|
||||
'There is exactly one, and it is Ultima Online. A paper dry-run for a Rust module ' +
|
||||
'exists and is deliberately unimplemented — it was written to test whether the ' +
|
||||
'module contract generalises, not to ship. Until a second one exists, "any game" is ' +
|
||||
'an argument about a shape rather than a demonstration.',
|
||||
resolvedBy: 'The first module built for a game that is not Ultima Online.',
|
||||
link: { href: `${GITEA}/docs/src/branch/main/modules/rust-dryrun.md`, label: 'The dry-run' },
|
||||
},
|
||||
// `second-module` was here until phase 13 (PLAN.md §16): "a second game module", resolved
|
||||
// by exactly the event its own `resolvedBy` named — the Rust module's release. Removed
|
||||
// rather than reworded, because an absence that is no longer absent is not an entry.
|
||||
{
|
||||
id: 'integration-kit-draft',
|
||||
scope: ['integrations', 'modules'],
|
||||
|
||||
@@ -12,24 +12,28 @@
|
||||
"wrong protocol number in the first place."
|
||||
],
|
||||
|
||||
"verifiedOn": "2026-09-15",
|
||||
"verifiedOn": "2026-10-22",
|
||||
|
||||
"protocol": 8,
|
||||
|
||||
"moduleApi": "1.10.0",
|
||||
|
||||
"bundle": {
|
||||
"tag": "2026.09.15",
|
||||
"sidecar": "v2.3.0",
|
||||
"overlay": "v1.3.0",
|
||||
"servuoMin": "57.4"
|
||||
},
|
||||
"$comment_moduleApi": [
|
||||
"The one version every deployment shares, whichever game it runs. D66: it is the only",
|
||||
"version the homepage hero and the footer show — a protocol and a bundle belong to a game,",
|
||||
"so they appear on that game's own pages."
|
||||
],
|
||||
"moduleApi": "1.17.0",
|
||||
|
||||
"$comment_releases": [
|
||||
"Every repository whose release the site quotes, flat, so checkFacts.mjs reads them all",
|
||||
"the same way. Which game a repository belongs to is said once, under `games` below."
|
||||
],
|
||||
"releases": {
|
||||
"installer": "v0.8.0",
|
||||
"Android-app": "v0.5.0",
|
||||
"link": "v2.3.0",
|
||||
"installer": "v0.2.0",
|
||||
"Module-uo": "v1.3.0",
|
||||
"Android-app": "v0.5.0"
|
||||
"Rust-Link": "v0.3.0",
|
||||
"Rust-Plugins": "v0.3.0",
|
||||
"Module-Rust": "v0.5.0",
|
||||
"runicnpc-rust": "v1.0.0"
|
||||
},
|
||||
|
||||
"$comment_website": [
|
||||
@@ -40,16 +44,70 @@
|
||||
],
|
||||
"websiteHasReleases": false,
|
||||
|
||||
"moduleUoCapabilities": [
|
||||
"shard",
|
||||
"atlas",
|
||||
"market",
|
||||
"governors",
|
||||
"guilds",
|
||||
"houses",
|
||||
"champs",
|
||||
"cliloc"
|
||||
"$comment_games": [
|
||||
"PLAN.md §16. One entry per game the platform supports. Each game has its own wire",
|
||||
"protocol (declared by its sidecar AND its game-side plugin, and re-read from both) and",
|
||||
"its own bundle on the installer's `bundles` branch, at `v2/<bundleGame>/current.json`.",
|
||||
"The root `current.json` is the schema-1 manifest and is no longer read: it stopped",
|
||||
"moving when the installer went to one bundle per game.",
|
||||
"",
|
||||
"`module.capabilities` is re-read from the module's own module.json, unsorted order being",
|
||||
"the module's business. `name` is the game's own name — D63 lets the site at large say it."
|
||||
],
|
||||
"games": {
|
||||
"uo": {
|
||||
"name": "Ultima Online",
|
||||
"bundleGame": "servuo",
|
||||
"protocol": 8,
|
||||
"module": {
|
||||
"repo": "Module-uo",
|
||||
"coreApi": "^1.10.0",
|
||||
"capabilities": ["shard", "atlas", "market", "governors", "guilds", "houses", "champs", "cliloc"]
|
||||
},
|
||||
"sidecarRepo": "link",
|
||||
"pluginRepo": "servuo-plugins",
|
||||
"bundle": {
|
||||
"tag": "2026.09.15",
|
||||
"sidecar": "v2.3.0",
|
||||
"overlay": "v1.3.0",
|
||||
"servuoMin": "57.4"
|
||||
}
|
||||
},
|
||||
"rust": {
|
||||
"name": "Rust",
|
||||
"bundleGame": "rust",
|
||||
"protocol": 14,
|
||||
"module": {
|
||||
"repo": "Module-Rust",
|
||||
"coreApi": "^1.17.0",
|
||||
"capabilities": ["rust", "servers", "killfeed", "leaderboard", "presence", "wipes", "identity", "map"]
|
||||
},
|
||||
"sidecarRepo": "Rust-Link",
|
||||
"pluginRepo": "Rust-Plugins",
|
||||
"bundle": {
|
||||
"tag": "2026.10.22",
|
||||
"sidecar": "v0.3.0",
|
||||
"plugin": "v0.3.0",
|
||||
"oxideMin": "2.0.7585",
|
||||
"carbonMin": "2.0.259",
|
||||
"requiresPlugins": ["Kits", "ZoneManager"],
|
||||
"runicnpc": "v1.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"$comment_runicnpc": [
|
||||
"RunicNPC — the Rust NPC plugin (PLAN.md §16, D61). It ships in the Rust bundle and also",
|
||||
"stands alone, so it has facts of its own: `api` is the version a calling plugin relies",
|
||||
"on, declared in runicnpc-rust's plugin.toml and re-read from there and from the bundle.",
|
||||
"Its framework floors are its own and differ from the bridge's."
|
||||
],
|
||||
"runicnpc": {
|
||||
"api": 6,
|
||||
"oxideMin": "2.0.7726",
|
||||
"carbonMin": "2.0.259",
|
||||
"requiresPlugins": ["Kits"]
|
||||
},
|
||||
|
||||
"androidApplicationId": "com.runicgateway.app",
|
||||
|
||||
|
||||
@@ -256,7 +256,7 @@ export const canonicalDocs = {
|
||||
'link/ADMIN_CONTROLS.md': 'What the site may command the game to do',
|
||||
'installer/INSTALL.md': 'The operator guide for setting a shard up',
|
||||
'installer/PLAN.md': "The installer's design of record",
|
||||
'modules/rust-dryrun.md': 'A second module designed on paper, to test that the contract generalises',
|
||||
'modules/rust-dryrun.md': 'The Rust module as first designed on paper, to test that the contract generalises — since built',
|
||||
'modules/uo/API.md': "module-uo's own API, including its audience rules",
|
||||
'android/PLAN.md': 'The Android app',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user