@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
package/src/pr/paths.ts CHANGED
@@ -3,12 +3,12 @@ import { findBacktickSpans } from '@/markdown/backticks'
3
3
  /**
4
4
  * The heading whose bullets state what a branch changed.
5
5
  *
6
- * Read alone, and never widened to a sibling section. `## Technical Context`
6
+ * Read alone, and never widened to a sibling section. `## Technical context`
7
7
  * legitimately names files a branch never touched, such as an install stamp
8
8
  * inside a target, so a reader that took the whole body would manufacture a
9
9
  * finding out of every argument the author made for the change.
10
10
  */
11
- export const KEY_CHANGES = 'Key Changes'
11
+ export const KEY_CHANGES = 'Key changes'
12
12
 
13
13
  /** What one bullet claimed, kept with its bullet so a finding can quote it. */
14
14
  export interface PathClaim {
@@ -86,7 +86,7 @@ const BARE_LINE = /^:\d+(?:-\d+)?$/
86
86
  * `canon markdown audit .claude/rules --json` carries a slash and names no file.
87
87
  * Angle brackets answer a second, since `.canon/plans/feature-<slug>.md`
88
88
  * describes a shape rather than naming a file. A glob and a caret describe a
89
- * shape too, `^src/` being a grep pattern one body spelled in Key Changes, and
89
+ * shape too, `^src/` being a grep pattern one body spelled in Key changes, and
90
90
  * a leading anchor names something outside this repository.
91
91
  *
92
92
  * Deliberately not shared with `classifySpan` in `@/gov/citations`, which asks
@@ -307,7 +307,7 @@ function resolveSpan(span: string): ResolvedSpan | undefined {
307
307
  }
308
308
 
309
309
  /**
310
- * Every path the `## Key Changes` section claims a change to.
310
+ * Every path the `## Key changes` section claims a change to.
311
311
  *
312
312
  * `roots` names the entries the tree holds at its top level, which is what
313
313
  * separates a whole path from one written partially. It is passed in rather
@@ -30,7 +30,7 @@ import { type BlockedPath, guardPayload } from '@/records/push-guard'
30
30
  * rather than named here. That is what keeps this list at one line per surface
31
31
  * as archives spread, which a sibling-per-archive layout could not.
32
32
  *
33
- * `RECORD_KINDS` in `validate.ts` overlaps this on five names and carries one
33
+ * `RECORD_KINDS` in `validate.ts` overlaps this on four names and carries one
34
34
  * more that no backup reaches. The two lists differ on purpose: one is what a
35
35
  * standard governs, this is what a disk loss would take, and `standards` is
36
36
  * tracked so a backup would carry a second copy of committed files.
@@ -39,7 +39,6 @@ export const BACKED_FOLDERS = [
39
39
  'diagrams',
40
40
  'groundwork',
41
41
  'intake',
42
- 'memory',
43
42
  'plans',
44
43
  'proposals',
45
44
  'review',
@@ -51,6 +50,15 @@ export const BACKED_FOLDERS = [
51
50
  'walkthroughs',
52
51
  ] as const
53
52
 
53
+ /**
54
+ * Folders a retired kind left at a legacy `.claude` root that the allowlist
55
+ * must still read, so a half-finished move that strands one still trips
56
+ * `split-roots`. Absent from `BACKED_FOLDERS` because nothing writes them, and
57
+ * absent from `RETIRED_FOLDERS` because that list stages a deletion and this
58
+ * folder is an archive to keep.
59
+ */
60
+ const LEGACY_RECORD_FOLDERS = ['memory'] as const
61
+
54
62
  /**
55
63
  * Names that have left `BACKED_FOLDERS` and whose removal still has to reach a
56
64
  * records history once.
@@ -124,7 +132,9 @@ function isExcluded(name: string): boolean {
124
132
  */
125
133
  function foldersAt(dir: string): string[] {
126
134
  if (basename(dir) === '.claude') {
127
- return BACKED_FOLDERS.filter((folder) => existsSync(join(dir, folder)))
135
+ return [...BACKED_FOLDERS, ...LEGACY_RECORD_FOLDERS].filter((folder) =>
136
+ existsSync(join(dir, folder)),
137
+ )
128
138
  }
129
139
 
130
140
  const entries = existsSync(dir)
@@ -378,7 +388,7 @@ async function enclosingRemotes(
378
388
  * Clears the four gates both verbs share and returns the records remote URL.
379
389
  *
380
390
  * The last two are the ones the payload depends on. This repository is public,
381
- * so a records branch on any of its remotes serves the memory pen and the
391
+ * so a records branch on any of its remotes serves the plans and the
382
392
  * groundwork trails to anyone who fetches all refs. Comparing the configured
383
393
  * URL against every remote of the enclosing repository is what keeps a
384
394
  * misconfigured `origin` from publishing them, and refusing when that list
@@ -416,7 +426,7 @@ async function resolveRemote(
416
426
  if (!enclosing) {
417
427
  return refuse(
418
428
  'remote-unreadable',
419
- `Cannot read the remotes of the project at ${root}, so the records origin cannot be checked against them. Records carry the memory pen and the groundwork trails, and an unchecked origin risks publishing them.`,
429
+ `Cannot read the remotes of the project at ${root}, so the records origin cannot be checked against them. Records carry the plans and the groundwork trails, and an unchecked origin risks publishing them.`,
420
430
  )
421
431
  }
422
432
 
@@ -424,7 +434,7 @@ async function resolveRemote(
424
434
  if (enclosing.identities.includes(url)) {
425
435
  return refuse(
426
436
  'remote-shared',
427
- `The records origin ${remote.text} is a remote of this project. Records carry the memory pen and the groundwork trails, so they need a repository of their own.`,
437
+ `The records origin ${remote.text} is a remote of this project. Records carry the plans and the groundwork trails, so they need a repository of their own.`,
428
438
  )
429
439
  }
430
440
 
@@ -4,7 +4,7 @@ import { recordDir } from '@/roots/record'
4
4
 
5
5
  /**
6
6
  * The two record folders that share one ordinal sequence, per
7
- * `standards/intake.md` and `standards/groundwork.md`. A folder opened as
7
+ * `claude/skills/plan-intake/references/intake.md` and `claude/skills/plan-groundwork/references/groundwork.md`. A folder opened as
8
8
  * either kind blocks the same number for the other, so the two read together
9
9
  * rather than each keeping a count of its own.
10
10
  */
@@ -35,7 +35,8 @@ const LEGACY_MOVES: ReadonlyMap<string, string> = new Map([
35
35
  * Scratch-root names a different migration moves out of scratch for good,
36
36
  * derived from that migration's own table rather than duplicated in a second
37
37
  * hand-kept list. `RECORD_LAYOUT_MOVES` names `memory-archive`, the
38
- * retired-entry archive `603-memory` says never to delete, and `PROMOTED_FOLDERS`
38
+ * retired-entry archive of the memory kind, which is never offered for deletion,
39
+ * and `PROMOTED_FOLDERS`
39
40
  * names an evidence folder a durable record cites by name. A project that has
40
41
  * not run either migration still carries these at the scratch root, where an
41
42
  * ordinary slug's own age test would eventually offer them.
@@ -3,11 +3,10 @@ import { existsSync } from 'node:fs'
3
3
  import { readFile } from 'node:fs/promises'
4
4
  import { relative } from 'node:path'
5
5
  import { gitEnv } from '@/git/env'
6
- import { readReviewed } from '@/records/stale'
7
6
  import { surfaceDir } from '@/roots/surface'
8
7
 
9
- /** The two records whose drift is identity rather than a stale path. */
10
- const CANONICAL_DOCS = ['REQUIREMENTS.md', 'ARCHITECTURE.md'] as const
8
+ /** The record whose drift is identity rather than a stale path. */
9
+ const CANONICAL_DOCS = ['REQUIREMENTS.md'] as const
11
10
 
12
11
  export interface CanonicalDoc {
13
12
  /** Relative to the root, at whichever surface root carries the doc. */
@@ -22,6 +21,37 @@ export interface CanonicalDoc {
22
21
  readonly latestRelease: string | null
23
22
  }
24
23
 
24
+ const REVIEWED_FIELD = /^reviewed:[ \t]*(.*?)[ \t]*$/m
25
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/
26
+ const RAW_FRONTMATTER = /^---\n([\s\S]*?)\n---/
27
+
28
+ /**
29
+ * Reads `reviewed` off the raw block rather than the parsed fields, for the
30
+ * reason `hasOpeningDate` in the validator gives: a YAML parser resolves a
31
+ * bare `YYYY-MM-DD` to a date on one schema and a string on another.
32
+ *
33
+ * A value that is not a calendar date reads as never reviewed and is carried
34
+ * back so the review can see it, rather than throwing over one hand edit.
35
+ */
36
+ function readReviewed(
37
+ text: string,
38
+ ): Pick<CanonicalDoc, 'reviewed' | 'invalidReviewed'> {
39
+ const block = RAW_FRONTMATTER.exec(text)?.[1]
40
+ const match = block ? REVIEWED_FIELD.exec(block) : null
41
+ if (!match) return { reviewed: null }
42
+
43
+ const value = match[1].replace(/^(['"])(.*)\1$/, '$2')
44
+ const parsed = Date.parse(`${value}T00:00:00Z`)
45
+ const isDate =
46
+ ISO_DATE.test(value) &&
47
+ Number.isFinite(parsed) &&
48
+ new Date(parsed).toISOString().slice(0, 10) === value
49
+
50
+ return isDate
51
+ ? { reviewed: value }
52
+ : { reviewed: null, invalidReviewed: value }
53
+ }
54
+
25
55
  export interface CanonicalReport {
26
56
  readonly ok: true
27
57
  readonly root: string
@@ -22,7 +22,6 @@ export const RECORD_KINDS = [
22
22
  'plans',
23
23
  'groundwork',
24
24
  'intake',
25
- 'memory',
26
25
  'standards',
27
26
  'teach',
28
27
  ] as const
@@ -60,7 +59,6 @@ export type ValidateRefusal = (typeof VALIDATE_REFUSALS)[number]
60
59
  export const FINDING_KINDS = [
61
60
  'name-malformed',
62
61
  'title-missing',
63
- 'title-is-slug',
64
62
  'section-missing',
65
63
  'scope-unanchored',
66
64
  'entry-unreasoned',
@@ -72,7 +70,6 @@ export const FINDING_KINDS = [
72
70
  'state-missing',
73
71
  'closing-partial',
74
72
  'item-incomplete',
75
- 'category-mismatch',
76
73
  'operator-call-phrasing',
77
74
  'batch-unsplit',
78
75
  'source-unquoted',
@@ -81,22 +78,12 @@ export const FINDING_KINDS = [
81
78
 
82
79
  export type FindingKind = (typeof FINDING_KINDS)[number]
83
80
 
84
- /**
85
- * The transforms `migrate.ts` carries. Most finding kinds have none, since a
86
- * transform is only safe where the old shape is recoverable from the file
87
- * itself, so this stays optional on `Finding` rather than required.
88
- */
89
- export const FINDING_REMEDIES = ['category-from-name'] as const
90
-
91
- export type FindingRemedy = (typeof FINDING_REMEDIES)[number]
92
-
93
81
  export interface Finding {
94
82
  readonly kind: FindingKind
95
83
  /** The record the finding sits in, relative to the validated folder. */
96
84
  readonly record: string
97
85
  readonly subject: string
98
86
  readonly message: string
99
- readonly remedy?: FindingRemedy
100
87
  }
101
88
 
102
89
  export interface ValidateReport {
@@ -214,9 +201,8 @@ function finding(
214
201
  record: string,
215
202
  subject: string,
216
203
  message: string,
217
- remedy?: FindingRemedy,
218
204
  ): Finding {
219
- return { kind, record, subject, message, remedy }
205
+ return { kind, record, subject, message }
220
206
  }
221
207
 
222
208
  async function listMarkdown(dir: string): Promise<string[]> {
@@ -934,169 +920,6 @@ async function checkWorkspace(dir: string, slug: string): Promise<Finding[]> {
934
920
  ]
935
921
  }
936
922
 
937
- const MEMORY_INDEX = 'index.md'
938
- const MEMORY_FIELDS = ['title', 'description', 'category'] as const
939
-
940
- /**
941
- * The filename prefix and the `category` field are one fact in two spellings,
942
- * so the map is the whole type list and the comparison against it is what
943
- * catches a prefix outside the set, a field disagreeing with the prefix, and a
944
- * casing drift that would open a second group in the catalog.
945
- */
946
- export const CATEGORY_BY_TYPE = {
947
- feedback: 'Feedback',
948
- project: 'Project',
949
- user: 'User',
950
- reference: 'Reference',
951
- } as const
952
-
953
- export type MemoryType = keyof typeof CATEGORY_BY_TYPE
954
-
955
- const MEMORY_TYPES = Object.keys(CATEGORY_BY_TYPE) as readonly MemoryType[]
956
-
957
- export const MEMORY_NAME = /^([a-z]+)-[a-z0-9]+(?:-[a-z0-9]+)*\.md$/
958
-
959
- /** The two markers a rule-bearing body carries, on top of the rule line itself. */
960
- const MEMORY_MARKERS = ['**Why:**', '**How to apply:**'] as const
961
-
962
- export function memoryType(value: string): MemoryType | undefined {
963
- return MEMORY_TYPES.find((type) => type === value)
964
- }
965
-
966
- /**
967
- * The one missing-field shape `migrate.ts` can repair: `category` alone,
968
- * recoverable from the same filename prefix `checkMemory` already read it
969
- * from. `title` and `description` are prose nobody wrote down, so a finding
970
- * naming either carries no remedy.
971
- */
972
- function memoryRemedy(
973
- missing: readonly string[],
974
- named: MemoryType | undefined,
975
- ): FindingRemedy | undefined {
976
- return named && missing.length === 1 && missing[0] === 'category'
977
- ? 'category-from-name'
978
- : undefined
979
- }
980
-
981
- export function checkMemory(name: string, text: string): Finding[] {
982
- const findings: Finding[] = []
983
- const match = MEMORY_NAME.exec(name)
984
- const named = match ? memoryType(match[1]) : undefined
985
-
986
- if (!named) {
987
- findings.push(
988
- finding(
989
- 'name-malformed',
990
- name,
991
- name,
992
- `is not named <type>-<slug>.md with a type of ${MEMORY_TYPES.join(', ')}.`,
993
- ),
994
- )
995
- }
996
-
997
- const frontmatter = parseFrontmatter(text)
998
- const missing = MEMORY_FIELDS.filter(
999
- (field) => !readField(frontmatter, field),
1000
- )
1001
-
1002
- if (missing.length > 0) {
1003
- findings.push(
1004
- finding(
1005
- 'frontmatter-incomplete',
1006
- name,
1007
- name,
1008
- `carries no ${missing.join(' and no ')}.`,
1009
- memoryRemedy(missing, named),
1010
- ),
1011
- )
1012
- }
1013
-
1014
- // Its own kind rather than `title-missing`, which means an absent heading on a
1015
- // plan. One kind covering both leaves a caller filtering the JSON unable to
1016
- // tell a record with no title from one whose title is its own slug.
1017
- if (readField(frontmatter, 'title') === name.replace(/\.md$/, '')) {
1018
- findings.push(
1019
- finding(
1020
- 'title-is-slug',
1021
- name,
1022
- name,
1023
- 'is titled with its own filename, so the catalog renders a slug where the rule belongs.',
1024
- ),
1025
- )
1026
- }
1027
-
1028
- const category = readField(frontmatter, 'category')
1029
-
1030
- // Reported against the prefix alone. A name the prefix rule already failed
1031
- // has no type to compare against, and reporting it twice names one defect as
1032
- // two.
1033
- if (named && category && category !== CATEGORY_BY_TYPE[named]) {
1034
- findings.push(
1035
- finding(
1036
- 'category-mismatch',
1037
- name,
1038
- category,
1039
- `is not ${CATEGORY_BY_TYPE[named]}, which the filename prefix declares.`,
1040
- ),
1041
- )
1042
- }
1043
-
1044
- return [
1045
- ...findings,
1046
- ...checkMemoryBody(
1047
- name,
1048
- text.slice(frontmatter?.raw.length ?? 0),
1049
- named ?? category,
1050
- ),
1051
- ]
1052
- }
1053
-
1054
- /**
1055
- * A `user` or `reference` entry is a single sentence by design, so the markers
1056
- * are checked only where a rule is being stated. The type is read off the
1057
- * prefix, falling back to the category so a misnamed file is still checked
1058
- * against the shape it claims.
1059
- */
1060
- function checkMemoryBody(
1061
- name: string,
1062
- text: string,
1063
- claimed: string | undefined,
1064
- ): Finding[] {
1065
- const type = claimed && memoryType(claimed.toLowerCase())
1066
- if (type !== 'feedback' && type !== 'project') return []
1067
-
1068
- const body = linesOutsideFences(text).filter((line) => line.trim().length > 0)
1069
-
1070
- const findings: Finding[] = []
1071
- const opening = body[0]
1072
-
1073
- if (!opening || MEMORY_MARKERS.some((marker) => opening.startsWith(marker))) {
1074
- findings.push(
1075
- finding(
1076
- 'section-missing',
1077
- name,
1078
- 'the rule line',
1079
- 'is absent, so the entry carries a rationale with no rule to apply.',
1080
- ),
1081
- )
1082
- }
1083
-
1084
- for (const marker of MEMORY_MARKERS) {
1085
- if (!body.some((line) => line.startsWith(marker))) {
1086
- findings.push(
1087
- finding(
1088
- 'section-missing',
1089
- name,
1090
- marker,
1091
- `is required on a ${type} entry and the body carries no such line.`,
1092
- ),
1093
- )
1094
- }
1095
- }
1096
-
1097
- return findings
1098
- }
1099
-
1100
923
  const STANDARD_INDEX = 'index.md'
1101
924
  const STANDARD_FIELDS = ['title', 'description'] as const
1102
925
 
@@ -1225,7 +1048,7 @@ export function checkStandard(name: string, text: string): Finding[] {
1225
1048
  */
1226
1049
  const FOLDER_CHECK: Readonly<
1227
1050
  Record<
1228
- Exclude<RecordKind, 'plans' | 'memory' | 'standards'>,
1051
+ Exclude<RecordKind, 'plans' | 'standards'>,
1229
1052
  (dir: string, slug: string) => Promise<Finding[]>
1230
1053
  >
1231
1054
  > = {
@@ -1279,15 +1102,6 @@ export async function validateRecords(
1279
1102
 
1280
1103
  if (kind === 'plans') return validateFiles(dir, kind, checkPlan)
1281
1104
 
1282
- if (kind === 'memory') {
1283
- return validateFiles(
1284
- dir,
1285
- kind,
1286
- checkMemory,
1287
- (file) => file === MEMORY_INDEX,
1288
- )
1289
- }
1290
-
1291
1105
  // The walk stays flat, matching install and the catalog.
1292
1106
  if (kind === 'standards') {
1293
1107
  return validateFiles(
@@ -56,7 +56,7 @@ const CANON_SCRATCH = 'tmp'
56
56
  * Everything absent from this list is committed and never lands under the
57
57
  * record root, which is the rule the move ran on. `rules`, `skills`, and
58
58
  * `hooks` stay under `.claude/` because the vendor reads them there, while
59
- * `context`, `wireframes`, and the loose documents are tracked surfaces that
59
+ * `context` and the loose documents are tracked surfaces that
60
60
  * `surface.ts` resolves under `canon/` instead. A seed and a
61
61
  * superseded-layout report each ask this rather than assuming a root.
62
62
  */
@@ -71,7 +71,7 @@ export function listSkills(root: string): string[] {
71
71
  *
72
72
  * `<category>-<command>` is the rule `canon/context/sandbox/coverage/census.md` states, and it
73
73
  * alone pairs 29 of 54 skills. The bare `<command>` fallback is what reaches the
74
- * rest: `claude/target-setup.sh` drives the `target-setup` skill, not a `claude-target-setup` that
74
+ * rest: `claude/target-setup.ts` drives the `target-setup` skill, not a `claude-target-setup` that
75
75
  * does not exist. Stating one spelling and shipping two is what let the audit
76
76
  * report a paired skill as unpaired.
77
77
  *
@@ -44,13 +44,9 @@ function listScenarios(sandboxDir: string): ScenarioCoverage[] {
44
44
  const scenarios: ScenarioCoverage[] = []
45
45
 
46
46
  for (const category of listCategories(sandboxDir)) {
47
- // A stem in both forms counts once, and provisioning refuses it by name.
48
- const { scenarios: files, ambiguous } = listScenarioFiles(
49
- join(sandboxDir, category),
50
- )
51
- const commands = [...files.map((f) => f.command), ...ambiguous].sort()
47
+ const { scenarios: files } = listScenarioFiles(join(sandboxDir, category))
52
48
 
53
- for (const command of commands) {
49
+ for (const { command } of files) {
54
50
  scenarios.push({ category, command, armed: [] })
55
51
  }
56
52
  }
@@ -22,7 +22,6 @@ import {
22
22
  listCategories,
23
23
  listScenarioFiles,
24
24
  loadScenario,
25
- type ScenarioKind,
26
25
  } from '@/sandbox/scenario'
27
26
  import { createStubRemote, readStubManifest } from '@/sandbox/stub-remote'
28
27
 
@@ -153,28 +152,6 @@ export function armKey(arm: Arm): string {
153
152
  return arm.arm === undefined ? scenario : `${scenario}/${arm.arm}`
154
153
  }
155
154
 
156
- /**
157
- * Reads the quoted arguments of `select_or_route_scenario`, joining a call that
158
- * continues across backslash-newline pairs. The first argument is the prompt and
159
- * the rest are arm names. A call this cannot see returns no arms, which the
160
- * coverage cross-check in `enumerateArms` turns into an error rather than a
161
- * smaller list.
162
- */
163
- export function parseArmNames(source: string): string[] {
164
- const start = source.search(/select_or_route_scenario\b/)
165
- if (start === -1) return []
166
-
167
- const call = source
168
- .slice(start)
169
- .replace(/\\\n/g, ' ')
170
- .split('\n')[0]
171
- ?.replace(/^select_or_route_scenario/, '')
172
-
173
- return [...(call ?? '').matchAll(/"([^"]*)"/g)]
174
- .map((match) => match[1] ?? '')
175
- .slice(1)
176
- }
177
-
178
155
  function matchesTarget(
179
156
  category: string,
180
157
  command: string,
@@ -199,25 +176,14 @@ function matchesArm(arm: Arm, targets: readonly string[]): boolean {
199
176
  }
200
177
 
201
178
  /**
202
- * Reads a scenario's arm names and anchor flag: off a bash file's source, and
203
- * off a TypeScript module's own keys, which is what its stage routes on.
179
+ * Reads a scenario's arm names and anchor flag off its module's own keys, which
180
+ * is what its stage routes on.
204
181
  */
205
182
  function readArms(
206
183
  file: string,
207
- kind: ScenarioKind,
208
184
  ):
209
185
  | { ok: true; anchor: boolean; names: string[] }
210
186
  | { ok: false; error: string } {
211
- if (kind === 'sh') {
212
- const source = readFileSync(file, 'utf8')
213
-
214
- return {
215
- ok: true,
216
- anchor: /^use_anchor\s*\(\)/m.test(source),
217
- names: parseArmNames(source),
218
- }
219
- }
220
-
221
187
  try {
222
188
  const definition = loadScenario(file)
223
189
 
@@ -250,17 +216,12 @@ export function enumerateArms(
250
216
  const coverage = collectCoverage(root)
251
217
 
252
218
  for (const category of listCategories(sandboxDir)) {
253
- const { scenarios, ambiguous } = listScenarioFiles(
254
- join(sandboxDir, category),
255
- )
256
- for (const command of ambiguous)
257
- if (matchesTarget(category, command, targets))
258
- errors.push(`${category}:${command} exists as both .sh and .ts`)
219
+ const { scenarios } = listScenarioFiles(join(sandboxDir, category))
259
220
 
260
- for (const { command, file, kind } of scenarios) {
221
+ for (const { command, file } of scenarios) {
261
222
  if (!matchesTarget(category, command, targets)) continue
262
223
 
263
- const declared = readArms(file, kind)
224
+ const declared = readArms(file)
264
225
  if (!declared.ok) {
265
226
  errors.push(`${category}:${command} did not load: ${declared.error}`)
266
227
  continue
@@ -354,7 +354,7 @@ function checkWriteScope(
354
354
  // none, and without this the declaration vanishes from the verdict entirely:
355
355
  // no result, no skipped entry, and no contribution to the unchecked count that
356
356
  // exists to surface exactly this. The `undefined` branch above cannot stand in,
357
- // since `run.sh` always passes `--writes` and `readPathList` returns `[]` for an
357
+ // since `canon sandbox run` always passes `--writes` and `readPathList` returns `[]` for an
358
358
  // empty file. An arm whose output escaped the snapshot reads as a clean run,
359
359
  // which is the vacuous pass the harness exists to remove.
360
360
  if (writes.length === 0) {
@@ -377,7 +377,7 @@ function checkWriteScope(
377
377
  }
378
378
 
379
379
  /**
380
- * `run.sh` watches two toolkit roots for a write to shared session scratch
380
+ * `canon sandbox run` watches two toolkit roots for a write to shared session scratch
381
381
  * during a run, and reports every one it finds as an unattributed escape with
382
382
  * no arm able to fail on it. An arm whose skill legitimately reaches outside
383
383
  * the sandbox tree declares the destinations here, and the harness asserts
@@ -388,8 +388,8 @@ function checkWriteScope(
388
388
  * nothing skips rather than passing on a fabricated zero. An escape-scope
389
389
  * declaration exists to bound a side effect nothing requires, so zero escapes
390
390
  * is the outcome a correct run produces and reports as a pass outright,
391
- * provided a watched root held something to watch. `run.sh`'s `snapshot_root`
392
- * returns an empty manifest both when a watch ran clean and when none of the
391
+ * provided a watched root held something to watch. `snapshotRoot` in
392
+ * `src/sandbox/headless/watch.ts` returns an empty manifest both when a watch ran clean and when none of the
393
393
  * four watched directories existed under a root, and the two produce the same
394
394
  * empty `escapes` list. `watched` is what tells them apart: a run that had
395
395
  * nothing to watch reports unmeasured rather than passing on a diff it never