The module's half of PLAN_FIXES §6 step 2 (decisions D181-D185, docs#288).
- F13/F14 (D170, D183): `world.expired`, recognisable from protocol 13 by its
`what`, is handed to core as the resource the zone step ledgered
(`world`, `<serverId>:<id>`) through ctx.events.expired, which records it
`expired`. coreApi moves to ^1.11.0 (website#209).
- F8 (D184): `plugin.loaded` / `plugin.unloaded` mark the permission sync dirty
when the plugin added or removed permissions, so an unresolved grant lands on
the next tick instead of the fifteen-minute audit.
- Catalogue: plugin.loaded/unloaded, world.expired and lease.expired are staff
kinds. The last two were never classified (default deny kept them off public
pages); the test now covers every event kind through protocol 13.
- F7: permission and title pushes hold while the stored hello says
`worldReady: false` (a human's "sync now" does not); a failed or refused
permission sync now logs at warn.
- F2 (D185): the killfeed names an NPC attacker — a family (Scientist, Bandit
guard, Bradley APC…) or the prefab without its variant digits (wolf2 → Wolf).
- F5/F6: a link code is asked of the servers that minted one in the last six
minutes first, then of the rest, each group in parallel; "unsure" only when
one of the minting servers is unreachable.
- D182: the admin server list carries the ZoneManager helper's state from the
hello, and the servers page says what a missing or failed helper costs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Two defects the phase 13a walk found by restarting the rig mid-run:
- The watch asked core to reconcile the moment a new boot id appeared, which
is before the game has loaded its save — every crate looked gone and was
orphaned. It now waits for the plugin's hello to say `worldReady`; an older
plugin that never says is taken as ready.
- revert() read any 200 as success. On this bridge a refusal is a 200
carrying world.error (`not-ready` while loading), so every row would have
been marked reverted with the game still holding every crate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
Core learns which caps an action accepts by pricing its declared examples
once, and drops a dimension priced at zero. A single rust.prefab.place whose
cost moved between rust.prefabs and rust.npcs by its prefab param could only
ever show the crates cap, so D89's separate dial for fights was unreachable.
Two verbs, each pricing exactly one dimension, with the prefab source split
to match (rust.options.crates / rust.options.npcs). The switchboard can now
allow crates and leave NPCs off. The plugin's world.place is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
- registerEventActions: rust.zone.open and rust.prefab.place, both
reversible 'ledger' with revert() and reconcile(), budgetMs 15000 above the
client's 12 s. A location is a monument (kind + instance, carrying its
server) or raw coordinates, exactly one (D87, D93); bounds mirrored from the
plugin so a bad step is refused on the form (D95); zone minutes required and
held by the game (D96).
- registerEventBudgets: rust.prefabs, rust.npcs and rust.zone.minutes, each
beside the verb that spends it (D79, D89).
- Option sources rust.options.monuments (live, searchable) and
rust.options.prefabs (mirrored, answers with every server off), registered in
the one batch core accepts alongside the lease sources.
- Refs are <serverId>:<id>, since revert and reconcile get no params. The undo
sends no idempotency key; a lost answer is reverted by key on every server.
reconcile asks the plugin, and a server that cannot be asked keeps its rows.
- The refresh's bootId/wipeId watch calls ctx.events.reconcile() on a restart
or a wipe, never on a first sighting or a reconnect (§11.1).
- The permission mirror keeps the plugin's new notLanded grants out of what it
records as pushed, and the admin page says so (D85).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY