diff --git a/website/ENGAGEMENT.md b/website/ENGAGEMENT.md index 4e6b036..d378d9e 100644 --- a/website/ENGAGEMENT.md +++ b/website/ENGAGEMENT.md @@ -1387,7 +1387,7 @@ change is not complete until `docs/` reflects it" — is the floor; this table i | **10** Protocol bump | `link/INTEGRATION.md` §Housing **and §Market** (tables + examples) + the new `account.login.result` row · `link/PLAN.md` §5/§7 · **a `link/v5.md`** — the bump now carries three enrichments across three subsystems, which is what earned v3 and v4 their own design docs | `servuo-plugins/overlay.toml` · `servuo-plugins/patches/README.md` — `vendor.sale` stays in the tier and the docs must say what that costs · **`runicgateway.com`**: `platform.json.protocol` → 5, `bundle.*`, `architecture/protocol-versions.mdx` | | **11a** module-uo triggers | `modules/uo/API.md` — **the full trigger catalogue, its audiences and its ceilings**, not one entry · `modules/uo/README.md` · `website/ENGAGEMENT.md` §8.6 kept true as rows ship · `website/MODULE_API.md` §1.1 (**1.8.0**) and the ceiling vocabulary wherever it is enumerated · `BACKEND_DESIGN.md` — the `news.post` publish path now runs through the engine | `module-uo/README.md` | | **11b** Seeded rules + templates | `website/ENGAGEMENT.md` this phase as built · a release note naming **the seeded-disabled `news.post` rule as an upgrade step** (decision 5) — without it a deployment loses news push silently | **`runicgateway.com`**: `capabilities.mjs` and the notifications page — "one rule" and "the whole catalogue" are different marketing claims | -| **12** Public site | — | **`runicgateway.com`**, in full — see the phase | +| **12** Public site | `website/ENGAGEMENT.md` this phase as built, incl. the 12a/12b split and Phase 13's fill-in step | **`runicgateway.com`**, in full — see the phase. **Two PRs**: 12a (#26) mergeable now, 12b (#27) a draft held for the cutover window | | **13** Cutover | `README.md` index rows · every doc's status line | `.profile/README.md` if this is a headline capability | **One thing this table is protecting against.** `runicgateway.com` appears in eight rows, and it is the @@ -3646,6 +3646,65 @@ post-cutover `main` of every source repo**; `grep -ri "gmail" src/` returns only references; `/privacy` and `PLAY_DATA_SAFETY.md` regenerate from the amended inventory with no manual edit; the Notifications capability line is true of the shipped system. +#### As built (2026-09-01) — split 12a / 12b, because the facts cannot be green and correct at once + +**The org lead's decision: split the phase.** The timing note above says Phase 12's work is "written +and reviewed before the cutover and merged inside the same window", and building it made the reason +sharper than the sentence. `checkFacts.mjs` fetches from `main`, so the moment `platform.json` says +`protocol: 5` the repo is red — and it stays red for the whole `edge` window. Worse, **three of its +values cannot be written at all today**: `bundle.tag` / `bundle.sidecar` / `bundle.overlay` name an +artefact that does not exist until Phase 13 has landed `link` + `servuo-plugins` on `main` and CI has +republished the bundle. So: + +- **12a — `runicgateway.com#26`, mergeable on `edge` today.** The `Engagement rules` page, the + Troubleshooting symptom that points at it, the cross-links, and the `/privacy` + Play Data Safety + inventory. Every check green. +- **12b — `runicgateway.com#27`, a DRAFT, deliberately red.** `platform.json` `protocol` → 5 and + `moduleApi` → 1.9.0, plus the protocol page. Held for the Phase 13 window; the fill-in step is in + Phase 13's order below. + +**Two of this section's own statements were already stale**, both because Phase 11 moved after it was +written: `moduleApi` is **1.9.0**, not 1.7.0 (1.8.0 for the `admin` ceiling, 1.9.0 for the module seed +API), and the `capabilities.mjs` "Web" claim was already corrected in Phase 7's rg.com#24. The Gmail +sweep is likewise already done — `grep -ri gmail src/` returns only the migration note Phase 1 wrote +and the historical reference in Troubleshooting, which is what the acceptance line asks for. + +**The page the phase actually owed.** "New docs pages … the engagement rules screen, the template +editor, and per-channel notification preferences" — the second and third landed in Phases 5b and 7. The +first had not, and it was the largest hole on the site: there was a page for *where* a message goes and +a page for *what it says*, and nothing for **what makes one get sent**, which is the entire admin +surface this workstream built. One page — Rules, Audiences, the trigger catalog and the send log — +between the two it joins up. Suppressions stays in Troubleshooting (Phase 9) and Templates keeps its +own page (Phase 5b). + +Two things it exists to state, because both are things a reader gets wrong by reasoning: + +- **Every rule ships disabled, including the ones a module brings.** "Installed" is not "on". +- **The ceiling is a tree, not a ladder** (§7.2's lattice). The ladder reading says a staff-only event + could obviously also go to one person; "one person" for `uo.cheat.detected` is *the player it was + detected on*. + +#### Three findings, none of them in the phase's own text + +**1. `/privacy` had been publishing a false sentence since Phase 8.** The `app-content` row claimed +"Nothing is cached for offline use and nothing is duplicated anywhere else", and Phase 8 shipped a +DataStore snapshot of the inbox. That row is an *input to the generated Play Data Safety answers*, so +it is a store-review matter and not a doc nit. The snapshot now has its own row and its own Play +mapping (Messages / Other in-app messages; not collected by us, stored on the device), and the old +claim is narrowed rather than softened. + +**2. Nothing in the engagement schema has a retention sweep.** `engagementCooldowns.db.prune()` exists +and **has no caller**; a finished `engagement_outbox` row is never deleted; the send log and the +suppression list grow forever. The `deploy-engagement` privacy row therefore says "kept until the +operator removes them; nothing here expires on its own", which is the true answer rather than the one +a reader assumes. **Recorded, not fixed** — a sweep is a `website` change and outside this phase. + +**3. The one page whose whole subject is the protocol number was the one page that hardcoded it.** +`platform.json`'s header says no version number is ever hardcoded in prose; `protocol-versions.mdx` +wrote `4` three times. It now imports the JSON like every other page that quotes a fact. Note for +whoever does this again: **MDX does not evaluate an expression inside backticks**, so the interpolation +has to sit outside the code span or the braces reach the published page. + --- ### Phase 13 — The cutover: `edge` → `main`, in order @@ -3658,7 +3717,7 @@ v4 overlay is a shard that cannot pair, and the installer refuses it by design. 2. **`servuo-plugins`** and **`link`** together — the emitter and `overlay.toml` and `PROTOCOL_VERSION` are one protocol bump with three declaration sites (CLAUDE.md). Then CI publishes the paired bundle. -3. **`website`** — core: the transport abstraction, the trigger registry, `MODULE_API_VERSION` 1.7.0, +3. **`website`** — core: the transport abstraction, the trigger registry, `MODULE_API_VERSION` **1.9.0**, the engine, the templates, the in-app channel, the Teams migration. 4. **`module-uo`** — its `coreApi` range and its triggers, after the core it declares against. 5. **`Integration-kit`** — `ci/core-ref.json` to the new website `main` sha. Its equality check is red @@ -3666,6 +3725,14 @@ v4 overlay is a shard that cannot pair, and the installer refuses it by design. chapters. 6. **`android-app`** — the in-app inbox. First real CI run (§6.0a). 7. **`runicgateway.com`** — last, because every fact it fetches has to be true on `main` first. + Two merges, in this order: **12a (#26)** into `edge` at any time, then `edge` → `main`, then + **12b (#27)** with its three unknowable values filled in. Filling them in is mechanical, because + the check names them: run `GITEA_TOKEN= node scripts/checkFacts.mjs` and copy what it prints + in the "says" column — `bundle.tag`, `bundle.sidecar`, `bundle.overlay` from + `installer bundles:current.json`, `releases.Module-uo` if the cutover cut a new module release, and + `verifiedOn` as the date it was run. Then re-read the two pages that quote the bundle + (`getting-started/connect-a-game-server`, `administration/the-shard-connection`) before merging — + §12's own rule is that a value is never edited to make the check pass. 8. **`.profile/README.md`** — only if this is a headline capability. **Acceptance:** a clean install from `main` alone stands the whole stack up — installer pairs a v5