docs(link): protocol 7 -- what an event owns, and the split that carries it
`link/v7.md` is the spec of record: one command family for five verbs, the persisted ownership registry and why it is forced rather than chosen, the oracle that reuses ServUO's own dialogue vocabulary without its command-scripting field, and the decoration index. `EVENTS_PLAN.md` splits Phase 12 into 12a and 12b (org lead, 2026-09-07), on the line section G already draws between what an event OWNS and what it BORROWS. Ten verbs, four repos and a protocol bump is one review and one walk too many, and the halves prove different things. One protocol version across both, the 11a/11b shape. Three corrections the survey forced on `EVENTS.md`: The config lease catalog does NOT grow in 12b, and the plan's promise of "the rest of the allowlist" was written before anyone counted. Measured on ServUO 57.4: 156 non-Bridge `Config.Get` call sites; 82 sit outside a field declaration, but all but four of those are inside a `Configure()` or a static constructor and are cached at boot exactly as the field initialisers are. The live, event-useful reads are `PlayerCaps.SkillCap` (11b shipped it) and vendor bribe decay. So 12b's lease work is object-property leases. Section G calls the seasonal toggle "a nine-value enum". `EventStatus` has THREE values; it is `EventType` that has nine entries. The verb is a three-state toggle over nine named events, which is a different form to author and to cap. Section G costed the reopening at one protocol bump. It is two: the idempotency guarantee had to land before the verbs that depend on it, which is v6's own argument. `README.md` gains rows for v6 and v7. v6's was missing -- the index has been one protocol behind since 11a. Refs: EVENTS_PLAN.md Phase 12a Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
@@ -1122,22 +1122,24 @@ a capability exists.
|
||||
| Name landmarks, regions, creatures for authoring | ✅ | The spawn atlas — and it answers the "meeting location" field every EM listing carries. |
|
||||
| Detect a boss defeated | ✅ **built (protocol 6)** | `champ.boss.killed`, fired from `EventSink.CreatureDeath` and detected by type, with the altar attributed from the sweep. The inference this replaces was more fragile than "slightly": `bossUp` also drops when a GM resets a spawn, when a boss despawns, and after a sidecar reconnect clears the diff cache. And it was silent about who fought — the new kind carries the damage table, which exists at the death and nowhere else. |
|
||||
| **Participation attribution** | ✅ built | Protocol 6 part b. Presence in a declared area plus kill credit inside it, keyed by character serial, **persisted in the world save** so a restart mid-event does not lose it. The area is a map, a point and a radius rather than a region name — the most specific region containing an event is routinely anonymous. Kill credit goes to every damager standing in the area, not to the killer: a last hit is a poor description of who fought something. |
|
||||
| Oracle NPC with scripted dialogue | 🔧 📡 | PEC caps this at 5 NPCs × 5 lines. **This is literally a web form** — arguably a better fit for browser authoring than spawning is, and it is how most story events actually work. |
|
||||
| Temporary gate to a venue | 🔧 📡 | PEC caps at 4 hours and forbids cross-facet gating to restricted areas. Inherently temporary, so it maps onto a run's lifetime and the ledger with no friction. |
|
||||
| Temporary decoration lockdown | 🔧 📡 | Permanent decoration prohibited in the program and should be prohibited here. Ledgered and reverted like anything else. |
|
||||
| Named, hued creatures from an allowlist | 🔧 📡 | PEC's core capability, and its cap is the useful part: common creatures, custom name and hue, **capped at 30**. A bounded one-shot spawn with each serial ledgered — **not a spawner**, which PEC withholds precisely because it is unbounded over time. |
|
||||
| "Simple" boss variants | 🔧 📡 | An enhanced regular mob, capped at 2–4. The defensible form is an **event-owned creature template** — the event declares what it spawns, stats included, and never touches a creature it did not create. |
|
||||
| Oracle NPC with scripted dialogue | ✅ **built (protocol 7)** | PEC caps this at 5 NPCs × 5 lines. **This is literally a web form** — arguably a better fit for browser authoring than spawning is, and it is how most story events actually work. Phase 12a: a greeting on approach plus keyword rows, on `Mobile.OnMovement` and `Mobile.OnSpeech`. Built rather than layered on `XmlSpawner2.XmlDialog`, which implements exactly this vocabulary **and an `Action` command-scripting field** — the `[set` this table excludes, one field away from an author. |
|
||||
| Temporary gate to a venue | ✅ **built (protocol 7)** | PEC caps at 4 hours and forbids cross-facet gating to restricted areas. Inherently temporary, so it maps onto a run's lifetime and the ledger with no friction. Phase 12a; the deadline is the SHARD's, so a gate closes whether or not the website is heard from again — and it crosses as a duration, never an absolute time. |
|
||||
| Temporary decoration lockdown | ✅ **built (protocol 7)** | Permanent decoration prohibited in the program and should be prohibited here. Ledgered and reverted like anything else. Phase 12a places it from the shard's OWN `Data/Decoration/**/*.cfg` vocabulary, carrying the item id: `Static` alone accounts for 5031 placements under **1992 different graphics**, so a bare type name places the wrong thing. Containers are refused — teardown would delete what a player left inside. |
|
||||
| Named, hued creatures from an allowlist | ✅ **built (protocol 7)** | PEC's core capability, and its cap is the useful part: common creatures, custom name and hue, **capped at 30**. A bounded one-shot spawn with each serial ledgered — **not a spawner**, which PEC withholds precisely because it is unbounded over time. Phase 12a; the ledger is a PERSISTED shard-side registry, because a spawned creature survives the restart that proves a crier line gone. |
|
||||
| "Simple" boss variants | ✅ **built (protocol 7)** | An enhanced regular mob, capped at 2–4. The defensible form is an **event-owned creature template** — the event declares what it spawns, stats included, and never touches a creature it did not create. Phase 12a: an allowlisted type plus hits/damage/stat multipliers, each bounded. |
|
||||
| **Lease a live config value** — rates, toggles, caps | ✅ built (one key) | Protocol 6 part b: the registry, the deadline timer, compare-and-set restore and `lease.list`, proved end to end against one verified live-read key. **The allowlist is far shorter than this table assumed** — of the 158 non-Bridge `Config.Get` call sites in `Scripts/`, roughly *eight* are read live, so the split below is nearer 95/5 than half and half. Phase 12 adds the rest with the boot-time self-check. |
|
||||
| Lease a property on an existing object | 🔧 📡 | Practical, and an earlier revision was wrong to rule it out. The before-image lives in the website's database and survives a shard restart; a save just persists current state; a deleted target makes restore a no-op. The one real hazard — a GM editing the same property mid-event — is answered by compare-and-set restore and the `drifted` state. |
|
||||
| Grant an event item | 🔧 📡 | An ordinary action, not a special contract member. Admin-gated and capped like any other, and `reversible: 'none'` *for UO specifically* — an object in a backpack cannot be recalled. The constructible allowlist is the plugin's; every label and icon comes from `shard_clilocs` and `item_id`. Failure aborts rather than retries: a retried grant is one winner receiving two. |
|
||||
| Toggle a ServUO seasonal event | 🔧 📡 | Small and safe: `SeasonalEventSystem.GetEntry(type).Status` over a nine-value enum, already persisted across saves. |
|
||||
| Toggle a ServUO seasonal event | 🔧 📡 | Small and safe: `SeasonalEventSystem.GetEntry(type).Status`, already persisted across saves. **Corrected in Phase 12a's survey:** `EventStatus` is a **three**-value enum (`Inactive`, `Active`, `Seasonal`); it is `EventType` that has nine entries. So the verb is a three-state toggle over nine named events — a different form to author and to cap than one nine-way choice. Phase 12b. |
|
||||
| Trigger a world save | 🔧 📡 | Catalogued Tier B in `ADMIN_CONTROLS.md` §3.6, never built. `AutoSave.Save()`; emits the `world.save.*` events already streamed. Useful as a phase boundary. |
|
||||
| Idempotent command application | ✅ **built (protocol 6)** | Phase 11a, and deliberately ahead of every verb below it rather than alongside one. A key is executed at most once; a repeat gets the original reply. Its immediate dividend is that `uo.broadcast` stopped being un-retryable — Phase 9 had to answer `retry: false` even to a 503 from a restarting shard, because a lost ack and a command that never applied were the same event. |
|
||||
| Loot-table changes | ⛔ | Per-creature-type and shard-wide, so it cannot be scoped to one run at all — the one thing on this list a lease genuinely cannot express. Attach loot to an event-owned creature template instead. |
|
||||
| Arbitrary `[set` / `[get` / `[add` | ⛔ | `ADMIN_CONTROLS.md` §8's exclusion of these should survive the reopening unchanged. Sharp, privilege-escalating, and expressible only as "trust the caller" — which is precisely a change with no baseline, no cap and no ledger entry. |
|
||||
|
||||
**What the reopening actually costs.** Nine new plugin verbs, one protocol bump carrying an
|
||||
idempotency key and a lease deadline, and a participation ledger. Bounded work, and every verb is
|
||||
**What the reopening actually costs.** Nine new plugin verbs and **two** protocol bumps: 6
|
||||
for the idempotency key, the lease deadline and the participation ledger, and 7 for the world
|
||||
verbs themselves. (One bump was the estimate; the guarantee had to land before the verbs that
|
||||
depend on it, which is [`../link/v6.md`](../link/v6.md) §1's whole argument.) Bounded work, and every verb is
|
||||
cap-bounded, ledgered and attributable by construction. **None of it is `[add`.** The distinction that
|
||||
makes it defensible: an event may **own** what it creates and **borrow** what it changes — and a
|
||||
borrowed value carries a deadline the game itself enforces. What it may never do is change something
|
||||
|
||||
Reference in New Issue
Block a user