docs(site): the engagement system — cutover 7 of 7 (edge → main)
#28
Reference in New Issue
Block a user
No description provided.
Delete Branch "edge"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Engagement Phase 13, step 7 of 7 — the last one. The public site, which the merge order put last because every fact it fetches has to be true on
mainfirst. It now is: steps 1–6 are merged, the bundle was republished as 2026.09.01, andcheckFactsagrees with all nineteen authorities.17 commits, 18 files, a clean fast-forward (
mainis 0 commits ahead). Seven PRs, #21 through #27.What lands
platform.jsonlinkv2.1.0,Module-uov1.1.0/privacyand the generated Play Data Safety answers, re-derived from one inventory that an engagement mailer changescontentsendpoint instead ofrawThis is the first CI run these checks have ever had
pr-checks.ymltriggers on PRs intomainonly, so not one of the seven phase PRs was gated — the same shape asandroid-app's trigger before Phase 8 fixed it. Everything below was run locally against this head instead, and is green:The one thing worth reading twice
checkFactsfailed this branch for amoduleApithat was correct. Gitea'srawAPI route answersCache-Control: public, max-age=21600, so the CDN served a copy of website'sversion.jsfrom two weeks earlier (cf-cache-status: HIT,Age: 15713) and no edit here could have made it pass. The same run reported the already-republished bundle triple as still current — a stale read fails both ways, and the false pass is the dangerous half for a repo whose whole bargain is going red when the platform moves.contentsanswersprivate, must-revalidate, which the CDN bypasses. Without that fix this PR would have been red for a reason nobody could find in the diff.PLAN.md§12 records it next to the check it constrains.🤖 Generated with Claude Code
Engagement Phase 12a. The site had pages for where a message goes (Notifications and email) and what it says (Message templates), and nothing at all for what makes one get sent -- the four Engagement screens the workstream built. New page: Engagement rules. Rules, Audiences, the trigger catalog and the send log on one page, sitting between the two it joins up. Templates already has its own page and Suppressions is in Troubleshooting, so neither is repeated here. Two things it exists to state plainly: * Every rule ships disabled, including the ones a module brings. "Installed" is not "on", and an upgrade whose Team mail went quiet is the same fact. * The ceiling is a TREE, not a ladder. The tempting reading -- a staff-only event could obviously also go to one person -- is wrong, and the example is the argument: "one person" for cheat detection is the player it was detected on. Troubleshooting gains the symptom that page answers ("nothing is sent for one particular event"): the rule is off, the rule is dormant, its own cooldown held it, or the audience is empty. Privacy: two rows the engagement work makes necessary, and one sentence it made false. * app-content claimed "Nothing is cached for offline use". Phase 8 shipped a DataStore snapshot of the inbox, so it was untrue -- and that row feeds the generated Play Data Safety answers, which is a store-review matter rather than 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 app-content's claim is narrowed to everything else. * deploy-engagement, for the deployment scope: an address is now used for more than getting into an account, there is a delivery log holding a one-way hash of it, and there is a suppression list. Its retention line says what is true rather than what a reader assumes -- none of these tables has a retention sweep. PLAY_DATA_SAFETY.md regenerated from the inventory; legal.lastUpdated moved with the page it dates. Verified: the whole `verify` chain green -- checkSidebar (plannedSidebar moved with the live tree), checkFacts 19/19, checkQuickstart 59, checkReference 22, checkLinks 2605, checkA11y, checkCsp, playDataSafety --check, 42 + 7 tests. Read in a browser as well, in the served build. AI-assisted: written with Claude Code. Co-Authored-By: Claude <noreply@anthropic.com>Engagement Phase 12b. **This branch is deliberately red and must not be merged until the Phase 13 cutover has landed link and servuo-plugins on `main` and CI has republished the bundle.** checkFacts.mjs fetches every value from the source repo's `main`, so it fails today exactly as designed: FAIL protocol (sidecar) platform.json 5 link main 4 FAIL protocol (overlay) platform.json 5 servuo-plugins main 4 FAIL moduleApi platform.json 1.9.0 website main 1.6.0 FAIL protocol (bundle) platform.json 5 installer bundles:current.json 4 Every other check is green on this branch: checkLinks 2503, checkReference 22, checkA11y, checkCsp, checkSidebar, 42 tests. moduleApi is **1.9.0**, not the 1.7.0 the plan named -- Phase 11 moved it twice after that sentence was written (1.8.0 for the `admin` ceiling, 1.9.0 for the module seed API). ## Also: the one page whose whole subject is the protocol number was the one page that ## hardcoded it platform.json's own header says no version number is ever hardcoded in prose, and `architecture/protocol-versions.mdx` had `4` written out three times -- the headline sentence and both declaration-site rows. It now imports platform.json like every other page that quotes a fact, so it moves with the JSON and cannot say 4 while the JSON says 5. Note the interpolation is OUTSIDE the code spans: MDX does not evaluate an expression inside backticks, so `PROTOCOL_VERSION: u32 = {platform.protocol}` would have rendered the braces literally. Verified in the built HTML -- "currently 5", and no `platform.protocol` survives anywhere in the output. The same page's "what a bump obliges" section said version 4 was the first bump to need a store migration, which read as though every bump does. v5 needed none (it only widens frames the store already keeps whole -- docs link/v5.md), so the sentence now says which did and which did not, and v5.md joins v4.md under canonical documents. ## The fill-in step, at merge time Three values are not knowable today because the artefact does not exist yet. After the bundle republishes, run: GITEA_TOKEN=<token> node scripts/checkFacts.mjs and copy what it prints in the "says" column into src/data/platform.json: * bundle.tag, bundle.sidecar, bundle.overlay -- from installer bundles:current.json * releases.Module-uo -- if the cutover cuts a new module release * verifiedOn -- the date you ran it Then re-read `getting-started/connect-a-game-server` and `administration/the-shard-connection`, which quote the bundle, before merging. The check is green when all 19 agree. AI-assisted: written with Claude Code. Co-Authored-By: Claude <noreply@anthropic.com>The three checks that read another repository -- checkFacts, checkQuickstart, checkReference -- fetched source files from the API's `raw` route, which answers `Cache-Control: public, max-age=21600`. The CDN in front of Gitea caches that, so the checks can read a blob most of a working day old. It bit on cutover day. checkFacts reported FAIL moduleApi platform.json says : 1.9.0 website main:server/src/modules/version.js says : 1.6.0 against a `main` that says 1.9.0 -- the served copy was two weeks old (`cf-cache-status: HIT`, `Age: 15713`, `last-modified: 18 Aug`). No edit in this repository could have made it pass, and the same run reported a bundle triple that had already been republished as still current: a stale read fails BOTH ways, and the false pass is the dangerous one. The `contents` endpoint answers `private, must-revalidate`, which the CDN bypasses, so it is always the ref's current blob. The cost is a JSON parse and a base64 decode. checkReference's canonical-document existence loop already used it, which is why that half was never affected. PLAN.md 12 records the finding next to the check it constrains. Co-Authored-By: Claude <noreply@anthropic.com>