@erclx/canon 4.107.0 → 4.109.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 +15 -30
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/document-health/REQUIREMENT.md +46 -0
- package/claude/skills/document-health/SKILL.md +88 -0
- package/claude/skills/document-health/references/axes.md +78 -0
- package/claude/skills/git-ship/SKILL.md +1 -1
- package/claude/skills/review-address/SKILL.md +4 -3
- package/claude/skills/task-board/REQUIREMENT.md +1 -1
- package/claude/skills/task-board/SKILL.md +2 -2
- package/docs/agents/capture.md +3 -3
- package/docs/agents/commands.md +2 -2
- package/docs/agents/pr-reads.md +2 -0
- package/docs/agents/tasks.md +10 -8
- package/docs/workflow/ai-workflow.md +1 -0
- package/package.json +1 -1
- package/scripts/core/regen-hero.sh +2 -34
- package/src/claude/cases/workflow.ts +10 -0
- package/src/cli.ts +2 -161
- package/src/commands/pr.ts +29 -4
- package/src/commands/tasks.ts +22 -7
- package/src/help.ts +196 -0
- package/src/pr/checks.ts +29 -0
- package/src/tasks/label.ts +136 -29
- package/standards/readme.md +1 -0
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
3
|
<picture>
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/brand/mark-accent.svg">
|
|
5
|
+
<img src="assets/brand/mark-accent-light.svg" alt="canon" width="56" height="56">
|
|
6
6
|
</picture>
|
|
7
7
|
|
|
8
8
|
# canon
|
|
@@ -17,12 +17,7 @@ canon is a CLI and Claude Code plugin that stops your AI conventions drifting ap
|
|
|
17
17
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
<source media="(prefers-color-scheme: dark)" srcset="assets/evidence/arrival.png">
|
|
22
|
-
<img src="assets/evidence/arrival-light.png" alt="The first screen of the canon landing page, a project before and after one canon init, with the file counts each step lays down">
|
|
23
|
-
</picture>
|
|
24
|
-
|
|
25
|
-
The page is one real session the toolkit ran on itself, and every count on it is read from the repo when the page builds.
|
|
20
|
+
That page is one real session the toolkit ran on itself, and every count on it is read from this repository when the page builds.
|
|
26
21
|
|
|
27
22
|
## Why
|
|
28
23
|
|
|
@@ -46,8 +41,8 @@ claude plugin install canon@canon
|
|
|
46
41
|
```
|
|
47
42
|
|
|
48
43
|
<picture>
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/evidence/install.png">
|
|
45
|
+
<img src="assets/evidence/install-light.png" alt="Adding the canon marketplace and installing the plugin in Claude Code">
|
|
51
46
|
</picture>
|
|
52
47
|
|
|
53
48
|
The skills land as `/canon:<name>`. If your session was already open, run `/reload-plugins` to pick them up.
|
|
@@ -73,35 +68,21 @@ Each domain has a canonical source in this repo and a thin install or sync CLI o
|
|
|
73
68
|
| Tooling stacks | Golden configs, seeds, and a reference per framework | Laid down by `canon init`, reconciled by `canon tooling sync` |
|
|
74
69
|
| Design system | Ships a `DESIGN.md` token format, a skill that drafts one from an existing project or from scratch, and a render command | `canon design render` |
|
|
75
70
|
| Slides | A `SLIDES.md` source format with a layout catalog | `canon slides render` writes PowerPoint |
|
|
71
|
+
| Teach | Lessons, sources, and a glossary in one workspace, rendered to a small site | `canon teach` |
|
|
76
72
|
| Transcripts | A YouTube transcript with metadata frontmatter | `canon transcripts <url>` writes it into any repo |
|
|
77
73
|
| Sandbox | Scenario scaffolds that provision an isolated project state for verifying each domain flow | `canon sandbox` |
|
|
78
74
|
|
|
79
|
-
|
|
80
|
-
<source media="(prefers-color-scheme: dark)" srcset="assets/evidence/catalog.png">
|
|
81
|
-
<img src="assets/evidence/catalog-light.png" alt="The canon catalog as a ledger of five rows, with the count each ships and a few real names: skills, rules, standards, commands, and stacks">
|
|
82
|
-
</picture>
|
|
83
|
-
|
|
84
|
-
Every count in that image is read from the catalogs when it is built, so they're what the repo ships today. A tooling stack lands as real files under version control, because a config is something your build reads and your project owns. A standard stays here and is opened by name, so there is no copy in your repo to drift from this one. Governance is the third shape. A rule with a path glob loads only when a matching path is edited, and a rule with none loads every session. Run `canon gov list` to see the glob beside each rule.
|
|
85
|
-
|
|
86
|
-
Two of the outputs are documents you open rather than files you run. A `SLIDES.md` renders to a deck, and a learning workspace renders to a small site.
|
|
75
|
+
Those domains reach you in three shapes. A tooling stack lands as real files under version control, because a config is something your build reads and your project owns. A standard stays here and is opened by name, so there is no copy in your repo to drift from this one.
|
|
87
76
|
|
|
88
|
-
|
|
89
|
-
<source media="(prefers-color-scheme: dark)" srcset="examples/slides/evidence/showcase-dark-04.png">
|
|
90
|
-
<img src="examples/slides/evidence/showcase-light-04.png" alt="A slide from the showcase deck rendered by canon slides render, a bulleted list under a heading on a warm background">
|
|
91
|
-
</picture>
|
|
92
|
-
|
|
93
|
-
<picture>
|
|
94
|
-
<source media="(prefers-color-scheme: dark)" srcset="examples/teach/evidence/root-listing.png">
|
|
95
|
-
<img src="examples/teach/evidence/root-listing-light.png" alt="The learning workspace listing rendered by canon teach, three workspaces with their lesson and term counts, one still a stub">
|
|
96
|
-
</picture>
|
|
77
|
+
Governance is the third shape. A rule with a path glob loads only when a matching path is edited, and a rule with none loads every session. Run `canon gov list` to see the glob beside each rule.
|
|
97
78
|
|
|
98
79
|
## It runs on itself
|
|
99
80
|
|
|
100
81
|
The workflow this toolkit ships is the workflow that built it. Several Claude Code sessions run at once, each in its own git worktree on its own branch, and each opens its own pull request.
|
|
101
82
|
|
|
102
83
|
<picture>
|
|
103
|
-
|
|
104
|
-
|
|
84
|
+
<source media="(prefers-color-scheme: dark)" srcset="demos/agent-view.gif">
|
|
85
|
+
<img src="demos/agent-view-light.gif" alt="The canon landing page scrolling from the dispatch section to the branch graph, three workers and a planner on disjoint file sets with the pull request each opened">
|
|
105
86
|
</picture>
|
|
106
87
|
|
|
107
88
|
That recording is the landing page's own `dispatch` and `workers` sections, driven by `canon demo run` against a local build. The branch graph beside the pull request numbers is authored rather than read, because nothing on a build machine records which files four sessions held.
|
|
@@ -110,6 +91,8 @@ That recording is the landing page's own `dispatch` and `workers` sections, driv
|
|
|
110
91
|
|
|
111
92
|
Scaffolding your first project? Start with target projects, then the AI workflow loop. Everything else answers questions that arrive later.
|
|
112
93
|
|
|
94
|
+
Working with an agent rather than reading this yourself? It loads `CLAUDE.md` at your project root first, then whichever rules under `.claude/rules/` match the paths it edits. Run `canon docs agents` for the command catalog with flags, exit codes, and JSON shapes.
|
|
95
|
+
|
|
113
96
|
- [AI workflow](docs/workflow/ai-workflow.md): feature-development loop inside a toolkit-managed project
|
|
114
97
|
- [Operating model](docs/workflow/operating-model.md): orchestrator, planner, and worker roles for building across parallel sessions
|
|
115
98
|
- [Visual design workflow](docs/workflow/visual-design-workflow.md): tiered guide for design and wireframe authoring
|
|
@@ -165,7 +148,9 @@ git init
|
|
|
165
148
|
canon init
|
|
166
149
|
```
|
|
167
150
|
|
|
168
|
-
`canon init` installs base tooling configs, Claude seeds, and governance rules in one pass, and scaffolds a `.claude/wiki/` stub for your project's own reference pages. Governance defaults to the `base` stack, so a bare init lands the coding and doc-authoring rules in `.claude/rules/`. Each rule names the standard it answers to and reads it with `canon standards <name>`, so no corpus is copied into your project.
|
|
151
|
+
`canon init` installs base tooling configs, Claude seeds, and governance rules in one pass, and scaffolds a `.claude/wiki/` stub for your project's own reference pages. Governance defaults to the `base` stack, so a bare init lands the coding and doc-authoring rules in `.claude/rules/`. Each rule names the standard it answers to and reads it with `canon standards <name>`, so no corpus is copied into your project.
|
|
152
|
+
|
|
153
|
+
Pass `--stack <name>` for a framework stack, or `--skip governance` to leave rules out. A snippet resolves the same way, reached at its `@` reference through the plugin's live `claude/snippets` symlink rather than a copy. Run `canon tooling list --json` to see the catalog.
|
|
169
154
|
|
|
170
155
|
For the full journey from scaffold through adding a domain later to syncing upstream drift, see [target projects](docs/target-projects.md).
|
|
171
156
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: document-health
|
|
3
|
+
description: What the document health check is for, the gap it closes, and why it reports three axes rather than one number
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Document health requirement
|
|
7
|
+
|
|
8
|
+
## Gap
|
|
9
|
+
|
|
10
|
+
Without this skill, a project learns which documents are missing and never learns which have rotted. `target-check` reports per domain what a target holds against what the toolkit ships, and every one of its domains asks a structural question: does the file exist, does it hold the required sections, do the bytes match what shipped. A document that exists, holds every section, and describes a tree that moved six months ago passes every one of them.
|
|
11
|
+
|
|
12
|
+
The second half of the gap is the axes being read as one thing. Length, placement, and staleness answer to different evidence, and a run that reports them in one undifferentiated list hands the reader a judgment wearing the authority of a measurement. The operator's own complaint was staleness, which is the axis with nothing behind it, so the flattening runs in the direction that overstates the weakest finding.
|
|
13
|
+
|
|
14
|
+
The third is silence on an unread axis. Both measured verbs resolve their folders by surface root, so a project whose layout differs resolves nothing and the verb refuses. A run reading that refusal as an empty finding set reports a healthy corpus for documents nothing looked at.
|
|
15
|
+
|
|
16
|
+
## Must
|
|
17
|
+
|
|
18
|
+
- Report per document across three named axes, so a reader can tell which question a finding answers
|
|
19
|
+
- Read length and placement through the verb that already owns each measurement, rather than re-deriving either by hand
|
|
20
|
+
- Mark every finding with its evidence class, so a judgment is never read as a measurement
|
|
21
|
+
- Ship the staleness axis, and mark it as a reading rather than cutting it for lacking a verb
|
|
22
|
+
- Report a refusal, an absent key, and a missing subcommand as an unread axis, naming the cause
|
|
23
|
+
- Say which layer answered the classifier sweep, since its model layer being off narrows the read without refusing it
|
|
24
|
+
- Take every checkpoint from the record the verb returns rather than from a number written into the skill
|
|
25
|
+
- Run standalone, and stay callable from the structural check rather than reachable only through it
|
|
26
|
+
|
|
27
|
+
## Must not
|
|
28
|
+
|
|
29
|
+
- Repair a finding, write a file in the project, or open a pull request. A check that repaired as it read leaves the reader unable to tell a finding from a fix.
|
|
30
|
+
- Emit a verdict across the three axes, or a score across the documents. Two axes answer from verbs and one answers from a reading, so any roll-up is a figure that lies about the third.
|
|
31
|
+
- Report a finding against a file nobody hand-authors. A generated index, a gitignored file, and a copied reference each name a file an author cannot fix.
|
|
32
|
+
- Answer an axis by file inspection where a verb answers it. The verb is the surface under test and a hand-rolled read of the same files is not.
|
|
33
|
+
- Read a document's modification time as its staleness. A file untouched beside code untouched is current, and the timestamp answers a different question.
|
|
34
|
+
|
|
35
|
+
## Guards
|
|
36
|
+
|
|
37
|
+
- `canon` absent from the path: stop, since neither measured axis can be read
|
|
38
|
+
- No tracked markdown under the working root: stop, since there is no corpus to read
|
|
39
|
+
|
|
40
|
+
## Out of scope
|
|
41
|
+
|
|
42
|
+
- Whether a document exists or holds its required sections, which is the structural question `target-check` answers across six domains
|
|
43
|
+
- Conformance of changed markdown to the authoring standards declaring jurisdiction over its paths, which is `standards-audit`. That skill is diff-scoped and standard-declared, taking a changed file and reporting which stated rule it breaks with a line number. This one is corpus-scoped and reads rot in documents nobody changed, which is the case a diff-scoped audit never reaches. The two sit beside each other rather than one absorbing the other.
|
|
44
|
+
- Rewriting a stale claim once this run has named it, which is `markdown-propose`
|
|
45
|
+
- Running the toolkit's own checks as one gating set over its own corpus, which is `canon audits run`. That set gates a push and this reports to a reader.
|
|
46
|
+
- Repairing anything an axis names. Each routes to the command or skill that owns it.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: document-health
|
|
3
|
+
description: Reports which of a project's documents have rotted, one section per document, across length, placement, and staleness. Reads each axis through the verb that owns it and marks the evidence class each answer carries. Use when asked to "check document health", "which docs have gone stale", "audit the docs for rot", "are these documents still accurate", "which docs are too long", or after a target check reports the structural side. Do NOT use to repair a finding, which the owning command or skill does, and do NOT use to check whether a document exists or holds the right sections, which is `target-check`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Document health
|
|
7
|
+
|
|
8
|
+
Reports which documents have rotted rather than which are missing. `target-check` answers whether a project's documents exist and hold the right kind of content, and this answers whether the ones that exist still earn their place. It reports and never repairs, matching the structural check beside it.
|
|
9
|
+
|
|
10
|
+
Three axes carry the report. Two answer from a verb and the third answers from a reading, which it says rather than hiding. `${CLAUDE_SKILL_DIR}/references/axes.md` holds what each axis measures, the checkpoint it reads against, and where a finding routes. This body holds the order, the guards, and the report shape.
|
|
11
|
+
|
|
12
|
+
## Guards
|
|
13
|
+
|
|
14
|
+
- `canon` absent from the path: stop. `❌ canon is not on PATH, so neither measured axis can be read.`
|
|
15
|
+
- `git ls-files '*.md'` listing nothing: stop. `❌ No tracked markdown here, so there is no corpus to read.`
|
|
16
|
+
- Run every command under `CANON_NON_INTERACTIVE=1` and prompt at no point. A caller reaching this from a rollout wave has nobody present to answer.
|
|
17
|
+
- Branch on each record's own fields rather than on an exit status. An operator's shell profile may wrap `canon` in a function whose status comes from a trailing command, which reports every refusal as success.
|
|
18
|
+
- Repair nothing, write no file in the project, and open no pull request. Whoever read the report decides what to fix.
|
|
19
|
+
|
|
20
|
+
## Step 1: scope the corpus
|
|
21
|
+
|
|
22
|
+
Take the documents the project hand-authors, defaulting to every tracked markdown file the two measured verbs reach. Narrow to a path the caller named when one was given, and say which scope the run took.
|
|
23
|
+
|
|
24
|
+
Drop what nobody hand-authors before reporting a finding against it: a generated `index.md`, a file under a gitignored folder, and a bundled reference a generator copied out to its consumers. A finding against a copy names a file an author cannot fix, since the next regeneration overwrites it.
|
|
25
|
+
|
|
26
|
+
## Step 2: read the two measured axes
|
|
27
|
+
|
|
28
|
+
Run these from the project root, in parallel:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
CANON_NON_INTERACTIVE=1 canon markdown audit --json
|
|
32
|
+
CANON_NON_INTERACTIVE=1 canon context audit --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The first answers length, carrying the bullet, paragraph, and depth checkpoints and the per-file weights read against them. The second answers placement for the folders it resolves, carrying entry length, reference form, and index drift.
|
|
36
|
+
|
|
37
|
+
Then read which classifier would run, and deepen placement with the verdicts per section:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
CANON_NON_INTERACTIVE=1 canon context classifier show
|
|
41
|
+
CANON_NON_INTERACTIVE=1 canon context classify sweep --json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The first names the backend, the model, and the source that decided both. Report which layer answered, since a project with the model layer off reads from the regex layer alone and the sweep says nothing about which one it used.
|
|
45
|
+
|
|
46
|
+
Take the checkpoints from the record each verb returns rather than from a number written here. A checkpoint the CLI moves reaches this report with no edit, and a number held in this body goes stale on its own cadence.
|
|
47
|
+
|
|
48
|
+
### An unread axis is not a healthy one
|
|
49
|
+
|
|
50
|
+
A refusal, an absent key, and a subcommand the project's binary does not carry each leave an axis unread. Report it as unread against the documents it would have covered, name the read that could not be taken, and name the cause.
|
|
51
|
+
|
|
52
|
+
`canon context audit` refuses with `reason: "no-folders"` in a project whose folders resolve to nothing, which is the ordinary shape where the layout differs from the one the verb looks for. That refusal is the honest answer rather than a failure, and reading it as an empty finding set reports a healthy corpus for documents nothing looked at.
|
|
53
|
+
|
|
54
|
+
A narrower read is not an unread one. The sweep running on its regex layer alone still answered, so it is reported with the layer named rather than as an axis nothing reached.
|
|
55
|
+
|
|
56
|
+
## Step 3: read the staleness axis
|
|
57
|
+
|
|
58
|
+
No verb answers whether a document still describes the tree it was written about. Read each document against the surfaces it names and report where the two have parted, taking the file paths, commands, and counts it states as the claims to test.
|
|
59
|
+
|
|
60
|
+
Mark every staleness finding as a reading. It is this session's judgment rather than a measurement, and a report that sets it beside two verb-backed axes without marking it implies evidence the axis does not carry.
|
|
61
|
+
|
|
62
|
+
## Step 4: report per document
|
|
63
|
+
|
|
64
|
+
Give each document its three axes, and give each axis three things: the state, the evidence class, and the command or skill that repairs it. Naming the repair is not running it.
|
|
65
|
+
|
|
66
|
+
The three classes are what keep the axes apart:
|
|
67
|
+
|
|
68
|
+
- `measured`: a verb returned a number read against a stated checkpoint
|
|
69
|
+
- `classified`: a verb returned a verdict carrying its own confidence
|
|
70
|
+
- `read`: this session's judgment, backed by no verb
|
|
71
|
+
|
|
72
|
+
Emit no verdict across the three. Two answer from verbs and one answers from a reading, so a roll-up is a figure that lies about the third. Emit no score across the documents either, for the same reason one level up.
|
|
73
|
+
|
|
74
|
+
## Output
|
|
75
|
+
|
|
76
|
+
Lead with the table, then one detail block per document carrying a finding:
|
|
77
|
+
|
|
78
|
+
```markdown
|
|
79
|
+
Document health: `<scope>`, <n> documents read.
|
|
80
|
+
|
|
81
|
+
| Document | Length | Placement | Staleness |
|
|
82
|
+
| ---------------- | ------------------- | ------------------- | ---------------- |
|
|
83
|
+
| `path/to/doc.md` | ok / heavy / unread | ok / moved / unread | ok / stale / n/a |
|
|
84
|
+
|
|
85
|
+
Length and placement are measured. Staleness is a reading.
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Keep the evidence line under the table on every run. A table read without it flattens a judgment into a measurement, which is the one shape the three classes exist to prevent.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Document health axes
|
|
3
|
+
description: What each axis measures, the verb behind it, the evidence class it carries, and where a finding routes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Document health axes
|
|
7
|
+
|
|
8
|
+
One section per axis. Each states what it measures, the verb that answers it, the evidence class the answer carries, and the surface a finding routes to.
|
|
9
|
+
|
|
10
|
+
The skill body holds the order, the guards, and the report shape. This holds the detail a run dereferences once it has a finding to place.
|
|
11
|
+
|
|
12
|
+
## Length
|
|
13
|
+
|
|
14
|
+
**Measures:** whether a document, or a passage inside it, has grown past what a reader takes in one pass.
|
|
15
|
+
|
|
16
|
+
**Verb:** `canon markdown audit --json`.
|
|
17
|
+
|
|
18
|
+
**Evidence class:** `measured`.
|
|
19
|
+
|
|
20
|
+
The record carries the checkpoints it read against under `checkpoints` and the per-file weights under `entries`. Read both from the record rather than from a number stated here, since the CLI moves a checkpoint on its own cadence and a copy of one goes stale in place.
|
|
21
|
+
|
|
22
|
+
Four weights answer this axis, each naming a different shape of overgrowth:
|
|
23
|
+
|
|
24
|
+
- `heavyBullets`: a top-level bullet past the character checkpoint, which is a paragraph wearing a dash
|
|
25
|
+
- `heavyParagraphs`: a paragraph past the sentence or character checkpoint
|
|
26
|
+
- `longestRun`, against `longestRunLine`: unbroken rendered lines between headings, which is the depth checkpoint
|
|
27
|
+
- `cadence`, carrying `measured`, `flat`, and `repeating`: sentence-length spread and repeated openers
|
|
28
|
+
|
|
29
|
+
Weight is a judgment a reader settles rather than a defect, which the verb states for itself and which this axis carries forward. A finding here is an argument for a split or a trim rather than a rule broken.
|
|
30
|
+
|
|
31
|
+
**Routes to:** a split of the document, or a move of the overgrown passage to the surface that owns it. Where the project states what a given document may hold, that statement decides whether the passage belongs in it at all, and the finding routes there rather than to a trim.
|
|
32
|
+
|
|
33
|
+
**Caveat:** the cadence numbers are drawn from prose a person reads straight through. Terse reference prose sits below that range correctly, so a flat paragraph in a table-heavy or bullet-heavy file is not a finding.
|
|
34
|
+
|
|
35
|
+
## Placement
|
|
36
|
+
|
|
37
|
+
**Measures:** whether a document's content sits in the file that owns it, and whether the catalogs pointing at it still resolve.
|
|
38
|
+
|
|
39
|
+
**Verbs:** `canon context audit --json` for the structural half, `canon context classify sweep --json` for the per-section verdicts.
|
|
40
|
+
|
|
41
|
+
**Evidence class:** `measured` for the audit's findings, `classified` for the sweep's verdicts.
|
|
42
|
+
|
|
43
|
+
The audit answers required sections, entry length, citation resolution, reference form, catalog tables, provenance, and index drift. A citation resolving to nothing is a fact and gates. Entry length, reference form, table shape, and provenance are judgments under every flag.
|
|
44
|
+
|
|
45
|
+
The sweep classifies each section as keep, replace or rewrite, history, or move. A `move` verdict is the placement finding proper, naming content sitting in the wrong document. Each verdict carries its own confidence, which is why the class is `classified` rather than `measured`, and a low-confidence `move` is a prompt to look rather than an instruction to cut.
|
|
46
|
+
|
|
47
|
+
**Routes to:** the document the verdict names as the owner. Where the move crosses a tier rather than a file, the project's own content-ownership rules decide the destination.
|
|
48
|
+
|
|
49
|
+
**Caveat:** both verbs resolve their folders by surface root rather than by a path written into them, so a project whose layout differs from the one they look for resolves nothing. The audit says so, refusing with `reason: "no-folders"` and naming the folders it looked for. Report that refusal as an unread axis. The sweep degrades differently: with the model layer off it answers from its regex layer alone, which is a narrower read rather than a refusal, so say which layer answered.
|
|
50
|
+
|
|
51
|
+
## Staleness
|
|
52
|
+
|
|
53
|
+
**Measures:** whether a document still describes the tree it was written about.
|
|
54
|
+
|
|
55
|
+
**Verb:** none.
|
|
56
|
+
|
|
57
|
+
**Evidence class:** `read`.
|
|
58
|
+
|
|
59
|
+
This is the axis the operator names first and the one nothing measures. A document goes stale by the tree moving under it rather than by anything changing in the document, so no property of the file answers it and a timestamp answers a different question. A file untouched for a year beside code untouched for a year is current, and one edited yesterday against a refactor from this morning is stale.
|
|
60
|
+
|
|
61
|
+
Read each document against the surfaces it names. Four claim shapes are testable without leaving the project:
|
|
62
|
+
|
|
63
|
+
- A file or folder path the document states, against whether it resolves
|
|
64
|
+
- A command or verb the document names, against whether it exists and carries the flags shown
|
|
65
|
+
- A count the document states over a tree, against the tree
|
|
66
|
+
- A cross-reference to another document, against what that document now says
|
|
67
|
+
|
|
68
|
+
A claim resting on none of the four is unverifiable from here. Report it as unread rather than as passing, which is the same rule the measured axes take when a verb refuses.
|
|
69
|
+
|
|
70
|
+
**Routes to:** the skill that rewrites a stale claim against an answer, rather than a direct edit from here. A document health run reports and never repairs.
|
|
71
|
+
|
|
72
|
+
**Caveat:** a reading is the weakest evidence in the report and the most consequential finding in it, which is the tension this axis ships with. Marking the class is what keeps the two facts together in the reader's hands.
|
|
73
|
+
|
|
74
|
+
## Why the three stay apart
|
|
75
|
+
|
|
76
|
+
The axes are not equally actionable and a report flattening them implies they are. A length finding is a number against a checkpoint, a placement finding is a verdict carrying a confidence, and a staleness finding is a judgment with nothing behind it. Each is worth reporting and each is worth a different response, so the class travels beside the state on every row rather than being stated once in a preamble a reader skims.
|
|
77
|
+
|
|
78
|
+
Shipping staleness on weaker evidence than the other two is the trade taken deliberately. Cutting it would leave the report answering the two questions that were never the operator's complaint.
|
|
@@ -31,7 +31,7 @@ Run `git diff --cached --name-only 2>/dev/null` to check for staged files. If ou
|
|
|
31
31
|
6. Invoke `canon:git-stage` to group staged changes and commit by concern
|
|
32
32
|
7. Invoke `canon:git-branch` to rename branch to match conventional format
|
|
33
33
|
8. Invoke `canon:git-pr` to push branch and open pull request
|
|
34
|
-
9. After the PR opens, watch CI. Poll `canon pr checks <number> --json` until the record's `state` leaves `pending`, branching on
|
|
34
|
+
9. After the PR opens, watch CI. Poll `canon pr checks <number> --json` until the record's `state` leaves `pending` or the record carries `conflicted: true`, branching on those fields rather than on the exit, and fall back to `gh pr checks <number>` when no record comes back at all, which is a target whose CLI predates the verb. On `passing`, continue. On `failing`, stop the sequence and report the failing check with its URL. On `conflicted`, stop the sequence and report that the branch conflicts with its base, since no run will start for it and polling on never ends. A rebase is the repair. Do not auto-fix. This step may output on failure, the one exception to the no-text-between-steps rule.
|
|
35
35
|
|
|
36
36
|
A caller wrapping this sequence may act between step 8 and step 9, which is the one gap the order leaves open, since the pull request exists there and nothing has read its checks yet. `auto-ship` marks the pull request draft in it. Nothing else may go there, and a caller that needs a step anywhere else in the sequence is asking for a change to this body rather than for a place to stand.
|
|
37
37
|
|
|
@@ -30,7 +30,7 @@ Also read the CI check status so the fixes cover failing checks, not only review
|
|
|
30
30
|
canon pr checks <number> --json
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
Read the verdict off the record's `state` rather than off the exit. Treat `failing` as a finding to resolve alongside the review comments. A `pending` covers a tip whose runs have yet to conclude and a tip carrying no run at all, which the record separates on `matched`, and neither is a green to continue on. Fall back to `gh pr checks <number>` when no record comes back at all, which is a target whose CLI predates the verb.
|
|
33
|
+
Read the verdict off the record's `state` rather than off the exit. Treat `failing` as a finding to resolve alongside the review comments. A `pending` covers a tip whose runs have yet to conclude and a tip carrying no run at all, which the record separates on `matched`, and neither is a green to continue on. A record carrying `conflicted: true` is a third case: the branch conflicts with its base, so no run will start and the wait never ends. Stop and report it, since a rebase is the repair. Fall back to `gh pr checks <number>` when no record comes back at all, which is a target whose CLI predates the verb.
|
|
34
34
|
|
|
35
35
|
## Step 2: address each finding
|
|
36
36
|
|
|
@@ -170,8 +170,9 @@ echo "${comment_url##*issuecomment-}" > .canon/tmp/pr/reply/reply-<number>.id
|
|
|
170
170
|
## Step 7: confirm resolution
|
|
171
171
|
|
|
172
172
|
After the follow-up push, watch CI on the PR. Poll
|
|
173
|
-
`canon pr checks <number> --json` until the record's `state` leaves `pending
|
|
174
|
-
|
|
173
|
+
`canon pr checks <number> --json` until the record's `state` leaves `pending`
|
|
174
|
+
or it carries `conflicted: true`, then read it. On `conflicted`, stop and report
|
|
175
|
+
that a rebase is the repair rather than polling on. When every finding is addressed and the state is `passing`, append
|
|
175
176
|
the closing confirmation to the reply file Step 6 already posted, so the thread
|
|
176
177
|
carries one terminal state rather than a second comment under no heading:
|
|
177
178
|
|
|
@@ -18,7 +18,7 @@ Placing a row without checking for another writer collides the same way. Two ses
|
|
|
18
18
|
- Resolve the board at the main worktree root, since a linked worktree writing to `pwd` creates a second board nothing reads
|
|
19
19
|
- Read the tasks standard before writing, rather than working the filename and frontmatter from memory
|
|
20
20
|
- Require an origin at creation, because that is the only moment the invariant is enforceable
|
|
21
|
-
-
|
|
21
|
+
- Claim the phase label with `canon tasks next-label --claim` rather than reading or proposing one by hand
|
|
22
22
|
- Check the roster for a live orchestrator before writing a row, and hand off rather than write when one is found
|
|
23
23
|
- Confirm the work reached the default branch before archiving
|
|
24
24
|
- Run the archive command and route on the reason it refuses, since each reason has one resolution
|
|
@@ -29,13 +29,13 @@ Accept work whose origin is the conversation itself only when the user says so e
|
|
|
29
29
|
|
|
30
30
|
### Step 2: allocate the phase label
|
|
31
31
|
|
|
32
|
-
Run `canon tasks next-label --json` and take its `label` field. The verb reads the live board and its `archive/` sibling together, so the label it returns accounts for what the board alone no longer shows.
|
|
32
|
+
Run `canon tasks next-label --claim --json` and take its `label` field. The verb reads the live board and its `archive/` sibling together, so the label it returns accounts for what the board alone no longer shows, and `--claim` reserves it under `.canon/ordinal-locks/` so a second session filing at the same moment gets the next one. Branch on the record's `reason` rather than the exit: `label-contended` means re-run the claim, and a usage error from an unknown `--claim` means the installed binary predates the flag, so report the verb as unavailable rather than falling back to a bare read, which reopens the race.
|
|
33
33
|
|
|
34
34
|
Do not derive the label from a version file. `${CLAUDE_SKILL_DIR}/../../standards/versioning.md` permits free renumbering, so the verb's two folders are the only surface that knows what a label currently means.
|
|
35
35
|
|
|
36
36
|
### Step 3: write the file
|
|
37
37
|
|
|
38
|
-
Write `.canon/tasks/vXX.Y-<slug>.md` following the format in `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. Include a link line only when the file or folder it names exists. A link to a plan nobody has written yet is the broken pointer the archive rules exist to prevent.
|
|
38
|
+
Write `.canon/tasks/vXX.Y-<slug>.md` under the claimed label, reading the file first if a session ever stubbed it, following the format in `${CLAUDE_SKILL_DIR}/../../standards/tasks.md`. Include a link line only when the file or folder it names exists. A link to a plan nobody has written yet is the broken pointer the archive rules exist to prevent.
|
|
39
39
|
|
|
40
40
|
Write `Plan:`, `Groundwork:`, and `Intake:` as markdown links relative to `.canon/tasks/`, as in `Plan: [feature-<slug>](../plans/feature-<slug>.md)`. Leave `Issue:` a bare `#NNN`. A task written in the older bare-path form still parses, so it costs the board a clickable line rather than an archive, but it leaves the board in two shapes for every reader after.
|
|
41
41
|
|
package/docs/agents/capture.md
CHANGED
|
@@ -18,11 +18,11 @@ canon capture https://example.com --selector .window --out preview.png
|
|
|
18
18
|
|
|
19
19
|
## What this repository captures
|
|
20
20
|
|
|
21
|
-
A capture set here spans two folders. `assets/captures/` holds
|
|
21
|
+
A capture set here spans two folders. `assets/captures/` holds three sources and the two templates they are written from, and `assets/evidence/` holds their images and the built-page capture a document points at with the stamp answering for each, under the segment `canon pr evidence` compares. One run over the source folder rebuilds every image, and it takes `--out assets/evidence` to put each PNG where its document points rather than beside the markup it rendered. None of the sources is edited by hand. `scripts/core/regen-hero.sh` writes each `.html` from the template beside it, filling one shared value map into all of them. A branch commits none of them for a moved count or token, since the refresh workflow regenerates them from `main` and opens one pull request, and `bun run check` runs the script with `--check`, which fills every template into a temp folder and fails when the regeneration cannot run.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
The `hero` template takes catalog data, so a stack gaining a rule moves the frame on the next run. `install.html` is the exception, since it holds terminal text from a real run in its template rather than derived from a live catalog at build time. `assets/evidence/arrival.png` is the one image with no source here: it is the built page's `.fold` element captured in dark mode against a local `web/` preview, since `canon capture` takes no color scheme and the page follows the browser's default of light, so it is retaken by hand when the page's first screen changes.
|
|
24
24
|
|
|
25
|
-
The README shows each still in two themes through `<picture>`, so a frame is a pair named `<name>` and `<name>-light`. `
|
|
25
|
+
The README shows each still in two themes through `<picture>`, so a frame is a pair named `<name>` and `<name>-light`. `install` takes the light half from its template, which `regen-hero.sh` fills a second time with the plain color roles pointed at the light ones, and each half is its own capture set with its own stamp. `arrival-light.png` is the same `.fold` capture of the same address taken without forcing dark, so it is retaken by hand alongside `arrival.png`, and nothing catches one drifting from the other.
|
|
26
26
|
|
|
27
27
|
A stamp for a URL source digests the address string rather than the page it served, so two themes of one address carry one `source-sha256` and only `image-sha256` tells the frames apart. That holds for `examples/teach/evidence/root-listing-light.png`, which is retaken by serving a copy of the fixture with `data-theme="light"` on its `<html>` element at the same address, since the page follows the dark default and the command takes no scheme.
|
|
28
28
|
|
package/docs/agents/commands.md
CHANGED
|
@@ -5,7 +5,7 @@ description: Every project-level command and every domain subcommand, plus the s
|
|
|
5
5
|
|
|
6
6
|
# Command catalog
|
|
7
7
|
|
|
8
|
-
Full help: `canon <command> --help`. Bare `canon --help` lists every top-level command under five headings, Project, Domains, Author and render, Session and ship, and Repo reports, with descriptions cut at 80 columns. Behavior notes for the install and sync verbs live in `install-and-sync.md`.
|
|
8
|
+
Full help: `canon <command> --help`. Bare `canon --help` lists every top-level command under five headings, Project, Domains, Author and render, Session and ship, and Repo reports, with descriptions cut at 80 columns. Piped into another command, the block prints without its frame glyphs and carries the same text. Behavior notes for the install and sync verbs live in `install-and-sync.md`.
|
|
9
9
|
|
|
10
10
|
## Project-level
|
|
11
11
|
|
|
@@ -92,7 +92,7 @@ Full help: `canon <command> --help`. Bare `canon --help` lists every top-level c
|
|
|
92
92
|
| `canon autoship classify` | Decide whether a changed set needs the review pass, naming the file and the test that decided it (`--json`) |
|
|
93
93
|
| `canon pr key-changes` | Compare the files a pull request body's Key Changes names against its own diff, in both directions (`--body`, `--base`, `--json`) |
|
|
94
94
|
| `canon pr head` | Compare the head a pull request object reports against the branch tip the remote carries, naming both shas (`--root`, `--json`) |
|
|
95
|
-
| `canon pr checks` | Report the check runs belonging to the branch tip, reading pending for a tip carrying none rather than clean (`--root`, `--json`)
|
|
95
|
+
| `canon pr checks` | Report the check runs belonging to the branch tip, reading pending for a tip carrying none rather than clean, and `conflicted` when the branch conflicts with its base (`--root`, `--json`) |
|
|
96
96
|
| `canon pr review-state` | Report the commit and instant the last review pass covered, off the pass's own marker rather than the fields GitHub stamps at submission (`--root`, `--json`) |
|
|
97
97
|
| `canon pr evidence` | Render a before-and-after comment comparing changed `evidence/` images against the merge base, editing its own prior comment in place rather than posting a second (`--root`, `--json`, `--preview`) |
|
|
98
98
|
| `canon pr preview` | Dispatch the Pages deploy on a pull request's branch and report the preview address the run prints, refusing a deploy that passes no `--branch` (`--root`, `--json`, `--timeout`) |
|
package/docs/agents/pr-reads.md
CHANGED
|
@@ -74,6 +74,8 @@ Both empty cases report `pending` instead: a tip carrying no run yet, and a list
|
|
|
74
74
|
|
|
75
75
|
The verb keeps the newest run per check name rather than rolling every matched run into the state. A workflow that fires twice on one commit used to leave its first, stale run beside the rerun, where a failing one could outvote a passing rerun. Grouping the matched set by name and keeping the highest `id` per group removes that stale run before the rollup runs. `collapsed` on the record counts what the fold discards, so a caller reading it against `matched` sees the dedupe directly, instead of reading a `matched` above the check count as the verb disagreeing with `gh pr checks`.
|
|
76
76
|
|
|
77
|
+
A conflicted branch produces no `pull_request` check runs rather than a failing one. GitHub builds no merge ref for it, so no `pull_request` workflow starts and a repository running only that trigger leaves the listing empty, which reads as `pending` and never leaves it. A workflow triggered by a push to the branch still runs on the tip, so `matched` rises above zero, `conflicted` stays false, and the wait ends on those runs rather than on the reading. `mergeStateStatus` is the field that separates the two, and the record carries `conflicted: true` and `mergeState` when it reads `DIRTY` with no run belonging to the tip. A `DIRTY` reading beside runs on the tip leaves the state as those runs say, since a conflict arising after they completed does not unsay them. `UNKNOWN` is transient while GitHub computes the merge state, right after a push, so it reads as not conflicted and costs one more poll. A binary predating the field keeps answering `pending`.
|
|
78
|
+
|
|
77
79
|
A listing carrying even one foreign run reports `pending` whatever the matching half says. A set that describes another commit says nothing about this one, so answering off the rows that happen to match would put a verdict on a set already known to be incomplete.
|
|
78
80
|
|
|
79
81
|
A count above the rows returned reports `pending` for the same reason. The query asks for 100 rows against the endpoint's default of 30, and a commit carrying more than that comes back short, so the verb reports the tip as unread rather than collapsing the page it happens to hold. `reported` against `matched` and `foreign` is where a reader sees which of the three shapes produced the answer.
|
package/docs/agents/tasks.md
CHANGED
|
@@ -7,25 +7,27 @@ description: Selecting a shipped task by stem or pull request, recording a numbe
|
|
|
7
7
|
|
|
8
8
|
## Next label
|
|
9
9
|
|
|
10
|
-
`canon tasks next-label` reports the next unused phase label, reading `.canon/tasks/` and its `archive/` sibling together. A scan confined to the live board is blind to every label the archive already spent, which is what let two sessions hand out the same label within minutes of each other.
|
|
10
|
+
`canon tasks next-label` reports the next unused phase label, reading `.canon/tasks/` and its `archive/` sibling together. A scan confined to the live board is blind to every label the archive already spent, which is what let two sessions hand out the same label within minutes of each other. Bare, it reports and never writes. With `--claim` it reserves the label first.
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
13
|
canon tasks next-label
|
|
14
14
|
canon tasks next-label --json
|
|
15
|
+
canon tasks next-label --claim --json
|
|
15
16
|
```
|
|
16
17
|
|
|
17
|
-
| Option | Effect
|
|
18
|
-
| --------------- |
|
|
19
|
-
| `--json` | Emit a machine-readable record on stdout
|
|
20
|
-
| `--
|
|
18
|
+
| Option | Effect |
|
|
19
|
+
| --------------- | ------------------------------------------------ |
|
|
20
|
+
| `--json` | Emit a machine-readable record on stdout |
|
|
21
|
+
| `--claim` | Reserve the label so a second claim gets another |
|
|
22
|
+
| `--root <path>` | Board root, defaulting to the main worktree |
|
|
21
23
|
|
|
22
|
-
The record carries `label`, the next free `vXX.Y`, and `highest`, the label it was derived from. `highest` is absent when neither folder carries a label yet, and `label` reads `v01.0` in that case, matching the zero-padded-major shape every other label already takes. <!-- canon-allow-reference: illustrates the verb's answer for a board holding no label yet, not a citation of a real task -->
|
|
24
|
+
The record carries `label`, the next free `vXX.Y`, `claimed`, whether the label was reserved, and `highest`, the label it was derived from. `highest` is absent when neither folder carries a label yet, and `label` reads `v01.0` in that case, matching the zero-padded-major shape every other label already takes. <!-- canon-allow-reference: illustrates the verb's answer for a board holding no label yet, not a citation of a real task -->
|
|
23
25
|
|
|
24
|
-
Exit codes: `0` derived, `1` refused with `no-board
|
|
26
|
+
Exit codes: `0` derived, `1` refused with `no-board`, `2` refused with `label-contended` after five lost reservations, on `--claim` only.
|
|
25
27
|
|
|
26
28
|
The minor digit rolls from 9 to 0 on the next major rather than growing a second digit, which is the single-digit-minor shape every phase label already takes. `canon tasks archive` moves a task's file from the live folder into the archive without renumbering it, so the same label counts toward the maximum wherever it currently sits, and a label claimed by two different files folds into the same scan without a dedicated check.
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
A claim is an exclusive `mkdir` at `.canon/ordinal-locks/<label>`, and the scan counts every reservation beside the task files, since the file lands after the verb returns. Reservations never expire, so a claim that died leaves a gap, which `standards/versioning.md` permits. A bare read still reports without reserving, and it does not count reservations either, so it can return a label a claim already holds until that claim's task file lands. Two bare reads in the same second can also take the same answer.
|
|
29
31
|
|
|
30
32
|
```bash
|
|
31
33
|
canon tasks next-label --json | jq -r '.label'
|
|
@@ -240,6 +240,7 @@ This section is the corpus the coverage claim is measured against: every name `c
|
|
|
240
240
|
| ------------------------ | --------------------------------------------------------------------------------------- |
|
|
241
241
|
| `canon:review-branch` | On the local branch diff, before anything is pushed |
|
|
242
242
|
| `canon:standards-audit` | When changed markdown has to answer to the authoring standards |
|
|
243
|
+
| `canon:document-health` | When the documents themselves have to answer for length, placement, and staleness |
|
|
243
244
|
| `canon:markdown-propose` | When a markdown claim needs rewriting and the change should wait for an answer per file |
|
|
244
245
|
| `canon:ux-audit` | To read UI source for missing states, edge cases, and inconsistencies |
|
|
245
246
|
| `canon:ux-measure` | To start the interface and measure paint, processor, and layout cost |
|
package/package.json
CHANGED
|
@@ -96,11 +96,8 @@ GOV_JSON="$(catalog gov list)"
|
|
|
96
96
|
STANDARDS_JSON="$(catalog standards list)"
|
|
97
97
|
SNIPPETS_JSON="$(catalog snippets list)"
|
|
98
98
|
TOOLING_JSON="$(catalog tooling list)"
|
|
99
|
-
# The catalog ledger names three commands, and the registered set is only
|
|
100
|
-
# readable from the root help, which lists one per line under `Commands:`.
|
|
101
|
-
COMMANDS_HELP="$(cd "$PROJECT_ROOT" && CANON_NON_INTERACTIVE=1 bun src/cli.ts --help 2>/dev/null)"
|
|
102
99
|
|
|
103
|
-
for payload in "$COUNTS_JSON" "$SKILLS_JSON" "$GOV_JSON" "$STANDARDS_JSON" "$SNIPPETS_JSON" "$TOOLING_JSON"
|
|
100
|
+
for payload in "$COUNTS_JSON" "$SKILLS_JSON" "$GOV_JSON" "$STANDARDS_JSON" "$SNIPPETS_JSON" "$TOOLING_JSON"; do
|
|
104
101
|
if [ -z "$payload" ]; then
|
|
105
102
|
echo "regen-hero: a catalog returned nothing, refusing to write a zeroed hero" >&2
|
|
106
103
|
exit 1
|
|
@@ -120,7 +117,6 @@ printf '%s' "$GOV_JSON" >"$PAYLOAD_DIR/gov.json"
|
|
|
120
117
|
printf '%s' "$STANDARDS_JSON" >"$PAYLOAD_DIR/standards.json"
|
|
121
118
|
printf '%s' "$SNIPPETS_JSON" >"$PAYLOAD_DIR/snippets.json"
|
|
122
119
|
printf '%s' "$TOOLING_JSON" >"$PAYLOAD_DIR/tooling.json"
|
|
123
|
-
printf '%s' "$COMMANDS_HELP" >"$PAYLOAD_DIR/commands-help.txt"
|
|
124
120
|
printf '%s' "$TOKEN_CSS" >"$PAYLOAD_DIR/tokens.css"
|
|
125
121
|
|
|
126
122
|
export PAYLOAD_DIR
|
|
@@ -349,36 +345,8 @@ for (const [label, rows] of [
|
|
|
349
345
|
}
|
|
350
346
|
}
|
|
351
347
|
|
|
352
|
-
// The ledger names a few real entries per domain. Chosen by hand for the same
|
|
353
|
-
// reason FEATURED_SKILLS is, and asserted against the catalog so a rename fails
|
|
354
|
-
// the run rather than leaving a name the repository no longer ships.
|
|
355
|
-
const commandNames = readFileSync(PAYLOAD_DIR + "/commands-help.txt", "utf8")
|
|
356
|
-
.split("\n")
|
|
357
|
-
.map((line) => line.match(/^[│\s]{2,}(?<name>[a-z][a-z-]*)\s/)?.groups?.name)
|
|
358
|
-
.filter(Boolean)
|
|
359
|
-
const LEDGER = [
|
|
360
|
-
["skills", skills.length, ["plan-feature", "role-orchestrator", "review-pr"], skills],
|
|
361
|
-
["rules", rules.length, ["behavior", "memory", "testing"], rules],
|
|
362
|
-
["standards", standards.length, ["markdown", "plan", "teach"], standards],
|
|
363
|
-
["commands", commandCount, ["gov", "tasks", "design"], commandNames],
|
|
364
|
-
["stacks", toolingStacks.length, ["astro", "python", "web"], toolingStacks.map((stack) => stack.name)],
|
|
365
|
-
]
|
|
366
|
-
for (const [domain, , chosen, names] of LEDGER) {
|
|
367
|
-
const known = new Set(names)
|
|
368
|
-
const missing = chosen.filter((name) => !known.has(name))
|
|
369
|
-
if (missing.length > 0) {
|
|
370
|
-
console.error(`regen-hero: ledger ${domain} names missing from the catalog: ${missing.join(", ")}`)
|
|
371
|
-
process.exit(1)
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
const ledgerRows = LEDGER.map(
|
|
375
|
-
([domain, count, chosen]) =>
|
|
376
|
-
` <div class="row"><span class="count">${count}</span><span class="domain">${domain}</span><span class="names">${escape(chosen.join(", "))}</span></div>`,
|
|
377
|
-
).join("\n")
|
|
378
|
-
|
|
379
348
|
const values = {
|
|
380
349
|
TOKENS: tokenCss,
|
|
381
|
-
LEDGER_ROWS: ledgerRows,
|
|
382
350
|
GOV_STACK_ROWS: govStackRows,
|
|
383
351
|
GOV_RULE_ROWS: govRuleRows,
|
|
384
352
|
STANDARD_ROWS: standardRows,
|
|
@@ -417,7 +385,7 @@ if (templates.length === 0) {
|
|
|
417
385
|
// same template with the plain roles pointed at the light ones rather than a
|
|
418
386
|
// second copy of any hex value. The hero is a landing-page frame no README
|
|
419
387
|
// shows, so it stays dark.
|
|
420
|
-
const LIGHT_TEMPLATES = new Set(["
|
|
388
|
+
const LIGHT_TEMPLATES = new Set(["install.html.tmpl"])
|
|
421
389
|
|
|
422
390
|
const lightRoles = [...tokenCss.matchAll(/--color-light-([a-z-]+):/g)].map((match) => match[1])
|
|
423
391
|
if (lightRoles.length === 0) {
|
|
@@ -117,6 +117,16 @@ export const WORKFLOW_CASES: readonly SkillCase[] = [
|
|
|
117
117
|
'Check whether the markdown I changed violates any authoring standards.',
|
|
118
118
|
expect: 'standards-audit',
|
|
119
119
|
},
|
|
120
|
+
// Rot across documents nobody changed is what separates this from
|
|
121
|
+
// `standards-audit`, which is diff-scoped and reports a stated rule broken on
|
|
122
|
+
// a given line. It is also not `target-check`, which asks whether a document
|
|
123
|
+
// exists and holds its sections rather than whether it still describes the
|
|
124
|
+
// tree.
|
|
125
|
+
{
|
|
126
|
+
prompt:
|
|
127
|
+
'Which of our docs have gone stale, grown too long, or ended up in the wrong file?',
|
|
128
|
+
expect: 'document-health',
|
|
129
|
+
},
|
|
120
130
|
{
|
|
121
131
|
prompt: 'Open a new entry on the task board for this piece of work.',
|
|
122
132
|
expect: 'task-board',
|