docs(rust): the step-2 player walk, and D186-D187

PLAYER_WALK's step-2 rows 3-9 walked with the org lead in the game on
both rigs (2026-09-27). Records the results, corrects four rows (the
helper is unloaded, not deleted; no enter message can show; sleepers do
not score; ZoneManager's own entry counted the player anyway), and adds
D186 (a link code's second pass skips servers known down) and D187 (no
permission sync to a server the poll saw go away) with F6, F7 and F12's
as-walked notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-09-27 03:18:40 -05:00
parent 9aba725ca2
commit 1891f4f6fd
2 changed files with 34 additions and 8 deletions

View File

@@ -70,6 +70,8 @@ Taken by the org lead during and straight after the walk.
| **D183** | **F14's expiry is core's to record: the resource ledger gains an `expired` status, and a module reports one with `ctx.events.expired({ kind, ref })`.** `expired` is terminal like `reverted` — teardown never tries to take it back — and the run log says `resource.expired`. It is a MODULE_API minor (1.10.0 → 1.11.0), and it must not disturb Module-uo, which is already built against 1.10.0: additions only, no existing status changes meaning. Rejected: asking core to reconcile, which files an expected expiry as `orphaned` (a fault, and still claimable for a revert); and core marking rows expired from `lease_until` on its own clock. |
| **D184** | **F8's signal is `plugin.loaded` / `plugin.unloaded`, carrying the permissions that plugin added or removed.** The plugin diffs the registered permission list around each load and unload, emits only once the world is ready (a boot is the restart sync's), and the site marks the permission sync dirty when the list is not empty. The same list is §4.1's first evidence of which plugin owns a permission. Rejected: every load, names only. |
| **D185** | **F2 is the site's: NPC attackers are labelled by the killfeed**, which trims a prefab's variant digits (`wolf2` → wolf) and names the NPC families that read badly otherwise (scientists, bandits, animals). No wire change. Rejected: the plugin sending a display name Rust may not have. |
| **D186** | **F6, as walked: a link code's second pass skips the servers the site already knows are down.** Asking the non-issuers in parallel was not enough: while any server was down, a code no issuer held — every made-up one — still waited out that server's whole timeout (12 s on both rigs, the step-2 walk). A server the board poll last saw without a connected game is not an issuer, so it cannot hold the code: it counts as offline without the wait. Issuers are asked whatever their state, so a good code on a down server still answers "unsure". Rejected: dropping the second pass (a code typed before its mint is ingested would be refused once); a short timeout on it (still a wait, and a guess at the number). |
| **D187** | **F7, as walked: no permission sync goes to a server the poll saw go away until a fresh hello says its world is ready.** The `worldReady` hold reads the stored hello, which is the old boot's until the poll reads the new one — and on Carbon a due audit went out in that gap, 80 s before "Server startup complete". The poll already writes `online: 0` the moment a server goes away, so the hold reads that too (titles already did). A human's "sync now" is still not held. |
## 2. Fixes
@@ -118,6 +120,11 @@ to, that is D168's case (a helper), or the tally measures distance itself for zo
Carbon too. Settled by D181 and D182: ZoneManager has no public way (its `UpdatePlayerZones` is private and
runs only for a connecting player), so a helper patches `Zone.InitializeZone` with Harmony; without the helper the
bridge scores its own zones by `IsPositionInZone`.
*As walked, 2026-09-27, both rigs:* narrower than it reads. Without the helper, ZoneManager 3.1.14 counted the
player every time we tried — a zone opened around them, a zone re-created by a ZoneManager reload, and a rejoin
after a restart (its `UpdatePlayerZones` runs on connect) — only late: with the helper in, its sweep one tick after
`InitializeZone` found the player not yet counted. So the helper makes entry immediate, and its flags apply at
once; the score never depended on it. What the first walk saw may need a busier server than one player to recur.
**F13 — the `world.expired` frame leaves with its kind overwritten.** *(Rust-Plugins, protocol)*
Three zones expired in the game exactly on time; all three frames were filed as `kind: "zone"`. Line ~7310
@@ -149,6 +156,8 @@ issued a code in the last five minutes, and answer "unsure" only when one of *th
**F6 — redeeming a code waits on every dead server in turn.** *(Module-Rust)* About 21 seconds, four per dead
server; the rig sorts last, so a successful link waited too. F5's fix usually leaves one server to ask; failing
that, ask in parallel with a short timeout.
*As walked, 2026-09-27:* the parallel fleet still took 12 s for a made-up code whenever a server was down —
one whole timeout on the second pass. Settled by D186; 338 ms after it, 360 ms with a rig stopped as well.
**F8 — loading a missing plugin does not re-sync permissions.** *(Rust-Plugins, Module-Rust)* PopupNotifications
came back at about 18:44; the grant that had been unresolved landed at 18:57, on the fifteen-minute audit. The
@@ -168,6 +177,8 @@ deliberately wiped, the site restored its group, membership and grant — R2's c
restart sync ran 35 s before "Server startup complete", timed out with no warning in the log (the titles push
at the same moment did log one), and the retry 2.5 minutes later recorded "0 applied", so nothing says what the
restart restored. *Fix:* hold the restart sync until the hello says `worldReady: true`; log a failed sync.
*As walked, 2026-09-27:* the restart sync waited on both rigs, but on Carbon a due *audit* went out the moment
the sidecar reconnected — the stored hello was still the old boot's. Settled by D187.
**F2 — NPC killers are named by prefab.** *(Rust-Plugins or Module-Rust)* "killed by `wolf2`". Send a display name,
or map prefab to label on the site — whichever the killfeed page already expects. The site's, by D185.
@@ -405,9 +416,15 @@ in Rust-Plugins, Rust-Link and Module-Rust, and the three cut over to `main` tog
a 3-minute zone expired into `expired` with `resource.expired` and teardown never touched it (F13, F14)
— which found a run left `pending` for ever when its last resource expires while it runs, fixed in
website#209; a restart's sync waited for `worldReady` and went after it (F7); and `ZZZZZZ` with five
servers down answered "unknown or has expired", once, in one timeout (F5, F6). Still to walk: the rows
of [`PLAYER_WALK.md`](../../rust-link/PLAYER_WALK.md)'s step-2 section that need somebody in the game
(3–9).
servers down answered "unknown or has expired", once, in one timeout (F5, F6). The rows of
[`PLAYER_WALK.md`](../../rust-link/PLAYER_WALK.md)'s step-2 section that need somebody in the game (3–9)
were walked with the org lead in the game on 2026-09-27, on Oxide and then Carbon, and all passed but row 8's timing: the gather
tally matched the inventory to the unit, a player's own wall was not a raid, a zone scored a player who stood
still through its opening, a restart and a ZoneManager reload, with the helper and without it, and the killfeed
read Bear, Wolf, Boar and Scientist. The walk found two gaps, both fixed in Module-Rust on `edge` and walked on
the walk core: a made-up code still waited one timeout on a dead server (D186), and a due audit went to a
restarting Carbon before its hello was read (D187). F12 turned out narrower than written (see F12). Not walked:
a player killed by another player — there was no second player.
3. **The redesigns**, each planned in detail before code and walked on both frameworks: the permission manager
(§4.1), the event step editor with the kit-weekend template (§4.2, §4.3), zones and domes (§4.4), the map's
marker types (§4.5), the chat title conditions (§4.6), and the NPC research (§4.7).

View File

@@ -420,15 +420,24 @@ walked there without a player. The rest need somebody in the game.
| # | Do this | You should see |
|---|---|---|
| 1 | *No player.* `rgz.status` in the server console | `Runic Gateway Zones 0.1.0: patched`, and the servers page says nothing about the helper. Delete `RunicGatewayZones.cs` and wait a minute: the servers page warns that ZoneManager's flags miss a player already inside a new zone (D182). Put it back |
| 1 | *No player.* `rgz.status` in the server console | `Runic Gateway Zones 0.1.0: patched`, and the servers page says nothing about the helper. Unload it (`oxide.unload RunicGatewayZones`; Carbon: `c.unload RunicGatewayZones`) and wait a minute: the servers page warns that ZoneManager's flags miss a player already inside a new zone (D182). Deleting or renaming the file does **not** unload it on either framework. Load it again (`oxide.load`, or `c.load` — Carbon only queues the compile, so allow a minute) |
| 2 | *No player.* `oxide.unload Kits` (Carbon: `c.unload Kits`), grant a site group `kits.admin`, then `oxide.load Kits` | The sidecar's `/events?kind=plugin.loaded` shows Kits with `["kits.admin","kits.rgreward"]`, and the grant lands **within a minute** — not on the fifteen-minute audit (F8) |
| 3 | A fells a tree and picks up a hemp plant | The next `player.tally` counts the wood the inventory shows — the final hit's bonus included — and the cloth from the hemp (F1, D159) |
| 4 | A breaks a wall of their own base | `entity.destroyed` arrives; the next tally's `structures` does **not** move (F3) |
| 5 | Staff open a zone with a timed event while A stands where it will be | ZoneManager counts A at once: the zone's enter message shows, and the run's tally gives A seconds without A walking out and back in (F12) |
| 6 | With A standing in a live event zone, restart the server | After the restart A is in the zone again (ZoneManager says so) and keeps scoring without moving (F12). The site's restart permission sync goes **after** "Server startup complete", not before, and says what it applied (F7) |
| 7 | Staff delete the helper, then repeat step 5 | A still scores (the bridge measures the zone's shape, D182), but the zone's enter message does not show for A |
| 8 | Stop another enabled server, then have A type a made-up code on the website | "That code is unknown or has expired" — not "one of the servers could not be reached … your code is still good" (F5) — in a second or two, not many (F6). A real code from A's server still links |
| 5 | Staff open a zone with a timed event while A stands where it will be | ZoneManager counts A at once — `rgp.inzone` names A, and the helper may log `1 player(s) already inside were counted in` (on Carbon ZoneManager's own entry got there first) — and the run's tally gives A seconds without A walking out and back in (F12). No enter message shows: the bridge makes its zones without one |
| 6 | With A standing in a live event zone, restart the server. A sleeper can be killed while A is away, so stand in a small locked hut, and wake up at once on rejoining — asleep does not score | After the restart A is in the zone again (ZoneManager says so) and keeps scoring without moving (F12). The site's restart permission sync goes **after** "Server startup complete", not before, and says what it applied (F7) |
| 7 | Staff unload the helper (row 1), then repeat step 5, and reload ZoneManager with A still inside | A still scores, through the zone's re-creation too (the bridge measures the zone's shape, D182). On ZoneManager 3.1.14 its own entry counted A anyway, a moment late — the helper only makes that immediate |
| 8 | Stop another enabled server, then have A type a made-up code on the website | "That code is unknown or has expired" — not "one of the servers could not be reached … your code is still good" (F5) — in a second or two, not many (F6): a server the site already knows is down is not waited on (D186). A real code from A's server still links |
| 9 | A is killed by a wolf, then by a scientist | The killfeed says **Wolf** and **Scientist**, not `wolf2` or `scientistnpc full any` (F2) |
**What counts as a pass:** a zone counts somebody who was already standing in it, on both frameworks,
and an expired zone reads `expired` on the run console.
**Walked 2026-09-27, rows 3–9, on Oxide and then Carbon, with the org lead in the game.** Every row passed but row 8's timing.
The tallies matched the inventory exactly (653 and 654 wood, 10 cloth, a hemp seed); an own wall brought down
with C4 was an `entity.destroyed` and no raid; a zone scored a player who stood still through its opening, a
restart (128 s and 246 s, against the time actually spent inside) and a ZoneManager reload with the helper
unloaded (105 s and 90 s); a real code linked in under two seconds with the other rig stopped; and the killfeed
read Bear, Wolf, Boar and Scientist. Two findings were fixed the same day and walked on the walk core: a
made-up code still waited one timeout on a stopped rig, 12 s (D186 — now 360 ms), and on Carbon a due audit
went out before the restarted world's hello was read (D187). Not walked: a player killed by another player.