@erclx/canon 5.31.0 → 5.33.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 (413) hide show
  1. package/README.md +1 -1
  2. package/claude/.claude-plugin/plugin.json +1 -1
  3. package/claude/skills/api-design/references/adopted.md +1 -1
  4. package/claude/skills/auto-ship/REQUIREMENT.md +4 -16
  5. package/claude/skills/auto-ship/SKILL.md +13 -58
  6. package/claude/skills/auto-ship/references/draft-mark.md +2 -2
  7. package/claude/skills/auto-ship/references/failure-recovery.md +1 -5
  8. package/claude/skills/auto-ship/references/tier-failures.md +1 -1
  9. package/claude/skills/auto-ship/references/ui-checklist.md +2 -2
  10. package/claude/skills/auto-ship/references/verb-absent.md +3 -27
  11. package/claude/skills/auto-ship/references/worktree-name.md +1 -1
  12. package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
  13. package/claude/skills/backlog-triage/SKILL.md +2 -2
  14. package/claude/skills/canon-cli/REQUIREMENT.md +19 -18
  15. package/claude/skills/canon-cli/SKILL.md +75 -32
  16. package/claude/skills/canon-feedback/REQUIREMENT.md +1 -1
  17. package/claude/skills/canon-feedback/SKILL.md +11 -14
  18. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +13 -14
  19. package/claude/skills/canon-feedback-triage/SKILL.md +49 -30
  20. package/claude/skills/{canvas → canvas-board}/REQUIREMENT.md +5 -6
  21. package/claude/skills/{canvas → canvas-board}/SKILL.md +7 -7
  22. package/{standards → claude/skills/canvas-board/references}/canvas.md +12 -1
  23. package/{standards → claude/skills/canvas-board/references}/design.md +13 -5
  24. package/claude/skills/ci-workflow/REQUIREMENT.md +0 -1
  25. package/claude/skills/context-fold/REQUIREMENT.md +28 -48
  26. package/claude/skills/context-fold/SKILL.md +26 -95
  27. package/claude/skills/context-fold/references/classify.md +7 -8
  28. package/claude/skills/context-fold/references/completion-report.md +4 -8
  29. package/claude/skills/context-fold/references/context-refresh.md +7 -17
  30. package/{standards → claude/skills/context-fold/references}/context.md +19 -10
  31. package/claude/skills/context-fold/references/unusable-baseline.md +4 -8
  32. package/claude/skills/create-rule/REQUIREMENT.md +0 -1
  33. package/claude/skills/create-rule/SKILL.md +2 -2
  34. package/{standards → claude/skills/create-rule/references}/rule.md +12 -5
  35. package/claude/skills/create-skill/REQUIREMENT.md +6 -4
  36. package/claude/skills/create-skill/SKILL.md +10 -9
  37. package/{standards → claude/skills/create-skill/references}/skill-paths.md +1 -0
  38. package/{standards → claude/skills/create-skill/references}/skill.md +18 -15
  39. package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
  40. package/claude/skills/decision-escalate/SKILL.md +1 -1
  41. package/claude/skills/design-taste/REQUIREMENT.md +3 -5
  42. package/claude/skills/design-taste/SKILL.md +2 -4
  43. package/claude/skills/design-taste/references/vocabulary.md +1 -1
  44. package/claude/skills/docs-sync/REQUIREMENT.md +3 -3
  45. package/claude/skills/docs-sync/SKILL.md +3 -3
  46. package/{standards → claude/skills/docs-sync/references}/docs.md +11 -0
  47. package/{standards → claude/skills/docs-sync/references}/readme.md +9 -2
  48. package/claude/skills/document-health/REQUIREMENT.md +2 -2
  49. package/claude/skills/document-health/SKILL.md +4 -5
  50. package/claude/skills/document-health/references/axes.md +4 -6
  51. package/claude/skills/draft-and-pick/REQUIREMENT.md +16 -14
  52. package/claude/skills/draft-and-pick/SKILL.md +40 -32
  53. package/claude/skills/draft-and-pick/references/live-arms.md +9 -9
  54. package/claude/skills/draft-doc/REQUIREMENT.md +5 -5
  55. package/claude/skills/draft-doc/SKILL.md +9 -10
  56. package/claude/skills/draft-doc/references/requirements.md +61 -0
  57. package/claude/skills/draft-doc/references/wiki-kind.md +53 -0
  58. package/claude/skills/draft-doc/references/wiki.md +50 -30
  59. package/claude/skills/draft-figure/REQUIREMENT.md +2 -2
  60. package/claude/skills/draft-figure/SKILL.md +5 -5
  61. package/claude/skills/draft-figure/references/architecture-set.md +4 -4
  62. package/claude/skills/draft-figure/references/hand-drawn.md +2 -2
  63. package/claude/skills/draft-figure/references/mermaid-path.md +55 -0
  64. package/claude/skills/draft-figure/references/mermaid.md +43 -34
  65. package/claude/skills/draft-identity/REQUIREMENT.md +3 -3
  66. package/claude/skills/draft-identity/SKILL.md +10 -8
  67. package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
  68. package/claude/skills/draft-ready/SKILL.md +7 -7
  69. package/claude/skills/draft-ready/references/assembly.md +1 -1
  70. package/{standards → claude/skills/draft-ready/references}/ready.md +13 -5
  71. package/claude/skills/git-branch/SKILL.md +1 -1
  72. package/{standards → claude/skills/git-branch/references}/branch.md +1 -1
  73. package/claude/skills/git-commit/SKILL.md +2 -2
  74. package/claude/skills/git-followup/REQUIREMENT.md +1 -1
  75. package/claude/skills/git-followup/SKILL.md +1 -1
  76. package/claude/skills/git-issue/SKILL.md +1 -1
  77. package/claude/skills/git-issue/references/issue.md +3 -3
  78. package/claude/skills/git-pr/SKILL.md +13 -13
  79. package/claude/skills/git-pr/references/evidence.md +2 -2
  80. package/claude/skills/git-pr/references/final-command.md +38 -14
  81. package/claude/skills/git-pr/references/labels.md +5 -1
  82. package/{standards → claude/skills/git-pr/references}/pr.md +19 -9
  83. package/{standards → claude/skills/git-pr/references}/publish.md +5 -3
  84. package/claude/skills/git-pr/references/task-number.md +1 -1
  85. package/claude/skills/git-ship/REQUIREMENT.md +0 -2
  86. package/claude/skills/git-ship/SKILL.md +5 -12
  87. package/claude/skills/git-split/SKILL.md +3 -3
  88. package/claude/skills/git-stage/SKILL.md +1 -1
  89. package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
  90. package/claude/skills/plan-feature/SKILL.md +2 -6
  91. package/{standards → claude/skills/plan-feature/references}/plan.md +9 -10
  92. package/claude/skills/plan-groundwork/SKILL.md +5 -6
  93. package/{standards → claude/skills/plan-groundwork/references}/groundwork.md +17 -4
  94. package/claude/skills/plan-intake/SKILL.md +2 -3
  95. package/{standards → claude/skills/plan-intake/references}/intake.md +17 -2
  96. package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
  97. package/claude/skills/plan-intake-answer/SKILL.md +1 -1
  98. package/claude/skills/review-address/SKILL.md +2 -2
  99. package/claude/skills/review-address/references/post-review-findings.md +1 -1
  100. package/claude/skills/review-craft/REQUIREMENT.md +3 -3
  101. package/claude/skills/review-craft/SKILL.md +2 -2
  102. package/claude/skills/review-craft/references/ui.md +4 -4
  103. package/claude/skills/review-pr/REQUIREMENT.md +2 -2
  104. package/claude/skills/review-pr/SKILL.md +8 -10
  105. package/claude/skills/review-pr/references/body-variants.md +2 -2
  106. package/claude/skills/review-pr/references/key-changes.md +3 -3
  107. package/claude/skills/review-pr/references/post.md +4 -2
  108. package/claude/skills/review-ui/REQUIREMENT.md +1 -2
  109. package/claude/skills/review-ui/SKILL.md +2 -2
  110. package/claude/skills/review-ui/references/post.md +1 -1
  111. package/claude/skills/role-orchestrator/REQUIREMENT.md +3 -3
  112. package/claude/skills/role-orchestrator/SKILL.md +10 -10
  113. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +3 -3
  114. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +9 -9
  115. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +23 -1
  116. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
  117. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -5
  118. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +4 -1
  119. package/claude/skills/role-planner/REQUIREMENT.md +2 -1
  120. package/claude/skills/role-planner/SKILL.md +15 -4
  121. package/claude/skills/role-reviewer/SKILL.md +2 -2
  122. package/claude/skills/role-worker/REQUIREMENT.md +1 -0
  123. package/claude/skills/role-worker/SKILL.md +11 -3
  124. package/claude/skills/session-compact/REQUIREMENT.md +1 -4
  125. package/claude/skills/session-compact/SKILL.md +3 -13
  126. package/claude/skills/session-compact/references/handoff-note.md +2 -2
  127. package/claude/skills/session-map/REQUIREMENT.md +1 -9
  128. package/claude/skills/session-map/SKILL.md +9 -17
  129. package/{standards → claude/skills/session-map/references}/session.md +17 -11
  130. package/claude/skills/session-relay/REQUIREMENT.md +1 -1
  131. package/claude/skills/session-resume/REQUIREMENT.md +6 -8
  132. package/claude/skills/session-resume/SKILL.md +3 -9
  133. package/claude/skills/session-worktree/SKILL.md +6 -6
  134. package/claude/skills/session-worktree/references/main-root-writes.md +2 -2
  135. package/claude/skills/systematic-debugging/REQUIREMENT.md +0 -1
  136. package/claude/skills/target-check/REQUIREMENT.md +3 -3
  137. package/claude/skills/target-check/SKILL.md +1 -1
  138. package/claude/skills/target-check/references/domains.md +1 -1
  139. package/claude/skills/target-setup/REQUIREMENT.md +4 -4
  140. package/claude/skills/target-setup/SKILL.md +3 -3
  141. package/claude/skills/target-setup/references/detect.md +2 -2
  142. package/claude/skills/task-board/REQUIREMENT.md +7 -12
  143. package/claude/skills/task-board/SKILL.md +9 -21
  144. package/{standards → claude/skills/task-board/references}/board.md +9 -0
  145. package/claude/skills/task-board/references/decline.md +1 -1
  146. package/{standards → claude/skills/task-board/references}/tasks.md +15 -10
  147. package/claude/skills/task-complete/REQUIREMENT.md +47 -0
  148. package/claude/skills/task-complete/SKILL.md +86 -0
  149. package/claude/skills/{task-board → task-complete}/references/archive.md +5 -5
  150. package/claude/skills/task-complete/references/receipt-sweep.md +32 -0
  151. package/claude/skills/task-complete/references/unusable-baseline.md +19 -0
  152. package/claude/skills/teach-workspace/REQUIREMENT.md +6 -2
  153. package/claude/skills/teach-workspace/SKILL.md +9 -5
  154. package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
  155. package/claude/skills/teach-workspace/references/promotion-fold.md +29 -0
  156. package/claude/skills/teach-workspace/references/promotion.md +3 -3
  157. package/claude/skills/teach-workspace/references/revisit.md +1 -1
  158. package/{standards → claude/skills/teach-workspace/references}/teach.md +17 -5
  159. package/claude/skills/ui-checklist/SKILL.md +1 -1
  160. package/claude/skills/ux-audit/REQUIREMENT.md +2 -2
  161. package/claude/skills/ux-audit/SKILL.md +3 -4
  162. package/claude/skills/ux-measure/SKILL.md +1 -1
  163. package/claude/skills/write-human/REQUIREMENT.md +0 -1
  164. package/claude/skills/write-human/SKILL.md +1 -1
  165. package/docs/agents/audits.md +1 -1
  166. package/docs/agents/canvas.md +1 -1
  167. package/docs/agents/commands.md +4 -8
  168. package/docs/agents/context-audit-checks.md +11 -25
  169. package/docs/agents/context-audit.md +7 -15
  170. package/docs/agents/context-classify.md +5 -5
  171. package/docs/agents/counts.md +5 -5
  172. package/docs/agents/drift-surfaces.md +2 -2
  173. package/docs/agents/index.md +5 -7
  174. package/docs/agents/indexes.md +1 -1
  175. package/docs/agents/install-and-sync.md +6 -11
  176. package/docs/agents/intake.md +1 -1
  177. package/docs/agents/key-changes.md +5 -5
  178. package/docs/agents/label-coverage.md +11 -0
  179. package/docs/agents/migrate.md +1 -1
  180. package/docs/agents/records-push.md +2 -2
  181. package/docs/agents/records-stale.md +13 -48
  182. package/docs/agents/records-validate.md +4 -8
  183. package/docs/agents/records.md +6 -28
  184. package/docs/agents/restated.md +1 -1
  185. package/docs/agents/rule-citations.md +2 -2
  186. package/docs/agents/sandbox.md +4 -4
  187. package/docs/agents/skills-audit.md +2 -2
  188. package/docs/agents/state-scoped-risk.md +2 -2
  189. package/docs/agents/superseded.md +2 -2
  190. package/docs/agents/tasks-plans.md +1 -1
  191. package/docs/agents/tasks-validate.md +1 -1
  192. package/docs/agents/tasks.md +3 -3
  193. package/docs/agents/teach.md +1 -1
  194. package/docs/agents/upstream.md +26 -2
  195. package/docs/target/migrations.md +32 -0
  196. package/docs/target/projects.md +5 -7
  197. package/docs/target/scenarios.md +2 -2
  198. package/docs/target/sync.md +4 -4
  199. package/docs/workflow/ai-workflow.md +7 -38
  200. package/docs/workflow/index.md +1 -1
  201. package/docs/workflow/operating-model.md +10 -10
  202. package/docs/workflow/parallel-features.md +12 -12
  203. package/docs/workflow/skill-map-on-request.md +21 -24
  204. package/docs/workflow/skill-map.md +23 -34
  205. package/docs/workflow/visual-design-workflow.md +13 -16
  206. package/governance/renames.toml +0 -30
  207. package/governance/rules/canon/605-worktrees.md +1 -1
  208. package/governance/rules/canon/context.md +13 -0
  209. package/governance/rules/{standards → canon}/plan.md +4 -5
  210. package/governance/rules/canon/tasks.md +18 -0
  211. package/governance/rules/claude/skill.md +17 -0
  212. package/governance/stacks/base.toml +2 -4
  213. package/package.json +4 -4
  214. package/scripts/core/install-check.sh +4 -4
  215. package/scripts/core/regen-web-previews.ts +1 -1
  216. package/scripts/lib/ui.sh +0 -159
  217. package/src/audits/catalog.ts +5 -98
  218. package/src/claude/cases/authoring.ts +0 -18
  219. package/src/claude/cases/misc.ts +1 -14
  220. package/src/claude/cases/setup.ts +7 -20
  221. package/src/claude/cases/workflow.ts +6 -34
  222. package/src/claude/seeds.ts +1 -7
  223. package/src/claude/skills-audit.ts +3 -3
  224. package/src/cli/help.ts +4 -5
  225. package/src/cli/ui.ts +2 -3
  226. package/src/cli.ts +0 -4
  227. package/src/commands/claude.ts +9 -15
  228. package/src/commands/context.ts +18 -280
  229. package/src/commands/feedback.ts +22 -91
  230. package/src/commands/gov.ts +2 -15
  231. package/src/commands/labels.ts +326 -7
  232. package/src/commands/migrate.ts +6 -1
  233. package/src/commands/pr.ts +1 -1
  234. package/src/commands/records.ts +17 -403
  235. package/src/commands/sandbox.ts +3 -6
  236. package/src/commands/sync.ts +5 -3
  237. package/src/commands/tasks.ts +3 -3
  238. package/src/commands/upstream.ts +135 -0
  239. package/src/context/audit.ts +10 -19
  240. package/src/context/classify/extract.ts +6 -13
  241. package/src/context/classify/patterns.ts +2 -41
  242. package/src/context/classify/prompts.ts +2 -6
  243. package/src/context/classify/run.ts +3 -3
  244. package/src/context/folders.ts +8 -13
  245. package/src/context/gate.ts +11 -91
  246. package/src/context/requirements.ts +13 -4
  247. package/src/counts/scan.ts +3 -3
  248. package/src/design/budget.ts +1 -1
  249. package/src/design/components.ts +3 -3
  250. package/src/design/document.ts +1 -1
  251. package/src/design/regen.ts +1 -1
  252. package/src/design/render.ts +1 -1
  253. package/src/feedback/body.ts +0 -12
  254. package/src/gate/measures.ts +7 -58
  255. package/src/gate/sequencer.ts +56 -1
  256. package/src/gate/stages.ts +1 -7
  257. package/src/gov/citations.ts +9 -3
  258. package/src/gov/install.ts +2 -3
  259. package/src/gov/restated.ts +3 -3
  260. package/src/gov/stacks.ts +1 -1
  261. package/src/hooks/post-merge.ts +1 -1
  262. package/src/labels/apply.ts +39 -0
  263. package/src/labels/format.ts +3 -3
  264. package/src/labels/phase.ts +3 -3
  265. package/src/labels/sections.ts +43 -0
  266. package/src/markdown/structure.ts +2 -2
  267. package/src/migrate/record-layout.ts +3 -3
  268. package/src/migrate/skill-names.ts +20 -1
  269. package/src/pr/paths.ts +4 -4
  270. package/src/records/backup.ts +16 -6
  271. package/src/records/ordinal.ts +1 -1
  272. package/src/records/prune.ts +2 -1
  273. package/src/records/stale-canonical.ts +33 -3
  274. package/src/records/validate.ts +2 -188
  275. package/src/roots/record.ts +1 -1
  276. package/src/sandbox/census.ts +1 -1
  277. package/src/sandbox/coverage.ts +2 -6
  278. package/src/sandbox/equivalence.ts +5 -44
  279. package/src/sandbox/expect.ts +4 -4
  280. package/src/sandbox/provision.ts +13 -36
  281. package/src/sandbox/scenario.ts +137 -55
  282. package/src/sandbox/tree.ts +2 -6
  283. package/src/shipped/references.ts +3 -3
  284. package/src/standards/read.ts +44 -0
  285. package/src/sync/git.ts +1 -1
  286. package/src/sync/seeds-report.ts +1 -1
  287. package/src/tasks/archive.ts +5 -5
  288. package/src/tasks/branch.ts +3 -3
  289. package/src/tasks/label.ts +1 -1
  290. package/src/tasks/reach.ts +2 -2
  291. package/src/tasks/record.ts +2 -2
  292. package/src/tasks/validate.ts +2 -2
  293. package/src/teach/workspace.ts +1 -1
  294. package/src/upstream/cursor.ts +1 -1
  295. package/src/upstream/due.ts +128 -0
  296. package/src/upstream/releases.ts +2 -1
  297. package/standards/index.md +0 -35
  298. package/standards/standard.md +1 -7
  299. package/tooling/base/reference.md +2 -2
  300. package/tooling/base/seeds/.github/pull_request_template.md +2 -2
  301. package/tooling/claude/reference.md +7 -21
  302. package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +9 -1
  303. package/tooling/claude/seeds/.claude/hooks/records-index.sh +8 -20
  304. package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +171 -0
  305. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +3 -3
  306. package/tooling/claude/seeds/.claude/settings.json +9 -0
  307. package/tooling/claude/seeds/CLAUDE.md +1 -3
  308. package/tooling/claude/seeds/canon/REQUIREMENTS.md +2 -9
  309. package/tooling/web/configs/e2e/screenshot.ts +0 -1
  310. package/claude/skills/auto-ship/references/review-findings.md +0 -20
  311. package/claude/skills/bash-cli-script/REQUIREMENT.md +0 -43
  312. package/claude/skills/bash-cli-script/SKILL.md +0 -53
  313. package/claude/skills/bash-cli-script/references/template.md +0 -19
  314. package/claude/skills/canon-operator/REQUIREMENT.md +0 -62
  315. package/claude/skills/canon-operator/SKILL.md +0 -113
  316. package/claude/skills/canon-rollout/REQUIREMENT.md +0 -59
  317. package/claude/skills/canon-rollout/SKILL.md +0 -140
  318. package/claude/skills/canon-rollout/references/failure-recovery.md +0 -20
  319. package/claude/skills/context-fold/references/anchor-sweep.md +0 -58
  320. package/claude/skills/context-fold/references/promoted-pages.md +0 -29
  321. package/claude/skills/context-fold/references/receipt-sweep.md +0 -43
  322. package/claude/skills/context-fold/references/wireframe-sweep.md +0 -45
  323. package/claude/skills/create-standard/REQUIREMENT.md +0 -33
  324. package/claude/skills/create-standard/SKILL.md +0 -31
  325. package/claude/skills/design-extract/REQUIREMENT.md +0 -42
  326. package/claude/skills/design-extract/SKILL.md +0 -108
  327. package/claude/skills/draft-and-pick/references/frame.html +0 -118
  328. package/claude/skills/draft-doc/references/wireframes.md +0 -48
  329. package/claude/skills/markdown-propose/REQUIREMENT.md +0 -47
  330. package/claude/skills/markdown-propose/SKILL.md +0 -122
  331. package/claude/skills/markdown-propose/references/format.md +0 -118
  332. package/claude/skills/memory-capture/REQUIREMENT.md +0 -50
  333. package/claude/skills/memory-capture/SKILL.md +0 -117
  334. package/claude/skills/memory-review/REQUIREMENT.md +0 -52
  335. package/claude/skills/memory-review/SKILL.md +0 -129
  336. package/claude/skills/memory-review/references/later-phases.md +0 -118
  337. package/claude/skills/memory-review/references/receipt-format.md +0 -64
  338. package/claude/skills/project-commands/REQUIREMENT.md +0 -42
  339. package/claude/skills/project-commands/SKILL.md +0 -87
  340. package/claude/skills/repo-metadata/REQUIREMENT.md +0 -37
  341. package/claude/skills/repo-metadata/SKILL.md +0 -54
  342. package/claude/skills/restate-plainly/REQUIREMENT.md +0 -41
  343. package/claude/skills/restate-plainly/SKILL.md +0 -41
  344. package/claude/skills/review-branch/REQUIREMENT.md +0 -40
  345. package/claude/skills/review-branch/SKILL.md +0 -137
  346. package/claude/skills/seed-sync/REQUIREMENT.md +0 -45
  347. package/claude/skills/seed-sync/SKILL.md +0 -158
  348. package/claude/skills/sketch-design/REQUIREMENT.md +0 -38
  349. package/claude/skills/sketch-design/SKILL.md +0 -94
  350. package/claude/skills/ux-walkthrough/REQUIREMENT.md +0 -56
  351. package/claude/skills/ux-walkthrough/SKILL.md +0 -53
  352. package/claude/skills/ux-walkthrough/references/builds.md +0 -15
  353. package/claude/skills/ux-walkthrough/references/candidate-pages.md +0 -11
  354. package/claude/skills/ux-walkthrough/references/measuring.md +0 -22
  355. package/claude/skills/ux-walkthrough/references/record.md +0 -36
  356. package/claude/skills/ux-walkthrough/references/relay.md +0 -25
  357. package/docs/agents/architecture-record.md +0 -36
  358. package/docs/agents/review-classification.md +0 -76
  359. package/governance/rules/canon/603-memory.md +0 -11
  360. package/governance/rules/lang/120-bash.md +0 -18
  361. package/governance/rules/standards/architecture.md +0 -13
  362. package/governance/rules/standards/context.md +0 -14
  363. package/governance/rules/standards/design.md +0 -12
  364. package/governance/rules/standards/groundwork.md +0 -13
  365. package/governance/rules/standards/intake.md +0 -12
  366. package/governance/rules/standards/memory.md +0 -12
  367. package/governance/rules/standards/readme.md +0 -12
  368. package/governance/rules/standards/ready.md +0 -13
  369. package/governance/rules/standards/requirements.md +0 -12
  370. package/governance/rules/standards/rule.md +0 -13
  371. package/governance/rules/standards/session.md +0 -13
  372. package/governance/rules/standards/skill.md +0 -21
  373. package/governance/rules/standards/standard.md +0 -13
  374. package/governance/rules/standards/tasks.md +0 -15
  375. package/governance/rules/standards/teach.md +0 -14
  376. package/governance/rules/standards/wiki.md +0 -13
  377. package/governance/rules/standards/wireframes.md +0 -13
  378. package/scripts/config.sh +0 -11
  379. package/scripts/lib/gov.sh +0 -14
  380. package/scripts/lib/sandbox-fixtures.sh +0 -191
  381. package/scripts/lib/sandbox-git.sh +0 -125
  382. package/scripts/lib/sandbox-path.sh +0 -50
  383. package/scripts/sandbox-hook.sh +0 -99
  384. package/src/autoship/classify.ts +0 -75
  385. package/src/autoship/paths.ts +0 -50
  386. package/src/commands/autoship.ts +0 -129
  387. package/src/commands/repo.ts +0 -393
  388. package/src/context/architecture.ts +0 -654
  389. package/src/context/wireframe-states.ts +0 -238
  390. package/src/gov/standard-rules.ts +0 -179
  391. package/src/records/migrate.ts +0 -78
  392. package/src/records/stale.ts +0 -243
  393. package/src/repo/metadata.ts +0 -206
  394. package/src/sandbox/hooks.ts +0 -128
  395. package/standards/architecture.md +0 -127
  396. package/standards/memory.md +0 -158
  397. package/standards/mermaid.md +0 -64
  398. package/standards/requirements.md +0 -79
  399. package/standards/wiki.md +0 -77
  400. package/standards/wireframes.md +0 -143
  401. package/tooling/claude/seeds/.claude/memory/index.md +0 -8
  402. package/tooling/claude/seeds/canon/ARCHITECTURE.md +0 -23
  403. package/tooling/claude/seeds/canon/wireframes/index.md +0 -8
  404. /package/{standards → claude/skills/create-skill/references}/skill-practice.md +0 -0
  405. /package/{standards → claude/skills/create-skill/references}/skill-requirement.md +0 -0
  406. /package/{standards → claude/skills/draft-figure/references}/figures.md +0 -0
  407. /package/{standards → claude/skills/git-branch/references}/slug.md +0 -0
  408. /package/{standards → claude/skills/git-commit/references}/commit.md +0 -0
  409. /package/{standards → claude/skills/git-commit/references}/versioning.md +0 -0
  410. /package/{standards → claude/skills/plan-feature/references}/plan-lifecycle.md +0 -0
  411. /package/{standards → claude/skills/plan-groundwork/references}/groundwork-spikes.md +0 -0
  412. /package/{standards → claude/skills/task-board/references}/tasks-decline.md +0 -0
  413. /package/{standards → claude/skills/teach-workspace/references}/glossary.md +0 -0
@@ -1,654 +0,0 @@
1
- import { access, readFile } from 'node:fs/promises'
2
- import { join, relative } from 'node:path'
3
- import { AUDITS } from '@/audits/catalog'
4
- import { type BodyLine, bodyLines } from '@/markdown/scan'
5
- import { surfaceDir } from '@/roots/surface'
6
-
7
- /**
8
- * The record this measures, relative to `root`.
9
- *
10
- * A function rather than a fixed constant, because the path now resolves at
11
- * either surface root and a constant naming one of them would be believed to
12
- * be true of a project that has moved. One fixed name rather than a folder
13
- * walk otherwise, because the standard governing it names one document, and
14
- * the length rule this measures is stated by whichever record sits there
15
- * rather than by the standard or by this file.
16
- */
17
- export function architectureRel(root: string): string {
18
- return relative(root, surfaceDir(root, 'ARCHITECTURE.md'))
19
- }
20
-
21
- /**
22
- * The line allowances a record states for itself, absent when it states none.
23
- *
24
- * No standard sets a length rule for this document, so the numbers belong to
25
- * whichever record declares them rather than to the toolkit. Holding a pair in
26
- * code and gating every project against it audits a target against a rule it
27
- * never adopted, which is the failure `canResolveAtRoot` already answers on the
28
- * folder side. A record stating no rule is measured and never gated.
29
- */
30
- export interface Allowances {
31
- readonly frame: number
32
- readonly perDecision: number
33
- }
34
-
35
- /**
36
- * What a machine could do with the entry's reasoning, which is a candidate
37
- * rather than a verdict.
38
- *
39
- * - `countable`: carries a figure over a tree, so a run could recompute it.
40
- * - `invariant`: quantifies over a named tree, so a walk could falsify it.
41
- * - `neither`: says why a choice was made, which nothing tests.
42
- */
43
- export type ClaimKind = 'countable' | 'invariant' | 'neither'
44
-
45
- export interface DecisionReport {
46
- readonly heading: string
47
- /** Line of the `###` heading, so a report line opens at the entry. */
48
- readonly line: number
49
- readonly claim: ClaimKind
50
- /** The digit-spelled figures behind a `countable` reading, in order. */
51
- readonly figures: readonly string[]
52
- /** The first sentence behind an `invariant` reading, absent otherwise. */
53
- readonly quantified?: string
54
- /**
55
- * Executable checks the entry names, which is the only coverage signal the
56
- * record carries. Empty on an entry that names none, including one whose
57
- * claim some check happens to cover without the entry saying so.
58
- */
59
- readonly checks: readonly string[]
60
- /**
61
- * The entry's prose word count, its heading and fenced lines left out. Gates
62
- * only against a per-decision cap the record states, so the report and the
63
- * stage read one number.
64
- */
65
- readonly words: number
66
- /**
67
- * Whether a sentence outside code opens with `Revisit when`. Read on every
68
- * record and required only by one stating the clause, so a project that
69
- * never adopted it sees the reading without failing on it.
70
- */
71
- readonly revisit: boolean
72
- }
73
-
74
- export interface ArchitectureReport {
75
- readonly rel: string
76
- readonly lines: number
77
- /** The whole record's word count, reported for the same reason. */
78
- readonly words: number
79
- /**
80
- * Word count of the `## Risks / open questions` section, absent when the
81
- * record carries no such heading. The standard asks that section to hold
82
- * only what is still open, so its weight is read the same way the file's is.
83
- */
84
- readonly risksWords?: number
85
- /**
86
- * List items in the Risks section, nested ones included, since a nested
87
- * bullet is weight the reader pays for. Absent alongside `risksWords`, so a
88
- * record with no section never reads as one holding zero bullets.
89
- */
90
- readonly risksBullets?: number
91
- /** What the record declared, absent when it states no length rule. */
92
- readonly allowances?: Allowances
93
- /** The frame plus the per-decision allowance, absent alongside it. */
94
- readonly ceiling?: number
95
- /**
96
- * The most decisions the record says it holds, absent when it states no
97
- * cap. Declared by the record for the reason the allowances are, so a
98
- * project that never adopted a cap is measured and never gated.
99
- */
100
- readonly entryCap?: number
101
- /** The most words a decision may hold, absent when the record states none. */
102
- readonly wordCap?: number
103
- /** The most Risks bullets the record allows, absent when it states none. */
104
- readonly riskCap?: number
105
- /**
106
- * Whether the record states that every decision closes with a revisit
107
- * sentence. Declared by the record for the reason the cap is, so a record
108
- * that never wrote the clause is reported and never gated.
109
- */
110
- readonly revisitRequired: boolean
111
- readonly decisions: readonly DecisionReport[]
112
- }
113
-
114
- const DECISION_HEADING = /^###\s+(.+?)\s*$/
115
- const SECTION_HEADING = /^##\s+\S/
116
- /** A markdown list item at any depth, which is what a risk bullet is. */
117
- const LIST_ITEM = /^\s*(?:[-*+]|\d+[.)])\s+\S/
118
- /** The H2 whose bullets the standard's `## Caps` section counts. */
119
- const RISKS_HEADING = /^##\s+Risks\s*\/\s*open questions\s*$/i
120
- const CODE_SPAN = /`[^`]*`/g
121
- /** Dropped ahead of the figure scan, since an anchor date is not a claim. */
122
- const ISO_DATE = /\b\d{4}-\d{2}-\d{2}\b/g
123
- const FIGURE = /\b\d+(?:,\d{3})*\b/g
124
- const SENTENCE_SPLIT = /(?<=[.])\s+/
125
-
126
- /** A code span naming a path, which is what a quantifier has to govern. */
127
- const PATH_SPAN = String.raw`\`[^\`]*(?:/|\.md|\.ts|\.sh|\.json)[^\`]*\``
128
- const QUANTIFIER = String.raw`\b(?:every|each|no|nothing|any|all|never|only)\b`
129
- /** Six words is the widest gap the corpus puts between the two. */
130
- const WINDOW = String.raw`(?:\s+\S+){0,6}?\s+`
131
-
132
- const QUANTIFIES_PATH = new RegExp(
133
- `${QUANTIFIER}${WINDOW}${PATH_SPAN}|${PATH_SPAN}${WINDOW}${QUANTIFIER}`,
134
- 'i',
135
- )
136
-
137
- /**
138
- * A code span naming a check this repository could run: a shell script, or a
139
- * gate module whose measures read the tree in-process.
140
- */
141
- const SCRIPT_SPAN = /^(?:scripts\/[\w./-]+\.sh|src\/gate\/[\w./-]+\.ts)$/
142
- /** A code span invoking the CLI, which may or may not name a registered audit. */
143
- const CANON_SPAN = /^canon\s+(.+)$/
144
-
145
- /**
146
- * The audit invocations a decision could name, spelled as a reader writes them.
147
- *
148
- * Read off the catalog rather than listed, so a verb renamed at its source
149
- * stops matching here instead of going on matching a string nobody maintains.
150
- */
151
- const AUDIT_INVOCATIONS: readonly string[] = AUDITS.map((audit) =>
152
- audit.argv.filter((arg) => arg !== '--json').join(' '),
153
- )
154
-
155
- function codeSpans(text: string): string[] {
156
- return (text.match(CODE_SPAN) ?? []).map((span) => span.slice(1, -1))
157
- }
158
-
159
- /**
160
- * Names the executable checks an entry spells.
161
- *
162
- * A script has to exist on disk and a `canon` invocation has to match a
163
- * registered audit, because an entry naming a check that was removed is an
164
- * uncovered claim wearing a covered one's words.
165
- */
166
- async function namedChecks(root: string, body: string): Promise<string[]> {
167
- const spans = [...new Set(codeSpans(body))]
168
-
169
- const verbs = spans.filter((span) => {
170
- const invocation = span.match(CANON_SPAN)?.[1]
171
- return invocation !== undefined && AUDIT_INVOCATIONS.includes(invocation)
172
- })
173
-
174
- const scripts = spans.filter((span) => SCRIPT_SPAN.test(span))
175
- const present = await Promise.all(
176
- scripts.map((span) =>
177
- access(join(root, span)).then(
178
- () => true,
179
- () => false,
180
- ),
181
- ),
182
- )
183
-
184
- return [...verbs, ...scripts.filter((_, index) => present[index])]
185
- }
186
-
187
- /**
188
- * Reads the figures a decision carries, which is the countable-claim signal.
189
- *
190
- * Digits alone. A cardinal spelled in words reads as pronominal far more often
191
- * than as measured in this corpus, where "the alternative and it is one nobody
192
- * passes" outnumbers "eleven copies", and admitting the spelled form classified
193
- * 22 of 24 entries as countable, which distinguishes nothing. The cost is that
194
- * a measured claim written in words reads as uncounted, which the report says.
195
- */
196
- function figuresIn(body: string): string[] {
197
- return body.replace(ISO_DATE, ' ').replace(CODE_SPAN, ' ').match(FIGURE) ?? []
198
- }
199
-
200
- /**
201
- * The first sentence quantifying over a named tree, or undefined.
202
- *
203
- * The quantifier has to sit within a short window of the path so a sentence
204
- * mentioning both without relating them does not read as a claim about the
205
- * tree. Both orders are matched, since the corpus writes the property before
206
- * the path as readily as after it.
207
- */
208
- function quantifiedSentence(body: string): string | undefined {
209
- return body
210
- .replace(ISO_DATE, ' ')
211
- .split(SENTENCE_SPLIT)
212
- .map((sentence) => sentence.replace(/\n/g, ' ').trim())
213
- .find((sentence) => QUANTIFIES_PATH.test(sentence))
214
- }
215
-
216
- /**
217
- * Classifies one entry, with the countable reading taking precedence.
218
- *
219
- * An entry carrying both a figure and a quantified tree is recomputable, which
220
- * is the stronger test, and the two readings are reported as one kind because
221
- * the coverage split a reader wants is testable against unverifiable rather
222
- * than a per-entry inventory of every claim in it.
223
- */
224
- export function classifyDecision(body: string): {
225
- claim: ClaimKind
226
- figures: string[]
227
- quantified?: string
228
- } {
229
- const figures = figuresIn(body)
230
- if (figures.length > 0) return { claim: 'countable', figures }
231
-
232
- const quantified = quantifiedSentence(body)
233
- if (quantified !== undefined) {
234
- return { claim: 'invariant', figures: [], quantified }
235
- }
236
-
237
- return { claim: 'neither', figures: [] }
238
- }
239
-
240
- interface RawDecision {
241
- readonly heading: string
242
- readonly line: number
243
- readonly body: string
244
- /** The body with its fenced lines dropped, which is where prose is read. */
245
- readonly prose: string
246
- }
247
-
248
- /**
249
- * Splits the record into its `###` entries.
250
- *
251
- * A heading inside a fenced block is skipped, since the seed template shows the
252
- * shape it asks a project to write and a template entry is not a decision.
253
- *
254
- * A heading carrying several decisions counts once, so the total reads low by
255
- * however many it holds. The report states that rather than parsing for it,
256
- * because splitting a decision from its heading needs a marker the standard
257
- * does not ask a record to carry.
258
- */
259
- export function splitDecisions(source: string): RawDecision[] {
260
- const lines = bodyLines(source)
261
- const decisions: RawDecision[] = []
262
- let open:
263
- | { heading: string; line: number; body: string[]; prose: string[] }
264
- | undefined
265
-
266
- const close = (): void => {
267
- if (!open) return
268
- decisions.push({
269
- heading: open.heading,
270
- line: open.line,
271
- body: open.body.join('\n'),
272
- prose: open.prose.join('\n'),
273
- })
274
- }
275
-
276
- for (const line of lines) {
277
- if (line.fenced) {
278
- open?.body.push(line.text)
279
- continue
280
- }
281
-
282
- const heading = line.text.match(DECISION_HEADING)?.[1]
283
- if (heading !== undefined) {
284
- close()
285
- open = { heading, line: line.number, body: [], prose: [] }
286
- continue
287
- }
288
-
289
- // A decision runs to the next `###` or to the section that follows the
290
- // decision list, so the risks below never read as the last entry's body.
291
- if (SECTION_HEADING.test(line.text)) {
292
- close()
293
- open = undefined
294
- continue
295
- }
296
-
297
- open?.body.push(line.text)
298
- open?.prose.push(line.text)
299
- }
300
-
301
- close()
302
- return decisions
303
- }
304
-
305
- /**
306
- * Counts whitespace-delimited tokens, the unit a record's word caps are stated
307
- * in. A code span counts as the tokens it holds, so a decision citing a long
308
- * path pays for it the way a reader does. A caller gating on the count hands
309
- * in prose with fenced lines already dropped.
310
- */
311
- export function wordCount(text: string): number {
312
- return text.match(/\S+/g)?.length ?? 0
313
- }
314
-
315
- /**
316
- * Extracts the `## Risks / open questions` section, or nothing when the
317
- * record carries no such heading.
318
- *
319
- * The section is read the same way `splitDecisions` reads a decision: capture
320
- * starts at the heading and stops at the next H2, or at the end of the file
321
- * when the section is last, which is where the standard's template puts it.
322
- */
323
- export function risksSection(source: string): string | undefined {
324
- return risksLines(source)
325
- ?.map((line) => line.text)
326
- .join('\n')
327
- }
328
-
329
- /**
330
- * Counts the list items in the Risks section, nested ones included, or
331
- * nothing when the record carries no such heading. A fenced line is skipped,
332
- * since a template bullet is not a risk.
333
- */
334
- export function riskBullets(source: string): number | undefined {
335
- return risksLines(source)?.filter(
336
- (line) => !line.fenced && LIST_ITEM.test(line.text),
337
- ).length
338
- }
339
-
340
- function risksLines(source: string): BodyLine[] | undefined {
341
- const body: BodyLine[] = []
342
- let capturing = false
343
- let found = false
344
-
345
- for (const line of bodyLines(source)) {
346
- if (line.fenced) {
347
- if (capturing) body.push(line)
348
- continue
349
- }
350
-
351
- if (RISKS_HEADING.test(line.text)) {
352
- capturing = true
353
- found = true
354
- continue
355
- }
356
-
357
- if (capturing && SECTION_HEADING.test(line.text)) {
358
- capturing = false
359
- continue
360
- }
361
-
362
- if (capturing) body.push(line)
363
- }
364
-
365
- return found ? body : undefined
366
- }
367
-
368
- /** Cardinals a record spells rather than writes, which the corpus does for both. */
369
- const SPELLED: Record<string, number> = {
370
- one: 1,
371
- two: 2,
372
- three: 3,
373
- four: 4,
374
- five: 5,
375
- six: 6,
376
- seven: 7,
377
- eight: 8,
378
- nine: 9,
379
- ten: 10,
380
- eleven: 11,
381
- twelve: 12,
382
- thirteen: 13,
383
- fourteen: 14,
384
- fifteen: 15,
385
- sixteen: 16,
386
- seventeen: 17,
387
- eighteen: 18,
388
- nineteen: 19,
389
- twenty: 20,
390
- }
391
-
392
- // Longest first, so `fourteen` is tried ahead of the `four` it starts with.
393
- const SPELLED_ALTERNATION = Object.keys(SPELLED)
394
- .sort((a, b) => b.length - a.length)
395
- .join('|')
396
- const CARDINAL = String.raw`(\d+|${SPELLED_ALTERNATION})`
397
- const FRAME_CLAUSE = new RegExp(String.raw`${CARDINAL}-line frame`, 'i')
398
- const PER_DECISION_CLAUSE = new RegExp(
399
- String.raw`${CARDINAL}\s+lines?\s+a\s+decision`,
400
- 'i',
401
- )
402
- const ENTRY_CAP_CLAUSE = new RegExp(
403
- String.raw`\bat\s+most\s+${CARDINAL}\s+decisions?\b`,
404
- 'i',
405
- )
406
- const WORD_CAP_CLAUSE = new RegExp(
407
- String.raw`\bat\s+most\s+${CARDINAL}\s+words\s+a\s+decision\b`,
408
- 'i',
409
- )
410
- const RISK_CAP_CLAUSE = new RegExp(
411
- String.raw`\bat\s+most\s+${CARDINAL}\s+risk\s+bullets?\b`,
412
- 'i',
413
- )
414
-
415
- function readCardinal(token: string | undefined): number | undefined {
416
- if (token === undefined) return undefined
417
- const spelled = SPELLED[token.toLowerCase()]
418
- if (spelled !== undefined) return spelled
419
-
420
- const digits = Number.parseInt(token, 10)
421
- return Number.isNaN(digits) ? undefined : digits
422
- }
423
-
424
- /**
425
- * Reads the allowances a record declares for itself, or nothing.
426
- *
427
- * Both clauses have to be present, because half a formula is not one. A record
428
- * whose wording drifts past these clauses falls back to reporting rather than
429
- * to a stale ceiling held here, so the failure is visible in the run's own
430
- * output instead of gating a project on a rule nobody can point at.
431
- */
432
- export function readAllowances(source: string): Allowances | undefined {
433
- const frame = readCardinal(source.match(FRAME_CLAUSE)?.[1])
434
- const perDecision = readCardinal(source.match(PER_DECISION_CLAUSE)?.[1])
435
-
436
- if (frame === undefined || perDecision === undefined) return undefined
437
- return { frame, perDecision }
438
- }
439
-
440
- /**
441
- * Reads the entry cap a record declares for itself, or nothing.
442
- *
443
- * The clause is the record's own, like the allowances above, so a record
444
- * whose wording drifts past it falls back to reporting rather than to a cap
445
- * held here that no project wrote.
446
- */
447
- export function readEntryCap(source: string): number | undefined {
448
- return readCardinal(source.match(ENTRY_CAP_CLAUSE)?.[1])
449
- }
450
-
451
- /**
452
- * Reads the per-decision word cap a record declares, spelled `at most <n>
453
- * words a decision`, or nothing. One spelling, the way the line allowance
454
- * reads `<n> lines a decision`, so a drift falls back to reporting.
455
- */
456
- export function readWordCap(source: string): number | undefined {
457
- return readCardinal(source.match(WORD_CAP_CLAUSE)?.[1])
458
- }
459
-
460
- /** Reads the Risks cap a record declares, spelled `at most <n> risk bullets`. */
461
- export function readRiskCap(source: string): number | undefined {
462
- return readCardinal(source.match(RISK_CAP_CLAUSE)?.[1])
463
- }
464
-
465
- const REVISIT_CLAUSE =
466
- /\bevery\s+decision\s+closes\s+with\s+a\s+revisit\s+sentence\b/i
467
- /**
468
- * `Revisit when` opening a sentence: at the start of the text, after a line
469
- * break, or after a sentence's closing stop. Mid-sentence it is not the
470
- * sentence the standard asks for.
471
- */
472
- const REVISIT_SENTENCE = /(?:^|\n|[.!?]\s+)\s*(?:[-*]\s+)?Revisit when\b/
473
-
474
- /**
475
- * Whether the record states the revisit clause for itself, read off its prose
476
- * alone so a template quoting the clause inside a fence does not adopt it.
477
- *
478
- * The clause is the record's own, like the cap, so wording that drifts past it
479
- * falls back to reporting rather than to a requirement held here.
480
- */
481
- export function readRevisitRule(source: string): boolean {
482
- const prose = bodyLines(source)
483
- .filter((line) => !line.fenced)
484
- .map((line) => line.text)
485
- .join('\n')
486
- .replace(CODE_SPAN, ' ')
487
- return REVISIT_CLAUSE.test(prose)
488
- }
489
-
490
- /**
491
- * Whether a decision's prose carries a sentence opening `Revisit when`.
492
- *
493
- * Presence only, never content, so a vacuous sentence passes. A code span is
494
- * dropped first, since a standard quoting the form is not stating one.
495
- */
496
- export function hasRevisitSentence(prose: string): boolean {
497
- return REVISIT_SENTENCE.test(prose.replace(CODE_SPAN, ' '))
498
- }
499
-
500
- /** Whether a read failed because nothing sits at the path. */
501
- function isMissing(error: unknown): boolean {
502
- const code = (error as { code?: unknown }).code
503
- return code === 'ENOENT' || code === 'ENOTDIR'
504
- }
505
-
506
- /** The ceiling the record's own formula derives from its decision count. */
507
- export function ceilingFor(allowances: Allowances, decisions: number): number {
508
- return allowances.frame + allowances.perDecision * decisions
509
- }
510
-
511
- /**
512
- * Measures the record, or reports nothing when the project carries none.
513
- *
514
- * Absent rather than empty, for the reason the sibling checks state: a project
515
- * with no record and one whose record holds no decision are different answers,
516
- * and a zeroed report reads as the second.
517
- */
518
- export async function measureArchitecture(
519
- root: string,
520
- ): Promise<ArchitectureReport | undefined> {
521
- const rel = architectureRel(root)
522
- const path = join(root, rel)
523
-
524
- let source: string
525
- try {
526
- source = await readFile(path, 'utf8')
527
- } catch (error) {
528
- // Only a record that is not there reads as absent. A record present and
529
- // unreadable propagates the way every sibling reader here lets one
530
- // propagate, since swallowing it reports a project with no record and the
531
- // length gate passes over a file nobody opened.
532
- if (!isMissing(error)) throw error
533
- return undefined
534
- }
535
-
536
- const allowances = readAllowances(source)
537
- const entryCap = readEntryCap(source)
538
- const wordCap = readWordCap(source)
539
- const riskCap = readRiskCap(source)
540
- const revisitRequired = readRevisitRule(source)
541
- const raw = splitDecisions(source)
542
- const decisions = await Promise.all(
543
- raw.map(async (entry) => {
544
- const { claim, figures, quantified } = classifyDecision(entry.body)
545
- return {
546
- heading: entry.heading,
547
- line: entry.line,
548
- claim,
549
- figures,
550
- ...(quantified !== undefined && { quantified }),
551
- checks: await namedChecks(root, entry.body),
552
- words: wordCount(entry.prose),
553
- revisit: hasRevisitSentence(entry.prose),
554
- }
555
- }),
556
- )
557
-
558
- const risks = risksSection(source)
559
- const bullets = riskBullets(source)
560
-
561
- return {
562
- rel,
563
- lines: source.replace(/\n$/, '').split('\n').length,
564
- words: wordCount(
565
- bodyLines(source)
566
- .map((line) => line.text)
567
- .join('\n'),
568
- ),
569
- ...(risks !== undefined && { risksWords: wordCount(risks) }),
570
- ...(bullets !== undefined && { risksBullets: bullets }),
571
- ...(allowances !== undefined && {
572
- allowances,
573
- ceiling: ceilingFor(allowances, raw.length),
574
- }),
575
- ...(entryCap !== undefined && { entryCap }),
576
- ...(wordCap !== undefined && { wordCap }),
577
- ...(riskCap !== undefined && { riskCap }),
578
- revisitRequired,
579
- decisions,
580
- }
581
- }
582
-
583
- /**
584
- * Whether the record holds more decisions than the cap it states.
585
- *
586
- * False for a record stating no cap, for the reason `isOverLength` gives. The
587
- * count is by heading, so a heading carrying several decisions counts once,
588
- * which is the undercount `splitDecisions` already names.
589
- */
590
- export function isOverCount(report: ArchitectureReport): boolean {
591
- return (
592
- report.entryCap !== undefined && report.decisions.length > report.entryCap
593
- )
594
- }
595
-
596
- /**
597
- * The decisions holding more prose words than the cap the record states.
598
- *
599
- * Empty for a record stating no word cap, for the reason `isOverCount` gives.
600
- */
601
- export function overWords(report: ArchitectureReport): DecisionReport[] {
602
- const cap = report.wordCap
603
- if (cap === undefined) return []
604
- return report.decisions.filter((entry) => entry.words > cap)
605
- }
606
-
607
- /**
608
- * Whether the Risks section holds more bullets than the cap the record states.
609
- *
610
- * False for a record stating no cap, and false for one carrying no Risks
611
- * section, which the stage reports as absent rather than as zero bullets.
612
- */
613
- export function isOverRisks(report: ArchitectureReport): boolean {
614
- return (
615
- report.riskCap !== undefined &&
616
- report.risksBullets !== undefined &&
617
- report.risksBullets > report.riskCap
618
- )
619
- }
620
-
621
- /**
622
- * The headings of decisions lacking a revisit sentence the record requires.
623
- *
624
- * Empty for a record stating no clause, for the reason `isOverCount` gives.
625
- */
626
- export function missingRevisit(report: ArchitectureReport): string[] {
627
- if (!report.revisitRequired) return []
628
- return report.decisions
629
- .filter((entry) => !entry.revisit)
630
- .map((entry) => entry.heading)
631
- }
632
-
633
- /**
634
- * Whether the record is longer than the ceiling it derives for itself.
635
- *
636
- * False for a record declaring no allowances, which has no ceiling to be past.
637
- * That is the answer rather than a gap, since the length rule is the record's
638
- * own and a project that never wrote one owes nothing to it.
639
- */
640
- export function isOverLength(report: ArchitectureReport): boolean {
641
- return report.ceiling !== undefined && report.lines > report.ceiling
642
- }
643
-
644
- /** How many entries carry a claim a machine could test. */
645
- export function testableCount(report: ArchitectureReport): number {
646
- return report.decisions.filter((entry) => entry.claim !== 'neither').length
647
- }
648
-
649
- /** How many testable entries name a check that exists. */
650
- export function coveredCount(report: ArchitectureReport): number {
651
- return report.decisions.filter(
652
- (entry) => entry.claim !== 'neither' && entry.checks.length > 0,
653
- ).length
654
- }