@adia-ai/adia-ui-forge 0.1.3 → 0.8.1

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 (259) hide show
  1. package/.claude-plugin/plugin.json +4 -7
  2. package/CHANGELOG.md +35 -34
  3. package/README.md +35 -40
  4. package/agents/a2ui-engineer.md +22 -53
  5. package/agents/component-author.md +29 -0
  6. package/agents/framework-verifier.md +26 -0
  7. package/agents/release-engineer.md +21 -81
  8. package/agents/routing-corpus.json +293 -64
  9. package/bin/demo-postwrite-pattern-gate +94 -0
  10. package/bin/forge-lint +17 -2
  11. package/bin/sidecar-prewrite-guard +104 -0
  12. package/commands/deploy.md +9 -0
  13. package/commands/dogfood.md +10 -0
  14. package/commands/gen-review.md +9 -0
  15. package/commands/release.md +10 -0
  16. package/hooks/hooks.json +15 -0
  17. package/package.json +3 -6
  18. package/references/contracts/a2ui-mcp-surface.md +35 -0
  19. package/references/contracts/migration-guide-format.md +34 -0
  20. package/references/shared/content-trust.md +19 -74
  21. package/skills/adia-a2ui/SKILL.md +99 -0
  22. package/skills/{adia-ui-a2ui → adia-a2ui}/evals/routing-corpus.json +10 -10
  23. package/skills/adia-a2ui/references/anti-patterns.md +27 -0
  24. package/skills/adia-a2ui/references/chunk-authoring.md +71 -0
  25. package/skills/adia-a2ui/references/corpus-discipline.md +68 -0
  26. package/skills/adia-a2ui/references/eval-diagnostics.md +86 -0
  27. package/skills/adia-a2ui/references/format-extension-decisions.md +66 -0
  28. package/skills/adia-a2ui/references/leverage-rules.md +52 -0
  29. package/skills/adia-a2ui/references/mcp-pipeline-ops.md +83 -0
  30. package/skills/adia-a2ui/references/mcp-tool-reference.md +59 -0
  31. package/skills/adia-a2ui/references/pipeline-overview.md +115 -0
  32. package/skills/adia-a2ui/references/semantic-fail-lifting.md +74 -0
  33. package/skills/adia-a2ui/references/strategy-engines.md +109 -0
  34. package/skills/adia-a2ui/references/zettel-calibration.md +104 -0
  35. package/skills/adia-author/SKILL.md +112 -0
  36. package/skills/adia-author/evals/routing-corpus.json +222 -0
  37. package/skills/{adia-ui-authoring → adia-author}/references/anti-patterns.md +33 -4
  38. package/skills/{adia-ui-authoring → adia-author}/references/authoring-cycle.md +9 -11
  39. package/skills/adia-author/references/canonical-pattern-index.md +243 -0
  40. package/skills/{adia-ui-authoring → adia-author}/references/code-style.md +19 -21
  41. package/skills/adia-author/references/common-gotchas.md +129 -0
  42. package/skills/adia-author/references/composite-demo-protocol.md +271 -0
  43. package/skills/{adia-ui-authoring → adia-author}/references/css-patterns.md +19 -6
  44. package/skills/{adia-ui-authoring → adia-author}/references/lifecycle-patterns.md +1 -0
  45. package/skills/{adia-ui-authoring → adia-author}/references/llm-bridge.md +3 -5
  46. package/skills/{adia-ui-authoring → adia-author}/references/module-promotion.md +20 -38
  47. package/skills/{adia-ui-authoring → adia-author}/references/primitive-audit.md +2 -4
  48. package/skills/{adia-ui-authoring → adia-author}/references/shell-patterns.md +12 -18
  49. package/skills/{adia-ui-authoring → adia-author}/references/token-contract.md +5 -7
  50. package/skills/{adia-ui-authoring → adia-author}/references/worked-example.md +3 -3
  51. package/skills/{adia-ui-authoring → adia-author}/references/yaml-contract.md +3 -3
  52. package/skills/{adia-ui-authoring → adia-author}/scripts/build-canonical-pattern-index.mjs +3 -3
  53. package/skills/adia-deploy/SKILL.md +128 -0
  54. package/skills/{adia-ui-ops → adia-deploy}/references/deploy-playbooks.md +47 -30
  55. package/skills/adia-dogfood/SKILL.md +124 -0
  56. package/skills/adia-dogfood/references/admin-shell-anatomy.md +77 -0
  57. package/skills/adia-dogfood/references/app-shell-pitfalls.md +66 -0
  58. package/skills/adia-dogfood/references/card-anatomy-sweep.md +66 -0
  59. package/skills/adia-dogfood/references/html-attr-sweep.md +63 -0
  60. package/skills/adia-dogfood/references/native-leak-annotations.md +73 -0
  61. package/skills/adia-dogfood/references/visual-probe-triage.md +80 -0
  62. package/skills/{adia-ui-dogfood → adia-dogfood}/scripts/analyze.mjs +30 -14
  63. package/skills/adia-gen-review/SKILL.md +127 -0
  64. package/skills/adia-gen-review/references/corpus-html-patterns.md +279 -0
  65. package/skills/adia-gen-review/references/loop-protocol.md +216 -0
  66. package/skills/adia-gen-review/references/rubric-cosmetic.md +100 -0
  67. package/skills/adia-gen-review/references/rubric-decompose.md +101 -0
  68. package/skills/adia-gen-review/references/rubric-score.md +214 -0
  69. package/skills/{adia-ui-gen-review → adia-gen-review}/references/scores.schema.json +2 -2
  70. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-coverage-audit.mjs +4 -4
  71. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-decompose.mjs +10 -6
  72. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/gen-review-status.mjs +5 -5
  73. package/skills/{adia-ui-gen-review → adia-gen-review}/scripts/validate-cycle-scores.mjs +5 -5
  74. package/skills/adia-llm-internals/SKILL.md +77 -0
  75. package/skills/{adia-ui-llm → adia-llm-internals}/references/adapter-contract.md +4 -2
  76. package/skills/{adia-ui-llm → adia-llm-internals}/references/add-a-provider.md +4 -5
  77. package/skills/{adia-ui-llm → adia-llm-internals}/references/bridge-facade.md +10 -3
  78. package/skills/{adia-ui-llm → adia-llm-internals}/references/browser-proxy-boundary.md +1 -1
  79. package/skills/{adia-ui-llm → adia-llm-internals}/references/model-registry.md +5 -3
  80. package/skills/{adia-ui-llm → adia-llm-internals}/references/streaming-sse.md +2 -2
  81. package/skills/adia-release/SKILL.md +72 -0
  82. package/skills/adia-release/references/changelog-discipline.md +119 -0
  83. package/skills/adia-release/references/cut-procedure.md +247 -0
  84. package/skills/adia-release/references/gates-catalog.md +222 -0
  85. package/skills/adia-release/references/independent-package-release.md +52 -0
  86. package/skills/adia-release/references/migration-guide-authoring.md +86 -0
  87. package/skills/adia-release/references/notes-authoring.md +90 -0
  88. package/skills/adia-release/references/recovery-paths.md +106 -0
  89. package/skills/{adia-ui-release → adia-release}/scripts/bump.mjs +28 -3
  90. package/skills/{adia-ui-release → adia-release}/scripts/dispatch-publish.mjs +10 -7
  91. package/skills/{adia-ui-release → adia-release}/scripts/insert-stub.mjs +1 -1
  92. package/skills/{adia-ui-release → adia-release}/scripts/package-paths.mjs +6 -0
  93. package/skills/{adia-ui-release → adia-release}/scripts/promote-unreleased.mjs +1 -1
  94. package/skills/{adia-ui-release → adia-release}/scripts/release-pack.mjs +38 -31
  95. package/skills/{adia-ui-release → adia-release}/scripts/tag-lockstep.mjs +7 -3
  96. package/skills/adia-site-docs/SKILL.md +68 -0
  97. package/skills/adia-site-docs/evals/audit-report.md +30 -0
  98. package/skills/adia-site-docs/evals/routing-corpus.json +176 -0
  99. package/skills/adia-site-docs/intent.md +72 -0
  100. package/agents/README.md +0 -209
  101. package/agents/author.md +0 -56
  102. package/agents/repo-steward.md +0 -56
  103. package/agents/spec-architect.md +0 -53
  104. package/agents/tech-lead.md +0 -57
  105. package/agents/verifier.md +0 -55
  106. package/bin/lib/audit-axes.mjs +0 -555
  107. package/bin/lib/dry-run-irreversible.mjs +0 -236
  108. package/bin/lib/run-skill-evals.mjs +0 -487
  109. package/bin/lib/teach-router.mjs +0 -250
  110. package/commands/adia-forge-a2ui.md +0 -10
  111. package/commands/adia-forge-author.md +0 -10
  112. package/commands/adia-forge-dogfood.md +0 -8
  113. package/commands/adia-forge-llm.md +0 -8
  114. package/commands/adia-forge-orient.md +0 -10
  115. package/commands/adia-forge-release.md +0 -8
  116. package/commands/adia-forge-review.md +0 -10
  117. package/references/shared/pev-rationale.md +0 -64
  118. package/references/shared/skill-conventions.md +0 -133
  119. package/skills/adia-ui-a2ui/CHANGELOG.md +0 -32
  120. package/skills/adia-ui-a2ui/SKILL.md +0 -243
  121. package/skills/adia-ui-a2ui/evals/adversarial-corpus.json +0 -75
  122. package/skills/adia-ui-a2ui/evals/teach-routing-cases.json +0 -100
  123. package/skills/adia-ui-a2ui/references/anti-patterns.md +0 -24
  124. package/skills/adia-ui-a2ui/references/chunk-authoring.md +0 -88
  125. package/skills/adia-ui-a2ui/references/corpus-discipline.md +0 -56
  126. package/skills/adia-ui-a2ui/references/eval-diagnostics.md +0 -127
  127. package/skills/adia-ui-a2ui/references/fragment-graph.md +0 -91
  128. package/skills/adia-ui-a2ui/references/mcp-pipeline-ops.md +0 -106
  129. package/skills/adia-ui-a2ui/references/mcp-tool-reference.md +0 -398
  130. package/skills/adia-ui-a2ui/references/pipeline-overview.md +0 -175
  131. package/skills/adia-ui-a2ui/references/semantic-fail-lifting.md +0 -120
  132. package/skills/adia-ui-a2ui/references/strategy-engines.md +0 -111
  133. package/skills/adia-ui-a2ui/references/teach-protocol.md +0 -220
  134. package/skills/adia-ui-a2ui/references/zettel-calibration.md +0 -93
  135. package/skills/adia-ui-a2ui/scripts/audit-a2ui-roster.mjs +0 -96
  136. package/skills/adia-ui-a2ui/scripts/teach-route.mjs +0 -157
  137. package/skills/adia-ui-a2ui/skill.json +0 -38
  138. package/skills/adia-ui-authoring/CHANGELOG.md +0 -32
  139. package/skills/adia-ui-authoring/SKILL.md +0 -256
  140. package/skills/adia-ui-authoring/assets/case-studies/admin-shell-decomposition.md +0 -101
  141. package/skills/adia-ui-authoring/assets/case-studies/maxtokens-32768-discovery.md +0 -109
  142. package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +0 -113
  143. package/skills/adia-ui-authoring/evals/adversarial-design-plan-gates.json +0 -138
  144. package/skills/adia-ui-authoring/evals/routing-corpus.json +0 -245
  145. package/skills/adia-ui-authoring/references/canonical-pattern-index.md +0 -179
  146. package/skills/adia-ui-authoring/references/common-gotchas.md +0 -93
  147. package/skills/adia-ui-authoring/references/composite-demo-protocol.md +0 -1084
  148. package/skills/adia-ui-authoring/references/teach-protocol.md +0 -428
  149. package/skills/adia-ui-authoring/scripts/audit-authoring-roster.mjs +0 -148
  150. package/skills/adia-ui-authoring/skill.json +0 -45
  151. package/skills/adia-ui-dogfood/CHANGELOG.md +0 -17
  152. package/skills/adia-ui-dogfood/README.md +0 -62
  153. package/skills/adia-ui-dogfood/SKILL.md +0 -866
  154. package/skills/adia-ui-dogfood/skill.json +0 -40
  155. package/skills/adia-ui-forge/SKILL.md +0 -88
  156. package/skills/adia-ui-forge/evals/routing-corpus.json +0 -30
  157. package/skills/adia-ui-gen-review/CHANGELOG.md +0 -108
  158. package/skills/adia-ui-gen-review/SKILL.md +0 -266
  159. package/skills/adia-ui-gen-review/references/loop-protocol.md +0 -712
  160. package/skills/adia-ui-gen-review/references/rubric-cosmetic.md +0 -144
  161. package/skills/adia-ui-gen-review/references/rubric-decompose.md +0 -117
  162. package/skills/adia-ui-gen-review/references/rubric-score.md +0 -249
  163. package/skills/adia-ui-gen-review/references/teach-protocol.md +0 -214
  164. package/skills/adia-ui-gen-review/skill.json +0 -23
  165. package/skills/adia-ui-llm/CHANGELOG.md +0 -25
  166. package/skills/adia-ui-llm/SKILL.md +0 -165
  167. package/skills/adia-ui-llm/evals/adversarial-corpus.json +0 -75
  168. package/skills/adia-ui-llm/evals/routing-corpus.json +0 -30
  169. package/skills/adia-ui-llm/evals/teach-routing-cases.json +0 -73
  170. package/skills/adia-ui-llm/references/teach-protocol.md +0 -78
  171. package/skills/adia-ui-llm/scripts/audit-llm-roster.mjs +0 -93
  172. package/skills/adia-ui-llm/scripts/teach-route.mjs +0 -119
  173. package/skills/adia-ui-llm/skill.json +0 -33
  174. package/skills/adia-ui-ops/CHANGELOG.md +0 -291
  175. package/skills/adia-ui-ops/SKILL.md +0 -401
  176. package/skills/adia-ui-ops/references/INDEX.md +0 -158
  177. package/skills/adia-ui-ops/references/audit-cadence.md +0 -263
  178. package/skills/adia-ui-ops/references/audit-patterns/archive-link-sweep.md +0 -96
  179. package/skills/adia-ui-ops/references/audit-patterns/audit-history-ledger.md +0 -162
  180. package/skills/adia-ui-ops/references/audit-patterns/browser-bundle-node-imports.md +0 -154
  181. package/skills/adia-ui-ops/references/audit-patterns/changelog-unreleased-bloat.md +0 -75
  182. package/skills/adia-ui-ops/references/audit-patterns/coverage-gaps.md +0 -187
  183. package/skills/adia-ui-ops/references/audit-patterns/entry-file-coverage.md +0 -122
  184. package/skills/adia-ui-ops/references/audit-patterns/format-hygiene.md +0 -217
  185. package/skills/adia-ui-ops/references/audit-patterns/lockstep-versioning.md +0 -113
  186. package/skills/adia-ui-ops/references/audit-patterns/memory-fragmentation.md +0 -180
  187. package/skills/adia-ui-ops/references/audit-patterns/orphan-detection.md +0 -202
  188. package/skills/adia-ui-ops/references/audit-patterns/pointer-validation.md +0 -180
  189. package/skills/adia-ui-ops/references/audit-patterns/redundancy-detection.md +0 -210
  190. package/skills/adia-ui-ops/references/audit-patterns/spec-dating-sweep.md +0 -91
  191. package/skills/adia-ui-ops/references/audit-patterns/stale-content.md +0 -182
  192. package/skills/adia-ui-ops/references/audit-patterns/staleness-tooling.md +0 -156
  193. package/skills/adia-ui-ops/references/audit-patterns/token-waste-detection.md +0 -196
  194. package/skills/adia-ui-ops/references/doc-types/adr-pattern.md +0 -210
  195. package/skills/adia-ui-ops/references/doc-types/architecture-md.md +0 -190
  196. package/skills/adia-ui-ops/references/doc-types/changelog.md +0 -183
  197. package/skills/adia-ui-ops/references/doc-types/decisions-log.md +0 -146
  198. package/skills/adia-ui-ops/references/doc-types/plan-roadmap.md +0 -182
  199. package/skills/adia-ui-ops/references/doc-types/postmortem-pattern.md +0 -206
  200. package/skills/adia-ui-ops/references/genres/prose-and-writing.md +0 -149
  201. package/skills/adia-ui-ops/references/guidance/context-budget.md +0 -137
  202. package/skills/adia-ui-ops/references/guidance/llm-doc-writing.md +0 -116
  203. package/skills/adia-ui-ops/references/guidance/reliability-dial.md +0 -186
  204. package/skills/adia-ui-ops/references/recipes/adr-introduction.md +0 -211
  205. package/skills/adia-ui-ops/references/recipes/audit-existing-repo.md +0 -234
  206. package/skills/adia-ui-ops/references/recipes/cold-start-harvest.md +0 -263
  207. package/skills/adia-ui-ops/references/recipes/concurrent-learnings-merge.md +0 -158
  208. package/skills/adia-ui-ops/references/recipes/continuous-learning-loop.md +0 -169
  209. package/skills/adia-ui-ops/references/recipes/external-reference-verification.md +0 -158
  210. package/skills/adia-ui-ops/references/recipes/findings-index-readout.md +0 -126
  211. package/skills/adia-ui-ops/references/recipes/greenfield-setup.md +0 -252
  212. package/skills/adia-ui-ops/references/recipes/harvest-repo-brain.md +0 -169
  213. package/skills/adia-ui-ops/references/recipes/import-repo-brain-harvest.md +0 -153
  214. package/skills/adia-ui-ops/references/recipes/memory-organization.md +0 -182
  215. package/skills/adia-ui-ops/references/recipes/recommend-then-validate.md +0 -199
  216. package/skills/adia-ui-ops/references/recipes/self-healing-hooks.md +0 -366
  217. package/skills/adia-ui-ops/references/recipes/skill-stewardship-loop.md +0 -113
  218. package/skills/adia-ui-ops/references/standards/agents-md-spec.md +0 -138
  219. package/skills/adia-ui-ops/references/standards/claude-md-convention.md +0 -123
  220. package/skills/adia-ui-ops/references/standards/cross-tool-matrix.md +0 -85
  221. package/skills/adia-ui-ops/references/standards/readme-conventions.md +0 -232
  222. package/skills/adia-ui-ops/references/teach-protocol.md +0 -215
  223. package/skills/adia-ui-ops/scripts/audit-ops-roster.mjs +0 -104
  224. package/skills/adia-ui-ops/skill.json +0 -65
  225. package/skills/adia-ui-release/CHANGELOG.md +0 -66
  226. package/skills/adia-ui-release/SKILL.md +0 -323
  227. package/skills/adia-ui-release/assets/case-studies/2026-05-20-batch-push-v0.6.14-v0.6.15.md +0 -144
  228. package/skills/adia-ui-release/assets/case-studies/2026-05-20-corpus-drift-remediation-v0.6.15.md +0 -155
  229. package/skills/adia-ui-release/assets/case-studies/2026-05-20-version-skip-correction-v0.6.12.md +0 -114
  230. package/skills/adia-ui-release/assets/case-studies/2026-05-21-author-from-scratch-v0.6.18.md +0 -139
  231. package/skills/adia-ui-release/assets/case-studies/2026-05-21-feedback37-retraction-v0.6.21.md +0 -124
  232. package/skills/adia-ui-release/assets/case-studies/2026-05-21-fn1-enrichment-pass-v0.6.19.md +0 -125
  233. package/skills/adia-ui-release/assets/case-studies/2026-05-21-stale-test-detection-v0.6.20.md +0 -142
  234. package/skills/adia-ui-release/assets/case-studies/2026-05-23-freshness-gate-recovery-v0.6.32.md +0 -97
  235. package/skills/adia-ui-release/assets/case-studies/2026-05-26-catalog-drift-recurring-v0.6.40.md +0 -147
  236. package/skills/adia-ui-release/assets/templates/stub-changelog.template.md +0 -22
  237. package/skills/adia-ui-release/evals/evals.json +0 -164
  238. package/skills/adia-ui-release/references/changelog-discipline.md +0 -250
  239. package/skills/adia-ui-release/references/cycle-happy-path.md +0 -520
  240. package/skills/adia-ui-release/references/exe-deploy.md +0 -149
  241. package/skills/adia-ui-release/references/gates-catalog.md +0 -778
  242. package/skills/adia-ui-release/references/independent-package-release.md +0 -129
  243. package/skills/adia-ui-release/references/ledger-discipline.md +0 -232
  244. package/skills/adia-ui-release/references/migration-guide-authoring.md +0 -174
  245. package/skills/adia-ui-release/references/multi-agent-baseline.md +0 -207
  246. package/skills/adia-ui-release/references/notes-authoring.md +0 -212
  247. package/skills/adia-ui-release/references/recovery-paths.md +0 -262
  248. package/skills/adia-ui-release/references/rollup-notes.md +0 -208
  249. package/skills/adia-ui-release/references/teach-protocol.md +0 -468
  250. package/skills/adia-ui-release/scripts/audit-gate-roster.mjs +0 -196
  251. package/skills/adia-ui-release/scripts/make-ledger.mjs +0 -200
  252. package/skills/adia-ui-release/skill.json +0 -77
  253. package/skills/dogfood-sweep/CHANGELOG.md +0 -37
  254. package/skills/dogfood-sweep/README.md +0 -105
  255. package/skills/dogfood-sweep/SKILL.md +0 -1000
  256. package/skills/dogfood-sweep/analyze.mjs +0 -600
  257. package/skills/dogfood-sweep/skill.json +0 -31
  258. /package/skills/{adia-ui-authoring → adia-author}/references/api-contract.md +0 -0
  259. /package/skills/{adia-ui-release → adia-release}/scripts/assert-monorepo-root.mjs +0 -0
@@ -1,202 +0,0 @@
1
- ---
2
- date: 2026-04-27
3
- coverage: canonical
4
- peers:
5
- - pointer-validation.md
6
- - redundancy-detection.md
7
- - token-waste-detection.md
8
- - entry-file-coverage.md
9
- - ../recipes/self-healing-hooks.md
10
- primary_sources:
11
- - https://en.wikipedia.org/wiki/Reachability — graph reachability (the formal model behind orphan detection)
12
- - https://github.com/lycheeverse/lychee — secondary; lychee's `--reachable` mode does similar accounting
13
- - https://djw.fyi/portfolio/preventing-drift/ — Daryl White on doc archival flows
14
- status: research-verified
15
- ---
16
-
17
- # Orphan detection (delivers Promise 1, "less-wasteful")
18
-
19
- > **The premise.** A doc no one references is a doc no one reads — but it still costs tokens when a globbed `.brain/**/*.md` or `docs/**/*.md` load picks it up, still costs trust when a future reader finds it and can't tell whether it's current, and still drifts because no PR ever touches it. Orphans are the silent compounding cost of an unmaintained doc tree.
20
-
21
- ## The graph model
22
-
23
- Treat the repo as a directed graph:
24
-
25
- - **Nodes:** every Markdown file under `.brain/**` and `docs/**` plus the top-level entries (`AGENTS.md`, `CLAUDE.md`, `README.md`, `CONTRIBUTING.md`, etc.).
26
- - **Edges:** every relative-path link from one node to another (extracted by the same grammar `pointer-validation.md` uses).
27
- - **Roots:** `AGENTS.md` is the canonical root. `CLAUDE.md` (when fat), `README.md`, and `CONTRIBUTING.md` are secondary roots.
28
- - **Orphan:** any node in `.brain/**` or `docs/**` that is **not reachable** from any root.
29
-
30
- Reachability is transitive — if `AGENTS.md` links `ARCHITECTURE.md` and `ARCHITECTURE.md` links `docs/services/auth.md`, then `auth.md` is reachable.
31
-
32
- ## What this pattern catches
33
-
34
- | # | Class | Example | Severity |
35
- |---|---|---|---|
36
- | 1 | **Orphaned active doc** | `docs/setup-2024.md` not referenced; still describes current behavior | Medium |
37
- | 2 | **Orphaned stale doc** | `docs/old-redis-setup.md` not referenced AND last touched 18 months ago | Medium |
38
- | 3 | **Orphaned generated content** | `docs/api/Foo.md` from a typedoc dump nobody linked | Low (fix is `.gitignore`, not archive — see `redundancy-detection.md`) |
39
- | 4 | **Orphan with inbound link from outside `docs/`** | `docs/onboarding.md` linked from a `package.json` script comment but not from any doc | Low (advisory — re-link from AGENTS.md) |
40
-
41
- ## The bash check
42
-
43
- Two-pass set-difference: build the set of *files in `.brain/` + `docs/`*, build the set of *files referenced from a root or its transitive closure*, diff.
44
-
45
- ```bash
46
- #!/usr/bin/env bash
47
- # scripts/find-orphan-docs.sh — find .brain/*.md and docs/*.md unreachable from any root.
48
- set -euo pipefail
49
-
50
- all_docs=$(find .brain docs -type f -name '*.md' 2>/dev/null | sort -u)
51
-
52
- roots=()
53
- for r in AGENTS.md CLAUDE.md README.md CONTRIBUTING.md \
54
- .cursorrules .windsurfrules \
55
- .github/copilot-instructions.md .github/pull_request_template.md \
56
- .brain/README.md .brain/INDEX.md docs/README.md docs/INDEX.md; do
57
- [ -f "$r" ] && roots+=("$r")
58
- done
59
-
60
- # Extract resolved relative-path link targets from a Markdown file.
61
- extract_links() {
62
- local src_dir; src_dir=$(dirname "$1")
63
- grep -oE '\]\([^)]+\)' "$1" \
64
- | sed -E 's/^\]\(//; s/\)$//; s/[[:space:]]+["\x27].*$//; s/#.*$//' \
65
- | while read -r path; do
66
- case "$path" in ''|http://*|https://*|mailto:*|file://*) continue ;; esac
67
- if [ -d "$src_dir/$path" ]; then
68
- find "$src_dir/$path" -maxdepth 1 -name '*.md' 2>/dev/null
69
- else
70
- python3 -c "import os,sys; print(os.path.normpath('$src_dir/$path'))"
71
- fi
72
- done
73
- }
74
-
75
- # Transitive closure: BFS from roots.
76
- declare -A reachable
77
- queue=("${roots[@]}")
78
- while [ "${#queue[@]}" -gt 0 ]; do
79
- src="${queue[0]}"; queue=("${queue[@]:1}")
80
- [ -n "${reachable[$src]:-}" ] && continue
81
- reachable[$src]=1
82
- [ -f "$src" ] || continue
83
- while read -r t; do [ -f "$t" ] && queue+=("$t"); done < <(extract_links "$src")
84
- done
85
-
86
- for f in $all_docs; do
87
- [ -z "${reachable[$f]:-}" ] && \
88
- echo "ORPHAN: $f (last modified: $(git log -1 --format=%cs -- "$f"))"
89
- done
90
- ```
91
-
92
- Notes: `python3` only normalizes paths (swap for `realpath --relative-to=.` if unavailable). Reference-style links (`[text][ref]`) aren't parsed — use `lychee --include-paths` if needed.
93
-
94
- ## What to do with each orphan (the three-way choice)
95
-
96
- For every `ORPHAN: <file>` finding, the audit recommends one of three actions. **Always via PR**, never silently:
97
-
98
- ### (a) Re-link — orphan is still relevant
99
-
100
- The doc is current but unpointed. Add a link from AGENTS.md's "Where to find things" or the area `docs/<area>/README.md`:
101
-
102
- ```markdown
103
- # AGENTS.md (excerpt)
104
-
105
- ## Where to find things
106
-
107
- - **Architecture:** `.brain/architecture/`
108
- - **ADRs:** `.brain/adrs/`
109
- - **Onboarding:** `docs/onboarding.md` <-- newly re-linked
110
- - **Post-mortems:** `.brain/postmortems/`
111
- ```
112
-
113
- ### (b) Archive — orphan is obsolete-but-historic
114
-
115
- Cutting loses institutional memory; keeping in place invites confusion. Move to `.brain/archive/`:
116
-
117
- ```bash
118
- git mv docs/old-redis-setup.md .brain/archive/old-redis-setup.md
119
- git commit -m 'docs: archive old-redis-setup.md (orphan, obsolete since 2025-10 Redis -> Memorystore migration)'
120
- ```
121
-
122
- The `.brain/archive/` folder gets its own `README.md` listing what's in there and why it's archived. The audit *excludes* `.brain/archive/**` from the orphan scan (everything in there is intentionally orphaned).
123
-
124
- ### (c) Delete — if the orphan adds no value
125
-
126
- Truly obsolete content with no historical interest. **In a PR**, never silently:
127
-
128
- ```bash
129
- git rm docs/notes-from-old-design-meeting.md
130
- git commit -m 'docs: remove obsolete design-meeting notes (orphan, no longer relevant)'
131
- ```
132
-
133
- The PR description must say *why* — so a future reader who finds the deletion in `git log` understands the rationale.
134
-
135
- ## The 30-day grace period
136
-
137
- Per `../recipes/self-healing-hooks.md`, the auto-archive workflow does *not* archive on the first scan after a doc goes orphaned. The grace period is **30 days** of being orphaned-and-untouched before auto-archive proposes a PR.
138
-
139
- Reasons: (1) a PR in flight may temporarily orphan a doc while a link is being moved; (2) a planned re-link may be queued; (3) genuine forgotten orphans accumulate dust within 30 days regardless. The audit *report* always lists current orphans; the *auto-archive workflow* applies the 30-day floor before acting.
140
-
141
- ## Always-referencing files (avoid false positives)
142
-
143
- Some files act as *indices* — they enumerate every file in a folder, so every file in that folder is reachable by virtue of the index existing. Treat these as ALWAYS_REFERENCING in the orphan-scan reachability graph:
144
-
145
- | File | What it indexes |
146
- |---|---|
147
- | `.brain/adrs/README.md` | every ADR (`0001-*.md` … `NNNN-*.md`) |
148
- | `.brain/postmortems/README.md` | every postmortem |
149
- | `.brain/runbooks/README.md` | every runbook |
150
- | `docs/specs/INDEX.md` | every spec |
151
- | `docs/journal/README.md` | every dated journal entry |
152
-
153
- Without them in the entry-file set, every ADR / postmortem / runbook / spec / journal entry shows up as an orphan — a false-positive cluster that drowns the real findings. Observed in the wild on 2026-04-29: an audit pass flagged seven ADRs as orphans because the orphan-scan didn't include `.brain/adrs/README.md` as a referencer. Adding it resolved all seven.
154
-
155
- The rule is index-shaped: any folder with a `README.md` whose body is a *table* listing the folder's files counts as a referencer. Apply this in the entry-file set:
156
-
157
- ```bash
158
- ENTRY_FILES=(
159
- "AGENTS.md" "CLAUDE.md" "README.md" "PLAN.md" "ROADMAP.md"
160
- ".brain/adrs/README.md" # ← add these
161
- ".brain/postmortems/README.md"
162
- ".brain/runbooks/README.md"
163
- "docs/specs/INDEX.md"
164
- "docs/journal/README.md"
165
- )
166
- ```
167
-
168
- ## Excluding intentional orphans
169
-
170
- Some docs are intentionally orphaned. Mark them so the audit doesn't keep flagging:
171
-
172
- | Convention | What it does |
173
- |---|---|
174
- | Place file under `.brain/archive/**` | Excluded from orphan scan |
175
- | Add YAML frontmatter `orphan: intentional` | Excluded from orphan scan |
176
- | Add file to `.brain/ignore` (one path per line) | Excluded from orphan scan |
177
-
178
- The skill recommends `.brain/archive/` as the default — it's the most discoverable. Frontmatter and ignorefile are escape hatches.
179
-
180
- ## Severity rubric
181
-
182
- | Finding | Severity | Why |
183
- |---|---|---|
184
- | Orphaned doc that contradicts AGENTS.md (stale active content) | High | Causes drift if anyone finds and follows it |
185
- | Orphaned active doc (matches code/AGENTS.md but unlinked) | Medium | Useful content, agent never finds it |
186
- | Orphaned stale doc (>6mo old, no `_Last reviewed:_`) | Medium | Obsolete; archive candidate |
187
- | Orphaned generated content (typedoc/sphinx/etc.) | Low | Fix is `.gitignore`, not archive — see `redundancy-detection.md` |
188
- | Orphaned doc with inbound link from non-doc source (script comment, code) | Low | Re-link from AGENTS.md and move on |
189
-
190
- ## What this pattern is NOT for
191
-
192
- - **Files outside `.brain/` and `docs/`** — orphan-detection scope is `.brain/**` and `docs/**`. Top-level files (`LICENSE`, `package.json`) aren't candidates.
193
- - **Code files** — dead-code detection is a separate problem. This audit is about *documentation*.
194
- - **Folders with no `.md`** — assets-only folders (`docs/images/`) don't get scanned. They're referenced from inside `.md` files via `![alt](images/foo.png)`, which is a `pointer-validation.md` concern.
195
-
196
- ## Cross-references
197
-
198
- - Pointer validation (the inverse — links that don't resolve): `pointer-validation.md`
199
- - Redundancy detection (sibling Promise 1 audit): `redundancy-detection.md`
200
- - Token-waste detection (orphans contribute to glob-load tax): `token-waste-detection.md`
201
- - Entry-file coverage (the precondition — roots exist): `entry-file-coverage.md`
202
- - Auto-archive workflow + 30-day grace: `../recipes/self-healing-hooks.md`
@@ -1,180 +0,0 @@
1
- ---
2
- date: 2026-04-27
3
- coverage: canonical
4
- peers:
5
- - orphan-detection.md
6
- - stale-content.md
7
- - staleness-tooling.md
8
- - entry-file-coverage.md
9
- - ../recipes/self-healing-hooks.md
10
- primary_sources:
11
- - https://github.com/lycheeverse/lychee — fast Markdown/HTML link checker (Rust)
12
- - https://daringfireball.net/projects/markdown/syntax#link — original Markdown link syntax (Gruber)
13
- - https://spec.commonmark.org/0.31.2/#links — CommonMark 0.31.2 link grammar
14
- status: research-verified
15
- ---
16
-
17
- # Pointer validation (delivers Promise 1, "less-wasteful" + Promise 3, "less-prone-to-staleness")
18
-
19
- > **The premise.** A pointer that doesn't resolve is worse than no pointer. The agent follows the link, hits a 404, and either gives up (silent failure) or hallucinates (loud failure). This audit catches every relative-path reference in the repo's instruction graph and verifies it lands on a real file before the agent ever has to.
20
-
21
- ## What this pattern catches
22
-
23
- Five classes of broken pointer:
24
-
25
- | # | Class | Example | Severity |
26
- |---|---|---|---|
27
- | 1 | **Pointer to a renamed/moved file** | AGENTS.md says `docs/architecture.md`; file was moved to `.brain/architecture/overview.md` six months ago | High |
28
- | 2 | **Pointer to a never-existed file** | Author typo: `.brain/runbooks/databse.md` (missing the `a`) | High |
29
- | 3 | **Pointer to a folder without an index** | AGENTS.md says `.brain/adrs/`; folder exists but no `README.md` to land on | Medium |
30
- | 4 | **Pointer from canonical file to missing file** | AGENTS.md links `[Memory primitives](docs/memory.md)`; that file is gone | **Critical** |
31
- | 5 | **Repo-root file using `docs/`-relative paths** | `PLAN.md` at repo root has `[spec](./specs/foo.md)`; resolves to `./specs/foo.md` (404), should be `./docs/specs/foo.md` | **Critical** |
32
-
33
- Class 4 is the load-bearing case: the canonical entry file is the agent's single source of truth, and a broken link from it is a broken promise to every agent on every session.
34
-
35
- Class 5 is a particularly nasty failure mode that surfaces when a doc gets moved between directories without its links being rewritten. **Watch for it** when `PLAN.md` / `ROADMAP.md` / `CHANGELOG.md` move from `docs/` to repo root (or vice versa), or when `docs/foo/bar.md` is hoisted to `docs/bar.md`. The check below catches it because relative-path resolution starts from the source file's directory — but human reviewers miss it constantly because the *display text* often shows the correct path while the link itself is wrong:
36
-
37
- ```markdown
38
- [`docs/specs/genui-multiturn.md`](./specs/genui-multiturn.md)
39
- ↑ broken — file is at root, not docs/
40
- ```
41
-
42
- Observed in the wild on 2026-04-29: 25+ broken intra-repo links across `PLAN.md` + `ROADMAP.md` after the files were moved from `docs/` to repo root. Display text was correct on every link; targets all wrong.
43
-
44
- ## Scope: what files we validate pointers from
45
-
46
- | File | Why |
47
- |---|---|
48
- | `AGENTS.md` | Canonical entry; every link must resolve |
49
- | `CLAUDE.md` (when fat) | Same as AGENTS.md while it's still fat; once thin-pointered the only link is to AGENTS.md |
50
- | `README.md` | Human + agent landing |
51
- | `CONTRIBUTING.md` | Often points at `docs/dev-setup.md` etc. |
52
- | `.brain/**/*.md`, `docs/**/*.md` | Doc-to-doc links must resolve too |
53
- | `.cursor/rules/*.mdc`, `.windsurfrules`, `.github/copilot-instructions.md` | If fat, validate; if thin pointers to AGENTS.md, only the one link to validate |
54
- | `.github/pull_request_template.md` | Often points at ADR conventions / contribution guides |
55
-
56
- Validate **relative paths only**. External URLs are `lychee`'s job — see `staleness-tooling.md` for the tool wiring. `lychee` will *also* check intra-repo paths, but the skill implements its own check so the audit can run offline and produce structured findings independent of `lychee` being installed.
57
-
58
- ## The bash check (intra-repo links)
59
-
60
- The link-extraction grammar (CommonMark 0.31.2 §6.3) is `[text](target)` with optional title. We capture `target` and check it.
61
-
62
- ```bash
63
- #!/usr/bin/env bash
64
- # scripts/check-pointers.sh
65
- # Validate every relative-path link in entry + docs files.
66
- set -euo pipefail
67
-
68
- # Files we extract pointers from.
69
- candidates=(
70
- AGENTS.md CLAUDE.md README.md CONTRIBUTING.md
71
- .cursorrules .windsurfrules
72
- .github/copilot-instructions.md
73
- .github/pull_request_template.md
74
- )
75
- for f in .brain/**/*.md .brain/*.md docs/**/*.md docs/*.md .cursor/rules/*.mdc 2>/dev/null; do
76
- [ -f "$f" ] && candidates+=("$f")
77
- done
78
-
79
- fail=0
80
- for src in "${candidates[@]}"; do
81
- [ -f "$src" ] || continue
82
- # Extract the (target) of every Markdown link, drop quoted titles.
83
- grep -oE '\]\([^)]+\)' "$src" \
84
- | sed -E 's/^\]\(//; s/\)$//; s/[[:space:]]+["\x27].*$//' \
85
- | sort -u \
86
- | while read -r target; do
87
- # Skip empty, anchors-only, mailto:, and absolute URLs.
88
- case "$target" in
89
- ''|'#'*|mailto:*|http://*|https://*|ftp://*|file://*) continue ;;
90
- esac
91
- # Strip fragment (#section) before resolving.
92
- path="${target%%#*}"
93
- [ -z "$path" ] && continue
94
- # Resolve relative to the source file's directory.
95
- src_dir=$(dirname "$src")
96
- resolved="$src_dir/$path"
97
- # Folder pointer? Accept if folder exists and has a README.md or any *.md.
98
- if [ -d "$resolved" ]; then
99
- if [ -f "$resolved/README.md" ] || ls "$resolved"/*.md >/dev/null 2>&1; then
100
- continue
101
- fi
102
- echo "EMPTY-FOLDER-POINTER: $src -> $target (folder exists but no .md inside)"
103
- fail=1
104
- continue
105
- fi
106
- # File pointer.
107
- if [ ! -f "$resolved" ]; then
108
- echo "BROKEN-POINTER: $src -> $target (resolved: $resolved)"
109
- fail=1
110
- fi
111
- done
112
- done
113
- exit $fail
114
- ```
115
-
116
- Dedupe is done by `sort -u` per file — the same target referenced 5 times in one file emits only one finding.
117
-
118
- ## The dedupe step (why it matters for the report)
119
-
120
- A 200-line AGENTS.md often references `.brain/adrs/` 4-6 times (Where-to-find-things, Memory-primitives, Conventions, etc.). Without dedupe, a single broken folder produces a 6-line report. Dedupe per-source-file before reporting; the same target broken from multiple files is genuinely worth multiple findings (it tells you *where* to fix).
121
-
122
- ## Folder-pointer special case
123
-
124
- A pointer like `.brain/adrs/` is not a file — it's a folder. The check passes if:
125
-
126
- 1. The folder exists, AND
127
- 2. The folder has a `README.md`, OR
128
- 3. The folder contains at least one `.md` file (so the agent can list and pick).
129
-
130
- A folder with `.png` and `.svg` only is not a valid landing target for a doc pointer. Flag it with `EMPTY-FOLDER-POINTER`.
131
-
132
- ## External link validation (out of scope for this check)
133
-
134
- External URLs (`https://...`) are validated by `lychee` per `staleness-tooling.md`. Reasons we keep them separate:
135
-
136
- - External checks need network; intra-repo checks must run offline.
137
- - External links rate-limit; intra-repo links are free.
138
- - External links are validated weekly (cron) per `../recipes/self-healing-hooks.md`; intra-repo links are validated on every commit.
139
-
140
- If you want a one-shot "all links" pass, run both sequentially:
141
-
142
- ```bash
143
- bash scripts/check-pointers.sh # intra-repo, fast, offline
144
- lychee --no-progress '.brain/**/*.md' 'docs/**/*.md' '*.md' # external + intra-repo, network-bound
145
- ```
146
-
147
- The intra-repo check is allowed to be redundant with `lychee --offline`; what it adds is structured output the audit pipeline can ingest without parsing `lychee` JSON.
148
-
149
- ## Severity rubric
150
-
151
- | Finding | Severity | Why |
152
- |---|---|---|
153
- | Broken pointer **from AGENTS.md** to a canonical file (`.brain/adrs/`, `.brain/postmortems/`, `.brain/architecture/`) | **Critical** | Agent's primary memory map is wrong; trust collapses |
154
- | Broken pointer from any other entry file (`CLAUDE.md`, `README.md`, `.cursor/rules/`) | High | Agent following that tool will hit 404 |
155
- | Broken doc-to-doc pointer in `.brain/**` or `docs/**` | High | Reachable but breaks navigation graph |
156
- | Empty-folder pointer (`.brain/runbooks/` exists, no `.md` inside) | Medium | Agent lands but finds nothing actionable |
157
- | Pointer with stale fragment (`docs/foo.md#old-section` where the file exists but the anchor doesn't) | Low | File loads, agent skim-reads; advisory |
158
-
159
- The fragment check (`#section-name` resolves to a real heading slug) is supported by `lychee --include-fragments` and is the cleanest way to catch class 5. Don't reimplement slug-generation in bash; pay the lychee dependency.
160
-
161
- ## What this pattern is NOT for
162
-
163
- - **External links** — `staleness-tooling.md`'s `lychee` integration owns those.
164
- - **Symbol references inside prose** — "the `FooHandler` class" is a *content* claim, not a pointer; it's covered by `stale-content.md`.
165
- - **Image / asset paths** — same machinery works (`![alt](path/to/img.png)`), but assets are usually checked-in alongside the doc, so failures are rare. The check above will catch them anyway.
166
- - **Reference-style links** (`[text][ref]` with `[ref]: target` later in the file) — the bash above doesn't parse them. CommonMark §6.3.2. If your repo uses them, swap to a Python parser (`markdown-it-py`) or run `lychee --offline` which handles them natively.
167
-
168
- ## How AGENTS.md's pointers become self-healing
169
-
170
- The pre-commit hook in `../recipes/self-healing-hooks.md` runs this check on every commit that touches `AGENTS.md`, `CLAUDE.md`, `README.md`, `CONTRIBUTING.md`, or any file under `.brain/**` or `docs/**`. A broken pointer fails the commit — the author is forced to fix it locally. This is the cheapest place to catch it; by the time it reaches CI, the author has already context-switched.
171
-
172
- The weekly cron (`repo-brain-weekly.yml`) re-runs the check across the whole repo (in case a PR touched a target without touching the source pointing at it — the canonical "rename without re-link" case).
173
-
174
- ## Cross-references
175
-
176
- - Orphan detection (the inverse — files no one points at): `orphan-detection.md`
177
- - Stale content (symbol-level rot): `stale-content.md`
178
- - External link checking: `staleness-tooling.md`
179
- - Entry-file coverage (the precondition — entry files exist): `entry-file-coverage.md`
180
- - Self-healing hooks (where the check runs automatically): `../recipes/self-healing-hooks.md`
@@ -1,210 +0,0 @@
1
- ---
2
- date: 2026-04-27
3
- coverage: canonical
4
- peers:
5
- - orphan-detection.md
6
- - token-waste-detection.md
7
- - ../standards/claude-md-convention.md
8
- - ../recipes/self-healing-hooks.md
9
- primary_sources:
10
- - https://github.com/anthropics/claude-code/issues/31005
11
- status: research-verified
12
- ---
13
-
14
- # Redundancy detection (delivers Promise 1, "less-wasteful")
15
-
16
- > **The premise.** Redundancy is waste *and* drift waiting to happen. Two files saying "use pnpm" will, eventually, disagree — one will say `pnpm`, the other will say `npm` after a sloppy edit. The audit's job is to detect redundancy *before* it drifts.
17
-
18
- ## What this pattern catches
19
-
20
- Five classes of redundancy:
21
-
22
- | Class | Example | Severity |
23
- |---|---|---|
24
- | **Drift between entry files** | CLAUDE.md and AGENTS.md both fat with substantively different content | Critical |
25
- | **Repeated commands** | Build commands listed in AGENTS.md, README.md, AND CONTRIBUTING.md | Medium |
26
- | **Repeated facts** | "We use Postgres" stated in AGENTS.md, ARCHITECTURE.md, AND README.md | Low |
27
- | **Verbose-vs-tabular duplication** | Same conventions written as prose AND as a table later in the same file | Low |
28
- | **Generated content checked in alongside source** | API reference markdown alongside the docstrings it was generated from | Medium |
29
-
30
- ## Drift between entry files (the critical case)
31
-
32
- This is the audit's single most-important check. Claude Code reads CLAUDE.md, every other agent reads AGENTS.md natively (per `cross-tool-matrix.md`). When the two files contain different instructions, the team has two failure modes simultaneously:
33
-
34
- 1. **Claude Code follows out-of-date rules** (because CLAUDE.md is stale).
35
- 2. **Cursor/Codex/Devin follow out-of-date rules** (because AGENTS.md is stale).
36
-
37
- The fix is the canonical model from this skill: AGENTS.md fat, CLAUDE.md as symlink or thin pointer.
38
-
39
- ### Detection logic
40
-
41
- ```bash
42
- # Pseudocode for the drift check
43
- if [ ! -f AGENTS.md ] || [ ! -f CLAUDE.md ]; then
44
- # No drift possible
45
- exit 0
46
- fi
47
-
48
- if [ -L CLAUDE.md ] && [ "$(readlink CLAUDE.md)" = "AGENTS.md" ]; then
49
- # Symlink → identical content
50
- exit 0
51
- fi
52
-
53
- claude_lines=$(wc -l < CLAUDE.md)
54
- if [ "$claude_lines" -le 15 ] && grep -qi 'AGENTS.md' CLAUDE.md; then
55
- # Thin pointer → no fat content to drift
56
- exit 0
57
- fi
58
-
59
- # Both fat → drift risk; emit finding
60
- echo "DRIFT — CLAUDE.md ($claude_lines lines) vs AGENTS.md ($(wc -l <AGENTS.md) lines)"
61
- echo " Diff highlights:"
62
- diff <(grep -v '^$' CLAUDE.md) <(grep -v '^$' AGENTS.md) | head -20
63
- ```
64
-
65
- The full hook is in `../recipes/self-healing-hooks.md`.
66
-
67
- ### Recipe to fix
68
-
69
- ```bash
70
- # Pick AGENTS.md as canonical (recommended).
71
- # Move CLAUDE.md content into AGENTS.md, deduplicating.
72
- # Then:
73
-
74
- # Option A: symlink (cleanest)
75
- rm CLAUDE.md
76
- ln -s AGENTS.md CLAUDE.md
77
- git add CLAUDE.md
78
- git commit -m 'docs: CLAUDE.md → symlink to AGENTS.md (eliminate drift)'
79
-
80
- # Option B: thin pointer (works on Windows, no symlink quirks)
81
- cat > CLAUDE.md <<'EOF'
82
- # CLAUDE.md
83
-
84
- This repo's instructions for LLM coding agents live in [`AGENTS.md`](./AGENTS.md).
85
- Please read that file. The contents apply identically to Claude Code.
86
-
87
- _Last reviewed: 2026-04-27_
88
- EOF
89
- git add CLAUDE.md
90
- git commit -m 'docs: CLAUDE.md → thin pointer to AGENTS.md'
91
- ```
92
-
93
- ## Repeated commands
94
-
95
- A common pattern: build/test/run commands appear in AGENTS.md, README.md, and CONTRIBUTING.md. Each is true at the moment of writing; one will eventually drift.
96
-
97
- ### Detection
98
-
99
- ```bash
100
- # Heuristic: extract code-fenced shell blocks from each file, hash them, find duplicates.
101
- for f in AGENTS.md README.md CONTRIBUTING.md .brain/**/*.md docs/**/*.md; do
102
- [ -f "$f" ] || continue
103
- awk '/^```(bash|sh|shell)/,/^```$/' "$f" | sha256sum | awk -v f="$f" '{print f, $1}'
104
- done | sort -k2 | awk '{
105
- if ($2 == prev_hash) print "DUPLICATE: " prev_file " <-> " $1;
106
- prev_file = $1; prev_hash = $2
107
- }'
108
- ```
109
-
110
- Tighter heuristic: parse out individual commands (lines starting with `$ ` or matching `pnpm|npm|yarn|cargo|go run`) and find which appear in multiple files.
111
-
112
- ### Fix recipe
113
-
114
- Pick a canonical home (AGENTS.md is typical). Other files reference it:
115
-
116
- ```markdown
117
- # README.md (excerpt)
118
-
119
- ## Build / test / run
120
-
121
- See [`AGENTS.md`](./AGENTS.md) for build, test, and run commands.
122
- ```
123
-
124
- ```markdown
125
- # CONTRIBUTING.md (excerpt)
126
-
127
- ## Local setup
128
-
129
- For build / test / run commands, see [`AGENTS.md`](./AGENTS.md). For
130
- contribution conventions, continue below.
131
- ```
132
-
133
- The agent reads AGENTS.md every session anyway, so this isn't a navigation cost.
134
-
135
- ## Repeated facts
136
-
137
- Lower severity: same fact ("we use Postgres") appears in 3 places. The fact rarely changes, so drift risk is low — but tokens are wasted on each load.
138
-
139
- ### Detection
140
-
141
- This is hard to automate well — paraphrased duplicates evade hashing. Practical approach: look for *named entities* (technology names, version numbers, named services) that appear in multiple top-level docs, and surface as "consider consolidating."
142
-
143
- ```bash
144
- # Heuristic: find tech names that appear in 3+ entry-level docs
145
- grep -l -i -E '\b(postgres|mysql|redis|kafka|s3|aws|gcp|azure)\b' \
146
- AGENTS.md README.md CONTRIBUTING.md ARCHITECTURE.md 2>/dev/null \
147
- | sort | uniq -c | sort -rn | awk '$1 >= 3 { print "POSSIBLE-REDUNDANCY: " $2 }'
148
- ```
149
-
150
- Treat as advisory; humans decide whether to consolidate.
151
-
152
- ## Verbose-vs-tabular duplication within one file
153
-
154
- A surprisingly common pattern: AGENTS.md says
155
-
156
- > "We use TypeScript with strict mode enabled. Our test runner is Vitest. We use Conventional Commits for commit messages. ESLint is configured for our coding style."
157
-
158
- ...and then *also* has:
159
-
160
- ```markdown
161
- | Tool | Choice |
162
- |---|---|
163
- | Language | TypeScript (strict) |
164
- | Tests | Vitest |
165
- | Commits | Conventional |
166
- | Linting | ESLint |
167
- ```
168
-
169
- Both communicate the same facts. Cut the prose, keep the table — bullets/tables are denser and the agent prefers them.
170
-
171
- ### Detection
172
-
173
- Hard. Practical heuristic: flag files with both `^>` blockquotes longer than 100 chars AND a Markdown table covering similar content. Manual review.
174
-
175
- ## Generated content checked in
176
-
177
- If the project generates API reference markdown (TypeDoc, sphinx, mkdocs-jsdoc, rustdoc → md, etc.), don't check in the output:
178
-
179
- ```
180
- # .gitignore (excerpt)
181
- docs/api/ # generated by `pnpm docs:generate`
182
- docs/typedoc/ # generated by TypeDoc
183
- ```
184
-
185
- The audit signal: many `.md` files in `docs/api/` or `docs/typedoc/` that look auto-generated (template-driven structure, very uniform front-matter, mass-modified in single commits). These get loaded as orphan candidates by the orphan-detection pass — but the right fix is `.gitignore`, not archive.
186
-
187
- ## Severity rubric
188
-
189
- | Finding | Severity | Why |
190
- |---|---|---|
191
- | AGENTS.md / CLAUDE.md drift (both fat, divergent) | Critical | Causes Claude Code and other agents to follow different rules |
192
- | Repeated build commands across 3+ files | Medium | High drift risk over time |
193
- | Repeated facts (named entities) across 3+ docs | Low | Drift risk lower; tokens wasted |
194
- | Verbose+tabular duplication in same file | Low | Internal redundancy; advisory |
195
- | Generated content checked in | Medium | Bloats repo, confuses orphan detection |
196
-
197
- ## What this pattern is NOT for
198
-
199
- - **Repeated *links*** are good. Linking to AGENTS.md from README.md is fine — it's *not* duplicating content, it's pointing to it.
200
- - **Repeated section headers** (every ADR has a "Status:" section) are not redundancy — they're structural convention.
201
- - **Repeated examples** in docs (e.g., the same `pnpm install` shown in a setup walkthrough) are not redundancy if each appears in a different procedural context.
202
-
203
- ## Cross-references
204
-
205
- - Orphan detection (sibling Promise 1 audit): `orphan-detection.md`
206
- - Token-waste detection (sibling Promise 2 audit): `token-waste-detection.md`
207
- - CLAUDE.md thin-pointer recipe: `../standards/claude-md-convention.md`
208
- - Self-healing hooks (where the drift trip-wire lives): `../recipes/self-healing-hooks.md`
209
- - Concurrent learnings merge (uses this trip-wire as the post-merge backstop): `../recipes/concurrent-learnings-merge.md`
210
- - Cold-start harvest (uses this trip-wire to detect imported conflicts in phase 5): `../recipes/cold-start-harvest.md`