/* * The subscribable kind vocabulary — a LEAF module, importing nothing. * * It lives alone because `events.ts` and `record-events.ts` both need it and * import each other: with the registry inside `record-events.ts`, loading that * module FIRST threw `Cannot access 'EVENT_KIND_IDS' before initialization`, * since `events.ts` reads it at module scope while `record-events.ts` is still * evaluating. It worked only because `tools/index.ts` happens to export * `events.js` first — a load-ORDER dependency, invisible until something * imports the module directly, which is exactly what a consumer or a test does. * * A cycle that works by luck is not a working cycle. */ /** * The kind vocabulary lives HERE, beside the emitters, and `events.ts` imports * it. That direction is deliberate: it is what makes the enum impossible to * widen without adding an emitter in the same file. */ export type SubKind = keyof typeof EVENT_KINDS; /** * ⟨q-2b7d9f04⟩ — EVERY KIND SHIPS WITH THE CHANGE THAT MUST PRODUCE IT. The * `item` subscription sat at `health: ok` for three days while structurally * unable to fire: an emitter existed, so the registry was satisfied, and the * scanner RAN, so liveness was satisfied — but the grammar never read the * leading item id `land` writes, so no live commit could ever produce the * kind. A probe is the LIVE shape, not the smallest one: two items out, two * leading-id entries in, one PR — the #328 commit. Health asks the scanner to * produce each kind from its probe; a kind whose probe yields nothing CANNOT * FIRE, whatever the emitter list and the scan clock say. */ export type KindProbe = { diff: string; after?: { done?: string; phases?: Record } }; /** `refs`: ⟨q-cbace757⟩ — a closure cited by N PRs carries all N, each checked against the record on its own; `ref` stays the joined form for the event key. */ export type RecordEvent = { kind: SubKind; target: string; ref: string; summary: string; refs?: string[] }; /* * THE KIND REGISTRY IS THE SINGLE SOURCE, AND THAT IS TASK 9.2. * * `SubKind` used to be a hand-written union next to a hand-written zod enum next * to an emitter that covered one of the four. Nothing connected them, so a kind * could be offered for subscription while nothing could ever emit it — and * `list_subscriptions` would report its permanent `never evaluated` forever, * honestly and uselessly. * * Now the union, the wire enum, and the emitter set are all derived from THIS * object. A kind cannot be offered without an emitter because the enum is * generated from the emitters; `test/record-events.test.mjs` closes the other * half by asserting each kind actually fires. Unsatisfiable BY CONSTRUCTION, * rather than by a reviewer noticing. */ export const EVENT_KINDS = { item: { record: "docs/QUEUE.md + docs/DONE.md", what: "a queue item closed — a DONE.md entry beginning with its ⟨q-…⟩ id appeared (land writes it), or it left QUEUE.md against one unambiguous entry", targetIs: "the queue item id", probe: { diff: "diff --git a/docs/QUEUE.md b/docs/QUEUE.md\n--- a/docs/QUEUE.md\n+++ b/docs/QUEUE.md\n@@ -1,1 +1,1 @@\n-- [ ] (P1) ⟨q-0a0a0a01⟩ Kit: the first thing to do\n-- [ ] (P1) ⟨q-0a0a0a02⟩ Kit: the second thing to do\n\ndiff --git a/docs/DONE.md b/docs/DONE.md\n--- a/docs/DONE.md\n+++ b/docs/DONE.md\n@@ -1,1 +1,1 @@\n+- [x] ⟨q-0a0a0a01⟩ Kit: what was done for the first… — owner/repo#77 · 2026-09-14\n+- [x] ⟨q-0a0a0a02⟩ Kit: what was done for the second… — owner/repo#77 · 2026-09-14\n" } as KindProbe, }, pr: { record: "docs/DONE.md", what: "a PR recorded in the completion log", targetIs: "the PR ref, e.g. owner/repo#163", probe: { diff: "diff --git a/docs/DONE.md b/docs/DONE.md\n--- a/docs/DONE.md\n+++ b/docs/DONE.md\n@@ -1,1 +1,1 @@\n+- [x] a PR recorded in the completion log — owner/repo#78 · 2026-09-14\n" } as KindProbe, }, task: { record: "docs/phases/**/PHASE*_TASKS.md", what: "a phase task checkbox newly ticked", targetIs: "the task key, e.g. 5:12.1", probe: { diff: "diff --git a/docs/phases/phase9/PHASE9_TASKS.md b/docs/phases/phase9/PHASE9_TASKS.md\n--- a/docs/phases/phase9/PHASE9_TASKS.md\n+++ b/docs/phases/phase9/PHASE9_TASKS.md\n@@ -1,1 +1,1 @@\n-- [ ] 1.1 first\n+- [x] 1.1 first\n" } as KindProbe, }, phase: { record: "docs/phases/**/PHASE*_TASKS.md", what: "the last open checkbox in a phase document ticked", targetIs: "the phase number, e.g. 5", probe: { diff: "diff --git a/docs/phases/phase9/PHASE9_TASKS.md b/docs/phases/phase9/PHASE9_TASKS.md\n--- a/docs/phases/phase9/PHASE9_TASKS.md\n+++ b/docs/phases/phase9/PHASE9_TASKS.md\n@@ -1,1 +1,1 @@\n-- [ ] 1.2 second\n+- [x] 1.2 second\n", after: { phases: { "docs/phases/phase9/PHASE9_TASKS.md": "# Phase 9\n\n- [x] 1.1 first\n- [x] 1.2 second\n" } } } as KindProbe, }, } as const; export const EVENT_KIND_IDS = Object.keys(EVENT_KINDS) as [SubKind, ...SubKind[]];