gm-skill 2.0.1549 → 2.0.1551

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -22,161 +22,153 @@ Skills encode environment-specific constraints that override general knowledge.
22
22
 
23
23
  # Architecture & Philosophy
24
24
 
25
- This repo IS the published `gm-skill` npm package. The repo root is the package root, no factory, no build step that generates a separate output dir. `skills/gm-skill/SKILL.md` is the ~12-line entry point; every possible phase prose and orchestration logic lives in rs-plugkit and is served on demand via the `instruction` verb.
25
+ This repo IS the published `gm-skill` npm package: repo root = package root, no factory, no build step generating a separate output dir. `skills/gm-skill/SKILL.md` is the entry point; orchestration logic lives in rs-plugkit, served on demand via the `instruction` verb. Agent-facing prose (phase instruction text + gate/residual messages) is externalized to an editable bundle in `gm-plugkit/instructions/`, shipped by gm-plugkit and provisioned into `.gm/instructions/<key>.md`; `rs-plugkit/src/prose.rs` serves the bundle entry per key and falls back to the compiled `const` when absent -- so editing prose is a gm-plugkit republish with no Rust rebuild. The bundle .md and the rs-plugkit `src/orchestrator/instructions/<key>.rs` consts are kept byte-aligned by `gm-plugkit/scripts/sync-instruction-consts.mjs` (regenerates each `<key>.rs` as `pub const TEXT` from the .md). Detail in rs-learn (`recall: string-externalization project`).
26
26
 
27
27
  ## WASM-only
28
28
 
29
- The plugkit stack runs as a wasm cdylib loaded by `plugkit-wasm-wrapper.js` under Node/bun. No native binaries are built, downloaded, or published. The shipped `plugkit.wasm` (~149MB, embeds bge-small-en-v1.5 for offline in-wasm embeddings) is fetched at bootstrap from `plugkit-wasm` npm / `plugkit-bin` gh-releases, sha256-pinned, not bundled in `gm-skill`. Full size/embedding mechanics in rs-learn (`recall: WASM-only plugkit size mechanics`).
29
+ The plugkit stack runs as a wasm cdylib loaded by `plugkit-wasm-wrapper.js` under Node/bun -- no native binaries built, downloaded, or published. The shipped `plugkit.wasm` (~149MB, embeds bge-small-en-v1.5 for offline in-wasm embeddings) is fetched at bootstrap from `plugkit-wasm` npm / `plugkit-bin` gh-releases, sha256-pinned. Size/embedding mechanics in rs-learn (`recall: WASM-only plugkit size mechanics`).
30
30
 
31
- **Every wasm host-import `extern "C"` block carries `#[link(wasm_import_module = "env")]`.** Holds in rs-plugkit AND every dep crate linked into the cdylib (rs-learn) AND any sibling that builds wasm (rs-exec, rs-search) -- add a host import anywhere and the block carries the attribute or the cascade goes dark. The silent-pass trap (local builds stay green, only Linux CI link fails), recovery, and the full host-fn `env` enumeration live in rs-learn (`recall: cascade outage wasm import module link`, `recall: wasm host-import link-module trap`).
31
+ **Every wasm host-import `extern "C"` block carries `#[link(wasm_import_module = "env")]`** -- in rs-plugkit AND every dep crate linked into the cdylib (rs-learn) AND any sibling building wasm (rs-exec, rs-search); miss it anywhere and the cascade goes dark (local builds stay green, only Linux CI link fails). Incident + host-fn enumeration in rs-learn (`recall: cascade outage wasm import module link`, `recall: wasm host-import link-module trap`).
32
32
 
33
- **`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()` (throws silently under bun's ESM inside `catch(_){}`).** Full incident in rs-learn (`recall: wrapper require not defined under bun`).
33
+ **`plugkit-wasm-wrapper.js` is ESM; import node builtins at module scope, never inline `require()`** (throws silently under bun's ESM inside `catch(_){}`). Incident in rs-learn (`recall: wrapper require not defined under bun`).
34
34
 
35
- **Every single-instance / lock guard is atomic (`fs.openSync(path,'wx')` O_EXCL or atomic-rename), never check-then-act; count plugkit processes by executable Name not command-line substring.** Both are Windows concurrency mechanics whose full incident lives in rs-learn (`recall: supervisor churn TOCTOU atomic guard`).
35
+ **Every single-instance/lock guard is atomic** (`fs.openSync(path,'wx')` O_EXCL or atomic-rename), never check-then-act; count plugkit processes by executable Name, not command-line substring. Incident in rs-learn (`recall: supervisor churn TOCTOU atomic guard`).
36
36
 
37
37
  ## Spool dispatch ABI
38
38
 
39
- Agents dispatch verbs by writing to `.gm/exec-spool/in/<verb>/<N>.txt` (request body) and reading the response from `.gm/exec-spool/out/<verb>-<N>.json` (nested verbs) or `.gm/exec-spool/out/<N>.json` (root verbs). The wasm orchestrator services every possible verb; the harness never executes side effects directly.
39
+ Agents dispatch verbs by writing `.gm/exec-spool/in/<verb>/<N>.txt` and reading `.gm/exec-spool/out/<verb>-<N>.json` (nested) or `out/<N>.json` (root). The wasm orchestrator services every verb; the harness never executes side effects directly.
40
40
 
41
- **Orchestrator verbs**: `instruction`, `transition`, `phase-status`, `mutable-resolve`, `memorize-fire`, `residual-scan`, `auto-recall`.
42
-
43
- **Wasm-direct verbs**: fs/kv/exec/fetch/env, recall, codesearch, memorize(+prune), health, filter, and the full git verb family. Complete enumeration in rs-learn (`recall: wasm-direct plugkit verbs full list`).
44
-
45
- **memorize-prune verb**: deletes bad/superseded memories -- pruning bad memory matters more than preserving good memory (a wrong recall hit is worse than a miss). Explicit `{key}`/`{keys:[...]}` deletes; `{query}` returns review-only candidates the agent judges before re-dispatching the stale keys -- never a blind similarity-delete (that is itself a bad-memory generator). Full two-mode spec in rs-learn (`recall: memorize-prune verb two-mode spec`).
46
-
47
- **git verbs**: git is a first-class spool surface, never a shell command; `git_finalize {message}` is the bundled COMPLETE-phase push surface and `git_push` is the only admissible raw push (porcelain-gated, rebase-retry). A git-dominant `bash`/`powershell` body is gated (`deviation.bash-git-bypass`). Full per-verb shapes, host_git `.exe` resolution, and the gate detail live in rs-learn (`recall: git verbs rs-plugkit spool surface`).
48
-
49
- **filter verb**: pure stdout -> compact-stdout transformation, in-wasm, no subprocess; pipe raw command output through it before it enters context. Full per-kind spec in rs-learn (`recall: filter verb rs-plugkit spool spec`).
41
+ - **Orchestrator verbs**: `instruction`, `transition`, `phase-status`, `mutable-resolve`, `memorize-fire`, `residual-scan`, `auto-recall`.
42
+ - **Wasm-direct verbs**: fs/kv/exec/fetch/env, recall, codesearch, memorize(+prune), health, filter, full git verb family. Enumeration in rs-learn (`recall: wasm-direct plugkit verbs full list`).
43
+ - **memorize-prune**: deletes bad/superseded memories (a wrong recall hit is worse than a miss). `{key}`/`{keys:[...]}` deletes; `{query}` returns review-only candidates to judge before re-dispatching stale keys -- never a blind similarity-delete. Spec in rs-learn (`recall: memorize-prune verb two-mode spec`).
44
+ - **git verbs**: git is a first-class spool surface, never a shell command; `git_finalize {message}` is the bundled COMPLETE-phase push surface, `git_push` the only admissible raw push (porcelain-gated, rebase-retry). A git-dominant `bash`/`powershell` body is gated (`deviation.bash-git-bypass`). Per-verb shapes + host_git `.exe` resolution in rs-learn (`recall: git verbs rs-plugkit spool surface`).
45
+ - **filter**: pure stdout -> compact-stdout transform, in-wasm, no subprocess; pipe raw command output through it before it enters context. Spec in rs-learn (`recall: filter verb rs-plugkit spool spec`).
50
46
 
51
47
  ## Documentation Policy
52
48
 
53
- Only record non-obvious technical caveats that cost multiple runs to discover. Remove every possible thing that no longer applies. Never document what is already obvious from reading the code.
49
+ Record only non-obvious technical caveats that cost multiple runs to discover; remove what no longer applies; never document what is obvious from the code.
54
50
 
55
- **No changelog history in AGENTS.md.** Every possible entry is a present-tense rule about what must or must-not be the case in code now. Forbidden: `(FIXED)` markers, commit hashes, dated audit entries, `## Learning audit` sections, "(added 2026-04-DD)" annotations, "we used to X, now we Y" phrasing. Historical framing belongs in `git log` and `CHANGELOG.md`.
51
+ **No changelog history in AGENTS.md.** Every entry is a present-tense rule about what must/must-not be the case in code now. Forbidden: `(FIXED)` markers, commit hashes, dated audit entries, `## Learning audit` sections, "(added 2026-...)" annotations, "we used to X, now Y". History belongs in `git log` and `CHANGELOG.md`.
56
52
 
57
- **Detail-heavy caveats live in rs-learn (`.gm/rs-learn.db`), not here.** Per-crate runtime quirks, Windows process-spawn mechanics, hook implementation details, ocw/site/workflow specifics, and similar fact-base material are exfiltrated to rs-learn and reachable via `exec:recall`. AGENTS.md keeps only top-level rules that govern gm-the-repo. When in doubt: gm-the-repo architecture or cross-cutting policy stays here; single-crate or single-platform mechanism goes to rs-learn.
53
+ **Detail-heavy caveats live in rs-learn (`.gm/rs-learn.db`), not here.** Per-crate runtime quirks, Windows process-spawn mechanics, hook details, ocw/site/workflow specifics, and similar fact-base material are exfiltrated to rs-learn (`exec:recall`); AGENTS.md keeps only top-level rules governing gm-the-repo. In doubt: cross-cutting policy stays here, single-crate/single-platform mechanism goes to rs-learn.
58
54
 
59
- **Every memorize run also drains AGENTS.md -- migration is bidirectional, deflation is the back-pressure.** AGENTS.md grows monotonically if facts only flow in; left unchecked it bloats past the context budget it protects. So every session that dispatches `memorize-fire` for new facts ALSO picks a few existing AGENTS.md entries that have become detail-heavy / single-crate / single-platform (the material this policy says belongs in rs-learn) and exfiltrates them: `memorize-fire` the entry's substance to the default namespace, then delete or compress its AGENTS.md paragraph to a one-line pointer in the same commit. Witnessed by both the store gaining the fact (recallable next turn) and the AGENTS.md byte-count dropping. A few entries per run, never a wholesale rewrite; top-level cross-cutting rules stay, everything reachable by `recall` drains. Skipping the drain on a memorize run is the slow-bloat drift this policy exists to prevent.
55
+ **Every memorize run also drains AGENTS.md -- migration is bidirectional, deflation is the back-pressure.** AGENTS.md bloats past the budget it protects if flow is only inward, so every session firing `memorize-fire` for new facts ALSO exfiltrates a few existing detail-heavy/single-crate/single-platform entries: fire the substance to the default namespace, then delete or compress the paragraph to a one-line pointer in the same commit. Witnessed by the store gaining the fact AND the byte-count dropping. A few entries per run, never a wholesale rewrite; top-level rules stay, everything recall-reachable drains.
60
56
 
61
57
  ## Coding Style
62
58
 
63
- **No comments in code.** No inline, block, or JSDoc comments in every possible location, source, generated output, hooks, scripts.
59
+ **No comments in code** -- no inline, block, or JSDoc comments anywhere (source, generated output, hooks, scripts).
64
60
 
65
- **No graphical symbols; convert to industry-standard text on sight.** Decorative glyphs are forbidden in all output and source: arrow glyphs, box and geometric glyphs, stars, filled or hollow dots and bullets, checkmarks and crosses, emojis, and any non-ASCII decorative symbol. The instant one is found anywhere, convert it to its ASCII equivalent in the same turn (arrow glyph to `->`, bullet glyph to `-` or `*`, check/cross to `[x]`/`[ ]` or the words done/todo/pass/fail, status dot to the word it means). This is the tell-tale-AI class: one sighting spawns the full-codebase sweep, never a one-off local edit. Exempt and narrow: functional code operators (`=>`, `??`, `?.`, comparison/math), frozen historical changelog and git-log entries, binary stores, and intentional icon-font or CSS-content product glyphs. `ccsniff --glyph-discipline` flags decorative glyphs written into files post-hoc (run it each audit, like `--git-discipline`/`--search-discipline`).
61
+ **No graphical symbols; convert to industry-standard text on sight.** Decorative glyphs are forbidden in all output and source: arrows, box/geometric glyphs, stars, filled/hollow dots and bullets, checks/crosses, emojis, any non-ASCII decorative symbol. Convert on sight in the same turn (arrow -> `->`, bullet -> `-`/`*`, check/cross -> `[x]`/`[ ]` or done/todo/pass/fail, status dot -> the word). Tell-tale-AI class: one sighting spawns the full-codebase sweep, never a one-off edit. Exempt: functional code operators (`=>`, `??`, `?.`, comparison/math), frozen changelog/git-log entries, binary stores, intentional icon-font/CSS-content product glyphs. `ccsniff --glyph-discipline` flags decorative glyphs post-hoc (run each audit, like `--git-discipline`/`--search-discipline`).
66
62
 
67
- **Skill SKILL.md files:** Strip explanatory prose. Keep ONLY invocation syntax, transition markers (`->`), gate conditions, constraint lists, and code examples showing exact usage.
63
+ **Skill SKILL.md files:** strip explanatory prose; keep ONLY invocation syntax, transition markers (`->`), gate conditions, constraint lists, exact-usage code examples.
68
64
 
69
- **Implicit, not explicit, in skill prose.** Skill files (and prompt-submit.txt) elicit behavior, they do not describe it. Write terse imperative principles whose phrasing triggers the model's already-learned dispositions, not numbered procedures that spell out what to do. Forbidden: "1. agent runs N parallel calls 2. then writes 3. then...", "see paper IV section 2.3", "as documented in docs/skills.html", citations to the site or papers, multi-step recipes. The skill is a prompt, not a manual; if it reads like a manual the behavior gets imitated as a script and breaks at the first edge case. The papers and site are *outputs* of the discipline, not *inputs* to it; never link from a skill into the docs. Cross-cutting rules that need a citation belong in this file (AGENTS.md), not in skills.
65
+ **Implicit, not explicit, in skill prose.** Skill files (and prompt-submit.txt) elicit behavior, they do not describe it: terse imperative principles that trigger already-learned dispositions, not numbered procedures. Forbidden: step-by-step recipes, "see paper section X", citations to the site/papers, multi-step manuals. A skill that reads like a manual gets imitated as a script and breaks at the first edge case. The papers and site are outputs of the discipline, not inputs; never link from a skill into the docs. Cross-cutting rules needing a citation belong here, not in skills.
70
66
 
71
67
  ## Build
72
68
 
73
- There is no build step. The repo root is the published artifact. `npm publish` from root publishes `gm-skill` directly; `package.json` `files:` pins which paths ship.
74
-
75
- `AnEntrypoint/gm-skill` is a back-compat repo mirror that receives only `skills/gm-skill/SKILL.md` per release. The canonical install is `bun x skills add AnEntrypoint/gm`.
76
-
77
- ## the agent is the orchestrator; plugkit is the brain it drives
69
+ No build step; the repo root is the published artifact. `npm publish` from root publishes `gm-skill`; `package.json` `files:` pins the shipped paths. `AnEntrypoint/gm-skill` is a back-compat mirror receiving only `skills/gm-skill/SKILL.md` per release. Canonical install: `bun x skills add AnEntrypoint/gm`.
78
70
 
79
- **The agent orchestrates.** Plugkit is the stateful library the agent drives by dispatching verbs. Plugkit does not act autonomously, does not advance phases in the background, does not validate transitions while the agent waits. Every possible state change is a verb the agent writes into `.gm/exec-spool/in/<verb>/<N>.txt`. If a session shows zero dispatches but the agent narrated a full PLAN->COMPLETE walk, the agent fabricated the walk, plugkit's dispatch ledger is ground truth.
71
+ ## The agent is the orchestrator; plugkit is the brain it drives
80
72
 
81
- The PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE state machine lives natively in rs-plugkit; plugkit owns phase/mutables/memorize/transition-legality *as data + gate checks*, but the agent triggers every operation by dispatching an orchestrator verb -- the harness never reimplements the state machine and never expects plugkit to act without a verb. Plugkit is synchronous from the agent's view; polling the output dir instead of reading the response file is the canonical misuse. File paths + verb enumeration in rs-learn (`recall: rs-plugkit state-machine internals`).
73
+ Plugkit is the stateful library the agent drives by dispatching verbs -- it does not act autonomously, advance phases in the background, or validate transitions while the agent waits. Every state change is a verb the agent writes into `.gm/exec-spool/in/<verb>/<N>.txt`; the dispatch ledger is ground truth, so zero dispatches with a narrated PLAN->COMPLETE walk = a fabricated walk. The PLAN -> EXECUTE -> EMIT -> VERIFY -> COMPLETE state machine lives natively in rs-plugkit (phase/mutables/memorize/transition-legality as data + gate checks), but the agent triggers every operation; plugkit is synchronous from the agent's view, so polling the output dir instead of reading the response file is the canonical misuse. File paths + verb enumeration in rs-learn (`recall: rs-plugkit state-machine internals`).
82
74
 
83
75
  ## gm-skill is the canonical universal harness
84
76
 
85
- `skills/gm-skill/SKILL.md` is the single source of truth for harness behavior. It is the only skill shipped, the legacy 15-platform fanout (gm-cc, gm-gc, gm-oc, gm-codex, gm-kilo, gm-qwen, gm-hermes, gm-thebird, gm-vscode, gm-cursor, gm-zed, gm-jetbrains, gm-copilot-cli, gm-antigravity, gm-windsurf) is retired; those downstream repos are archived. Users install gm-skill directly into whatever harness they use.
77
+ `skills/gm-skill/SKILL.md` is the single source of truth for harness behavior and the only skill shipped; the legacy 15-platform fanout (gm-cc/gm-gc/gm-oc/gm-codex/gm-kilo/gm-qwen/gm-hermes/gm-thebird/gm-vscode/gm-cursor/gm-zed/gm-jetbrains/gm-copilot-cli/gm-antigravity/gm-windsurf) is retired and those repos archived. Users install gm-skill directly into whatever harness they use.
86
78
 
87
79
  ## Tool surface is plugkit-only
88
80
 
89
- Every possible skill's `allowed-tools:` frontmatter is reduced to `Skill, Read, Write`. `Write` is permitted exclusively for spool dispatch (writing into `.gm/exec-spool/in/<lang>/`). Every possible other side effect, code execution, git, browser, recall, memorize, codesearch, routes through the spool and is serviced by plugkit. The harness never reaches around plugkit; if a capability is missing, add it as a plugkit verb, not as a skill-side tool.
81
+ Every skill's `allowed-tools:` is reduced to `Skill, Read, Write` (plus the SKILL.md boot commands `Bash(bun *)`/`Bash(npx *)`); `Write` is permitted exclusively for spool dispatch. Every other side effect -- code execution, git, browser, recall, memorize, codesearch -- routes through the spool and is serviced by plugkit. The harness never reaches around plugkit; a missing capability is a new plugkit verb, not a skill-side tool.
90
82
 
91
83
  ## Core Rules
92
84
 
93
- **Shared memory & search index are tracked, never ignored**: `.gm/rs-learn.db` and `.gm/code-search/` are committed so memory and index state shares across every possible machine, session, and CI run. Never add `.gm/`, `.gm/rs-learn.db`, `.gm/code-search/`, or legacy `.code-search/` to ignore rules; transient `.gm/*` entries are listed one-by-one between the managed markers (parent-re-include caveat). Full entry list + `ensureGitignored` writer mechanics in rs-learn (`recall: gm managed-gitignore mechanics`). Every possible project-local persistent state writes under `.gm/<name>/`, never a top-level dotfile/dotdir.
85
+ **Shared memory & search index are tracked, never ignored**: `.gm/rs-learn.db` and `.gm/code-search/` are committed so state shares across machines, sessions, CI runs. Never add `.gm/`, `.gm/rs-learn.db`, `.gm/code-search/`, or legacy `.code-search/` to ignore rules; transient `.gm/*` entries are listed one-by-one between the managed markers (parent-re-include caveat). Entry list + `ensureGitignored` mechanics in rs-learn (`recall: gm managed-gitignore mechanics`). Project-local persistent state writes under `.gm/<name>/`, never a top-level dotfile/dotdir.
94
86
 
95
- **Disciplines are isolated knowledge stores**: per-project, at `<project>/.gm/disciplines/<name>/{rs-learn.db, code-search/}`. Every possible discipline owns its own rs-learn DB and code-search index. When a `@<name>` sigil is present in the request, isolation is strict, cross-discipline reads are forbidden. Without a sigil, reads (recall/codesearch) fan across `default` plus every possible enabled discipline (one per line in `<project>/.gm/disciplines/enabled.txt`) and merge-rank results with `[discipline:<name>]` prefixes; writes (memorize/ingest/index) without a sigil go to `default` only. Disciplines are tracked in git, never ignored, `ensureGitignored` and any gm-managed gitignore entry must not list `.gm/disciplines` or any subpath. The gm-skill harness and every possible spool verb propagate the `@<name>` sigil verbatim through their dispatch chain.
87
+ **Disciplines are isolated knowledge stores**: per-project at `<project>/.gm/disciplines/<name>/{rs-learn.db, code-search/}`, each owning its own DB + index. A `@<name>` sigil makes isolation strict (cross-discipline reads forbidden). Without a sigil, reads (recall/codesearch) fan across `default` plus every enabled discipline (one per line in `enabled.txt`), merge-ranked with `[discipline:<name>]` prefixes; writes without a sigil go to `default` only. Disciplines are tracked, never ignored (`ensureGitignored` must not list `.gm/disciplines` or any subpath). The harness and every spool verb propagate the `@<name>` sigil verbatim.
96
88
 
97
- **Nothing fake in source the user runs**: every possible stub, mock, placeholder return, fixture-only path, demo-mode short-circuit, and "TODO: implement" body is forbidden in shipped code. Scaffolds and shims are permitted only when they delegate to real behavior (real upstream API, real subprocess, real disk). Before adding a shim, check whether a published library or tool already provides that surface, maintaining a local reimplementation of an upstream solution drifts and ages. Detection is behavioral, not by keyword: code that always succeeds, returns the same value regardless of input, or short-circuits a real call to satisfy a type signature is a stub. Acceptance is real input through real code into real output, witnessed; every possible degradation from that leaves the mutable open.
89
+ **Nothing fake in source the user runs**: every stub, mock, placeholder return, fixture-only path, demo-mode short-circuit, and "TODO: implement" body is forbidden in shipped code. Scaffolds/shims are permitted only when they delegate to real behavior (real upstream API, subprocess, disk); before adding a shim, check whether a published library already provides the surface. Detection is behavioral: code that always succeeds, returns the same value regardless of input, or short-circuits a real call to satisfy a type signature is a stub. Acceptance is real input through real code into real output, witnessed.
98
90
 
99
- **Spool dispatch gates**: `lib/spool-dispatch.js::checkDispatchGates(sessionId, operation)` reads `.gm/` marker files and returns `{allowed, reason}`; denials surface the reason to the model as imperative instruction, never mutate args. Marker list + per-marker semantics in rs-learn (`recall: spool dispatch gates marker files`).
91
+ **Spool dispatch gates**: `lib/spool-dispatch.js::checkDispatchGates(sessionId, operation)` reads `.gm/` marker files and returns `{allowed, reason}`; denials surface the reason as imperative instruction, never mutate args. Marker semantics in rs-learn (`recall: spool dispatch gates marker files`).
100
92
 
101
- **Done is plugkit's pronouncement, never the agent's claim**: the chain is COMPLETE only when `transition to=COMPLETE` returns COMPLETE phase and plugkit's on-disk state file reflects it. "I think we're done" is not done. "The user seems satisfied" is not done. The COMPLETE gate (gates.rs) is the single arbiter, it refuses on PRD-open, mutables-unresolved, dirty worktree, or missing residual-scan marker. The agent's job is to drive the chain into a state where the gate allows, then dispatch the verb, then read the response. Every possible alternative is narration.
93
+ **Done is plugkit's pronouncement, never the agent's claim**: the chain is COMPLETE only when `transition to=COMPLETE` returns COMPLETE phase and the on-disk state file reflects it. The COMPLETE gate (gates.rs) is the single arbiter -- it refuses on PRD-open, mutables-unresolved, dirty worktree, or missing residual-scan marker. The agent drives the chain into a gate-allowing state, dispatches the verb, reads the response; every alternative is narration.
102
94
 
103
- **Every residual is triaged this turn, never named-and-deferred**: every entry in `git status --porcelain` at residual-scan or COMPLETE-attempt is the agent's responsibility to triage now. Triage = decide one of (a) commit (real session work or real upstream artifact landed in this tree), (b) add to the managed gitignore block (transient runtime emission, e.g., `.gm/witness/`, `.gm/exec-spool/.*-stale.json`), (c) revert (accidental or stale junk). The label "pre-existing residual" is NOT a stop excuse, it is the *outcome* of triage decision (a) when work is real, or (c) when junk. Name-and-stop with `blockedBy: external` is admissible *only* when triage requires external authority that this session cannot reach (another team's repo, hardware credential, owner-only decision visible to no one in-process). For local-tree residuals the agent always has authority and triages this turn; declaring "pre-existing, can't touch" on local files is the canonical drift mechanism that wedges the chain at VERIFY. Disciplines (`.gm/disciplines/`) are tracked, never ignored, new memorize-fire mem-*.json files are committed, not gitignored. The managed gitignore block (between `# >>> plugkit managed` markers) carries only runtime artifacts that have no future read value (witness JSON, transient staleness markers, lock files).
95
+ **Every residual is triaged this turn, never named-and-deferred**: every `git status --porcelain` entry at residual-scan or COMPLETE-attempt is triaged now -- (a) commit (real session/upstream work), (b) add to the managed gitignore block (transient runtime emission like `.gm/witness/`, `.gm/exec-spool/.*-stale.json`), or (c) revert (junk). "Pre-existing residual" is the outcome of triage (a)/(c), never a stop excuse. `blockedBy: external` is admissible only when triage needs authority this session cannot reach; for local-tree files the agent always has authority. Disciplines are tracked; new memorize-fire `mem-*.json` are committed. The managed block (between `# >>> plugkit managed` markers) carries only runtime artifacts with no future read value.
104
96
 
105
- **"Every possible" is the load-bearing test, applied to every noun the request names**: PLAN-phase PRD construction is exhaustive, not minimal. The phrase "every possible" is how the agent thickens the cover, every possible task, every possible validation, every possible mutable, every possible corner case, every possible caveat, every possible failure mode, every possible interaction, every possible empty/overflow/reentry state, every possible degenerate input, each application of the phrase produces PRD rows. A non-trivial request that yields a single-digit PRD has not finished enumerating; the closure is still in the agent's head, not in plugkit's store, and the chain will converge on a thin slice that leaves silent residuals. After the first PRD pass, the existing list becomes input to a second transform, for each row, the agent asks what every possible corner case looks like, and writes those as additional rows. The expansion is closed when applying "every possible" to the current list yields nothing new, not when the agent feels done. Validations, edge cases, and anticipated mutables are first-class PRD rows, never implicit. Long-horizon requests routinely produce PRDs in the high tens or hundreds; the row count is the resolution of the cover, and resolution is what the user asked for when they handed over a long-horizon prompt. Sparse PRDs under-specify the closure and orphan the work; dense PRDs make completion observable.
97
+ **"Every possible" is the load-bearing test, applied to every noun the request names**: PLAN-phase PRD construction is exhaustive, not minimal -- "every possible" task/validation/mutable/corner-case/caveat/failure-mode/interaction/empty-overflow-reentry/degenerate-input produces rows. A non-trivial request yielding a single-digit PRD has not finished enumerating. After the first pass, the list feeds a second transform: for each row, what every possible corner case looks like becomes more rows; closed when applying "every possible" yields nothing new, not when the agent feels done. Validations, edge cases, anticipated mutables are first-class rows. Long-horizon requests routinely produce high-tens-to-hundreds; the row count is the resolution of the cover, which is what the user asked for. Sparse PRDs orphan the work; dense PRDs make completion observable.
106
98
 
107
- **Every possible aspect that can be checked for jank is a PRD row; the architecture is pliable**: at PLAN, for every surface the user's prompt concerns, the agent adds to the PRD a complete enumeration of every possible aspect that can be checked for `jank` -- every immaturity, every unfinished edge, every half-wired path -- across gui, ux, ui, client state, server state, the client/server state boundary, and any other surface the request reaches. `jank` is the load-bearing word: the agent hunts the rough/unpolished/almost-done, not only outright bugs. Each aspect to improve or validate is its own row, including a profiling row and a security row per surface. The sweep is scoped to the prompt's concern and its reachable closure, not an unbounded repo audit, but exhaustive within it. Every issue found along the way opens its own debug-and-repair plan spooled to the PRD the same turn, never inline-and-forgotten; every outstanding quick improvement is spooled too. The architecture is `pliable`: every possible architectural change that clearly improves it or reduces code-maintenance burden is a spooled PRD plan; replacing bespoke code with native functionality or a very-popular well-maintained library is encouraged ONLY when it reduces the codebase (net-smaller maintained surface) -- a heavy dependency added to delete a few lines net-grows maintenance and is the guarded failure mode. Fan-out is the spool-native shape (parallel `prd-add`/`codesearch`/`exec_js` in one block, plugkit task-spawn), never the platform's native Task/Explore subagent. If any tell-tale AI design element is found along the way (boilerplate flourish, over-hedged comment, generic scaffold name, machine-authored shape), one sighting spawns a full-sweep plan that scans every possible part of the codebase for every other tell-tale AI design element and fixes them across the board -- spooled to the PRD as its own rows (scan, per-cluster findings, fix-and-verify), exhaustive over every possible file, never a one-off local fix, because a tell-tale left standing anywhere is the tell the whole was machine-shaped.
99
+ **Every possible aspect that can be checked for jank is a PRD row; the architecture is pliable**: at PLAN, for every surface the prompt concerns, enumerate every aspect checkable for `jank` -- every immaturity, unfinished edge, half-wired path -- across gui/ux/ui/client-state/server-state/the boundary and any surface reached, each its own row including a profiling row and a security row per surface. `jank` is load-bearing: hunt the rough/unpolished/almost-done, not only outright bugs. Scoped to the prompt's concern + its reachable closure, exhaustive within it. Every issue found opens its own debug-and-repair plan spooled the same turn; every quick improvement is spooled too. `pliable`: every architectural change that clearly improves or reduces maintenance burden is a spooled plan -- replacing bespoke code with native functionality or a popular well-maintained library is encouraged ONLY when it nets a smaller maintained surface (a heavy dep for a few lines is the guarded failure mode). Fan-out is the spool-native shape (parallel `prd-add`/`codesearch`/`exec_js`, plugkit task-spawn), never the platform's Task/Explore subagent. One tell-tale AI design element (boilerplate flourish, over-hedged comment, generic scaffold name, machine-authored shape) spawns a full-codebase sweep plan -- scan/per-cluster/fix-and-verify rows, exhaustive over every file, never a one-off fix.
108
100
 
109
- **Client-side debugging exposes globals and evaluates in-browser, never blind-restarts**: to debug client-side code the agent surfaces the relevant state as a `window.*` global and reads it live via the `browser` verb's `page.evaluate`, running experiments in the browser, rather than blind experimentation + continuous server restarts. A global + one `page.evaluate` reads actual runtime state in a single dispatch where a restart-and-eyeball loop burns a turn and observes nothing. The live page is the debugger; the same `browser` surface that witnesses an edit (Browser Witness) also diagnoses it.
101
+ **Client-side debugging exposes globals and evaluates in-browser, never blind-restarts**: surface the relevant state as a `window.*` global and read it live via the `browser` verb's `page.evaluate`, running experiments in the browser, rather than blind experimentation + server restarts. The live page is the debugger; the same `browser` surface that witnesses an edit also diagnoses it.
110
102
 
111
- **Mundane user-facing output is suppressed or stripped to the bone**: every possible mundane line of user-facing text is suppressed or cut to the bone -- drop articles, drop preamble, drop the play-by-play; boot-probe narration, dispatch echoes, restating prose just read, status recaps do not ship. What survives is substantive: a real finding, a decision and its one-line reason, a blocker, the single-line PRD-read declaration. Terse means fewer/shorter words, NEVER zero tool calls and NEVER silent work -- the turn still ends in the chain-advancing tool call and the agent still states in one terse clause what it is about to do. Cut the mundane, never the chain.
103
+ **Mundane user-facing output is suppressed or stripped to the bone**: drop articles, preamble, play-by-play; boot-probe narration, dispatch echoes, restating prose just read, status recaps do not ship. What survives is substantive: a real finding, a decision + one-line reason, a blocker, the single-line PRD-read declaration. Terse = fewer/shorter words, NEVER zero tool calls and NEVER silent work -- the turn still ends in the chain-advancing tool call.
112
104
 
113
- **Noticing is a planning event, at every phase, in every dispatch window**: any observation the agent makes during the chain, anything that should be done, anything outstanding, anything unfinished, anything improvable, anything misaligned with user preferences, anything the work itself surfaces about what *else* the work touches, is a `prd-add` the agent dispatches this turn. Observations carried in the response body without conversion to a PRD row evaporate when the turn ends; only the PRD store survives. The default response to noticing is to convert. The discovery surface keeps producing new in-scope items as the chain walks PLAN->EXECUTE->EMIT->VERIFY, every phase has its own noticing-to-PRD pressure. Skipping the conversion ("I'll mention it in the summary" / "future work" / "note for later") is the canonical drift mechanism: the observation does not persist, the future turn does not arrive, the residual goes silent. Density grows along the walk, not just at PLAN-time; a chain that exits PLAN with N rows and reaches COMPLETE with N rows has either had no real discoveries (unlikely on a non-trivial task) or has lost them. When the discovery is structural rather than concrete, "the project would benefit from X", "this surface has no test coverage", "the docs do not mention Y", "the agent's preference for Z is being violated here", it is still a PRD row, written with the witness that motivated it. Preference-aware noticing applies the same conversion: when the agent observes that current state diverges from user-stated preferences (dense PRDs, residual-triage, no name-and-defer, every-possible expansion, browser-witness coverage, push-on-clean), each divergence is a `prd-add` describing what the aligned state looks like.
105
+ **Noticing is a planning event, at every phase, in every dispatch window**: any observation -- anything outstanding, unfinished, improvable, misaligned with user preferences, or that the work surfaces about what else it touches -- is a `prd-add` this turn. Observations carried in the response body without conversion evaporate when the turn ends; only the PRD store survives. Density grows along the walk, not just at PLAN-time; a chain exiting PLAN with N rows and reaching COMPLETE with N rows has lost its discoveries. Structural noticing ("no test coverage on X", "docs miss Y", "commit Z violates a rule") and preference-aware noticing (state diverging from dense-PRDs/residual-triage/no-name-and-defer/every-possible-expansion/browser-witness/push-on-clean) each become a row with the witness that motivated it.
114
106
 
115
- **A turn without a tool call is a stop; summary is a stop; both are forbidden until plugkit pronounces COMPLETE**: every programming agent, regardless of vendor, reads only tool calls and their outputs, so an assistant message that ends in prose with no tool call IS the turn ending and the session halts there. This is the mechanical root of the "agent did one small piece and stopped" failure: the model wrote a wrap-up paragraph, emitted no tool call, and the harness read that as done. Deferred intent is the same stop facing forward -- a turn-final sentence naming the next move ("let me read X", "I'll re-dispatch instruction") instead of making it; the chain strands where the prose pointed (one real run halted at EXECUTE with 22 open rows on an announced-but-unmade read). The rule is absolute and tool-agnostic: while the chain is in-flight (phase != COMPLETE OR prd_pending_count > 0) the agent NEVER ends a turn in prose -- every turn terminates in a tool call that advances the chain (`instruction`, the next named verb, `transition`, `phase-status`). Take the move you were about to describe; surface a decision through `AskUserQuestion` or `prd-add`, never a prose-only "confirming direction." The only event that authorizes a prose-only turn is plugkit returning `phase=COMPLETE` AND `prd_pending_count=0`; the agent's own sense that "the work feels done" authorizes nothing. Before any apparent stop or any summary, the agent dispatches `phase-status` and rechecks, a non-terminal phase means the urge to stop was drift, and the recovery is to dispatch `instruction` and continue. This depends on nothing but the verb spool, so it holds on every agent with no hook and no tool-specific feature; any continuation mechanism that relies on a hook or a single tool's behavior is non-portable and must be replaced by this spool-only discipline.
107
+ **A turn without a tool call is a stop; summary is a stop; both are forbidden until plugkit pronounces COMPLETE**: every programming agent reads only tool calls and their outputs, so a prose-only message ends the turn and halts the session -- the mechanical root of "agent did one piece and stopped". Deferred intent is the same stop facing forward (a turn-final sentence naming the next move instead of making it strands the chain where the prose pointed). Absolute and tool-agnostic: while in-flight (phase != COMPLETE OR prd_pending_count > 0) the agent NEVER ends a turn in prose -- every turn ends in a chain-advancing tool call (`instruction`, the next named verb, `transition`, `phase-status`). Surface a decision through `AskUserQuestion` or `prd-add`, never a prose-only "confirming direction." Only `phase=COMPLETE` AND `prd_pending_count=0` authorizes a prose-only turn; the agent's sense that "the work feels done" authorizes nothing. Before any apparent stop, dispatch `phase-status` and recheck. Depends only on the verb spool, so it holds on every agent with no hook.
116
108
 
117
- **Always seek the next state transition**: if the chain is not COMPLETE, there is a next move. Idle mid-chain is a deviation. The agent who finishes a verb and stops without dispatching the next instruction has stopped walking the chain. `phase-status` tells you where you are; `instruction` tells you what's next. There is no "I'll wait for the user" mid-chain, the user authorized closure at request time, not phase-by-phase.
109
+ **Always seek the next state transition**: not-COMPLETE means a next move exists; idle mid-chain is a deviation. `phase-status` tells you where you are, `instruction` what's next. No "I'll wait for the user" mid-chain -- the user authorized closure at request time, not phase-by-phase.
118
110
 
119
- **Return to plugkit on every possible drift**: `instruction` is the recovery primitive. Against every possible stall, gate-denial, unexpected error, or moment of uncertainty about the next step, the response is always to dispatch `instruction` and read the prose, never to improvise. The verb is synchronous, cheap, idempotent; over-dispatching it has no cost, under-dispatching it is the canonical drift mechanism. A session that goes >N tool calls without an instruction dispatch in a non-trivial phase is hallucinating its own chain. Every possible gate denial names the next verb in its `reason` field, the agent reads the field and dispatches the named verb, never argues around the denial.
111
+ **Return to plugkit on every possible drift**: `instruction` is the recovery primitive -- against every stall, gate-denial, error, or uncertainty, dispatch `instruction` and read the prose, never improvise. Synchronous, cheap, idempotent; over-dispatching has no cost, under-dispatching is the canonical drift mechanism. Every gate denial names the next verb in its `reason` field; read it and dispatch that verb, never argue around the denial.
120
112
 
121
- **Push is part of COMPLETE, never optional, never asked**: every possible session that mutates tracked files ends with commit + push to origin. Asking the user "do you want me to push?" is a deviation, the push IS the validation dispatch (`verify.rs`: "The push you make IS the validation dispatch"). The chain is not COMPLETE until the remote reflects HEAD. ccsniff `--git-discipline` and a pending `deviation.complete-without-push` event flag sessions that close without pushing.
113
+ **Push is part of COMPLETE, never optional, never asked**: every session that mutates tracked files ends with commit + push to origin. Asking "do you want me to push?" is a deviation -- the push IS the validation dispatch (`verify.rs`). The chain is not COMPLETE until the remote reflects HEAD. ccsniff `--git-discipline` and `deviation.complete-without-push` flag sessions closing without pushing.
122
114
 
123
- **Direct-push to main, never a branch, never a PR**: every possible gm/rs-* change commits straight to `main` and pushes; the git verbs (`git_finalize`/`git_push`) already target `main`, and the cascade ships from `main`. Creating a feature branch, opening a pull request, or forking is a deviation -- the workflow has no review-gate step, the push IS the validation dispatch, and a PR left open is unshipped work the cascade never sees. For a sibling repo with an existing open PR, merge it to `main` and push, then delete the branch; never leave a branch-and-PR pending. The only admissible remote refs are `main` and `gh-pages`. This holds for sibling repos reached via `git_push {repo, branch:"main"}` exactly as for gm.
115
+ **Direct-push to main, never a branch, never a PR**: every gm/rs-* change commits straight to `main` and pushes; the git verbs (`git_finalize`/`git_push`) already target `main`, and the cascade ships from `main`. A feature branch, PR, or fork is a deviation -- the workflow has no review-gate, the push IS the validation dispatch. For a sibling repo with an open PR, merge to `main`, push, delete the branch. The only admissible remote refs are `main` and `gh-pages`; holds for siblings via `git_push {repo, branch:"main"}` as for gm.
124
116
 
125
- **Push requires clean worktree witnessed in its own tool-use event**: `git push` is admissible only when `git status --porcelain` returns empty, and the porcelain probe must be its own Bash tool-use event before the push, never a `&&`-chained shell command within the push event (`add && commit && push` in one Bash call = one event with no porcelain witness). A push from a dirty tree orphans the unstaged delta and breaks the next session's first read. Enforcement-location enumeration (spool-dispatch.js gate, gates.rs COMPLETE branch, verify.rs/update_docs.rs prose, residual.rs dirty-skip, ccsniff --git-discipline) in rs-learn (`recall: push clean worktree enforcement locations`).
117
+ **Push requires clean worktree witnessed in its own tool-use event**: `git push` is admissible only when `git status --porcelain` is empty, and the porcelain probe is its own Bash tool-use event before the push, never `&&`-chained (`add && commit && push` in one call = one event with no witness). A dirty-tree push orphans the unstaged delta. The `git_push`/`git_finalize` verbs gate this internally and are preferred. Enforcement-location enumeration in rs-learn (`recall: push clean worktree enforcement locations`).
126
118
 
127
- **memorize dispatch manages CLAUDE.md / AGENTS.md**: Do not inline-edit. Dispatch via spool: write `.gm/exec-spool/in/memorize/<N>.txt` with the fact text; the wasm orchestrator embeds and persists it. Classifier rejects changelog-shaped facts from AGENTS.md ingestion (rs-learn store still accepts them).
119
+ **AGENTS.md / CLAUDE.md are inline-edited AND dual-written to the store**: edit AGENTS.md/CLAUDE.md inline for structural rules (the top of the preserved hierarchy, the only doc surviving context summarization), AND in the same session dispatch `memorize-fire` (`.gm/exec-spool/in/memorize-fire/<N>.txt`, raw text or `{text, namespace?}`) for the same rule so `recall`/`auto_recall` surface it on future turns. The two are complementary, not alternatives. Never pass `namespace:"AGENTS.md"`; load-bearing rules go to the default namespace. The classifier rejects changelog-shaped facts from AGENTS.md ingestion (the rs-learn store still accepts them).
128
120
 
129
- **Behavioral discipline lives in plugkit's `instruction` verb**: dispatch `instruction` for the live phase-specific prose (Three-Layer Admission Filter, maturity-first emit, closure anti-shapes, code invariants); do not duplicate it here. Full enumeration in rs-learn (`recall: instruction-verb behavioral discipline invariants`).
121
+ **Behavioral discipline lives in plugkit's `instruction` verb**: dispatch `instruction` for the live phase-specific prose (Three-Layer Admission Filter, maturity-first emit, closure anti-shapes, code invariants); do not duplicate it here. Enumeration in rs-learn (`recall: instruction-verb behavioral discipline invariants`).
130
122
 
131
- **The agent IS the LLM rs-learn calls; every judgment rs-learn needs is the agent deciding on the spot**: rs-learn never reaches out to a separate judge model for a quality score, relevance call, prune decision, route outcome, or loss signal -- plugkit IS the harness and the agent IS the model it dispatched, so each is a decision the agent makes inline and reports through the spool. Encourage heavy `recall`+`learn` so judgments are grounded, not guessed. Per-core internals (MicroLoRA self-report logit, FastGRNN router, deep-core record_loss, attention nudge_relation, memorize-prune) in rs-learn (`recall: rs-learn self-report core internals`).
123
+ **The agent IS the LLM rs-learn calls**: rs-learn never reaches a separate judge model for a quality score, relevance call, prune decision, route outcome, or loss signal -- plugkit IS the harness and the agent IS the model, so each is an inline decision reported through the spool. Heavy `recall`+`learn` grounds the judgments. Per-core internals (MicroLoRA self-report logit, FastGRNN router, deep-core record_loss, attention nudge_relation, memorize-prune) in rs-learn (`recall: rs-learn self-report core internals`).
132
124
 
133
- **host_exec_js is synchronous**: pass a real per-call `timeoutMs` (zero/missing is a hard error); long subprocesses block the watcher; no async/background exec under wasm. Mechanism detail in rs-learn (`recall: host_exec_js synchronous`).
125
+ **host_exec_js is synchronous**: pass a real per-call `timeoutMs` (zero/missing is a hard error); long subprocesses block the watcher; no async/background exec under wasm. Detail in rs-learn (`recall: host_exec_js synchronous`).
134
126
 
135
- **Sync-before-emit (codeinsight + search)**: codeinsight/search output must come from a freshly-synced index this invocation (cache serves only on digest match); unverified-index emit = stale ground truth. Digest/cache mechanics in rs-learn (`recall: sync-before-emit codeinsight search`).
127
+ **Sync-before-emit (codeinsight + search)**: codeinsight/search output must come from a freshly-synced index this invocation (cache serves only on digest match); unverified-index emit = stale ground truth. Mechanics in rs-learn (`recall: sync-before-emit codeinsight search`).
136
128
 
137
- **Auto-recall on turn entry**: the `instruction` verb attaches an `auto_recall` pack to its response on the first dispatch after a >30s idle gap or session-start; orientation comes through that pack, not legacy hooks. Mechanism detail in rs-learn (`recall: auto-recall on turn entry`).
129
+ **Auto-recall on turn entry**: the `instruction` verb attaches an `auto_recall` pack on the first dispatch after a >30s idle gap or session-start; orientation comes through that pack, not legacy hooks. Detail in rs-learn (`recall: auto-recall on turn entry`).
138
130
 
139
131
  **Skill SKILL.md frontmatter `allowed-tools:` is harness-enforced**: a skill must list `Skill` (and `Read`/`Write`, Write only for spool dispatch) or it loses downstream-skill invocation that turn. Detail in rs-learn (`recall: SKILL.md frontmatter allowed-tools`).
140
132
 
141
- **rs-learn observability**: every learning-pipeline state change emits a structured `evt:{event,sess,ts,...}` line into `.gm/exec-spool/.watcher.log` + gm-log; recall replies carry `mode`/`namespace`/`derived_query`/per-hit `score`; gmsniff/ccsniff expose the taxonomy. Learning quality is observable, not a black box. Full event taxonomy + flag list in rs-learn (`recall: rs-learn observability taxonomy`).
133
+ **rs-learn observability**: every learning-pipeline state change emits a structured `evt:{event,sess,ts,...}` line into `.gm/exec-spool/.watcher.log` + gm-log; recall replies carry `mode`/`namespace`/`derived_query`/per-hit `score`; gmsniff/ccsniff expose the taxonomy. Taxonomy + flag list in rs-learn (`recall: rs-learn observability taxonomy`).
142
134
 
143
- **Bootstrap contract (skill-init + SKILL.md auto-refresh + project wiring)**: `bootstrapPlugkit`/`ensureReady` initialize wasm hook-free (failures non-fatal), sha256-rewrite stale installed SKILL.md, and seed per-project `CLAUDE.md` (`@AGENTS.md`) + `.gm/next-step.md` the wiring must live in `gm-plugkit/bootstrap.js::ensureReady` (the consumer-project watcher boot path), not only repo-root `bin`/`lib`. Detail in rs-learn (`recall: skill-initiated bootstrap contract`, `recall: SKILL.md auto-refresh`).
135
+ **Bootstrap contract (skill-init + SKILL.md auto-refresh + project wiring)**: `bootstrapPlugkit`/`ensureReady` initialize wasm hook-free (failures non-fatal), sha256-rewrite stale installed SKILL.md, and seed per-project `CLAUDE.md` (`@AGENTS.md`) + `.gm/next-step.md`; the wiring lives in `gm-plugkit/bootstrap.js::ensureReady` (the consumer-project watcher boot path), not only repo-root `bin`/`lib`. Detail in rs-learn (`recall: skill-initiated bootstrap contract`, `recall: SKILL.md auto-refresh`).
144
136
 
145
137
  ## Cascade pipeline
146
138
 
147
- Push to any rs-* sibling triggers `cascade.yml` -> rs-plugkit `release.yml` -> single `plugkit.wasm` (npm `plugkit-wasm` + `plugkit-bin` Releases) -> auto-bump `gm.json::plugkitVersion` -> `publish.yml` ships gm-skill + gm-plugkit + the SKILL.md mirror. Full step sequence + PUBLISHER_TOKEN setup in rs-learn (`recall: cascade pipeline`).
139
+ Push to any rs-* sibling triggers `cascade.yml` -> rs-plugkit `release.yml` -> single `plugkit.wasm` (npm `plugkit-wasm` + `plugkit-bin` Releases) -> auto-bump `gm.json::plugkitVersion` -> `publish.yml` ships gm-skill + gm-plugkit + the SKILL.md mirror. Step sequence + PUBLISHER_TOKEN setup in rs-learn (`recall: cascade pipeline`).
148
140
 
149
- Three npm packages publish from this repo: `gm-skill` (the skill harness), `gm-plugkit` (bootstrap + watcher), `plugkit-wasm` (wasm binary). publish.yml + the rs-plugkit cascade ships all three on every version-bump commit. The legacy 15 downstream repos are archived on GitHub, no further releases, no orphan-commit publish step.
141
+ Three npm packages publish from this repo: `gm-skill` (harness), `gm-plugkit` (bootstrap + watcher), `plugkit-wasm` (wasm binary) -- all shipped on every version-bump commit. The legacy 15 downstream repos are archived (no further releases).
150
142
 
151
- **Repos involved (push to any triggers cascade):** `AnEntrypoint/{rs-exec, rs-codeinsight, rs-search, rs-plugkit, rs-learn, gm}` rs-plugkit Cargo.toml is the version source-of-truth, gm.json holds plugkitVersion. Per-repo roles in rs-learn (`recall: cascade repos involved roles`).
143
+ **Repos involved (push to any triggers cascade):** `AnEntrypoint/{rs-exec, rs-codeinsight, rs-search, rs-plugkit, rs-learn, gm}` -- rs-plugkit Cargo.toml is the version source-of-truth, gm.json holds plugkitVersion. Per-repo roles in rs-learn (`recall: cascade repos involved roles`).
152
144
 
153
- **To update every possible thing**: push to the relevant repo. No manual version bumps, no local cargo builds. Never run `cargo update` or `cargo build` locally, push and let CI build.
145
+ **To update every possible thing**: push to the relevant repo. No manual version bumps, no local cargo builds -- never run `cargo update`/`cargo build` locally, push and let CI build.
154
146
 
155
- **Timeout enforcement**: every possible `exec_js` dispatch carries a positive `timeoutMs`. The host treats missing or zero as a hard error.
147
+ **Timeout enforcement**: every `exec_js` dispatch carries a positive `timeoutMs`; the host treats missing or zero as a hard error.
156
148
 
157
149
  ## Spool-dispatch architecture replaces hooks
158
150
 
159
- Orchestration state is tracked via `.gm/` marker files, not hook events; the CLI layer calls `checkDispatchGates()` before tool execution to gate Write/Edit/git. Marker set (`prd.yml, mutables.yml, needs-gm, gm-fired-<sessionId>, residual-check-fired`), per-marker semantics, and the SpoolDispatcher CLI mechanism live in rs-learn (`recall: gate enforcement layer`, `recall: spool dispatch gates marker files`).
151
+ Orchestration state is tracked via `.gm/` marker files, not hook events; the CLI layer calls `checkDispatchGates()` before tool execution to gate Write/Edit/git. Marker set (`prd.yml, mutables.yml, needs-gm, gm-fired-<sessionId>, residual-check-fired`) + SpoolDispatcher mechanism in rs-learn (`recall: gate enforcement layer`, `recall: spool dispatch gates marker files`).
160
152
 
161
- **gm-skill tool-use sequencing**: Invoking `Skill(skill="gm-skill")` writes `.gm/gm-fired-<sessionId>` to clear the needs-gm gate. The marker is cleared at turn start to reset the gate. There is one shipped skill; no subagent variant exists.
153
+ **gm-skill tool-use sequencing**: `Skill(skill="gm-skill")` writes `.gm/gm-fired-<sessionId>` to clear the needs-gm gate (cleared at turn start to reset it). One shipped skill, no subagent variant.
162
154
 
163
- **The skill is the driver, not a post-hoc witness**: when a request carries the standing instruction to use gm-skill (every `/loop` fire, any prompt naming `/gm-skill`), the FIRST working action of the session is `Skill(skill="gm-skill")`, and the skill prose then drives the chain from PLAN through COMPLETE. Dispatching the spool verbs (`instruction`, `transition`, `prd-add`, `prd-resolve`, `memorize-fire`, `residual-scan`, `phase-status`) directly without first entering the skill executes the work outside the skill the user asked to drive it, the spool verbs are the skill's mechanism, not a substitute for invoking it. Entering the skill only at the end to confirm terminal state does NOT satisfy the instruction: the condition is that the skill drives the planned work from inception, not that it witnesses retroactive completion. The boot probe (`cat .gm/exec-spool/.status.json` ...) is still prescribed by the skill itself and may precede the invocation; everything that mutates state or advances the chain happens inside the skill-driven session.
155
+ **The skill is the driver, not a post-hoc witness**: when a request carries the standing instruction to use gm-skill (every `/loop` fire, any prompt naming `/gm-skill`), the FIRST working action is `Skill(skill="gm-skill")`, and the skill prose drives the chain PLAN->COMPLETE. Dispatching spool verbs directly without first entering the skill executes the work outside the skill the user asked to drive it; entering only at the end to confirm terminal state does NOT satisfy the instruction. The boot probe (`cat .gm/exec-spool/.status.json` ...) is prescribed by the skill and may precede invocation; everything that mutates state happens inside the skill-driven session.
164
156
 
165
- **Dead-watcher recovery uses `bun x gm-plugkit@latest spool`, never direct-node boot** (mechanism + wrapper-deploy verification in rs-learn: `recall: dead-watcher recovery bun x not direct-node`).
157
+ **Dead-watcher recovery uses `bun x gm-plugkit@latest spool`, never direct-node boot** (mechanism in rs-learn: `recall: dead-watcher recovery bun x not direct-node`).
166
158
 
167
- **The first verb after a genuine multi-minute IDLE is `instruction`, to reset the long-gap clock** (mechanism in rs-learn: `recall: first verb after multi-minute wait instruction long-gap`). The gate fires on genuine idle only -- both >300s since the last instruction AND >300s since the previous dispatch of any verb -- so active back-to-back work verbs (a browser-heavy debugging stretch, a fan-out of exec/codesearch) keep the chain alive without an interleaved `instruction`; you do not inject defensive instruction dispatches between active work. A true wait (version download, overnight, long external CI watch with no dispatches) still trips it, and there the first verb back is `instruction`. When the wait is self-inflicted and predictable -- a blocking `TaskOutput`/`gh run watch` on a multi-minute workflow or CI run you yourself launched -- dispatch `instruction` immediately BEFORE entering the wait, not only after: prevention resets the clock so a sub-300s tail never trips the gate, where recovery-after only cleans up a deviation that already fired.
159
+ **The first verb after a genuine multi-minute IDLE is `instruction`, to reset the long-gap clock**: the gate fires on genuine idle only (>300s since the last instruction AND >300s since any verb), so active back-to-back work verbs keep the chain alive without an interleaved `instruction` -- do not inject defensive instruction dispatches between active work. A true wait (version download, overnight, long external CI watch) trips it, and the first verb back is `instruction`. When the wait is self-inflicted and predictable (a blocking `TaskOutput`/`gh run watch`), dispatch `instruction` immediately BEFORE entering the wait, not only after. Mechanism in rs-learn (`recall: first verb after multi-minute wait instruction long-gap`).
168
160
 
169
- **A stop-hook firing on a terminal chain does not authorize re-polling**: when a stop-hook or unsatisfiable condition fires while the chain is already at `phase=COMPLETE` AND `prd_pending_count=0`, re-dispatching `instruction` or `phase-status` to "re-confirm" terminality is itself a deviation, it emits `deviation.complete-chain-poll` (`instructions/mod.rs`) and marks the agent as polling a closed chain. COMPLETE already authorizes the prose-only turn; the hook cannot be satisfied by more poll dispatches over elapsed work, and re-running already-committed work to manufacture skill-driven activity is the fabrication `Nothing Fake` forbids. Two admissible responses only: (a) a prose-only turn (the COMPLETE pronouncement is in hand), or (b) genuinely new planned work opened with a FRESH `{"prompt":...}` body, which resets phase to PLAN and is driven through the skill from inception. Repeatedly answering the same already-acknowledged hook is a loop; state the terminal facts once and stop, or open new work.
161
+ **A stop-hook firing on a terminal chain does not authorize re-polling**: when a stop-hook fires while already at `phase=COMPLETE` AND `prd_pending_count=0`, re-dispatching `instruction`/`phase-status` to "re-confirm" is a deviation (`deviation.complete-chain-poll`, `instructions/mod.rs`). Two admissible responses: (a) a prose-only turn (COMPLETE is in hand), or (b) genuinely new planned work opened with a FRESH `{"prompt":...}` body (resets phase to PLAN, driven through the skill). Repeatedly answering the same hook is a loop; state the terminal facts once and stop, or open new work.
170
162
 
171
163
  **Session lifecycle**: background tasks + browser sessions persist across turn-stops; cleanup fires only on real-exit reasons; residual-scan fires when PRD empty AND no open browser sessions AND no running tasks. Detail in rs-learn (`recall: session lifecycle killSessionTasks residual-scan`).
172
164
 
173
165
  ## Spool observability surface
174
166
 
175
- One-shot system-state probe: dispatch `plugkit health` via the file-spool before assuming any component is broken. Three runtime diagnostic files at `.gm/exec-spool/` root (`.status.json`, `.last-session-start.json`, `.bootstrap-error.json`) are readable directly via Read (runtime-data exception). Return-field enumeration + per-file semantics in rs-learn (`recall: plugkit health verb fields`).
167
+ One-shot system-state probe: dispatch `plugkit health` via the file-spool before assuming any component is broken. Three runtime diagnostic files at `.gm/exec-spool/` root (`.status.json`, `.last-session-start.json`, `.bootstrap-error.json`) are readable directly via Read (runtime-data exception). Field enumeration in rs-learn (`recall: plugkit health verb fields`).
176
168
 
177
169
  ## Site Build & Documentation
178
170
 
179
- **Site build is single-surface detail in rs-learn** (`recall: gm site build details`): navigation.yaml grouped-entry format + flatspace `C.Topbar` dropdowns, the `site/theme.mjs`+`home.yaml` landing renderer (never `site/index.html`), in-page topbar sync, Mermaid render, generated `docs/styles.css`, and the `docs/made-with.html` showcase.
171
+ Site build is single-surface detail in rs-learn (`recall: gm site build details`): navigation.yaml grouped-entry format + flatspace `C.Topbar` dropdowns, the `site/theme.mjs`+`home.yaml` landing renderer (never `site/index.html`), in-page topbar sync, Mermaid render, generated `docs/styles.css`, and the `docs/made-with.html` showcase.
180
172
 
181
173
 
182
174
  @.gm/next-step.md
@@ -1,50 +1,43 @@
1
1
  # BROWSER
2
2
 
3
- ## Hard Rule: Browser Witness Mandate (paper §23)
3
+ ## Hard Rule: Browser Witness Mandate (paper section 23)
4
4
 
5
- **Every possible edit to code that runs in a browser requires a live `browser` dispatch in the same turn as the edit.** Client-side surfaces `.html`, `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, `.svelte`, `.mjs`, `.css`, web components, service workers, every possible asset loaded by a `<script>` tag, every possible path reached by `import` from a browser-side entry must be witnessed by a live `page.evaluate` of the specific invariant the edit establishes. A passing node test, a passing build, a `curl` of the served HTML, a static-analysis pass every possible one of these is non-substitutive: they witness server delivery, not browser behavior. The witness IS the proof; the prose is not.
5
+ **Every edit to code that runs in a browser requires a live `browser` dispatch in the same turn as the edit.** Client-side surfaces -- `.html`, `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, `.svelte`, `.mjs`, `.css`, web components, service workers, every asset loaded by `<script>`, every path reached by `import` from a browser-side entry -- must be witnessed by a live `page.evaluate` of the specific invariant the edit establishes. A passing node test, build, `curl` of the HTML, or static-analysis pass witnesses server delivery, not browser behavior, and is non-substitutive. The witness IS the proof; prose is not.
6
6
 
7
- Protocol (paper §23): (1) boot the real surface server up, page reachable, HTTP 200 witnessed; (2) `browser` dispatch navigate poll for the global the change affects; (3) `page.evaluate` asserting the specific invariant, capturing the witnessed values into `stdout`; (4) variance fix at root cause, re-witness (Fix on Sight). Never advance on unwitnessed client behavior. Never queue browser validation for "later" the same turn that edited every possible client-side file dispatches the browser verb that validates each one; emit-without-witness is forced closure.
7
+ Protocol: (1) boot the real surface -- server up, page reachable, HTTP 200 witnessed; (2) `browser` dispatch -> navigate -> poll for the global the change affects; (3) `page.evaluate` asserting the invariant, capturing witnessed values into `stdout`; (4) variance -> fix at root cause, re-witness. Never advance on unwitnessed client behavior, never queue validation for "later" -- the same turn that edits a client-side file dispatches the browser verb validating it.
8
8
 
9
- The rule fires across phases:
10
- - **EXECUTE**: edit a client-side file → dispatch `browser` in the same turn against the live page asserting the invariant the edit establishes
11
- - **EMIT**: post-emit re-witness — the page still passes the invariant after the full diff lands
12
- - **VERIFY**: final gate — `browser-witness-hash-mismatch` deviation fires if any file you witnessed earlier has changed without re-witnessing
9
+ Fires across phases: **EXECUTE** edit -> same-turn browser dispatch asserting the invariant; **EMIT** post-emit re-witness (page still passes after the full diff); **VERIFY** final gate -- `deviation.browser-witness-hash-mismatch` fires if a witnessed file changed without re-witnessing. Pure-prose static-document edits (no JS, no CSS-driven behavior, no DOM mutation) are the ONLY exempt category, and the exemption must be named explicitly in the response so the skip is auditable. Silent skip on actual behavior change is forced closure.
13
10
 
14
- Pure-prose static-document edits (no JS, no CSS-driven behavior, no DOM mutation) are the ONLY exempt category and the exemption must be named explicitly in the response so the skip is auditable. Silent skip on actual behavior change is forced closure.
11
+ YOU drive the browser through the spool: plugkit holds the Chromium handle, per-project profile, and session table; you advance by writing `.gm/exec-spool/in/browser/<N>.txt` and reading `out/<N>.json`. There is no library import, no puppeteer/playwright/CDP handle that shortcuts this. The verb is the surface; every other reach is fabrication.
15
12
 
16
- YOU drive the browser through the spool. Plugkit holds the Chromium handle, the per-project profile, the session table; you advance the work by writing `.gm/exec-spool/in/browser/<N>.txt` and reading `out/<N>.json`. There is no library import that shortcuts this. There is no puppeteer/playwright/CDP handle you can hold. The verb is the surface; every possible other reach is fabrication.
13
+ ## Body shapes
17
14
 
18
- The body is a string. Five shapes, nothing else:
15
+ The body is a string, five shapes only:
19
16
 
20
17
  ```
21
18
  session new
22
19
  session list
23
- session kill <id>
20
+ session close <id>
24
21
  <arbitrary JS expression evaluated in page context>
25
22
  timeout=<ms>\n<expression>
26
23
  ```
27
24
 
28
- A bare expression with no live session opens one and evaluates against `about:blank`. A bare expression with a live session reuses it. `session new` returns the id you carry on subsequent dispatches; you keep it in your turn and refer to it by writing `session=<id>\n<expr>` when more than one is open.
29
-
30
- Default per-evaluation timeout is 14000ms. Operations that legitimately exceed this (long page loads, multi-step navigation, slow remote APIs) prefix `timeout=<ms>\n` with the desired millisecond cap; the wrapper clamps to 50000ms maximum. The response includes `timeout_ms_used` so you witness which budget actually applied. `browser.runner-timeout` event fires when the runner hits the cap — read your `stderr`, narrow the operation, or raise timeout; do not retry blind at the same budget.
25
+ A bare expression with no live session opens one against `about:blank`; with a live session it reuses it. `session new` returns the id you carry; with more than one open, target it via `session=<id>\n<expr>`. (`session close` and `session kill` are aliases.) Default per-eval timeout 14000ms; operations that legitimately exceed it prefix `timeout=<ms>\n` (wrapper clamps to 50000ms). The response carries `timeout_ms_used`; `browser.runner-timeout` fires at the cap -- read `stderr`, narrow or raise, never retry blind at the same budget.
31
26
 
32
27
  ## Envelope
33
28
 
34
- You read `{ok, stdout, stderr, exit_code, session_id?}`. `stdout` is the stringified evaluation result. `stderr` carries page errors and launch diagnostics. `exit_code` non-zero = the dispatch you fired did not land; you read `stderr` and re-dispatch, you do not retry blind.
29
+ `{ok, stdout, stderr, exit_code, session_id?}`. `stdout` = stringified eval result; `stderr` = page errors + launch diagnostics; `exit_code` non-zero = the dispatch did not land -- read `stderr` and re-dispatch, never blind.
35
30
 
36
31
  ## Headed by default
37
32
 
38
- The window opens on the user's screen. That is the witness — you launched, they saw the tab, the DOM mutated visibly. `GM_BROWSER_HEADLESS=1` opts into headless; absent that env, a session with no visible window is a launch you did not actually make. Do not assume headless. Do not request headless to "be quiet". The flash IS the proof.
33
+ The window opens on the user's screen -- that IS the witness. `GM_BROWSER_HEADLESS=1` opts into headless; absent it, a session with no visible window is a launch you did not make. Do not assume or request headless to "be quiet"; the flash is the proof.
39
34
 
40
35
  ## Profile
41
36
 
42
- `session new` (or a bare expression with no live session) spawns a locally-profiled Chromium at `<cwd>/.gm/browser-profile/` and the runner attaches via `--direct <wsEndpoint>`. Cookies, storage, extensions persist across every possible session, turn, and run. A second concurrent launch contends the SingletonLock; the watcher reuses the live CDP rather than re-launching. The runner's own extension-attach mode (the "Waiting for extension to connect" message) is never the default and is never what you want if you see it in your `stderr`, the host failed to spawn the local Chromium and you dispatch `instruction` for the recovery prose, not retry blind.
37
+ `session new` (or a bare expression with no live session) spawns a locally-profiled Chromium at `<cwd>/.gm/browser-profile/`; the runner attaches via `--direct <wsEndpoint>`. Cookies/storage/extensions persist across sessions, turns, and runs. A second concurrent launch contends the SingletonLock; the watcher reuses the live CDP rather than re-launching. The runner's extension-attach mode ("Waiting for extension to connect") is never the default or what you want -- seeing it in `stderr` means the host failed to spawn local Chromium; dispatch `instruction` for recovery, not a blind retry.
43
38
 
44
39
  ## Discipline
45
40
 
46
- You never spawn Chromium yourself. You never `npm i puppeteer`. You never shell `chrome.exe`. The verb owns the handle; bypassing it orphans state plugkit cannot reap and breaks the next session's first read. When the page needs navigation, you evaluate `location.href = '...'` through the spool. When it needs a screenshot, you dispatch the verb that returns one you do not reach for a library to take it.
47
-
48
- A dispatch that returns `ok:false` with a launch error is plugkit telling you the environment refused; you read the `stderr`, you dispatch `instruction`, you do not loop the same body waiting for a different answer.
41
+ Never spawn Chromium yourself, `npm i puppeteer`, or shell `chrome.exe`; the verb owns the handle, and bypassing it orphans state plugkit cannot reap and breaks the next session's first read. Navigate by evaluating `location.href = '...'` through the spool; screenshot by dispatching the verb that returns one. A dispatch returning `ok:false` with a launch error is plugkit reporting the environment refused -- read `stderr`, dispatch `instruction`, do not loop the same body.
49
42
 
50
- **Dead-watcher recovery, never substitute.** If your Write to `.gm/exec-spool/in/browser/<N>.txt` produces no response file after two consecutive re-Reads AND `.gm/exec-spool/.status.json` ts is stale (>15s from current epoch), the watcher is dead. Your next call is `bun x gm-plugkit@latest spool` to boot a fresh watcher, then re-dispatch the browser body. Do NOT reach for puppeteer-core, puppeteer, playwright, agent-browser, `chrome.exe`, `npx browserless`, WebFetch, curl-then-parse, or any other browser substitute when the spool surface is reachable. The browser verb is the only admissible browser surface; substitutes spawn orphan Chromium processes plugkit cannot reap, bypass paper §23 witness-marked events, and produce evidence that does not feed the witness gate. The recovery loop is always: empty response check `.status.json` if stale, boot re-dispatch. The full chain ends in a browser-witness-marked event with non-empty `files:[…]` when the browser session actually saw the artifact change; anything shorter is forced closure.
43
+ **Dead-watcher recovery, never substitute.** If a Write to `.gm/exec-spool/in/browser/<N>.txt` produces no response after two re-Reads AND `.status.json` ts is stale (>15s from current epoch), the watcher is dead: boot `bun x gm-plugkit@latest spool`, then re-dispatch the browser body. Do NOT reach for puppeteer-core, puppeteer, playwright, agent-browser, `chrome.exe`, `npx browserless`, WebFetch, or curl-then-parse -- the browser verb is the only admissible browser surface; substitutes spawn orphan Chromium plugkit cannot reap, bypass section 23 witness-marked events, and produce evidence the gate cannot read. The recovery loop is always: empty response -> check `.status.json` -> if stale, boot -> re-dispatch.
@@ -1,31 +1,27 @@
1
1
  # EMIT
2
2
 
3
- YOU are the state machine. Plugkit is the synchronous library serving this prose; advancing the chain is your dispatch, not its action. Every possible write lands only through the verb you dispatch to land it.
3
+ YOU are the state machine. Plugkit is the synchronous library serving this prose; advancing the chain is your dispatch. Every write lands only through the verb you dispatch to land it.
4
4
 
5
- L3 audit on disk. You land every possible node of the covering family; your first emit = closure.
5
+ L3 audit on disk. Land every node of the covering family; your first emit = closure.
6
6
 
7
7
  ## Read-before-write
8
8
 
9
- You treat the target file's on-disk content as the goal-relative reference. If you diff against an unread file, you diff against an imagined baseline and your candidate mutation is unmeasured. When you observe disk-state divergence, you dispatch `transition` back to PLAN.
9
+ The target file's on-disk content is the goal-relative reference; diffing an unread file diffs an imagined baseline, leaving your candidate unmeasured. On observed disk divergence, `transition` back to PLAN.
10
10
 
11
11
  ## Fresh index
12
12
 
13
- You feed search outputs into EMIT only when the digest matches live filesystem. Admitting stale-index results = L1 bluff.
13
+ Feed search outputs into EMIT only when the digest matches the live filesystem; a stale-index result is an L1 bluff.
14
14
 
15
15
  ## Write-then-verify
16
16
 
17
- You issue one write per artifact; you then dispatch a disk Read against every possible touched path to assert the change. Verified disk state IS your witness, not the tool-call return. On discrepancy, you regress to root cause, not retry.
17
+ One write per artifact, then a disk Read against every touched path to assert the change -- verified disk state IS the witness, not the tool-call return. On discrepancy, regress to root cause, do not retry.
18
18
 
19
- **Client-side artifacts: write-then-browser-witness, in the same turn.** If the artifact is `.html`, `.js`, `.jsx`, `.ts`, `.tsx`, `.vue`, `.svelte`, `.mjs`, `.css`, or every possible other path loaded by a browser, the disk Read is necessary but not sufficient you also dispatch a `browser` verb that `page.evaluate`s the invariant the artifact establishes. The page-side assertion is the actual witness; the disk Read just witnesses serialization. Skip the browser dispatch on a client-side emit and you have a green-checked stub: the file landed, you don't know the page works. the COMPLETE gate refuses without the paired browser-witness for every client-side file edited this session — the `deviation.client-edit-no-witness` event fires (gates.rs, complete branch) and you regress to dispatch the missing `browser` witness before re-attempting COMPLETE.
19
+ **Client-side artifacts: write-then-browser-witness, same turn.** If the artifact is `.html .js .jsx .ts .tsx .vue .svelte .mjs .css` or any browser-loaded path, the disk Read is necessary but not sufficient -- also dispatch a `browser` verb that `page.evaluate`s the invariant the artifact establishes (the page-side assertion is the real witness; the disk Read only witnesses serialization). Skipping it ships a green-checked stub. The COMPLETE gate refuses without the paired browser-witness for every client-side file edited this session (`deviation.client-edit-no-witness`, gates.rs), and you regress to dispatch the missing witness.
20
20
 
21
21
  ## Artifact scope
22
22
 
23
- PRD names the artifacts you may write. You direct closure narrative to commit message + `memorize-fire`. Every possible file you write that PRD does not name = your response body displacing the dispatch surface.
24
-
25
- If during write-then-verify you notice an adjacent artifact the user clearly meant included, or an improvement the act of writing exposes (a generated file the build needs, a doc that names the new artifact, a witness script the artifact deserves) — you dispatch `prd-add` for it this turn, not as a follow-on. The same noticing-to-PRD discipline applies in EMIT: an observation that does not land as a PRD row evaporates with the turn.
26
-
27
- Between artifacts, between disk-Read checks, between a write you're uncertain about and the next — you re-dispatch `instruction`. Closure is the EMIT discipline; re-reading the prose between artifacts is how you avoid partial emits.
23
+ PRD names the artifacts you may write; direct closure narrative to the commit message + `memorize-fire`. A file PRD does not name is your response body displacing the dispatch surface. If write-then-verify exposes an adjacent artifact the user meant included or an improvement the act of writing reveals (a generated file the build needs, a doc naming the new artifact, a witness script), `prd-add` it this turn -- an observation that does not land as a row evaporates with the turn. Between artifacts and uncertain writes, re-dispatch `instruction`.
28
24
 
29
25
  ## Dispatch
30
26
 
31
- You dispatch `transition` when every planned artifact is written and you have disk-verified it. On new unknown, you dispatch `transition` back to PLAN.
27
+ `transition` when every planned artifact is written and disk-verified. On a new unknown, `transition` back to PLAN.