Commit Graph

4 Commits

Author SHA1 Message Date
e91e76bfa9 docs(site): the Event System — the platform's facts, and two pages for it
All checks were successful
PR checks / checks (pull_request) Successful in 9m34s
Phase 16c of the events plan: `runicgateway.com`'s half of the workstream, now
that `main` carries the engine, the module, the app and the bundle.

The checks were already red and named their own answers:

* `checkFacts` — nine values had moved. Protocol 5 → 7 in all three declaration
  sites, `moduleApi` 1.9.0 → 1.10.0, the bundle to 2026.09.10 with sidecar
  v2.2.0 and overlay v1.2.0, `link` v2.2.0, `Module-uo` v1.2.2.
* `checkReference` — twenty-seven `Bridge.cfg` keys the site listed nowhere: the
  events switch and its sweep, the ten caps, the oracle NPC, the two lease keys
  and the seven participation keys. They are five new groups rather than an
  appendix to an existing one, because `EventsEnabled` is a second consent
  switch and belongs beside its own ceilings.

Two pages, matching the treatment Teams has:

* **Scheduled events** (Administration) — where it is and who sees it, authoring
  and immutable versions, the switchboard that arrives off, caps as a condition
  on an `UPDATE` rather than a role check, the dry run, the run console, what an
  event owns versus what it borrows, generated cleanup, the shard's own switches,
  and what a player sees.
* **Events architecture** — the two sentences it turns on, what is a table and
  what deliberately is not, budgets in SQL, the ledger's two rules, at-most-once
  on a wire that can lose an answer, the three layers, and the four omissions.

And the rest of the surface:

* `/privacy` gains **`deploy-events`** — the participation ledger is personal
  data and no row named it. Scores and ranks against a module-opaque member key,
  linked to an account where one is linked; the diagnostic log swept after 90
  days on terminal runs only; the run, its steps and its participants not swept
  at all, because they are the record of what was done to a shared world.
  `deploy-game-data`'s citation moves from `link/v4.md` to `v7.md`.
* **Protocol versions** — the most recent bump touched *five* repositories, and
  the `website` row is the interesting one: core is normally out of a protocol
  bump's reach and this one reached it, because what changed was not a game noun
  but the shape of a thing core owns the ledger for. The store-migration
  paragraph now says four bumps' worth rather than two.
* Two capability entries, so `/`, `/features/` and `/modules/` stop omitting the
  subsystem — an Administration item, and an **Event calendar** under Community
  with `/site/events` as its deep link. Deliberately *not* `needsModule`: a bare
  core can author and run an event, and only the world verbs need a module.
* **`reference/event-catalog` is retitled "Shard event catalog"** and says what
  it is not. Two things in the docs were called an event catalog; the route is
  unchanged, so nothing outside this repository breaks.
* `canonicalDocs` gains `website/EVENTS.md` and moves `link/v4.md` → `v7.md`.

No screenshots. Capturing the events surfaces means standing the whole rig back
up — game server, sidecar, core, module, a published event with a live run — for
two or three images that no check requires, and the engagement workstream's own
site leg added none either.

`npm run verify` green end to end, including `checkReference` against the
protocol spec that only reached `docs` `main` in RunicGateway/docs#232 — the
seventh cutover step, which 16b had left on `edge`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
2026-09-09 22:04:27 -05:00
82b55e3084 docs(site): /privacy tells the truth about engagement retention again
All checks were successful
PR checks / checks (pull_request) Successful in 1m23s
ENGAGEMENT.md Phase 14. The deploy-engagement entry in the collection
inventory said "Kept until the operator removes them; nothing here expires
on its own" and, in its detail, "the delivery log, the suppression list and
the per-person rate limits have no retention sweep, so they are as long as
the site is old". That was the true answer until Phase 14 landed a sweep,
and it is the kind of sentence a Play reviewer reads.

It now describes what the code does: a nightly sweep with an
operator-settable horizon per table (180 days for the delivery log, 30 for
the queue and the rate limits), and the two things that deliberately do NOT
expire — an item still waiting to be sent, because it is a message the site
still intends to deliver, and the suppression list, because ageing an entry
out would mean mailing an address that already bounced.

PLAY_DATA_SAFETY.md is unchanged and check:datasafety stays green:
deploy-engagement is deployment-scoped, and the Play answers are generated
from the app-scoped entries, because Play asks what the app collects rather
than what a self-hosted deployment keeps.

All ten checks green, 42 tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-01 15:41:14 -05:00
c8a293b8f6 docs(admin): the engagement rules screen, and the privacy inventory an engagement mailer changes
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>
2026-09-01 08:11:10 -05:00
a2faf07104 feat(legal): phase 6 — the privacy policy and the terms
All checks were successful
PR checks / checks (pull_request) Successful in 55s
PLAN.md §9. Builds /privacy and /terms, links them from the footer on every page,
and generates the Play Data Safety notes from the same inventory the policy renders.

Four decisions taken by the org lead before either page was written, recorded in
§9 under "How phase 6 built the legal pages":

  D30  DNS-only records, so the reverse proxy on the host keeps the only access
       log. Described qualitatively — the retention belongs to the proxy, and a
       policy that quotes a number the deployment does not enforce is worse than
       one that does not.
  D31  Eighteen or older. Above the children's-consent threshold everywhere in the
       EEA, so consent works with no parental-consent machinery this form could not
       honestly operate. Four surfaces render it from src/data/legal.mjs, and every
       one says plainly that nothing verifies it.
  D32  No governing-law clause. Nothing of value is contracted for here.
  D33  PLAY_DATA_SAFETY.md is generated from src/data/collection.mjs and checked in
       CI, so the published policy and the answers given to Google cannot drift.

/privacy is three separately-scoped sections because "we" means three different
parties: this site (one form, no cookies, no third-party requests), the Android app
(we operate no server it talks to — the rows are what the DEVICE holds), and a
self-hosted deployment (the operator is the controller, not us). Every row names the
file it was read out of, because a policy is the document most likely to be written
from a template and least likely to be re-read against the software.

/terms governs only what we run: this site, the beta list, and the APK we publish.
The software is governed by its licence, and a community's deployment by that
community — a terms page claiming authority over every install of a GPL program is
the thing a generated template gets wrong.

Also here:
  - the age clause changed CONSENT_TEXT, so CONSENT_VERSION gained a suffix; rows
    written from now on carry the new sentence and older rows keep theirs
  - PLANNED_ROUTES is now empty — these were its last two entries, and its reverse
    check is what forced the deletion; the list stays for phases 7 and 8
  - test/legal.test.mjs asserts the structural promises no build check can see,
    including that every mapped Play row still answers "not collected, not shared"
  - --check normalises line endings: the repo has no .gitattributes and Windows
    checkouts are CRLF, so a byte comparison would fail for every Windows developer
    while passing in CI

Verified: npm run verify green end to end (tokens, brand, data safety, astro check,
36 tests, build, 214 links, 19 facts), both pages walked in a browser, and neither
overflows at 390px. One defect the checks could not see and a look could: the
retention line was being pushed to the foot of the tallest card in its row, opening
a void in the middle of the short ones.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-24 04:21:47 -05:00