docs(link): the cutover, and the counter two branches bumped at once (Phase 9b, 5 of 5) #245

Merged
whitlocktech merged 2 commits from docs/asset-bridge-p9b into main 2026-09-15 10:05:51 +00:00
Showing only changes of commit e53ee15f15 - Show all commits

View File

@@ -1702,7 +1702,7 @@ disagree, so a split bump means the next bundle silently fails to compose.
| 7 | **DONE 2026-09-14.** The atlas over the sidecar (§10); shared-filesystem requirement retired. The measurement came first again and changed the shape: `tree/<label>` → bytes **cannot work**`Spawns/trammel.xml` is 4.03 MB against a 1 MiB line cap — so a file crosses as **512 KiB chunks, each gzipped**, which is §5's depth scheme paying for itself a second time (§10.1). It is a `tree` **family** on `assets.fetch` rather than §14's separate commands, with `assets.manifest` generalised to match and its **own consent, `Bridge.TreeEnabled`** (§10.2) — so `link` needed nothing for the third phase running. **141 files / 11.9 MB / 158 chunks / 3 pages / 1.33 MB on the wire / 512 ms**, and the atlas built over the bridge is identical to the one built off the disk. Two defects, each found by a different harness: an empty `catalog` refusing every fetch, and `GZipStream` emitting **nothing** for the two empty files stock ServUO ships (§10.3). `PARSER_VERSION` bumped for one canonical read order — written as 4 → 5, renumbered to **6** at the cutover (§10.4, §17.15); protocol stays 8; `EXTRACTOR_VERSION` stays 3 | servuo-plugins, module-uo |
| 8 | **DONE 2026-09-14.** The admin surface (§12.2): `Admin → Client Files` — one page over all three planes, because they come off one client and change on one event. The cliloc pair had had no UI since phase 2, which on a bridge install meant `curl` was the only way to import 67,496 names. §14's "activity view" is the **last import's own summary** rather than a filtered feed, which kept the phase to one repo (org lead, 2026-09-14). The walk imported **1,095 portraits in 3.5 s, warmed 313 item pictures in 0.6 s and reloaded 67,496 cliloc rows in 1.7 s** against a real shard — and found **two deletions nobody could see before a screen put the numbers together**: the body import diffing its manifest against *every* family's rows, which staged all 313 item pictures for deletion, and an approved vanish that unlinked the sprite and kept the row, so the key came back for review forever. Both fixed here; `EXTRACTOR_VERSION` and the protocol are untouched | module-uo |
| 9a | **DONE 2026-09-14.** The docs pass and the acceptance walk (§17.13). `INTEGRATION.md` carried to protocol 8 — it had stopped at **6**, contradicted itself, and documented none of this plane; the operator-facing upgrade note; the index rows; the installer's `libgdiplus` `doctor` check and the kit's chapter note, both promised by §15 and built by no phase. The walk wiped every asset row and every imported sprite and went through it as a new operator: **1,095 portraits in 3.18 s, 67,496 names in 1.42 s, 313 item pictures in 1.38 s, the atlas over the bridge in ~2.0 s, and an Update with no drift answered in 0.99 s**. Two defects (§17.14), the larger of them **not ours and released** — Events phase 12b's `unique_id` has been failing every spawn-atlas import on every upgraded install since v1.2.0, which only a walk on a rig whose tables predate it could see | docs, module-uo, installer, integration-kit, servuo-plugins |
| 9b | **DONE 2026-09-14.** The `edge → main` cutover, and it is **five repos, not four**`installer`'s `doctor` check was on `edge` too, and `SHARD_PREREQS.md` on `main` had been describing it as if it shipped (§17.15). Order: the `module-uo` sync first, then `link` + `servuo-plugins` **together** because `bundle.yml` Gate 1 refuses a protocol-mismatched pair, then `website`, `module-uo`, `installer`. The sync found the one real conflict in the whole cutover: both branches had bumped `PARSER_VERSION` **4 → 5** for different reasons and main's 5 was **released**, so keeping it would have made phase 7's re-read unreachable on every existing install — the merged value is **6** (§10.4). Core's entire share of eight phases is a **deletion**: `MODULE_API` never moved, because `ctx.uploads` was already exposed | link, servuo-plugins, module-uo, website, installer |
| 9b | **DONE 2026-09-14.** The `edge → main` cutover, and it is **five repos, not four**`installer`'s `doctor` check was on `edge` too, and `SHARD_PREREQS.md` on `main` had been describing it as if it shipped (§17.15). Order: the `module-uo` sync first, then `link` + `servuo-plugins` **together** because `bundle.yml` Gate 1 refuses a protocol-mismatched pair, then `website`, `module-uo`, `installer`. The sync found the one real conflict in the whole cutover: both branches had bumped `PARSER_VERSION` **4 → 5** for different reasons and main's 5 was **released**, so keeping it would have made phase 7's re-read unreachable on every existing install — the merged value is **6** (§10.4). Core's entire share of eight phases is a **deletion**: `MODULE_API` never moved, because `ctx.uploads` was already exposed. Published: sidecar **v2.3.0**, overlay **v1.3.0**, module **v1.3.0**, installer **v0.2.0**, bundle **2026.09.15 (protocol 8)**. `edge` stays standing in every repo | link, servuo-plugins, module-uo, website, installer |
| 9c | runicgateway.com: `platform.json`'s protocol 7 → 8 and the bundle triple, and any prose the bridge changed. Must follow 9b — `checkFacts.mjs` reads the protocol from `link`'s `main` | runicgateway.com |
Phase 0 exists because §4 chose to call code that can take the shard down if it is wrong, and the
@@ -1949,4 +1949,44 @@ in the document.
The ordering itself was not a question: `link` and `servuo-plugins` must land **together**,
because `bundle.yml` Gate 1 refuses a sidecar/overlay pair that disagrees on protocol and
whichever lands alone leaves a compose that cannot run. That is not a prediction — it is what
happened at the Event System's cutover, compose run 102.
happened at the Event System's cutover, compose run 102, and it happened again here: the overlay
released nine minutes ahead of the sidecar and **compose run 111 refused the pair in exactly
those terms** — *"sidecar v2.2.0 speaks 7, overlay v1.3.0 declares 8. Refusing to publish a
bundle that would install a shard whose events the sidecar rejects with 409."* The gate is not
a formality; it is the only thing standing between a half-landed cutover and an operator
installing a shard that cannot talk to its own sidecar.
16. **What the cutover published, and the one thing that needed a hand.**
| Component | Release | Protocol |
|---|---|---|
| `link` sidecar | **v2.3.0** | 8 |
| `servuo-plugins` overlay | **v1.3.0** | 8 |
| `module-uo` | **v1.3.0** | — |
| `installer` | **v0.2.0** | — |
| bundle | **2026.09.15** | 8 |
`edge` stays standing in every repo.
The re-verify §17.15 chose — check the pairing rather than rebuild the whole rig — is what
found the one thing that did not happen by itself. **The bundle did not recompose on its own.**
Two compose runs failed for two unrelated reasons, and only reading both logs separates them:
- **Run 111 was Gate 1**, correctly refusing the mismatched pair in the window between the two
releases. Expected, and the reason the pair lands together.
- **Run 114 was the runner**, after both releases were out: `Set up job` took **14m33s** and
then every subsequent step failed at **0s** with **no log blob stored** (its log route 500s).
That is the same signature as the 2026-09-09 outage and has nothing to do with the bundle's
content.
A failed compose is silent from the outside: the bundle simply stays at its previous value, so
operators keep installing the **previous protocol** while `main` carries the new one, and
nothing says so. `bundle.yml`'s nightly cron exists to self-heal exactly this, but that is up to
a day of operators fetching a stale pair. Recovery is
`POST /api/v1/repos/RunicGateway/installer/actions/workflows/bundle.yml/dispatches {"ref":"main"}`
→ 204, and the recomposed bundle published within the minute.
**The lesson for any future cutover: publishing the releases is not the last step — verifying
the bundle actually moved is.** A green release run does not imply a recomposed bundle, and the
gap between them is invisible to everything except a direct read of `current.json` (through
`/contents/`, never `/raw/`, which is CDN-cached for six hours).