docs(runicnpc): stage 9b built; INSTALL and COMMANDS; RunicNPC required (D315, D316)

- runicnpc/PLAN.md: 9b built and measured; D315 (the performance check records
  today's cost, the warning says it, idle overhead is runicnpc-rust#13) and D316
  (the picker keeps Rust's own; a step on a server without RunicNPC is refused
  on save).
- runicnpc/INSTALL.md (new): requirements, the installer and egg, by hand
  without Runic Gateway, Kits and ZoneManager reported not installed, its files,
  the cost warning with stage 9's numbers, caps, and after a Rust update.
- runicnpc/COMMANDS.md (new): every /rnpc verb and console command with its
  permission, options and defaults, and how to read rnpc.status.
- rust-link/INSTALL.md: RunicNPC is required; the installer refuses a bundle
  without it and doctor fails. (The plan named modules/rust/OPERATING.md, which
  is a verbatim uMod mirror; this is the operator guide that lists Kits.)
- rust-link/PROTOCOL.md: §19.16, every NPC placement needs RunicNPC; no message
  changes shape.

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-06 21:35:04 -05:00
parent 6cd24bd302
commit eec8e6e698
5 changed files with 306 additions and 11 deletions

View File

@@ -12,7 +12,8 @@ and **its build's own questions answered 2026-10-01** (D267–D272). **Stage 5 b
site 2026-10-05** on both rigs (§9); its API is [API.md](API.md) version 4. **Stage 6's design answered
2026-10-05** (D273–D282, §0), **its spike measured 2026-10-05** on both rigs, and **its two questions answered the
same day** (D283, D284, §9). **Its build's own questions were answered the same day too** (D285–D289), and **stage 6 was built and walked on the site 2026-10-05** on both rigs (§9); its API is [API.md](API.md) version 5. **Stage 7's design answered 2026-10-05** (D290–D299, §0). **Stage 9's design answered 2026-10-06**
(D306–D314, §0 and §9).
(D306–D314, §0 and §9). **Phase 9b was built 2026-10-06** (§9), with its two questions answered the same day (D315,
D316).
RunicNPC is Runic Gateway's own NPC plugin for Rust servers, in its own repository,
[`RunicGateway/runicnpc-rust`](https://gitea.whitlocktech.com/RunicGateway/runicnpc-rust). It runs on Oxide and
@@ -136,6 +137,8 @@ architectural or design decision is implemented.
| **D312** | **The player walk is one checklist in one session per rig.** Every in-game check deferred so far is gathered with stage 9's own. I prepare the rigs and the walk site, the org lead plays, and I watch the logs and record the results (stage 9). | A checklist per stage; release without a player walk. |
| **D313** | **v1.0.0 is one coordinated cutover.** After the walk passes, `edge` goes to `main` in all five Rust repos: RunicNPC v1.0.0 first, then the bridge, the sidecar, the installer and the bundle that pins them, and the module's requirement last (stage 9). | RunicNPC alone first, the rest later. |
| **D314** | **Core's public phase label is fixed in stage 9**, in its own website PR. `eventPublic.phaseLabel` matches a phase by `key`, which specs use, and still accepts `id`; its test fixture moves to `key`. It has said "Under way" for every phase since Events Phase 14a, UO's events included (stage 9, from docs#323). | A website issue for later. |
| **D315** | **The performance check records what 100 NPCs cost today, and the cost warning says it; the idle overhead is an optimisation issue, not a release blocker.** Stage 1's own bare NPC no longer meets stage 1's bar on today's rigs (fighting +7.5 / +8.0 ms against +5.2), and RunicNPC fights at the same cost; awake idle on Oxide is about 2 ms per 100 over the bare NPC (runicnpc-rust#13). Narrows D306 (stage 9b; the org lead: "Write a warning for it, log it as an optimization bug fix issue on gitea and keep going"). | A same-session bar against the bare NPC; fixing idle before v1.0; keeping D306's absolute bar. |
| **D316** | **On a server without RunicNPC, the Place NPCs picker keeps listing Rust's own scientists, and the step is refused when saved, with the reason.** Core's option sources cannot show a module's reason (a refusal reads only "could not be read"), and Admin → Rust → Servers already says "Incomplete". Narrows 9b's "the picker shows the same reason instead of a list" (stage 9b). | A core change letting an option source answer a reason (MODULE_API minor); an empty list. |
**Borrowing, not copying.** NpcSpawn states no licence at all, so its source grants us nothing and is read only as a
description of *what* can be done in Rust. HumanNPC is MIT on uMod, which is GPL-compatible, but §1.2 rules out its
@@ -1615,6 +1618,39 @@ is asked before the next one starts.
harness of stages 1 and 5. It passes at about +1 ms and +5 ms of median frame over that session's empty baseline.
The numbers go into INSTALL and the cost warning.
**9b built (2026-10-06).** Rust 25681086, Oxide 2.0.7801, Carbon 2.0.262 on both rigs.
- **Core's phase label (D314):** website PR. `phaseLabel` finds the phase by `key`, then `id`; the fixture uses
`key`, and a unit test covers a UO-shaped spec, the fallback and key-before-id.
- **RunicNPC is required (D310):** `module-rust` asks every Place NPCs step for RunicNPC first ("Main needs
RunicNPC to place NPCs, Rust's own scientists included: RunicNPC is not loaded on it"), and its floor rises from
API 4 to the bridge's 6, so a server the site calls ready is one the bridge will not refuse. Admin → Rust → Servers
carries each server's `runicNpc` and reads "Incomplete" with the reason. The picker is unchanged (D316). The
bridge refuses one of Rust's own NPC prefabs the same way, before anything spawns, and a profile placement now
refuses an old RunicNPC up front (PROTOCOL §19.16; no message changes shape, protocol stays 13). The installer
refuses a Rust bundle without RunicNPC, `doctor` fails without it, and the bundle CI composes no Rust bundle
without a RunicNPC that answers the bridge (tested against the real releases: it refuses today's v0.1.1 bridge,
which declares no RunicNPC API, and leaves ServUO alone). **The installer had no `edge` any more**, since its
cutover deleted it; it is recreated from `main` for this, so `main`, which releases on every push, gets it at 9e.
The egg follows the bundle and is unchanged.
- **Operator documentation:** [INSTALL.md](INSTALL.md) and [COMMANDS.md](COMMANDS.md). The required note went into
[`../rust-link/INSTALL.md`](../rust-link/INSTALL.md), the Rust operator guide that lists Kits:
`modules/rust/OPERATING.md`, which this section named, is a verbatim mirror of uMod's pages.
- **The update surface:** `runicnpc-rust`'s README lists every Rust type and member the swap and the brain depend
on, where, and whether a change is caught by compiling, by the field list, or only on a running server.
- **The performance check (D306, D315):** `rnt.cost` in the test harness measures RunicNPC's own NPCs, with stage
1's `rnh.cost` beside it in the same session as the reference. 100 NPCs, increase of the median frame:
| | Oxide: bare NPC | Oxide: RunicNPC | Carbon: bare NPC | Carbon: RunicNPC |
|---|---|---|---|---|
| Idle, awake | +0.96 ms | +2.65 / +2.92 ms | +0.97 ms | +1.52 ms |
| Idle, asleep | | | | +0.52 ms |
| Fighting 20 stand-ins | +7.53 ms | +7.19 ms | +7.96 ms | +9.04 ms |
The rigs are slower than in September (an empty Oxide frame 22–30 ms, against 16.4 ms then), and between two
empty windows the median moved by up to 7 ms, so every run ends with a second empty window and is judged against
the lower. The cost warning now says 3 ms per 100 awake, 0.5 ms asleep and 9 ms fighting.
**9c. The staging drill (D307–D309).**
- **The rig:** a new Pterodactyl server, `rust-staging`, Oxide only, on a 2000 map at about 6 GB. It keeps a