docs(kit): pin core 1.12.0; chapter 5 teaches progress() and ctx.events.expired #14

Merged
whitlocktech merged 1 commits from docs/core-1.12.0 into main 2026-10-06 13:33:21 +00:00
3 changed files with 38 additions and 4 deletions

View File

@@ -148,6 +148,7 @@ api.registerEventActions([{
async perform({ runId, stepId, idempotencyKey, scope, params, actor, verify }) {}, async perform({ runId, stepId, idempotencyKey, scope, params, actor, verify }) {},
async revert({ runId, resources, idempotencyKey }) {}, // required iff 'ledger' async revert({ runId, resources, idempotencyKey }) {}, // required iff 'ledger'
async reconcile({ runId, resources }) {}, // optional 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 reach without writing, then stop. Answering `{ ok: true }` unconditionally makes
the dry run worthless in the one situation it exists for. 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 **`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 authoring form's placeholder. It is one word at declaration time and it is
unreconstructable afterwards by anybody who did not write the action. 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 read as "it is gone". A resource you report missing becomes `orphaned` rather than
`reverted`, because nobody asked for it to go. `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 **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 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 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 5. **One action that ledgers**, with `revert` and the four traps above. This is
where the work is, and where the damage is. where the work is, and where the damage is.
6. **`reconcile`**, and the boot-id watch that calls `ctx.events.reconcile()`. 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 Its absence is merely a lower standard rather than a broken promise.
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. Then read your own `revert` again, and ask what it answers when the game is down.

View File

@@ -1,9 +1,21 @@
{ {
"repo": "https://gitea.whitlocktech.com/RunicGateway/website.git", "repo": "https://gitea.whitlocktech.com/RunicGateway/website.git",
"branch": "main", "branch": "main",
"ref": "655fbf3f69a6a1fd650ecbc81afd6cf9c2ad9f66", "ref": "0a37a44164ab107584b918e656651452b50bd4f3",
"why": [ "why": [
"The core this kit is written against, pinned to a commit rather than a branch.", "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", "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", "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", "declares. It moved here from 66bb3b9a (1.9.0, the engagement cutover) because",

View File

@@ -2,7 +2,7 @@
"id": "examplegame", "id": "examplegame",
"name": "Example Game", "name": "Example Game",
"version": "0.1.0", "version": "0.1.0",
"coreApi": "^1.10.0", "coreApi": "^1.12.0",
"server": "server/index.js", "server": "server/index.js",
"client": { "entry": "client/dist/entry.js" }, "client": { "entry": "client/dist/entry.js" },
"schema": "server/db/schema.sql", "schema": "server/db/schema.sql",