@nurix/etna 0.20.9 → 0.20.11

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.
Files changed (54) hide show
  1. package/data/catalog/rules/cloudflare.md +8 -0
  2. package/data/catalog/rules/database.md +10 -0
  3. package/data/catalog/rules/frontend.md +10 -0
  4. package/data/catalog/rules/pnpm.md +9 -0
  5. package/data/catalog/rules/react-native.md +10 -0
  6. package/data/catalog/rules/rust-desktop.md +8 -0
  7. package/data/catalog/rules/temporal.md +9 -0
  8. package/data/harness-index.json +1 -1
  9. package/data/harnesses/code/CLAUDE.md +6 -4
  10. package/data/harnesses/code/agents/polygraph-applier.md +24 -0
  11. package/data/harnesses/code/agents/polygraph-finder.md +31 -0
  12. package/data/harnesses/code/agents/polygraph-verifier.md +20 -0
  13. package/data/harnesses/code/codex/agents/polygraph-applier.toml +21 -0
  14. package/data/harnesses/code/codex/agents/polygraph-finder.toml +28 -0
  15. package/data/harnesses/code/codex/agents/polygraph-verifier.toml +17 -0
  16. package/data/harnesses/code/harness.json +2 -2
  17. package/data/harnesses/code/hooks/awareness.mjs +23 -6
  18. package/data/harnesses/code/hooks/lib/ownership.mjs +51 -19
  19. package/data/harnesses/code/hooks/lib/plans.mjs +11 -1
  20. package/data/harnesses/code/rules/cloudflare.md +8 -0
  21. package/data/harnesses/code/rules/database.md +10 -0
  22. package/data/harnesses/code/rules/frontend.md +10 -0
  23. package/data/harnesses/code/rules/pnpm.md +9 -0
  24. package/data/harnesses/code/skills/documentation/SKILL.md +10 -3
  25. package/data/harnesses/code/skills/documentation/references/frontmatter.md +21 -7
  26. package/data/harnesses/code/skills/documentation/references/instruction-style.md +1 -1
  27. package/data/harnesses/code/skills/documentation/templates/Readme.md +3 -1
  28. package/data/harnesses/code/skills/documentation/templates/package.md +131 -0
  29. package/data/harnesses/code/skills/documentation/templates/plan.md +2 -2
  30. package/data/harnesses/code/skills/documentation/templates/structure.md +9 -3
  31. package/data/harnesses/code/skills/documentation/templates/system.md +143 -0
  32. package/data/harnesses/code/skills/polygraph/SKILL.md +71 -0
  33. package/data/harnesses/code/skills/polygraph/references/dispatch.md +80 -0
  34. package/data/harnesses/code/skills/polygraph/references/rows.md +57 -0
  35. package/data/harnesses/code/skills/polygraph/scripts/audit.mjs +113 -0
  36. package/data/harnesses/delivery/harness.json +2 -2
  37. package/data/harnesses/delivery/skills/documentation/SKILL.md +10 -3
  38. package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +21 -7
  39. package/data/harnesses/delivery/skills/documentation/references/instruction-style.md +1 -1
  40. package/data/harnesses/delivery/skills/documentation/templates/Readme.md +3 -1
  41. package/data/harnesses/delivery/skills/documentation/templates/package.md +131 -0
  42. package/data/harnesses/delivery/skills/documentation/templates/plan.md +2 -2
  43. package/data/harnesses/delivery/skills/documentation/templates/structure.md +9 -3
  44. package/data/harnesses/delivery/skills/documentation/templates/system.md +143 -0
  45. package/data/harnesses/etna/harness.json +2 -2
  46. package/data/harnesses/etna/skills/documentation/SKILL.md +10 -3
  47. package/data/harnesses/etna/skills/documentation/references/frontmatter.md +21 -7
  48. package/data/harnesses/etna/skills/documentation/references/instruction-style.md +1 -1
  49. package/data/harnesses/etna/skills/documentation/templates/Readme.md +3 -1
  50. package/data/harnesses/etna/skills/documentation/templates/package.md +131 -0
  51. package/data/harnesses/etna/skills/documentation/templates/plan.md +2 -2
  52. package/data/harnesses/etna/skills/documentation/templates/structure.md +9 -3
  53. package/data/harnesses/etna/skills/documentation/templates/system.md +143 -0
  54. package/package.json +2 -2
@@ -1,3 +1,12 @@
1
+ ---
2
+ paths:
3
+ - "**/package.json"
4
+ - "**/pnpm-workspace.yaml"
5
+ - "**/pnpm-lock.yaml"
6
+ - "**/.npmrc"
7
+ - "**/tsconfig*.json"
8
+ - "**/turbo.json"
9
+ ---
1
10
  # pnpm — `@nurix/*` Workspaces: naming, boundaries, and consuming
2
11
 
3
12
  How a `@nurix/*` repo is **named**, **structured**, and how its packages are **consumed** — every repo takes the workspace shape, single-package frontends included. Publishing and CLI design live in the `nustack` skill, not here — no `nustack` skill in the runtime ⇒ ask before crossing the publish boundary.
@@ -60,6 +60,8 @@ The two guarantees are complementary and both break on mixing: a reader holding
60
60
  | Baseline / reconcile docs | `maintenance` agent (baseline mode) — it calls this skill per template |
61
61
  | Document feature/module (LLD) | [`templates/feature.md`](templates/feature.md) |
62
62
  | Document data flow / state / Redux | [`templates/feature.md`](templates/feature.md) — they are sections of the feature doc |
63
+ | Document a workspace package (`docs/architecture/packages/{package}.md`) | [`templates/package.md`](templates/package.md) — the **residual** owner of `packages/{name}/**`: its manifest, build, entry, layout and every behavior no system or feature doc claims at higher specificity |
64
+ | Document one system spanning packages (`docs/architecture/systems/{system}.md`) | [`templates/system.md`](templates/system.md) — one machine end to end; its `owns:` names the machine's subtrees, narrower than the package glob, so it wins by specificity. Not a screen — a system doc written as a giant feature doc is the mistake it prevents |
63
65
  | Create/update changelog entry | [`templates/changelog-entry.md`](templates/changelog-entry.md) (record — one per unit of work; carries the refinement fields, frozen inside its commit, distilled by the `retro` agent) |
64
66
  | Create/update plan | [`templates/plan.md`](templates/plan.md) (record) |
65
67
  | Record/revise architecture decision | [`templates/architecture-decision.md`](templates/architecture-decision.md) — one AD per subject; revisions update it in place |
@@ -82,7 +84,7 @@ The two guarantees are complementary and both break on mixing: a reader holding
82
84
  | Add to protected files | [`templates/protected-files.md`](templates/protected-files.md) |
83
85
  | Create/update root README | [`templates/root-readme.md`](templates/root-readme.md) |
84
86
  | Scaffold a standard doc (docs index, `structure.md`, CHANGELOG, backlog, memory) | [`templates/Readme.md`](templates/Readme.md) — the index names each scaffold file |
85
- | Derive/update a feature doc's `owns:` | [`references/frontmatter.md`](references/frontmatter.md) |
87
+ | Derive/update an owning doc's `owns:` (feature, package, system) | [`references/frontmatter.md`](references/frontmatter.md) |
86
88
  | Update existing doc | § Editing an existing doc (below) |
87
89
  | Instruction file (`CLAUDE.md`, a rule, an agent, skill prose) | [`references/instruction-style.md`](references/instruction-style.md) — not these templates; every-load prose stays lean, and the present-tense rule still applies |
88
90
  | Author or restructure a **skill** (fit, triggers, shape, anatomy, shipping) | The skill-authoring field guide — the `etna` repo (`nurixlabs/etna`), folder `docs/playbooks/skills/`, chapters `00`–`10`. **No etna checkout available ⇒ ask the user for access to the etna repo, or proceed from first principles** with [`references/instruction-style.md`](references/instruction-style.md) governing the prose. This row is the only place the playbook is referenced |
@@ -105,6 +107,8 @@ The two guarantees are complementary and both break on mixing: a reader holding
105
107
  | Document | Nature | Name | Lifecycle |
106
108
  | --- | --- | --- | --- |
107
109
  | Feature (LLD) | Truth | `kebab-case.md` | Living; `status:` `draft` → `active` → `deprecated` |
110
+ | Package | Truth | `{package-folder}.md` | Living; `status:` as the feature doc |
111
+ | System | Truth | `{machine}.md` | Living; `status:` as the feature doc |
108
112
  | Architecture Decision | Truth | `AD-NNN-kebab-case.md` | Living; `Proposed` → `Accepted` → `Deprecated`; revisions rewrite the body + append to its Decision Changelog |
109
113
  | Steering docs (overview, domain model, glossary, non-goals, security, testing strategy) | Truth | fixed names | Living |
110
114
  | API reference / environment registry | Truth | fixed names | Living |
@@ -125,8 +129,11 @@ doc, plus the genre's own keys beside it; a document without its frontmatter fai
125
129
  contract and is not done. **There is no frontmatter-less genre.** A feature or UX doc carries the
126
130
  full set — `owns:` (required), `module:` (optional), `keywords:` (required), `status:` (required),
127
131
  `applies:` (the architecture docs it obeys; omitted when none), optional `last-reviewed:`. A
128
- behavioral checklist (`docs/tests/`) carries `type: checklist` and `verifies:` — the doc whose
129
- promises it proves. An acceptance-criteria doc (`docs/acceptance/`) carries `type:` and `status:`.
132
+ **package** doc (`docs/architecture/packages/`) and a **system** doc (`docs/architecture/systems/`)
133
+ carry the same set minus `module:` — a package is already a bounded unit and a machine spanning
134
+ packages belongs to no single context. A behavioral checklist (`docs/tests/`) carries
135
+ `type: checklist` and `verifies:` — the doc whose promises it proves. An acceptance-criteria doc
136
+ (`docs/acceptance/`) carries `type:` and `status:`.
130
137
 
131
138
  **The frontmatter is where the docs tree's edges live**, and a doc that declares none is a node
132
139
  nothing can reach: no change implicates it, so it rots without the rot being detectable. Deriving
@@ -1,6 +1,6 @@
1
1
  # Frontmatter Derivation — the doc graph
2
2
 
3
- Load when: creating a doc that declares an edge (a feature doc, a UX doc, a behavioral checklist), updating one whose scope moved, or running a baseline/reconcile pass over many docs.
3
+ Load when: creating a doc that declares an edge (a feature, package or system doc, a UX doc, a behavioral checklist), updating one whose scope moved, or running a baseline/reconcile pass over many docs.
4
4
 
5
5
  **A docs tree is a graph, and every edge in it is declared in frontmatter.** Two kinds of edge exist: **doc → code** (`owns:`), and **doc → doc** (`verifies:`, `applies:`). The SessionStart hook reads them all and injects the generated indexes; there is no hand-maintained map of either kind.
6
6
 
@@ -14,13 +14,25 @@ The consuming end is also the end that **knows**. A checklist author knows what
14
14
 
15
15
  ## When to run
16
16
 
17
- - **Baseline / reconcile** — for every feature doc whose code paths aren't yet declared in its `owns:` frontmatter (the `maintenance` agent (baseline mode) calls this)
18
- - **New feature doc** — when creating a doc via the [Feature template](../templates/feature.md), project its `owns:` globs
17
+ - **Baseline / reconcile** — for every owning doc whose code paths aren't yet declared in its `owns:` frontmatter (the `maintenance` agent (baseline mode) calls this)
18
+ - **New owning doc** — when creating one via the [Feature](../templates/feature.md), [Package](../templates/package.md) or [System](../templates/system.md) template, project its `owns:` globs
19
19
  - **Doc update** — when the documented scope changes, update the doc's `owns:` globs
20
20
 
21
+ ## Which genres own code
22
+
23
+ **Three do, and no others: `feature`, `package`, `system`.** They layer by glob specificity over the same tree, which is what lets a repo be documented at three altitudes without subtracting anything by hand:
24
+
25
+ | Genre | Claims | Wins because |
26
+ | --- | --- | --- |
27
+ | `package` (`docs/architecture/packages/`) | `packages/{name}/**` — the whole tree, one glob | Nothing; it is the **residual** owner and loses every narrower claim, keeping what no one else takes |
28
+ | `system` (`docs/architecture/systems/`) | the subtrees and exact files one machine is made of | Its globs are narrower than the package glob — specificity |
29
+ | `feature` (`docs/features/`) | one capability's or one surface's globs | Same — specificity over the package glob |
30
+
31
+ Every other genre owns no code and carries no `owns:`. That includes the cross-cutting doctrine in `docs/architecture/` (and `docs/architecture/common/`), which describes patterns rather than regions — a surface declares it is bound by one through `applies:`, and the doctrine never claims the surface back. Checklists, acceptance docs, ADs, operations procedures, research and brainstorm records own nothing.
32
+
21
33
  ## How to derive the frontmatter
22
34
 
23
- A feature doc's ownership frontmatter is `owns:` (required), `module:` (optional), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
35
+ An owning doc's ownership frontmatter is `owns:` (required), `module:` (optional — feature docs only; a package is already a bounded unit and a system spans contexts by definition), `keywords:` (required), and `status:` (required). An optional `last-reviewed:` date (stamped whenever the doc is substantively reviewed or updated) gives the `maintenance` agent a staleness signal to rank its audits by — it is tooling metadata, never narrated in the body. `type:` (required — the genre, enum = the template names) and `rev:` (generator-written generation stamp) are the same class: external tooling reads them, sessions **preserve them on edits** and never narrate or inject them. The `maintenance` agent stamps `type:` on docs that predate the key. `slug:` completes the set on generated docs: the identity key, minted once at creation and never re-derived from a display name — in the repo the filename is the slug, and the `maintenance` agent re-aligns the two when they diverge.
24
36
 
25
37
  **1. `owns:`** (the path scope)
26
38
 
@@ -35,15 +47,17 @@ Prefer one region glob over many file globs. Ten paths say nothing about which i
35
47
  | A feature's own directory | `src/feature/**` |
36
48
  | A feature split across two directories | One glob each |
37
49
  | A single entry-point file, and nothing beside it | The exact file path |
50
+ | A whole workspace package, residually | `packages/{name}/**` — one glob, on the package doc |
51
+ | A machine spanning packages | One glob or exact path per subtree it is made of, on the system doc |
38
52
  | A shared file several features import | **Nothing — leave it unowned** |
39
53
 
40
54
  **An unowned shared file is the system working, not a gap.** A shared module's authority is the contract it exposes, not any one consumer, so a library-references file or a common utility legitimately has no owning doc. Claiming it would make the index bigger and the routing less certain at once.
41
55
 
42
56
  Glob each pattern against the codebase. At `status: active`, drop any that match nothing; at `status: draft`, projected globs may match nothing yet — confirm them against real code when the doc flips to `active`.
43
57
 
44
- **2. `module:`**
58
+ **2. `module:`** (feature docs only)
45
59
 
46
- The single bounded-context label this feature belongs to, or omit it for a cross-cutting feature that belongs to no single context. A module is a label, not a folder — features sharing a `module:` value are what ties that module to code (a filter over the generated ownership index).
60
+ The single bounded-context label this feature belongs to, or omit it for a cross-cutting feature that belongs to no single context. A module is a label, not a folder — features sharing a `module:` value are what ties that module to code (a filter over the generated ownership index). Package and system docs omit it entirely.
47
61
 
48
62
  **3. `keywords:` & `status:`**
49
63
 
@@ -67,7 +81,7 @@ That edge has a property the others lack, and it is worth naming: **a `Pinned:`
67
81
 
68
82
  ## Rules
69
83
 
70
- - One canonical doc per path. A doc's `owns:` globs must not overlap another doc's at equal specificity — the narrower glob wins; equal-specificity overlap is an ownership conflict to resolve.
84
+ - One canonical doc per path. A doc's `owns:` globs must not overlap another doc's at equal specificity — the narrower glob wins; equal-specificity overlap is an ownership conflict to resolve. Overlap at **unequal** specificity is the layering working as designed: a package doc's `packages/{name}/**` is meant to be outranked, and what survives every narrower claim is exactly what that doc describes.
71
85
  - Use glob patterns for directories, explicit paths for individual files. At `active`, never list paths that don't exist in the codebase; a `draft`'s projected paths are confirmed at `active`.
72
86
  - When a doc covers a deep feature with sub-specs (e.g., `editor/`), each sub-spec owns its own globs — don't duplicate a path across siblings.
73
87
  - For baseline/reconcile with many docs, use parallel sub-agents to read source and propose `owns:` globs.
@@ -4,7 +4,7 @@ The shared style for every file an agent obeys — a `CLAUDE.md`, a rule, an age
4
4
 
5
5
  ## The test for every line
6
6
 
7
- An instruction file is paid for whenever it loads, scaled by its load class: `CLAUDE.md` and rules load on **every turn of every session** — the most expensive prose in a repo per word; an agent definition loads per dispatch, a skill per invocation. The bar is not "is this true?" but **"must this be in front of the agent whenever this file loads?"** Measure weight in tokens, not lines; trim biggest-first on every edit.
7
+ An instruction file is paid for whenever it loads, scaled by its load class: `CLAUDE.md` and unscoped rules load on **every turn of every session** — the most expensive prose in a repo per word; a `paths:`-scoped rule loads on those same terms from its first matching file read on; an agent definition loads per dispatch, a skill per invocation. The bar is not "is this true?" but **"must this be in front of the agent whenever this file loads?"** Measure weight in tokens, not lines; trim biggest-first on every edit.
8
8
 
9
9
  **Rewriting, the test is armor vs. narration.** A reason clause either blocks a move an agent would otherwise make — the failure is counter-intuitive, the wrong fix looks correct, or the rule reads as arbitrary tidiness and gets "improved away" — or it explains the self-evident. Ask of each: *does the forbidden move look correct to an agent mid-task?* Keep the first kind, cut the second. **A constraint may lose its explanation; it may never lose its existence** — compression is fewer words for the same constraints, so a passage that cannot shrink without dropping one stays long.
10
10
 
@@ -5,6 +5,8 @@ One file per template. Every template is either a **truth document** (states cur
5
5
  | Template | File | Nature |
6
6
  | --- | --- | --- |
7
7
  | Feature (LLD) | [feature.md](feature.md) | Truth |
8
+ | Package (one workspace package) | [package.md](package.md) | Truth |
9
+ | System (one machine spanning packages) | [system.md](system.md) | Truth |
8
10
  | Architecture Decision (AD) | [architecture-decision.md](architecture-decision.md) | Truth (Decision Changelog tail sanctioned) |
9
11
  | System overview | [system-overview.md](system-overview.md) | Truth |
10
12
  | Domain model | [domain-model.md](domain-model.md) | Truth |
@@ -35,4 +37,4 @@ One file per template. Every template is either a **truth document** (states cur
35
37
 
36
38
  **Baseline scaffolds** — files that must exist after every baseline; the `maintenance` agent (baseline mode) creates any that are missing: [docs-readme.md](docs-readme.md), [structure.md](structure.md), [changelog-index.md](changelog-index.md), [backlog.md](backlog.md), [memory-main.md](memory-main.md), and [root-readme.md](root-readme.md) (never overwriting an existing root README).
37
39
 
38
- **Ownership.** A feature doc is the canonical reference for the code paths in its **`owns:` frontmatter** — the only ownership key. To find what a doc owns, read its `owns:` globs; to find the doc for a path, match the path against the injected ownership index (the union of every feature's `owns:` globs), narrower glob wins. See [`../references/frontmatter.md`](../references/frontmatter.md) for turning code into `owns:` globs.
40
+ **Ownership.** Three genres carry code — **feature**, **package**, **system** — and each is the canonical reference for the code paths in its **`owns:` frontmatter**, the only ownership key. To find what a doc owns, read its `owns:` globs; to find the doc for a path, match the path against the injected ownership index (the union of every owning doc's globs), narrower glob wins. That is what layers them: a package doc claims `packages/{name}/**` and is the tree's **residual** owner, while a system doc claims the narrower subtrees of one machine and a feature doc claims one surface — both win those paths by specificity, and the package doc keeps everything neither claims. Two docs may never claim a path at **equal** specificity. Every other genre here owns no code, including the cross-cutting doctrine in `docs/architecture/common/`. See [`../references/frontmatter.md`](../references/frontmatter.md) for turning code into `owns:` globs.
@@ -0,0 +1,131 @@
1
+ # Package Documentation (docs/architecture/packages/{package}.md)
2
+
3
+ Truth document. Use for: **one workspace package — what it is and how it behaves**. One file per package, named for the package's folder (`packages/cli/` → `docs/architecture/packages/cli.md`). It states the package's own machinery: its manifest and published identity, its build and entry point, its source layout, and every behavior of its tree that no system or feature document claims.
4
+
5
+ **A package document is the residual owner of its own tree.** Its `owns:` is the whole package glob — `["packages/{name}/**"]` — and that glob is the *broadest* claim anything makes on those paths, so it loses to every narrower one. A system document naming `packages/{name}/src/server/runs/**` wins those files by specificity; a feature document naming `packages/{name}/src/surfaces/apps/**` wins those. What is left after every narrower claim is what this document describes, and it describes that exhaustively. **The residual claim is a promise of completeness, not of scope**: a package document with nothing left after the systems and features have claimed their subtrees is still owed — the manifest, the build, the entry, the layout, the test wiring and the deploy shape are always residual.
6
+
7
+ **Two rules bind the glob.** Neither genre may claim a path another document claims at **equal specificity** — equal-specificity overlap is an ownership conflict to resolve before either document ships, not a duplication to live with. And every glob **matches at least one file on disk** at `status: active`; a projected glob is permitted only at `draft`, and is confirmed when the document flips.
8
+
9
+ **How this differs from its neighbours.** A **feature** document covers one capability or one page a person names, and owns that surface's globs. A **system** document covers one machine that spans packages, and owns the subtrees that machine is made of. A **package** document covers one unit of distribution — a manifest, a build, a binary or a bundle — and owns what is left of it. The unit is the package boundary, so if the subject you are writing about does not stop at a `package.json`, it is not this genre. Route it: one screen → feature; one machine crossing two packages → [system](system.md).
10
+
11
+ **Required vs optional.** Required in every package document: the **frontmatter**, the **opening** (title, identity line, what the package is), the **ownership boundary** (what this document does not describe and which document does), at least one **behavior section**, **Files**, and **Related**. Everything else is optional — include a section only when the package has something real to put in it. A package with no test wiring of its own gets no verification section; a package that nothing else in the repo consumes says so in one line rather than growing a Consumers section. A short accurate document beats a full skeleton with empty headings.
12
+
13
+ Package documents run long because they are exhaustive over their residue — roughly 150 to 600 lines is the working range, and the top of that range is a package holding an application, not a document that has lost discipline.
14
+
15
+ ```yaml
16
+ ---
17
+ owns: ["packages/{name}/**"] # required — the whole package tree, one glob; the residual claim
18
+ keywords: [package-name, binary, build, entry] # required — discovery terms: the npm name, the binary, the surfaces
19
+ status: active # required — active | draft | deprecated
20
+ applies: [docs/architecture/common/api.md] # optional — cross-cutting doctrine this package is BOUND by (obligation, not a bibliography); omit when none
21
+ type: package # required tooling key — genre stamp; preserve on edits, never narrate
22
+ ---
23
+ ```
24
+
25
+ > A package document carries no `module:` — a package is already a bounded unit, and a second label
26
+ > for the same boundary is a thing to keep in sync for nothing. `last-reviewed:` is optional and,
27
+ > like `type:`, is tooling metadata: preserve it, never narrate it.
28
+
29
+ ```
30
+ # {package-path} — {the one-line role}
31
+
32
+ **Package:** `@scope/name` · **Ships as:** {a public npm package with one binary `x` / a private
33
+ source-first workspace package / a Worker on {domain}} · **Source:** `packages/{name}`
34
+
35
+ {One paragraph: what this package is and the job it does in the product. Name what it holds that
36
+ nothing else does, and what it deliberately does not hold. Written for someone who has not opened
37
+ the folder.}
38
+
39
+ {One paragraph: the ownership boundary. This document is the residual owner of `packages/{name}/**`;
40
+ these subtrees are claimed at higher specificity by these documents and are pointed at, not
41
+ restated. Where the routing is more than a sentence, make it the table below instead.}
42
+
43
+ {Optional, and worth its line whenever the body names paths: "Paths below are relative to
44
+ `packages/{name}/` unless they name another package."}
45
+
46
+ ## What is built and what is not
47
+
48
+ {Optional — required in substance whenever some of the tree does not run. State plainly which
49
+ halves exist and which do not, with the source evidence for each claim, and say what a reader who
50
+ runs the unbuilt half will actually observe. A package whose subject as a whole does not run is
51
+ `status: draft` and says so here; a scoped gap in a working package stays `active` and takes an
52
+ UNBUILT marker at the section that describes the gap.}
53
+
54
+ ## Ownership — packages/{name}
55
+
56
+ {Optional — use the table form when more than two documents claim subtrees of this package.}
57
+
58
+ **The package glob is the residual claim.** A system or feature document's `owns:` is more specific
59
+ and wins by specificity, so this document describes only what none of them claims, and points to
60
+ each for the rest.
61
+
62
+ | Path | What it is |
63
+ | --- | --- |
64
+ | `src/index.ts` | {the residue: the entry, the dispatch, the layout} |
65
+
66
+ | Subtree | Stated and owned by |
67
+ | --- | --- |
68
+ | `src/{machine}/**` | [{system}](../systems/{system}.md) |
69
+ | `src/surfaces/{x}/**` | [{feature}](../../features/{feature}.md) |
70
+
71
+ ## {Behavior sections — named for this package's own machinery}
72
+
73
+ {The body. There is no fixed section list, and inventing one would be a lie: what a CLI owes
74
+ (commands, the store, the on-ramp) and what a UI package owes (the host port, the frame, the route
75
+ zones, the component pool) share no headings. Name each section for the thing it describes and
76
+ order them the way a reader meets them — identity and build first, then the surface, then what it
77
+ writes, then how it is verified. Prefer a table wherever the content is a roster (commands, routes,
78
+ exports, bindings, environment variables); prefer prose wherever the content is a rule and its
79
+ reason. State mechanisms and contracts, never pasted implementations.}
80
+
81
+ ## Tests
82
+
83
+ {Optional. What proves this package, and what each suite pins — a `Suite | Pins` table, or the
84
+ commands a reader runs. A package whose verification is a build check names the check instead
85
+ (`## Checks`, `## Build and test`); a package with no suite of its own says so in one line in the
86
+ build section and carries no heading here.}
87
+
88
+ ## Files
89
+
90
+ | Path | Role |
91
+ | --- | --- |
92
+ | `packages/{name}/package.json` | {the manifest: the bin, the exports, the scripts} |
93
+ | `packages/{name}/src/index.ts` | {the entry} |
94
+
95
+ {One row or bullet per file this document owns, with what it holds — the roster a reader uses to go
96
+ from the document to the code. Close with the inverse where it helps: "Read here, owned elsewhere:"
97
+ naming the paths the body describes but another document claims.}
98
+
99
+ ## Related
100
+
101
+ - [`{system}.md`](../systems/{system}.md) — {why a reader of this document would open that one}
102
+ - [`{other-package}.md`]({other-package}.md) — {the seam between the two}
103
+ - [`{doctrine}.md`](../common/{doctrine}.md) — {the cross-cutting contract this package answers to}
104
+ ```
105
+
106
+ ### The identity line
107
+
108
+ The bolded `·`-separated run under the title is what a reader checks first, and it answers three
109
+ questions no body section should have to: **what is this called** on the registry or in the
110
+ workspace, **how does it ship** (a public tarball, a private source-first package, a deployed
111
+ Worker, a signed installer), and **where is its source**. A package that ships two artifacts names
112
+ both. Add a `**Crate:**` or `**Deploys as:**` term where the package has one; drop any term that
113
+ would restate the title.
114
+
115
+ ### Marking what is decided and unbuilt
116
+
117
+ Where the package holds code for a design that is decided and not built — or a surface whose other
118
+ half does not exist — wrap the prose in a marker so the gap is machine-findable and its evidence
119
+ travels with it:
120
+
121
+ ```
122
+ <!-- UNBUILT:START — {what is decided, where it is decided (an AD or an owner ruling), and the
123
+ source evidence that it is not built: the file that does not exist, the route that is not mounted,
124
+ the binding that is not declared} -->
125
+ {the prose describing the unbuilt half}
126
+ <!-- UNBUILT:END -->
127
+ ```
128
+
129
+ **A design that was decided *against* carries no marker.** A marker means the work is owed and
130
+ absent; using one for a rejected design turns the register of debt into a register of opinions.
131
+ Say in prose that it is not built and not owed, and name the decision that settled it.
@@ -8,13 +8,13 @@ The `boundary` skill parses the **Proposed Changes** sections to check boundary
8
8
 
9
9
  **Doc Obligations is the one ledger the plan's author writes.** Deriving tests from behavior is judgment, which is why `testing` owns that section and it is marked never-hand-author; resolving Proposed Changes' file paths to the feature docs that own them is a **lookup** against the ownership index already injected at session start. Different work, different rule — fill it yourself, while the touch list is fresh.
10
10
 
11
- The **`Gates:`** line carries one machine-read segment. The compliance hook greps **`Boundary:`** — implementation edits inside the plan's scope are blocked while it reads `Boundary: pending`; the `boundary` skill rewrites it to `Boundary: passed YYYY-MM-DD` or `Boundary: blocked YYYY-MM-DD`. The other two gates are enforced by **section presence**: a plan with no `## Test Obligations` or no `## Doc Obligations` section blocks the same edits — the sections are the artifacts, and the gate derives from them, not from a claim about them. Never hand-edit the line to skip a gate.
11
+ The **`Gates:`** line carries two machine-read segments. The compliance hook greps **`Boundary:`** — implementation edits inside the plan's scope are blocked while it reads `Boundary: pending`; the `boundary` skill rewrites it to `Boundary: passed YYYY-MM-DD` or `Boundary: blocked YYYY-MM-DD`. The other two plan gates are enforced by **section presence**: a plan with no `## Test Obligations` or no `## Doc Obligations` section blocks the same edits — the sections are the artifacts, and the gate derives from them, not from a claim about them. **`Polygraph:`** is the completion gate's trace: it reads `Polygraph: pending` from the first draft until the `polygraph` skill (gate mode) certifies the plan's documents — every Doc Obligations row discharged **updated** plus every `Spec:` doc — and rewrites it to `Polygraph: passed YYYY-MM-DD (N docs · N claims · N corrected · N registered)`. A plan that touched no document writes `Polygraph: owes nothing — {reason}` by hand; nothing else on this segment is ever hand-written. A Complete plan still reading `pending` raises a `needs-session:` queue row and fails CI. Never hand-edit the line to skip a gate.
12
12
 
13
13
  ```
14
14
  # {Feature Name}
15
15
 
16
16
  **Status:** Draft | In Progress | Complete | Abandoned
17
- **Gates:** Boundary: pending
17
+ **Gates:** Boundary: pending · Polygraph: pending
18
18
  **Spec:** [docs/features/{feature}.md](../../features/{feature}.md) <!-- one line per feature doc this plan implements against; a plan spanning three features names three -->
19
19
  **Started:** YYYY-MM-DD
20
20
  **Completed:** YYYY-MM-DD <!-- fill in the SAME edit that flips Status to Complete — along with every ledger Outcome cell: the flip freezes the file instantly, so anything left for a second edit is unreachable (the frozen-record gate rightly blocks it) -->
@@ -18,8 +18,10 @@ Each topic has one canonical location. Read from here, not from plans or changel
18
18
 
19
19
  | Topic | Authority | Key Files |
20
20
  | ----- | --------- | --------- |
21
- | Code-path ownership (path → doc + module) | feature `owns:` frontmatter | the generated ownership index |
21
+ | Code-path ownership (path → doc + module) | `owns:` frontmatter on features, packages and systems | the generated ownership index |
22
22
  | System overview | `docs/architecture/` | system-design.md |
23
+ | One workspace package | `docs/architecture/packages/` | {package-folder}.md |
24
+ | One machine spanning packages | `docs/architecture/systems/` | {machine}.md |
23
25
  | Steering (domain model, glossary, non-goals) | `docs/architecture/` | domain-model.md, glossary.md, non-goals.md |
24
26
  | Architecture decisions (ADs) | `docs/architecture/decisions/` | AD-NNN-*.md |
25
27
  | API surface | `docs/architecture/` | api.md |
@@ -45,8 +47,12 @@ Every doc is a **truth document** (states current absolutes, topic-named, update
45
47
 
46
48
  ## Folder Rules
47
49
 
48
- - `docs/features/`: Living reference for implemented features. Each feature doc **carries** the `owns:` / `module:` / `keywords:` / `status:` frontmatter — `owns:` declares the code-path globs it owns (the only ownership key), `module:` is an optional bounded-context label, `keywords:` are discovery terms, `status:` is `active`/`draft`/`deprecated`. The SessionStart hook unions every feature's `owns:` globs into the injected ownership index.
49
- - `docs/architecture/`: The truth layer for system-wide shape: overview, domain model, glossary, non-goals, API surface, security, and `decisions/` (ADs — one per subject, updated in place, journey in each AD's Decision Changelog). Update when cross-cutting reality changes.
50
+ - `docs/features/`: Living reference for implemented features. Each feature doc **carries** the `owns:` / `module:` / `keywords:` / `status:` frontmatter — `owns:` declares the code-path globs it owns (the only ownership key), `module:` is an optional bounded-context label, `keywords:` are discovery terms, `status:` is `active`/`draft`/`deprecated`. The SessionStart hook unions every owning doc's `owns:` globs into the injected ownership index.
51
+ - `docs/architecture/`: The truth layer for system-wide shape: overview, domain model, glossary, non-goals, API surface, security, and `decisions/` (ADs — one per subject, updated in place, journey in each AD's Decision Changelog). Update when cross-cutting reality changes. The cross-cutting doctrine directly under `architecture/` (and under `architecture/common/` where a repo separates it) **owns no code** — it describes patterns every surface obeys, and `applies:` is how a surface declares it is bound.
52
+ - `docs/architecture/packages/`: One doc per workspace package (`{package-folder}.md`), present in a workspace repo. Each is the **residual owner** of its tree — `owns: ["packages/{name}/**"]` — describing the manifest, build, entry, layout and every behavior no system or feature doc claims at higher specificity. Template: the `documentation` skill's `templates/package.md`.
53
+ - `docs/architecture/systems/`: One doc per machine that spans packages (`{machine}.md`) — the walk, the egress, the ingest. Its `owns:` names the machine's own subtrees and files, narrower than the package glob, so it wins those paths by specificity and the package doc keeps the rest. Not a surface doc: what a person sees stays in `docs/features/`. Template: the `documentation` skill's `templates/system.md`.
54
+
55
+ **Three genres carry `owns:`** — features, packages, systems — and no others. Their globs layer by specificity (package `**` residual, system and feature narrower), and two docs may never claim a path at **equal** specificity: that is an ownership conflict to resolve, not a duplication to live with. Every glob matches at least one file on disk at `status: active`.
50
56
  - `docs/operations/`: How-to procedures for setup, development, and deployment, plus the environment registry. Update when workflows change. One-shot migrations do NOT live here — they are records (`docs/history/migrations/`).
51
57
  - `docs/tests/`: Testing strategy and test docs. Present when the repo has a test posture worth documenting.
52
58
  - `docs/history/plans/`: Records. Must have `Status:` field. Never modify after completion.
@@ -0,0 +1,143 @@
1
+ # System Documentation (docs/architecture/systems/{system}.md)
2
+
3
+ Truth document. Use for: **one machine that spans packages** — exactly how it works, end to end, in one place. One file per machine, named for the machine (`docs/architecture/systems/update-engine.md`). It states the machine's model and its whole path: what enters it, every stage it passes through, what it writes, what re-drives it when it stalls, and what a reader sees at the far end.
4
+
5
+ **A system document's globs win by specificity.** Its `owns:` names the subtrees and exact files the machine is made of — `packages/studio/src/server/execution/**`, `packages/ui/src/shared/harnessVocabulary.ts` — and those are narrower than the package document's `packages/studio/**`, so the system takes them and the package keeps the residue. That is the whole mechanism: **the package document is the residual owner and the system document is the specific one**, and nothing needs to be subtracted by hand. A machine confined to one package still gets a system document if the machine is the thing worth stating; it is the *narrower glob* that makes it a system, not the package count.
6
+
7
+ **Two rules bind the globs.** Neither genre may claim a path another document claims at **equal specificity** — equal-specificity overlap is an ownership conflict to resolve before either document ships. And every glob **matches at least one file on disk** at `status: active`; projected globs are permitted only at `draft` and are confirmed when the document flips. Because a system's `owns:` list is long and hand-assembled, re-glob it whenever the machine's code moves — a stale entry here silently un-owns real code back to the package document, which does not describe it.
8
+
9
+ **How this differs from its neighbours — and the mistake this template exists to prevent.** A **feature** document covers one capability or one page a person names and owns that surface's globs. A **package** document covers one unit of distribution and owns what is left of its tree. A **system** document covers a *machine*: something with an entry, stages, state and an outcome, which a person does not open and cannot point at. **The failure mode is a system document written as a giant feature document** — a tour of screens and what each button does, at ten times a feature doc's length. The test is mechanical: if the subject can be named by an address a person navigates to, it is a feature; if it can be named only as a verb over the product's own nouns — the walk, the egress, the ingest, the settlement — it is a system. A system document says what a surface *renders from* and links to the feature document for what the surface looks like; it never describes the surface.
10
+
11
+ **Required vs optional.** Required in every system document: the **frontmatter**, the **opening statement** (what the machine is, then what this document states end to end), the **boundary paragraph** (what this document does not restate, and which document holds each part), the **machine diagram**, at least one **stage section**, **Files**, and **Related**. Everything else is optional. Do not add a section because it seems owed — a stage the machine does not have is a section that will be filled with something untrue.
12
+
13
+ System documents are long by nature, because the point is that the whole machine is in one place — roughly 300 to 1000 lines. Length is earned by stages, never by restating a neighbour: every paragraph that could have been a link to the document that owns it is the genre's characteristic waste.
14
+
15
+ ```yaml
16
+ ---
17
+ owns: # required — the machine's subtrees and exact files; narrower than the package glob
18
+ - packages/{pkg}/src/{machine}/**
19
+ - packages/{pkg}/src/routes/{machine}.ts
20
+ - packages/{other}/src/shared/{machine}Vocabulary.ts
21
+ keywords: [machine name, its nouns, its verbs] # required — discovery terms: the machine's own vocabulary, the table and route names
22
+ status: active # required — active | draft | deprecated
23
+ applies: # optional — the decisions and doctrine this machine is BOUND by (obligation, not a bibliography)
24
+ - docs/architecture/decisions/AD-0NN-{slug}.md
25
+ - docs/architecture/common/{doctrine}.md
26
+ type: system # required tooling key — genre stamp; preserve on edits, never narrate
27
+ ---
28
+ ```
29
+
30
+ > A system document carries no `module:` — a machine that spans packages belongs to no single
31
+ > bounded context, and labelling it with one asserts a boundary it crosses by definition.
32
+ > `last-reviewed:` is optional tooling metadata: preserve it, never narrate it.
33
+
34
+ ```
35
+ # {The machine}
36
+
37
+ {One paragraph that defines the machine in its own first sentence — bold the term being defined —
38
+ then says what this document states, in the order the body states it. The enumeration is the
39
+ contract: a reader who wants one stage finds it by reading this sentence. Where the machine's
40
+ purpose is easier stated as an outcome, lead with `**Goal:**` and one sentence instead.}
41
+
42
+ {One paragraph: the boundary. What this document does **not** restate, and which document holds
43
+ each part — the neighbouring systems, the package documents whose residue this sits inside, the
44
+ feature documents that render from it, the common-plane doctrine it obeys, the decision records
45
+ behind its shape. Name each with a link and the subject it holds. This paragraph is what keeps the
46
+ document from growing into its neighbours.}
47
+
48
+ ```text
49
+ {The machine diagram. One fenced block, drawn as the thing flows — entry at the top or left,
50
+ each stage a box or a labelled arrow, the durable writes named, the re-drive path shown returning.
51
+ Label the arrows with what crosses them, not with verbs. This is the picture a reader holds while
52
+ reading the rest, so it carries the machine's real names — routes, tables, classes, files — and
53
+ not generic boxes.}
54
+ ```
55
+
56
+ {Optional, and worth its line whenever the body names paths: "Every path below is relative to
57
+ `packages/{pkg}/src/{dir}/` unless it names another package."}
58
+
59
+ {Optional: a reading order for a long document — "§ X is the data; § Y is the code that reads it;
60
+ § Z is what re-drives it" — where the section list is not self-evidently a sequence.}
61
+
62
+ ## The shape
63
+
64
+ {Optional. Where the machine has parts a reader must hold at once before any stage makes sense,
65
+ name them in one table before the stages begin.}
66
+
67
+ | Part | Where | What it holds |
68
+ | --- | --- | --- |
69
+ | {Entry} | `routes/{x}.ts` | {thin, tenancy first} |
70
+ | {Ledger} | `{machine}/ledger.ts` | {the durable row} |
71
+
72
+ ## {Stage sections — one per stage, in the order the machine runs them}
73
+
74
+ {The body, and the only genre where the section order is decided for you: the machine's own order.
75
+ Entry, then each stage, then what is written durably, then what re-drives a stalled one, then what
76
+ reads the result. Name each section for its stage in the product's own vocabulary. Within a
77
+ section, state the mechanism and its reason: what the code does, what it refuses, and why it
78
+ refuses that rather than something else. Tables for rosters (routes, columns, frames, states,
79
+ bindings); prose for a rule and the defect it prevents. Never paste an implementation — a
80
+ signature, a state list, a wire shape, a table's columns.}
81
+
82
+ ## Tests
83
+
84
+ {Optional. What proves this machine, and what each suite pins — a `Suite | Pins` table. Include it
85
+ where the machine has a suite of its own; omit the heading where the coverage lives in the package
86
+ documents' suites.}
87
+
88
+ ## Files
89
+
90
+ | Path | Role |
91
+ | --- | --- |
92
+ | `packages/{pkg}/src/{machine}/{file}.ts` | {what it holds, by name — the exports a reader is looking for} |
93
+
94
+ {One row per file this document owns — the roster is the `owns:` list, made readable. Close with
95
+ the inverse: "Read here, owned elsewhere:" naming the paths the body describes but another document
96
+ claims, each with the document that claims it. That closing line is what stops a system document
97
+ from quietly annexing the code it reads.}
98
+
99
+ ## Related
100
+
101
+ - [AD-0NN — {the ruling}](../decisions/AD-0NN-{slug}.md) — {the decision behind this shape, the options weighed}
102
+ - [`{neighbour}.md`]({neighbour}.md) — {the machine on the other side of this seam}
103
+ - [`{feature}.md`](../../features/{feature}.md) — {what a person sees of this machine}
104
+ - [`{doctrine}.md`](../common/{doctrine}.md) — {the cross-cutting contract this machine answers to}
105
+ ```
106
+
107
+ ### The boundary paragraph is the genre's load-bearing section
108
+
109
+ Systems overlap: they share tables, call each other, and render into the same surfaces. Without a
110
+ paragraph that names the seams, two system documents describe the same stage from two angles and
111
+ drift apart on the first change — and a reader has no way to tell which is authoritative. So the
112
+ boundary paragraph is not a courtesy list of related reading; it is the statement of what this
113
+ document is *not*, written specifically enough that a later editor can tell where to put a fact.
114
+ Write it as a list of subjects with their owners — "the coordinator's tables, alarm and drive claim
115
+ are `harness.md`; a run's ledger row and settlement are `generation-runs.md`" — never as bare
116
+ links.
117
+
118
+ ### Marking what is decided and unbuilt
119
+
120
+ Where the machine has a stage that is decided and not built — a predicate that selects but never
121
+ acts, a column that is written and never read, a door with no caller — wrap the prose in a marker
122
+ so the gap is machine-findable and its evidence travels with it:
123
+
124
+ ```
125
+ <!-- UNBUILT:START — {what is decided, where it is decided (an AD § or an owner ruling), and the
126
+ source evidence that it is not built: the function with no caller, the route that is not mounted,
127
+ the value written and never read} -->
128
+ {the prose describing the unbuilt stage, and what runs in its place}
129
+ <!-- UNBUILT:END -->
130
+ ```
131
+
132
+ **State what runs instead.** A machine with a hole in it still works somehow, and the workaround is
133
+ the fact a reader needs. **A design decided *against* carries no marker** — a marker means the work
134
+ is owed and absent, so using one for a rejected design turns the register of debt into a register
135
+ of opinions.
136
+
137
+ ### `status: draft` on a system
138
+
139
+ A system document is `draft` when the **machine as a whole** does not run — the code is on disk and
140
+ nothing reaches it. Say so in the first section, in plain words, with the evidence: which halves
141
+ exist, which do not, and what a reader who invokes it actually observes. A scoped gap in a working
142
+ machine is not a draft: the document stays `active` and takes an UNBUILT marker at the stage that
143
+ has the hole.
@@ -0,0 +1,71 @@
1
+ ---
2
+ name: polygraph
3
+ description: "Use when a document's truth is in question — audit a named doc, feature, folder, or code path against the code — and at every plan completion, where gate mode certifies the plan's docs before the freeze. Never the whole tree by reflex; not docs health, boundary, or the verification gate."
4
+ ---
5
+
6
+ # Polygraph — two witnesses, one verdict
7
+
8
+ Code and docs are two witnesses to the same product, and each lies in its own direction: documents describe designs the code never built, code runs behaviour no document learned. The audit checks a document's claims against the code, presumes the code correct unless a standing decision names it for retirement, corrects the document, registers the code-side findings, and puts to the owner what evidence cannot settle. It runs at two moments and nowhere else:
9
+
10
+ | Moment | Mode | Ends with |
11
+ | --- | --- | --- |
12
+ | Any time, on a named target — a doc, a feature, a folder of docs, or a code path resolved to its owning docs | **Audit** | the target corrected, code-side rows registered, verdict counts reported |
13
+ | Plan completion — after the verification gate has discharged and the Doc Obligations rows read **updated**, before the freeze | **Gate** | the same, over the plan's docs, plus the plan's `Polygraph:` segment |
14
+
15
+ You are the **primary**: you hold the conversation, compose every context pack and packet, judge every contested verdict, and write the segment. Agents sweep and apply; a verdict is never delegated, and neither is a word said to the owner.
16
+
17
+ References — read the routed file in full at the named moment:
18
+
19
+ | Reference | Load when |
20
+ | --- | --- |
21
+ | `references/rows.md` | writing or reading any row; judging CONTESTED, QUESTION, residue, or a document's right to exist |
22
+ | `references/dispatch.md` | composing a context pack, dispatching any role, packeting, recovering a dead or capped agent, pricing a run |
23
+
24
+ ## Standing rules
25
+
26
+ 1. **Code is presumed correct — unless a standing decision names it.** The precedent pack decides by **naming**: a decision condemns code only when it names the file, table, route, command, or surface by the product's own name for it, and the row quotes the naming words. A resembling thing is not a match; arguable → QUESTION. Documenting undocumented code is the mechanically easiest resolution and quietly canonizes a retiring lane; condemning on a resemblance retires code the product still ships. The full test is `references/rows.md` § The residue guard.
27
+ 2. **No citation, no row** — `file:line`, or the exact command and its result. Prove or refute, never confirm by plausibility.
28
+ **A documented behaviour the code lacks is UNBUILT, never MISDESCRIBED.** The document may be stating the target design; rewriting it to match the code silently abandons that design. Without the repo's unbuilt marker on the passage or a precedent naming the subject, the row is a QUESTION for the owner, and the passage stands until the answer.
29
+ 3. **Finders never edit; appliers never judge; the audit never edits code.** A code-side finding leaves as a register row for the planning workflow, however small and however directly it is asked for; a source fix asked for *inside* the audit is refused, registered, and answered with the one thing that would let it happen — a separate ask outside the audit. **Markdown is not source**: every document read may be edited under the applier discipline; frozen records are exempt.
30
+ 4. **The applier re-check is the gate.** Every row is re-derived against today's tree before its doc is touched; a claim that fails to reproduce dies as *did not reproduce* and never becomes an edit. This is what lets a row be applied by an agent that never saw the finder's reasoning.
31
+ 5. **Rows live on disk, never in your context.** Partials, packets, and outcomes land under `.claude/state/polygraph/{run}/`; you re-read files. The folder is machine-local and you delete it when the run closes — in the same turn as the report, **whatever is still open**: the reply carries every open row in full, an owner's answer starts a new run over those rows only, and the changelog entry of the commit is the record. Nothing under `.claude/state/polygraph/` outlives the reply.
32
+ 6. **The owner's answer is applied in the same pass** — verbatim in the doc it settles, quoted in the changelog entry's Ask line. There is no question ledger to park it in.
33
+
34
+ ## The run
35
+
36
+ Both modes run the same sequence; the modes differ only in how the target list and the closing write are derived.
37
+
38
+ 1. **Resolve the targets.** A doc path is a target; a feature name resolves to `docs/features/{feature}.md`; a folder yields every doc in it; a code path resolves through the injected ownership index to the docs whose `owns:` globs match — or, when no index is in context, by scanning the `owns:` frontmatter under the docs root. A code path with no owner is **reported, never refused** — say which paths are unowned and go on with the rest. A target with no document at all is the one refusal: there is nothing to audit.
39
+ 2. **Price it and say so** before dispatching when the target list exceeds ten documents: per-doc cost at the pinned tier, the wave count under the runtime's concurrency ceiling, and the total. An owner directive to run on a stronger tier is priced the same way — state the multiplier and record the directive in the changelog entry.
40
+ 3. **Write one context pack per doc** (`references/dispatch.md` § The context pack) — the doc's `owns:` globs, the code paths in question, the precedent quotations that name this subject, the register rows already tracking it, and the owner rulings that bind. The pack is the agent's whole reading list.
41
+ 4. **Dispatch one `polygraph-finder` per doc**, in waves under the concurrency ceiling. Each writes its partial to the run folder and returns at most 120 words. A finder that returns **partial** at its turn cap is resumed once from its partial on disk; a second partial is accepted as that doc's sweep and reported as such.
42
+ 5. **Merge and check.** Concatenate the partials into `findings.psv`, quarantine malformed lines into `malformed.txt` (kept, never silently repaired), run `scripts/audit.mjs {run}` and fix what it reports by hand.
43
+ 6. **Judge.** Read every non-COHERENT row's evidence yourself. CONTESTED rows you judge with both sets of evidence in hand; a row you doubt goes to a `polygraph-verifier` (claim and subject only) and comes back CONTESTED if the two disagree. QUESTION rows — and every proposed deletion, with its inbound count — go to the owner **now, inline**, batched and ranked by how many rows each answer unblocks; work proceeds on everything else while they are open.
44
+ 7. **Packet and apply.** One doc, one `polygraph-applier`, always — `audit.mjs` asserts no collision. MISDESCRIBED rows and in-scope UNDOCUMENTED rows that passed the residue guard go to the owning doc's packet; RESIDUE, UNBUILT-abandoned, and every code-side row go to the register (the backlog, in its existing grammar, deduped against what is already there); frozen records resolve `exempt-frozen`. Fold each applier's outcome file into row status by hand, then run `audit.mjs` again.
45
+ 8. **Run the repo's doc gates in your own seat** — lint, links, ownership — over every doc touched; a delegated gate that dies reports nothing, which reads exactly like a pass.
46
+ 9. **Report** in prose: docs audited, claims checked, corrected, registered, contested-and-judged, questions answered; the refuted-on-apply count is the quality signal, stated every time. Then delete the run folder — also when rows are still open for the owner; they are in the reply.
47
+
48
+ ## Gate mode — the closing write
49
+
50
+ Gate mode's target list is **every Doc Obligations row discharged as `updated` plus every `Spec:` doc**, and its code scope is the plan's Proposed Changes paths together with those docs' `owns:` globs. It runs after the verification gate and the Doc Obligations discharge, before `Status: Complete` is written — the freeze waits for it, and the harness's completion policy says so. The skill writes the `Polygraph:` segment and nothing else on the plan: the status flip is the author's, in the discharge-then-freeze edit.
51
+
52
+ Ends by rewriting your own segment of the plan's **`Gates:`** line, exactly:
53
+
54
+ - `Polygraph: passed YYYY-MM-DD (N docs · N claims · N corrected · N registered)` — every target swept, every non-QUESTION row resolved.
55
+ - `Polygraph: owes nothing — {reason}` — written by the plan's **author**, not by you, when the plan has no `Spec:` doc and its Doc Obligations row is `None`, or when the repo's harness ships no polygraph.
56
+
57
+ A QUESTION the owner has not answered leaves the segment at `pending`; the plan stays open, and the completion machinery says why. Never write `passed` over an open question.
58
+
59
+ ## Economy
60
+
61
+ The tier is pinned in the three agent definitions — the cheapest capable tier, low to medium effort, a turn cap — never chosen at dispatch. The strong tier's value concentrates in judgment, and every judgment in this skill is yours. Where a role agent is not installed (a runtime whose plugin channel carries skills only), dispatch an independent subagent on the cheapest capable tier with the role's body inline, and say so in the report.
62
+
63
+ ## What this skill is NOT
64
+
65
+ - **Routine docs health** — stale globs, broken links, structural drift: the `maintenance` agent.
66
+ - **A plan's contract check** — both sides of a boundary for a diff or plan: the `boundary` skill.
67
+ - **Test verification** — proving built behaviour: the `testing` skill.
68
+ - **A whole-tree audit by reflex.** The tree is audited one target at a time, and every plan certifies its own docs; a full sweep is an explicit ask, priced before it runs.
69
+ - **A code editor** — code-side findings exit as register rows (standing rule 3).
70
+
71
+ If the request is one of these, say so and redirect — don't adapt.