From 067804706eb912b2c55728b980a96daf3289b2fe Mon Sep 17 00:00:00 2001 From: wtclaude Date: Tue, 6 Oct 2026 08:26:57 -0500 Subject: [PATCH] docs(kit): pin core 1.12.0; chapter 5 teaches progress() and ctx.events.expired The pin moves from 655fbf3f (1.10.0) to 0a37a44 (1.12.0, website#210), past 1.11.0 (website#209), which it had skipped. Chapter 5 was read again for both versions: - 1.11.0: a thing the game ends on its own schedule is reported with ctx.events.expired and filed `expired`, not `orphaned`. - 1.12.0: an action's optional progress(), the line on a public event page. It answers for one reader, cheaply, and costs a line rather than the page when it fails. "What to build, in order" gains it as step 7. The template declares neither, so nothing it does changed meaning. template/module.json's coreApi becomes ^1.12.0 for the equality check. Checks run at the new pin: - checkCoreApi, links, rename sites and chapter paths all pass. - The template's import, swagger, build and externals checks pass. - Tests pass: server 82, client 20, scripts 10 and 11. - The template was loaded as `examplegame` into a real core of this code through core's own loader, and it registered. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY --- book/05-events.md | 26 ++++++++++++++++++++++++-- ci/core-ref.json | 14 +++++++++++++- template/module.json | 2 +- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/book/05-events.md b/book/05-events.md index 7eb314a..d0747a9 100644 --- a/book/05-events.md +++ b/book/05-events.md @@ -148,6 +148,7 @@ api.registerEventActions([{ async perform({ runId, stepId, idempotencyKey, scope, params, actor, verify }) {}, async revert({ runId, resources, idempotencyKey }) {}, // required iff 'ledger' async reconcile({ runId, resources }) {}, // optional + async progress({ runId, stepId, idempotencyKey, params, resources, viewer }) {}, // optional, 1.12.0 }]) ``` @@ -166,6 +167,20 @@ second code path is a dry run of the second path. Validate everything you can reach without writing, then stop. Answering `{ ok: true }` unconditionally makes the dry run worthless in the one situation it exists for. +**`progress` is read by strangers, so it answers for one reader** (MODULE_API 1.12.0). +While a run is live, core asks it how its step stands and puts the answer on the +event's public page and in the app. + +- **The answer.** `{ label, left, of }` ("Beacons: 3 of 8 lit") or `{ label, percent }` + ("The warden: 62%"), or `null`. Core renders the text and reads nothing out of it. +- **Who is reading.** `viewer.userId` is the account reading the page, or null for a + stranger. Answer `null` to anybody your own pages would hide that information from: + a public page must never say what your map does not. +- **The cost.** It is a read, it may be asked every few seconds for as long as the + run lasts, and core gives it 2 s. Answer from something you already hold or + already cache, not from a fresh round trip to the game per reader. +- **Failure.** A throw or a late answer costs a line, never the page. + **`example` is required on every param, optional ones included.** It is the authoring form's placeholder. It is one word at declaration time and it is unreconstructable afterwards by anybody who did not write the action. @@ -294,6 +309,12 @@ And when you do answer: **anything that is not an explicit read as "it is gone". A resource you report missing becomes `orphaned` rather than `reverted`, because nobody asked for it to go. +**A thing your game ends on its own schedule is not orphaned** (MODULE_API 1.11.0). +If the game removes something at its own deadline (a zone that closes when its +time is up), call `ctx.events.expired({ kind, ref })` when it does. Core then marks the +row `expired`: finished as planned, never taken back at teardown. Left to `reconcile`, +the same thing would turn up `orphaned` and read as something that went wrong. + **You say WHEN to reconcile, because core cannot.** Core has no concept of the game being up — it sees `{ ok: false, retry: true }` and cannot tell a wedged sidecar from a game that rebooted and lost everything an event made. So it asks once, at @@ -355,8 +376,9 @@ Four things a second module's author reaches for and should not. 5. **One action that ledgers**, with `revert` and the four traps above. This is where the work is, and where the damage is. 6. **`reconcile`**, and the boot-id watch that calls `ctx.events.reconcile()`. - Last, because it is the only one whose absence is merely a lower standard - rather than a broken promise. + Its absence is merely a lower standard rather than a broken promise. +7. **`progress`**, if a visitor would want to watch the step happen. It is the only + one an outsider reads, so build it once the ledger it counts from is right. Then read your own `revert` again, and ask what it answers when the game is down. diff --git a/ci/core-ref.json b/ci/core-ref.json index 0a105f0..c6f8b82 100644 --- a/ci/core-ref.json +++ b/ci/core-ref.json @@ -1,9 +1,21 @@ { "repo": "https://gitea.whitlocktech.com/RunicGateway/website.git", "branch": "main", - "ref": "655fbf3f69a6a1fd650ecbc81afd6cf9c2ad9f66", + "ref": "0a37a44164ab107584b918e656651452b50bd4f3", "why": [ "The core this kit is written against, pinned to a commit rather than a branch.", + "", + "2026-10-06: moved from 655fbf3f (1.10.0) to 0a37a44 (1.12.0, website#210),", + "past 1.11.0 (website#209), which this pin had skipped. Chapter 5 was read again", + "for both versions and gained two paragraphs:", + "- ctx.events.expired (1.11.0): a thing the game ends on its own schedule is", + " `expired`, not `orphaned`;", + "- an action's optional progress() (1.12.0): the live line on a public event", + " page, which answers for one reader.", + "The template declares neither, and nothing it does changed meaning. The real", + "core run below was repeated at this ref.", + "", + "Before that move:" "This one is the EVENT SYSTEM cutover, the commit MODULE_API_VERSION 1.10.0", "reached `main` on (website#199), and 1.10.0 is what template/module.json", "declares. It moved here from 66bb3b9a (1.9.0, the engagement cutover) because", diff --git a/template/module.json b/template/module.json index fbe47e8..3301201 100644 --- a/template/module.json +++ b/template/module.json @@ -2,7 +2,7 @@ "id": "examplegame", "name": "Example Game", "version": "0.1.0", - "coreApi": "^1.10.0", + "coreApi": "^1.12.0", "server": "server/index.js", "client": { "entry": "client/dist/entry.js" }, "schema": "server/db/schema.sql", -- 2.49.1