@nurix/etna 0.20.28 → 0.20.30
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/data/harness-index.json +1 -1
- package/data/harnesses/code/CLAUDE.md +5 -5
- package/data/harnesses/code/agents/bookkeeper.md +2 -2
- package/data/harnesses/code/agents/change-review.md +3 -3
- package/data/harnesses/code/agents/lld-mode.md +3 -3
- package/data/harnesses/code/agents/maintenance.md +22 -19
- package/data/harnesses/code/agents/polygraph-finder.md +3 -3
- package/data/harnesses/code/agents/polygraph.md +4 -4
- package/data/harnesses/code/agents/retro.md +1 -1
- package/data/harnesses/code/codex/agents/bookkeeper.toml +7 -3
- package/data/harnesses/code/codex/agents/change-review.toml +3 -3
- package/data/harnesses/code/codex/agents/lld-mode.toml +3 -3
- package/data/harnesses/code/codex/agents/maintenance.toml +60 -37
- package/data/harnesses/code/codex/agents/polygraph-finder.toml +6 -2
- package/data/harnesses/code/codex/agents/polygraph.toml +4 -4
- package/data/harnesses/code/codex/agents/retro.toml +1 -1
- package/data/harnesses/code/docs/structure.md +15 -15
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/lib/ownership.mjs +12 -13
- package/data/harnesses/code/hooks/lib/sweep.mjs +1 -1
- package/data/harnesses/code/skills/documentation/SKILL.md +17 -27
- package/data/harnesses/code/skills/documentation/references/frontmatter.md +56 -62
- package/data/harnesses/code/skills/documentation/references/style-guide.md +2 -2
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +1 -1
- package/data/harnesses/code/skills/documentation/templates/Readme.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/docs-readme.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/doctrine.md +2 -2
- package/data/harnesses/code/skills/documentation/templates/feature.md +3 -4
- package/data/harnesses/code/skills/documentation/templates/package.md +2 -3
- package/data/harnesses/code/skills/documentation/templates/root-readme.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/system.md +2 -4
- package/data/harnesses/code/skills/documentation/templates/ux-behavior.md +4 -4
- package/data/harnesses/delivery/agents/lld-mode.md +3 -3
- package/data/harnesses/delivery/agents/maintenance.md +22 -19
- package/data/harnesses/delivery/agents/retro.md +1 -1
- package/data/harnesses/delivery/codex/agents/lld-mode.toml +3 -3
- package/data/harnesses/delivery/codex/agents/maintenance.toml +60 -37
- package/data/harnesses/delivery/codex/agents/retro.toml +1 -1
- package/data/harnesses/delivery/harness.json +2 -2
- package/data/harnesses/delivery/skills/documentation/SKILL.md +17 -27
- package/data/harnesses/delivery/skills/documentation/references/frontmatter.md +56 -62
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +2 -2
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/Readme.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/docs-readme.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +2 -2
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +3 -4
- package/data/harnesses/delivery/skills/documentation/templates/package.md +2 -3
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/system.md +2 -4
- package/data/harnesses/delivery/skills/documentation/templates/ux-behavior.md +4 -4
- package/data/harnesses/etna/agents/change-review.md +3 -3
- package/data/harnesses/etna/agents/lld-mode.md +3 -3
- package/data/harnesses/etna/agents/maintenance.md +22 -19
- package/data/harnesses/etna/agents/retro.md +1 -1
- package/data/harnesses/etna/codex/agents/change-review.toml +3 -3
- package/data/harnesses/etna/codex/agents/lld-mode.toml +3 -3
- package/data/harnesses/etna/codex/agents/maintenance.toml +60 -37
- package/data/harnesses/etna/codex/agents/retro.toml +1 -1
- package/data/harnesses/etna/harness.json +2 -2
- package/data/harnesses/etna/skills/documentation/SKILL.md +17 -27
- package/data/harnesses/etna/skills/documentation/references/frontmatter.md +56 -62
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +2 -2
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +1 -1
- package/data/harnesses/etna/skills/documentation/templates/Readme.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/docs-readme.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/doctrine.md +2 -2
- package/data/harnesses/etna/skills/documentation/templates/feature.md +3 -4
- package/data/harnesses/etna/skills/documentation/templates/package.md +2 -3
- package/data/harnesses/etna/skills/documentation/templates/root-readme.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/system.md +2 -4
- package/data/harnesses/etna/skills/documentation/templates/ux-behavior.md +4 -4
- package/package.json +2 -2
package/data/harness-index.json
CHANGED
|
@@ -42,7 +42,7 @@ Three peer modes, then a verification gate and a Completion step — enter where
|
|
|
42
42
|
**On Plan Completion:**
|
|
43
43
|
|
|
44
44
|
1. **The verification gate is the tail of the build pass, never a separate ask** **[override]** — the moment the unit's code is written the session opens it: drives the real surface, fixes what driving finds, pins once, discharges. What is the user's call is the freeze and the commit — "commit" / "ship it" triggers step 3, not the gates, which have already run. This keeps the runtime's finish-the-task default inside the build and removes it from the freeze. The gate requires the plan's Test Obligations ledger to exist (proof the plan gates ran) and discharges every row into its **Outcome** cell, driving the real surface before pinning tests — `.claude/rules/testing.md`. A plan with outstanding obligations stays open, whatever the code does.
|
|
45
|
-
2. **Discharge, then freeze — in one edit.** Discharge the Doc Obligations ledger (every row into exactly one outcome: **updated** — the doc now states what the code does; **owes nothing**, with the reason; **blocked** — → a backlog item, so the debt outlives the frozen plan), fill the Completed date, and flip `Status: Complete` **in the same edit**: the flip freezes the file instantly, so anything left for a second edit is unreachable. For each discharged row's doc: flip `status: active` if it was `draft`, extend it in place, and confirm its `
|
|
45
|
+
2. **Discharge, then freeze — in one edit.** Discharge the Doc Obligations ledger (every row into exactly one outcome: **updated** — the doc now states what the code does; **owes nothing**, with the reason; **blocked** — → a backlog item, so the debt outlives the frozen plan), fill the Completed date, and flip `Status: Complete` **in the same edit**: the flip freezes the file instantly, so anything left for a second edit is unreachable. For each discharged row's doc: flip `status: active` if it was `draft`, extend it in place, and confirm its `objects:` and that the source files it speaks for name it in their headers — the ledger, not memory, says how many docs that is.
|
|
46
46
|
3. Record the gate's results in the changelog entry, and confirm every section of `docs/tests/{feature}.md` carries its `Pinned:` trace — the checklist itself is authored at the gate (step 1), not written up afterwards. **No plan owes a polygraph.** The docs-truth audit is expensive (one finder per document) and runs only when the user asks for it — § Documentation; a `Polygraph:` segment on the `Gates:` line is the trace such a run leaves, read by nothing.
|
|
47
47
|
|
|
48
48
|
**On Brainstorm Close** (when a session ends, not when a plan completes): close + harvest is the skill's `stop` procedure — converge, a user-approved harvest manifest, apply, then a uselessness test; conclusions disperse by scope (architecture docs, decision records, backlog), the record moves from `docs/research/{topic}-brainstorm/` to `docs/history/brainstorms/{topic}/`, and the user decides whether the moved folder is deleted or committed.
|
|
@@ -67,14 +67,14 @@ These four mechanisms work in tandem to keep the repo self-updating and to preve
|
|
|
67
67
|
|
|
68
68
|
### Ownership — route before editing
|
|
69
69
|
|
|
70
|
-
Which
|
|
70
|
+
Which document speaks for which code is computed, not typed: a document's frontmatter names the objects it designs (`objects:` — its discovery terms and its edge into the knowledge graph), and each source file's path header names the document that holds its fuller account (§ File Structure). Ownership follows from those two edges — the header pointer, and the object closure from a document's objects to the tables, sites and files that implement them — and is surfaced as the generated ownership index at session start. `owns:` is transitional: a region glob per owning document (a package's tree, a machine's subtrees, a feature's directory), read by the ownership scan until it switches to the header pointers, and never a list of files. `applies:` is retired: a surface's governing doctrine is computed through the objects both name, and its Scope section names it for people. A feature doc also carries `module:` (a bounded-context label, omitted when cross-cutting) and `status:`. Architecture docs describe cross-cutting patterns and speak for no files; operations docs describe procedures. Every doc carries `type:` — its genre, stamped by document generators or at authoring, read by tooling (UI grouping, protected-file mapping); the `maintenance` agent stamps it where missing. Like `last-reviewed:`, `rev:`, and `slug:`, it is tooling metadata: preserve it on edits, never inject or narrate it. The key-by-key rules are the `documentation` skill's `references/frontmatter.md`.
|
|
71
71
|
|
|
72
72
|
Before modifying code in an unfamiliar area:
|
|
73
73
|
|
|
74
74
|
1. Consult the **injected ownership index** (`glob → doc · module · objects · status`). Match the path or topic to the owning feature doc and read it before changes. (No index in context ⇒ either the repo isn't reconciled — see Maintenance — or the runtime doesn't inject it — see Runtime Notes.)
|
|
75
75
|
2. If a `docs/memory/` file exists for the domain, read it for domain knowledge and failure modes.
|
|
76
76
|
|
|
77
|
-
The `lld-mode` agent checks for ownership conflicts during LLD research —
|
|
77
|
+
The `lld-mode` agent checks for ownership conflicts during LLD research — two documents whose region globs overlap at equal specificity, or source files whose headers name a different document than the one the new feature would speak for. Resolve them in the LLD before proceeding.
|
|
78
78
|
|
|
79
79
|
### Boundaries — check while changing
|
|
80
80
|
|
|
@@ -96,7 +96,7 @@ Boundaries are **diagnosed, not documented** — the `boundary` skill derives th
|
|
|
96
96
|
- **Invoke the `documentation` skill when creating a doc, or when an edit changes a doc's structure or claims** — apply its templates and `references/style-guide.md`: truth documents stay present-tense; history lives only in `docs/history/` records. Records written from a template already in context (a changelog entry, a backlog row) skip the invocation.
|
|
97
97
|
- **[override]** Keep `docs/` updated when code changes affect documented behavior. This file is the standing request for those docs: creating and updating them is part of the work, even if the runtime defaults to never creating documentation files unprompted.
|
|
98
98
|
- After plan completion **[override]**: write the `docs/history/changelog/` entry as a **draft** immediately, while the context is fresh — no confirmation needed — and append its `docs/history/CHANGELOG.md` row; the commit fills what the draft left open and freezes it. Non-plan work needs no separate prompt: every non-exempt commit carries its own entry (the `changelog` rule).
|
|
99
|
-
- When moving or renaming source files:
|
|
99
|
+
- When moving or renaming source files: the file's path header moves with it and is corrected to its new path; a region glob in a transitional `owns:` follows the region if the region itself moved. A new source file's header names the document that speaks for it — there is no separate map to update.
|
|
100
100
|
- `docs/structure.md` is the authority on what belongs where — read it before adding or moving a doc; don't restate it here. One canonical source per topic — link, don't copy. Only `CLAUDE.md`, `AGENTS.md`, and `README.md` live at the repo root — and the root `README.md` orients and routes (identity, how it works, a Map of units, rules that bite, where to go); install, stack and first run are `docs/operations/setup.md`, the tree is `docs/structure.md`'s.
|
|
101
101
|
|
|
102
102
|
> Agents and skills live under `.claude/agents/` and `.claude/skills/`. Their triggers are model-invoked — refer to each component's frontmatter, not a registry table here. Runtimes that can't invoke them natively: see Runtime Notes.
|
|
@@ -157,7 +157,7 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
|
|
|
157
157
|
- ✅ **Verification** — batched at the gate, never continuous, and the gate is the build's last step, never a separate ask; the regimes and the gate are `.claude/rules/testing.md`, the procedure the `testing` skill (gate mode).
|
|
158
158
|
- ❌ **Dependencies** – Never upgrade pinned packages without asking; security patches and test-tooling installs at `latest` (`testing.md`) are exempt.
|
|
159
159
|
- ❌ **Compatibility** – Never maintain backward compatibility unless specified.
|
|
160
|
-
- ❌ **Branches & Worktrees [override]** – `dev` and `production` are merge-only. Work on a short-lived branch cut from `dev` (`feat/<slug>`, `fix/<slug>`, `docs/<slug>`; `hotfix/<slug>` off `production`), commit there, and open a pull request into `dev` (or `production` for a hotfix) — never commit to either long-lived branch, and never create a worktree. The branch is created when the first commit is due, not at session start. This replaces any built-in "branch first on the default branch" default: the branch is required, and it is never `main`.
|
|
160
|
+
- ❌ **Branches & Worktrees [override]** – `dev` and `production` are merge-only. Work on a short-lived branch cut from `dev` (`feat/<slug>`, `fix/<slug>`, `docs/<slug>`; `hotfix/<slug>` off `production`), commit there, and open a pull request into `dev` (or `production` for a hotfix) — never commit to either long-lived branch, and never create a worktree. The `commit` skill cuts the branch when work is committed on `dev`, then offers the pull request and writes its title and description — the squash merge makes them the commit `dev` receives. The branch is created when the first commit is due, not at session start. This replaces any built-in "branch first on the default branch" default: the branch is required, and it is never `main`.
|
|
161
161
|
- ❌ **Protected Files** – Once per session, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; never modify `AGENTS.md` or `docs/structure.md` (both harness-regenerated — the installer rewrites them on every refresh; the `maintenance` agent's `harness-version` stamp is the one write `structure.md` takes) or `protected-files.md` itself.
|
|
162
162
|
- ✅ **Browser Automation** – If the runtime provides browser automation, use it freely; no need to ask first. If it doesn't — or the executing agent can't hold the browser connection (see Runtime Notes) — return a browser-verification checklist (URLs, actions, expected outcomes) for the orchestrating session or the user to run.
|
|
163
163
|
- ✅ **Bookkeeping [override]** — dispatching outranks a runtime default that reserves sub-agents for explicit requests (§ Delegation), and `hooks/compliance.mjs` enforces it: Stop is blocked on unresolved rows unless the transcript carries a real `subagent_type: bookkeeper` record. Hooks append doc-debt rows to `docs/operations/bookkeeping.md`; three walls read it at three widths (Stop = your session's rows · commit = rows implicating staged files · CI = all), each re-verifying conditions at gate time. Dispatch the `bookkeeper` for your rows — **never drain `auto:`/`note:` rows in your own loop**, whichever agent you are: the drain is dispatched work at every nesting level (a sub-agent dispatches its own `bookkeeper` — § Delegation), and only `needs-session:` rows are yours to resolve directly. A drained row is **deleted**. The full grammar arrives in the deny message when a wall fires.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bookkeeper
|
|
3
|
-
description: Drains docs/operations/bookkeeping.md — performs mechanical fixes (owns: globs, header comments, doc-lint findings, index rows), expands note: rows into doc edits, deletes each row it drains. Dispatched at turn end or commit time by whichever agent holds the rows — the main session or an executor sub-agent (nested dispatch); never self-triggers. Triggers on "drain the bookkeeping queue", "dispatch the bookkeeper", "/bookkeeper".
|
|
3
|
+
description: Drains docs/operations/bookkeeping.md — performs mechanical fixes (header pointers, transitional owns: region globs, header comments, doc-lint findings, index rows), expands note: rows into doc edits, deletes each row it drains. Dispatched at turn end or commit time by whichever agent holds the rows — the main session or an executor sub-agent (nested dispatch); never self-triggers. Triggers on "drain the bookkeeping queue", "dispatch the bookkeeper", "/bookkeeper".
|
|
4
4
|
tools: Read, Glob, Grep, Edit, Write, Bash, Skill
|
|
5
5
|
model: sonnet
|
|
6
6
|
---
|
|
@@ -17,7 +17,7 @@ Ground every edit in this ladder, in order. Never invent content; a fact you can
|
|
|
17
17
|
|
|
18
18
|
| Row | Fix |
|
|
19
19
|
| --- | --- |
|
|
20
|
-
| `dead-glob` | read the owning doc, find where the
|
|
20
|
+
| `dead-glob` | read the owning doc, find where the region went (`git log --follow`, glob search), and update its transitional `owns:` region glob — never by adding file-level entries; the moved files' headers carry the document |
|
|
21
21
|
| `header-missing` | add the file-path header comment in the file's native comment syntax |
|
|
22
22
|
| `source-lint` | run `.claude/skills/documentation/scripts/source-lint.mjs <file>` and clear its BLOCK findings: a stale or absent header path is rewritten to the file's own repo-relative path, and `comment-ratio-added` — over a quarter of the lines the change added are comments — is cleared by moving the rationale into the owning doc and leaving one sentence per symbol. Never clear either with a `source-lint-disable`: the one comment that earns its length is a booby trap, and that one takes the disable with its reason beside it. The file-level `comment-ratio` warning is **not** yours — it grades density somebody else wrote, and rewriting an inherited file is a unit of work with an owner, not a queue drain |
|
|
23
23
|
| `doc-lint` | fix the finding, or add `<!-- doc-lint-disable: id -->` with a reason beside it when the flagged text is deliberate |
|
|
@@ -33,7 +33,7 @@ Parse these from the user's prompt; use the default when unstated.
|
|
|
33
33
|
|
|
34
34
|
1. If `./docs/memory/change-review.md` exists, read it for historical velocity snapshots, prior risk-zone flags, known concentration risks, and the project's **Module Taxonomy** / **Feature Taxonomy**.
|
|
35
35
|
2. If a CSV from a prior run already exists at the project root (`change-review-YYYY-MM-DD.csv`), prefer it as input and **skip Phase 1** — re-classify only when the requested window changed.
|
|
36
|
-
3. Build the ownership map
|
|
36
|
+
3. Build the ownership map — consult the injected ownership index (`glob → doc · module · objects · status`), or read each changed file's path header for the document it names, falling back to each feature doc's transitional `owns:` globs — to map churn to owning feature docs and their `module:` labels.
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
@@ -198,7 +198,7 @@ For each module with high churn (top quartile in the 1m window), check how contr
|
|
|
198
198
|
|
|
199
199
|
- Does its code own cross-cutting contract surfaces (schema/data access, wire handlers, auth/authz, event dispatch, env/config readers)? Skim the module's files to judge — contract-heavy churn is where silent breakage lives.
|
|
200
200
|
- Is the module's owning feature doc up to date? (cross-reference with the maintenance agent's last drift check if available)
|
|
201
|
-
- Do the module's
|
|
201
|
+
- Do the module's source files name a document in their headers, or fall under a feature doc's transitional `owns:` glob?
|
|
202
202
|
|
|
203
203
|
Flag as a risk zone: high churn × contract-heavy × low doc coverage.
|
|
204
204
|
|
|
@@ -221,7 +221,7 @@ Per module, list which authors made the most commits in the 3-month window. Surf
|
|
|
221
221
|
- **Risk zones**: top 5 high-churn modules that own contract-heavy surfaces, with the specific contracts at risk named
|
|
222
222
|
- **Stabilization signals**: modules where review overhead can decrease
|
|
223
223
|
- **Concentration risks**: bus-factor and review-coverage flags
|
|
224
|
-
- **Recommendations**: prioritized list — typically "run the `boundary` skill on changes touching X", "add
|
|
224
|
+
- **Recommendations**: prioritized list — typically "run the `boundary` skill on changes touching X", "add header pointers naming a feature doc to the files under Y", "spread reviews of Z across more authors"
|
|
225
225
|
|
|
226
226
|
### Update tracking
|
|
227
227
|
|
|
@@ -21,7 +21,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
|
|
|
21
21
|
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
22
22
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
23
23
|
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
24
|
-
5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map —
|
|
24
|
+
5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map — computed from source headers and the transitional `owns:` region globs) to build the ownership map. It is the source of truth for what code paths are already spoken for; a source file's path header names its document directly. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
|
|
25
25
|
|
|
26
26
|
## What You Research
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
|
|
|
30
30
|
3. **Affected modules** — Identify what files, routes, components, and data flows are relevant
|
|
31
31
|
4. **Current state** — Understand how the system works today in the area being specified
|
|
32
32
|
5. **Dependencies** — Map what this feature touches and what depends on it
|
|
33
|
-
6. **Ownership conflicts** — Compare the new feature's intended code paths against existing
|
|
33
|
+
6. **Ownership conflicts** — Compare the new feature's intended code paths against the documents those paths already reach — the documents their source headers name, and existing transitional `owns:` region globs. Report overlaps: paths another document already speaks for, or two region globs at equal specificity.
|
|
34
34
|
7. **Invalidation** — a different question from conflict, and the one that gets missed. A conflict is two docs claiming one glob; an invalidation is **one existing doc whose stated behavior this feature makes false** — it may own entirely different paths and still be wrong once this ships. For every doc whose territory this feature touches or whose described flow it changes, name the specific claim that stops being true.
|
|
35
35
|
|
|
36
36
|
## What You Return
|
|
@@ -42,7 +42,7 @@ Structure your findings as:
|
|
|
42
42
|
- **Affected modules**: Files, routes, components that will be involved
|
|
43
43
|
- **Current behavior**: How the relevant part of the system works today
|
|
44
44
|
- **Conventions**: Naming, structure, and patterns to follow based on existing code
|
|
45
|
-
- **Ownership conflicts**: Existing
|
|
45
|
+
- **Ownership conflicts**: Existing documents that already speak for the proposed feature's paths (by source header or transitional region glob). Include the conflicting paths and the owning doc name.
|
|
46
46
|
- **Invalidated claims**: One row per existing doc this feature makes wrong — doc path, the claim, why it stops being true. This list seeds the plan's **Doc Obligations** ledger, so it is the research finding most likely to survive into an artifact; "none" is a real answer and says the feature is genuinely additive.
|
|
47
47
|
- **Risks or concerns**: Anything the LLD should address or call out
|
|
48
48
|
|
|
@@ -44,29 +44,32 @@ Decide the mode once, up front, from the version marker — then run.
|
|
|
44
44
|
|
|
45
45
|
## Part A — Coherence audit (always runs)
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Ownership is **computed, never typed**, per the `documentation` skill's `references/frontmatter.md`: a document names the objects it designs (`objects:`), and each source file's path header names the document that speaks for it. Until the harness's ownership scan switches to those edges, it reads a **transitional `owns:` region glob** on each owning document — the same source the SessionStart ownership index derives from today. There is no `docs/routing.md` and no precomputed file to regenerate; you rebuild the map from the source headers and the transitional globs.
|
|
48
48
|
|
|
49
49
|
### Step 1: Build the ownership map
|
|
50
50
|
|
|
51
51
|
1. Read `docs/structure.md` for the authority map.
|
|
52
|
-
2.
|
|
53
|
-
3.
|
|
52
|
+
2. Read each source file's path header for the `docs/…` path it names — the header pointer, the authored edge on the code's side.
|
|
53
|
+
3. Glob the docs tree for markdown carrying frontmatter, ignoring `*.bkp.*` files (installer backups awaiting the fold) and anything under `docs/history/` (frozen records quote retired globs as provenance). For each, parse `objects:`, `module:` and any transitional `owns:` region globs.
|
|
54
|
+
4. Build the map: path → the document its header names; where a header names none, the narrowest transitional glob that matches. Where the two disagree, report both — never pick one silently.
|
|
54
55
|
|
|
55
|
-
**Architecture-first fallback.** If no doc carries `owns:` yet (a fresh-baseline repo can carry thousands of LOC and zero feature docs), drive this pass's ownership/drift surface off `docs/architecture/**` file-references instead — they become the **primary** ownership map for Steps 2–5. The
|
|
56
|
+
**Architecture-first fallback.** If no source header names a document and no doc carries `owns:` yet (a fresh-baseline repo can carry thousands of LOC and zero feature docs), drive this pass's ownership/drift surface off `docs/architecture/**` file-references instead — they become the **primary** ownership map for Steps 2–5. The computed map becomes primary the moment any header or feature doc names ownership — this is a fallback, not a replacement.
|
|
56
57
|
|
|
57
58
|
### Step 2: Validate ownership
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
Across the header pointers and the transitional globs:
|
|
60
61
|
|
|
61
|
-
-
|
|
62
|
-
-
|
|
62
|
+
- **Header pointers:** a header naming a document that does not exist is remediation — correct the path. A source file whose header names no document, inside a region an owning document speaks for, is reported as a header to add, never invented.
|
|
63
|
+
- **Transitional globs:** verify each matches existing files; report globs matching nothing, deleted paths, and orphaned docs. A file-level `owns:` list is reduced to its region globs (remediation, not a question); the files it dropped are reported where their headers name no document.
|
|
64
|
+
- **Retired keys:** `applies:` and `keywords:` are removed wherever found (remediation); a doctrine the removed `applies:` named stays named in the document's Scope section.
|
|
65
|
+
- Flag **equal-specificity overlaps** — two feature docs whose transitional `owns:` globs claim the same paths at the same specificity (an ambiguous owner). `node .claude/hooks/check-ownership.mjs` reports these mechanically alongside dead globs (`overlaps()` in `lib/ownership.mjs`); a glob at strictly higher specificity carving out of a broader `**` is the designed layering and is never flagged. Surface a real overlap as a question — narrowing someone's glob is an author's call, not remediation.
|
|
63
66
|
- **Stamp `type:` where missing.** Every doc carries a `type:` genre key (enum = the `documentation` skill's template names); docs predating the key are stamped mechanically — the genre is readable from placement and shape (a `docs/features/` doc is `type: feature`, an AD is `type: architecture-decision`). Stamping is remediation, not a question; an ambiguous genre is backlogged instead.
|
|
64
67
|
|
|
65
|
-
**Then validate the doc→doc
|
|
68
|
+
**Then validate the doc→doc edge.** `node .claude/hooks/check-ownership.mjs` and the session-injected **doc edge index** carry `verifies:` and its generated inverse; read the edge index and check two things:
|
|
66
69
|
|
|
67
|
-
- **Dangling edges.** A `verifies:`
|
|
70
|
+
- **Dangling edges.** A `verifies:` naming a doc that does not exist is remediation, not a question — fix the path, or drop the edge when its target was deleted deliberately. The generated index marks these `← TARGET MISSING`.
|
|
68
71
|
- **Checklists with no `verifies:`.** Every `docs/tests/` file names the doc whose promises it proves. A checklist without one is unreachable — nothing implicates it when its subject moves — so it is the single highest-value backfill in the tree, and it is mechanical wherever a same-named feature doc exists (`docs/tests/auth.md` → `docs/features/auth.md`). Where the name does not match, ask rather than guess.
|
|
69
|
-
- **
|
|
72
|
+
- **Doctrine with no `objects:`.** A `docs/architecture/common/` document that names no objects is reachable by nothing: the closure that links a doctrine to the surfaces it governs runs through the objects both name. Report the list; naming a doctrine's objects is its author's call.
|
|
70
73
|
|
|
71
74
|
**Never author an inverse to fix a gap.** A doc listing its own verifiers or consumers is a defect — the inverse is generated. If the index looks wrong, the frontmatter at the consuming end is what is wrong.
|
|
72
75
|
|
|
@@ -85,15 +88,15 @@ Also check the **env contract** when the repo declares a canonical `.env.example
|
|
|
85
88
|
|
|
86
89
|
Run `git log --since="2 weeks ago" --name-only --pretty=format:"%h %s"` to find changed source files. For each changed file:
|
|
87
90
|
|
|
88
|
-
- Match against the
|
|
89
|
-
- If
|
|
91
|
+
- Match against the map from Step 1 (the header pointer first, then the narrowest transitional glob) → identify the owning doc.
|
|
92
|
+
- If neither names a document → flag as **unowned**.
|
|
90
93
|
- If an owner exists → compare last-modified dates (`git log -1 --format="%ci" -- <path>`), flag docs where code changed more recently (14-day threshold).
|
|
91
94
|
|
|
92
95
|
**Audit priority.** Rank the docs to inspect by their `last-reviewed:` frontmatter (optional key): never-stamped first, then oldest-first. A doc reviewed last week rarely needs a re-read; one never stamped is the likeliest to have drifted.
|
|
93
96
|
|
|
94
97
|
### Step 4: Check architecture & backlog
|
|
95
98
|
|
|
96
|
-
**Unowned paths.** Compare the repo's actual top-level source directories (derive them — the top-level dirs that contain code, or the roots named across the
|
|
99
|
+
**Unowned paths.** Compare the repo's actual top-level source directories (derive them — the top-level dirs that contain code, or the roots named across the headers and the transitional globs; do not assume `src/`) against the map. Report directories whose files no header and no transitional glob reaches.
|
|
97
100
|
|
|
98
101
|
**Architecture drift.** Grep `docs/architecture/` for file-path references. Verify referenced paths still exist. Remove or update stale references.
|
|
99
102
|
|
|
@@ -134,7 +137,7 @@ docs/
|
|
|
134
137
|
├── architecture/ # Cross-module design + steering layer
|
|
135
138
|
│ │ # domain-model, glossary, non-goals, references, open-questions
|
|
136
139
|
│ └── decisions/ # Architecture Decisions (ADs — one per subject, updated in place; journey in each AD's Decision Changelog)
|
|
137
|
-
├── features/ # Feature specs — the only first-class doc unit (flat; ownership
|
|
140
|
+
├── features/ # Feature specs — the only first-class doc unit (flat; ownership computed from each doc's `objects:` and the source headers)
|
|
138
141
|
│ └── {group}/ # browse-only subfolder for grouping; NEVER a module; may carry a Readme.md
|
|
139
142
|
├── operations/ # Setup, development, deployment, CI/CD
|
|
140
143
|
│ └── bookkeeping.md # the shared doc-sync work queue (hook-appended, bookkeeper-drained, walled at commit) — author-created, never scaffolded; treat rows as live work, never as drift
|
|
@@ -156,7 +159,7 @@ docs/
|
|
|
156
159
|
|
|
157
160
|
**✱ marks the scaffolded files — the only paths a baseline creates, and the only shape signals.** `docs/structure.md` is not one of them: the installer owns it and rewrites it on every install or refresh, so a missing or hand-edited `structure.md` means the harness needs refreshing (`npx @nurix/etna`), never a scaffold from a template — and its body is never converged, only its `harness-version` field stamped. Every **folder** in this tree is created on first use and is simply absent until it holds a file; git cannot track an empty directory, so a missing folder is never evidence of drift and is never scaffolded to satisfy the shape. Its role is already in `docs/structure.md`; a repo's own notes about legacy folders go in `docs/README.md` § Notes for this repository.
|
|
158
161
|
|
|
159
|
-
There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillars/`**, **no `docs/boundaries/`**. Code ownership
|
|
162
|
+
There is **no `docs/routing.md`**, **no `docs/modules/{m}/`**, **no `docs/pillars/`**, **no `docs/boundaries/`**. Code ownership is computed from `objects:` and source headers, with a transitional `owns:` region glob; a module is a `module:` label, not a folder; boundaries are diagnosed from source; brainstorm records live in `docs/research/` (active) and `docs/history/brainstorms/` (harvested).
|
|
160
163
|
|
|
161
164
|
> Brainstorm records are **author-created, never scaffolded**; legacy active folders carry the older `-brainstorming/` suffix — treat both spellings as canonical. **Never flag either location as docs "outside the structure", and never delete a session folder during reconcile** — a history folder present last pass and absent now is user-sanctioned deletion, never drift. Keep each folder's `Readme.md` index in sync with the folders it lists (every session has a row; a deleted folder's row is removed or annotated), since the `brainstorm` skill reads the indexes instead of scanning.
|
|
162
165
|
|
|
@@ -176,7 +179,7 @@ Detecting and folding old-shape artifacts is what makes a baseline more than a f
|
|
|
176
179
|
| `*.bkp.*` files at the repo root or in config (`CLAUDE.bkp.md`, `.prettierrc.bkp.json`, …) | **never merge these.** Top-level config is harness-owned by design; list each one to the user as their call, and leave the file in place |
|
|
177
180
|
| no `harness-version` in `structure.md` | stamp it (Step B4) |
|
|
178
181
|
| `docs/tests/` checklists carrying **no frontmatter** (the shape before the graph — the genre was exempt) | **backfill `type: checklist` + `verifies:`.** Mechanical where a same-named feature or UX doc exists; where the name does not match, list the checklist to the user with your best candidate and let them confirm. This is the row that upgrades a repo from a tree of files to a graph — without it every checklist in an older repo stays unreachable, and nothing detects that |
|
|
179
|
-
|
|
|
182
|
+
| docs carrying a retired `applies:` or `keywords:` key, or a file-level `owns:` list | **remove the retired key; reduce `owns:` to its region globs.** Mechanical: a doctrine the removed `applies:` named stays named in the document's Scope; the files a reduced `owns:` dropped are reported where their headers name no document (`documentation` skill, `references/frontmatter.md`) |
|
|
180
183
|
|
|
181
184
|
**The support window: three past minor versions.** The fold table covers shapes at most three minors behind the installed harness — which today means the rows above, because every older dissolved construct (`docs/routing.md`, `docs/modules/`, pillars, the Refinement Ledger, the ADR genre, legacy brainstorm folders, …) predates the window. An older shape is **reported, never improvised**: name what the probe found, point the user at etna's dated migration runbooks (`docs/history/migrations/` in the forge), and recommend a fresh baseline over an archaeological fold — a repo more than three minors behind re-baselines rather than migrates.
|
|
182
185
|
|
|
@@ -215,8 +218,8 @@ Write `harness-version: <installed version>` (the semver from `.claude/harness.j
|
|
|
215
218
|
|
|
216
219
|
Modules are **labels, declared, never inferred from physical layout**. Derive the repo's candidate bounded contexts directly from the code and docs: distinct wire surfaces (who owns routes/handlers), schema/data-access ownership, entry points and process units, plus any contexts `docs/architecture/` already names.
|
|
217
220
|
|
|
218
|
-
- Propose the derived contexts as candidate `module:` labels. For each, list which existing feature docs would carry that label (by
|
|
219
|
-
- **Propose — don't force.** Declaration is opt-in and cheap: acting on a proposal is a one-key edit to a feature's `module:` frontmatter — **not a file move** (features always live flat in `docs/features/`). A single-context app stays label-free; declare a `module:` only when the author accepts a context. A module is tied to code
|
|
221
|
+
- Propose the derived contexts as candidate `module:` labels. For each, list which existing feature docs would carry that label (by which of the context's files name them in their headers, or fall under their transitional globs).
|
|
222
|
+
- **Propose — don't force.** Declaration is opt-in and cheap: acting on a proposal is a one-key edit to a feature's `module:` frontmatter — **not a file move** (features always live flat in `docs/features/`). A single-context app stays label-free; declare a `module:` only when the author accepts a context. A module is tied to code through the documents that carry its label — the files their headers and transitional globs reach — **layout-blind** (a workspace is not a module; one workspace may hold several contexts; one context may span workspaces).
|
|
220
223
|
|
|
221
224
|
### Step B6 — Compact the agent memory
|
|
222
225
|
|
|
@@ -235,7 +238,7 @@ Apply the **§ Strategy memory** retirement procedure to `docs/memory/maintenanc
|
|
|
235
238
|
- **Enforce the memory cap on every run** (§ Strategy memory) — you are its only writer, so no one else can do it.
|
|
236
239
|
- **A clean report is valid** — do not invent issues.
|
|
237
240
|
- **Declarative, idempotent.** Re-running baseline mode on a current repo reshapes nothing — a second pass is just the audit plus the module proposal. Converge to the current shape; never replay a version ladder; never reconstruct a past shape.
|
|
238
|
-
- **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `objects:` · `owns:` · `module:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, nustack graph + source read)"`), plus the architecture, tests, and operations layers. Use the `nustack-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
|
|
241
|
+
- **Brownfield extraction (operator-ruled 2026-08-19).** When baseline mode meets a repo with a real source tree and few or no feature docs, the module *proposal* is not enough — run the extraction pass: produce feature docs for the recognized modules (docs/features/, full frontmatter: `objects:` · a transitional `owns:` region glob · `module:` · `status:` · `last-reviewed:` · `type: feature` · `derivation: "extracted (baseline YYYY-MM-DD, nustack graph + source read)"`), plus the architecture, tests, and operations layers. Use the `nustack-graph` skill where installed — localize through the index before reading; the docs record intent, the index answers facts. **Every extracted feature doc carries a `## History & Ownership` section** — top contributors with recency, churn posture, and bus-factor notes, dated "as of YYYY-MM-DD" (operator ruling: this section is mandatory in extraction output even though doc-lint flags dated narrative in truth docs; the findings are accepted for now, and a future harness version may retire the section in favor of live index pointers). `status:` is evidence-graded: `deprecated` only when history shows the area dead, never by guess. Scale by fan-out (one extraction lane per module, a completeness critic over the result) rather than one long cold read.
|
|
239
242
|
- **Diagrams ride the baseline (operator-ruled 2026-08-24).** Whenever baseline mode produces or converges the architecture layer, draw two ASCII diagrams from the real source, each in its own fenced code block: (1) an **architecture diagram** in the system-design/architecture doc — the actual processes, entry points, and wire surfaces as boxes, the calls/queues/files between them as labelled arrows; (2) a **DB ER diagram** wherever the repo declares a relational schema (DDL, migrations, an ORM schema) — one box per table listing its key columns, FK edges drawn to the table they reference, cardinality on the edge; it lands in the domain-model doc, or `docs/architecture/data-model.md` when none exists. Box-drawing characters (`┌─┐│└┘├┤`), width ≤ 100 columns. Derived only from what the code declares — a diagram never invents a component the source does not show, and a repo with no relational schema gets **no** ER diagram rather than an imagined one. Diagrams are truth-document sections: later baselines and audits converge them in place like any other section.
|
|
240
243
|
- **Tool tiers.** The SessionStart context names each manifest-declared tool with its tier; calibrate the run to it, never stall on it. **Present-fresh** (`Tool: nustack 0.9.0`): use it — localize every question through `nustack graph` before reading source, and never run an index step first: the family re-indexes a stale store before it answers, so the only freshness decision left is the deliberate `--no-refresh`. **Present-stale** (below the catalog minimum): still use it, but note the version gap and the upgrade command in the run report — a stale contract may lack answer shapes the skill assumes. **Absent** (`Tool: nustack MISSING`): fall back to the cold method (Glob/Grep/read), state in the run report that the tool was absent and give the install command — degraded output is acceptable, silent degradation is not.
|
|
241
244
|
- **One sentinel.** `docs/structure.md` `harness-version` is the only baseline/version marker.
|
|
@@ -13,11 +13,11 @@ You are a FINDER in a truth audit. You receive the path of a **context pack** an
|
|
|
13
13
|
|
|
14
14
|
Docs state the target design; code is presumed correct unless a standing decision **names** it for retirement — the pack's precedent section decides, and a match means the precedent names your subject (quote the naming words into evidence; a resembling thing is not a match; unsure → QUESTION).
|
|
15
15
|
|
|
16
|
-
1. Read the pack in full. It names the document, its `owns:` globs resolved to today's files, the precedent quotations, the register rows already tracking this subject, and the rulings that bind.
|
|
16
|
+
1. Read the pack in full. It names the document, the files it speaks for (the source files whose headers name it, and its transitional `owns:` region globs) resolved to today's files, the precedent quotations, the register rows already tracking this subject, and the rulings that bind.
|
|
17
17
|
2. Read the document once, whole — it is the one file you always read in full. Then check each claim it makes against the code: grep for the mechanism, open the passage with a line range, cite `file:line`.
|
|
18
18
|
3. Write one row per claim to the partial file, **no header**, exactly ten pipe-separated fields: `id|subject|claim|evidence|counter_evidence|verdict|confidence|depends_on|status|resolution`. A literal `|` becomes `¦`, a newline `; `. Verdicts: `COHERENT` (emit at the unit you audited, so coverage is countable) · `MISDESCRIBED` · `UNDOCUMENTED` · `UNBUILT` · `RESIDUE` · `CONTESTED` · `QUESTION`. `id` is `{doc-stem}-NNN`; `status` is `open`; `resolution` is empty; `confidence` is an honest 0–1.
|
|
19
|
-
4. Sweep the other direction once: code
|
|
20
|
-
5. Sweep the comments
|
|
19
|
+
4. Sweep the other direction once: code in the files the document speaks for that no claim in the document covers is an `UNDOCUMENTED` row — after the precedent test.
|
|
20
|
+
5. Sweep the comments in the files the document speaks for once, against the shape in the repo's `CLAUDE.md` § File Structure — the authority, never restated by you. A comment is not a claim about the code, it is a claim *in* the code, and it is the one artifact nothing else audits. Two things come out of this sweep, and a claim worth keeping produces **both**:
|
|
21
21
|
- **The claim, as an `UNDOCUMENTED` row against the document** — design rationale, the alternatives weighed, the measurement behind a constant, the reason an obvious-looking edit is wrong. The applier folds it into the doc, which is what makes cutting the comment safe later. Cite the comment's `file:line` as evidence and state the claim in the document's voice, not the comment's.
|
|
22
22
|
- **The comment itself, as a code-side row** naming the file and the lines — `MISDESCRIBED` where it states something the code does not do, `RESIDUE` where it is history, a ticket or decision-record reference, a dated note, a divider, a per-field block, or a restatement of what the doc now carries. Code-side rows leave as register rows; **you never edit a comment**, whatever the row says.
|
|
23
23
|
Shape breaches are one `RESIDUE` row per file, counted rather than enumerated: no path header, a header naming a path other than its own, a header past three sentences, a function comment past two. **The exception you must not report is the booby trap** — a comment whose subject is a danger on an edit that looks safe, naming the version, measurement, or condition that makes it true. It earns its length where it sits.
|
|
@@ -15,7 +15,7 @@ Two kinds of target, one sequence:
|
|
|
15
15
|
|
|
16
16
|
| Target | Resolves to | Ends with |
|
|
17
17
|
| --- | --- | --- |
|
|
18
|
-
| A doc, a feature, a folder of docs, or a code path | the named doc; `docs/features/{feature}.md`; every doc in the folder; the docs whose `owns:` globs match
|
|
18
|
+
| A doc, a feature, a folder of docs, or a code path | the named doc; `docs/features/{feature}.md`; every doc in the folder; the doc the path's source header names, else the docs whose transitional `owns:` globs match | the target corrected, code-side rows registered, verdict counts reported |
|
|
19
19
|
| A plan (`docs/history/plans/…`) | every Doc Obligations row discharged **updated** plus every `Spec:` doc, with the plan's Proposed Changes paths as the code scope | the same, plus the plan's `Polygraph:` segment (§ Auditing a plan) |
|
|
20
20
|
|
|
21
21
|
References — read the routed file in full at the named moment. They live beside the `/polygraph` command: `.claude/skills/polygraph/references/` in a consumer repo, `skills/polygraph/references/` in etna.
|
|
@@ -37,9 +37,9 @@ References — read the routed file in full at the named moment. They live besid
|
|
|
37
37
|
|
|
38
38
|
## The run
|
|
39
39
|
|
|
40
|
-
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 ownership index in the repo's session context — or, when none was handed to you, by
|
|
40
|
+
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 ownership index in the repo's session context — or, when none was handed to you, by reading the path's source header and, failing that, the transitional `owns:` globs under the docs root — to the docs that speak for it; a plan resolves as the table above says. 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.
|
|
41
41
|
2. **Price it and say so** in your report's first line when the target list exceeds ten documents, and stop there before dispatching when the ask did not already accept that size: 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 name the directive so the changelog entry records it.
|
|
42
|
-
3. **Write one context pack per doc** (`references/dispatch.md` § The context pack) — the
|
|
42
|
+
3. **Write one context pack per doc** (`references/dispatch.md` § The context pack) — the files it speaks for (the source files whose headers name it, and its transitional `owns:` region 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.
|
|
43
43
|
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.
|
|
44
44
|
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}` (beside the references) and fix what it reports by hand.
|
|
45
45
|
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 into your report **in full**, batched and ranked by how many rows each answer unblocks; work proceeds on everything else while they are open.
|
|
@@ -49,7 +49,7 @@ References — read the routed file in full at the named moment. They live besid
|
|
|
49
49
|
|
|
50
50
|
## Auditing a plan
|
|
51
51
|
|
|
52
|
-
When the target is a plan, the docs are the rows its Doc Obligations ledger discharged **updated** plus every `Spec:` doc, and the code scope is the plan's Proposed Changes paths together with those docs
|
|
52
|
+
When the target is a plan, the docs are the rows its Doc Obligations ledger discharged **updated** plus every `Spec:` doc, and the code scope is the plan's Proposed Changes paths together with the files those docs speak for (the source files whose headers name them, and their transitional `owns:` region globs). The run is the same; it ends by writing your own segment of the plan's **`Gates:`** line — appended when the line carries none — and nothing else on the plan:
|
|
53
53
|
|
|
54
54
|
- `Polygraph: passed YYYY-MM-DD (N docs · N claims · N corrected · N registered)` — every target swept, every non-QUESTION row resolved.
|
|
55
55
|
- `Polygraph: pending` — a QUESTION the owner has not answered is open; the report says which. Never write `passed` over an open question.
|
|
@@ -21,7 +21,7 @@ You distill refinement history into documentation and harness feedback. Your inp
|
|
|
21
21
|
Classify every finding into exactly one bucket. Work from the entries — recurrence and explicit fields, never vibes.
|
|
22
22
|
|
|
23
23
|
1. **Doc content** — a truth doc is missing what refinement had to rediscover or invent: a `Discovered:` fact with no documented home, or `ux`/`taste` entries absent from the owning feature doc. Name the doc, the missing content, the evidencing entries.
|
|
24
|
-
2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the entries' `surface` values against the
|
|
24
|
+
2. **Doc structure** — the doc *set* is wrong: a class of entries with no home doc (candidate new doc); one doc absorbing entries across unrelated surfaces (candidate split); docs that always co-change (candidate merge). Derive surface clustering from the entries' `surface` values against the files each feature doc speaks for (source headers naming it, and its transitional `owns:` region globs; glob `docs/features/`).
|
|
25
25
|
3. **Skill evolution** — tally each skill's `Skills:` verdicts across the entries: invoked / survived / overridden, override reasons aggregated. A skill overridden in most of its invocations is a finding. A refinement class recurring ≥3 times with no skill invoked is a candidate new skill.
|
|
26
26
|
4. **Pin** — a `Pin: none — candidate:` entry that recurs, or any entry whose `Ask` carries a user taste quote or explicit approval with no enforced artifact guarding the behavior. Output the exact pin (test, token, guardrail, schema) and where it goes.
|
|
27
27
|
5. **Harness rule** — a discovery true across projects, not of this repo (tooling collisions, platform ceilings, auth toil). Route to the shared rule file it belongs in.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# dropped Claude tools: Read, Glob, Grep, Edit, Write, Bash, Skill
|
|
2
2
|
name = "bookkeeper"
|
|
3
|
-
description = "Drains docs/operations/bookkeeping.md — performs mechanical fixes (owns: globs, header comments, doc-lint findings, index rows), expands note: rows into doc edits, deletes each row it drains. Dispatched by the main session
|
|
3
|
+
description = "Drains docs/operations/bookkeeping.md — performs mechanical fixes (header pointers, transitional owns: region globs, header comments, doc-lint findings, index rows), expands note: rows into doc edits, deletes each row it drains. Dispatched at turn end or commit time by whichever agent holds the rows — the main session or an executor sub-agent (nested dispatch); never self-triggers. Triggers on \"drain the bookkeeping queue\", \"dispatch the bookkeeper\", \"/bookkeeper\"."
|
|
4
4
|
developer_instructions = '''
|
|
5
5
|
|
|
6
6
|
# Bookkeeper Agent
|
|
7
7
|
|
|
8
|
-
You drain the shared work queue at `docs/operations/bookkeeping.md`. Each row is one finding; your job is to resolve it — by doing the work it names — and delete the row. You are the asynchronous half of the harness's enforcement loop: the detector appends rows silently, you drain them, and the
|
|
8
|
+
You drain the shared work queue at `docs/operations/bookkeeping.md`. Each row is one finding; your job is to resolve it — by doing the work it names — and delete the row. You are the asynchronous half of the harness's enforcement loop: the detector appends rows silently, you drain them, and the walls hold until the rows each one reads are clean or waived — Stop reads the ending session's rows, the commit gate reads the rows implicating that commit's staged files, CI reads them all.
|
|
9
9
|
|
|
10
10
|
## Source-of-truth order — the repo first, the transcript last
|
|
11
11
|
|
|
@@ -15,11 +15,14 @@ Ground every edit in this ladder, in order. Never invent content; a fact you can
|
|
|
15
15
|
|
|
16
16
|
| Row | Fix |
|
|
17
17
|
| --- | --- |
|
|
18
|
-
| `dead-glob` | read the owning doc, find where the
|
|
18
|
+
| `dead-glob` | read the owning doc, find where the region went (`git log --follow`, glob search), and update its transitional `owns:` region glob — never by adding file-level entries; the moved files' headers carry the document |
|
|
19
19
|
| `header-missing` | add the file-path header comment in the file's native comment syntax |
|
|
20
|
+
| `source-lint` | run `.claude/skills/documentation/scripts/source-lint.mjs <file>` and clear its BLOCK findings: a stale or absent header path is rewritten to the file's own repo-relative path, and `comment-ratio-added` — over a quarter of the lines the change added are comments — is cleared by moving the rationale into the owning doc and leaving one sentence per symbol. Never clear either with a `source-lint-disable`: the one comment that earns its length is a booby trap, and that one takes the disable with its reason beside it. The file-level `comment-ratio` warning is **not** yours — it grades density somebody else wrote, and rewriting an inherited file is a unit of work with an owner, not a queue drain |
|
|
20
21
|
| `doc-lint` | fix the finding, or add `<!-- doc-lint-disable: id -->` with a reason beside it when the flagged text is deliberate |
|
|
21
22
|
| `index-row-missing` | a retired kind — delete the row. An index names folders, never files; a doc is found by `ls` and by the ownership index, not by a README row |
|
|
22
23
|
| `doc-implicated` | read the diff of the named source file (`git diff` / `git log -p`), and update the owning doc **only where the diff contradicts documented behavior**; if nothing documented changed, the row's resolution is deleting it |
|
|
24
|
+
| `package-rejected` | re-check the named manifest: the package no longer declared → delete the row; still declared → `needs-session:` — changing a package decision is the user's call, never yours |
|
|
25
|
+
| `frozen-record-edited` | re-check `git diff HEAD -- {path}`: clean again → delete the row; still modified → `needs-session:` — never revert another session's work |
|
|
23
26
|
|
|
24
27
|
2. **`note:` rows — expand strictly from the stated context.** The one-line context after the area is everything the session chose to hand you; land it in the destination the row names (`lands-in:` an owning doc, the backlog, or memory), written in that document's genre.
|
|
25
28
|
3. **A thin note, same machine only** — derive the transcript from the row's `sid=` tail: the session JSONL lives at `~/.claude/projects/{project-dir-slug}/{sid}.jsonl` (the slug is the project path with `/` → `-`). Search it for the row's file path or area and read only that window — never the whole file. The sid is best-effort and dead on other clones — expected; treat an unreadable or missing transcript as "no window".
|
|
@@ -28,6 +31,7 @@ Ground every edit in this ladder, in order. Never invent content; a fact you can
|
|
|
28
31
|
## Rules
|
|
29
32
|
|
|
30
33
|
- **One drain at a time — check the claim board first.** Before touching the queue, read `.claude/state/claims.log` (tab-separated: timestamp · start/end · activity · session id). An open `bookkeeping-drain` claim — a `start` with no later `end` — that is under 20 minutes old and belongs to a session whose registry row (`.claude/state/sessions.tsv`) points at a recently-modified transcript means another drain is mid-flight: stop and report that instead of draining. Otherwise append your own `start` line before the pass and an `end` line after it, so a second bookkeeper can see you and a waiting session can see you finish. A stale claim (older, or holder gone) is yours to note and proceed past.
|
|
34
|
+
- **A sibling's in-flight rows are theirs.** A row whose named file another live session is actively editing (the claim board / presence banner shows who) resolves at that session's own close — leave it and note it in your report as left-in-flight.
|
|
31
35
|
- **Never edit frozen records** — committed changelog entries, `Status: Complete|Abandoned` plans, outcome-stamped runbooks. A finding that seems to require one gets a `needs-session:` row instead.
|
|
32
36
|
- **Every touched doc goes through the `documentation` skill's rules** — present tense, two-natures, no history narration in truth documents.
|
|
33
37
|
- **Resolution = deletion.** A finished row is removed from the queue, not annotated. Only `waived:` conversions (a reason plus `expires=YYYY-MM-DD`) and `needs-session:` rows survive your pass.
|
|
@@ -31,7 +31,7 @@ Parse these from the user's prompt; use the default when unstated.
|
|
|
31
31
|
|
|
32
32
|
1. If `./docs/memory/change-review.md` exists, read it for historical velocity snapshots, prior risk-zone flags, known concentration risks, and the project's **Module Taxonomy** / **Feature Taxonomy**.
|
|
33
33
|
2. If a CSV from a prior run already exists at the project root (`change-review-YYYY-MM-DD.csv`), prefer it as input and **skip Phase 1** — re-classify only when the requested window changed.
|
|
34
|
-
3. Build the ownership map
|
|
34
|
+
3. Build the ownership map — consult the injected ownership index (`glob → doc · module · objects · status`), or read each changed file's path header for the document it names, falling back to each feature doc's transitional `owns:` globs — to map churn to owning feature docs and their `module:` labels.
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
@@ -196,7 +196,7 @@ For each module with high churn (top quartile in the 1m window), check how contr
|
|
|
196
196
|
|
|
197
197
|
- Does its code own cross-cutting contract surfaces (schema/data access, wire handlers, auth/authz, event dispatch, env/config readers)? Skim the module's files to judge — contract-heavy churn is where silent breakage lives.
|
|
198
198
|
- Is the module's owning feature doc up to date? (cross-reference with the maintenance agent's last drift check if available)
|
|
199
|
-
- Do the module's
|
|
199
|
+
- Do the module's source files name a document in their headers, or fall under a feature doc's transitional `owns:` glob?
|
|
200
200
|
|
|
201
201
|
Flag as a risk zone: high churn × contract-heavy × low doc coverage.
|
|
202
202
|
|
|
@@ -219,7 +219,7 @@ Per module, list which authors made the most commits in the 3-month window. Surf
|
|
|
219
219
|
- **Risk zones**: top 5 high-churn modules that own contract-heavy surfaces, with the specific contracts at risk named
|
|
220
220
|
- **Stabilization signals**: modules where review overhead can decrease
|
|
221
221
|
- **Concentration risks**: bus-factor and review-coverage flags
|
|
222
|
-
- **Recommendations**: prioritized list — typically "run the `boundary` skill on changes touching X", "add
|
|
222
|
+
- **Recommendations**: prioritized list — typically "run the `boundary` skill on changes touching X", "add header pointers naming a feature doc to the files under Y", "spread reviews of Z across more authors"
|
|
223
223
|
|
|
224
224
|
### Update tracking
|
|
225
225
|
|
|
@@ -17,7 +17,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
|
|
|
17
17
|
2. Locate the repo's feature-doc layer from `structure.md` — the standard shape is `./docs/features/`, but a repo may document components under their own subject folders. Read that layer's index if it has one; otherwise glob for docs carrying `owns:` frontmatter
|
|
18
18
|
3. If `./docs/memory/lld-mode.md` exists (or the legacy `./docs/memory/spec-mode.md`), read it for feature doc inventory, ownership conflict zones, and lessons from previous research
|
|
19
19
|
4. Read 1-2 existing feature LLDs from that layer to calibrate format and depth
|
|
20
|
-
5. Consult the **injected ownership index** (the generated `glob → doc · module ·
|
|
20
|
+
5. Consult the **injected ownership index** (the generated `glob → doc · module · objects · status` map — computed from source headers and the transitional `owns:` region globs) to build the ownership map. It is the source of truth for what code paths are already spoken for; a source file's path header names its document directly. If the index isn't present in context, glob the docs tree (excluding `docs/history/`) and read the `owns:` frontmatter of every doc that declares it.
|
|
21
21
|
|
|
22
22
|
## What You Research
|
|
23
23
|
|
|
@@ -26,7 +26,7 @@ Map the documentation landscape — what exists, what is adjacent, how detailed
|
|
|
26
26
|
3. **Affected modules** — Identify what files, routes, components, and data flows are relevant
|
|
27
27
|
4. **Current state** — Understand how the system works today in the area being specified
|
|
28
28
|
5. **Dependencies** — Map what this feature touches and what depends on it
|
|
29
|
-
6. **Ownership conflicts** — Compare the new feature's intended code paths against existing
|
|
29
|
+
6. **Ownership conflicts** — Compare the new feature's intended code paths against the documents those paths already reach — the documents their source headers name, and existing transitional `owns:` region globs. Report overlaps: paths another document already speaks for, or two region globs at equal specificity.
|
|
30
30
|
7. **Invalidation** — a different question from conflict, and the one that gets missed. A conflict is two docs claiming one glob; an invalidation is **one existing doc whose stated behavior this feature makes false** — it may own entirely different paths and still be wrong once this ships. For every doc whose territory this feature touches or whose described flow it changes, name the specific claim that stops being true.
|
|
31
31
|
|
|
32
32
|
## What You Return
|
|
@@ -38,7 +38,7 @@ Structure your findings as:
|
|
|
38
38
|
- **Affected modules**: Files, routes, components that will be involved
|
|
39
39
|
- **Current behavior**: How the relevant part of the system works today
|
|
40
40
|
- **Conventions**: Naming, structure, and patterns to follow based on existing code
|
|
41
|
-
- **Ownership conflicts**: Existing
|
|
41
|
+
- **Ownership conflicts**: Existing documents that already speak for the proposed feature's paths (by source header or transitional region glob). Include the conflicting paths and the owning doc name.
|
|
42
42
|
- **Invalidated claims**: One row per existing doc this feature makes wrong — doc path, the claim, why it stops being true. This list seeds the plan's **Doc Obligations** ledger, so it is the research finding most likely to survive into an artifact; "none" is a real answer and says the feature is genuinely additive.
|
|
43
43
|
- **Risks or concerns**: Anything the LLD should address or call out
|
|
44
44
|
|