@erclx/canon 5.31.0 → 5.32.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 (303) 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/backlog-triage/SKILL.md +1 -1
  12. package/claude/skills/canon-cli/REQUIREMENT.md +4 -6
  13. package/claude/skills/canon-cli/SKILL.md +2 -2
  14. package/claude/skills/canon-feedback/REQUIREMENT.md +1 -1
  15. package/claude/skills/canon-feedback/SKILL.md +10 -13
  16. package/claude/skills/canon-feedback-triage/REQUIREMENT.md +13 -14
  17. package/claude/skills/canon-feedback-triage/SKILL.md +49 -30
  18. package/claude/skills/canvas/REQUIREMENT.md +3 -4
  19. package/claude/skills/canvas/SKILL.md +5 -5
  20. package/{standards → claude/skills/canvas/references}/canvas.md +12 -1
  21. package/claude/skills/ci-workflow/REQUIREMENT.md +0 -1
  22. package/claude/skills/context-fold/REQUIREMENT.md +8 -20
  23. package/claude/skills/context-fold/SKILL.md +20 -44
  24. package/claude/skills/context-fold/references/classify.md +7 -8
  25. package/claude/skills/context-fold/references/completion-report.md +2 -6
  26. package/claude/skills/context-fold/references/context-refresh.md +5 -15
  27. package/claude/skills/context-fold/references/promoted-pages.md +3 -3
  28. package/claude/skills/context-fold/references/receipt-sweep.md +6 -17
  29. package/claude/skills/context-fold/references/unusable-baseline.md +4 -6
  30. package/claude/skills/create-rule/REQUIREMENT.md +0 -1
  31. package/claude/skills/create-skill/REQUIREMENT.md +6 -4
  32. package/claude/skills/create-skill/SKILL.md +8 -7
  33. package/{standards → claude/skills/create-skill/references}/skill-paths.md +1 -0
  34. package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
  35. package/claude/skills/decision-escalate/SKILL.md +1 -1
  36. package/claude/skills/design-taste/REQUIREMENT.md +0 -2
  37. package/claude/skills/design-taste/SKILL.md +1 -3
  38. package/claude/skills/design-taste/references/vocabulary.md +1 -1
  39. package/claude/skills/docs-sync/REQUIREMENT.md +3 -3
  40. package/claude/skills/document-health/REQUIREMENT.md +2 -2
  41. package/claude/skills/document-health/SKILL.md +4 -5
  42. package/claude/skills/document-health/references/axes.md +4 -6
  43. package/claude/skills/draft-and-pick/REQUIREMENT.md +16 -14
  44. package/claude/skills/draft-and-pick/SKILL.md +40 -32
  45. package/claude/skills/draft-and-pick/references/live-arms.md +9 -9
  46. package/claude/skills/draft-doc/REQUIREMENT.md +5 -5
  47. package/claude/skills/draft-doc/SKILL.md +9 -10
  48. package/claude/skills/draft-doc/references/requirements.md +61 -0
  49. package/claude/skills/draft-doc/references/wiki-kind.md +53 -0
  50. package/claude/skills/draft-doc/references/wiki.md +50 -30
  51. package/claude/skills/draft-figure/REQUIREMENT.md +2 -2
  52. package/claude/skills/draft-figure/SKILL.md +4 -4
  53. package/claude/skills/draft-figure/references/architecture-set.md +4 -4
  54. package/claude/skills/draft-figure/references/hand-drawn.md +1 -1
  55. package/claude/skills/draft-figure/references/mermaid-path.md +55 -0
  56. package/claude/skills/draft-figure/references/mermaid.md +43 -34
  57. package/claude/skills/draft-identity/REQUIREMENT.md +1 -1
  58. package/claude/skills/draft-identity/SKILL.md +9 -7
  59. package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
  60. package/claude/skills/draft-ready/SKILL.md +6 -6
  61. package/claude/skills/draft-ready/references/assembly.md +1 -1
  62. package/{standards → claude/skills/draft-ready/references}/ready.md +13 -5
  63. package/claude/skills/git-issue/references/issue.md +3 -3
  64. package/claude/skills/git-ship/REQUIREMENT.md +0 -2
  65. package/claude/skills/git-ship/SKILL.md +16 -24
  66. package/claude/skills/plan-feature/SKILL.md +2 -6
  67. package/{standards → claude/skills/plan-feature/references}/plan.md +9 -10
  68. package/claude/skills/plan-groundwork/SKILL.md +5 -6
  69. package/{standards → claude/skills/plan-groundwork/references}/groundwork.md +17 -4
  70. package/claude/skills/plan-intake/SKILL.md +2 -3
  71. package/{standards → claude/skills/plan-intake/references}/intake.md +17 -2
  72. package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
  73. package/claude/skills/plan-intake-answer/SKILL.md +1 -1
  74. package/claude/skills/review-address/SKILL.md +1 -1
  75. package/claude/skills/review-craft/REQUIREMENT.md +3 -3
  76. package/claude/skills/review-craft/SKILL.md +2 -2
  77. package/claude/skills/review-craft/references/ui.md +4 -4
  78. package/claude/skills/review-pr/REQUIREMENT.md +1 -1
  79. package/claude/skills/review-pr/SKILL.md +5 -7
  80. package/claude/skills/review-ui/REQUIREMENT.md +0 -1
  81. package/claude/skills/review-ui/SKILL.md +1 -1
  82. package/claude/skills/role-orchestrator/REQUIREMENT.md +0 -3
  83. package/claude/skills/role-orchestrator/SKILL.md +8 -8
  84. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +3 -3
  85. package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +7 -10
  86. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
  87. package/claude/skills/role-orchestrator/references/orchestrator-refill.md +0 -3
  88. package/claude/skills/role-orchestrator/references/orchestrator-resume.md +1 -1
  89. package/claude/skills/role-planner/SKILL.md +2 -2
  90. package/claude/skills/role-reviewer/SKILL.md +1 -1
  91. package/claude/skills/role-worker/SKILL.md +2 -2
  92. package/claude/skills/session-compact/REQUIREMENT.md +1 -4
  93. package/claude/skills/session-compact/SKILL.md +3 -13
  94. package/claude/skills/session-compact/references/handoff-note.md +2 -2
  95. package/claude/skills/session-map/REQUIREMENT.md +1 -9
  96. package/claude/skills/session-map/SKILL.md +8 -16
  97. package/{standards → claude/skills/session-map/references}/session.md +17 -11
  98. package/claude/skills/session-relay/REQUIREMENT.md +1 -1
  99. package/claude/skills/session-resume/REQUIREMENT.md +4 -6
  100. package/claude/skills/session-resume/SKILL.md +3 -9
  101. package/claude/skills/session-worktree/SKILL.md +1 -1
  102. package/claude/skills/session-worktree/references/main-root-writes.md +2 -2
  103. package/claude/skills/systematic-debugging/REQUIREMENT.md +0 -1
  104. package/claude/skills/target-check/REQUIREMENT.md +3 -3
  105. package/claude/skills/target-check/SKILL.md +1 -1
  106. package/claude/skills/target-check/references/domains.md +1 -1
  107. package/claude/skills/target-setup/REQUIREMENT.md +4 -4
  108. package/claude/skills/target-setup/SKILL.md +3 -3
  109. package/claude/skills/target-setup/references/detect.md +1 -1
  110. package/claude/skills/task-board/SKILL.md +4 -4
  111. package/claude/skills/task-board/references/archive.md +1 -1
  112. package/{standards → claude/skills/task-board/references}/board.md +9 -0
  113. package/claude/skills/task-board/references/decline.md +1 -1
  114. package/{standards → claude/skills/task-board/references}/tasks.md +13 -8
  115. package/claude/skills/teach-workspace/SKILL.md +1 -1
  116. package/claude/skills/teach-workspace/references/revisit.md +1 -1
  117. package/{standards → claude/skills/teach-workspace/references}/teach.md +17 -5
  118. package/claude/skills/ux-audit/REQUIREMENT.md +2 -2
  119. package/claude/skills/ux-audit/SKILL.md +2 -3
  120. package/claude/skills/write-human/REQUIREMENT.md +0 -1
  121. package/claude/skills/write-human/SKILL.md +1 -1
  122. package/docs/agents/audits.md +1 -1
  123. package/docs/agents/canvas.md +1 -1
  124. package/docs/agents/commands.md +1 -6
  125. package/docs/agents/context-audit-checks.md +9 -23
  126. package/docs/agents/context-audit.md +7 -15
  127. package/docs/agents/context-classify.md +5 -5
  128. package/docs/agents/counts.md +5 -5
  129. package/docs/agents/drift-surfaces.md +2 -2
  130. package/docs/agents/index.md +3 -5
  131. package/docs/agents/install-and-sync.md +6 -6
  132. package/docs/agents/intake.md +1 -1
  133. package/docs/agents/records-stale.md +5 -5
  134. package/docs/agents/records-validate.md +1 -1
  135. package/docs/agents/records.md +2 -2
  136. package/docs/agents/restated.md +1 -1
  137. package/docs/agents/rule-citations.md +1 -1
  138. package/docs/agents/skills-audit.md +2 -2
  139. package/docs/agents/state-scoped-risk.md +2 -2
  140. package/docs/agents/superseded.md +2 -2
  141. package/docs/agents/tasks-plans.md +1 -1
  142. package/docs/agents/tasks-validate.md +1 -1
  143. package/docs/agents/tasks.md +1 -1
  144. package/docs/agents/teach.md +1 -1
  145. package/docs/agents/upstream.md +26 -2
  146. package/docs/target/migrations.md +24 -0
  147. package/docs/target/projects.md +5 -7
  148. package/docs/target/scenarios.md +2 -2
  149. package/docs/target/sync.md +3 -3
  150. package/docs/workflow/ai-workflow.md +7 -38
  151. package/docs/workflow/index.md +1 -1
  152. package/docs/workflow/operating-model.md +8 -8
  153. package/docs/workflow/parallel-features.md +7 -7
  154. package/docs/workflow/skill-map-on-request.md +12 -15
  155. package/docs/workflow/skill-map.md +20 -32
  156. package/docs/workflow/visual-design-workflow.md +11 -14
  157. package/governance/renames.toml +0 -19
  158. package/governance/rules/canon/605-worktrees.md +1 -1
  159. package/governance/rules/{standards → canon}/plan.md +4 -5
  160. package/governance/rules/canon/tasks.md +18 -0
  161. package/governance/stacks/base.toml +1 -1
  162. package/package.json +1 -1
  163. package/scripts/core/install-check.sh +1 -1
  164. package/scripts/core/regen-web-previews.ts +1 -1
  165. package/src/audits/catalog.ts +5 -97
  166. package/src/claude/cases/authoring.ts +0 -18
  167. package/src/claude/cases/misc.ts +0 -13
  168. package/src/claude/cases/setup.ts +3 -20
  169. package/src/claude/cases/workflow.ts +0 -33
  170. package/src/claude/seeds.ts +1 -7
  171. package/src/claude/skills-audit.ts +1 -1
  172. package/src/cli/help.ts +1 -4
  173. package/src/cli.ts +0 -4
  174. package/src/commands/claude.ts +8 -14
  175. package/src/commands/context.ts +18 -280
  176. package/src/commands/feedback.ts +22 -91
  177. package/src/commands/records.ts +5 -5
  178. package/src/commands/sync.ts +5 -3
  179. package/src/commands/upstream.ts +135 -0
  180. package/src/context/audit.ts +5 -14
  181. package/src/context/classify/extract.ts +6 -13
  182. package/src/context/classify/patterns.ts +2 -41
  183. package/src/context/classify/prompts.ts +2 -6
  184. package/src/context/classify/run.ts +3 -3
  185. package/src/context/folders.ts +7 -12
  186. package/src/context/gate.ts +11 -91
  187. package/src/context/requirements.ts +13 -4
  188. package/src/counts/scan.ts +3 -3
  189. package/src/design/components.ts +2 -2
  190. package/src/feedback/body.ts +0 -12
  191. package/src/gate/measures.ts +6 -57
  192. package/src/gov/citations.ts +9 -3
  193. package/src/gov/restated.ts +3 -3
  194. package/src/markdown/structure.ts +2 -2
  195. package/src/migrate/record-layout.ts +3 -3
  196. package/src/records/ordinal.ts +1 -1
  197. package/src/records/prune.ts +2 -1
  198. package/src/records/stale-canonical.ts +2 -2
  199. package/src/roots/record.ts +1 -1
  200. package/src/sandbox/scenario.ts +115 -11
  201. package/src/shipped/references.ts +3 -3
  202. package/src/standards/read.ts +31 -0
  203. package/src/sync/seeds-report.ts +1 -1
  204. package/src/tasks/reach.ts +2 -2
  205. package/src/tasks/validate.ts +1 -1
  206. package/src/teach/workspace.ts +1 -1
  207. package/src/upstream/cursor.ts +1 -1
  208. package/src/upstream/due.ts +128 -0
  209. package/src/upstream/releases.ts +2 -1
  210. package/standards/context.md +3 -5
  211. package/standards/design.md +2 -3
  212. package/standards/index.md +0 -22
  213. package/standards/publish.md +1 -1
  214. package/standards/skill.md +1 -1
  215. package/tooling/base/reference.md +1 -1
  216. package/tooling/claude/reference.md +6 -20
  217. package/tooling/claude/seeds/.claude/hooks/records-index.sh +8 -20
  218. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +3 -3
  219. package/tooling/claude/seeds/CLAUDE.md +1 -3
  220. package/tooling/claude/seeds/canon/REQUIREMENTS.md +2 -9
  221. package/tooling/web/configs/e2e/screenshot.ts +0 -1
  222. package/claude/skills/auto-ship/references/review-findings.md +0 -20
  223. package/claude/skills/bash-cli-script/REQUIREMENT.md +0 -43
  224. package/claude/skills/bash-cli-script/SKILL.md +0 -53
  225. package/claude/skills/bash-cli-script/references/template.md +0 -19
  226. package/claude/skills/canon-operator/REQUIREMENT.md +0 -62
  227. package/claude/skills/canon-operator/SKILL.md +0 -113
  228. package/claude/skills/canon-rollout/REQUIREMENT.md +0 -59
  229. package/claude/skills/canon-rollout/SKILL.md +0 -140
  230. package/claude/skills/canon-rollout/references/failure-recovery.md +0 -20
  231. package/claude/skills/context-fold/references/anchor-sweep.md +0 -58
  232. package/claude/skills/context-fold/references/wireframe-sweep.md +0 -45
  233. package/claude/skills/create-standard/REQUIREMENT.md +0 -33
  234. package/claude/skills/create-standard/SKILL.md +0 -31
  235. package/claude/skills/design-extract/REQUIREMENT.md +0 -42
  236. package/claude/skills/design-extract/SKILL.md +0 -108
  237. package/claude/skills/draft-and-pick/references/frame.html +0 -118
  238. package/claude/skills/draft-doc/references/wireframes.md +0 -48
  239. package/claude/skills/markdown-propose/REQUIREMENT.md +0 -47
  240. package/claude/skills/markdown-propose/SKILL.md +0 -122
  241. package/claude/skills/markdown-propose/references/format.md +0 -118
  242. package/claude/skills/memory-capture/REQUIREMENT.md +0 -50
  243. package/claude/skills/memory-capture/SKILL.md +0 -117
  244. package/claude/skills/memory-review/REQUIREMENT.md +0 -52
  245. package/claude/skills/memory-review/SKILL.md +0 -129
  246. package/claude/skills/memory-review/references/later-phases.md +0 -118
  247. package/claude/skills/memory-review/references/receipt-format.md +0 -64
  248. package/claude/skills/project-commands/REQUIREMENT.md +0 -42
  249. package/claude/skills/project-commands/SKILL.md +0 -87
  250. package/claude/skills/repo-metadata/REQUIREMENT.md +0 -37
  251. package/claude/skills/repo-metadata/SKILL.md +0 -54
  252. package/claude/skills/restate-plainly/REQUIREMENT.md +0 -41
  253. package/claude/skills/restate-plainly/SKILL.md +0 -41
  254. package/claude/skills/review-branch/REQUIREMENT.md +0 -40
  255. package/claude/skills/review-branch/SKILL.md +0 -137
  256. package/claude/skills/seed-sync/REQUIREMENT.md +0 -45
  257. package/claude/skills/seed-sync/SKILL.md +0 -158
  258. package/claude/skills/sketch-design/REQUIREMENT.md +0 -38
  259. package/claude/skills/sketch-design/SKILL.md +0 -94
  260. package/claude/skills/ux-walkthrough/REQUIREMENT.md +0 -56
  261. package/claude/skills/ux-walkthrough/SKILL.md +0 -53
  262. package/claude/skills/ux-walkthrough/references/builds.md +0 -15
  263. package/claude/skills/ux-walkthrough/references/candidate-pages.md +0 -11
  264. package/claude/skills/ux-walkthrough/references/measuring.md +0 -22
  265. package/claude/skills/ux-walkthrough/references/record.md +0 -36
  266. package/claude/skills/ux-walkthrough/references/relay.md +0 -25
  267. package/docs/agents/architecture-record.md +0 -36
  268. package/docs/agents/review-classification.md +0 -76
  269. package/governance/rules/canon/603-memory.md +0 -11
  270. package/governance/rules/lang/120-bash.md +0 -18
  271. package/governance/rules/standards/architecture.md +0 -13
  272. package/governance/rules/standards/groundwork.md +0 -13
  273. package/governance/rules/standards/intake.md +0 -12
  274. package/governance/rules/standards/memory.md +0 -12
  275. package/governance/rules/standards/ready.md +0 -13
  276. package/governance/rules/standards/requirements.md +0 -12
  277. package/governance/rules/standards/session.md +0 -13
  278. package/governance/rules/standards/tasks.md +0 -15
  279. package/governance/rules/standards/teach.md +0 -14
  280. package/governance/rules/standards/wiki.md +0 -13
  281. package/governance/rules/standards/wireframes.md +0 -13
  282. package/src/autoship/classify.ts +0 -75
  283. package/src/autoship/paths.ts +0 -50
  284. package/src/commands/autoship.ts +0 -129
  285. package/src/commands/repo.ts +0 -393
  286. package/src/context/architecture.ts +0 -654
  287. package/src/context/wireframe-states.ts +0 -238
  288. package/src/repo/metadata.ts +0 -206
  289. package/standards/architecture.md +0 -127
  290. package/standards/memory.md +0 -158
  291. package/standards/mermaid.md +0 -64
  292. package/standards/requirements.md +0 -79
  293. package/standards/wiki.md +0 -77
  294. package/standards/wireframes.md +0 -143
  295. package/tooling/claude/seeds/.claude/memory/index.md +0 -8
  296. package/tooling/claude/seeds/canon/ARCHITECTURE.md +0 -23
  297. package/tooling/claude/seeds/canon/wireframes/index.md +0 -8
  298. /package/{standards → claude/skills/create-skill/references}/skill-practice.md +0 -0
  299. /package/{standards → claude/skills/create-skill/references}/skill-requirement.md +0 -0
  300. /package/{standards → claude/skills/plan-feature/references}/plan-lifecycle.md +0 -0
  301. /package/{standards → claude/skills/plan-groundwork/references}/groundwork-spikes.md +0 -0
  302. /package/{standards → claude/skills/task-board/references}/tasks-decline.md +0 -0
  303. /package/{standards → claude/skills/teach-workspace/references}/glossary.md +0 -0
@@ -300,10 +300,10 @@ export function register(program: Command): void {
300
300
  'Entries are ordered due first, then those citing a missing path, then the',
301
301
  'longest unreviewed, then by name, so a review takes the first N as a batch.',
302
302
  '',
303
- 'canonical: reads REQUIREMENTS.md and ARCHITECTURE.md at whichever surface',
304
- 'root carries each, in the current worktree since both are tracked. Each',
305
- 'reports its reviewed date and the release tags merged into HEAD after that',
306
- 'day, or never when it carries no date. --days does not apply.',
303
+ 'canonical: reads REQUIREMENTS.md at whichever surface root carries it,',
304
+ 'in the current worktree since it is tracked. It reports its reviewed date',
305
+ 'and the release tags merged into HEAD after that day, or never when it',
306
+ 'carries no date. --days does not apply.',
307
307
  '',
308
308
  'Exit codes:',
309
309
  ' 0 the reading completed, whatever it found',
@@ -645,7 +645,7 @@ async function runStaleCanonical(
645
645
  logStep('Canonical')
646
646
 
647
647
  if (outcome.docs.length === 0) {
648
- logInfo('neither REQUIREMENTS.md nor ARCHITECTURE.md exists')
648
+ logInfo('REQUIREMENTS.md does not exist')
649
649
  } else {
650
650
  for (const doc of outcome.docs) logInfo(describeCanonical(doc, outcome))
651
651
  }
@@ -282,7 +282,7 @@ function renderTooling(report: CheckReport): void {
282
282
  /**
283
283
  * Seeds print their own section because no sync command applies them. A `stale`
284
284
  * seed is safe to take whole and a `drifted` one holds edits, which is the split
285
- * `seed-sync` reads to decide what needs a section-level merge.
285
+ * that decides what needs a hand merge.
286
286
  */
287
287
  function renderSeeds(report: CheckReport): void {
288
288
  const notable = report.seeds.entries.filter(
@@ -300,7 +300,9 @@ function renderSeeds(report: CheckReport): void {
300
300
  logWarn(`${entry.rel} (${entry.state})`)
301
301
  }
302
302
 
303
- logInfo('Run /canon:seed-sync to reconcile these section by section.')
303
+ logInfo(
304
+ 'A stale seed is safe to take whole. Merge a drifted one by hand against the toolkit copy.',
305
+ )
304
306
  }
305
307
 
306
308
  /**
@@ -401,7 +403,7 @@ async function runSync(target: string): Promise<number> {
401
403
 
402
404
  if (existsSync(join(resolved, '.claude'))) {
403
405
  process.stderr.write(
404
- `${GREY}Tip: run \`/seed-sync\` to audit seed drift per section, preserving local customizations.${NC}\n`,
406
+ `${GREY}Tip: merge a drifted seed by hand against the toolkit copy, and take a stale one whole.${NC}\n`,
405
407
  )
406
408
  }
407
409
 
@@ -1,23 +1,36 @@
1
1
  import { resolve } from 'node:path'
2
+ import { $ } from 'bun'
2
3
  import type { Command } from 'commander'
3
4
  import { intro, logInfo, logStep, logWarn, outro, plural } from '@/cli/ui'
4
5
  import { currentWorktreeRoot, mainWorktreeRoot } from '@/git/worktree'
5
6
  import { buildCatalog, renderCatalog } from '@/upstream/catalog'
6
7
  import {
7
8
  advanceCursor,
9
+ compareVersions,
8
10
  llmsDifference,
9
11
  readCursor,
10
12
  readLastLlms,
11
13
  } from '@/upstream/cursor'
12
14
  import { buildDigest } from '@/upstream/digest'
15
+ import {
16
+ decideDue,
17
+ passesVocabulary,
18
+ readDueCache,
19
+ writeDueCache,
20
+ type DueReason,
21
+ type Gap,
22
+ } from '@/upstream/due'
13
23
  import {
14
24
  githubPageFetcher,
15
25
  grepHint,
26
+ keepLines,
27
+ walkReleases,
16
28
  type FetchFailure,
17
29
  } from '@/upstream/releases'
18
30
 
19
31
  const LLMS_URL = 'https://code.claude.com/docs/llms.txt'
20
32
  const VERSION = /^\d+(\.\d+)*$/
33
+ const READ_BUDGET_MS = 5000
21
34
 
22
35
  interface RootOption {
23
36
  readonly root?: string
@@ -128,6 +141,33 @@ export function register(program: Command): void {
128
141
  process.exitCode = await runCatalog(opts)
129
142
  })
130
143
 
144
+ upstream
145
+ .command('due')
146
+ .description('Say whether a digest is due, from the cursor and the install')
147
+ .helpOption('-h, --help', 'Show this help message')
148
+ .option('--root <path>', 'Repository to read, defaulting to the main root')
149
+ .option('--json', 'Add a machine-readable record on stdout')
150
+ .addHelpText(
151
+ 'after',
152
+ [
153
+ '',
154
+ 'Due when the cursor is a week old and the installed version is ahead of',
155
+ 'it, or sooner when an Added line in the gap names a canon surface. The',
156
+ 'gap is read from GitHub at most once a day and cached under the scratch',
157
+ 'folder, and a failed read is held for the day as well.',
158
+ '',
159
+ 'Exit codes:',
160
+ ' 0 answered, whether or not a digest is due',
161
+ '',
162
+ 'Examples:',
163
+ ' canon upstream due --json',
164
+ '',
165
+ ].join('\n'),
166
+ )
167
+ .action(async (opts: RootOption) => {
168
+ process.exitCode = await runDue(opts)
169
+ })
170
+
131
171
  upstream
132
172
  .command('advance')
133
173
  .description('Move the cursor to a version once its digest is filed')
@@ -240,6 +280,101 @@ async function runFetch(opts: FetchOptions): Promise<number> {
240
280
  return 0
241
281
  }
242
282
 
283
+ const DUE_TEXT: Record<DueReason, string> = {
284
+ 'no-cursor': 'No digest has been run, so there is no cursor.',
285
+ week: 'A week has passed since the last digest.',
286
+ vocabulary: 'A release since the last digest added something canon may use.',
287
+ current: 'The installed version is at or below the cursor.',
288
+ recent:
289
+ 'The last digest is under a week old and nothing in the gap stands out.',
290
+ 'unknown-version': 'The installed version could not be read.',
291
+ }
292
+
293
+ async function installedVersion(): Promise<string | null> {
294
+ try {
295
+ const result = await $`claude --version`.quiet().nothrow()
296
+ const match = /^\d+(\.\d+)*/.exec(result.stdout.toString().trim())
297
+
298
+ return match ? match[0] : null
299
+ } catch {
300
+ return null
301
+ }
302
+ }
303
+
304
+ // A failed read is stored as a null gap, so a rate limit hit by one session of
305
+ // a wave is not retried by the nineteen after it.
306
+ async function readGap(
307
+ root: string,
308
+ installed: string,
309
+ cursor: string,
310
+ now: Date,
311
+ ): Promise<Gap | null> {
312
+ const cached = readDueCache(root, installed, cursor, now)
313
+ if (cached) return cached.gap
314
+
315
+ // The hook that calls this has a 10 second timeout, and a network that drops
316
+ // packets would otherwise hold every session start to it with nothing cached.
317
+ const walk = await walkReleases(
318
+ cursor,
319
+ githubPageFetcher(process.env, AbortSignal.timeout(READ_BUDGET_MS)),
320
+ )
321
+ const gap: Gap | null =
322
+ walk.kind === 'reached'
323
+ ? {
324
+ releases: walk.releases.length,
325
+ lines: walk.releases
326
+ .flatMap(keepLines)
327
+ .map((line) => line.text)
328
+ .filter(passesVocabulary),
329
+ }
330
+ : null
331
+
332
+ try {
333
+ await writeDueCache(root, {
334
+ checkedAt: now.toISOString(),
335
+ installed,
336
+ cursor,
337
+ gap,
338
+ })
339
+ } catch {
340
+ // A cache that cannot be written costs a request, not a wrong answer.
341
+ }
342
+
343
+ return gap
344
+ }
345
+
346
+ async function runDue(opts: RootOption): Promise<number> {
347
+ const root = opts.root ? resolve(opts.root) : await mainWorktreeRoot()
348
+ const now = new Date()
349
+ const cursor = readCursor(root)
350
+ const installed = await installedVersion()
351
+ const isAhead =
352
+ cursor !== null &&
353
+ installed !== null &&
354
+ compareVersions(installed, cursor.version) > 0
355
+ const gap = isAhead
356
+ ? await readGap(root, installed, cursor.version, now)
357
+ : null
358
+ const result = decideDue({ installed, cursor, gap, now })
359
+
360
+ intro('canon upstream due')
361
+ logStep(result.due ? 'Due' : 'Not due')
362
+ logInfo(DUE_TEXT[result.reason])
363
+ outro()
364
+
365
+ if (opts.json) {
366
+ process.stdout.write(
367
+ `${JSON.stringify({
368
+ ...result,
369
+ installed,
370
+ cursor: cursor?.version ?? null,
371
+ })}\n`,
372
+ )
373
+ }
374
+
375
+ return 0
376
+ }
377
+
243
378
  async function runCatalog(opts: RootOption): Promise<number> {
244
379
  const root = opts.root ? resolve(opts.root) : await currentWorktreeRoot()
245
380
  const catalog = buildCatalog(root)
@@ -18,7 +18,7 @@ import { isStubSeed } from '@/tooling/seed-marker'
18
18
  * Every reason `canon context audit` refuses for.
19
19
  *
20
20
  * `no-folders` is the one ordinary absence: a project that never adopted
21
- * `canon/context/` or `canon/wireframes/`, and holds no `.canon/diagrams/`
21
+ * `canon/context/`, and holds no `.canon/diagrams/`
22
22
  * folder an older install left, names no corpus this audit can measure, the
23
23
  * same state `no-skills` reads for the skill corpora. The other four are a malformed invocation or a checkout git
24
24
  * cannot read, which stay a break rather than an absence.
@@ -54,16 +54,13 @@ const CATALOG_NAMED_RATIO = 0.6
54
54
  *
55
55
  * These names do not generalize the way a length threshold does, which is why
56
56
  * each list is keyed on the folder whose standard states it. `context.md`
57
- * requires an overview and a layout. `wireframes.md` asks four questions of a
58
- * surface and answers each in a section, so those four are required and
59
- * `## Behavior` is not, since a static surface has no interaction to state. A
57
+ * requires an overview and a layout. A
60
58
  * diagram entry declares a heading per kind and its standard requires none.
61
59
  */
62
60
  export const REQUIRED_SECTIONS_BY_FOLDER: Readonly<
63
61
  Record<string, readonly string[]>
64
62
  > = {
65
63
  context: ['Overview', 'Layout'],
66
- wireframes: ['Regions', 'States', 'Copy', 'Not on this surface'],
67
64
  }
68
65
 
69
66
  /**
@@ -158,9 +155,8 @@ const SENTENCE_END = /[.!?:;]\s(?=[^.!?:;]*$)/
158
155
  * reading that field for a gain of one word.
159
156
  *
160
157
  * `standards/context.md` opens its scope by handing figures to the
161
- * `draft-figure` skill and wireframes to `wireframes.md`, so a marker reported
162
- * in a diagrams or wireframes entry would cite a rule that entry's own
163
- * standard routes elsewhere. The length and table
158
+ * `draft-figure` skill, so a marker reported in a diagrams entry would cite a
159
+ * rule that entry's own standard routes elsewhere. The length and table
164
160
  * checkpoints are quoted from the same standard and keep reaching every audited
165
161
  * folder, because a threshold on how far a reader travels generalizes across
166
162
  * entry types while a rule about what an entry may say does not.
@@ -495,7 +491,7 @@ function bareReferences(
495
491
  * path prefix hardcodes what `--folder` exists to override and misses a domain
496
492
  * split into `context/<sub-area>/`. Sibling names arrive the same way and for
497
493
  * the same reason, since the folder an entry sits in is what holds them. The
498
- * required sections arrive apart from jurisdiction, since a wireframe owes
494
+ * required sections arrive apart from jurisdiction, since a folder can owe
499
495
  * sections under a standard that states no provenance rule.
500
496
  */
501
497
  export function measureEntry(
@@ -652,11 +648,6 @@ export function matchesSiblings(folder: AuditedFolder): boolean {
652
648
  * The standard sanctions omitting `## Layout` from a domain owning no paths,
653
649
  * which no measure can tell from an entry that forgot it. An entry of that
654
650
  * shape therefore reports, which is a reason this is printed and never gated on.
655
- *
656
- * A wireframe folder answers per file whether nested or not, since its
657
- * standard keeps one surface per file. A subfolder of wireframes groups
658
- * surfaces the way the named context folder groups domains, so a conforming
659
- * sibling there says nothing about the surface beside it.
660
651
  */
661
652
  export function missingSections(
662
653
  root: string,
@@ -7,15 +7,13 @@ import { listChangedFiles, resolveBaseRef } from '@/git/files'
7
7
  import { surfaceDir } from '@/roots/surface'
8
8
 
9
9
  /**
10
- * The five canonical doc types the classifier reaches, matching the file
10
+ * The three canonical doc types the classifier reaches, matching the file
11
11
  * pattern the groundwork spike scoped its fixture to
12
12
  * (`scripts/hunks.py`'s `DOC_PATH`) and the file-type catalog both system
13
13
  * prompts state.
14
14
  */
15
15
  export const CANONICAL_DOC_TYPES = [
16
16
  'context',
17
- 'architecture',
18
- 'wireframes',
19
17
  'design',
20
18
  'requirements',
21
19
  ] as const
@@ -24,23 +22,19 @@ export type CanonicalDocType = (typeof CANONICAL_DOC_TYPES)[number]
24
22
 
25
23
  const DOC_PATTERNS: Record<CanonicalDocType, RegExp> = {
26
24
  context: /(^|\/)context\/.+\.md$/,
27
- architecture: /(^|\/)ARCHITECTURE\.md$/,
28
- wireframes: /(^|\/)wireframes\/.+\.md$/,
29
25
  design: /(^|\/)DESIGN\.md$/,
30
26
  requirements: /(^|\/)REQUIREMENTS\.md$/,
31
27
  }
32
28
 
33
29
  const INDEX_NAME = 'index.md'
34
30
 
35
- /** The two doc types `resolveFolders` discovers, paired with the folder name it takes. */
31
+ /** The doc type `resolveFolders` discovers, paired with the folder name it takes. */
36
32
  const MULTI_DOC_TYPES: readonly { type: CanonicalDocType; name: string }[] = [
37
33
  { type: 'context', name: 'context' },
38
- { type: 'wireframes', name: 'wireframes' },
39
34
  ]
40
35
 
41
- /** The three doc types that resolve to one file each, paired with `surfaceDir`'s entry name. */
36
+ /** The two doc types that resolve to one file each, paired with `surfaceDir`'s entry name. */
42
37
  const SINGLE_DOC_TYPES: readonly { type: CanonicalDocType; entry: string }[] = [
43
- { type: 'architecture', entry: 'ARCHITECTURE.md' },
44
38
  { type: 'design', entry: 'DESIGN.md' },
45
39
  { type: 'requirements', entry: 'REQUIREMENTS.md' },
46
40
  ]
@@ -388,11 +382,10 @@ function readSections(
388
382
  /**
389
383
  * Every sweep-mode section across the requested canonical doc types.
390
384
  *
391
- * `context` and `wireframes` resolve through `resolveFolders`, the same
385
+ * `context` resolves through `resolveFolders`, the same
392
386
  * folder discovery `canon context audit` uses, so a domain split into a
393
- * folder of its own is swept the same way it is audited. The three
394
- * single-file types resolve through `surfaceDir`, agreeing with
395
- * `architectureRel`'s own resolution.
387
+ * folder of its own is swept the same way it is audited. The two
388
+ * single-file types resolve through `surfaceDir`.
396
389
  */
397
390
  export async function extractSweepSections(
398
391
  root: string,
@@ -37,44 +37,17 @@ export interface PatternVerdict<V extends string> {
37
37
  const NARRATION =
38
38
  /moved (again|twice|on)|has since|at this branch|on `feat|Measured in PR|did not survive|the operator picked|picked arm|\barm \d|closed on|was retired|no longer|used to|\bround\b|a review pass|this pass/i
39
39
 
40
- /**
41
- * A source-file path inside prose, the shape of implementation detail landing
42
- * on a surface that should describe layout and intent instead. Ported
43
- * verbatim from `heuristic.py`.
44
- */
45
- const MECHANISM_IN_WIREFRAME = /`[\w./-]+\.(tsx?|py|css|spec\.ts)`/
46
-
47
40
  function narrationQuote(text: string): string | undefined {
48
41
  return text.match(NARRATION)?.[0]
49
42
  }
50
43
 
51
- /**
52
- * Classifies one diff-mode chunk from its added text alone.
53
- *
54
- * `file` decides whether the wireframe-only MOVE test applies. A file argument
55
- * rather than a boolean matches `run.ts`'s other call sites, which hold the
56
- * path and not a pre-computed flag.
57
- */
58
- export function diffPatternVerdict(
59
- file: string,
60
- added: string,
61
- ): PatternVerdict<DiffVerdict> {
44
+ /** Classifies one diff-mode chunk from its added text alone. */
45
+ export function diffPatternVerdict(added: string): PatternVerdict<DiffVerdict> {
62
46
  const quote = narrationQuote(added)
63
47
  if (quote !== undefined) {
64
48
  return { verdict: 'HISTORY', quote, reason: 'narrates how this got here' }
65
49
  }
66
50
 
67
- if (file.includes('wireframes/')) {
68
- const match = added.match(MECHANISM_IN_WIREFRAME)
69
- if (match) {
70
- return {
71
- verdict: 'MOVE',
72
- quote: match[0],
73
- reason: 'names a source file, which is implementation detail',
74
- }
75
- }
76
- }
77
-
78
51
  return { verdict: 'KEEP', reason: 'no narration or wrong-surface pattern' }
79
52
  }
80
53
 
@@ -87,7 +60,6 @@ export function diffPatternVerdict(
87
60
  * regex layer follows it.
88
61
  */
89
62
  export function sweepPatternVerdict(
90
- file: string,
91
63
  body: string,
92
64
  ): PatternVerdict<SweepVerdict> {
93
65
  const quote = narrationQuote(body)
@@ -99,16 +71,5 @@ export function sweepPatternVerdict(
99
71
  }
100
72
  }
101
73
 
102
- if (file.includes('wireframes/')) {
103
- const match = body.match(MECHANISM_IN_WIREFRAME)
104
- if (match) {
105
- return {
106
- verdict: 'MOVE',
107
- quote: match[0],
108
- reason: 'names a source file, which is implementation detail',
109
- }
110
- }
111
- }
112
-
113
74
  return { verdict: 'KEEP', reason: 'no narration or wrong-surface pattern' }
114
75
  }
@@ -13,15 +13,13 @@ export const DIFF_SYSTEM_PROMPT = `You review one hunk just added to a project's
13
13
 
14
14
  File types and what they hold:
15
15
  - context/<domain>.md: one domain's structure, decisions (choice + the alternative that lost), gotchas. No history of how the domain got here, no change numbers, branch names, or dates attached to a change.
16
- - ARCHITECTURE.md: cross-domain decisions only, each a few sentences: what was chosen, over what, why. A measurement or mechanism specific to one domain belongs in that domain's context entry. Loaded every session, so weight matters.
17
- - wireframes/<surface>.md: layout sketches, reachable states, exact on-screen copy, interaction intent. Would the line still be true if the surface were rebuilt in another framework? Component names, test files, pixel constants, and mechanism belong in context.
18
16
  - DESIGN.md: tokens and visual rules, current state only.
19
17
 
20
18
  Verdicts (pick exactly one):
21
19
  - KEEP: states current design, a rule, copy, a decision with its rejected alternative, or a live gotcha, on the right surface.
22
20
  - REPLACE: restates a fact or figure the existing section already carries ("moved again", "now", "the count moved", a newer number appended after an older one). The old statement should be rewritten in place, not appended to.
23
21
  - HISTORY: narrates how things got here: which branch/PR changed what, "closed on", "did not survive", review-pass stories, pick-by-pick rounds. The current state is what belongs; the trail goes to the PR.
24
- - MOVE: correct content on the wrong surface (domain mechanism in ARCHITECTURE.md, implementation detail in a wireframe).
22
+ - MOVE: correct content on the wrong surface (a rule written into a context entry, or a measured result written into the requirements record).
25
23
 
26
24
  Return only JSON: {"verdict": "...", "quote": "<the shortest added phrase that decided it>", "reason": "<one sentence>"}
27
25
 
@@ -35,15 +33,13 @@ export const SWEEP_SYSTEM_PROMPT = `You review one whole section of a project's
35
33
 
36
34
  File types and what they hold:
37
35
  - context/<domain>.md: one domain's structure, decisions (choice + the alternative that lost), gotchas. No history of how the domain got here, no change numbers, branch names, or dates attached to a change.
38
- - ARCHITECTURE.md: cross-domain decisions only, each a few sentences: what was chosen, over what, why. A measurement or mechanism specific to one domain belongs in that domain's context entry.
39
- - wireframes/<surface>.md: layout, reachable states, exact on-screen copy, interaction intent. Would the line still be true if the surface were rebuilt in another framework? Component names, test files, and pixel constants belong in context.
40
36
  - DESIGN.md: tokens and visual rules, current state only.
41
37
  - REQUIREMENTS.md: problem, goals, non-goals, scope, constraints. Never measured results.
42
38
 
43
39
  Verdicts (pick exactly one):
44
40
  - KEEP: the section states the current design, rules, copy, or decisions once, on the right surface. A single commit anchor on a figure is fine.
45
41
  - REWRITE: the section carries its own history: a figure followed by a later corrected figure, "superseded", "now", "moved", "no longer", "reverses the earlier reading", branch or PR narration, pick-by-pick rounds, a heading that narrates an event. The subject belongs here, but it must be restated as the current state.
46
- - MOVE: the section, or most of it, belongs on another surface (results in requirements, one domain's mechanism in architecture, implementation detail in a wireframe).
42
+ - MOVE: the section, or most of it, belongs on another surface (results in requirements).
47
43
 
48
44
  Decision checks, in order:
49
45
  1. Judge what the text says, not how long it is. A long section that states current design once is KEEP.
@@ -245,7 +245,7 @@ async function modelVerdictFor<V extends string>(opts: {
245
245
  * A finding's `verdict` takes the model's reading when the model ran and
246
246
  * parsed, and the regex reading otherwise, since the groundwork measurements
247
247
  * show the model catching what the regex layer structurally cannot
248
- * (REPLACE, and MOVE outside a wireframe). Both readings stay on the finding
248
+ * (REPLACE and MOVE). Both readings stay on the finding
249
249
  * regardless of which one decided, so a caller can see where they disagreed.
250
250
  */
251
251
  export async function classifyDiff(
@@ -263,7 +263,7 @@ export async function classifyDiff(
263
263
 
264
264
  const findings: DiffFinding[] = []
265
265
  for (const chunk of extraction.chunks) {
266
- const regex = withQuote(diffPatternVerdict(chunk.file, chunk.added))
266
+ const regex = withQuote(diffPatternVerdict(chunk.added))
267
267
  const model = await modelVerdictFor({
268
268
  plan,
269
269
  client,
@@ -312,7 +312,7 @@ export async function classifySweep(
312
312
 
313
313
  const findings: SweepFinding[] = []
314
314
  for (const section of extraction.sections) {
315
- const regex = withQuote(sweepPatternVerdict(section.file, section.body))
315
+ const regex = withQuote(sweepPatternVerdict(section.body))
316
316
  const model = await modelVerdictFor({
317
317
  plan,
318
318
  client,
@@ -17,19 +17,14 @@ import { SURFACE_ROOTS } from '@/roots/surface'
17
17
  * these names. A folder left off the list is never resolved, so a path into one
18
18
  * goes stale silently rather than failing a push.
19
19
  */
20
- export const DEFAULT_FOLDERS: readonly string[] = [
21
- 'context',
22
- 'diagrams',
23
- 'wireframes',
24
- ]
20
+ export const DEFAULT_FOLDERS: readonly string[] = ['context', 'diagrams']
25
21
 
26
22
  /**
27
23
  * The bases every folder in the default list is looked for under.
28
24
  *
29
25
  * `diagrams` is a session record and resolves under `RECORD_ROOTS`, while
30
- * `context` and `wireframes` are tracked and resolve under `SURFACE_ROOTS`, so
31
- * the split this comment used to describe as hypothetical is real: two
32
- * folders on this list read from two different root lists. The base array is
26
+ * `context` is tracked and resolves under `SURFACE_ROOTS`, so two folders on
27
+ * this list read from two different root lists. The base array is
33
28
  * their union rather than a per-name map, since a name resolving at the wrong
34
29
  * root costs one extra `existsSync` and nothing else, where a map states the
35
30
  * split a second time next to the one each resolver module already carries.
@@ -90,10 +85,10 @@ export interface AuditedFolder {
90
85
  * Names the requested record-root folders that actually exist, which is the
91
86
  * citation check's scope.
92
87
  *
93
- * A skill or seed pointing into `canon/wireframes/` is a live instruction for
88
+ * A skill or seed pointing into an optional folder is a live instruction for
94
89
  * a project that carries the folder and says nothing about one that does not.
95
- * Checking a path into an absent folder would fail eight shipped references
96
- * here for the sole reason that this repository has no wireframes.
90
+ * Checking a path into an absent folder would fail shipped references here for
91
+ * the sole reason that this repository does not carry it.
97
92
  *
98
93
  * A folder resolved at the project root is measured and stays out of this. The
99
94
  * pattern the citation check builds spells the `.claude/` prefix, so admitting
@@ -172,7 +167,7 @@ function locate(
172
167
  * beside `node_modules` and a build output.
173
168
  *
174
169
  * The project root is reached only when the caller opts in, so a target holding
175
- * a root `wireframes/` is not audited against a standard it never adopted by
170
+ * a root folder of its own name is not audited against a standard it never adopted by
176
171
  * the mere act of running the command. `.claude/` still wins a name carried by
177
172
  * both, and the scope line prints the resolved path so a caller reads which
178
173
  * base was taken rather than inferring it.
@@ -1,61 +1,19 @@
1
1
  import type { SectionFinding } from '@/context/audit'
2
2
  import type { FolderDrift } from '@/context/index-drift'
3
- import type { WireframeStatesReport } from '@/context/wireframe-states'
4
3
 
5
4
  export interface GateInput {
6
5
  /** Cited paths that resolved to nothing, which gate under either mode. */
7
6
  readonly unresolvedCitations: number
8
- /**
9
- * Whether the architecture record is longer than the ceiling it derives for
10
- * itself, which gates under either mode for the reason a citation does.
11
- *
12
- * False when the project carries no record and false under
13
- * `--citations-only`, which never measures it. That mode runs one check by
14
- * construction, so widening it here would gate on a reading it never took.
15
- */
16
- readonly recordOverLength: boolean
17
- /**
18
- * Whether the record holds more decisions than the cap it states, which
19
- * gates under the same two modes and is false in the same two cases.
20
- */
21
- readonly recordOverCount: boolean
22
- /**
23
- * Whether a decision lacks the revisit sentence the record requires of
24
- * every decision, which gates under the same two modes and is false in the
25
- * same two cases, plus a record stating no such clause.
26
- */
27
- readonly recordMissingRevisit: boolean
28
- /**
29
- * Whether a decision holds more words than the cap the record states, which
30
- * gates under the same two modes and is false in the same two cases, plus a
31
- * record stating no word cap.
32
- */
33
- readonly recordOverWords: boolean
34
- /** The same reading for the Risks section's bullet cap. */
35
- readonly recordOverRisks: boolean
36
7
  /**
37
8
  * Whether the requirements record holds more words than the cap it states,
38
- * which gates for the reason the architecture record's caps do.
9
+ * which gates under either mode for the reason a citation does. False when
10
+ * the project carries no record and false under `--citations-only`, which
11
+ * never measures it. That mode runs one check by construction, so widening
12
+ * it here would gate on a reading it never took.
39
13
  */
40
14
  readonly requirementsOverWords: boolean
41
15
  readonly sections: readonly SectionFinding[]
42
16
  readonly drift: readonly FolderDrift[]
43
- /**
44
- * Every wireframe entry's states report, empty for a project carrying no
45
- * `canon/wireframes/` folder. A states/evidence mismatch is a fact read off
46
- * the file, the same standing the missing-section and index-drift findings
47
- * already have, so it gates alongside them under the widened mode.
48
- *
49
- * A sketch beside existing evidence stays out of the gate on both modes.
50
- * `sketchWithEvidence` reads the whole entry against whether any of its
51
- * states has evidence, not the sketched layout against the evidence for
52
- * that same layout, since the standard's `## States` table names states
53
- * rather than layouts and the report has no narrower unit to match on. An
54
- * entry with a captured default layout and a sketch for a breakpoint layout
55
- * that is not built yet is conforming and still trips this reading, so the
56
- * finding stays a judgment for a reader rather than a fact a push fails on.
57
- */
58
- readonly wireframes: readonly WireframeStatesReport[]
59
17
  /**
60
18
  * Whether the caller asked for the widened gate. False leaves a missing
61
19
  * section and a drifted index advisory, which is what the project-root stage
@@ -71,65 +29,27 @@ export function hasDrift(drift: readonly FolderDrift[]): boolean {
71
29
  )
72
30
  }
73
31
 
74
- /** Whether any wireframe's States table disagrees with its evidence folders. */
75
- export function hasStatesMismatch(
76
- wireframes: readonly WireframeStatesReport[],
77
- ): boolean {
78
- return wireframes.some(
79
- (entry) =>
80
- entry.missingFolders.length > 0 || entry.unlistedFolders.length > 0,
81
- )
82
- }
83
-
84
- /** Whether any wireframe carries a sketch beside evidence that already exists. */
85
- export function hasSketchWithEvidence(
86
- wireframes: readonly WireframeStatesReport[],
87
- ): boolean {
88
- return wireframes.some((entry) => entry.sketchWithEvidence)
89
- }
90
-
91
32
  /**
92
33
  * Whether the audit found something that should fail the caller.
93
34
  *
94
35
  * An unresolved citation is a broken pointer and gates unconditionally, and so
95
- * does a record past its own ceiling, entry cap, word cap, or bullet cap, or
96
- * missing a revisit sentence it requires, and a requirements record past its
97
- * own word cap: each record states its rules for itself, which makes those the
98
- * measures here that are facts
99
- * rather than thresholds a reader weighs. The findings `--gate` adds are
36
+ * does a requirements record past its own word cap: the record states its rule
37
+ * for itself, which makes it a fact rather than a threshold a reader weighs. The findings `--gate` adds are
100
38
  * the ones answerable from the file itself: a required section it does not
101
- * declare, an index disagreeing with its folder, and a wireframe's States
102
- * table disagreeing with its evidence folders. Entry length, depth, bullet,
103
- * table, provenance, the record's claim coverage, and a sketch beside
104
- * existing evidence are judgments, so they stay out under both modes. The
105
- * `wireframes` field's own doc states why the sketch finding is a judgment
106
- * rather than a fact.
39
+ * declare, and an index disagreeing with its folder. Entry length, depth, bullet,
40
+ * table, provenance, and the record's claim coverage are judgments, so they
41
+ * stay out under both modes.
107
42
  */
108
43
  export function isGating({
109
44
  unresolvedCitations,
110
- recordOverLength,
111
- recordOverCount,
112
- recordMissingRevisit,
113
- recordOverWords,
114
- recordOverRisks,
115
45
  requirementsOverWords,
116
46
  sections,
117
47
  drift,
118
- wireframes,
119
48
  widened,
120
49
  }: GateInput): boolean {
121
50
  if (unresolvedCitations > 0) return true
122
- if (
123
- recordOverLength ||
124
- recordOverCount ||
125
- recordMissingRevisit ||
126
- recordOverWords ||
127
- recordOverRisks ||
128
- requirementsOverWords
129
- ) {
130
- return true
131
- }
51
+ if (requirementsOverWords) return true
132
52
  if (!widened) return false
133
53
 
134
- return sections.length > 0 || hasDrift(drift) || hasStatesMismatch(wireframes)
54
+ return sections.length > 0 || hasDrift(drift)
135
55
  }