@nurix/etna 0.19.54 → 0.19.56

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 (68) hide show
  1. package/data/harness-index.json +1 -1
  2. package/data/harnesses/apollo/CLAUDE.md +29 -30
  3. package/data/harnesses/apollo/harness.json +1 -1
  4. package/data/harnesses/apollo/hooks/approved-packages.md +42 -0
  5. package/data/harnesses/apollo/hooks/compliance.mjs +11 -6
  6. package/data/harnesses/apollo/hooks/lib/ownership.mjs +11 -1
  7. package/data/harnesses/apollo/rules/changelog.md +7 -1
  8. package/data/harnesses/apollo/rules/cloudflare.md +167 -0
  9. package/data/harnesses/apollo/rules/database.md +1 -125
  10. package/data/harnesses/apollo/rules/frontend.md +2 -4
  11. package/data/harnesses/apollo/rules/general.md +20 -42
  12. package/data/harnesses/apollo/rules/nomenclature.md +2 -6
  13. package/data/harnesses/apollo/rules/pnpm.md +2 -2
  14. package/data/harnesses/apollo/rules/testing.md +44 -3
  15. package/data/harnesses/apollo/skills/documentation/references/instruction-style.md +1 -0
  16. package/data/harnesses/apollo/skills/documentation/templates/plan.md +4 -4
  17. package/data/harnesses/apollo/skills/schema-design/SKILL.md +171 -0
  18. package/data/harnesses/apollo/skills/test/SKILL.md +104 -0
  19. package/data/harnesses/apollo/skills/testing/SKILL.md +100 -29
  20. package/data/harnesses/code/CLAUDE.md +29 -30
  21. package/data/harnesses/code/harness.json +1 -1
  22. package/data/harnesses/code/hooks/approved-packages.md +42 -0
  23. package/data/harnesses/code/hooks/compliance.mjs +11 -6
  24. package/data/harnesses/code/hooks/lib/ownership.mjs +11 -1
  25. package/data/harnesses/code/rules/changelog.md +7 -1
  26. package/data/harnesses/code/rules/cloudflare.md +167 -0
  27. package/data/harnesses/code/rules/database.md +1 -125
  28. package/data/harnesses/code/rules/frontend.md +2 -4
  29. package/data/harnesses/code/rules/general.md +20 -42
  30. package/data/harnesses/code/rules/nomenclature.md +2 -6
  31. package/data/harnesses/code/rules/pnpm.md +2 -2
  32. package/data/harnesses/code/rules/testing.md +44 -3
  33. package/data/harnesses/code/skills/documentation/references/instruction-style.md +1 -0
  34. package/data/harnesses/code/skills/documentation/templates/plan.md +4 -4
  35. package/data/harnesses/code/skills/schema-design/SKILL.md +171 -0
  36. package/data/harnesses/code/skills/test/SKILL.md +104 -0
  37. package/data/harnesses/code/skills/testing/SKILL.md +100 -29
  38. package/data/harnesses/delivery/CLAUDE.md +13 -1
  39. package/data/harnesses/delivery/harness.json +1 -1
  40. package/data/harnesses/delivery/hooks/generate-ownership-index.mjs +39 -4
  41. package/data/harnesses/delivery/rules/changelog.md +7 -1
  42. package/data/harnesses/delivery/rules/nomenclature.md +2 -6
  43. package/data/harnesses/delivery/skills/documentation/references/instruction-style.md +1 -0
  44. package/data/harnesses/delivery/skills/documentation/templates/plan.md +4 -4
  45. package/data/harnesses/discover/CLAUDE.md +14 -1
  46. package/data/harnesses/discover/harness.json +1 -1
  47. package/data/harnesses/discussion/CLAUDE.md +4 -2
  48. package/data/harnesses/discussion/harness.json +1 -1
  49. package/data/harnesses/etna/CLAUDE.md +14 -2
  50. package/data/harnesses/etna/harness.json +1 -1
  51. package/data/harnesses/etna/hooks/generate-ownership-index.mjs +39 -4
  52. package/data/harnesses/etna/rules/changelog.md +7 -1
  53. package/data/harnesses/etna/rules/general.md +20 -42
  54. package/data/harnesses/etna/rules/nomenclature.md +2 -6
  55. package/data/harnesses/etna/rules/testing.md +44 -3
  56. package/data/harnesses/etna/skills/documentation/references/instruction-style.md +1 -0
  57. package/data/harnesses/etna/skills/documentation/templates/plan.md +4 -4
  58. package/data/harnesses/hr/CLAUDE.md +8 -3
  59. package/data/harnesses/hr/harness.json +1 -1
  60. package/data/harnesses/kb-agi/CLAUDE.md +8 -2
  61. package/data/harnesses/kb-agi/harness.json +1 -1
  62. package/package.json +2 -2
  63. package/data/harnesses/apollo/rules/express.md +0 -33
  64. package/data/harnesses/apollo/rules/verification.md +0 -67
  65. package/data/harnesses/apollo/skills/test-plan/SKILL.md +0 -85
  66. package/data/harnesses/code/rules/express.md +0 -33
  67. package/data/harnesses/code/rules/verification.md +0 -67
  68. package/data/harnesses/code/skills/test-plan/SKILL.md +0 -85
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: test
3
+ description: Test Runner using Chrome DevTools Protocol (CDP). Run UI tests with Claude-in-Chrome browser automation. Triggers include: "run my tests", "run the test suite", "execute tests", "test this code", "check if tests pass".
4
+ argument-hint: [test-name]
5
+ ---
6
+
7
+ # Test Runner (CDP)
8
+
9
+ Run UI tests using Claude-in-Chrome browser automation.
10
+
11
+ ## Prerequisites
12
+
13
+ Complete these steps before executing test assertions:
14
+
15
+ ### 1. Load Credentials
16
+
17
+ Read `tests/.env` for: `TEST_USER_EMAIL`, `TEST_USER_PASSWORD`, `TEST_BASE_URL`, `TEST_APP_ID`
18
+
19
+ - `TEST_USER_EMAIL` / `TEST_USER_PASSWORD`: credentials used to log in during browser setup.
20
+ - `TEST_BASE_URL`: the root URL the browser will navigate to (e.g. `http://localhost:3000`).
21
+ - `TEST_APP_ID` _(optional)_: an application or workspace identifier passed to tests that need to target a specific app instance. When unset, tests run against the default app/workspace returned by the base URL.
22
+
23
+ If the file is missing, instruct user to copy `tests/.env.example` to `tests/.env`.
24
+
25
+ ### 2. Connect to Chrome
26
+
27
+ ```
28
+ mcp__claude-in-chrome__tabs_context_mcp with createIfEmpty: true
29
+ ```
30
+
31
+ If connection fails: Install Claude-in-Chrome extension, ensure Chrome is running.
32
+
33
+ ### 3. Setup Browser
34
+
35
+ ```
36
+ mcp__claude-in-chrome__tabs_create_mcp
37
+ ```
38
+
39
+ Navigate to `${TEST_BASE_URL}`. Login if required using credentials from step 1.
40
+
41
+ ### 4. Verify Ready State
42
+
43
+ Confirm main dashboard is visible before proceeding.
44
+
45
+ ## Execution
46
+
47
+ 1. **Locate test file**: `.github/docs/tests/<test-name>.md`
48
+ 2. **Validate exists**: If not found, list available tests in `.github/docs/tests/`. If that directory does not exist, search for common test patterns: `*.test.*`, `*.spec.*`, `__tests__/`, `test/`, `tests/` directories, or check `package.json` for a `test` script to determine how tests should be run.
49
+ 3. **Create results file**: `tests/claude-runs/<test-name>-<YYYY-MM-DD-HHmmss>.md`
50
+ 4. **Execute sequentially**: Update checkboxes as you go
51
+ 5. **Save results**: Write completed file with summary header
52
+
53
+ ## Checkbox Markers
54
+
55
+ | Marker | Meaning |
56
+ | ------ | ----------------------------------- |
57
+ | `[x]` | Passed |
58
+ | `[!]` | Failed - add `**FAILED**: <reason>` |
59
+ | `[-]` | Skipped |
60
+ | `[ ]` | Not run |
61
+
62
+ ## Results Template
63
+
64
+ ```markdown
65
+ # Test Results: <Test Name>
66
+
67
+ ## Execution Summary
68
+
69
+ | Property | Value |
70
+ | ----------- | ------------------------------- |
71
+ | Test File | `<path>` |
72
+ | Executed At | `<YYYY-MM-DD HH:mm:ss>` |
73
+ | Status | `PASSED` / `FAILED` / `PARTIAL` |
74
+
75
+ ## Results Overview
76
+
77
+ | Metric | Count |
78
+ | ---------------- | ----- |
79
+ | Total Assertions | X |
80
+ | Passed | X |
81
+ | Failed | X |
82
+ | Skipped | X |
83
+
84
+ ## Failed Assertions Summary
85
+
86
+ - Section X.X: <failure description>
87
+
88
+ ---
89
+
90
+ ## Test: <Original Title>
91
+
92
+ ... (test content with updated checkboxes)
93
+ ```
94
+
95
+ ## Error Handling
96
+
97
+ - **Network errors**: Retry once, then mark failed
98
+ - **Timeout**: Mark failed with timeout note
99
+ - **Element not found**: Screenshot, mark failed, continue
100
+ - **Browser disconnect**: Stop, save partial results, inform user
101
+
102
+ ## Screenshots
103
+
104
+ Take screenshots: before each major section, on failures, after completion.
@@ -1,15 +1,69 @@
1
1
  ---
2
2
  name: testing
3
- description: "Use when deciding where tests live — designing a package's test architecture, laying out a new suite, placing a new test, or judging whether an existing test is at the right altitude. Layered test strategy: derives which ownership layers an application has, what each layer owns and may assert, and the technology class per layer. Use it whenever a testing strategy, test pyramid, coverage plan, or 'should this be a unit/integration/e2e test' question comes up, even if the word 'layer' is never said. Triggers on 'testing strategy', 'test architecture', 'test layers', 'where should this test live'."
3
+ description: "The test-lifecycle skill — three modes. Plan-gate mode: after `boundary` passes, derives the tests a plan owes and writes the Test Obligations ledger into the plan (a row per behavior: layer, target file, oracle, fixtures); writes no test files. Placement mode: layered test strategy — which ownership strata the application has, where a test lives and what it may assert; use for any testing-strategy, test-architecture, test-pyramid, or 'unit/integration/e2e?' question, even if 'layer' is never said. Gate mode: executes the verification gate — derives the behavioral checklist, drives the real surface (browser automation, the real CLI, HTTP; the `/test` runner where wired), pins durable behaviors, discharges every ledger row. Triggers on 'test plan', 'testing strategy', 'test architecture', 'test layers', 'where should this test live', 'run the verification gate'."
4
4
  ---
5
5
 
6
- # Layered Test Strategy
6
+ # Testing — Ledger, Layers, Gate
7
7
 
8
- You decide **where a test lives and what it may assert**. Not *when* tests are written — that is `.claude/rules/verification.md` — and not *which framework* — that is `.claude/rules/testing.md`'s per-stack table. This skill owns the layer model those two rules leave open: the strata, their responsibilities, and the derivation of which strata a given application has.
8
+ One skill owns the test lifecycle's three procedural moments; the standing constraints (regimes, deferral, gate preconditions) are `.claude/rules/testing.md` and are never restated here. Pick the mode from the moment:
9
9
 
10
- **The litmus is "where can this defect originate?"** A test lives with the only layer that can produce the defect it catches. "The 409 response carries the current body" can only break in a route handler — service-contract layer. "The buffer the user typed survives the 409" can only break in component state — component layer. Same feature, two owners, two tests, zero overlap. Placement is decided by this question alone, never by which surface the author happened to be looking at — testing a feature wherever you first *see* it is what makes suites flat, duplicative, and multiplicative in cost.
10
+ | Moment | Mode |
11
+ | --- | --- |
12
+ | Plan gate, after `boundary` passes | **Plan-gate** — derive what the plan owes |
13
+ | A strategy / placement / altitude question, or laying out a suite | **Placement** — derive the strata, place the tests |
14
+ | The user triggers the verification gate | **Gate** — drive, pin, discharge |
15
+
16
+ ---
17
+
18
+ ## Plan-gate mode — the Test Obligations ledger
19
+
20
+ You derive the tests an implementation plan owes and pin them into the plan as an explicit, reviewable manifest — at the same gate `boundary` runs, ordered second. You never write a test file; you write the **ledger gate mode discharges**, so the gate proves a checklist instead of a vibe.
21
+
22
+ **The litmus is "which promise, at which altitude, proven by what?"** A plan promises behavior; each promise earns exactly one test at the cheapest layer that can actually prove it. Spend your reading deciding the *layer* and the *oracle*, not on prose. Writing tests *before* the code exists fabricates implementation coupling or leaves the suite red for the plan's duration; writing them *during* the build loop taxes every iteration — so the plan gate emits obligations, the loop stays free of test files, and gate mode discharges the manifest in one pass.
23
+
24
+ ### Contract sources
25
+
26
+ - **The plan's Proposed Changes** — each file/entity/API change is a behavior that may owe a test.
27
+ - **The owning LLD** (`docs/features/{feature}.md`, via the ownership index) — every obligation names the LLD promise it proves; the LLD is referenced, never restated. This one-directional chain (LLD → manifest → tests + Completion checklist) is what stops the artifacts drifting.
28
+ - **`.claude/rules/testing.md`** — frameworks and canonical placement per stack; target paths come from there, never invented. The repo's existing runner always wins.
29
+ - **`boundary`'s output** — a HIGH/CRITICAL finding is itself a behavior owed a regression test. Fold boundary's amendments first, then read the amended plan.
30
+
31
+ ### Layer assignment
32
+
33
+ Assign each behavior the **cheapest layer that can prove it**, then name the oracle. The ledger altitudes are `unit` / `component` / `integration` / `e2e` (strata mapping: § Bridge below); **integration is the default for server behavior** — a route/handler against a real in-memory datastore via the app instance. Error paths, races, and idempotency are obligations too, and belong at **integration** with injected faults (network mock, fake timers, forced constraint) — never e2e.
34
+
35
+ **The e2e altitude gate:** an e2e obligation is earned **only** when the behavior genuinely spans processes no single-process test can exercise together. Density is one scenario per cross-process journey, not per feature — prefer **"extend scenario `<name>`"** over **"new scenario"**. **Refuse to emit any e2e obligation while the project's e2e smoke gate is not wired in CI** — emit a **blocked** row naming the missing gate instead.
36
+
37
+ ### Run (plan-gate)
38
+
39
+ **Input:** a plan path (given, or the newest in `docs/history/plans/`), boundary-checked with amendments folded; skipped on a boundary BLOCK. For a non-plan diff, the hunks stand in for Proposed Changes but the obligations are paid **immediately** — only a plan has a ledger to defer into.
40
+
41
+ 1. **Build the behavior list** from Proposed Changes + the LLD's promises + HIGH/CRITICAL boundary findings. Note compiler-guarded behaviors — they owe **no** test.
42
+ 2. **Assign layer + oracle** per behavior; cheapest proving layer wins.
43
+ 3. **Map to a target file** per `testing.md`; name fixtures/factories and fault injection; use the repo-standard fake-data source.
44
+ 4. **Apply the e2e altitude gate**; downgrade everything else to integration.
45
+ 5. **Emit the Test Obligations section into the plan** (an executor dispatched with only the plan sees nothing else), plus a one-line chat summary:
46
+
47
+ ```
48
+ ## Test Obligations
11
49
 
12
- ## The stack
50
+ | # | Behavior (LLD promise) | Layer | Target file | Oracle | Fixtures / faults |
51
+ | - | ---------------------- | ----- | ----------- | ------ | ----------------- |
52
+
53
+ Coverage: {N} behaviors · {N} integration · {N} component · {N} unit · {N} e2e ({N} extend, {N} new)
54
+ Completion checklist: docs/tests/{feature}.md (derived at the gate, not now)
55
+ ```
56
+
57
+ A behavior with no obligation is stated too, with the reason — "none — compiler-guarded" reads as *checked*; an empty cell reads as *not analyzed*. A short manifest is valid — do not pad.
58
+ 6. **Record the write in the plan's `Gates:` line**, rewriting only your segment to exactly `Test-plan: written YYYY-MM-DD (N rows)` — the compliance hook greps this exact form. Add the line if the plan predates the format.
59
+
60
+ ---
61
+
62
+ ## Placement mode — layered test strategy
63
+
64
+ You decide **where a test lives and what it may assert**. **The litmus is "where can this defect originate?"** A test lives with the only layer that can produce the defect it catches. "The 409 response carries the current body" can only break in a route handler — service-contract layer. "The buffer the user typed survives the 409" can only break in component state — component layer. Same feature, two owners, two tests, zero overlap. Placement is decided by this question alone — testing a feature wherever you first *see* it is what makes suites flat, duplicative, and multiplicative in cost.
65
+
66
+ ### The stack
13
67
 
14
68
  The maximum form, for a full-stack application. Each layer names what only it can break, the oracle that proves it, and the technology **class** — the concrete framework comes from `testing.md`'s stack table, never from here.
15
69
 
@@ -24,11 +78,11 @@ The maximum form, for a full-stack application. Each layer names what only it ca
24
78
  | 7 | **Component / surface** | Interaction orchestration — what a user action changes on screen: buffer lifecycle, optimistic states, error surfaces | Rendered output a user can observe; network answered by layer 4 | DOM testing-library class + interception |
25
79
  | 8 | **System smoke** | Composition only — the layers are actually stacked: the build serves, auth flows end to end, one write round-trips | A real browser or real binary against the really-running app | Browser/process driver class; 3–5 journeys, zero variants |
26
80
 
27
- Layer 4 is the hinge. Every layer ≥5 runs on the assumption that layers 1–3 are green — and the artifact is what makes that assumption *enforceable* rather than aspirational: when the provider's response type changes, the fixture stops compiling, and every consumer test fails at typecheck before it runs. A consumer-side test that hand-writes a wire response has smuggled unverified layer-3 knowledge upward; route it through the artifact instead.
81
+ Layer 4 is the hinge. Every layer ≥5 runs on the assumption that layers 1–3 are green — and the artifact makes that assumption *enforceable*: when the provider's response type changes, the fixture stops compiling, and every consumer test fails at typecheck before it runs. A consumer-side test that hand-writes a wire response has smuggled unverified layer-3 knowledge upward; route it through the artifact.
28
82
 
29
- ## How many layers — derived, never chosen
83
+ ### How many layers — derived, never chosen
30
84
 
31
- The count is not a taste decision. **A layer exists iff the application has the boundary that can originate that layer's defects; an absent boundary makes the layer vanish** — it never merges its responsibilities into a neighbor. Merging is the failure mode: a team that "simplifies" layers 3 and 7 together has reinvented the flat feature test, where every UI assertion silently re-verifies the API beneath it and cost goes multiplicative again.
85
+ **A layer exists iff the application has the boundary that can originate that layer's defects; an absent boundary makes the layer vanish** — it never merges into a neighbor. Merging is the failure mode: "simplifying" layers 3 and 7 together reinvents the flat feature test, where every UI assertion silently re-verifies the API beneath it and cost goes multiplicative again.
32
86
 
33
87
  | Application shape | Strata present |
34
88
  | --- | --- |
@@ -40,19 +94,17 @@ The count is not a taste decision. **A layer exists iff the application has the
40
94
 
41
95
  Derive the stack first, then place tests: a placement argument that starts "this feels like an integration test" has skipped the derivation.
42
96
 
43
- ## Placement discipline
97
+ ### Placement discipline
44
98
 
45
99
  - **An assertion provable at two layers is misplaced — it belongs at the lower one.** The duplication check is mechanical, not judgment.
46
- - **Behavior variants sink to the cheapest layer that owns them** — almost always 2 or 6, where a variant costs one function call. A variant at layer 3 pays wire tax on a domain test; a variant at layer 8 is a placement failure below, by definition.
47
- - **One representative path upward.** Layer 3 keeps one happy path per route to prove wiring into layer 2, plus exhaustive coverage of *contract edges only* (auth refusals, not-found indistinguishability, projection/withholding). Layer 8 keeps 3–5 journeys total.
48
- - **External systems enter as modeled fakes, not spies.** A fake implements the port's semantics so tests assert resulting state ("the branch gained two commits, the first holds the earlier body"); a spy only proves methods were called, which passes just as happily with the bytes swapped.
49
- - **Failure localization is the payoff to protect.** One defect should turn exactly one layer red, at its owner. When a single change reddens tests across several layers, at most one of those tests was correctly placed — treat the rest as findings.
100
+ - **Behavior variants sink to the cheapest layer that owns them** — almost always 2 or 6. A variant at layer 3 pays wire tax on a domain test; a variant at layer 8 is a placement failure below, by definition.
101
+ - **One representative path upward.** Layer 3 keeps one happy path per route plus exhaustive coverage of *contract edges only*; layer 8 keeps 3–5 journeys total.
102
+ - **External systems enter as modeled fakes, not spies.** A fake implements the port's semantics so tests assert resulting state; a spy only proves methods were called, which passes just as happily with the bytes swapped.
103
+ - **Failure localization is the payoff to protect.** One defect turns exactly one layer red, at its owner. When a single change reddens several layers, at most one of those tests was correctly placed — treat the rest as findings.
50
104
 
51
- Why this is the cheap strategy at the horizon: layering makes cost **additive** — a new API behavior costs one layer-2 test and maybe a layer-3 edge, zero frontend tests; a new UI state costs one layer-7 test, zero backend tests. A flat suite pays N×M, because every top-layer path implicitly re-verifies every behavior beneath it.
105
+ Layering makes cost **additive** — a new API behavior costs one layer-2 test and maybe a layer-3 edge, zero frontend tests; a new UI state costs one layer-7 test, zero backend tests. A flat suite pays N×M, because every top-layer path implicitly re-verifies every behavior beneath it.
52
106
 
53
- ## The tree
54
-
55
- The directory layout follows the strata, so a test's home states its layer and the runner split is mechanical, not per-file judgment:
107
+ ### The tree
56
108
 
57
109
  ```
58
110
  tests/
@@ -68,13 +120,13 @@ e2e/ L8 — its own config, never mixed into the unit runner's glob
68
120
  ```
69
121
 
70
122
  - **A stratum the app lacks gets no directory** — an empty `component/` in a backend service is a lie about the app's shape.
71
- - **One shared glob list, imported by both runner configs** — the infrastructure-bound runner *includes* `schema|domain|routes`, the unit runner *excludes* them. Two hand-maintained lists drift; one imported constant cannot.
72
- - **Which concrete runner, framework, and DOM environment fill these slots is `testing.md`'s per-stack table** — this skill names the slot, never the brand, so the two files cannot disagree.
73
- - **Contract modules the provider binds** (the layer-4 source types) live in the app's shared source zone — importable by both provider and consumer builds — not in the test tree; `tests/contract/` holds only the fixtures and fakes compiled from them.
123
+ - **One shared glob list, imported by both runner configs** — two hand-maintained lists drift; one imported constant cannot.
124
+ - **Concrete runner, framework, and DOM environment come from `testing.md`'s per-stack table** — this skill names the slot, never the brand.
125
+ - **Contract modules the provider binds** (the layer-4 source types) live in the app's shared source zone — importable by both sides; `tests/contract/` holds only the compiled fixtures and fakes.
74
126
 
75
- ## Bridge to the obligation ledger
127
+ ### Bridge to the obligation ledger
76
128
 
77
- The `test-plan` skill's ledger assigns each obligation a runner altitude — `unit` / `component` / `integration` / `e2e`. Those are coarse names for where a test *runs*; the strata here say what it may *assert*. The mapping:
129
+ The ledger's altitudes are coarse names for where a test *runs*; the strata say what it may *assert*:
78
130
 
79
131
  | Ledger altitude | Strata it covers |
80
132
  | --- | --- |
@@ -83,13 +135,32 @@ The `test-plan` skill's ledger assigns each obligation a runner altitude — `un
83
135
  | component | 7 |
84
136
  | e2e | 8 |
85
137
 
86
- When writing or discharging a ledger row, name the stratum, not just the altitude — "integration" alone leaves open whether the row asserts a schema invariant, a business rule, or an envelope, and those are three different owners with three different oracles.
138
+ When writing or discharging a ledger row, name the stratum, not just the altitude — "integration" alone leaves open whether the row asserts a schema invariant, a business rule, or an envelope: three owners, three oracles.
139
+
140
+ ### Run (placement)
141
+
142
+ 1. **Derive the stack** from the application's real boundaries (storage? published wire? separate client? DOM?).
143
+ 2. **Place each behavior** by the litmus; name stratum, oracle, technology class; take the concrete framework and file placement from `testing.md`.
144
+ 3. **Flag violations, don't just place** — assertions provable lower, variants above 2/6, hand-written wire fixtures above layer 4, spies where fakes should model state, layer-8 variants.
145
+ 4. **Report as a stratum map** — one line per stratum: exists/absent (why), what lives there, what is misplaced and where it moves. For a plan, feed the strata into the ledger's rows.
146
+
147
+ ---
148
+
149
+ ## Gate mode — discharge the ledger
150
+
151
+ Runs only when the user triggers the verification gate (constraints — preconditions, verdict-inline, tier, honesty — are `.claude/rules/testing.md` § The gate). **Drive the real thing first, then pin what must not regress**: driving finds the defects that matter to a user, and shows which behaviors are worth the permanent cost of a test.
87
152
 
88
- ## Run
153
+ 1. **Write the checklist** — derive or update `docs/tests/{feature}.md` from the ledger and the LLD's promises (the `documentation` skill's `templates/behavioral-checklist.md`; one `**Assert**` per observable). Derived before the driving it is the script; derived after, it is merely a report with nothing to trace tests back to.
154
+ 2. **Drive the real surface** — browser automation for web UI (the `/test` runner skill where the repo wires it), the actual CLI binary, HTTP against the running worker. **A failing checklist assertion is never softened to make a run green** — record the defect, send it to the backlog. Where the runtime offers no browser automation, emit the browser-verification checklist for the user to run; their report is the rung's verdict and `Status: Complete` waits for it.
155
+ 3. **Pin the durable behaviors** as suite tests per `testing.md`, naming each test's stratum (§ Bridge). A test is a permanent maintenance cost, bought deliberately:
89
156
 
90
- Given a package, a plan, or a "where does this test go?" question:
157
+ | Earns a suite test | Verified by driving alone |
158
+ | --- | --- |
159
+ | A promise an LLD makes about the feature's contract | Layout, spacing, copy — restated by a test, not protected by one |
160
+ | A bug that occurred once — its regression test | A one-off migration or backfill's output |
161
+ | An error path, race, or idempotency guarantee | Behavior a type or the compiler already makes unshippable |
91
162
 
92
- 1. **Derive the stack.** From the application's shape (its real boundaries: storage? published wire? separate client? DOM?), list which strata exist. This takes minutes and settles every later argument.
93
- 2. **Place each behavior.** Apply the litmus per behavior: which stratum is the only origin of this defect? Name the stratum, the oracle, and the technology class; take the concrete framework and file placement from `testing.md`.
94
- 3. **Flag violations, don't just place.** When reviewing an existing suite or plan: assertions provable lower, variants above layer 2/6, hand-written wire fixtures above layer 4, spies where a fake should model state, and any layer-8 test carrying a behavior variant.
95
- 4. **Report as a stratum map** — one line per stratum: exists/absent (and why), what currently lives there, what is misplaced and where it should move. For a plan, feed the strata into the ledger's rows instead.
163
+ A driven check is evidence, not an artifact — it proves the change works today and leaves nothing behind; that is why this rung exists.
164
+ 4. **Run the affected suite**, plus the project's e2e smoke gate where one is wired.
165
+ 5. **Discharge every ledger row into exactly one outcome**: **satisfied** (test green, or driven check passed), **owes nothing** (with the reason — compiler-guarded, covered elsewhere), or **blocked** (missing infrastructure named, row converted to a backlog item). A row left unexamined blocks the gate.
166
+ 6. **Report results honestly, including failures**; record which test now guards each checklist section (`Pinned:` traces). Completion steps — freezing the plan, the changelog entry — are the root policy file's, not yours.
@@ -6,13 +6,13 @@ How AI coding agents — any vendor, any runtime — work on this project. Rules
6
6
 
7
7
  ## Maintenance
8
8
 
9
- Invoke the `maintenance` agent whenever the docs look like they need it — not just at first setup: a missing `docs/structure.md` (the repo isn't reconciled — baseline before applying anything below), a `harness-version` marker behind the installed version, docs contradicting code, unowned source paths, or drift noticed while working. Never reconcile these by hand — the agent auto-selects its mode (baseline when the marker is missing or behind, coherence audit otherwise) and hands back; if it returns a follow-up (typically the module proposal), re-invoke it to finish. Each component's internals live in the component, not here.
9
+ Invoke the `maintenance` agent when a mechanical condition holds: `docs/structure.md` is missing (the repo isn't reconciled — baseline first), the `harness-version` marker is behind the installed version, a doc contradicts code being touched, or source paths are unowned — not on prose that merely looks stale. Structural reconciliation is never done by hand — the agent auto-selects its mode (baseline when the marker is missing or behind, coherence audit otherwise) and hands back; if it returns a follow-up (typically the module proposal), re-invoke it to finish. Single-glob or single-line doc corrections are done inline, per § Documentation. Each component's internals live in the component, not here.
10
10
 
11
11
  ---
12
12
 
13
13
  ## Getting Started
14
14
 
15
- - Read **[`docs/structure.md`](docs/structure.md)** for the documentation map and folder authority (architecture, features, operations)
15
+ - Consult **[`docs/structure.md`](docs/structure.md)** when adding or moving a doc — it is the authority on placement
16
16
  - Read **[`docs/memory/`](docs/memory/)** for agent memory files (one per agent)
17
17
  - Prefer `docs/` over `README.md` — docs/ is canonical for agents; check the README only when docs/ lacks a setup detail
18
18
  - Check **[`package.json`](package.json)** for available scripts. Detect the package manager from the lockfile — see `.claude/rules/general.md`; don't hardcode one.
@@ -31,9 +31,11 @@ Three peer modes, then a verification gate and a Completion step — enter where
31
31
 
32
32
  > Brainstorm entry needs a **basis** — a reference document or a one-shot brain dump; drip-sized asks (a bug fix, one button) are too small and get redirected. A **pillar** is a recorded strategic principle from a past brainstorm: in-progress sessions live under `docs/research/`, harvested ones under `docs/history/brainstorms/`, harvested doctrine under `docs/architecture/`. The LLD is the feature doc itself — `docs/features/{feature}.md`, design intent first, extended in place at Completion.
33
33
 
34
+ > **The lightweight lane:** a change touching one module, no cross-module contract surface, and under about a day's work skips the modes above entirely — the ad-hoc regime of `.claude/rules/testing.md` applies: make the change, pay its test immediately if it alters promised behavior, cover it with a changelog row.
35
+
34
36
  **On Plan Completion:**
35
37
 
36
- 1. **The verification gate passes first** — user-triggered: when implementation completes, report it and offer the gate; never run it unbidden. It requires the plan's Test Obligations ledger to exist (proof the plan gates ran) and discharges every row, driving the real surface before pinning tests — `.claude/rules/verification.md`. A plan with outstanding obligations stays open, whatever the code does.
38
+ 1. **The verification gate passes first** — user-triggered: when implementation completes, report it and offer the gate; never run it unbidden. It requires the plan's Test Obligations ledger to exist (proof the plan gates ran) and discharges every row, driving the real surface before pinning tests — `.claude/rules/testing.md`. A plan with outstanding obligations stays open, whatever the code does.
37
39
  2. Freeze the plan — `Status: Complete`, fill the Completed date. The file is now frozen.
38
40
  3. Flip the feature LLD to `status: active`; extend it in place with the how-it-works sections; confirm its `owns:` globs against the actual code.
39
41
  4. 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.
@@ -65,20 +67,15 @@ Boundaries are **diagnosed, not documented** — the `boundary` skill derives th
65
67
 
66
68
  ### Test obligations — specify before implementing
67
69
 
68
- **After `boundary` passes and its amendments are folded, invoke the `test-plan` skill** — same plan gate, ordered second. It derives the tests the plan owes from its Proposed Changes and the owning LLD, and writes the **Test Obligations** ledger into the plan (one row per promised behavior: layer · target file · oracle · fixtures). It writes no test files — the ledger is what the verification gate discharges, and because it lives in the plan file it survives dispatch to an executor that sees only the plan. On a boundary **BLOCK** it does not run — re-plan first. Layer rules and the e2e altitude gate live in the skill.
70
+ **After `boundary` passes and its amendments are folded, invoke the `testing` skill (plan-gate mode)** — same plan gate, ordered second. It derives the tests the plan owes from its Proposed Changes and the owning LLD, and writes the **Test Obligations** ledger into the plan (one row per promised behavior: layer · target file · oracle · fixtures). It writes no test files — the ledger is what the verification gate discharges, and because it lives in the plan file it survives dispatch to an executor that sees only the plan. On a boundary **BLOCK** it does not run — re-plan first. Layer rules and the e2e altitude gate live in the skill.
69
71
 
70
72
  ### Verification — prove before completing
71
73
 
72
- **Deferring tests is what keeps the build loop fast, and the ledger is what makes deferring safe.** A plan-driven build writes no new test files while the code is taking shape; obligations accumulate in the plan and are discharged in one pass at the **verification gate** — user-triggered, offered when implementation completes, mandatory before `Status: Complete`. The gate, the two regimes, the mid-loop rules, and what earns a durable test are `.claude/rules/verification.md`.
73
-
74
- - **Only a plan may defer.** A bug fix in shipped behavior and any ad-hoc change ship their test immediately — deferral needs a ledger and a gate, and non-plan work has neither.
75
- - **The checklist is the gate's first artifact, not its last.** Opening the gate derives or updates `docs/tests/{feature}.md` from the ledger and the LLD's promises (the `documentation` skill's `templates/behavioral-checklist.md`). It is the script rung 1 drives and the source rung 2's tests are drawn from — written after the driving it would be a report, and the tests would have no stated behavior to trace to.
76
- - **Drive the real surface before pinning tests.** Browser automation for web UI, the real CLI, HTTP against the running worker; the suite then pins the checklist assertions that must not regress, and each section records which test now guards it.
77
- - **The gate's verdict is never delegated** — a sub-agent's summary is not verifiable ground truth (the Fan-out guardrail), and browser work is main-session-only where Runtime Notes say so.
74
+ **Deferring tests is what keeps the build loop fast, and the ledger is what makes deferring safe.** Obligations accumulate in the plan and are discharged in one pass at the **verification gate** — mandatory before `Status: Complete`. The gate and the regimes are `.claude/rules/testing.md`; the procedure (checklist → drive → pin → discharge) is the `testing` skill (gate mode). The gate's verdict is never delegated (§ Delegation), and browser work is main-session-only where Runtime Notes say so.
78
75
 
79
76
  ### Documentation — close the loop
80
77
 
81
- - **Every markdown document goes through the `documentation` skill.** Before creating or substantively editing any `.md` document — a doc, a README, an index, a record — invoke the `documentation` skill and apply its templates and `references/style-guide.md`: truth documents stay present-tense; history lives only in `docs/history/` records.
78
+ - **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.
82
79
  - **[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.
83
80
  - 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).
84
81
  - When moving or renaming source files: update the `owns:` globs of the feature doc that owns them so the generated ownership index stays accurate. A new doc that owns code declares its paths in its own `owns:` frontmatter — there is no separate map to update.
@@ -104,20 +101,13 @@ When recording a learning, ask: _is this true of this project, or true of this u
104
101
 
105
102
  ## Changelog
106
103
 
107
- The working session is the last holder of the refinement context that produced a change — asks, iterations, rejections, skill outcomes, discoveries. The changelog captures it; the `retro` agent distills it on demand. A commit marks the user's acceptance of the work it carries — for plan work, behavioral verification is the gate's job, and a mid-plan commit is a checkpoint (the `verification` rule). The `changelog` rule carries the trigger and the lifecycle; this is the policy:
108
-
109
- - **Every non-mechanical commit is covered by an entry** at `docs/history/changelog/YYYY-MM-DD-{three-words}.md`, staged inside the commit it describes — whatever tool or session performs the commit — plus a row in `docs/history/CHANGELOG.md`. Format, required fields, and the closed exemption list are the `documentation` skill's `templates/changelog-entry.md`; the failure fields (rejected attempts, overridden skill output) and verbatim taste quotes are required, not optional — the entry's value concentrates there.
110
- - **An entry may exist before its commit.** A plan reaching `Status: Complete` writes its entry as a **draft** immediately, while the context is fresh; the commit fills what the draft left open. **Immutability begins at commit, not creation** — a draft is mutable, a committed entry never is, and a correction is a new entry that links back. Doc-health passes skip the genre.
111
- - **A commit is the smallest unit an entry may describe**; above that the mapping is judgment. Work exceeding a draft's scope gets a *second* entry rather than stretching the first.
112
- - **Distillation is the `retro` agent** — run on demand (before a brainstorm or LLD, before a new project, after a refinement arc), it converts accumulated entries into a typed punch list (doc content, doc structure, skill evolution, pins, harness rules), appends actionable items to the backlog, and proposes only — application runs through the normal documentation loop.
113
-
114
- **One-shot migrations are a different genre.** Work that runs **once** against a live system — a data backfill, a schema cutover, a dependency or harness upgrade rolled across repos — is a **migration runbook** at `docs/history/migrations/YYYY-MM-DD-{slug}.md` (template: the `documentation` skill's `templates/migration-runbook.md`), authored **before** execution and outcome-stamped after. A changelog entry says what changed in the repo; a runbook says what was executed against the world and how to verify or undo it. A repeatable procedure is neither — that is `docs/operations/`. When a runbook defers targets, it records **why** and the **trigger to re-evaluate them**, so the next run re-checks rather than inheriting the skip.
104
+ The working session is the last holder of the refinement context that produced a change — asks, iterations, rejections, discoveries; the changelog captures it, and the `retro` agent distills it on demand into doc, skill, and pin feedback. When an entry is owed, its lifecycle, its granularity, and the migration-runbook genre are the `changelog` rule; format and required fields are the `documentation` skill's `templates/changelog-entry.md`. A plan reaching `Status: Complete` writes its entry as a **draft** immediately, while the context is fresh; **immutability begins at commit, not creation** — a committed entry is never edited, a correction is a new entry that links back.
115
105
 
116
106
  ---
117
107
 
118
108
  ## Out-of-Scope Discovery
119
109
 
120
- When a plan's implementation surfaces work that is important but outside the plan's scope and is not being done now (a pre-existing bug being fixed on the spot is the bug-fix regime — the `verification` rule — not a backlog item):
110
+ When a plan's implementation surfaces work that is important but outside the plan's scope and is not being done now (a pre-existing bug being fixed on the spot is the bug-fix regime — the `testing` rule — not a backlog item):
121
111
 
122
112
  - Append it to `docs/history/backlog.md` under the appropriate priority (P0-P3)
123
113
  - Format: `- **[P1]** Description — discovered by [plan-name or agent-name]`
@@ -125,22 +115,31 @@ When a plan's implementation surfaces work that is important but outside the pla
125
115
 
126
116
  ---
127
117
 
118
+ ## Delegation
119
+
120
+ The single policy for sub-agent dispatch — when to fan out, at what tier, and how far to trust the result. Component-internal dispatch mechanics (the foreman loop, the brainstorm twin, batch classification) stay in their components and defer here for anything this section covers. No dispatch mechanism ⇒ inline.
121
+
122
+ - **Delegate to keep bulk out of the main context.** Wide file reads, sweeps, broad research, audits, fixture prep — work whose raw tool output the main session doesn't need — defaults to a sub-agent: output a sub-agent reads dies with it, while output read inline is re-read and re-billed on every later turn. The hand-off is self-contained (the sub-agent sees none of the conversation), so it must still cost less than the work; run independent delegations in parallel.
123
+ - **Small or judgment work stays inline.** A task finishable in a handful of tool calls is faster done than briefed. **Never delegate judgment by reflex** — a second opinion is for a high-stakes call or an explicit request.
124
+ - **A delegated result is a report, not verifiable ground truth** — verify load-bearing results directly.
125
+ - **Tiers**: mechanical fan-out → the cheapest capable tier; judgment-heavy delegation → the session's standard tier; the strongest tier **only** on explicit user request. The session itself defaults to the standard tier, entering the strongest only by explicit user switch. Model names live in Runtime Notes.
126
+ - **An explicit user directive about tier, cost, or delegation overrides this section.**
127
+
128
+ ---
129
+
128
130
  ## Guardrails & Defaults
129
131
 
130
132
  Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise; ✅ and ⚠️ items are standing policy:
131
133
 
132
- - ✅ **Verification — batched at a gate, not continuous.** A plan-driven build loop ships code without new test files; the tests and the driven checks land together at the **verification gate** — user-triggered, offered when implementation completes, mandatory before a plan reaches `Status: Complete`. The gate, the regimes, and the mechanism ladder are `.claude/rules/verification.md`; framework, test-tree placement, and shared fixtures are `.claude/rules/testing.md` — the repo's existing runner and layout always win.
133
- - **Only a plan defers**: a bug fix in shipped behavior and any ad-hoc change ship their test immediately — a regression test that fails before the change and passes after.
134
- - **Drive before pinning**: prove the change in the real product first — browser automation for web UI, the real CLI, HTTP against the running worker — then pin as suite tests only the behaviors that must not regress.
135
- - **Discipline**: run the affected part of the suite at the gate and report results honestly. Never weaken, skip, or delete a test to mask an unexplained failure — when a plan or LLD intentionally changes behavior, updating the affected tests to the new contract is part of the change.
136
- - **Throwaway checks are not tests**: temporary verification scripts go to scratch space and are deleted, never committed into the test tree.
137
- - ❌ **Dependencies** – Never upgrade frameworks, libraries, or dependencies.
134
+ - ✅ **Verification — batched at a gate, not continuous.** Only a plan defers tests; bug fixes and ad-hoc changes that alter promised behavior pay theirs immediately. The gate, regimes, frameworks, and placement are `.claude/rules/testing.md`; the procedure is the `testing` skill (gate mode) — the repo's existing runner and layout always win.
135
+ - ❌ **Dependencies** – Never upgrade pinned packages without asking; security patches and test-tooling installs at `latest` (`testing.md`) are exempt.
138
136
  - ❌ **Compatibility** – Never maintain backward compatibility unless specified.
139
137
  - ❌ **Branches & Worktrees [override]** – Never self-create git branches or worktrees; commit straight to the checked-out branch. This replaces any built-in "branch first on the default branch" default. Exception: when the user asks for a pull request, create the branch the PR requires before committing its changes.
140
- - ❌ **Protected Files** – Before editing, if `docs/operations/protected-files.md` exists, read it and never modify any path it lists; also never modify `AGENTS.md` or the `protected-files.md` file itself.
138
+ - ❌ **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` (harness-regenerated) or `protected-files.md` itself.
141
139
  - ✅ **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.
142
- - ✅ **Fan-out is a tool, not a default** — the main session does the work and its own reasoning; a delegated result comes back as a summary, not verifiable ground truth. Delegate **only when** the work is large, independent, or repetitive enough that a self-contained hand-off (the sub-agent sees none of the conversation) costs less than the work — broad research, wide sweeps, audits — and run independent delegations in parallel. **Never delegate judgment by reflex**: a second opinion is for a high-stakes call or an explicit request. No dispatch mechanism ⇒ inline.
143
- - ⚠️ **Plans** – Plans are created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Status: Abandoned`, the file is frozen — never edited. Abandoning a plan whose code was committed first converts its undischarged Test Obligations into backlog items (the `verification` rule). If scope changes after completion, write a new dated plan that links back to the old one.
140
+ - ✅ **Bookkeeping** — hooks silently append doc-debt rows to `docs/operations/bookkeeping.md`; the commit hook blocks while unresolved rows remain — dispatch the `bookkeeper` agent to drain the queue.
141
+ - ✅ **Delegation** — when to fan out, tiers, and trust are § Delegation.
142
+ - ⚠️ **Plans** – Plans are created directly in `docs/history/plans/` (see Workflows). Once `Status: Complete` or `Status: Abandoned`, the file is frozen — never edited. Abandoning a plan whose code was committed first converts its undischarged Test Obligations into backlog items (the `testing` rule). If scope changes after completion, write a new dated plan that links back to the old one.
144
143
  - ⚠️ **Tool Issues** – If any CLI tool, shell alias, or MCP tool behaves unexpectedly (syntax errors, silent failures, wrong defaults), report the exact tool name, command, and error to the user so they can fix or remove the underlying library.
145
144
 
146
145
  ---
@@ -156,5 +155,5 @@ Defaults — ❌ prohibitions hold unless the user explicitly asks otherwise;
156
155
 
157
156
  Everything above is runtime-neutral. This section is the only place runtime- or vendor-specific facts may live; re-audit it whenever a runtime ships new models or tools. Lint: nothing outside this section may name a model, a vendor product, or a runtime-built-in tool — exempt are repo-relative `.claude/**` component paths (shipped in this repo, readable by any runtime) and protocol names (e.g. MCP).
158
157
 
159
- - **Claude Code**: sub-agent dispatch is the Agent tool; sub-agents can run skills and spawn their own sub-agents (probe-verified; re-verify on runtime updates), but cannot reliably hold the browser connection (the "can't hold the browser connection" condition the Browser Automation guardrail refers to) — browser work is Chrome CDP ("Claude in Chrome"), main session only. The user-level memory store is `~/.claude/` (auto-memory under `~/.claude/projects/...`). The ownership index and skill/agent descriptions are injected at session start; skills are invoked as slash commands (e.g. `/brainstorm start`). Dispatch tiers: mechanical fan-out runs on the cheapest capable tier; a user-requested second opinion takes the strongest — pick by capability at dispatch, since model names go stale.
158
+ - **Claude Code**: sub-agent dispatch is the Agent tool; sub-agents can run skills and spawn their own sub-agents (probe-verified; re-verify on runtime updates), but cannot reliably hold the browser connection (the "can't hold the browser connection" condition the Browser Automation guardrail refers to) — browser work is Chrome CDP ("Claude in Chrome"), main session only. The user-level memory store is `~/.claude/` (auto-memory under `~/.claude/projects/...`). The ownership index and skill/agent descriptions are injected at session start; skills are invoked as slash commands (e.g. `/brainstorm start`). Dispatch tiers (§ Delegation): the standard tier is Opus-class and is the session default; mechanical fan-out runs on the cheapest capable tier (Sonnet-class); the strongest tier (Fable-class) only on explicit user switch or request — pick by capability at dispatch, since model names go stale.
160
159
  - **Runtimes without native component support** (AGENTS.md readers, etc.): read `.claude/agents/<name>.md` and each skill's `.claude/skills/<name>/SKILL.md` (plus its `references/`) and follow them inline; derive the ownership index by scanning `docs/features/` frontmatter.
@@ -10,5 +10,5 @@
10
10
  "seeds": [
11
11
  ".mcp.json"
12
12
  ],
13
- "digest": "cc0eb9871a83"
13
+ "digest": "a3c50783b9c0"
14
14
  }
@@ -0,0 +1,42 @@
1
+ # Approved Packages
2
+
3
+ Read by the PreToolUse install gate (`compliance.mjs`) — an off-table install is denied. Not model-loaded; the policy line lives in `.claude/rules/general.md`. The table changes only by explicit user decision.
4
+
5
+ | Package | Version | Use | Don't use |
6
+ | --- | --- | --- | --- |
7
+ | `react` | ^19.2.3 | UI components | — |
8
+ | `vite` | ^8.0.0 | Build tool, dev server | `webpack`, CRA |
9
+ | `tailwindcss` | ^4.1.18 | Styling | `styled-components` |
10
+ | `@vitejs/plugin-react-swc` | ^4.2.2 | JSX compilation | `@vitejs/plugin-react` |
11
+ | `react-router-dom` | ^7.11.0 | Routing | — |
12
+ | `@reduxjs/toolkit` | ^2.11.2 | State management | `zustand`, `jotai` |
13
+ | `react-redux` | ^9.2.0 | Redux React bindings | — |
14
+ | `axios` | ^1.13.2 | HTTP requests in browser/Node code | `fetch` in browser code — Workers and edge runtimes use native `fetch`, which is correct there |
15
+ | `@microsoft/fetch-event-source` | ^2.0.1 | SSE over POST — streaming agent output | hand-rolled `getReader()` loops, `EventSource` |
16
+ | `date-fns` | ^4.1.0 | Date formatting | `moment`, `dayjs` |
17
+ | `@dnd-kit/core` | ^6.3.1 | Drag and drop | `react-beautiful-dnd` |
18
+ | `@xyflow/react` | ^12.11.0 | Node-based flow charts | `reactflow`, `react-flow-renderer` |
19
+ | `motion` | ^12.23.26 | Animations | `react-spring` |
20
+ | `sonner` | ^2.0.7 | Toast notifications | `react-toastify` |
21
+ | `react-window` | ^2.2.3 | List virtualization | `react-virtualized` |
22
+ | `nanoid` | ^6.0.0 | ID generation | `uuid` — exempt: UUIDv5/v7 database ids per `database.md` |
23
+ | `express` | ^5.2.1 | HTTP server | `fastify`, `koa` |
24
+ | `drizzle-orm` | ^0.45.2 | Database ORM | `prisma`, `sequelize`, `typeorm` |
25
+ | `drizzle-kit` | ^0.31.10 | Schema tooling | — |
26
+ | `zod` | ^4.2.1 | Schema validation | `yup`, `joi` |
27
+ | `jose` | ^6.1.3 | JWT handling | `jsonwebtoken` |
28
+ | `microdiff` | ^1.5.0 | JSON object diffing | `deep-diff`, `just-diff` |
29
+ | `react18-json-view` | ^0.2.9 | JSON tree view | `react-json-view` |
30
+ | `@tiptap/react` | ^3.11.1 | Rich text editor | `slate`, `quill`, `draft-js` |
31
+ | `shiki` | ^4.3.1 | Syntax highlighting | `prism`, `highlight.js` |
32
+ | `lucide-react` | ^1.26.0 | Icons | `react-icons`, `heroicons` |
33
+ | `@pdfme/generator` | ^6.1.12 | PDF generation | `jspdf`, `pdfkit` |
34
+ | `cmdk` | ^1.1.1 | Command palette | `kbar`, `ninja-keys` |
35
+ | `@monaco-editor/react` | ^4.7.0 | Code editor | `codemirror`, `ace` |
36
+ | `localforage` | ^1.10.0 | Client-side storage | `idb`, `dexie` |
37
+ | `react-markdown` | ^10.1.0 | Markdown rendering | `marked`, `markdown-it` |
38
+ | `remark-gfm` | ^4.0.1 | GFM (tables, tasklists) | `remark-github`, custom |
39
+ | `fast-deep-equal` | ^3.1.3 | Deep equality checks | `lodash.isEqual` |
40
+ | `@ngneat/falso` | latest | Fake data generation | `@faker-js/faker`, `chance` |
41
+ | `pino` | ^10.1.0 | Logging | `winston` |
42
+
@@ -107,14 +107,14 @@ function fileGate(projectDir, rel, toolName) {
107
107
  if (!plan.hasLedger) {
108
108
  return decision(
109
109
  "deny",
110
- `BLOCKED — plan gate. \`${plan.file}\` has no \`## Test Obligations\` section. Run the \`test-plan\` skill; its ledger is what the verification gate discharges.`
110
+ `BLOCKED — plan gate. \`${plan.file}\` has no \`## Test Obligations\` section. Run the \`testing\` skill (plan-gate mode); its ledger is what the verification gate discharges.`
111
111
  );
112
112
  }
113
113
  }
114
114
  }
115
115
 
116
116
  // Writing a test file is never an interruption. Deferring tests to the verification gate stays
117
- // doctrine (`verification.md` § During the loop), but it needs no gate here: what the ledger
117
+ // doctrine (`testing.md` § During the loop), but it needs no gate here: what the ledger
118
118
  // actually guarantees is enforced at both ends already — a plan may not take implementation
119
119
  // edits until its `## Test Obligations` section exists (above), and it may not reach
120
120
  // `Status: Complete` until the gate discharges every row (the Stop gate). Policing the *moment*
@@ -169,11 +169,16 @@ function commitGate(projectDir) {
169
169
  return null;
170
170
  }
171
171
 
172
- // Package names approved anywhere in the rules (general.md table + testing.md's frameworks).
172
+ // Package names approved in .claude/hooks/approved-packages.md (plus testing.md frameworks and general.md).
173
173
  function approvedPackages(projectDir) {
174
174
  const names = new Set();
175
- for (const rule of ["general.md", "testing.md"]) {
176
- const text = readSafe(path.join(projectDir, ".claude", "rules", rule));
175
+ const sources = [
176
+ path.join(projectDir, ".claude", "hooks", "approved-packages.md"),
177
+ path.join(projectDir, ".claude", "rules", "general.md"),
178
+ path.join(projectDir, ".claude", "rules", "testing.md"),
179
+ ];
180
+ for (const src of sources) {
181
+ const text = readSafe(src);
177
182
  for (const m of text.matchAll(/`(@?[a-z0-9][\w./-]*)`/g)) names.add(m[1]);
178
183
  }
179
184
  return names;
@@ -191,7 +196,7 @@ function packageGate(projectDir, command) {
191
196
  if (!approved.has(pkg)) {
192
197
  return decision(
193
198
  "deny",
194
- `BLOCKED — package table. \`${pkg}\` is not in the approved table (.claude/rules/general.md; test packages: .claude/rules/testing.md). The table changes only by explicit user decision.`
199
+ `BLOCKED — package table. \`${pkg}\` is not in the approved table (.claude/hooks/approved-packages.md; test packages: .claude/rules/testing.md). The table changes only by explicit user decision.`
195
200
  );
196
201
  }
197
202
  }
@@ -134,6 +134,9 @@ export function scanFeatureDocs(projectDir) {
134
134
 
135
135
  // Build the ownership index text from every feature doc's frontmatter.
136
136
  export function buildIndex(projectDir) {
137
+ // Total markdown under docs/features/, counted independently of scanFeatureDocs — which
138
+ // drops a doc carrying no owns:, making a parse failure and a doc that owns nothing look alike.
139
+ const total = listMarkdown(path.join(projectDir, "docs", "features")).length;
137
140
  const docs = scanFeatureDocs(projectDir);
138
141
  const lines = [];
139
142
  let deprecated = 0;
@@ -152,7 +155,14 @@ export function buildIndex(projectDir) {
152
155
  const header =
153
156
  "# Ownership index (generated) — code-path glob → owning feature doc · module · keywords · status\n" +
154
157
  "# Match the file or topic you're about to touch, then read the owning doc before changing it.\n";
155
- const footer = deprecated > 0 ? `\n# (${deprecated} deprecated feature doc(s) omitted)` : "";
158
+ const indexed = docs.length - deprecated;
159
+ const skipped = total - docs.length;
160
+ const notes = [];
161
+ if (deprecated > 0) notes.push(`${deprecated} deprecated`);
162
+ if (skipped > 0) notes.push(`${skipped} with no owns:`);
163
+ const footer = notes.length
164
+ ? `\n# (${indexed}/${total} feature doc(s) indexed - ${notes.join(", ")})`
165
+ : "";
156
166
  return header + lines.join("\n") + footer;
157
167
  }
158
168
 
@@ -8,7 +8,9 @@ Every unit of work leaves one record — `docs/history/changelog/YYYY-MM-DD-{thr
8
8
  | --- | --- |
9
9
  | A plan reaches `Status: Complete` | A draft entry for that plan, linked to it — written now, while the session still holds the context |
10
10
  | The user asks for a changelog | The entry for the work in hand. No commit required |
11
- | A commit is made | Every non-exempt commit is covered by an entry — the `commit` skill writes or completes it |
11
+ | A commit is made | Every non-exempt commit is covered by an entry — the `commit` skill writes or completes it (no `commit` skill in the runtime ⇒ write the entry from the `documentation` skill's `templates/changelog-entry.md` and stage it with the commit) |
12
+
13
+ An entry is owed only by work that changes promised behavior or takes a design decision; mechanical and cosmetic commits — a typo, a copy tweak, a config value, a log line — take only their `docs/history/CHANGELOG.md` row, no entry file. The failure fields (`Ask:`, `Skills:`, `Pin:`) are required only when non-none.
12
14
 
13
15
  ## Lifecycle
14
16
 
@@ -17,3 +19,7 @@ Draft (created before its commit exists) → complete (missing fields filled fro
17
19
  ## Granularity
18
20
 
19
21
  A commit is the smallest unit an entry may describe; above that the mapping is judgment — four commits may be four entries or one, whichever reads better as history. An entry spanning several commits rides in the **last** of them, naming the predecessors in `Commits:`. When work exceeds what a draft describes, write a second entry rather than stretching the draft — the first stays an honest account of the plan.
22
+
23
+ ## Migrations are a different genre
24
+
25
+ **One-shot migrations are a different genre.** Work that runs **once** against a live system — a data backfill, a schema cutover, a dependency or harness upgrade rolled across repos — is a **migration runbook** at `docs/history/migrations/YYYY-MM-DD-{slug}.md` (template: the `documentation` skill's `templates/migration-runbook.md`), authored **before** execution and outcome-stamped after. A changelog entry says what changed in the repo; a runbook says what was executed against the world and how to verify or undo it. A repeatable procedure is neither — that is `docs/operations/`. When a runbook defers targets, it records **why** and the **trigger to re-evaluate them**, so the next run re-checks rather than inheriting the skip.