docs(rust): protocol 13 step 2 — expiry, plugin loads, the zone helper, the tally (§19.4-19.8, MODULE_API 1.11.0)

The spec for PLAN_FIXES §6 step 2, as built (D181-D185):

- PROTOCOL.md §19.4 world.expired's `what` and the website recording an
  expiry (amends §15's "maps it to nothing"); §19.5 plugin.loaded /
  plugin.unloaded with the permission diff; §19.6 the ZoneManager helper and
  `zoneHelper` at hello; §19.7 what the tally counts (F1, F3, F4); §19.8 the
  website (F7 hold, F5/F6 link fleet, F2 names).
- MODULE_API.md 1.11.0 and ctx.events.expired; EVENTS.md §L the `expired`
  status, terminal and green, and `resource.expired`.
- rust-link/INSTALL.md: the helper in the tarball, by hand, and in doctor.
- PLAYER_WALK.md: events step 6 can pass now; a step-2 section whose rows 1-2
  were walked on both rigs without a player and 3-9 need one.
- PLAN_FIXES §6: step 2 as built, with its PRs.

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-26 21:47:42 -05:00
parent e7551cbf8f
commit 1a7f52743f
6 changed files with 185 additions and 11 deletions

View File

@@ -26,13 +26,23 @@ here extends the contract first, in this file, before the module is written agai
Core exports a single integer-major semver string from `server/src/modules/version.js`:
```js
const MODULE_API_VERSION = '1.10.0'
const MODULE_API_VERSION = '1.11.0'
```
The client half carries the same number (`client/src/modules/version.js`) and a test asserts the two
agree. Duplicated rather than fetched because the value has to be on `window.__rg` before the first
module chunk evaluates, which is earlier than any network round trip could answer.
**1.11.0 — `ctx.events.expired({ kind, ref })`** (`website/EVENTS.md` §L; Rust
`modules/rust/PLAN_FIXES.md` F14, D183). One addition and no removal, so minor. A game that ends
something at its own deadline — a Rust zone the plugin erases when its time is up — tells core, and core
marks the calling module's live row for that target **`expired`**: terminal like `reverted`, never taken
back at teardown, and not `orphaned`, which `reconcile` uses for a thing that vanished with nobody
asking. The owner is bound, as `reconcile`'s is; it is fire-and-forget and returns `undefined`; a
`{ kind, ref }` no run ledgered is not an error. **Module-uo is unaffected**: it declares `^1.10.0`,
calls none of this and reads no ledger status, and its frozen-manifest job, server and client suites
passed against the 1.11.0 core before the bump merged (website#209).
**1.10.0 — the event contract opens to modules: `api.registerEventActions(...)`,
`api.registerEventBudgets(...)`, `api.registerEventLeases(...)` and
`api.registerEventOptionSources(...)`** (`website/EVENTS.md` §F, `EVENTS_PLAN.md` Phases 7 and 8).
@@ -100,6 +110,11 @@ api.registerEventActions([{
// claim about a world that no longer exists.
ctx.events.reconcile()
// 1.11.0. The game ended one of this module's resources at its OWN deadline —
// the same `{ kind, ref }` the action reported when it made it. Core files it
// `expired`: terminal, and not the `orphaned` a reconcile would have said.
ctx.events.expired({ kind: 'world', ref: 'srv-a:rg-13-35875416-1' })
api.registerEventOptionSources([{
id: 'uo.options.creatures', label: 'Creatures',
async resolve() { return [{ value: 'Orc', label: 'Orc', group: 'Humanoid' }] },
@@ -352,6 +367,11 @@ branches lacks — so it is the only place `permits` is true between two values
between `admin` and `owner`, `members` or `subscribers`. `permits`, `meet` and `meetAll` are otherwise
unchanged, and so is every rule about composition narrowing rather than widening.
**1.11.0 — `ctx.events.expired`** (`website/EVENTS.md` §L, Rust PLAN_FIXES D183). One addition, so
minor; see §1.1. The resource ledger gains an `expired` status, and nothing that existed changes
meaning — `expired` joins neither the statuses that hold a target nor the ones that leave a run's
cleanup unfinished. Module-uo's `^1.10.0` still resolves and was proved against it.
**1.10.0 — the event contract** (`website/EVENTS.md` §F). Four additions, no removals and no changed
signature, so minor; `module-uo`'s `coreApi: "^1.9.0"` still resolves and it registers no actions
until `EVENTS_PLAN.md` Phase 9. `api.registerEventActions([...])`, `api.registerEventBudgets([...])`,
@@ -636,6 +656,7 @@ module-uo does not need is on the list.
| `ctx.teams.reconcile` | `({ reason }) => void`, returns at once | `model/teams/teamSync` | after a fresh account link (1.6.0) |
| `ctx.teams.activity.push` | `(items) => Promise<void>`, fire-and-forget | `model/teams/teamActivity` | the Team provider's module (1.6.0) |
| `ctx.events.emit` | `(triggerId, envelope) => void`, fire-and-forget | `utils/engagementEmit` | `module-uo`'s `utils/shardEngagement.js`, off the shard feed (1.7.0) |
| `ctx.events.expired` | `({ kind, ref }) => void`, fire-and-forget, owner bound | `events/cleanup` `expireResource` | `module-rust`'s ingest of `world.expired` (1.11.0) |
| `ctx.inbox.push` | `(userId, item) => void`, fire-and-forget | the in-app channel (live since Phase 7) | `module-uo` reaches both through `server/core.js` (1.7.0) |
**`ctx.events.emit(triggerId, envelope)`** fires an event the module DECLARED with