feat(events): one lease and the participation verbs (Phase 11b)
All checks were successful
PR Checks / client-build (pull_request) Successful in 20s
PR Checks / server-tests (pull_request) Successful in 26s
PR Checks / frozen-manifest (pull_request) Successful in 40s

The UO half of protocol 6 part b. No route added, no schema change, no
MODULE_API bump.

`uo.playercaps.skillcap` is the one lease, and the catalog is short because
ServUO made it short: of the 158 non-Bridge `Config.Get` call sites in
`Scripts/`, roughly eight are read live. This one is read inside
`CharacterCreation.cs`'s per-character path, so it is both live and observable --
which is what "proven" has to mean, since the failure an allowlist exists to
prevent is a key that applies cleanly and changes nothing.

Its `apply()` sends a DURATION rather than the deadline: an absolute time
computed here and honoured there is measured against two clocks, and a shard
running ten minutes fast would restore a ten-minute lease the instant it took it.
Its `restore()` turns `lease.drifted` into `{ drifted: true, current }` rather
than an error, because core records drift as a distinct successful outcome and an
error would put the row on the retry ladder. Its `inForce()` asks whether the
shard still HOLDS the lease, never whether the value still matches -- see the
core PR.

`uo.participation.open` / `.collect` count who took part and file them on the
success envelope. `open` is the one resource in this module that must NOT
reconcile by boot stamp: every other resource here lives in shard memory, so a
changed bootId IS the proof it is gone, while the participation ledger is written
into the world save precisely so it survives that restart. It asks instead.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-04 19:31:57 -05:00
parent bf9a702cfa
commit 88bfe9310e
8 changed files with 846 additions and 1 deletions

View File

@@ -246,6 +246,14 @@ const KIND_FEATURE = new Map(
// needs it live. An admin can turn it on.
'vendor.listing': 'market',
'vendor.listing.remove': 'market',
// Protocol 6 part b's `lease.applied` and `lease.expired` are deliberately NOT
// here, on the same reasoning that keeps `account.login.result` off it. They are
// operational frames about the WEBSITE changing this shard's configuration --
// which key, from what to what, on whose run, and whether the shard's own
// deadline had to put it back because nobody asked. Rule 2 fails an unmapped
// kind closed to admin-only, which is where an audit trail of the site's writes
// belongs; mapping them would mean choosing a feature an operator could then
// widen, and there is no rung below admin these frames belong on.
}),
)