@erclx/canon 5.48.0 → 5.50.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 (89) hide show
  1. package/claude/.claude-plugin/plugin.json +1 -1
  2. package/claude/skills/auto-ship/SKILL.md +1 -1
  3. package/claude/skills/canvas-board/REQUIREMENT.md +4 -3
  4. package/claude/skills/canvas-board/SKILL.md +8 -9
  5. package/claude/skills/context-fold/references/context.md +4 -3
  6. package/claude/skills/design-record/REQUIREMENT.md +33 -0
  7. package/claude/skills/design-record/SKILL.md +84 -0
  8. package/claude/skills/design-record/references/folder.md +69 -0
  9. package/claude/skills/design-taste/SKILL.md +1 -1
  10. package/claude/skills/markdown-craft/REQUIREMENT.md +1 -0
  11. package/claude/skills/markdown-craft/SKILL.md +6 -1
  12. package/claude/skills/markdown-craft/references/markdown.md +3 -3
  13. package/claude/skills/markdown-craft/references/tables.md +30 -0
  14. package/claude/skills/pick-by-eye/SKILL.md +10 -8
  15. package/claude/skills/plan-feature/SKILL.md +31 -16
  16. package/claude/skills/plan-feature/references/batches.md +5 -5
  17. package/claude/skills/plan-feature/references/plan.md +82 -33
  18. package/claude/skills/plan-groundwork/SKILL.md +8 -0
  19. package/claude/skills/plan-groundwork/references/groundwork.md +2 -1
  20. package/claude/skills/plan-intake/SKILL.md +8 -0
  21. package/claude/skills/plan-intake/references/intake.md +9 -1
  22. package/claude/skills/plan-ready/REQUIREMENT.md +3 -3
  23. package/claude/skills/plan-ready/SKILL.md +3 -3
  24. package/claude/skills/plan-ready/references/assembly.md +7 -7
  25. package/claude/skills/plan-ready/references/ready.md +8 -6
  26. package/claude/skills/review-ui/REQUIREMENT.md +1 -1
  27. package/claude/skills/review-ui/SKILL.md +4 -11
  28. package/claude/skills/review-ui/references/close-out.md +1 -1
  29. package/claude/skills/review-ui/references/drive-copy.md +38 -0
  30. package/claude/skills/review-ui/references/post.md +24 -3
  31. package/claude/skills/review-ui/references/verb-absent.md +18 -0
  32. package/claude/skills/role-orchestrator/SKILL.md +3 -2
  33. package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
  34. package/claude/skills/role-orchestrator/references/orchestrator-hand-launch.md +60 -0
  35. package/claude/skills/role-orchestrator/references/orchestrator-launch.md +5 -0
  36. package/claude/skills/role-orchestrator/references/orchestrator-parked.md +1 -1
  37. package/claude/skills/role-orchestrator/references/orchestrator-reviewer-launch.md +1 -1
  38. package/claude/skills/role-planner/SKILL.md +1 -1
  39. package/claude/skills/role-worker/SKILL.md +4 -2
  40. package/claude/skills/session-compact/references/handoff-note.md +3 -1
  41. package/claude/skills/session-map/references/session.md +1 -1
  42. package/claude/skills/session-worktree/SKILL.md +1 -1
  43. package/claude/skills/task-board/references/board.md +2 -2
  44. package/claude/skills/task-board/references/tasks.md +1 -1
  45. package/docs/agents/index.md +1 -1
  46. package/docs/agents/markdown-audit.md +5 -2
  47. package/docs/agents/records.md +1 -1
  48. package/docs/target/migrations.md +7 -0
  49. package/docs/target/projects.md +1 -1
  50. package/docs/workflow/parallel-features.md +2 -2
  51. package/docs/workflow/skill-map.md +2 -1
  52. package/docs/workflow/visual-design-workflow.md +2 -1
  53. package/governance/ledger/ui/design-reference.md +1 -0
  54. package/governance/rules/ui/design-reference.md +1 -0
  55. package/package.json +1 -1
  56. package/src/claude/cases/misc.ts +5 -0
  57. package/src/commands/claude.ts +26 -1
  58. package/src/commands/gate.ts +57 -16
  59. package/src/commands/markdown.ts +98 -19
  60. package/src/commands/pr.ts +411 -23
  61. package/src/commands/records.ts +45 -8
  62. package/src/commands/tasks.ts +12 -0
  63. package/src/context/audit.ts +6 -5
  64. package/src/design/budget.ts +1 -1
  65. package/src/design/components.ts +1 -1
  66. package/src/design/document.ts +1 -1
  67. package/src/design/regen.ts +1 -1
  68. package/src/design/render.ts +1 -1
  69. package/src/gate/hand-suite.ts +52 -0
  70. package/src/gate/measures.ts +9 -2
  71. package/src/gate/sequencer.ts +17 -8
  72. package/src/hooks/post-merge.ts +11 -0
  73. package/src/markdown/gated.ts +5 -7
  74. package/src/markdown/scope.ts +60 -10
  75. package/src/markdown/structure.ts +1 -1
  76. package/src/markdown/tables.ts +150 -0
  77. package/src/pr/drive-copy.ts +218 -0
  78. package/src/pr/local.ts +26 -0
  79. package/src/pr/rest.ts +2 -0
  80. package/src/records/structure.ts +147 -0
  81. package/src/records/validate.ts +113 -12
  82. package/src/tasks/archive.ts +137 -4
  83. package/src/tasks/board.ts +68 -13
  84. package/src/tasks/validate.ts +54 -14
  85. package/tooling/base/configs/.github/workflows/pr-local-preview.yml +1 -1
  86. package/tooling/claude/reference.md +1 -0
  87. package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +11 -1
  88. package/tooling/claude/seeds/CLAUDE.md +9 -0
  89. /package/claude/skills/{canvas-board → design-record}/references/design.md +0 -0
@@ -6,7 +6,7 @@ import { BAN_SETS, emptyBanSets } from '@/markdown/bans'
6
6
  import { isChangelog, lengthExemption } from '@/markdown/ceiling'
7
7
  import { type ColonFinding, findColons } from '@/markdown/colons'
8
8
  import { type MarkdownAuditRefusal, resolveMarkdown } from '@/markdown/files'
9
- import { densityFindings, type DensityKind } from '@/markdown/density'
9
+ import type { DensityKind } from '@/markdown/density'
10
10
  import {
11
11
  type GatedDensityFinding,
12
12
  type GatedReferenceShapeFinding,
@@ -38,7 +38,19 @@ import {
38
38
  readGatedConfig,
39
39
  resolveGatedList,
40
40
  } from '@/markdown/gated'
41
- import { densityGates, inDensityScope } from '@/markdown/scope'
41
+ import {
42
+ densityGates,
43
+ inDensityScope,
44
+ scopedDensityFindings,
45
+ } from '@/markdown/scope'
46
+ import {
47
+ TABLE_CELL,
48
+ TABLE_ROWS,
49
+ TABLE_TOKEN,
50
+ type TableFinding,
51
+ tableFindings,
52
+ type TableKind,
53
+ } from '@/markdown/tables'
42
54
  import {
43
55
  BASELINE,
44
56
  CHECKPOINTS,
@@ -86,6 +98,8 @@ interface FileReport {
86
98
  readonly headingCase: readonly HeadingCaseFinding[]
87
99
  /** Empty on a path outside the density scope, so a plan never carries one. */
88
100
  readonly density: readonly GatedDensityFinding[]
101
+ /** Empty outside the density scope, and never gating anywhere. */
102
+ readonly tables: readonly TableFinding[]
89
103
  /** Empty on a page whose frontmatter does not carry `kind: reference`. */
90
104
  readonly referenceShape: readonly GatedReferenceShapeFinding[]
91
105
  readonly structure: StructureReport
@@ -131,13 +145,20 @@ export function register(program: Command): void {
131
145
  'a row, a 200-character bullet, 5 plain bullets in a row, no H4, and a',
132
146
  'paragraph or table opening every H3. Only context, docs, skills, tooling',
133
147
  'seeds and references, the wiki, README.md, and CONTRIBUTING.md take a',
134
- 'finding. In a canon checkout one gates under a prefix in GATED_PATHS in',
135
- 'src/markdown/scope.ts, and a bullet run gates in context, docs, and',
136
- 'skills from the start. Elsewhere one gates only under a prefix',
137
- 'canon/config/markdown.toml lists, which canon markdown gated add writes,',
138
- 'and with no such file every density finding reports and none gates.',
148
+ 'finding. CLAUDE.md and its seed take only the bullet run and the H3',
149
+ 'opening, inside Key paths. In a canon checkout one gates under a',
150
+ 'prefix in GATED_PATHS in src/markdown/scope.ts, and a bullet run gates',
151
+ 'in context, docs, and skills from the start. Elsewhere one gates only',
152
+ 'under a prefix canon/config/markdown.toml lists, which canon markdown',
153
+ 'gated add writes, and with no such file every density finding reports',
154
+ 'and none gates.',
139
155
  'A config that does not parse refuses with its path named.',
140
156
  '',
157
+ 'Tables take four limits on the same paths, CLAUDE.md aside: a',
158
+ '120-character cell, 8 body rows, a list as the next block, and a code',
159
+ 'span with a run past 30 characters. A table finding reports and never',
160
+ 'fails a run.',
161
+ '',
141
162
  'A page whose frontmatter carries kind: reference takes the reference',
142
163
  'shape: no H2 beyond Output, Refusals, and See also, each at most once',
143
164
  'and in that order, no H3, and no table whose first header cell names',
@@ -361,17 +382,16 @@ async function runAudit(
361
382
  bans: scanBans(lines, bans),
362
383
  colons: advisory ? findColons(lines) : [],
363
384
  headingCase: advisory ? findHeadingCase(source) : [],
364
- density: inDensityScope(rel)
365
- ? densityFindings(lines).map((finding) => ({
366
- ...finding,
367
- gating: densityGates(
368
- rel,
369
- finding.kind,
370
- gated.prefixes,
371
- gated.alwaysGated,
372
- ),
373
- }))
374
- : [],
385
+ density: scopedDensityFindings(rel, lines).map((finding) => ({
386
+ ...finding,
387
+ gating: densityGates(
388
+ rel,
389
+ finding.kind,
390
+ gated.prefixes,
391
+ gated.alwaysGated,
392
+ ),
393
+ })),
394
+ tables: inDensityScope(rel) ? tableFindings(lines) : [],
375
395
  referenceShape: referenceShapeFindings(source).map((finding) => ({
376
396
  ...finding,
377
397
  gating: referenceShapeGates(rel, gated.prefixes),
@@ -393,6 +413,7 @@ async function runAudit(
393
413
  reportColons(reports)
394
414
  reportHeadingCase(reports)
395
415
  reportDensity(reports, gated, resolution.source)
416
+ reportTables(reports)
396
417
  reportReferenceShape(reports, gated)
397
418
  reportBullets(reports, checkpoints)
398
419
  reportParagraphs(reports, checkpoints)
@@ -430,6 +451,7 @@ async function runAudit(
430
451
  colons: report.colons,
431
452
  headingCase: report.headingCase,
432
453
  density: report.density,
454
+ tables: report.tables,
433
455
  referenceShape: report.referenceShape,
434
456
  longestRun: report.structure.longestRun,
435
457
  longestRunLine: report.structure.longestRunLine,
@@ -643,7 +665,7 @@ function reportDensity(
643
665
  `Paragraphs past ${CHECKPOINTS.paragraph} characters, more than 2 paragraphs in a row, bullets past ${CHECKPOINTS.bullet} characters, more than 5 plain bullets in a row, a heading past H3, and an H3 opening with neither a paragraph nor a table.`,
644
666
  )
645
667
  logInfo(
646
- 'Measured on context entries, docs, skill bodies, references, and requirements, tooling seeds and stack references, the wiki, README.md, and CONTRIBUTING.md. Every other path takes no density finding.',
668
+ 'Measured on context entries, docs, skill bodies, references, and requirements, tooling seeds and stack references, the wiki, README.md, and CONTRIBUTING.md. CLAUDE.md and its seed take the bullet run and the H3 opening inside Key paths alone. Every other path takes no density finding.',
647
669
  )
648
670
  logInfo(densityGatingLine(gated, source))
649
671
 
@@ -695,6 +717,63 @@ function densityGatingLine(
695
717
  : `A finding gates under a prefix ${GATED_CONFIG_REL} lists (${listed}). Every other finding reports.`
696
718
  }
697
719
 
720
+ const TABLE_LABELS: Record<TableKind, string> = {
721
+ 'table-cell': 'cell length',
722
+ 'table-rows': 'rows',
723
+ 'table-then-list': 'list after table',
724
+ 'table-token': 'wide token',
725
+ }
726
+
727
+ function describeTable(finding: TableFinding): string {
728
+ const measured =
729
+ finding.kind === 'table-then-list'
730
+ ? 'follows the table with no lead sentence'
731
+ : `${finding.value} past ${finding.limit}`
732
+ return ` :${finding.line} ${TABLE_LABELS[finding.kind]} ${measured}`
733
+ }
734
+
735
+ /**
736
+ * Lists every table finding on the density scope's paths. None gates yet,
737
+ * since a gate is decided per path rather than per kind, and a new density
738
+ * kind would fail every gated folder carrying a table hit at once.
739
+ */
740
+ function reportTables(reports: readonly FileReport[]): void {
741
+ logStep('Tables')
742
+ logInfo(
743
+ `Cells past ${TABLE_CELL} characters, tables past ${TABLE_ROWS} body rows, a list directly after a table, and a code span in a cell holding a run past ${TABLE_TOKEN} characters.`,
744
+ )
745
+ logInfo(
746
+ 'Measured on the paths density measures in full, so never on CLAUDE.md, outside fenced blocks. This never fails a run.',
747
+ )
748
+
749
+ const carrying = reports
750
+ .filter((report) => report.tables.length > 0)
751
+ .sort((a, b) => b.tables.length - a.tables.length)
752
+
753
+ if (carrying.length === 0) {
754
+ logInfo('No table finding.')
755
+ return
756
+ }
757
+
758
+ const total = carrying.reduce((sum, report) => sum + report.tables.length, 0)
759
+ logWarn(
760
+ `${plural(total, 'finding')} across ${plural(carrying.length, 'file')}`,
761
+ )
762
+ logInfo(
763
+ 'Move a long cell into a bullet under the lead, split a long table into groups each under a lead sentence, give a trailing list its own lead, and move a wide token out of the table.',
764
+ )
765
+ pipeOutput(
766
+ carrying
767
+ .map(
768
+ (report) =>
769
+ `${report.rel} ${plural(report.tables.length, 'finding')}\n${report.tables
770
+ .map(describeTable)
771
+ .join('\n')}`,
772
+ )
773
+ .join('\n'),
774
+ )
775
+ }
776
+
698
777
  const REFERENCE_SHAPE_LABELS: Record<ReferenceShapeKind, string> = {
699
778
  'extra-section': 'section outside the shape',
700
779
  'section-order': 'section out of order or repeated',