@erclx/canon 4.0.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 (643) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -0
  3. package/claude/.claude-plugin/plugin.json +19 -0
  4. package/claude/skills/bash-cli-script/REQUIREMENT.md +42 -0
  5. package/claude/skills/bash-cli-script/SKILL.md +48 -0
  6. package/claude/skills/bash-cli-script/references/template.md +43 -0
  7. package/claude/skills/bash-script/REQUIREMENT.md +36 -0
  8. package/claude/skills/bash-script/SKILL.md +100 -0
  9. package/claude/skills/bash-script/references/patterns.md +349 -0
  10. package/claude/skills/canon-cli/REQUIREMENT.md +41 -0
  11. package/claude/skills/canon-cli/SKILL.md +103 -0
  12. package/claude/skills/canon-feedback-file/REQUIREMENT.md +40 -0
  13. package/claude/skills/canon-feedback-file/SKILL.md +80 -0
  14. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +40 -0
  15. package/claude/skills/canon-feedback-triage/SKILL.md +63 -0
  16. package/claude/skills/canon-operator/REQUIREMENT.md +61 -0
  17. package/claude/skills/canon-operator/SKILL.md +108 -0
  18. package/claude/skills/canon-rollout/REQUIREMENT.md +59 -0
  19. package/claude/skills/canon-rollout/SKILL.md +147 -0
  20. package/claude/skills/canon-screencast/REQUIREMENT.md +39 -0
  21. package/claude/skills/canon-screencast/SKILL.md +167 -0
  22. package/claude/skills/canon-slides-draft/REQUIREMENT.md +39 -0
  23. package/claude/skills/canon-slides-draft/SKILL.md +62 -0
  24. package/claude/skills/ci-workflow/REQUIREMENT.md +40 -0
  25. package/claude/skills/ci-workflow/SKILL.md +65 -0
  26. package/claude/skills/ci-workflow/references/workflows.md +98 -0
  27. package/claude/skills/claude-address-review/REQUIREMENT.md +57 -0
  28. package/claude/skills/claude-address-review/SKILL.md +212 -0
  29. package/claude/skills/claude-address-review/references/rebase-conflicts.md +39 -0
  30. package/claude/skills/claude-autoship/REQUIREMENT.md +50 -0
  31. package/claude/skills/claude-autoship/SKILL.md +207 -0
  32. package/claude/skills/claude-design-extract/REQUIREMENT.md +42 -0
  33. package/claude/skills/claude-design-extract/SKILL.md +102 -0
  34. package/claude/skills/claude-diagram/REQUIREMENT.md +45 -0
  35. package/claude/skills/claude-diagram/SKILL.md +177 -0
  36. package/claude/skills/claude-docs/REQUIREMENT.md +60 -0
  37. package/claude/skills/claude-docs/SKILL.md +287 -0
  38. package/claude/skills/claude-docs/references/anchor-sweep.md +58 -0
  39. package/claude/skills/claude-docs/references/wireframe-sweep.md +45 -0
  40. package/claude/skills/claude-feature/REQUIREMENT.md +36 -0
  41. package/claude/skills/claude-feature/SKILL.md +115 -0
  42. package/claude/skills/claude-groundwork/REQUIREMENT.md +48 -0
  43. package/claude/skills/claude-groundwork/SKILL.md +142 -0
  44. package/claude/skills/claude-intake/REQUIREMENT.md +49 -0
  45. package/claude/skills/claude-intake/SKILL.md +114 -0
  46. package/claude/skills/claude-intake-answer/REQUIREMENT.md +48 -0
  47. package/claude/skills/claude-intake-answer/SKILL.md +90 -0
  48. package/claude/skills/claude-markdown-propose/REQUIREMENT.md +48 -0
  49. package/claude/skills/claude-markdown-propose/SKILL.md +118 -0
  50. package/claude/skills/claude-markdown-propose/references/format.md +107 -0
  51. package/claude/skills/claude-memory-capture/REQUIREMENT.md +50 -0
  52. package/claude/skills/claude-memory-capture/SKILL.md +101 -0
  53. package/claude/skills/claude-memory-review/REQUIREMENT.md +50 -0
  54. package/claude/skills/claude-memory-review/SKILL.md +210 -0
  55. package/claude/skills/claude-memory-review/references/receipt-format.md +48 -0
  56. package/claude/skills/claude-orchestrate/REQUIREMENT.md +121 -0
  57. package/claude/skills/claude-orchestrate/SKILL.md +241 -0
  58. package/claude/skills/claude-orchestrate/references/orchestrator-dispatch.md +132 -0
  59. package/claude/skills/claude-orchestrate/references/orchestrator-handoff.md +32 -0
  60. package/claude/skills/claude-orchestrate/references/orchestrator-parked.md +72 -0
  61. package/claude/skills/claude-orchestrate/references/orchestrator-poll.md +87 -0
  62. package/claude/skills/claude-orchestrate/references/orchestrator-resume.md +30 -0
  63. package/claude/skills/claude-orchestrate/references/orchestrator-sweep.md +21 -0
  64. package/claude/skills/claude-orchestrate/scripts/poll.sh +373 -0
  65. package/claude/skills/claude-orchestrate/scripts/watch.sh +181 -0
  66. package/claude/skills/claude-pr-review/REQUIREMENT.md +47 -0
  67. package/claude/skills/claude-pr-review/SKILL.md +295 -0
  68. package/claude/skills/claude-review/REQUIREMENT.md +39 -0
  69. package/claude/skills/claude-review/SKILL.md +142 -0
  70. package/claude/skills/claude-seed-sync/REQUIREMENT.md +45 -0
  71. package/claude/skills/claude-seed-sync/SKILL.md +156 -0
  72. package/claude/skills/claude-standards-audit/REQUIREMENT.md +33 -0
  73. package/claude/skills/claude-standards-audit/SKILL.md +99 -0
  74. package/claude/skills/claude-tasks/REQUIREMENT.md +43 -0
  75. package/claude/skills/claude-tasks/SKILL.md +161 -0
  76. package/claude/skills/claude-teach/REQUIREMENT.md +56 -0
  77. package/claude/skills/claude-teach/SKILL.md +196 -0
  78. package/claude/skills/claude-teach/references/lesson-craft.md +59 -0
  79. package/claude/skills/claude-teach/references/pedagogy.md +67 -0
  80. package/claude/skills/claude-teach/references/promotion.md +54 -0
  81. package/claude/skills/claude-ui-test/REQUIREMENT.md +40 -0
  82. package/claude/skills/claude-ui-test/SKILL.md +77 -0
  83. package/claude/skills/claude-ux-audit/REQUIREMENT.md +40 -0
  84. package/claude/skills/claude-ux-audit/SKILL.md +79 -0
  85. package/claude/skills/claude-ux-measure/REQUIREMENT.md +48 -0
  86. package/claude/skills/claude-ux-measure/SKILL.md +122 -0
  87. package/claude/skills/claude-worker/REQUIREMENT.md +54 -0
  88. package/claude/skills/claude-worker/SKILL.md +96 -0
  89. package/claude/skills/claude-worktree/REQUIREMENT.md +58 -0
  90. package/claude/skills/claude-worktree/SKILL.md +136 -0
  91. package/claude/skills/create-rule/REQUIREMENT.md +45 -0
  92. package/claude/skills/create-rule/SKILL.md +68 -0
  93. package/claude/skills/create-skill/REQUIREMENT.md +38 -0
  94. package/claude/skills/create-skill/SKILL.md +32 -0
  95. package/claude/skills/create-snippet/REQUIREMENT.md +39 -0
  96. package/claude/skills/create-snippet/SKILL.md +30 -0
  97. package/claude/skills/create-standard/REQUIREMENT.md +35 -0
  98. package/claude/skills/create-standard/SKILL.md +29 -0
  99. package/claude/skills/decision-escalate/REQUIREMENT.md +45 -0
  100. package/claude/skills/decision-escalate/SKILL.md +79 -0
  101. package/claude/skills/docs-sync/REQUIREMENT.md +41 -0
  102. package/claude/skills/docs-sync/SKILL.md +95 -0
  103. package/claude/skills/git-branch/REQUIREMENT.md +38 -0
  104. package/claude/skills/git-branch/SKILL.md +60 -0
  105. package/claude/skills/git-commit/REQUIREMENT.md +36 -0
  106. package/claude/skills/git-commit/SKILL.md +49 -0
  107. package/claude/skills/git-followup/REQUIREMENT.md +43 -0
  108. package/claude/skills/git-followup/SKILL.md +48 -0
  109. package/claude/skills/git-issue/REQUIREMENT.md +38 -0
  110. package/claude/skills/git-issue/SKILL.md +65 -0
  111. package/claude/skills/git-pr/REQUIREMENT.md +50 -0
  112. package/claude/skills/git-pr/SKILL.md +164 -0
  113. package/claude/skills/git-pr/references/labels.md +95 -0
  114. package/claude/skills/git-ship/REQUIREMENT.md +42 -0
  115. package/claude/skills/git-ship/SKILL.md +55 -0
  116. package/claude/skills/git-split/REQUIREMENT.md +39 -0
  117. package/claude/skills/git-split/SKILL.md +162 -0
  118. package/claude/skills/git-stage/REQUIREMENT.md +39 -0
  119. package/claude/skills/git-stage/SKILL.md +73 -0
  120. package/claude/skills/git-worktree/REQUIREMENT.md +38 -0
  121. package/claude/skills/git-worktree/SKILL.md +130 -0
  122. package/claude/skills/migration-claude-md/REQUIREMENT.md +40 -0
  123. package/claude/skills/migration-claude-md/SKILL.md +76 -0
  124. package/claude/skills/migration-context/REQUIREMENT.md +36 -0
  125. package/claude/skills/migration-context/SKILL.md +95 -0
  126. package/claude/skills/migration-standards-drop/REQUIREMENT.md +55 -0
  127. package/claude/skills/migration-standards-drop/SKILL.md +113 -0
  128. package/claude/skills/migration-superseded/REQUIREMENT.md +44 -0
  129. package/claude/skills/migration-superseded/SKILL.md +115 -0
  130. package/claude/skills/project-commands/REQUIREMENT.md +42 -0
  131. package/claude/skills/project-commands/SKILL.md +85 -0
  132. package/claude/skills/restate-plainly/REQUIREMENT.md +41 -0
  133. package/claude/skills/restate-plainly/SKILL.md +39 -0
  134. package/claude/skills/session-map/REQUIREMENT.md +57 -0
  135. package/claude/skills/session-map/SKILL.md +70 -0
  136. package/claude/skills/session-resume/REQUIREMENT.md +49 -0
  137. package/claude/skills/session-resume/SKILL.md +51 -0
  138. package/claude/skills/setup-gov/REQUIREMENT.md +37 -0
  139. package/claude/skills/setup-gov/SKILL.md +77 -0
  140. package/claude/skills/setup-indexes/REQUIREMENT.md +45 -0
  141. package/claude/skills/setup-indexes/SKILL.md +153 -0
  142. package/claude/skills/setup-init/REQUIREMENT.md +45 -0
  143. package/claude/skills/setup-init/SKILL.md +127 -0
  144. package/claude/skills/setup-plugins/REQUIREMENT.md +42 -0
  145. package/claude/skills/setup-plugins/SKILL.md +81 -0
  146. package/claude/skills/setup-plugins/references/plugin-catalog.md +53 -0
  147. package/claude/skills/setup-verify/REQUIREMENT.md +39 -0
  148. package/claude/skills/setup-verify/SKILL.md +51 -0
  149. package/claude/skills/systematic-debugging/REQUIREMENT.md +41 -0
  150. package/claude/skills/systematic-debugging/SKILL.md +70 -0
  151. package/claude/skills/write-human/REQUIREMENT.md +46 -0
  152. package/claude/skills/write-human/SKILL.md +68 -0
  153. package/claude/skills/write-human/references/density.md +38 -0
  154. package/claude/skills/write-human/references/machine-tells.md +107 -0
  155. package/claude/skills/write-human/references/source-material.md +37 -0
  156. package/claude/skills/youtube-transcripts/REQUIREMENT.md +38 -0
  157. package/claude/skills/youtube-transcripts/SKILL.md +34 -0
  158. package/docs/agents/audits.md +98 -0
  159. package/docs/agents/capture.md +37 -0
  160. package/docs/agents/census.md +23 -0
  161. package/docs/agents/commands.md +146 -0
  162. package/docs/agents/comments.md +34 -0
  163. package/docs/agents/context-audit-checks.md +120 -0
  164. package/docs/agents/context-audit.md +83 -0
  165. package/docs/agents/counts.md +76 -0
  166. package/docs/agents/demo.md +86 -0
  167. package/docs/agents/docs.md +17 -0
  168. package/docs/agents/gate.md +84 -0
  169. package/docs/agents/index.md +47 -0
  170. package/docs/agents/indexes.md +35 -0
  171. package/docs/agents/install-and-sync.md +385 -0
  172. package/docs/agents/intake.md +81 -0
  173. package/docs/agents/key-changes.md +103 -0
  174. package/docs/agents/label-coverage.md +73 -0
  175. package/docs/agents/markdown-audit.md +197 -0
  176. package/docs/agents/output-shape.md +70 -0
  177. package/docs/agents/overview.md +26 -0
  178. package/docs/agents/records.md +170 -0
  179. package/docs/agents/restated.md +81 -0
  180. package/docs/agents/review-classification.md +77 -0
  181. package/docs/agents/routing.md +61 -0
  182. package/docs/agents/rule-citations.md +98 -0
  183. package/docs/agents/sandbox.md +71 -0
  184. package/docs/agents/scripting.md +149 -0
  185. package/docs/agents/sessions.md +120 -0
  186. package/docs/agents/skills-audit.md +94 -0
  187. package/docs/agents/skills-reach.md +64 -0
  188. package/docs/agents/standards-audit.md +38 -0
  189. package/docs/agents/state-scoped-risk.md +105 -0
  190. package/docs/agents/superseded.md +85 -0
  191. package/docs/agents/targets.md +83 -0
  192. package/docs/agents/tasks.md +200 -0
  193. package/docs/agents/teach.md +158 -0
  194. package/docs/agents/test-order.md +56 -0
  195. package/docs/agents/worktrees.md +62 -0
  196. package/docs/ai-workflow.md +317 -0
  197. package/docs/index.md +23 -0
  198. package/docs/operating-model.md +223 -0
  199. package/docs/target-projects.md +258 -0
  200. package/docs/visual-design-workflow.md +151 -0
  201. package/docs/zshrc-aliases.md +65 -0
  202. package/governance/rules/ci/700-ci-workflow.md +44 -0
  203. package/governance/rules/claude/500-prose.md +15 -0
  204. package/governance/rules/claude/501-markdown.md +14 -0
  205. package/governance/rules/claude/510-context.md +28 -0
  206. package/governance/rules/claude/511-indexes.md +14 -0
  207. package/governance/rules/claude/520-wireframes.md +12 -0
  208. package/governance/rules/claude/530-requirements.md +11 -0
  209. package/governance/rules/claude/540-architecture.md +11 -0
  210. package/governance/rules/claude/550-design.md +11 -0
  211. package/governance/rules/claude/555-tasks.md +12 -0
  212. package/governance/rules/claude/556-groundwork.md +11 -0
  213. package/governance/rules/claude/557-intake.md +11 -0
  214. package/governance/rules/claude/558-plan.md +22 -0
  215. package/governance/rules/claude/559-memory.md +11 -0
  216. package/governance/rules/claude/560-diagrams.md +18 -0
  217. package/governance/rules/claude/561-teach.md +13 -0
  218. package/governance/rules/claude/562-session.md +15 -0
  219. package/governance/rules/claude/570-skill.md +24 -0
  220. package/governance/rules/claude/575-hooks.md +17 -0
  221. package/governance/rules/claude/576-settings.md +14 -0
  222. package/governance/rules/claude/580-readme.md +11 -0
  223. package/governance/rules/claude/590-rule-authoring.md +12 -0
  224. package/governance/rules/claude/591-standard-authoring.md +12 -0
  225. package/governance/rules/claude/592-claude-md.md +19 -0
  226. package/governance/rules/core/000-constitution.md +30 -0
  227. package/governance/rules/core/005-behavior.md +27 -0
  228. package/governance/rules/core/010-testing.md +35 -0
  229. package/governance/rules/core/015-output.md +20 -0
  230. package/governance/rules/core/020-concurrency.md +22 -0
  231. package/governance/rules/core/025-indexes.md +9 -0
  232. package/governance/rules/core/030-error-handling.md +31 -0
  233. package/governance/rules/core/035-tasks.md +13 -0
  234. package/governance/rules/core/040-performance.md +20 -0
  235. package/governance/rules/core/045-memory.md +12 -0
  236. package/governance/rules/core/050-logging.md +20 -0
  237. package/governance/rules/core/055-scratch.md +9 -0
  238. package/governance/rules/core/060-naming.md +19 -0
  239. package/governance/rules/core/065-spelling.md +19 -0
  240. package/governance/rules/core/070-planning.md +18 -0
  241. package/governance/rules/core/075-dependencies.md +25 -0
  242. package/governance/rules/core/080-config-comments.md +22 -0
  243. package/governance/rules/core/085-worktrees.md +17 -0
  244. package/governance/rules/core/087-git.md +11 -0
  245. package/governance/rules/core/090-code-comments.md +39 -0
  246. package/governance/rules/framework/200-react.md +51 -0
  247. package/governance/rules/framework/210-astro.md +41 -0
  248. package/governance/rules/framework/220-fastapi.md +43 -0
  249. package/governance/rules/framework/230-nextjs.md +48 -0
  250. package/governance/rules/framework/250-tailwind.md +32 -0
  251. package/governance/rules/framework/260-shadcn.md +34 -0
  252. package/governance/rules/lang/100-typescript.md +40 -0
  253. package/governance/rules/lang/110-python.md +42 -0
  254. package/governance/rules/lang/120-bash.md +19 -0
  255. package/governance/rules/lib/300-testing-ts.md +39 -0
  256. package/governance/rules/lib/305-e2e-reliability.md +34 -0
  257. package/governance/rules/lib/306-test-scope.md +25 -0
  258. package/governance/rules/lib/310-zod.md +25 -0
  259. package/governance/rules/lib/320-tanstack-query.md +32 -0
  260. package/governance/rules/lib/330-testing-py.md +44 -0
  261. package/governance/rules/lib/340-pydantic.md +38 -0
  262. package/governance/rules/lib/350-security-web.md +32 -0
  263. package/governance/rules/lib/360-security-server.md +39 -0
  264. package/governance/rules/lib/370-database.md +35 -0
  265. package/governance/rules/snippets/505-at-references.md +9 -0
  266. package/governance/rules/ui/400-ui.md +36 -0
  267. package/governance/rules/ui/410-a11y.md +48 -0
  268. package/governance/rules/ui/420-forms.md +36 -0
  269. package/governance/rules/ui/430-ux-completeness.md +65 -0
  270. package/governance/rules/ui/440-surface-capture.md +34 -0
  271. package/governance/rules/ui/450-link-behavior.md +19 -0
  272. package/governance/stacks/astro.toml +2 -0
  273. package/governance/stacks/base.toml +8 -0
  274. package/governance/stacks/node-server.toml +2 -0
  275. package/governance/stacks/node.toml +2 -0
  276. package/governance/stacks/python-fastapi.toml +2 -0
  277. package/governance/stacks/python.toml +2 -0
  278. package/governance/stacks/react.toml +2 -0
  279. package/package.json +69 -0
  280. package/scripts/config.sh +11 -0
  281. package/scripts/core/bootstrap.sh +81 -0
  282. package/scripts/core/check-color-source.sh +41 -0
  283. package/scripts/core/check-ignore-parity.sh +162 -0
  284. package/scripts/core/check-plugin-boundary.sh +45 -0
  285. package/scripts/core/check-seed-independence.sh +59 -0
  286. package/scripts/core/check-skill-paths.sh +24 -0
  287. package/scripts/core/clean.sh +36 -0
  288. package/scripts/core/install-check.sh +101 -0
  289. package/scripts/core/list-seed-roots.sh +18 -0
  290. package/scripts/core/regen-claude-copies.sh +10 -0
  291. package/scripts/core/regen-hero.sh +217 -0
  292. package/scripts/core/regen-indexes.sh +10 -0
  293. package/scripts/core/regen-tooling-paths.sh +61 -0
  294. package/scripts/core/repair-bare-flag.sh +19 -0
  295. package/scripts/core/snapshot.sh +134 -0
  296. package/scripts/core/update.sh +35 -0
  297. package/scripts/docs/list.sh +165 -0
  298. package/scripts/lib/frontmatter.sh +30 -0
  299. package/scripts/lib/gov.sh +14 -0
  300. package/scripts/lib/sandbox-fixtures.sh +191 -0
  301. package/scripts/lib/sandbox-git.sh +125 -0
  302. package/scripts/lib/sandbox-path.sh +206 -0
  303. package/scripts/lib/tooling.sh +35 -0
  304. package/scripts/lib/ui.sh +266 -0
  305. package/scripts/lib/worktree.sh +20 -0
  306. package/scripts/manage-sandbox.sh +466 -0
  307. package/scripts/snippets/create.sh +156 -0
  308. package/scripts/standards/list.sh +115 -0
  309. package/scripts/tooling/create.sh +109 -0
  310. package/scripts/tooling/verify.sh +179 -0
  311. package/snippets/align.md +12 -0
  312. package/snippets/claude/decision-memo.md +39 -0
  313. package/snippets/claude/feature-recap.md +19 -0
  314. package/snippets/claude/figma-steps.md +24 -0
  315. package/snippets/compact-summary.md +5 -0
  316. package/snippets/decision-help.md +6 -0
  317. package/snippets/meta-prompt.md +14 -0
  318. package/snippets/research-prompt.md +7 -0
  319. package/snippets/session-notes.md +11 -0
  320. package/snippets/snippets.toml +5 -0
  321. package/snippets/step-by-step.md +10 -0
  322. package/snippets/web-research.md +21 -0
  323. package/src/audits/baseline.ts +201 -0
  324. package/src/audits/catalog.ts +876 -0
  325. package/src/audits/run.ts +204 -0
  326. package/src/autoship/classify.ts +75 -0
  327. package/src/autoship/paths.ts +51 -0
  328. package/src/binary.ts +16 -0
  329. package/src/browser/engine.ts +40 -0
  330. package/src/census/count.ts +113 -0
  331. package/src/claude/cases/all.ts +24 -0
  332. package/src/claude/cases/authoring.ts +53 -0
  333. package/src/claude/cases/claude-workflow.ts +158 -0
  334. package/src/claude/cases/git.ts +44 -0
  335. package/src/claude/cases/misc.ts +27 -0
  336. package/src/claude/cases/setup.ts +94 -0
  337. package/src/claude/gitignore.ts +51 -0
  338. package/src/claude/routing.ts +283 -0
  339. package/src/claude/seeds-list.ts +47 -0
  340. package/src/claude/seeds.ts +150 -0
  341. package/src/claude/settings.ts +151 -0
  342. package/src/claude/skills-audit.ts +228 -0
  343. package/src/claude/skills-drift.ts +156 -0
  344. package/src/claude/skills-list.ts +99 -0
  345. package/src/claude/skills-rank.ts +320 -0
  346. package/src/claude/skills-reach.ts +227 -0
  347. package/src/cli-run.ts +43 -0
  348. package/src/cli.ts +200 -0
  349. package/src/commands/audits.ts +350 -0
  350. package/src/commands/autoship.ts +129 -0
  351. package/src/commands/capture.ts +133 -0
  352. package/src/commands/census.ts +105 -0
  353. package/src/commands/claude.ts +1286 -0
  354. package/src/commands/comments.ts +240 -0
  355. package/src/commands/context.ts +857 -0
  356. package/src/commands/demo.ts +389 -0
  357. package/src/commands/deps.ts +173 -0
  358. package/src/commands/design.ts +36 -0
  359. package/src/commands/docs.ts +60 -0
  360. package/src/commands/feedback-format.ts +23 -0
  361. package/src/commands/feedback.ts +112 -0
  362. package/src/commands/gate.ts +189 -0
  363. package/src/commands/gov.ts +1265 -0
  364. package/src/commands/indexes.ts +184 -0
  365. package/src/commands/init.ts +113 -0
  366. package/src/commands/intake.ts +406 -0
  367. package/src/commands/inventory.ts +256 -0
  368. package/src/commands/labels.ts +361 -0
  369. package/src/commands/markdown.ts +544 -0
  370. package/src/commands/migrate.ts +175 -0
  371. package/src/commands/pass-through.ts +39 -0
  372. package/src/commands/pr.ts +411 -0
  373. package/src/commands/records.ts +728 -0
  374. package/src/commands/sandbox.ts +468 -0
  375. package/src/commands/secrets.ts +132 -0
  376. package/src/commands/serve.ts +159 -0
  377. package/src/commands/sessions.ts +408 -0
  378. package/src/commands/slides.ts +126 -0
  379. package/src/commands/snippets.ts +84 -0
  380. package/src/commands/standards.ts +247 -0
  381. package/src/commands/sync.ts +428 -0
  382. package/src/commands/targets.ts +319 -0
  383. package/src/commands/tasks.ts +743 -0
  384. package/src/commands/teach.ts +786 -0
  385. package/src/commands/tooling.ts +573 -0
  386. package/src/commands/transcripts.ts +44 -0
  387. package/src/commands/upgrade.ts +231 -0
  388. package/src/commands/wiki.ts +100 -0
  389. package/src/commands/worktrees.ts +191 -0
  390. package/src/comments/scan.ts +338 -0
  391. package/src/comments/trend.ts +207 -0
  392. package/src/comments/vocabulary.ts +85 -0
  393. package/src/context/architecture.ts +364 -0
  394. package/src/context/audit.ts +790 -0
  395. package/src/context/citations.ts +196 -0
  396. package/src/context/folders.ts +186 -0
  397. package/src/context/gate.ts +57 -0
  398. package/src/context/index-drift.ts +64 -0
  399. package/src/context/narration.ts +99 -0
  400. package/src/copy.ts +30 -0
  401. package/src/counts/catalogs.ts +96 -0
  402. package/src/counts/numbers.ts +79 -0
  403. package/src/counts/scan.ts +314 -0
  404. package/src/demo/beats.ts +135 -0
  405. package/src/demo/compile.ts +326 -0
  406. package/src/demo/container.ts +63 -0
  407. package/src/demo/cursors.ts +55 -0
  408. package/src/demo/drive.ts +357 -0
  409. package/src/demo/pointer.ts +178 -0
  410. package/src/demo/theme.ts +112 -0
  411. package/src/deps/audit.ts +153 -0
  412. package/src/design/parse.ts +116 -0
  413. package/src/design/render.ts +249 -0
  414. package/src/docs/read.ts +77 -0
  415. package/src/exec.ts +16 -0
  416. package/src/exempt-marker.ts +43 -0
  417. package/src/frontmatter.ts +13 -0
  418. package/src/gate/measures.ts +682 -0
  419. package/src/gate/sequencer.ts +386 -0
  420. package/src/gate/stages.ts +412 -0
  421. package/src/git-env.ts +36 -0
  422. package/src/git-files.ts +105 -0
  423. package/src/git-ignore.ts +46 -0
  424. package/src/github-format.ts +13 -0
  425. package/src/github.ts +24 -0
  426. package/src/gov/adapter.ts +103 -0
  427. package/src/gov/citations.ts +514 -0
  428. package/src/gov/consumed.ts +129 -0
  429. package/src/gov/install.ts +132 -0
  430. package/src/gov/list.ts +106 -0
  431. package/src/gov/payload.ts +39 -0
  432. package/src/gov/restated.ts +814 -0
  433. package/src/gov/stacks.ts +205 -0
  434. package/src/gov/superseded.ts +415 -0
  435. package/src/gov/test-order.ts +407 -0
  436. package/src/indexes/frontmatter.ts +46 -0
  437. package/src/indexes/regen.ts +84 -0
  438. package/src/indexes/render.ts +201 -0
  439. package/src/indexes/walk.ts +83 -0
  440. package/src/init/flags.ts +60 -0
  441. package/src/init/plan.ts +114 -0
  442. package/src/init/run.ts +46 -0
  443. package/src/init/steps.ts +77 -0
  444. package/src/intake/folder.ts +320 -0
  445. package/src/intake/items.ts +174 -0
  446. package/src/inventory/config.ts +117 -0
  447. package/src/inventory/group.ts +76 -0
  448. package/src/inventory/subjects.ts +114 -0
  449. package/src/inventory/walk.ts +129 -0
  450. package/src/labels/audit.ts +82 -0
  451. package/src/labels/coverage.ts +79 -0
  452. package/src/labels/map.ts +101 -0
  453. package/src/labels/phase.ts +95 -0
  454. package/src/markdown/bans.ts +94 -0
  455. package/src/markdown/files.ts +102 -0
  456. package/src/markdown/gate.ts +28 -0
  457. package/src/markdown/scan.ts +295 -0
  458. package/src/markdown/structure.ts +730 -0
  459. package/src/migrate/apply.ts +115 -0
  460. package/src/migrate/plan.ts +103 -0
  461. package/src/migrate/rename.ts +183 -0
  462. package/src/pr/bijection.ts +145 -0
  463. package/src/pr/paths.ts +335 -0
  464. package/src/process/harness.ts +167 -0
  465. package/src/project-root.ts +19 -0
  466. package/src/records/backup.ts +455 -0
  467. package/src/records/migrate.ts +78 -0
  468. package/src/records/size.ts +260 -0
  469. package/src/records/validate.ts +1162 -0
  470. package/src/sandbox/census.ts +228 -0
  471. package/src/sandbox/coverage.ts +115 -0
  472. package/src/sandbox/expect.ts +629 -0
  473. package/src/sandbox/tree.ts +47 -0
  474. package/src/secrets/marker.ts +30 -0
  475. package/src/secrets/patterns.ts +142 -0
  476. package/src/secrets/scan.ts +123 -0
  477. package/src/secrets/shipped.ts +111 -0
  478. package/src/seed-marker.ts +74 -0
  479. package/src/serve/static.ts +322 -0
  480. package/src/sessions/claim.ts +85 -0
  481. package/src/sessions/live.ts +79 -0
  482. package/src/sessions/registry.ts +137 -0
  483. package/src/sessions/resolve.ts +333 -0
  484. package/src/slides/layouts.ts +391 -0
  485. package/src/slides/open.ts +18 -0
  486. package/src/slides/parse.ts +84 -0
  487. package/src/slides/render.ts +88 -0
  488. package/src/slides/styles.ts +44 -0
  489. package/src/snippets/categories.ts +66 -0
  490. package/src/snippets/list.ts +32 -0
  491. package/src/snippets/presets.ts +50 -0
  492. package/src/standards/audit.ts +132 -0
  493. package/src/standards/read.ts +100 -0
  494. package/src/sync/check.ts +692 -0
  495. package/src/sync/engine.ts +576 -0
  496. package/src/sync/git.ts +225 -0
  497. package/src/sync/history.ts +123 -0
  498. package/src/sync/layout.ts +140 -0
  499. package/src/sync/reverse.ts +268 -0
  500. package/src/sync/seeds-report.ts +126 -0
  501. package/src/sync/stamp.ts +358 -0
  502. package/src/sync/target.ts +70 -0
  503. package/src/sync/workflow.ts +200 -0
  504. package/src/target.ts +43 -0
  505. package/src/targets/pulls.ts +250 -0
  506. package/src/targets/registry.ts +203 -0
  507. package/src/targets/resolve.ts +145 -0
  508. package/src/targets/sweep.ts +246 -0
  509. package/src/tasks/archive.ts +506 -0
  510. package/src/tasks/record.ts +311 -0
  511. package/src/tasks/trunk.ts +89 -0
  512. package/src/tasks/validate.ts +1001 -0
  513. package/src/teach/lesson.ts +180 -0
  514. package/src/teach/workspace.ts +842 -0
  515. package/src/tooling/gitignore.ts +122 -0
  516. package/src/tooling/inject.ts +193 -0
  517. package/src/tooling/list.ts +39 -0
  518. package/src/tooling/manifest.ts +176 -0
  519. package/src/tooling/package.ts +166 -0
  520. package/src/tooling/read.ts +65 -0
  521. package/src/tooling/scan.ts +147 -0
  522. package/src/tooling/stamp.ts +44 -0
  523. package/src/transcripts/fetch.ts +156 -0
  524. package/src/transcripts/metadata.ts +54 -0
  525. package/src/transcripts/vtt.ts +114 -0
  526. package/src/ui.ts +266 -0
  527. package/src/version/compare.ts +53 -0
  528. package/src/version/installed.ts +40 -0
  529. package/src/version/manager.ts +67 -0
  530. package/src/version/skew.ts +192 -0
  531. package/src/wiki/init.ts +85 -0
  532. package/src/worktree.ts +143 -0
  533. package/src/worktrees/reclaim.ts +306 -0
  534. package/standards/architecture.md +72 -0
  535. package/standards/branch.md +59 -0
  536. package/standards/commit.md +72 -0
  537. package/standards/context.md +151 -0
  538. package/standards/design.md +93 -0
  539. package/standards/diagrams.md +152 -0
  540. package/standards/glossary.md +75 -0
  541. package/standards/groundwork.md +211 -0
  542. package/standards/index.md +36 -0
  543. package/standards/intake.md +192 -0
  544. package/standards/issue.md +94 -0
  545. package/standards/markdown.md +137 -0
  546. package/standards/memory.md +144 -0
  547. package/standards/plan.md +172 -0
  548. package/standards/pr.md +139 -0
  549. package/standards/publish.md +51 -0
  550. package/standards/readme.md +208 -0
  551. package/standards/requirements.md +70 -0
  552. package/standards/rule.md +118 -0
  553. package/standards/session.md +109 -0
  554. package/standards/skill.md +300 -0
  555. package/standards/slug.md +39 -0
  556. package/standards/snippets.md +76 -0
  557. package/standards/standard.md +170 -0
  558. package/standards/tasks.md +254 -0
  559. package/standards/teach.md +153 -0
  560. package/standards/versioning.md +71 -0
  561. package/standards/wireframes.md +113 -0
  562. package/tooling/astro/configs/astro.config.mjs +31 -0
  563. package/tooling/astro/configs/eslint.config.js +79 -0
  564. package/tooling/astro/configs/playwright.config.ts +26 -0
  565. package/tooling/astro/configs/tsconfig.json +12 -0
  566. package/tooling/astro/configs/vitest.config.ts +22 -0
  567. package/tooling/astro/manifest.toml +34 -0
  568. package/tooling/astro/reference.md +60 -0
  569. package/tooling/base/configs/.editorconfig +5 -0
  570. package/tooling/base/configs/.github/pull_request_template.md +18 -0
  571. package/tooling/base/configs/.github/workflows/verify.yml +35 -0
  572. package/tooling/base/configs/.husky/commit-msg +1 -0
  573. package/tooling/base/configs/.husky/post-merge +61 -0
  574. package/tooling/base/configs/.husky/post-rewrite +21 -0
  575. package/tooling/base/configs/.husky/pre-commit +1 -0
  576. package/tooling/base/configs/.husky/pre-push +1 -0
  577. package/tooling/base/configs/.prettierrc +12 -0
  578. package/tooling/base/configs/.shellcheckrc +1 -0
  579. package/tooling/base/configs/.vscode/extensions.json +9 -0
  580. package/tooling/base/configs/.vscode/settings.json +3 -0
  581. package/tooling/base/configs/commitlint.config.js +11 -0
  582. package/tooling/base/configs/scripts/verify.sh +64 -0
  583. package/tooling/base/manifest.toml +30 -0
  584. package/tooling/base/reference.md +98 -0
  585. package/tooling/base/seeds/.claude/context/ci.md +33 -0
  586. package/tooling/base/seeds/.claude/context/development.md +37 -0
  587. package/tooling/base/seeds/.claude/context/index.md +11 -0
  588. package/tooling/base/seeds/.cspell/project-terms.txt +0 -0
  589. package/tooling/base/seeds/.cspell/tech-stack.txt +19 -0
  590. package/tooling/base/seeds/.lintstagedrc +8 -0
  591. package/tooling/base/seeds/.prettierignore +0 -0
  592. package/tooling/base/seeds/cspell.json +20 -0
  593. package/tooling/claude/manifest.toml +14 -0
  594. package/tooling/claude/reference.md +79 -0
  595. package/tooling/claude/seeds/.claude/ARCHITECTURE.md +13 -0
  596. package/tooling/claude/seeds/.claude/DESIGN.md +62 -0
  597. package/tooling/claude/seeds/.claude/REQUIREMENTS.md +18 -0
  598. package/tooling/claude/seeds/.claude/diagrams/index.md +8 -0
  599. package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +50 -0
  600. package/tooling/claude/seeds/.claude/hooks/memory-index.sh +68 -0
  601. package/tooling/claude/seeds/.claude/hooks/path-form.sh +57 -0
  602. package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +52 -0
  603. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +86 -0
  604. package/tooling/claude/seeds/.claude/hooks/tasks-index.sh +71 -0
  605. package/tooling/claude/seeds/.claude/memory/index.md +8 -0
  606. package/tooling/claude/seeds/.claude/settings.json +47 -0
  607. package/tooling/claude/seeds/.claude/tasks/index.md +8 -0
  608. package/tooling/claude/seeds/.claude/wireframes/index.md +8 -0
  609. package/tooling/claude/seeds/CLAUDE.md +29 -0
  610. package/tooling/claude/user/settings.template.json +10 -0
  611. package/tooling/claude/user/statusline-command.sh +53 -0
  612. package/tooling/python/configs/.coveragerc +14 -0
  613. package/tooling/python/configs/.python-version +1 -0
  614. package/tooling/python/configs/mypy.ini +6 -0
  615. package/tooling/python/configs/pytest.ini +4 -0
  616. package/tooling/python/configs/ruff.toml +15 -0
  617. package/tooling/python/configs/scripts/verify.sh +77 -0
  618. package/tooling/python/manifest.toml +16 -0
  619. package/tooling/python/reference.md +66 -0
  620. package/tooling/python/seeds/.cspell/tech-stack.txt +19 -0
  621. package/tooling/python/seeds/tests/test_smoke.py +2 -0
  622. package/tooling/vite-react/configs/playwright.config.ts +26 -0
  623. package/tooling/vite-react/configs/tsconfig.json +35 -0
  624. package/tooling/vite-react/configs/vite.config.ts +24 -0
  625. package/tooling/vite-react/configs/vitest.config.ts +26 -0
  626. package/tooling/vite-react/manifest.toml +23 -0
  627. package/tooling/vite-react/reference.md +55 -0
  628. package/tooling/vite-react/seeds/.cspell/project-terms.txt +1 -0
  629. package/tooling/vite-react/seeds/.cspell/tech-stack.txt +1 -0
  630. package/tooling/web/configs/.github/workflows/verify.yml +134 -0
  631. package/tooling/web/configs/.vscode/extensions.json +13 -0
  632. package/tooling/web/configs/.vscode/settings.json +10 -0
  633. package/tooling/web/configs/e2e/home.spec.ts +6 -0
  634. package/tooling/web/configs/e2e/screenshot.ts +53 -0
  635. package/tooling/web/configs/eslint.config.js +82 -0
  636. package/tooling/web/configs/scripts/screenshot.sh +28 -0
  637. package/tooling/web/configs/scripts/verify.sh +80 -0
  638. package/tooling/web/configs/scripts/worktree-port.sh +74 -0
  639. package/tooling/web/configs/src/test/setup.ts +8 -0
  640. package/tooling/web/manifest.toml +58 -0
  641. package/tooling/web/reference.md +115 -0
  642. package/tooling/web/seeds/.cspell/tech-stack.txt +18 -0
  643. package/tsconfig.json +14 -0
@@ -0,0 +1,544 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import { resolve } from 'node:path'
3
+ import type { Command } from 'commander'
4
+ import { BAN_SETS, emptyBanSets } from '@/markdown/bans'
5
+ import { type MarkdownAuditRefusal, resolveMarkdown } from '@/markdown/files'
6
+ import { isGating } from '@/markdown/gate'
7
+ import {
8
+ type BanFinding,
9
+ type BanSets,
10
+ bodyLines,
11
+ scanBans,
12
+ } from '@/markdown/scan'
13
+ import {
14
+ BASELINE,
15
+ CHECKPOINTS,
16
+ type Checkpoints,
17
+ measureStructure,
18
+ type StructureReport,
19
+ } from '@/markdown/structure'
20
+ import {
21
+ intro,
22
+ logInfo,
23
+ logStep,
24
+ logWarn,
25
+ outro,
26
+ pipeOutput,
27
+ plural,
28
+ } from '@/ui'
29
+
30
+ const EXIT_REFUSED = 1
31
+ const EXIT_GATE = 2
32
+
33
+ /**
34
+ * A set shipped empty, so the run measured a corpus against nothing.
35
+ *
36
+ * Distinct from `EXIT_REFUSED` because the two want different responses. A
37
+ * refusal means no corpus was built and a push stage is right to skip, while an
38
+ * empty set means the corpus was walked and nothing was looked for, which is a
39
+ * defect in the build and has to fail.
40
+ */
41
+ const EXIT_UNUSABLE = 3
42
+
43
+ interface AuditCommandOptions {
44
+ readonly json?: boolean
45
+ }
46
+
47
+ interface FileReport {
48
+ readonly rel: string
49
+ readonly bans: readonly BanFinding[]
50
+ readonly structure: StructureReport
51
+ }
52
+
53
+ export function register(program: Command): void {
54
+ const markdown = program
55
+ .command('markdown')
56
+ .description('Report markdown files against the attribute standards')
57
+ .helpOption('-h, --help', 'Show this help message')
58
+
59
+ markdown
60
+ .command('audit')
61
+ .description(
62
+ 'Fail on a banned character, word, or spelling, and report bullet, paragraph, cadence, and depth',
63
+ )
64
+ .argument(
65
+ '[path...]',
66
+ 'Markdown files, directories, or globs, defaulting to every markdown file git lists',
67
+ )
68
+ .helpOption('-h, --help', 'Show this help message')
69
+ .option('--json', 'Add a machine-readable record on stdout')
70
+ .addHelpText(
71
+ 'after',
72
+ [
73
+ '',
74
+ 'Exit codes:',
75
+ ' 0 the audit completed with no gating finding',
76
+ ' 1 refused, with the reason on stderr',
77
+ ' 2 a banned character, word, or spelling is present',
78
+ ' 3 a shipped ban set is empty, so the run measured nothing',
79
+ '',
80
+ 'A ban hit is a fact and gates unconditionally. Bullet, paragraph, and',
81
+ 'depth weight are judgments a reader settles, so all three report and',
82
+ 'none of them fails a run.',
83
+ '',
84
+ 'Cadence reports the same way and carries one more caveat. Its range is',
85
+ 'drawn from prose a person reads, so terse reference prose sits below',
86
+ 'it correctly and a flat paragraph there is not a defect.',
87
+ '',
88
+ 'Rewrite the sentence carrying a hit rather than swapping the token for',
89
+ 'a near-synonym. A code span clears the report and is the answer only',
90
+ 'where the token is genuinely an identifier under discussion, which is',
91
+ 'what markdown.md reserves the span for.',
92
+ '',
93
+ 'Bans and checkpoints ship with the canon package rather than being read',
94
+ 'out of a standards file, so a project that installed no standards is',
95
+ 'measured the same as one that did. markdown.md still states every rule',
96
+ 'for a reader. No folder has to resolve and no index.md has',
97
+ 'to exist, so .claude/rules/, governance/, and snippets/ are in reach.',
98
+ '',
99
+ 'Examples:',
100
+ ' canon markdown audit',
101
+ ' canon markdown audit --json',
102
+ ' canon markdown audit .claude/rules governance',
103
+ ' canon markdown audit docs/agents/commands.md',
104
+ " canon markdown audit 'snippets/**/*.md'",
105
+ '',
106
+ ].join('\n'),
107
+ )
108
+ .action(async (paths: string[], opts: AuditCommandOptions) => {
109
+ process.exitCode = await runAudit(paths, opts)
110
+ })
111
+ }
112
+
113
+ async function runAudit(
114
+ paths: string[],
115
+ opts: AuditCommandOptions,
116
+ ): Promise<number> {
117
+ const root = process.cwd()
118
+ const scope = await resolveMarkdown(root, paths)
119
+
120
+ if (scope.kind === 'unavailable') {
121
+ return refuse(
122
+ 'no-git',
123
+ 'git could not list the tree, so no corpus was built. Run inside a git repository.',
124
+ root,
125
+ opts.json ?? false,
126
+ )
127
+ }
128
+
129
+ if (scope.files.length === 0) {
130
+ return refuse(
131
+ paths.length === 0 ? 'no-markdown' : 'no-match',
132
+ paths.length === 0
133
+ ? 'No markdown file in the tree.'
134
+ : `No markdown file matched: ${scope.unmatched.join(', ')}`,
135
+ root,
136
+ opts.json ?? false,
137
+ )
138
+ }
139
+
140
+ const bans = BAN_SETS
141
+ const empty = emptyBanSets(bans)
142
+ const checkpoints = CHECKPOINTS
143
+
144
+ const reports: FileReport[] = await Promise.all(
145
+ scope.files.map(async (rel) => {
146
+ const lines = bodyLines(await readFile(resolve(root, rel), 'utf8'))
147
+ return {
148
+ rel,
149
+ bans: scanBans(lines, bans),
150
+ structure: measureStructure(rel, lines, checkpoints),
151
+ }
152
+ }),
153
+ )
154
+
155
+ intro('canon markdown audit')
156
+ reportScope(scope.files, scope.unmatched)
157
+ reportBans(reports, bans, empty)
158
+ reportBullets(reports, checkpoints)
159
+ reportParagraphs(reports, checkpoints)
160
+ reportCadence(reports, checkpoints)
161
+ reportDepth(reports, checkpoints)
162
+ outro()
163
+
164
+ if (opts.json) {
165
+ process.stdout.write(
166
+ `${JSON.stringify({
167
+ root,
168
+ files: scope.files,
169
+ unmatchedPaths: scope.unmatched,
170
+ bans: {
171
+ characters: bans.characters,
172
+ words: bans.words,
173
+ spellings: bans.spellings,
174
+ emptySets: empty,
175
+ },
176
+ checkpoints: {
177
+ run: checkpoints.run,
178
+ peerBullet: checkpoints.peerBullet,
179
+ bullet: checkpoints.bullet,
180
+ paragraph: checkpoints.paragraph,
181
+ sentences: checkpoints.sentences,
182
+ renderWidth: checkpoints.renderWidth,
183
+ cadence: checkpoints.cadence,
184
+ spread: checkpoints.spread,
185
+ opener: checkpoints.opener,
186
+ },
187
+ entries: reports.map((report) => ({
188
+ path: report.rel,
189
+ bans: report.bans,
190
+ longestRun: report.structure.longestRun,
191
+ longestRunLine: report.structure.longestRunLine,
192
+ heavyBullets: report.structure.heavyBullets,
193
+ heavyParagraphs: report.structure.heavyParagraphs,
194
+ cadence: report.structure.cadence,
195
+ })),
196
+ })}\n`,
197
+ )
198
+ }
199
+
200
+ // An empty set finds nothing and would exit clean, which reports a corpus
201
+ // nobody checked as a corpus carrying no violation.
202
+ if (empty.length > 0) return EXIT_UNUSABLE
203
+
204
+ const gating = isGating({
205
+ bans: reports.flatMap((report) => report.bans),
206
+ structure: reports.map((report) => report.structure),
207
+ })
208
+
209
+ return gating ? EXIT_GATE : 0
210
+ }
211
+
212
+ function refuse(
213
+ reason: MarkdownAuditRefusal,
214
+ message: string,
215
+ root: string,
216
+ emitJson: boolean,
217
+ ): number {
218
+ intro('canon markdown audit')
219
+ logStep('Refused')
220
+ logWarn(message)
221
+ outro()
222
+
223
+ if (emitJson) {
224
+ process.stdout.write(`${JSON.stringify({ root, reason, message })}\n`)
225
+ }
226
+
227
+ return EXIT_REFUSED
228
+ }
229
+
230
+ function reportScope(
231
+ files: readonly string[],
232
+ unmatched: readonly string[],
233
+ ): void {
234
+ logStep('Scope')
235
+ logInfo(`${plural(files.length, 'markdown file')}`)
236
+
237
+ if (unmatched.length === 0) return
238
+
239
+ logWarn(`Matched no markdown file: ${unmatched.join(', ')}`)
240
+ }
241
+
242
+ /**
243
+ * Names what the closed sets reach and what they leave to a reader.
244
+ *
245
+ * The two standards state bans in three shapes and only two of them are a
246
+ * closed set. A phrase ban carries a placeholder standing in for the rest of
247
+ * the sentence and every voice rule is a judgment, so a report listing hits
248
+ * without naming those would read as a verdict on the whole standard.
249
+ */
250
+ function reportBans(
251
+ reports: readonly FileReport[],
252
+ bans: BanSets,
253
+ empty: readonly string[],
254
+ ): void {
255
+ logStep('Bans')
256
+
257
+ if (empty.length > 0) {
258
+ logWarn(
259
+ `Not measured. The shipped set is empty for: ${empty.join(', ')}. The sets ship with the canon package, so an empty one is a defect in the build rather than a missing install.`,
260
+ )
261
+ return
262
+ }
263
+
264
+ logInfo(
265
+ `${plural(bans.characters.length, 'character')}, ${plural(bans.words.length, 'word')}, and ${plural(bans.spellings.length, 'spelling')} shipped with the canon package`,
266
+ )
267
+ logInfo(
268
+ 'Frontmatter, fenced blocks, code spans, and link destinations are excluded.',
269
+ )
270
+ logInfo(
271
+ 'Phrase bans and every voice rule are patterns rather than closed sets, and stay a judgment for the reader.',
272
+ )
273
+
274
+ const carrying = reports
275
+ .filter((report) => report.bans.length > 0)
276
+ .sort((a, b) => b.bans.length - a.bans.length)
277
+
278
+ if (carrying.length === 0) {
279
+ logInfo('No banned character, word, or spelling.')
280
+ return
281
+ }
282
+
283
+ const total = carrying.reduce((sum, report) => sum + report.bans.length, 0)
284
+ logWarn(`${plural(total, 'hit')} across ${plural(carrying.length, 'file')}`)
285
+ logWarn('This fails the run. Every other check below reports.')
286
+ logInfo(
287
+ 'Rewrite the sentence rather than swapping the token for a near-synonym.',
288
+ )
289
+ logInfo(
290
+ 'A code span clears the report and is the answer only where the token is genuinely an identifier under discussion, which is what markdown.md reserves the span for.',
291
+ )
292
+ pipeOutput(
293
+ carrying
294
+ .map(
295
+ (report) =>
296
+ `${report.rel} ${plural(report.bans.length, 'hit')}\n${report.bans
297
+ .map(
298
+ (found) =>
299
+ ` :${found.line}:${found.column + 1} ${found.kind} ${found.term}`,
300
+ )
301
+ .join('\n')}`,
302
+ )
303
+ .join('\n'),
304
+ )
305
+ }
306
+
307
+ function reportBullets(
308
+ reports: readonly FileReport[],
309
+ checkpoints: Checkpoints,
310
+ ): void {
311
+ logStep('Bullets')
312
+ logInfo(
313
+ 'Top-level bullets measure characters, folding in continuation lines.',
314
+ )
315
+ logInfo(
316
+ 'Nested items and fenced blocks are excluded. Weight is a judgment, never a defect.',
317
+ )
318
+
319
+ const carrying = reports
320
+ .filter((report) => report.structure.heavyBullets.length > 0)
321
+ .sort(
322
+ (a, b) =>
323
+ b.structure.heavyBullets.length - a.structure.heavyBullets.length,
324
+ )
325
+
326
+ if (carrying.length === 0) {
327
+ logInfo(`No bullet past the ${checkpoints.bullet}-character checkpoint.`)
328
+ return
329
+ }
330
+
331
+ const total = carrying.reduce(
332
+ (sum, report) => sum + report.structure.heavyBullets.length,
333
+ 0,
334
+ )
335
+ logWarn(
336
+ `${plural(total, 'bullet')} past the ${checkpoints.bullet}-character checkpoint across ${plural(carrying.length, 'file')}`,
337
+ )
338
+ pipeOutput(
339
+ carrying
340
+ .map(
341
+ (report) =>
342
+ `${report.rel} ${plural(report.structure.heavyBullets.length, 'bullet')}\n${report.structure.heavyBullets
343
+ .map((found) => ` :${found.line} ${found.characters} characters`)
344
+ .join('\n')}`,
345
+ )
346
+ .join('\n'),
347
+ )
348
+ }
349
+
350
+ /**
351
+ * States both halves of the checkpoint on every run.
352
+ *
353
+ * The standard states a sentence cap and a weight, and a report naming only the
354
+ * first would leave a reader unable to tell why a two-sentence paragraph is
355
+ * listed.
356
+ */
357
+ function reportParagraphs(
358
+ reports: readonly FileReport[],
359
+ checkpoints: Checkpoints,
360
+ ): void {
361
+ logStep('Paragraphs')
362
+ logInfo(
363
+ `Prose paragraphs report past ${checkpoints.sentences} sentences or past ${checkpoints.paragraph} characters.`,
364
+ )
365
+ logInfo(
366
+ 'The standard states both, and weight moves independently of the bullet checkpoint.',
367
+ )
368
+ logInfo(
369
+ 'Bullets, headings, tables, quotes, and fenced blocks each end a paragraph, so a bullet is measured once.',
370
+ )
371
+
372
+ const carrying = reports
373
+ .filter((report) => report.structure.heavyParagraphs.length > 0)
374
+ .sort(
375
+ (a, b) =>
376
+ b.structure.heavyParagraphs.length - a.structure.heavyParagraphs.length,
377
+ )
378
+
379
+ if (carrying.length === 0) {
380
+ logInfo('No paragraph past either checkpoint.')
381
+ return
382
+ }
383
+
384
+ const total = carrying.reduce(
385
+ (sum, report) => sum + report.structure.heavyParagraphs.length,
386
+ 0,
387
+ )
388
+ logWarn(
389
+ `${plural(total, 'paragraph')} past a checkpoint across ${plural(carrying.length, 'file')}`,
390
+ )
391
+ pipeOutput(
392
+ carrying
393
+ .map(
394
+ (report) =>
395
+ `${report.rel} ${plural(report.structure.heavyParagraphs.length, 'paragraph')}\n${report.structure.heavyParagraphs
396
+ .map(
397
+ (found) =>
398
+ ` :${found.line} ${found.sentences} sentences, ${found.characters} characters`,
399
+ )
400
+ .join('\n')}`,
401
+ )
402
+ .join('\n'),
403
+ )
404
+ }
405
+
406
+ /**
407
+ * Reports the distribution rather than a verdict, which is what separates this
408
+ * step from the three above it.
409
+ *
410
+ * Bullet, paragraph, and depth weight each report a count against a checkpoint
411
+ * a reader settles. Cadence reports a count as well, and the range behind it is
412
+ * drawn from one surface class rather than from the corpus, so the step states
413
+ * where the numbers came from beside them. A reader whose file is terse
414
+ * reference prose is meant to read a flat paragraph as correct, and a number
415
+ * printed with no comparison beside it reads as a finding whatever the step is
416
+ * called.
417
+ */
418
+ function reportCadence(
419
+ reports: readonly FileReport[],
420
+ checkpoints: Checkpoints,
421
+ ): void {
422
+ logStep('Cadence')
423
+ logInfo(
424
+ `Paragraphs of ${checkpoints.cadence} sentences or more measure the words between their longest and shortest sentence, and the times one word opens a sentence.`,
425
+ )
426
+ logInfo(
427
+ `A spread of ${checkpoints.spread} words or under reads as one cadence, and a word opening more than ${checkpoints.opener} sentences is a pattern rather than a coincidence.`,
428
+ )
429
+ logInfo(
430
+ 'Both numbers are stated under Rhythm in the write-human skill, which writes them about prose a person reads.',
431
+ )
432
+ logInfo(
433
+ 'A shorter paragraph stays unmeasured, since a two-sentence note carries no spread worth reading.',
434
+ )
435
+ logInfo(
436
+ 'A healthy range differs by surface, so neither number gates and neither names a file wrong. Terse reference prose sits below the range a page written for a reader sits in.',
437
+ )
438
+ logInfo(
439
+ `The corpus these numbers were read against measured ${BASELINE.flatShare} percent flat overall, and its files carrying ${BASELINE.floor} or more measured paragraphs ran from ${BASELINE.low} to ${BASELINE.high} percent with a median near ${BASELINE.median}. Compare a rate against that rather than against zero.`,
440
+ )
441
+
442
+ const measured = reports.reduce(
443
+ (sum, report) => sum + report.structure.cadence.measured,
444
+ 0,
445
+ )
446
+
447
+ if (measured === 0) {
448
+ logInfo(
449
+ `No paragraph reached ${checkpoints.cadence} sentences, so nothing was measured.`,
450
+ )
451
+ return
452
+ }
453
+
454
+ const flat = reports.reduce(
455
+ (sum, report) => sum + report.structure.cadence.flat,
456
+ 0,
457
+ )
458
+ const repeating = reports.reduce(
459
+ (sum, report) => sum + report.structure.cadence.repeating,
460
+ 0,
461
+ )
462
+
463
+ logInfo(
464
+ `${plural(measured, 'paragraph')} measured, ${flat} at or under the spread checkpoint (${Math.round((flat / measured) * 100)} percent) and ${repeating} past the opener checkpoint.`,
465
+ )
466
+
467
+ const carrying = reports
468
+ .filter(
469
+ (report) =>
470
+ report.structure.cadence.flattest ||
471
+ report.structure.cadence.mostRepeated,
472
+ )
473
+ .sort(
474
+ (a, b) =>
475
+ b.structure.cadence.flat +
476
+ b.structure.cadence.repeating -
477
+ (a.structure.cadence.flat + a.structure.cadence.repeating),
478
+ )
479
+
480
+ if (carrying.length === 0) return
481
+
482
+ pipeOutput(
483
+ carrying
484
+ .map((report) => {
485
+ const { flattest, mostRepeated } = report.structure.cadence
486
+ const lines = [
487
+ flattest &&
488
+ ` :${flattest.line} ${plural(flattest.sentences, 'sentence')}, spread ${plural(flattest.spread, 'word')}`,
489
+ mostRepeated &&
490
+ ` :${mostRepeated.line} ${plural(mostRepeated.sentences, 'sentence')}, "${mostRepeated.opener}" opens ${mostRepeated.repeats}`,
491
+ ].filter(Boolean)
492
+
493
+ return `${report.rel}\n${lines.join('\n')}`
494
+ })
495
+ .join('\n'),
496
+ )
497
+ }
498
+
499
+ /**
500
+ * Names the render width and the blank-line convention on every run.
501
+ *
502
+ * The standard settles heading level and fenced blocks and stops there, so a
503
+ * hand reader who drops blank lines lands a line or two below this number.
504
+ * Stating both keeps the two measurements reconcilable, and the width matters
505
+ * more, since a number counted in rendered lines cannot be reproduced without
506
+ * it.
507
+ */
508
+ function reportDepth(
509
+ reports: readonly FileReport[],
510
+ checkpoints: Checkpoints,
511
+ ): void {
512
+ logStep('Depth')
513
+ logInfo(
514
+ `Runs measure rendered lines at ${checkpoints.renderWidth} columns and count blank lines.`,
515
+ )
516
+ logInfo(
517
+ `Fenced blocks are excluded, and so are peer lists averaging under ${checkpoints.peerBullet} characters a bullet.`,
518
+ )
519
+ logInfo(
520
+ 'A run that is entirely table rows is excluded too, since a heading inside a table splits the table rather than the run.',
521
+ )
522
+ logInfo(
523
+ 'A heading breaks a run and so does a bold section marker at column zero, such as a line reading only Risks in bold. A colon-less one breaks when it holds one whole code span, or when it runs to 20 characters or fewer, and an indented one stays prose.',
524
+ )
525
+
526
+ const over = reports
527
+ .filter((report) => report.structure.longestRun > checkpoints.run)
528
+ .sort((a, b) => b.structure.longestRun - a.structure.longestRun)
529
+
530
+ if (over.length === 0) {
531
+ logInfo(`No run past the ${checkpoints.run}-line checkpoint.`)
532
+ return
533
+ }
534
+
535
+ logWarn(`${over.length} past the ${checkpoints.run}-line checkpoint`)
536
+ pipeOutput(
537
+ over
538
+ .map(
539
+ (report) =>
540
+ `${report.structure.rel}:${report.structure.longestRunLine} ${report.structure.longestRun} rendered lines unbroken`,
541
+ )
542
+ .join('\n'),
543
+ )
544
+ }