feat(docs): phase 15 - the Rust group, its reference pages checked against their sources
All checks were successful
PR checks / checks (pull_request) Successful in 2m5s

PLAN.md §16 phase 15. A Rust group of fifteen pages after Ultima Online
(D70): the module, installing the bridge (installer, Pterodactyl egg, by
hand), connecting the site, verifying the bridge, linking Steam accounts,
permissions and groups, mod config, who sees who is online, events, zones
and rewards, optional plugins, the live map, troubleshooting, and three
reference pages - rust-link's sidecar.toml, the plugin's
RunicGateway.json, and the event kinds.

checkReference.mjs gains three Rust sections rather than a new check:
sidecar.toml keys and RUSTLINK_* overrides from Rust-Link config.rs,
RunicGateway.json from the plugin's PluginConfig, and the event kinds
in three classes against Module-Rust server/catalogue.js (D71). Every
admin screen was walked on the walk site before it was described (D36).

Core pages now hand off to the Rust group instead of linking out to the
docs repository. Three defects the re-read found here are fixed: the UO
/health sample's hard-coded protocol 4 (both games' samples now render
platform.json through <Code>), Authentication's missing Steam tab, and
two pages saying the site cannot reach EventsEnabled - false on Rust.

Installer v0.8.1 moved checkFacts red mid-phase; platform.json follows.

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 15:23:07 -05:00
parent a100195e7b
commit 75c8ffc07a
32 changed files with 1796 additions and 32 deletions

View File

@@ -26,7 +26,7 @@
"the same way. Which game a repository belongs to is said once, under `games` below."
],
"releases": {
"installer": "v0.8.0",
"installer": "v0.8.1",
"Android-app": "v0.5.0",
"link": "v2.3.0",
"Module-uo": "v1.3.0",

View File

@@ -230,6 +230,141 @@ export const bridgeCfg = {
},
};
/**
* rust-link's `sidecar.toml` — `Rust-Link` `sidecar/src/config.rs`, parsed from its serde
* structs the same way as uo-link's above. Each section is one `struct XCfg`.
*/
export const rustSidecarConfig = {
'game.bind': 'Loopback address the bridge plugin dials. Never move it off loopback',
'game.server_id':
"A cross-check against the id the plugin announces. A plugin naming another server is refused before anything it sent is stored",
'web.bind': 'Address the website reaches the sidecar on',
'web.auth_token': 'Shared secret the website must present. Generated and saved on first run if blank',
'store.path': "The sidecar's own database. Relative paths resolve beside the config file",
'store.retain_days': 'Days of raw event history the sidecar keeps. 0 keeps everything',
};
/**
* The environment variables rust-link reads, each overriding one key above. Read from the
* `get("RUSTLINK_…")` calls in the same file. An empty variable is ignored, which is what
* lets a panel declare one and leave it blank.
*/
export const rustSidecarEnv = {
RUSTLINK_GAME_BIND: 'game.bind',
RUSTLINK_SERVER_ID: 'game.server_id',
RUSTLINK_WEB_BIND: 'web.bind',
RUSTLINK_WEB_TOKEN: 'web.auth_token',
RUSTLINK_DB_PATH: 'store.path',
RUSTLINK_RETAIN_DAYS: 'store.retain_days',
};
/**
* The bridge plugin's own config — `Rust-Plugins` `overlay/oxide/plugins/RunicGateway.cs`,
* the public fields of its `PluginConfig` class. The framework writes it as
* `oxide/config/RunicGateway.json` or `carbon/configs/RunicGateway.json`.
*
* `readOnlyFromSite` marks the three keys the site's mod config editor shows but will not
* write: changing them from the website would cut the link carrying the change, or strand
* every row the site holds for this server.
*/
export const rustPluginConfig = {
Connection: {
Host: { why: 'Where the sidecar listens. Loopback is the trust boundary', readOnlyFromSite: true },
Port: { why: "The sidecar's game port. Must equal its game.bind port", readOnlyFromSite: true },
QueueCap: { why: 'Lines that may wait for a wedged sidecar before the oldest is dropped' },
ServerId: {
why: "This server's permanent identity on the website. Not the hostname, on purpose",
readOnlyFromSite: true,
},
},
Events: {
EventsEnabled: {
why: 'Whether the website may borrow values or change this world for events at all. Off by default',
},
EventsMaxCrates: { why: 'Crates one event step may place. Lowerable, never raisable past the ceiling' },
EventsMaxNpcs: { why: 'NPCs one event step may place' },
EventsMaxRecipients: { why: 'People one reward step may name' },
EventsMaxTallies: { why: 'Participation tallies counting at once' },
EventsMaxChat: { why: 'Longest line an event or a news post may say in chat' },
EventsMaxWorldCalls: { why: 'World events one run may call: helicopters, cargo ships, airdrops' },
},
Map: {
MapMaxSleepers: { why: 'Offline sleepers one live-map answer carries' },
MapMaxBases: { why: 'Tool cupboards and vending machines one live-map answer carries' },
},
};
/**
* Every event kind the Rust bridge sends, through its current protocol, as `Module-Rust`
* `server/catalogue.js` classifies them (PLAN.md §16, D71). The module is the side that
* enforces the boundary, so it is what this list is checked against — the same reason the
* UO ladder below is checked against the module and not against prose.
*
* - `public`: a signed-out visitor may see the kind. Some are filtered field by field
* inside it — a name for the presence audience, a position for staff — and that is the
* module's business, summarised on the page rather than restated here.
* - `presence`: public kinds that say a NAMED player was on the server. Their audience is
* an operator's choice on Admin → Rust visibility, staff only by default. A subset of
* the module's public list, kept separate here because that is how a reader needs it.
* - `staff`: admins and moderators, and nobody else.
*/
export const rustEventKinds = {
public: {
'server.wipe': 'The map was wiped',
'server.initialized': 'The server came up',
'server.shutdown': 'The server went down',
'npc.boss.spawned': 'A RunicNPC boss appeared',
'world.event': "Rust's own world events: cargo, helicopters, Bradley, airdrops, the vendor",
'pvp.zone.created': 'Dynamic PVP opened a PvP zone',
'dt.started': 'A Dangerous Treasures event opened',
'dt.won': 'A Dangerous Treasures chest was won',
'gc.started': 'A guarded crate landed',
'gc.ended': 'A guarded crate was cleared',
'raid.started': 'A RaidableBases base appeared',
'raid.completed': 'A raid base was completed',
'raid.purchased': 'A raid base was bought',
'raid.locked': 'An admin locked a raid base to a player',
},
presence: {
'player.connected': 'A player joined',
'player.disconnected': 'A player left',
'player.respawned': 'A player respawned',
'player.death': 'A death — the kill feed',
'player.chat': 'A line of in-game chat',
'player.tally': "A minute's gathering, kills and title counts, summed rather than sent per swing",
'npc.boss.died': 'A RunicNPC boss was killed, naming the killer',
},
staff: {
'entity.destroyed': 'A building part was destroyed — it says where somebody lives',
'player.reported': "One player's report about another",
'player.banned': 'A ban, with the IP address',
'player.unbanned': 'An unban, with the IP address',
'player.login.attempt': 'A login attempt, with the IP address',
'player.approved': 'A login approved, with the IP address',
'account.link.requested': 'Somebody asked for a link code — never the code itself',
'account.unlinked': 'A Steam account was unlinked in game',
'perm.drift': 'A permission or group was changed in game, outside the site',
'config.outcome': "How a config save's reload ended, with the log tail when it failed",
'plugin.loaded': 'A plugin loaded, with the permissions it registers',
'plugin.unloaded': 'A plugin unloaded',
'lease.expired': 'A value an event borrowed was given back on its deadline',
'world.expired': 'Something an event placed ended on its deadline',
'clan.created': 'A clan was created',
'clan.disbanded': 'A clan was disbanded',
'clan.member.added': 'Somebody joined a clan',
'clan.member.left': 'Somebody left a clan',
'clan.member.kicked': 'Somebody was removed from a clan',
'npc.died': 'A RunicNPC NPC died, naming everyone who hurt it',
'npc.health': 'A RunicNPC NPC fell to a health threshold',
'npc.placement.changed': 'A RunicNPC placement changed',
'npc.boss.phase': "A boss changed phase — told in game only to the players near it",
'pvp.zone.deleted': 'A Dynamic PVP zone closed',
'dt.ended': 'A Dangerous Treasures event ended, won or not',
'gc.failed': 'A guarded crate timed out with its guards standing',
'raid.ended': 'A raid base despawned',
},
};
/**
* The five-rung visibility ladder, from `module-uo`'s `server/utils/shardVisibility.js`.
*
@@ -275,5 +410,7 @@ export const canonicalDocs = {
'rust-link/INTEGRATION.md': 'Integrating with the sidecar',
'rust-link/PROTOCOL.md': 'The wire protocol between the bridge plugin and the sidecar',
'modules/rust/PLAN.md': 'The Rust module design of record',
'modules/rust/OPERATING.md': "Running Oxide: uMod's operator pages, plus the notes on RaidableBases and Guarded Crate",
'modules/rust/CARBON.md': 'Where Carbon differs from Oxide, and nowhere else',
},
};