devrites 1.19.0

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 (232) hide show
  1. package/.claude-plugin/marketplace.json +24 -0
  2. package/.claude-plugin/plugin.json +43 -0
  3. package/CHANGELOG.md +391 -0
  4. package/LICENSE +56 -0
  5. package/NOTICE.md +18 -0
  6. package/README.md +582 -0
  7. package/SECURITY.md +193 -0
  8. package/bin/devrites.mjs +100 -0
  9. package/docs/architecture.md +272 -0
  10. package/docs/cli-mcp.md +57 -0
  11. package/docs/command-map.md +143 -0
  12. package/docs/flow.md +360 -0
  13. package/docs/release.md +29 -0
  14. package/docs/skills.md +214 -0
  15. package/docs/usage.md +325 -0
  16. package/install.sh +359 -0
  17. package/mcp/devrites-mcp.mjs +103 -0
  18. package/pack/.claude/agents/devrites-code-reviewer.md +50 -0
  19. package/pack/.claude/agents/devrites-doubt-reviewer.md +55 -0
  20. package/pack/.claude/agents/devrites-frontend-reviewer.md +52 -0
  21. package/pack/.claude/agents/devrites-performance-reviewer.md +47 -0
  22. package/pack/.claude/agents/devrites-plan-reviewer.md +79 -0
  23. package/pack/.claude/agents/devrites-security-auditor.md +53 -0
  24. package/pack/.claude/agents/devrites-simplifier-reviewer.md +75 -0
  25. package/pack/.claude/agents/devrites-slice-wright.md +181 -0
  26. package/pack/.claude/agents/devrites-spec-reviewer.md +72 -0
  27. package/pack/.claude/agents/devrites-strategy-reviewer.md +62 -0
  28. package/pack/.claude/agents/devrites-test-analyst.md +47 -0
  29. package/pack/.claude/hooks/devrites-a1-guard.sh +81 -0
  30. package/pack/.claude/hooks/devrites-allow.sh +44 -0
  31. package/pack/.claude/hooks/devrites-cursor.sh +28 -0
  32. package/pack/.claude/hooks/devrites-orient.sh +53 -0
  33. package/pack/.claude/hooks/devrites-redwatch.sh +39 -0
  34. package/pack/.claude/hooks/devrites-refresh-indexes.sh +127 -0
  35. package/pack/.claude/hooks/devrites-reviewer-readonly.sh +28 -0
  36. package/pack/.claude/hooks/devrites-statusline.sh +18 -0
  37. package/pack/.claude/hooks/devrites-stop-gate.sh +45 -0
  38. package/pack/.claude/hooks/devrites-wright-scope.sh +35 -0
  39. package/pack/.claude/hooks/hooks.json +52 -0
  40. package/pack/.claude/rules/README.md +48 -0
  41. package/pack/.claude/rules/afk-hitl.md +245 -0
  42. package/pack/.claude/rules/agents.md +98 -0
  43. package/pack/.claude/rules/anti-patterns.md +48 -0
  44. package/pack/.claude/rules/code-review.md +38 -0
  45. package/pack/.claude/rules/coding-style.md +55 -0
  46. package/pack/.claude/rules/context-hygiene.md +97 -0
  47. package/pack/.claude/rules/core.md +119 -0
  48. package/pack/.claude/rules/development-workflow.md +40 -0
  49. package/pack/.claude/rules/documentation.md +27 -0
  50. package/pack/.claude/rules/error-handling.md +33 -0
  51. package/pack/.claude/rules/git-workflow.md +35 -0
  52. package/pack/.claude/rules/hooks.md +38 -0
  53. package/pack/.claude/rules/patterns.md +45 -0
  54. package/pack/.claude/rules/performance.md +27 -0
  55. package/pack/.claude/rules/prose-style.md +101 -0
  56. package/pack/.claude/rules/security.md +63 -0
  57. package/pack/.claude/rules/testing.md +88 -0
  58. package/pack/.claude/rules/tooling.md +72 -0
  59. package/pack/.claude/settings.json +53 -0
  60. package/pack/.claude/skills/devrites-api-interface/SKILL.md +45 -0
  61. package/pack/.claude/skills/devrites-audit/SKILL.md +73 -0
  62. package/pack/.claude/skills/devrites-browser-proof/SKILL.md +38 -0
  63. package/pack/.claude/skills/devrites-debug-recovery/SKILL.md +50 -0
  64. package/pack/.claude/skills/devrites-debug-recovery/reference/build-the-loop.md +47 -0
  65. package/pack/.claude/skills/devrites-debug-recovery/reference/cleanup-and-classify.md +17 -0
  66. package/pack/.claude/skills/devrites-debug-recovery/reference/hypotheses.md +17 -0
  67. package/pack/.claude/skills/devrites-debug-recovery/reference/instrumentation.md +21 -0
  68. package/pack/.claude/skills/devrites-debug-recovery/reference/regression-test.md +31 -0
  69. package/pack/.claude/skills/devrites-doubt/SKILL.md +75 -0
  70. package/pack/.claude/skills/devrites-frontend-craft/SKILL.md +96 -0
  71. package/pack/.claude/skills/devrites-frontend-craft/reference/craft.md +59 -0
  72. package/pack/.claude/skills/devrites-frontend-craft/reference/design-references.md +116 -0
  73. package/pack/.claude/skills/devrites-frontend-craft/reference/fullstack.md +45 -0
  74. package/pack/.claude/skills/devrites-frontend-craft/reference/quality-standards.md +215 -0
  75. package/pack/.claude/skills/devrites-frontend-craft/reference/reuse-first.md +59 -0
  76. package/pack/.claude/skills/devrites-frontend-craft/reference/shape.md +60 -0
  77. package/pack/.claude/skills/devrites-interview/SKILL.md +81 -0
  78. package/pack/.claude/skills/devrites-lib/SKILL.md +76 -0
  79. package/pack/.claude/skills/devrites-lib/scripts/analyze.sh +78 -0
  80. package/pack/.claude/skills/devrites-lib/scripts/check-acceptance.sh +75 -0
  81. package/pack/.claude/skills/devrites-lib/scripts/close-out.sh +47 -0
  82. package/pack/.claude/skills/devrites-lib/scripts/conventions.py +273 -0
  83. package/pack/.claude/skills/devrites-lib/scripts/coverage.sh +51 -0
  84. package/pack/.claude/skills/devrites-lib/scripts/devrites.sh +69 -0
  85. package/pack/.claude/skills/devrites-lib/scripts/doctor.sh +92 -0
  86. package/pack/.claude/skills/devrites-lib/scripts/evidence-fresh.sh +63 -0
  87. package/pack/.claude/skills/devrites-lib/scripts/footprint.sh +45 -0
  88. package/pack/.claude/skills/devrites-lib/scripts/learnings.sh +74 -0
  89. package/pack/.claude/skills/devrites-lib/scripts/mutation-gate.sh +52 -0
  90. package/pack/.claude/skills/devrites-lib/scripts/package-existence.sh +68 -0
  91. package/pack/.claude/skills/devrites-lib/scripts/preamble.sh +76 -0
  92. package/pack/.claude/skills/devrites-lib/scripts/progress.sh +103 -0
  93. package/pack/.claude/skills/devrites-lib/scripts/readiness.sh +62 -0
  94. package/pack/.claude/skills/devrites-lib/scripts/reconcile.sh +123 -0
  95. package/pack/.claude/skills/devrites-lib/scripts/resolve.sh +279 -0
  96. package/pack/.claude/skills/devrites-lib/scripts/stuck.sh +67 -0
  97. package/pack/.claude/skills/devrites-lib/scripts/test-integrity.sh +87 -0
  98. package/pack/.claude/skills/devrites-lib/scripts/tick-afk.sh +52 -0
  99. package/pack/.claude/skills/devrites-prose-craft/SKILL.md +105 -0
  100. package/pack/.claude/skills/devrites-prose-craft/reference/banned-phrases.md +95 -0
  101. package/pack/.claude/skills/devrites-prose-craft/reference/examples.md +88 -0
  102. package/pack/.claude/skills/devrites-prose-craft/reference/structures.md +134 -0
  103. package/pack/.claude/skills/devrites-refresh-indexes/SKILL.md +54 -0
  104. package/pack/.claude/skills/devrites-source-driven/SKILL.md +36 -0
  105. package/pack/.claude/skills/devrites-ux-shape/SKILL.md +121 -0
  106. package/pack/.claude/skills/devrites-ux-shape/reference/brief-template.md +93 -0
  107. package/pack/.claude/skills/devrites-ux-shape/reference/visual-direction-probe.md +48 -0
  108. package/pack/.claude/skills/rite/SKILL.md +135 -0
  109. package/pack/.claude/skills/rite/reference/menu.md +32 -0
  110. package/pack/.claude/skills/rite-adopt/SKILL.md +83 -0
  111. package/pack/.claude/skills/rite-adopt/reference/adoption.md +58 -0
  112. package/pack/.claude/skills/rite-adopt/reference/anti-patterns.md +19 -0
  113. package/pack/.claude/skills/rite-autocomplete/SKILL.md +96 -0
  114. package/pack/.claude/skills/rite-autocomplete/reference/decision-policy.md +35 -0
  115. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +54 -0
  116. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +59 -0
  117. package/pack/.claude/skills/rite-build/SKILL.md +261 -0
  118. package/pack/.claude/skills/rite-build/reference/afk-discipline.md +145 -0
  119. package/pack/.claude/skills/rite-build/reference/anti-patterns.md +25 -0
  120. package/pack/.claude/skills/rite-build/reference/checkpoint-protocol.md +149 -0
  121. package/pack/.claude/skills/rite-build/reference/evidence-standard.md +32 -0
  122. package/pack/.claude/skills/rite-build/reference/frontend-trigger.md +39 -0
  123. package/pack/.claude/skills/rite-build/reference/one-slice-cycle.md +38 -0
  124. package/pack/.claude/skills/rite-build/reference/spec-drift-guard.md +43 -0
  125. package/pack/.claude/skills/rite-build/reference/tdd.md +26 -0
  126. package/pack/.claude/skills/rite-build/reference/wright-dispatch.md +115 -0
  127. package/pack/.claude/skills/rite-define/SKILL.md +157 -0
  128. package/pack/.claude/skills/rite-define/reference/anti-patterns.md +25 -0
  129. package/pack/.claude/skills/rite-define/reference/gates.md +152 -0
  130. package/pack/.claude/skills/rite-define/reference/plan-template.md +65 -0
  131. package/pack/.claude/skills/rite-doctor/SKILL.md +50 -0
  132. package/pack/.claude/skills/rite-frame/SKILL.md +116 -0
  133. package/pack/.claude/skills/rite-frame/reference/failure-modes.md +68 -0
  134. package/pack/.claude/skills/rite-handoff/SKILL.md +95 -0
  135. package/pack/.claude/skills/rite-handoff/reference/handoff-template.md +34 -0
  136. package/pack/.claude/skills/rite-learn/SKILL.md +82 -0
  137. package/pack/.claude/skills/rite-plan/SKILL.md +82 -0
  138. package/pack/.claude/skills/rite-plan/reference/anti-patterns.md +24 -0
  139. package/pack/.claude/skills/rite-plan/reference/dependency-graph.md +33 -0
  140. package/pack/.claude/skills/rite-plan/reference/replan-and-repair.md +42 -0
  141. package/pack/.claude/skills/rite-plan/reference/slicing.md +52 -0
  142. package/pack/.claude/skills/rite-plan/reference/task-breakdown.md +34 -0
  143. package/pack/.claude/skills/rite-polish/SKILL.md +90 -0
  144. package/pack/.claude/skills/rite-polish/reference/anti-ai-slop.md +177 -0
  145. package/pack/.claude/skills/rite-polish/reference/anti-patterns.md +27 -0
  146. package/pack/.claude/skills/rite-polish/reference/backend-polish.md +80 -0
  147. package/pack/.claude/skills/rite-polish/reference/browser-polish-evidence.md +31 -0
  148. package/pack/.claude/skills/rite-polish/reference/code.md +85 -0
  149. package/pack/.claude/skills/rite-polish/reference/design-system-discovery.md +35 -0
  150. package/pack/.claude/skills/rite-polish/reference/harden-checklist.md +109 -0
  151. package/pack/.claude/skills/rite-polish/reference/ui.md +136 -0
  152. package/pack/.claude/skills/rite-pressure-test/SKILL.md +43 -0
  153. package/pack/.claude/skills/rite-prototype/SKILL.md +87 -0
  154. package/pack/.claude/skills/rite-prove/SKILL.md +120 -0
  155. package/pack/.claude/skills/rite-prove/reference/anti-patterns.md +25 -0
  156. package/pack/.claude/skills/rite-prove/reference/browser-proof.md +26 -0
  157. package/pack/.claude/skills/rite-prove/reference/failure-triage.md +25 -0
  158. package/pack/.claude/skills/rite-prove/reference/proof-ladder.md +26 -0
  159. package/pack/.claude/skills/rite-prove/reference/test-command-discovery.md +30 -0
  160. package/pack/.claude/skills/rite-quick/SKILL.md +81 -0
  161. package/pack/.claude/skills/rite-resolve/SKILL.md +113 -0
  162. package/pack/.claude/skills/rite-resolve/reference/answer-protocol.md +114 -0
  163. package/pack/.claude/skills/rite-review/SKILL.md +170 -0
  164. package/pack/.claude/skills/rite-review/reference/anti-patterns.md +32 -0
  165. package/pack/.claude/skills/rite-review/reference/cognitive-load.md +90 -0
  166. package/pack/.claude/skills/rite-review/reference/feature-scoped-review.md +26 -0
  167. package/pack/.claude/skills/rite-review/reference/five-axis-review.md +46 -0
  168. package/pack/.claude/skills/rite-review/reference/nielsen-heuristics.md +130 -0
  169. package/pack/.claude/skills/rite-review/reference/parallel-dispatch.md +62 -0
  170. package/pack/.claude/skills/rite-review/reference/performance-review.md +28 -0
  171. package/pack/.claude/skills/rite-review/reference/security-review.md +32 -0
  172. package/pack/.claude/skills/rite-seal/SKILL.md +183 -0
  173. package/pack/.claude/skills/rite-seal/reference/anti-patterns.md +27 -0
  174. package/pack/.claude/skills/rite-seal/reference/conventions-ledger.md +63 -0
  175. package/pack/.claude/skills/rite-seal/reference/final-evidence.md +72 -0
  176. package/pack/.claude/skills/rite-seal/reference/go-no-go.md +37 -0
  177. package/pack/.claude/skills/rite-seal/reference/parallel-dispatch.md +69 -0
  178. package/pack/.claude/skills/rite-seal/reference/risk-and-rollback.md +30 -0
  179. package/pack/.claude/skills/rite-seal/reference/seal-template.md +36 -0
  180. package/pack/.claude/skills/rite-ship/SKILL.md +120 -0
  181. package/pack/.claude/skills/rite-ship/reference/anti-patterns.md +25 -0
  182. package/pack/.claude/skills/rite-ship/reference/close-out.md +31 -0
  183. package/pack/.claude/skills/rite-ship/reference/design-memory.md +120 -0
  184. package/pack/.claude/skills/rite-ship/reference/git-ship.md +42 -0
  185. package/pack/.claude/skills/rite-ship/reference/ship-template.md +33 -0
  186. package/pack/.claude/skills/rite-spec/SKILL.md +126 -0
  187. package/pack/.claude/skills/rite-spec/reference/acceptance-criteria.md +31 -0
  188. package/pack/.claude/skills/rite-spec/reference/anti-patterns.md +25 -0
  189. package/pack/.claude/skills/rite-spec/reference/interview-patterns.md +56 -0
  190. package/pack/.claude/skills/rite-spec/reference/investigation.md +64 -0
  191. package/pack/.claude/skills/rite-spec/reference/question-protocol.md +61 -0
  192. package/pack/.claude/skills/rite-spec/reference/references-intake.md +57 -0
  193. package/pack/.claude/skills/rite-spec/reference/spec-checklists.md +73 -0
  194. package/pack/.claude/skills/rite-spec/reference/spec-template.md +124 -0
  195. package/pack/.claude/skills/rite-spec/reference/state-workspace.md +159 -0
  196. package/pack/.claude/skills/rite-status/SKILL.md +101 -0
  197. package/pack/.claude/skills/rite-temper/SKILL.md +119 -0
  198. package/pack/.claude/skills/rite-temper/reference/anti-patterns.md +29 -0
  199. package/pack/.claude/skills/rite-temper/reference/review-dimensions.md +65 -0
  200. package/pack/.claude/skills/rite-temper/reference/scope-modes.md +53 -0
  201. package/pack/.claude/skills/rite-temper/reference/significance.md +46 -0
  202. package/pack/.claude/skills/rite-temper/reference/strategy-template.md +90 -0
  203. package/pack/.claude/skills/rite-vet/SKILL.md +155 -0
  204. package/pack/.claude/skills/rite-vet/reference/anti-patterns.md +29 -0
  205. package/pack/.claude/skills/rite-vet/reference/artifacts.md +135 -0
  206. package/pack/.claude/skills/rite-vet/reference/cross-model.md +41 -0
  207. package/pack/.claude/skills/rite-vet/reference/depth.md +53 -0
  208. package/pack/.claude/skills/rite-vet/reference/eng-lenses.md +48 -0
  209. package/pack/.claude/skills/rite-vet/reference/review-axes.md +167 -0
  210. package/pack/.claude/skills/rite-zoom-out/SKILL.md +75 -0
  211. package/package.json +68 -0
  212. package/scripts/build-release-tarball.sh +74 -0
  213. package/scripts/check-cross-refs.py +121 -0
  214. package/scripts/check-no-global-writes.sh +44 -0
  215. package/scripts/check-rule-uniqueness.sh +73 -0
  216. package/scripts/devrites-detect.sh +175 -0
  217. package/scripts/eval-runner.py +273 -0
  218. package/scripts/grade-feature.sh +104 -0
  219. package/scripts/install-lib.sh +83 -0
  220. package/scripts/pin.sh +166 -0
  221. package/scripts/render-eval-summary.py +48 -0
  222. package/scripts/run-evals.sh +149 -0
  223. package/scripts/run-outcome-evals.sh +49 -0
  224. package/scripts/scan-pack-security.py +209 -0
  225. package/scripts/scan-supply-chain-iocs.py +127 -0
  226. package/scripts/supply-chain-iocs.json +11 -0
  227. package/scripts/sync-version.sh +56 -0
  228. package/scripts/validate-frontmatter.py +149 -0
  229. package/scripts/validate-workflow-security.py +86 -0
  230. package/scripts/validate.sh +234 -0
  231. package/uninstall.sh +137 -0
  232. package/update.sh +196 -0
@@ -0,0 +1,167 @@
1
+ # The vet review — scope challenge, four axes, required outputs
2
+
3
+ The body of `/rite-vet`. Run §0 first as a blocking gate, then the four axes one at a time,
4
+ then the required outputs. Apply the senior-engineer lenses in [`eng-lenses.md`](eng-lenses.md)
5
+ throughout — they're how you *see* the findings, not a separate checklist. Every finding is
6
+ calibrated and gated (see "Confidence + verification gate" below) before it reaches the human.
7
+
8
+ ---
9
+
10
+ ## §0. Scope Challenge (blocking gate — runs before any axis)
11
+
12
+ Before reviewing *how* the plan builds, challenge *whether it should build this much*. This is
13
+ implementation-scope discipline (the spec's ambition is settled — that was `/rite-temper`).
14
+
15
+ 1. **What already exists?** For each sub-problem in the plan, find the existing code/flow that
16
+ already solves it (use a code-intelligence index if available — see `../../../rules/tooling.md`).
17
+ Can the plan **capture outputs from an existing
18
+ flow** instead of building a parallel one? Reuse → extend → build new, in that order
19
+ (`coding-style.md`). List every reuse opportunity the plan misses.
20
+ 2. **Minimum diff.** What's the smallest set of changes that meets the spec's *acceptance
21
+ criteria*? Flag any planned work that can be deferred without blocking acceptance. Be ruthless
22
+ about implementation scope creep — but never cut an acceptance criterion (that's a Drift Guard
23
+ matter, not a trim).
24
+ 3. **Complexity smell.** If `plan.md` touches **>8 files** or adds **>2 new services / modules /
25
+ classes**, treat it as a smell. Check the plan's complexity gate justifies it. If it doesn't
26
+ → **STOP**: name what's overbuilt, propose a smaller version that meets acceptance, and ask
27
+ via `AskUserQuestion` whether to reduce or proceed. Do not start the axes until answered.
28
+ 4. **Built-in check.** For each new pattern / infra component / concurrency approach the plan
29
+ introduces, verify a framework/runtime built-in doesn't already do it, and that the choice is
30
+ current best practice with no known footgun — dispatch `devrites-source-driven` to confirm at
31
+ the source and record the citation. A custom roll where a built-in exists is a scope-reduction
32
+ finding.
33
+ 5. **Completeness check.** Is the plan doing the complete version or a shortcut? With AI-assisted
34
+ coding the cost of completeness (full edge-case handling, complete error paths, real test
35
+ coverage) is a fraction of what it was — a shortcut that saves human-hours but only saves
36
+ minutes here is a false economy. Prefer the complete option; flag shortcuts that exist only to
37
+ save effort that AI has already made cheap.
38
+ 6. **Distribution check.** If the plan introduces a new artifact (CLI binary, package, container,
39
+ deployable), does it include how it gets built / published / installed? If distribution is
40
+ deferred, say so explicitly in "NOT in scope" — don't let it silently drop.
41
+
42
+ > **STOP discipline.** If the complexity smell trips, the `AskUserQuestion` is a tool call, not
43
+ > prose. Naming the 80%-solution in chat and continuing is the failure this gate exists to prevent.
44
+
45
+ If the smell does not trip, present the §0 findings and proceed to Axis 1.
46
+
47
+ ---
48
+
49
+ ## The four axes (one at a time, ≤8 findings each)
50
+
51
+ For each axis: evaluate, then **walk each finding WITH the human** via `AskUserQuestion` (one
52
+ issue per call — see "How to ask" below). HITL pauses on each material finding; AFK auto-applies
53
+ within the gate ceiling (`depth.md`). If an axis genuinely has no issue, say "No issues,
54
+ moving on" and continue — don't manufacture findings.
55
+
56
+ ### 1. Architecture
57
+ - Component boundaries, coupling, data-flow patterns, single points of failure.
58
+ - Scaling characteristics; where the plan's approach breaks under real load.
59
+ - Security architecture at the seams (auth, data access, API boundaries) — does the plan name
60
+ the trust boundary for each untrusted input?
61
+ - For each new codepath / integration point: **one realistic production failure scenario** and
62
+ whether the plan accounts for it (feeds the failure-mode table).
63
+ - Does any key flow deserve an ASCII diagram in the plan or an inline comment in the code the
64
+ build will write? Name the files that should carry one.
65
+
66
+ ### 2. Plan code-quality
67
+ - Module structure the plan implies; DRY across the slices (flag planned repetition aggressively).
68
+ - Error-handling + edge cases the plan names — and the ones it doesn't (call those out explicitly).
69
+ - Over-engineering (premature abstraction, an extension point with no second caller) vs
70
+ under-engineering (fragile / hacky) relative to `patterns.md` + `coding-style.md`.
71
+ - Tech-debt hotspots the plan walks into; existing inline diagrams in touched files that the
72
+ change will make stale.
73
+
74
+ ### 3. Test-coverage design
75
+ The differentiator: design the tests *before* the code, so the build writes them alongside.
76
+ - **Framework detection** — find the project's existing test runner + conventions; match them
77
+ (never introduce a new runner to prove one change — `testing.md`).
78
+ - **Map acceptance → tests.** Every spec acceptance criterion must map to ≥1 planned test.
79
+ - **Tool per path** — unit (pure logic, single function, edge cases), integration/E2E (a user
80
+ flow spanning 3+ components, an auth/payment/data-loss path, a mock-hides-failure boundary),
81
+ eval (an LLM/prompt change that needs a quality bar).
82
+ - **Interaction inventory (UI slices) — enumerate every interactive element + flow.** List each
83
+ input field, checkbox, radio, select, toggle, button, and actionable link, plus each user
84
+ flow; assign each ≥1 asserting test **at the right level** — elements/fields → unit/component,
85
+ critical journeys → one E2E (never one-per-field). Every element/flow with no asserting test
86
+ is a GAP; no element ships unverified. Write the inventory to `test-plan.md` (table in
87
+ `artifacts.md`). This is `testing.md` "Completeness" made concrete for the plan.
88
+ - **Regression rule (mandatory, no question):** when the plan modifies existing behavior and the
89
+ current suite doesn't cover the changed path, a regression test is added to the plan as a
90
+ **Critical** requirement — no `AskUserQuestion`, no skipping. Regressions are the highest-priority
91
+ test because they prove something broke. When unsure whether a change is a regression, write the test.
92
+ - Produce the **coverage diagram** (shape below) and add a specific test requirement per GAP.
93
+
94
+ #### Coverage diagram (write to `test-plan.md`)
95
+ Both code paths and user flows in one view; mark E2E-worthy `[→E2E]` and eval-worthy `[→EVAL]`:
96
+
97
+ ```
98
+ CODE PATHS USER FLOWS
99
+ [+] services/billing [+] Checkout
100
+ ├── processPayment() ├── [★★★ planned] complete purchase — checkout.e2e
101
+ │ ├── [★★★ planned] happy + declined + timeout ├── [GAP] [→E2E] double-click submit
102
+ │ └── [GAP] invalid currency └── [GAP] navigate away mid-payment
103
+ └── refundPayment() [+] Error states
104
+ └── [★ planned] full refund only └── [GAP] network-timeout UX
105
+
106
+ COVERAGE: 4/9 planned (44%) | GAPS: 5 (2 E2E) | REGRESSIONS: 1 (Critical)
107
+ ```
108
+ Legend: ★★★ behavior+edge+error · ★★ happy path · ★ smoke · [→E2E] integration · [→EVAL] LLM eval.
109
+ **Fast path:** every acceptance criterion already maps to a planned test → "Test coverage: all
110
+ acceptance criteria covered ✓" and continue.
111
+
112
+ ### 4. Performance
113
+ - N+1 / unbounded queries and DB access patterns; memory concerns; caching opportunities;
114
+ high-complexity hot paths.
115
+ - Per `performance.md`: name a number to measure or a budget — don't recommend speculative
116
+ micro-tuning. A perf finding is "measure X against budget Y", not "this feels slow".
117
+
118
+ ---
119
+
120
+ ## Confidence + verification gate (applies to every finding, all axes)
121
+ Tag each finding `[severity] (confidence: N/10) <plan/task/spec ref> — finding`:
122
+ - **9-10** verified against a quoted line · **7-8** strong pattern match → report normally.
123
+ - **5-6** moderate → report with "verify this is real".
124
+ - **≤4** speculative → **suppress from the walk-through**, appendix only.
125
+
126
+ **The gate:** before raising a finding, quote the line(s) that motivate it. Can't quote it →
127
+ force confidence ≤4 and suppress. This kills the "the plan doesn't handle X" finding when the
128
+ plan *does* and you skimmed. Don't fabricate 7+ to dodge it. (Same discipline the reviewer agent
129
+ runs — `devrites-plan-reviewer`.)
130
+
131
+ ---
132
+
133
+ ## How to ask (the interactive walk)
134
+ Use `AskUserQuestion` per the pack's standard. Plan-review specifics:
135
+ - **One finding = one call.** Never batch findings into one question.
136
+ - Concrete: name the plan/task section + the quoted line.
137
+ - 2-3 options, including "do nothing / proceed as-is" where reasonable.
138
+ - Per option, one line: **effort** (human ~X / with the build agent ~Y), **risk**, **maintenance**.
139
+ If the complete option is only marginally more effort than the shortcut (AI makes it cheap),
140
+ recommend complete.
141
+ - **Map to a rule.** One sentence tying the recommendation to a DevRites rule (reuse-first,
142
+ fail-fast, test-behavior, measure-first, minimum diff).
143
+ - **Coverage vs kind:** if the options differ in *coverage* (more tests vs fewer, complete vs
144
+ happy-path), add `Completeness: N/10` per option. If they differ in *kind* (two different
145
+ architectures), skip the score and note "options differ in kind, not coverage". Never fabricate
146
+ a score on a kind question.
147
+ - Every material finding ends as a **recorded decision** — a resolved `questions.md` qid (HITL) or
148
+ a `decisions.md` ADR (AFK) — so the walk leaves an auditable trail, not just chat.
149
+
150
+ ---
151
+
152
+ ## Required outputs (after the axes)
153
+ 1. **"NOT in scope"** — work considered and explicitly deferred, one-line rationale each. Folds
154
+ into `plan.md` §Scope boundaries + `spec.md` Non-goals (via the Guard) so it can't silently re-enter.
155
+ 2. **"What already exists"** — existing code/flows that solve sub-problems, and whether the plan
156
+ reuses or rebuilds them. Every missed reuse becomes a §0 finding.
157
+ 3. **Failure-mode table** — for each new codepath: a realistic failure, and whether (a) a test
158
+ covers it, (b) error handling exists, (c) the user sees a clear error or a silent failure. A
159
+ failure with **no test AND no handling AND silent** is a **Critical gap**. (Shape in
160
+ [`artifacts.md`](artifacts.md).)
161
+ 4. **Worktree parallelization strategy** — analyze the slices for parallel execution. **Skip** if
162
+ all slices touch the same module or there are <2 independent workstreams ("Sequential, no
163
+ parallelization opportunity"). Otherwise: a dependency table (module-level, not file-level),
164
+ parallel lanes (shared module → same lane/sequential; independent → separate lanes), execution
165
+ order, and conflict flags where two lanes touch the same module dir. This feeds `/rite-build`'s
166
+ isolation strategy and the autocomplete loop. (Shape in [`artifacts.md`](artifacts.md).)
167
+ 5. **Completion summary** — the one-glance recap (shape in [`artifacts.md`](artifacts.md)).
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: rite-zoom-out
3
+ description: Zoom out one abstraction layer in unfamiliar code — return a structural map (modules, callers, callees, ADR/decisions touching the area) in the project's vocabulary. Use when the user says "zoom out", "map this", "bigger picture", "I don't know this area", "what calls this". Not for implementing changes (read-only) or one-symbol lookups (use grep).
4
+ user-invocable: true
5
+ ---
6
+
7
+ # /rite-zoom-out — step up one abstraction layer
8
+
9
+ When the agent (or the user) is staring at unfamiliar code without a working mental
10
+ model of how it fits the larger system. Stops the "open more files" reflex by returning
11
+ a single, structured map instead.
12
+
13
+ Read `.claude/rules/core.md` first — chiefly its vocabulary / existing-conventions
14
+ disciplines, which keep the map in the project's own language. The other rule files load
15
+ on demand.
16
+
17
+ ## What this skill returns
18
+
19
+ A **map, not an essay**. One pass should answer:
20
+
21
+ - **The area** — what this code is for, in one sentence, using the project's own
22
+ vocabulary.
23
+ - **Modules in scope** — the related files / packages / slices, with a one-line
24
+ purpose each.
25
+ - **Callers (in)** — who calls into this area from outside. Keep to the highest-signal
26
+ 3–6; collapse the rest.
27
+ - **Calls (out)** — what this area depends on downstream.
28
+ - **Decisions touching it** — ADRs (under `docs/adr/` if present) or notes in
29
+ `.devrites/work/<slug>/decisions.md` that pre-decide something here.
30
+ - **Smallest sensible change-scope** — where a fix would naturally land, so the next
31
+ step doesn't drift into a project-wide refactor.
32
+
33
+ ## Prefer a code-intelligence index (if available)
34
+
35
+ If the project has them — `codebase-memory-mcp` (`get_architecture` / `search_graph`) first,
36
+ cross-checked with `codegraph` (`.codegraph/`) and `graphify` (`graphify-out/`) — use them. For
37
+ codegraph, `codegraph_context` + one `codegraph_explore` return the map in two calls — vastly
38
+ cheaper than a file-walk and more accurate for callers/callees. Fall back to standard methods
39
+ (LSP, then `Grep` + `Read`) when no index is available. See `.claude/rules/tooling.md`.
40
+
41
+ ## Vocabulary discipline
42
+
43
+ Use the **project's** domain language — `CONTEXT.md`, glossaries, the active feature's
44
+ `spec.md` / `decisions.md`. Don't invent fresh names for things the project already
45
+ names. If you notice a fuzzy or overloaded term while mapping, flag it as a FYI at the
46
+ end; don't try to fix it here.
47
+
48
+ ## When NOT to use
49
+
50
+ - You already have a clear mental model — zooming out is just tax.
51
+ - The question is a literal text lookup (a string, a comment, an error message) — use
52
+ `Grep`.
53
+ - You need to design or change something — that's `/rite-spec` (new feature) or
54
+ `/rite-define` (plan an approved spec).
55
+ - You want a project-wide architecture audit — that's `improve-codebase-architecture`,
56
+ out of DevRites' feature-scoped remit.
57
+
58
+ ## Output shape
59
+
60
+ ```
61
+ Area: <one line, project's vocabulary>
62
+ Modules:
63
+ - path/x.ts — <purpose>
64
+ - path/y.ts — <purpose>
65
+ Callers (in):
66
+ - <module> — <how it calls in>
67
+ Calls (out):
68
+ - <module> — <what it calls for>
69
+ Decisions touching it:
70
+ - ADR-NNNN / decisions.md entry — <one-line claim>
71
+ Smallest sensible change-scope: <where a fix would land>
72
+ FYI (optional): <fuzzy term / suspected drift / open question>
73
+ ```
74
+
75
+ Print the path of any decisions/ADR files referenced so the user can open them.
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "devrites",
3
+ "version": "1.19.0",
4
+ "description": "DevRites — disciplined senior-engineer workflow skills pack for Claude Code",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "homepage": "https://github.com/ViktorsBaikers/DevRites#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ViktorsBaikers/DevRites.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/ViktorsBaikers/DevRites/issues"
13
+ },
14
+ "keywords": [
15
+ "claude-code",
16
+ "skills",
17
+ "agent-skills",
18
+ "workflow",
19
+ "senior-engineer",
20
+ "spec-driven",
21
+ "tdd",
22
+ "code-review",
23
+ "anti-slop",
24
+ "devrites"
25
+ ],
26
+ "bin": {
27
+ "devrites": "bin/devrites.mjs"
28
+ },
29
+ "files": [
30
+ "bin/",
31
+ "pack/",
32
+ "scripts/",
33
+ "install.sh",
34
+ "uninstall.sh",
35
+ "update.sh",
36
+ ".claude-plugin/",
37
+ "mcp/",
38
+ "docs/",
39
+ "README.md",
40
+ "LICENSE",
41
+ "SECURITY.md",
42
+ "NOTICE.md",
43
+ "CHANGELOG.md"
44
+ ],
45
+ "engines": {
46
+ "node": ">=18"
47
+ },
48
+ "scripts": {
49
+ "prepare": "husky || true",
50
+ "prepack": "rm -rf scripts/__pycache__ scripts/.cache docs/internal",
51
+ "commitlint": "commitlint --edit",
52
+ "validate": "bash scripts/validate.sh",
53
+ "test": "for t in tests/*.sh; do echo \"== $t ==\"; bash \"$t\" || exit 1; done",
54
+ "release": "semantic-release",
55
+ "release:dry": "semantic-release --dry-run --no-ci"
56
+ },
57
+ "devDependencies": {
58
+ "@commitlint/cli": "^21.0.2",
59
+ "@commitlint/config-conventional": "^21.0.2",
60
+ "@semantic-release/changelog": "^6.0.3",
61
+ "@semantic-release/exec": "^7.1.0",
62
+ "@semantic-release/git": "^10.0.1",
63
+ "@semantic-release/npm": "^13.1.5",
64
+ "conventional-changelog-conventionalcommits": "^9.3.1",
65
+ "husky": "^9.1.7",
66
+ "semantic-release": "^25.0.5"
67
+ }
68
+ }
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env bash
2
+ # Build the DevRites release tarball — the artifact attached to the GitHub Release
3
+ # by semantic-release. Extracting yields a `devrites-v<version>/` directory with
4
+ # everything an end-user needs (pack/, install.sh, uninstall.sh, scripts/, docs).
5
+ #
6
+ # Usage: build-release-tarball.sh <version>
7
+ set -euo pipefail
8
+
9
+ VERSION="${1:-}"
10
+ if [[ -z "$VERSION" ]]; then
11
+ echo "usage: build-release-tarball.sh <version>" >&2
12
+ exit 1
13
+ fi
14
+
15
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
16
+ DIST="$ROOT/dist"
17
+ NAME="devrites-v${VERSION}"
18
+ STAGE="$DIST/$NAME"
19
+
20
+ cd "$ROOT"
21
+
22
+ echo "Building release tarball: ${NAME}.tar.gz"
23
+
24
+ rm -rf "$STAGE"
25
+ mkdir -p "$STAGE"
26
+
27
+ # Files and directories shipped to end-users.
28
+ PAYLOAD=(
29
+ pack
30
+ .claude-plugin
31
+ scripts
32
+ mcp
33
+ docs
34
+ install.sh
35
+ uninstall.sh
36
+ update.sh
37
+ README.md
38
+ CHANGELOG.md
39
+ LICENSE
40
+ SECURITY.md
41
+ NOTICE.md
42
+ CODE_OF_CONDUCT.md
43
+ CODEOWNERS
44
+ package.json
45
+ )
46
+
47
+ for item in "${PAYLOAD[@]}"; do
48
+ if [[ -e "$item" ]]; then
49
+ cp -R "$item" "$STAGE/"
50
+ fi
51
+ done
52
+
53
+ # Drop dev-only artifacts that may have been copied transitively.
54
+ rm -rf "$STAGE/docs/internal" "$STAGE/scripts/.cache" 2>/dev/null || true
55
+
56
+ tar -C "$DIST" -czf "$DIST/${NAME}.tar.gz" "$NAME"
57
+ rm -rf "$STAGE"
58
+
59
+ # Emit a sibling checksum so install.sh can verify the artifact when present.
60
+ # Write just "<sha256> <filename>" (no path) so it verifies from any cwd.
61
+ (
62
+ cd "$DIST"
63
+ if command -v shasum >/dev/null 2>&1; then
64
+ shasum -a 256 "${NAME}.tar.gz" > "${NAME}.tar.gz.sha256"
65
+ elif command -v sha256sum >/dev/null 2>&1; then
66
+ sha256sum "${NAME}.tar.gz" > "${NAME}.tar.gz.sha256"
67
+ else
68
+ echo "warning: no sha256 tool found; skipping ${NAME}.tar.gz.sha256" >&2
69
+ fi
70
+ )
71
+
72
+ echo " → $DIST/${NAME}.tar.gz"
73
+ ls -lh "$DIST/${NAME}.tar.gz"
74
+ [[ -f "$DIST/${NAME}.tar.gz.sha256" ]] && { echo " → $DIST/${NAME}.tar.gz.sha256"; cat "$DIST/${NAME}.tar.gz.sha256"; } || true
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env python3
2
+ """Cross-reference linter for the DevRites pack.
3
+
4
+ Catches the maintenance-drift class the skills audit surfaced: a SKILL.md or
5
+ reference file pointing at another file that has moved, been renamed, or never
6
+ existed. Three checks, tuned for near-zero false positives:
7
+
8
+ 1. Markdown links to local .md targets — `](path.md)` resolved relative to the
9
+ containing file; the target must exist.
10
+ 2. Bare backtick .md filenames — `` `name.md` `` must exist SOMEWHERE in
11
+ the pack (by basename). Catches references to a file that exists nowhere.
12
+ 3. "canonical version: `path`" claims — the named path (relative to the skills
13
+ root) must exist. Catches a file disclaiming itself secondary to a missing one.
14
+
15
+ Scans pack/.claude/. Exit 1 on any dead reference. Read-only.
16
+ """
17
+ import os
18
+ import re
19
+ import sys
20
+
21
+ ROOT = os.path.join("pack", ".claude")
22
+ SKILLS_ROOT = os.path.join(ROOT, "skills")
23
+
24
+ # Runtime artifacts live under .devrites/ (per-feature work/<slug>/ files, plus the
25
+ # project-level conventions ledger), not in the pack. References to them by filename are
26
+ # legitimate, not dead refs.
27
+ WORKSPACE_ARTIFACTS = {
28
+ "spec.md", "plan.md", "tasks.md", "state.md", "decisions.md", "assumptions.md",
29
+ "questions.md", "drift.md", "evidence.md", "browser-evidence.md", "touched-files.md",
30
+ "review.md", "seal.md", "ship.md", "brief.md", "design-brief.md", "strategy.md",
31
+ "polish-report.md", "handoff.md", "eng-review.md", "test-plan.md", "references.md",
32
+ "conventions.md", "coverage.md", "analysis.md", "learnings.md",
33
+ # spec-quality checklists (.devrites/work/<slug>/checklists/<domain>.md)
34
+ "functional.md", "data-model.md", "interaction.md", "non-functional.md", "edge-cases.md",
35
+ }
36
+
37
+ # Files the skills legitimately tell Claude to read in the USER's project / the repo,
38
+ # which are not part of the shipped pack.
39
+ PROJECT_DOCS = {
40
+ "CLAUDE.md", "AGENTS.md", "DESIGN.md", "PRODUCT.md", "CONTEXT.md", "NOTES.md",
41
+ "README.md", "CHANGELOG.md", "CONTRIBUTING.md", "cli-mcp.md",
42
+ "ADR-NNN.md", # generated per-decision ADR in the user repo (docs/adr/), promoted at /rite-ship
43
+ }
44
+
45
+
46
+ def resolve(here, link):
47
+ """Resolve a link. `.claude/...`-rooted paths are install-root-relative (= pack/
48
+ in this repo); everything else is relative to the containing file."""
49
+ if link.startswith(".claude/"):
50
+ return os.path.normpath(os.path.join("pack", link))
51
+ return os.path.normpath(os.path.join(here, link))
52
+
53
+ md_files = []
54
+ all_basenames = set()
55
+ for base, _dirs, files in os.walk(ROOT):
56
+ for f in files:
57
+ if f.endswith(".md"):
58
+ p = os.path.join(base, f)
59
+ md_files.append(p)
60
+ all_basenames.add(f)
61
+
62
+ LINK_RE = re.compile(r"\]\(([^)]+)\)")
63
+ BACKTICK_MD_RE = re.compile(r"`([A-Za-z0-9._/\-]+\.md)`")
64
+ SEE_RE = re.compile(r"\(see\s+`?([A-Za-z0-9._/\-]+\.md)`?[^)]*\)")
65
+ CANONICAL_RE = re.compile(r"[Cc]anonical version:\s*`?\s*`?([A-Za-z0-9._/\-]+\.md)`")
66
+
67
+ errors = []
68
+
69
+ for path in md_files:
70
+ with open(path, encoding="utf-8") as fh:
71
+ text = fh.read()
72
+ here = os.path.dirname(path)
73
+
74
+ # 1. markdown links to .md
75
+ for link in LINK_RE.findall(text):
76
+ link = link.strip()
77
+ if link.startswith(("http://", "https://", "mailto:", "#")):
78
+ continue
79
+ target = link.split("#", 1)[0]
80
+ if not target.endswith(".md"):
81
+ continue
82
+ resolved = resolve(here, target)
83
+ if not os.path.isfile(resolved):
84
+ errors.append(f"{path}: markdown link -> {link} (resolved {resolved}) does not exist")
85
+
86
+ # 2. bare backtick filenames must exist somewhere in the pack (by basename),
87
+ # excluding runtime workspace artifacts and user-project docs.
88
+ for tok in BACKTICK_MD_RE.findall(text):
89
+ base = os.path.basename(tok)
90
+ if base in WORKSPACE_ARTIFACTS or base in PROJECT_DOCS or base in all_basenames:
91
+ continue
92
+ if "/" in tok: # a path inside the pack must actually resolve
93
+ if not os.path.isfile(resolve(here, tok)):
94
+ errors.append(f"{path}: backtick `{tok}` does not resolve")
95
+ continue
96
+ errors.append(f"{path}: backtick `{tok}` — no `{base}` exists anywhere in the pack")
97
+
98
+ # 4. "(see X.md)" prose pointers: slash form resolves (install-aware);
99
+ # bare form must exist in the pack (or be a workspace artifact / project doc).
100
+ for tok in SEE_RE.findall(text):
101
+ base = os.path.basename(tok)
102
+ if "/" in tok:
103
+ resolved = resolve(here, tok)
104
+ if not os.path.isfile(resolved):
105
+ errors.append(f"{path}: (see {tok}) (resolved {resolved}) does not exist")
106
+ elif base not in WORKSPACE_ARTIFACTS and base not in PROJECT_DOCS and base not in all_basenames:
107
+ errors.append(f"{path}: (see {tok}) — no `{base}` exists anywhere in the pack")
108
+
109
+ # 3. "canonical version: `path`" must resolve against the skills root
110
+ for claim in CANONICAL_RE.findall(text):
111
+ resolved = os.path.normpath(os.path.join(SKILLS_ROOT, claim))
112
+ if not os.path.isfile(resolved):
113
+ errors.append(f"{path}: 'canonical version' -> {claim} (resolved {resolved}) does not exist")
114
+
115
+ if errors:
116
+ print(f"check-cross-refs: {len(errors)} dead reference(s):\n")
117
+ for e in sorted(errors):
118
+ print(" " + e)
119
+ sys.exit(1)
120
+
121
+ print(f"check-cross-refs: OK — {len(md_files)} markdown files, no dead references.")
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env bash
2
+ # check-no-global-writes.sh — static guard that the installer/uninstaller never
3
+ # writes to the user's global ~/.claude, and that the global guard is present.
4
+ # Exits non-zero on violation.
5
+
6
+ set -u
7
+ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
8
+ fail=0
9
+
10
+ SCRIPTS="$ROOT/install.sh $ROOT/uninstall.sh"
11
+ for f in "$ROOT"/scripts/*.sh; do SCRIPTS="$SCRIPTS $f"; done
12
+
13
+ # 1) the no-global guard marker must exist in install.sh
14
+ if ! grep -q 'GUARD:no-global' "$ROOT/install.sh"; then
15
+ echo "FAIL: install.sh is missing the GUARD:no-global guard"
16
+ fail=1
17
+ else
18
+ echo "ok: install.sh contains the no-global guard"
19
+ fi
20
+
21
+ # 2) no write operation may target ~/.claude or \$HOME/.claude.
22
+ # Write verbs are actual file-writing commands / redirections. ('install' is
23
+ # intentionally excluded: the installer uses cp/mkdir, and "install" appears in
24
+ # prose like "install into a project", which is not a write.)
25
+ WRITE_RE='(\bmkdir\b|\bcp\b|\btee\b|\brsync\b|\bmv\b|\bln\b|>>?)'
26
+ GLOBAL_RE='(\$HOME/\.claude|~/\.claude)'
27
+ for f in $SCRIPTS; do
28
+ [ -f "$f" ] || continue
29
+ # lines that contain a global-claude path AND a write verb, excluding comments
30
+ hits="$(grep -nE "$GLOBAL_RE" "$f" | grep -vE '^\s*[0-9]+:\s*#' | grep -E "$WRITE_RE" || true)"
31
+ if [ -n "$hits" ]; then
32
+ echo "FAIL: possible global write in ${f#$ROOT/}:"
33
+ printf '%s\n' "$hits" | sed 's/^/ /'
34
+ fail=1
35
+ fi
36
+ done
37
+ [ "$fail" -eq 0 ] && echo "ok: no write operations target ~/.claude"
38
+
39
+ if [ "$fail" -eq 0 ]; then
40
+ echo "PASS: no global-write risks detected"
41
+ else
42
+ echo "FAILED: global-write check"
43
+ fi
44
+ exit "$fail"
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ # scripts/check-rule-uniqueness.sh — assert each canonical principle heading
3
+ # appears in exactly one canonical file under pack/.claude/.
4
+ #
5
+ # Drift catcher: if someone re-duplicates a principle's full treatment, this
6
+ # script fails and names the offenders. Cross-link summaries are fine — they
7
+ # don't use the canonical heading.
8
+ #
9
+ # Usage:
10
+ # scripts/check-rule-uniqueness.sh
11
+ # Exits non-zero if any principle is duplicated or missing from its canonical
12
+ # home. Add new entries to PRINCIPLES below as principles get a canonical
13
+ # home.
14
+
15
+ set -u
16
+ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
17
+ PACK="$ROOT/pack/.claude"
18
+
19
+ # Format: <grep-pattern>|<canonical-relative-path>
20
+ PRINCIPLES=(
21
+ '^## Reuse before you write|pack/.claude/rules/coding-style.md'
22
+ '^## Trust boundary (three tiers)|pack/.claude/rules/security.md'
23
+ )
24
+
25
+ fail=0
26
+
27
+ for entry in "${PRINCIPLES[@]}"; do
28
+ pattern="${entry%%|*}"
29
+ canonical="${entry##*|}"
30
+ # Use literal-string grep (-F) to avoid regex meta-char surprises in headings.
31
+ # Match anchored to line start by adding the '## ' prefix ourselves.
32
+ needle="${pattern#^}"
33
+ matches="$(grep -rln -F -- "$needle" "$PACK"/rules "$PACK"/skills "$PACK"/agents 2>/dev/null | sort -u)"
34
+ count="$(printf '%s\n' "$matches" | grep -c .)"
35
+ if [ "$count" -eq 1 ] && [ "$matches" = "$ROOT/$canonical" ]; then
36
+ printf 'ok: unique heading "%s" (canonical: %s)\n' "$needle" "$canonical"
37
+ else
38
+ printf 'FAIL: heading "%s" should appear only in %s; found in:\n' "$needle" "$canonical" >&2
39
+ printf '%s\n' "$matches" | sed 's|^| |' >&2
40
+ fail=1
41
+ fi
42
+ done
43
+
44
+ # Anti-rationalization table: core.md keeps a minimal 5-row subset that MUST be
45
+ # byte-identical to the matching rows in anti-patterns.md (the single source of
46
+ # the full table). The unique-heading check above can't see this — the rows live
47
+ # under the same heading in both files — so assert the 5 shared excuse strings
48
+ # (the excuse-column text, stable across both files) appear verbatim in both.
49
+ # These cover the five rows core.md duplicates:
50
+ # tests-later / small-refactor / special-case / user-will-tell / lint-and-build.
51
+ CORE="$PACK/rules/core.md"
52
+ ANTI="$PACK/rules/anti-patterns.md"
53
+ SHARED_EXCUSES=(
54
+ '"I'\''ll add the tests later."'
55
+ '"It'\''s only a small refactor while I'\''m in here."'
56
+ '"This is a special case, the pattern doesn'\''t apply."'
57
+ '"The user will tell me if something is wrong."'
58
+ '"Lint and build pass — that proves quality."'
59
+ )
60
+ for excuse in "${SHARED_EXCUSES[@]}"; do
61
+ in_core=0; in_anti=0
62
+ grep -qF -- "$excuse" "$CORE" 2>/dev/null && in_core=1
63
+ grep -qF -- "$excuse" "$ANTI" 2>/dev/null && in_anti=1
64
+ if [ "$in_core" -eq 1 ] && [ "$in_anti" -eq 1 ]; then
65
+ printf 'ok: shared excuse present in core.md + anti-patterns.md: %s\n' "$excuse"
66
+ else
67
+ printf 'FAIL: shared excuse must appear verbatim in BOTH core.md and anti-patterns.md: %s (core=%d anti=%d)\n' \
68
+ "$excuse" "$in_core" "$in_anti" >&2
69
+ fail=1
70
+ fi
71
+ done
72
+
73
+ exit "$fail"