docs(events): the acceptance walk, and the three contracts it moved (Phase 16a)
Phase 16 is split into 16a (the walk), 16b (the cutover) and 16c (runicgateway.com + .profile), because the phase as written asked for a walk "against released artefacts" BEFORE the cutover and all three component repos release on push to `main`. The walk therefore runs against artefacts built from `edge` the way a release builds them, and 16b re-verifies against the real bundle. `EVENTS_PLAN.md` gains the 16a record: the rig, all three deliberate failures passing, the six defects, the one finding withdrawn, and what each fix was verified against. Three contracts move, each because the walk proved the built thing did not match the written one: **`link/v6.md` — a refusal does not spend its key.** Rule 2 had two cases, throw and return, and needed a third: a handler that ran to completion and deliberately refused did nothing, so freezing that refusal as the key's answer made a refusal that WAITING FIXES impossible to retry past. The section now carries the case `uo.world.save` found it with, and the rule the release rests on — do not answer `*.error` after changing the world. `[bridge status` gains `refused=`. **`website/MODULE_API.md` — `revert`'s `idempotencyKey` identifies a dispatch; it is not a key to send on the undo.** The paragraph explained what the key is FOR and never said what it is not, and `module-uo` read it the other way: every despawn went out under the key its spawn had used, so a store that keys on the key alone answered the undo with the DO's reply and teardown became a no-op that reported success. **`website/EVENTS.md` §I — the public calendar matches a run that OVERLAPS the window.** The row promised "upcoming, live and recent" and the built route served only the first, because it read the start instant and a live run has already started. The default window now reaches back so "recent" has somewhere to live, and projections are forecast from now rather than into that tail. Pairs with `website#`, `Module-uo#` and `servuo-plugins#`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
@@ -1820,6 +1820,65 @@ website, emulator — running a real multi-phase event, including three delibera
|
||||
Then `edge` → `main`, in the order every previous cutover used: the protocol side first, the module,
|
||||
core, docs, then the kit's re-pin and `runicgateway.com`.
|
||||
|
||||
> **Split into 16a (the walk) and 16b (the cutover)** (org lead, 2026-09-09), on the same argument
|
||||
> 12a/12b and 14a/14b were split on. The two sentences above cannot both hold: `link`,
|
||||
> `servuo-plugins` and `Module-uo` all release on push to **`main`**, so no released artefact
|
||||
> carrying events can exist until after the cutover. Engagement Phase 13 met the same wall and
|
||||
> resolved it the other way, cutting over first and walking from `main`. Here the walk goes first
|
||||
> against artefacts built from `edge` exactly the way a release builds them, because every walk in
|
||||
> this workstream has found defects and a defect found on `edge` is a reviewed PR rather than a
|
||||
> hotfix to `main`. **16b re-verifies against the real released bundle** — install, boot, run one
|
||||
> event — so the delivery path is still proved, just second. A third leg, **16c**, carries
|
||||
> `runicgateway.com` and `.profile`.
|
||||
>
|
||||
> **16a WALKED, and it is four repos** — `Module-uo`, `website`, `servuo-plugins`, `docs`. The whole
|
||||
> rig: real ServUO 57.4 (208k items, 42k mobiles) → a `cargo --release` sidecar on protocol 7 → core
|
||||
> with the module installed from a release-shaped bundle → the Android app on an emulator. The
|
||||
> overlay was deployed from a tarball built the way CI builds one, into a tree with `Scripts/Custom/
|
||||
> Bridge` and `Saves/Bridge` deleted first, so it was a first install rather than an upgrade.
|
||||
>
|
||||
> **All three deliberate failures pass.** (1) A mid-run process kill landed mid-TEARDOWN — sharper
|
||||
> than mid-step, since a phase executes in about a second — with the run `completed`, cleanup
|
||||
> `pending`, a lease half-returned and 21 world objects up: teardown resumed on restart and all 15
|
||||
> steps still read `attempts = 1`, so nothing re-executed. (2) The sidecar killed during a phase gate
|
||||
> left the run `degraded` rather than failed, `core.lease` retrying with a reason, and the four world
|
||||
> writes behind it **parked at `attempts = 0`**; the shard reconnected on its own. (3) A cap of 5
|
||||
> against a step asking for 12 answered `refused` — its own status — with `code: "cap"` and *"asks
|
||||
> for 12 of `uo.creatures`; 0 of 5 is already spent this run"*, and the dry run had already refused
|
||||
> it in the author's own words.
|
||||
>
|
||||
> **Six defects, all in code already merged to `edge`, and the suites were green on either side of
|
||||
> every one.** Two were blocking or worse. **The spawn atlas could not import on a stock ServUO
|
||||
> tree** — a case-sensitive JS dedupe against an `..._ai_ci` PRIMARY KEY, four colliding decoration
|
||||
> spellings in ServUO's own files, and the whole transaction lost; with no atlas every option source
|
||||
> answers empty and no world verb can be authored at all. **Teardown of all five world verbs was a
|
||||
> no-op that reported success** — `revertOwned` sent the despawn under the step's key, which is the
|
||||
> key the SPAWN used, so the shard replayed the spawn's reply and `OnDespawn` never ran; the ledger
|
||||
> read `reverted` while the shard held all 21 objects, and the same despawn under a fresh key removed
|
||||
> every one. Then: **the public calendar served neither live nor recent runs** though §I promises all
|
||||
> three, so the site said `live` on one page and showed nothing on the other; **a resource left
|
||||
> `reverting` by a crash was never reclaimed**, and the manual cleanup route answered 200 while doing
|
||||
> nothing, which stranded a lease and blocked the NEXT run of the same event; **a transient refusal
|
||||
> under an idempotency key was permanent**, because the shard's store had no case for a handler that
|
||||
> ran and deliberately did nothing; and **three facts every announcement computes were declared by no
|
||||
> trigger** and silently dropped.
|
||||
>
|
||||
> One reported defect was **withdrawn**: `skip` refusing a `failed` step is not a dead end, because
|
||||
> `resume` carries a run past any settled step — the route's own docs say so and the rig confirmed
|
||||
> it. The runner claims only `pending` steps, so `failed` and `refused` are both settled.
|
||||
>
|
||||
> Every fix is verified against the rig, not only against tests: the atlas imports 309 decor types
|
||||
> and 6,455 points; a full four-phase run's teardown leaves the shard owning **0**; a lease stranded
|
||||
> by a real crash is reclaimed in one sweep and `cleanup_status` reaches `complete`; the same save
|
||||
> key 25 seconds apart answers "15 seconds ago" then "40 seconds ago"; and `/site/events` shows a
|
||||
> live run as **Happening now** beside recent ones, in the browser and in the app. Each new test was
|
||||
> confirmed to FAIL without its fix.
|
||||
>
|
||||
> **`Module-uo`'s `revert` no longer forwards core's key at all** — `MODULE_API.md` now says why that
|
||||
> key identifies a lost dispatch rather than addressing the undo. **Protocol 7 is amended in place**:
|
||||
> a refusal releases its key, with the rule that pays for it written down — *do not answer `*.error`
|
||||
> after changing the world*.
|
||||
|
||||
**Two documents that are cutover-window work by construction.**
|
||||
- **`runicgateway.com`** — `checkFacts` reads `main`, so any claim about events is unverifiable until
|
||||
the cutover lands. Same 12a/12b split the engagement workstream needed.
|
||||
|
||||
Reference in New Issue
Block a user