@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.
- package/README.md +1 -1
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/references/adopted.md +1 -1
- package/claude/skills/auto-ship/REQUIREMENT.md +4 -16
- package/claude/skills/auto-ship/SKILL.md +13 -58
- package/claude/skills/auto-ship/references/draft-mark.md +2 -2
- package/claude/skills/auto-ship/references/failure-recovery.md +1 -5
- package/claude/skills/auto-ship/references/tier-failures.md +1 -1
- package/claude/skills/auto-ship/references/ui-checklist.md +2 -2
- package/claude/skills/auto-ship/references/verb-absent.md +3 -27
- package/claude/skills/auto-ship/references/worktree-name.md +1 -1
- package/claude/skills/backlog-triage/REQUIREMENT.md +2 -2
- package/claude/skills/backlog-triage/SKILL.md +2 -2
- package/claude/skills/canon-cli/REQUIREMENT.md +19 -18
- package/claude/skills/canon-cli/SKILL.md +75 -32
- package/claude/skills/canon-feedback/REQUIREMENT.md +1 -1
- package/claude/skills/canon-feedback/SKILL.md +11 -14
- package/claude/skills/canon-feedback-triage/REQUIREMENT.md +13 -14
- package/claude/skills/canon-feedback-triage/SKILL.md +49 -30
- package/claude/skills/{canvas → canvas-board}/REQUIREMENT.md +5 -6
- package/claude/skills/{canvas → canvas-board}/SKILL.md +7 -7
- package/{standards → claude/skills/canvas-board/references}/canvas.md +12 -1
- package/{standards → claude/skills/canvas-board/references}/design.md +13 -5
- package/claude/skills/ci-workflow/REQUIREMENT.md +0 -1
- package/claude/skills/context-fold/REQUIREMENT.md +28 -48
- package/claude/skills/context-fold/SKILL.md +26 -95
- package/claude/skills/context-fold/references/classify.md +7 -8
- package/claude/skills/context-fold/references/completion-report.md +4 -8
- package/claude/skills/context-fold/references/context-refresh.md +7 -17
- package/{standards → claude/skills/context-fold/references}/context.md +19 -10
- package/claude/skills/context-fold/references/unusable-baseline.md +4 -8
- package/claude/skills/create-rule/REQUIREMENT.md +0 -1
- package/claude/skills/create-rule/SKILL.md +2 -2
- package/{standards → claude/skills/create-rule/references}/rule.md +12 -5
- package/claude/skills/create-skill/REQUIREMENT.md +6 -4
- package/claude/skills/create-skill/SKILL.md +10 -9
- package/{standards → claude/skills/create-skill/references}/skill-paths.md +1 -0
- package/{standards → claude/skills/create-skill/references}/skill.md +18 -15
- package/claude/skills/decision-escalate/REQUIREMENT.md +1 -1
- package/claude/skills/decision-escalate/SKILL.md +1 -1
- package/claude/skills/design-taste/REQUIREMENT.md +3 -5
- package/claude/skills/design-taste/SKILL.md +2 -4
- package/claude/skills/design-taste/references/vocabulary.md +1 -1
- package/claude/skills/docs-sync/REQUIREMENT.md +3 -3
- package/claude/skills/docs-sync/SKILL.md +3 -3
- package/{standards → claude/skills/docs-sync/references}/docs.md +11 -0
- package/{standards → claude/skills/docs-sync/references}/readme.md +9 -2
- package/claude/skills/document-health/REQUIREMENT.md +2 -2
- package/claude/skills/document-health/SKILL.md +4 -5
- package/claude/skills/document-health/references/axes.md +4 -6
- package/claude/skills/draft-and-pick/REQUIREMENT.md +16 -14
- package/claude/skills/draft-and-pick/SKILL.md +40 -32
- package/claude/skills/draft-and-pick/references/live-arms.md +9 -9
- package/claude/skills/draft-doc/REQUIREMENT.md +5 -5
- package/claude/skills/draft-doc/SKILL.md +9 -10
- package/claude/skills/draft-doc/references/requirements.md +61 -0
- package/claude/skills/draft-doc/references/wiki-kind.md +53 -0
- package/claude/skills/draft-doc/references/wiki.md +50 -30
- package/claude/skills/draft-figure/REQUIREMENT.md +2 -2
- package/claude/skills/draft-figure/SKILL.md +5 -5
- package/claude/skills/draft-figure/references/architecture-set.md +4 -4
- package/claude/skills/draft-figure/references/hand-drawn.md +2 -2
- package/claude/skills/draft-figure/references/mermaid-path.md +55 -0
- package/claude/skills/draft-figure/references/mermaid.md +43 -34
- package/claude/skills/draft-identity/REQUIREMENT.md +3 -3
- package/claude/skills/draft-identity/SKILL.md +10 -8
- package/claude/skills/draft-ready/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +7 -7
- package/claude/skills/draft-ready/references/assembly.md +1 -1
- package/{standards → claude/skills/draft-ready/references}/ready.md +13 -5
- package/claude/skills/git-branch/SKILL.md +1 -1
- package/{standards → claude/skills/git-branch/references}/branch.md +1 -1
- package/claude/skills/git-commit/SKILL.md +2 -2
- package/claude/skills/git-followup/REQUIREMENT.md +1 -1
- package/claude/skills/git-followup/SKILL.md +1 -1
- package/claude/skills/git-issue/SKILL.md +1 -1
- package/claude/skills/git-issue/references/issue.md +3 -3
- package/claude/skills/git-pr/SKILL.md +13 -13
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +38 -14
- package/claude/skills/git-pr/references/labels.md +5 -1
- package/{standards → claude/skills/git-pr/references}/pr.md +19 -9
- package/{standards → claude/skills/git-pr/references}/publish.md +5 -3
- package/claude/skills/git-pr/references/task-number.md +1 -1
- package/claude/skills/git-ship/REQUIREMENT.md +0 -2
- package/claude/skills/git-ship/SKILL.md +5 -12
- package/claude/skills/git-split/SKILL.md +3 -3
- package/claude/skills/git-stage/SKILL.md +1 -1
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
- package/claude/skills/plan-feature/SKILL.md +2 -6
- package/{standards → claude/skills/plan-feature/references}/plan.md +9 -10
- package/claude/skills/plan-groundwork/SKILL.md +5 -6
- package/{standards → claude/skills/plan-groundwork/references}/groundwork.md +17 -4
- package/claude/skills/plan-intake/SKILL.md +2 -3
- package/{standards → claude/skills/plan-intake/references}/intake.md +17 -2
- package/claude/skills/plan-intake-answer/REQUIREMENT.md +1 -1
- package/claude/skills/plan-intake-answer/SKILL.md +1 -1
- package/claude/skills/review-address/SKILL.md +2 -2
- package/claude/skills/review-address/references/post-review-findings.md +1 -1
- package/claude/skills/review-craft/REQUIREMENT.md +3 -3
- package/claude/skills/review-craft/SKILL.md +2 -2
- package/claude/skills/review-craft/references/ui.md +4 -4
- package/claude/skills/review-pr/REQUIREMENT.md +2 -2
- package/claude/skills/review-pr/SKILL.md +8 -10
- package/claude/skills/review-pr/references/body-variants.md +2 -2
- package/claude/skills/review-pr/references/key-changes.md +3 -3
- package/claude/skills/review-pr/references/post.md +4 -2
- package/claude/skills/review-ui/REQUIREMENT.md +1 -2
- package/claude/skills/review-ui/SKILL.md +2 -2
- package/claude/skills/review-ui/references/post.md +1 -1
- package/claude/skills/role-orchestrator/REQUIREMENT.md +3 -3
- package/claude/skills/role-orchestrator/SKILL.md +10 -10
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +3 -3
- package/claude/skills/role-orchestrator/references/orchestrator-handoff.md +9 -9
- package/claude/skills/role-orchestrator/references/orchestrator-launch.md +23 -1
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -5
- package/claude/skills/role-orchestrator/references/orchestrator-resume.md +4 -1
- package/claude/skills/role-planner/REQUIREMENT.md +2 -1
- package/claude/skills/role-planner/SKILL.md +15 -4
- package/claude/skills/role-reviewer/SKILL.md +2 -2
- package/claude/skills/role-worker/REQUIREMENT.md +1 -0
- package/claude/skills/role-worker/SKILL.md +11 -3
- package/claude/skills/session-compact/REQUIREMENT.md +1 -4
- package/claude/skills/session-compact/SKILL.md +3 -13
- package/claude/skills/session-compact/references/handoff-note.md +2 -2
- package/claude/skills/session-map/REQUIREMENT.md +1 -9
- package/claude/skills/session-map/SKILL.md +9 -17
- package/{standards → claude/skills/session-map/references}/session.md +17 -11
- package/claude/skills/session-relay/REQUIREMENT.md +1 -1
- package/claude/skills/session-resume/REQUIREMENT.md +6 -8
- package/claude/skills/session-resume/SKILL.md +3 -9
- package/claude/skills/session-worktree/SKILL.md +6 -6
- package/claude/skills/session-worktree/references/main-root-writes.md +2 -2
- package/claude/skills/systematic-debugging/REQUIREMENT.md +0 -1
- package/claude/skills/target-check/REQUIREMENT.md +3 -3
- package/claude/skills/target-check/SKILL.md +1 -1
- package/claude/skills/target-check/references/domains.md +1 -1
- package/claude/skills/target-setup/REQUIREMENT.md +4 -4
- package/claude/skills/target-setup/SKILL.md +3 -3
- package/claude/skills/target-setup/references/detect.md +2 -2
- package/claude/skills/task-board/REQUIREMENT.md +7 -12
- package/claude/skills/task-board/SKILL.md +9 -21
- package/{standards → claude/skills/task-board/references}/board.md +9 -0
- package/claude/skills/task-board/references/decline.md +1 -1
- package/{standards → claude/skills/task-board/references}/tasks.md +15 -10
- package/claude/skills/task-complete/REQUIREMENT.md +47 -0
- package/claude/skills/task-complete/SKILL.md +86 -0
- package/claude/skills/{task-board → task-complete}/references/archive.md +5 -5
- package/claude/skills/task-complete/references/receipt-sweep.md +32 -0
- package/claude/skills/task-complete/references/unusable-baseline.md +19 -0
- package/claude/skills/teach-workspace/REQUIREMENT.md +6 -2
- package/claude/skills/teach-workspace/SKILL.md +9 -5
- package/claude/skills/teach-workspace/references/lesson-craft.md +1 -1
- package/claude/skills/teach-workspace/references/promotion-fold.md +29 -0
- package/claude/skills/teach-workspace/references/promotion.md +3 -3
- package/claude/skills/teach-workspace/references/revisit.md +1 -1
- package/{standards → claude/skills/teach-workspace/references}/teach.md +17 -5
- package/claude/skills/ui-checklist/SKILL.md +1 -1
- package/claude/skills/ux-audit/REQUIREMENT.md +2 -2
- package/claude/skills/ux-audit/SKILL.md +3 -4
- package/claude/skills/ux-measure/SKILL.md +1 -1
- package/claude/skills/write-human/REQUIREMENT.md +0 -1
- package/claude/skills/write-human/SKILL.md +1 -1
- package/docs/agents/audits.md +1 -1
- package/docs/agents/canvas.md +1 -1
- package/docs/agents/commands.md +4 -8
- package/docs/agents/context-audit-checks.md +11 -25
- package/docs/agents/context-audit.md +7 -15
- package/docs/agents/context-classify.md +5 -5
- package/docs/agents/counts.md +5 -5
- package/docs/agents/drift-surfaces.md +2 -2
- package/docs/agents/index.md +5 -7
- package/docs/agents/indexes.md +1 -1
- package/docs/agents/install-and-sync.md +6 -11
- package/docs/agents/intake.md +1 -1
- package/docs/agents/key-changes.md +5 -5
- package/docs/agents/label-coverage.md +11 -0
- package/docs/agents/migrate.md +1 -1
- package/docs/agents/records-push.md +2 -2
- package/docs/agents/records-stale.md +13 -48
- package/docs/agents/records-validate.md +4 -8
- package/docs/agents/records.md +6 -28
- package/docs/agents/restated.md +1 -1
- package/docs/agents/rule-citations.md +2 -2
- package/docs/agents/sandbox.md +4 -4
- package/docs/agents/skills-audit.md +2 -2
- package/docs/agents/state-scoped-risk.md +2 -2
- package/docs/agents/superseded.md +2 -2
- package/docs/agents/tasks-plans.md +1 -1
- package/docs/agents/tasks-validate.md +1 -1
- package/docs/agents/tasks.md +3 -3
- package/docs/agents/teach.md +1 -1
- package/docs/agents/upstream.md +26 -2
- package/docs/target/migrations.md +32 -0
- package/docs/target/projects.md +5 -7
- package/docs/target/scenarios.md +2 -2
- package/docs/target/sync.md +4 -4
- package/docs/workflow/ai-workflow.md +7 -38
- package/docs/workflow/index.md +1 -1
- package/docs/workflow/operating-model.md +10 -10
- package/docs/workflow/parallel-features.md +12 -12
- package/docs/workflow/skill-map-on-request.md +21 -24
- package/docs/workflow/skill-map.md +23 -34
- package/docs/workflow/visual-design-workflow.md +13 -16
- package/governance/renames.toml +0 -30
- package/governance/rules/canon/605-worktrees.md +1 -1
- package/governance/rules/canon/context.md +13 -0
- package/governance/rules/{standards → canon}/plan.md +4 -5
- package/governance/rules/canon/tasks.md +18 -0
- package/governance/rules/claude/skill.md +17 -0
- package/governance/stacks/base.toml +2 -4
- package/package.json +4 -4
- package/scripts/core/install-check.sh +4 -4
- package/scripts/core/regen-web-previews.ts +1 -1
- package/scripts/lib/ui.sh +0 -159
- package/src/audits/catalog.ts +5 -98
- package/src/claude/cases/authoring.ts +0 -18
- package/src/claude/cases/misc.ts +1 -14
- package/src/claude/cases/setup.ts +7 -20
- package/src/claude/cases/workflow.ts +6 -34
- package/src/claude/seeds.ts +1 -7
- package/src/claude/skills-audit.ts +3 -3
- package/src/cli/help.ts +4 -5
- package/src/cli/ui.ts +2 -3
- package/src/cli.ts +0 -4
- package/src/commands/claude.ts +9 -15
- package/src/commands/context.ts +18 -280
- package/src/commands/feedback.ts +22 -91
- package/src/commands/gov.ts +2 -15
- package/src/commands/labels.ts +326 -7
- package/src/commands/migrate.ts +6 -1
- package/src/commands/pr.ts +1 -1
- package/src/commands/records.ts +17 -403
- package/src/commands/sandbox.ts +3 -6
- package/src/commands/sync.ts +5 -3
- package/src/commands/tasks.ts +3 -3
- package/src/commands/upstream.ts +135 -0
- package/src/context/audit.ts +10 -19
- package/src/context/classify/extract.ts +6 -13
- package/src/context/classify/patterns.ts +2 -41
- package/src/context/classify/prompts.ts +2 -6
- package/src/context/classify/run.ts +3 -3
- package/src/context/folders.ts +8 -13
- package/src/context/gate.ts +11 -91
- package/src/context/requirements.ts +13 -4
- package/src/counts/scan.ts +3 -3
- package/src/design/budget.ts +1 -1
- package/src/design/components.ts +3 -3
- package/src/design/document.ts +1 -1
- package/src/design/regen.ts +1 -1
- package/src/design/render.ts +1 -1
- package/src/feedback/body.ts +0 -12
- package/src/gate/measures.ts +7 -58
- package/src/gate/sequencer.ts +56 -1
- package/src/gate/stages.ts +1 -7
- package/src/gov/citations.ts +9 -3
- package/src/gov/install.ts +2 -3
- package/src/gov/restated.ts +3 -3
- package/src/gov/stacks.ts +1 -1
- package/src/hooks/post-merge.ts +1 -1
- package/src/labels/apply.ts +39 -0
- package/src/labels/format.ts +3 -3
- package/src/labels/phase.ts +3 -3
- package/src/labels/sections.ts +43 -0
- package/src/markdown/structure.ts +2 -2
- package/src/migrate/record-layout.ts +3 -3
- package/src/migrate/skill-names.ts +20 -1
- package/src/pr/paths.ts +4 -4
- package/src/records/backup.ts +16 -6
- package/src/records/ordinal.ts +1 -1
- package/src/records/prune.ts +2 -1
- package/src/records/stale-canonical.ts +33 -3
- package/src/records/validate.ts +2 -188
- package/src/roots/record.ts +1 -1
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/coverage.ts +2 -6
- package/src/sandbox/equivalence.ts +5 -44
- package/src/sandbox/expect.ts +4 -4
- package/src/sandbox/provision.ts +13 -36
- package/src/sandbox/scenario.ts +137 -55
- package/src/sandbox/tree.ts +2 -6
- package/src/shipped/references.ts +3 -3
- package/src/standards/read.ts +44 -0
- package/src/sync/git.ts +1 -1
- package/src/sync/seeds-report.ts +1 -1
- package/src/tasks/archive.ts +5 -5
- package/src/tasks/branch.ts +3 -3
- package/src/tasks/label.ts +1 -1
- package/src/tasks/reach.ts +2 -2
- package/src/tasks/record.ts +2 -2
- package/src/tasks/validate.ts +2 -2
- package/src/teach/workspace.ts +1 -1
- package/src/upstream/cursor.ts +1 -1
- package/src/upstream/due.ts +128 -0
- package/src/upstream/releases.ts +2 -1
- package/standards/index.md +0 -35
- package/standards/standard.md +1 -7
- package/tooling/base/reference.md +2 -2
- package/tooling/base/seeds/.github/pull_request_template.md +2 -2
- package/tooling/claude/reference.md +7 -21
- package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +9 -1
- package/tooling/claude/seeds/.claude/hooks/records-index.sh +8 -20
- package/tooling/claude/seeds/.claude/hooks/review-post-scan.sh +171 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +3 -3
- package/tooling/claude/seeds/.claude/settings.json +9 -0
- package/tooling/claude/seeds/CLAUDE.md +1 -3
- package/tooling/claude/seeds/canon/REQUIREMENTS.md +2 -9
- package/tooling/web/configs/e2e/screenshot.ts +0 -1
- package/claude/skills/auto-ship/references/review-findings.md +0 -20
- package/claude/skills/bash-cli-script/REQUIREMENT.md +0 -43
- package/claude/skills/bash-cli-script/SKILL.md +0 -53
- package/claude/skills/bash-cli-script/references/template.md +0 -19
- package/claude/skills/canon-operator/REQUIREMENT.md +0 -62
- package/claude/skills/canon-operator/SKILL.md +0 -113
- package/claude/skills/canon-rollout/REQUIREMENT.md +0 -59
- package/claude/skills/canon-rollout/SKILL.md +0 -140
- package/claude/skills/canon-rollout/references/failure-recovery.md +0 -20
- package/claude/skills/context-fold/references/anchor-sweep.md +0 -58
- package/claude/skills/context-fold/references/promoted-pages.md +0 -29
- package/claude/skills/context-fold/references/receipt-sweep.md +0 -43
- package/claude/skills/context-fold/references/wireframe-sweep.md +0 -45
- package/claude/skills/create-standard/REQUIREMENT.md +0 -33
- package/claude/skills/create-standard/SKILL.md +0 -31
- package/claude/skills/design-extract/REQUIREMENT.md +0 -42
- package/claude/skills/design-extract/SKILL.md +0 -108
- package/claude/skills/draft-and-pick/references/frame.html +0 -118
- package/claude/skills/draft-doc/references/wireframes.md +0 -48
- package/claude/skills/markdown-propose/REQUIREMENT.md +0 -47
- package/claude/skills/markdown-propose/SKILL.md +0 -122
- package/claude/skills/markdown-propose/references/format.md +0 -118
- package/claude/skills/memory-capture/REQUIREMENT.md +0 -50
- package/claude/skills/memory-capture/SKILL.md +0 -117
- package/claude/skills/memory-review/REQUIREMENT.md +0 -52
- package/claude/skills/memory-review/SKILL.md +0 -129
- package/claude/skills/memory-review/references/later-phases.md +0 -118
- package/claude/skills/memory-review/references/receipt-format.md +0 -64
- package/claude/skills/project-commands/REQUIREMENT.md +0 -42
- package/claude/skills/project-commands/SKILL.md +0 -87
- package/claude/skills/repo-metadata/REQUIREMENT.md +0 -37
- package/claude/skills/repo-metadata/SKILL.md +0 -54
- package/claude/skills/restate-plainly/REQUIREMENT.md +0 -41
- package/claude/skills/restate-plainly/SKILL.md +0 -41
- package/claude/skills/review-branch/REQUIREMENT.md +0 -40
- package/claude/skills/review-branch/SKILL.md +0 -137
- package/claude/skills/seed-sync/REQUIREMENT.md +0 -45
- package/claude/skills/seed-sync/SKILL.md +0 -158
- package/claude/skills/sketch-design/REQUIREMENT.md +0 -38
- package/claude/skills/sketch-design/SKILL.md +0 -94
- package/claude/skills/ux-walkthrough/REQUIREMENT.md +0 -56
- package/claude/skills/ux-walkthrough/SKILL.md +0 -53
- package/claude/skills/ux-walkthrough/references/builds.md +0 -15
- package/claude/skills/ux-walkthrough/references/candidate-pages.md +0 -11
- package/claude/skills/ux-walkthrough/references/measuring.md +0 -22
- package/claude/skills/ux-walkthrough/references/record.md +0 -36
- package/claude/skills/ux-walkthrough/references/relay.md +0 -25
- package/docs/agents/architecture-record.md +0 -36
- package/docs/agents/review-classification.md +0 -76
- package/governance/rules/canon/603-memory.md +0 -11
- package/governance/rules/lang/120-bash.md +0 -18
- package/governance/rules/standards/architecture.md +0 -13
- package/governance/rules/standards/context.md +0 -14
- package/governance/rules/standards/design.md +0 -12
- package/governance/rules/standards/groundwork.md +0 -13
- package/governance/rules/standards/intake.md +0 -12
- package/governance/rules/standards/memory.md +0 -12
- package/governance/rules/standards/readme.md +0 -12
- package/governance/rules/standards/ready.md +0 -13
- package/governance/rules/standards/requirements.md +0 -12
- package/governance/rules/standards/rule.md +0 -13
- package/governance/rules/standards/session.md +0 -13
- package/governance/rules/standards/skill.md +0 -21
- package/governance/rules/standards/standard.md +0 -13
- package/governance/rules/standards/tasks.md +0 -15
- package/governance/rules/standards/teach.md +0 -14
- package/governance/rules/standards/wiki.md +0 -13
- package/governance/rules/standards/wireframes.md +0 -13
- package/scripts/config.sh +0 -11
- package/scripts/lib/gov.sh +0 -14
- package/scripts/lib/sandbox-fixtures.sh +0 -191
- package/scripts/lib/sandbox-git.sh +0 -125
- package/scripts/lib/sandbox-path.sh +0 -50
- package/scripts/sandbox-hook.sh +0 -99
- package/src/autoship/classify.ts +0 -75
- package/src/autoship/paths.ts +0 -50
- package/src/commands/autoship.ts +0 -129
- package/src/commands/repo.ts +0 -393
- package/src/context/architecture.ts +0 -654
- package/src/context/wireframe-states.ts +0 -238
- package/src/gov/standard-rules.ts +0 -179
- package/src/records/migrate.ts +0 -78
- package/src/records/stale.ts +0 -243
- package/src/repo/metadata.ts +0 -206
- package/src/sandbox/hooks.ts +0 -128
- package/standards/architecture.md +0 -127
- package/standards/memory.md +0 -158
- package/standards/mermaid.md +0 -64
- package/standards/requirements.md +0 -79
- package/standards/wiki.md +0 -77
- package/standards/wireframes.md +0 -143
- package/tooling/claude/seeds/.claude/memory/index.md +0 -8
- package/tooling/claude/seeds/canon/ARCHITECTURE.md +0 -23
- package/tooling/claude/seeds/canon/wireframes/index.md +0 -8
- /package/{standards → claude/skills/create-skill/references}/skill-practice.md +0 -0
- /package/{standards → claude/skills/create-skill/references}/skill-requirement.md +0 -0
- /package/{standards → claude/skills/draft-figure/references}/figures.md +0 -0
- /package/{standards → claude/skills/git-branch/references}/slug.md +0 -0
- /package/{standards → claude/skills/git-commit/references}/commit.md +0 -0
- /package/{standards → claude/skills/git-commit/references}/versioning.md +0 -0
- /package/{standards → claude/skills/plan-feature/references}/plan-lifecycle.md +0 -0
- /package/{standards → claude/skills/plan-groundwork/references}/groundwork-spikes.md +0 -0
- /package/{standards → claude/skills/task-board/references}/tasks-decline.md +0 -0
- /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
|
|
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
|
|
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
|
|
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
|
|
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
|
package/src/records/backup.ts
CHANGED
|
@@ -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
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
|
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
|
|
package/src/records/ordinal.ts
CHANGED
|
@@ -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
|
-
* `
|
|
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
|
*/
|
package/src/records/prune.ts
CHANGED
|
@@ -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
|
|
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
|
|
10
|
-
const CANONICAL_DOCS = ['REQUIREMENTS.md'
|
|
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
|
package/src/records/validate.ts
CHANGED
|
@@ -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
|
|
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' | '
|
|
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(
|
package/src/roots/record.ts
CHANGED
|
@@ -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
|
|
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
|
*/
|
package/src/sandbox/census.ts
CHANGED
|
@@ -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.
|
|
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
|
*
|
package/src/sandbox/coverage.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
|
203
|
-
*
|
|
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
|
|
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
|
|
221
|
+
for (const { command, file } of scenarios) {
|
|
261
222
|
if (!matchesTarget(category, command, targets)) continue
|
|
262
223
|
|
|
263
|
-
const declared = readArms(file
|
|
224
|
+
const declared = readArms(file)
|
|
264
225
|
if (!declared.ok) {
|
|
265
226
|
errors.push(`${category}:${command} did not load: ${declared.error}`)
|
|
266
227
|
continue
|
package/src/sandbox/expect.ts
CHANGED
|
@@ -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
|
|
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
|
|
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. `
|
|
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
|