docs(engagement): Phase 12 as built — the 12a/12b split and three findings #198

Merged
whitlocktech merged 1 commits from docs/engagement-phase-12 into edge 2026-09-01 13:19:24 +00:00

View File

@@ -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` | | **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` | | **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 | | **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 | | **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 **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 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. 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 ### 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 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 `PROTOCOL_VERSION` are one protocol bump with three declaration sites (CLAUDE.md). Then CI
publishes the paired bundle. 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. 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. 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 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. chapters.
6. **`android-app`** — the in-app inbox. First real CI run (§6.0a). 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. 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=<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. 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 **Acceptance:** a clean install from `main` alone stands the whole stack up — installer pairs a v5