docs(link): protocol 6 part b -- leases, participation, and what the walk found

Six files. `v6.md` gains sections 7-10: one version with two halves, the lease
plane, the participation ledger, and 11b's verification.

Three corrections to what the plan and the design of record assumed.

Phase 11b is FIVE repos, not four, and in the opposite direction from 11a's
correction: a lease's ledger row had no reconcile path anywhere, because the step
that made it names `core.lease` and that is core's own action. `website` joins.

EVENTS.md's §D frames the 258 `Config.Get` call sites as splitting into two
patterns. Measured on 57.4: of the 158 non-Bridge sites in `Scripts/`, roughly
eight are read live. The allowlist is not a curated subset of a large pool, it is
nearly the whole of what exists. And `Config.Set` has exactly one caller in the
entire tree, so on a stock shard a GM cannot drift a configuration lease even
deliberately -- which is why proving `drifted` needed a scaffolding verb.

§G's "participation attribution is now the largest piece of new UO work" closes,
and the live-config-lease row goes to built-with-one-key.

§10.1 records the defect the phase's own deferral found in 11a's shipped code:
`bridge.busy` answered 200 instead of 425 because the frame carried two `kind`
fields and parsers take the last. Unreachable in 11a by construction; produced on
the first collision here.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-04 19:32:11 -05:00
parent 1521c5af7e
commit eabaf2635f
6 changed files with 546 additions and 23 deletions

View File

@@ -1358,6 +1358,66 @@ deliberate mid-lease GM edit producing `drifted` rather than a silent overwrite;
a shard restart mid-run; and the first live `bridge.busy`, which a deferring handler finally makes
reachable.
> **Built.** All four verifications passed on a real ServUO with the release sidecar. Protocol 6
> amended in place; `MODULE_API_VERSION` amended in place at 1.10.0. See
> [`../link/v6.md`](../link/v6.md) §§710.
>
> **It is FIVE repos, not four, and the plan was wrong about this in the opposite direction from
> 11a.** A lease's ledger row had no reconcile path anywhere, and nothing failed to say so:
> `cleanup.js` resolves a resource to the action of the step that made it, and for a lease that
> action is `core.lease` — a CORE action, on a path a module cannot register anything on. So every
> `override` row came back `unanswered` for the life of the run, and a lease the shard had quietly
> dropped stayed in the ledger as live until teardown went hunting a baseline nobody was holding.
> `website` joins the phase: `core.lease` gains a `reconcile()` and `registerEventLeases` gains an
> optional **`inForce()`**. Deliberately not `read()` plus a comparison — a changed value is DRIFT,
> which teardown must report so the row lands `drifted`, and inferring absence from it would orphan
> the row first and tell the operator the lease vanished rather than that somebody moved it.
>
> **Ten decisions (org lead, 2026-09-04), all as recommended.** The five-repo correction and
> `inForce()`; `PlayerCaps.SkillCap` as the one proven key; a scaffolding write verb to make
> `drifted` reachable at all; leases memory-only, so a restart is a free restore; a separate
> `Bridge.EventsEnabled` gate rather than `AdminWriteEnabled`; map + point + radius for the area;
> presence-plus-weighted-kills for the score; the shard-side bounds and grace window; chunking
> `participation.snapshot` as the thing that defers; and no `MODULE_API` bump.
>
> **The catalog is far shorter than §D expected, and the measurement is the finding.** §D frames the
> 258 `Config.Get` call sites as splitting into two patterns. Measured: of the **158** non-Bridge
> sites in `Scripts/`, roughly **eight** are read live. The allowlist is not a curated subset of a
> large pool — it is nearly the whole of what exists. And **`Config.Set` has exactly one caller in
> the entire tree** (`Server/ScriptCompiler.cs`), so no in-game command, gump or console verb writes
> a config key: on a stock shard a GM cannot drift a *configuration* lease even deliberately, which
> is why proving `drifted` needed a `configset` verb in the rig driver.
>
> **The walk found a defect in 11a's shipped code, which is the argument for the ordering.**
> `bridge.busy` came back **200**, not 425, the first time anything produced it:
> `BridgeIdempotency.Busy` built its frame with `Begin("bridge.busy")` and then appended a diagnostic
> `.Str("kind", prior.Kind)`, so the object carried **two `kind` fields** and every JSON parser takes
> the last. The sidecar read `participation.snapshot`, matched nothing, and answered a 200 whose body
> said nothing had happened — the worst of the three possible answers, because a retry loop reads it
> as success. Unreachable in 11a by construction, and the first deferring handler produced it on its
> first collision. Renamed `busyKind`.
>
> **One resource in `module-uo` must NOT reconcile by boot stamp, and it is this one.** Every other
> resource wave 1 ships is stamped with the shard boot that created it, because a crier line and a
> news article live in shard memory and a restart is definitionally the loss of both. The
> participation ledger is written into the world save *specifically* so it survives a restart, so
> the stamp would orphan the one resource the phase went to the trouble of persisting. It asks
> instead, and only a 404 takes a row out.
>
> **What the rig could not drive: presence.** The sweep credits online players (`NetState != null`),
> which is the correct test and not one a probe should loosen — a character parked in Britain and
> logged out for eight hours did not attend anything. There is no way to produce a NetState short of
> writing a client. Kill credit needs none, so the credit path, the accrual, the persistence, the
> chunking and the replay were all driven; the one unexercised line is the presence accrual itself,
> and it is named rather than assumed.
>
> **Two rig traps, both of which faked a defect.** `Core.Kill` does **not** save the world, so the
> first restart test reloaded an empty `Participation.bin` and looked exactly like a persistence bug
> — `save` then `shutdown` is the sequence. And a probe that means to produce two damagers must not
> kill with the first blow: 40 damage on a Mongbat killed it where it stood, the second damager never
> landed a hit, and the ledger correctly credited one player while reading as a plugin that credits
> only the killer.
---
### Phase 12 — UO wave 2: the world verbs (`servuo-plugins` + `link` + `module-uo` + `docs`)