@erclx/canon 4.121.0 → 4.123.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/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/auto-ship/SKILL.md +6 -5
- package/claude/skills/auto-ship/references/tier-failures.md +7 -4
- package/claude/skills/backlog-triage/REQUIREMENT.md +47 -0
- package/claude/skills/backlog-triage/SKILL.md +139 -0
- package/claude/skills/canon-rollout/SKILL.md +6 -6
- package/claude/skills/context-fold/REQUIREMENT.md +75 -0
- package/claude/skills/context-fold/SKILL.md +162 -0
- package/claude/skills/{docs-fold → context-fold}/references/anchor-sweep.md +1 -1
- package/claude/skills/{docs-fold → context-fold}/references/classify.md +4 -2
- package/claude/skills/context-fold/references/context-refresh.md +48 -0
- package/claude/skills/context-fold/references/promoted-pages.md +29 -0
- package/claude/skills/context-fold/references/receipt-sweep.md +43 -0
- package/claude/skills/context-fold/references/unusable-baseline.md +25 -0
- package/claude/skills/{docs-fold → context-fold}/references/wireframe-sweep.md +1 -1
- package/claude/skills/docs-fold/REQUIREMENT.md +8 -58
- package/claude/skills/docs-fold/SKILL.md +3 -278
- package/claude/skills/docs-sync/REQUIREMENT.md +1 -1
- package/claude/skills/docs-sync/SKILL.md +1 -1
- package/claude/skills/draft-context/REQUIREMENT.md +2 -2
- package/claude/skills/draft-context/SKILL.md +3 -3
- package/claude/skills/draft-docs/REQUIREMENT.md +1 -1
- package/claude/skills/draft-ready/SKILL.md +1 -1
- package/claude/skills/draft-wireframes/REQUIREMENT.md +1 -1
- package/claude/skills/draft-wireframes/SKILL.md +2 -2
- package/claude/skills/git-pr/SKILL.md +8 -146
- package/claude/skills/git-pr/references/evidence.md +114 -0
- package/claude/skills/git-pr/references/labels.md +20 -0
- package/claude/skills/git-pr/references/task-number.md +26 -0
- package/claude/skills/git-ship/SKILL.md +5 -4
- package/claude/skills/memory-capture/REQUIREMENT.md +2 -2
- package/claude/skills/memory-capture/SKILL.md +19 -9
- package/claude/skills/memory-review/REQUIREMENT.md +5 -3
- package/claude/skills/memory-review/SKILL.md +22 -107
- package/claude/skills/memory-review/references/later-phases.md +111 -0
- package/claude/skills/memory-review/references/receipt-format.md +19 -3
- package/claude/skills/plan-feature/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/REQUIREMENT.md +1 -1
- package/claude/skills/review-address/SKILL.md +1 -1
- package/claude/skills/review-branch/SKILL.md +1 -1
- package/claude/skills/role-orchestrator/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +4 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
- package/claude/skills/session-resume/REQUIREMENT.md +1 -1
- package/claude/skills/session-resume/SKILL.md +4 -3
- package/claude/skills/session-worktree/SKILL.md +4 -10
- package/claude/skills/task-board/REQUIREMENT.md +1 -1
- package/claude/skills/task-board/SKILL.md +7 -81
- package/claude/skills/task-board/references/archive.md +54 -0
- package/claude/skills/task-board/references/decline.md +40 -0
- package/claude/skills/teach-workspace/SKILL.md +8 -105
- package/claude/skills/teach-workspace/references/lesson-craft.md +51 -1
- package/claude/skills/teach-workspace/references/promotion.md +41 -0
- package/docs/agents/architecture-record.md +26 -0
- package/docs/agents/commands.md +87 -154
- package/docs/agents/context-audit-checks.md +2 -20
- package/docs/agents/context-audit.md +1 -1
- package/docs/agents/context-classify.md +1 -1
- package/docs/agents/drift-surfaces.md +192 -0
- package/docs/agents/index.md +12 -4
- package/docs/agents/install-and-sync.md +2 -181
- package/docs/agents/markdown-audit-weight.md +73 -0
- package/docs/agents/markdown-audit.md +3 -90
- package/docs/agents/migrate.md +34 -0
- package/docs/agents/records-stale.md +62 -0
- package/docs/agents/records.md +5 -1
- package/docs/agents/sandbox.md +1 -1
- package/docs/agents/tasks-archive.md +81 -0
- package/docs/agents/tasks-plans.md +149 -0
- package/docs/agents/tasks-validate.md +131 -0
- package/docs/agents/tasks.md +7 -334
- package/docs/target-projects.md +3 -3
- package/docs/workflow/ai-workflow.md +34 -29
- package/docs/workflow/operating-model.md +1 -1
- package/governance/rules/claude/555-tasks.md +2 -1
- package/governance/rules/core/045-memory.md +1 -1
- package/package.json +1 -1
- package/src/claude/cases/setup.ts +1 -1
- package/src/claude/cases/workflow.ts +22 -1
- package/src/commands/records.ts +146 -0
- package/src/commands/sandbox.ts +6 -4
- package/src/commands/tasks.ts +39 -29
- package/src/context/classify/extract.ts +1 -1
- package/src/context/classify/ollama.ts +1 -1
- package/src/context/classify/run.ts +1 -1
- package/src/gate/measures.ts +1 -1
- package/src/gate/stages.ts +1 -0
- package/src/migrate/skill-names.ts +15 -2
- package/src/records/stale.ts +243 -0
- package/src/sandbox/expect.ts +1 -1
- package/src/tasks/archive.ts +223 -92
- package/src/tasks/reach.ts +1 -1
- package/src/tasks/record.ts +60 -17
- package/src/tasks/validate.ts +37 -4
- package/standards/board.md +136 -0
- package/standards/commit.md +5 -0
- package/standards/groundwork.md +25 -36
- package/standards/index.md +2 -1
- package/standards/memory.md +13 -1
- package/standards/plan.md +20 -34
- package/standards/readme.md +8 -77
- package/standards/requirements.md +2 -2
- package/standards/tasks.md +19 -126
- package/standards/versioning.md +1 -1
- package/tooling/astro/reference.md +1 -1
- package/tooling/base/configs/.husky/post-merge +1 -1
- package/tooling/base/configs/commitlint.config.js +27 -1
- package/tooling/base/reference.md +1 -1
- package/tooling/claude/reference.md +1 -1
- package/tooling/go/reference.md +1 -1
- package/tooling/nextjs/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +1 -1
- package/tooling/vite-react/reference.md +1 -1
- package/tooling/web/reference.md +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Drift surfaces
|
|
3
|
+
description: The six sections canon sync --check reports beside the per-domain scan, being seeds, superseded artifacts, unmigrated domains, new rules and skills, and the reverse walk, with the managed-target gate and what counts toward the exit code
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Drift surfaces
|
|
7
|
+
|
|
8
|
+
`canon sync --check` reports six sections outside the per-domain scan that
|
|
9
|
+
`install-and-sync.md` describes, because each names something
|
|
10
|
+
that walk cannot see: `seeds`, `superseded`, `unmigrated`, `newSkills`,
|
|
11
|
+
`newRules`, and `reverse`. None of them produces a change, and no sync command
|
|
12
|
+
applies any of them. The headings below group the first three together and give
|
|
13
|
+
`newSkills` its description under `newRules`, which answers the same question
|
|
14
|
+
about a different corpus.
|
|
15
|
+
|
|
16
|
+
All six report only against a toolkit-managed target, which is one carrying a
|
|
17
|
+
`.claude/` directory, a `CLAUDE.md`, or a domain still at the root layout. The
|
|
18
|
+
report says so through `managed` in the JSON and routes an unmanaged directory to
|
|
19
|
+
`canon init`. Seeds are why the gate exists, since they enumerate from the toolkit
|
|
20
|
+
source rather than from what a target installed, so an unmanaged directory would
|
|
21
|
+
otherwise report every seed as `missing`.
|
|
22
|
+
|
|
23
|
+
A root-layout domain counts as a marker on its own, because the detection fires
|
|
24
|
+
only on root files the toolkit ships and a project in the old layout is one the
|
|
25
|
+
toolkit installed. When `managed` is false every section comes back empty rather
|
|
26
|
+
than the render alone going quiet, so a consumer reading `--json` never acts on a
|
|
27
|
+
finding the rendered half withheld.
|
|
28
|
+
|
|
29
|
+
## Seeds, superseded artifacts, and unmigrated domains
|
|
30
|
+
|
|
31
|
+
`seeds` classifies every seed the toolkit ships against the target's copy, as
|
|
32
|
+
`matching`, `stale`, `drifted`, or `missing`. `missing` has no per-domain
|
|
33
|
+
equivalent, since the domain walk lists what a target installed and cannot see a
|
|
34
|
+
file that never arrived. There is no `customized` verdict here, because that one
|
|
35
|
+
needs a stamp and seeds carry none, so a file history cannot attribute stays
|
|
36
|
+
`drifted`. Reconcile the section with `seed-sync`, which merges one
|
|
37
|
+
section at a time rather than replacing a file the project edits.
|
|
38
|
+
|
|
39
|
+
A markdown seed installs rewritten rather than copied, since the `stub: true`
|
|
40
|
+
marker the toolkit's own seed gate reads is stripped on the way in. The
|
|
41
|
+
comparison above runs against what the install would write, so a marked seed a
|
|
42
|
+
target never touched still reports `matching`. Every other seed copies byte for
|
|
43
|
+
byte.
|
|
44
|
+
|
|
45
|
+
`superseded` names a file a newer seed folder replaced, such as `.claude/TASKS.md`
|
|
46
|
+
against the `.canon/tasks/` that now ships. The entry carries `replacedBy` and
|
|
47
|
+
nothing else, and the file is never deleted, since the content belongs to the
|
|
48
|
+
project and only its author can decide where it moves. The list derives from the
|
|
49
|
+
seed tree rather than from a fixed set of filenames, so a folder added later is
|
|
50
|
+
covered without a code change. Only an exact stem matches, which leaves a
|
|
51
|
+
suffixed variant such as `TASKS-ARCHIVE.md` unreported.
|
|
52
|
+
|
|
53
|
+
No skill splits the file. The standard governing `replacedBy` is the one the
|
|
54
|
+
`appliesTo` the standards catalog declares, and `canon standards <name>` reads
|
|
55
|
+
its destination shape, so the split is the project's own to make.
|
|
56
|
+
|
|
57
|
+
`unmigrated` names a domain sitting at the root layout an older toolkit installed
|
|
58
|
+
to, with nothing at the path the current one reads. It carries `rootPath`,
|
|
59
|
+
`installPath`, and a file count. Without it a project holding `standards/` at its
|
|
60
|
+
root reports zero entries for that domain and reads as clean, which is the most
|
|
61
|
+
misleading state the report can produce.
|
|
62
|
+
|
|
63
|
+
The field currently names no domain. Standards and snippets are the two the
|
|
64
|
+
toolkit ever installed at a project root, and both closed their install channel,
|
|
65
|
+
so a project still holding a root `standards/` or `snippets/` folder is carrying
|
|
66
|
+
its own authoring surface rather than an unfinished install. Nothing proposes
|
|
67
|
+
moving either, and no command relocates the content. Move it yourself.
|
|
68
|
+
|
|
69
|
+
## Rules the target never received
|
|
70
|
+
|
|
71
|
+
`newRules` names a rule the target could receive and its tree does not hold. A
|
|
72
|
+
sync refreshes the files a target already holds and adds none, so without this
|
|
73
|
+
section a project's rule set freezes at its install date while every file it
|
|
74
|
+
does hold reports as current. That is the report's most confident wrong
|
|
75
|
+
answer, since a clean result reads as a target holding everything the toolkit
|
|
76
|
+
publishes.
|
|
77
|
+
|
|
78
|
+
The list rides beside `newSkills`, which asks the same question about the plugin
|
|
79
|
+
catalog. Both are names rather than paths, and neither queues a change, because
|
|
80
|
+
the two remedies differ: a skill loads live from the plugin directory and needs
|
|
81
|
+
nothing run, while a rule reaches a target only when someone runs
|
|
82
|
+
`canon gov install`.
|
|
83
|
+
|
|
84
|
+
Read a clean section as reporting rather than as delivering. Nothing here
|
|
85
|
+
installs, nothing counts toward `--exit-code`, and a target can read the list and
|
|
86
|
+
act on none of it. The value stops at an operator reading it, which is the same
|
|
87
|
+
contract the skills list already sets.
|
|
88
|
+
|
|
89
|
+
Since `canon gov install` records the stack it resolved, a target carrying that
|
|
90
|
+
record answers this by comparing its current entitlement against its current
|
|
91
|
+
tree, with no anchor and no git diff involved. That is what lets the section
|
|
92
|
+
name a rule that shipped before the target's last sync: the anchor a sync
|
|
93
|
+
advances plays no part in the read, where an anchor-bound diff can never see a
|
|
94
|
+
rule on the far side of a window a later sync moved past it. The per-file
|
|
95
|
+
`missing` state `canon gov sync` reports comes from the same comparison, so a
|
|
96
|
+
rule the chain lists reaches both surfaces the same way.
|
|
97
|
+
|
|
98
|
+
A target stamped before governance recorded a chain falls back to the older
|
|
99
|
+
band-inference read below. The measurement there anchors on governance's own
|
|
100
|
+
stamp rather than on the oldest anchor across domains, since rules are
|
|
101
|
+
domain-scoped and a shared anchor would let another domain's sync move the
|
|
102
|
+
revision rules are measured from. A target carrying no chain and no governance anchor
|
|
103
|
+
reports nothing at all: it has no date to measure against, and diffing from the
|
|
104
|
+
start of history would read the whole catalog as new.
|
|
105
|
+
|
|
106
|
+
An anchor this toolkit cannot resolve reports nothing by the same route, and that
|
|
107
|
+
one is not visible. A stamp naming a revision the running clone has never seen,
|
|
108
|
+
which is what a registry install without history or a shallow clone produces,
|
|
109
|
+
fails the read and yields an empty list rather than a stated absence. It looks
|
|
110
|
+
identical to a target holding every rule the toolkit publishes. `newSkills`
|
|
111
|
+
behaves the same way, and neither carries the `historyUnavailable` flag the
|
|
112
|
+
per-domain scan uses to separate the two. Treat an empty section on a toolkit
|
|
113
|
+
that is not a full clone as unmeasured rather than clean. This gap does not
|
|
114
|
+
reach the chain-based read above, since it consults no anchor at all.
|
|
115
|
+
|
|
116
|
+
In the fallback, entitlement is filtered, because a stack does not receive
|
|
117
|
+
every rule. The base stack takes the `core` and `claude` folders whole and
|
|
118
|
+
every other stack extends it with individually named rules, so an unfiltered
|
|
119
|
+
list would tell a base consumer about rules it can never receive and train the
|
|
120
|
+
reader to skip the section.
|
|
121
|
+
|
|
122
|
+
The filter accepts a band on either of two grounds. A folder the base stack takes
|
|
123
|
+
whole is entitled to every target, read from the stack file so a folder added to
|
|
124
|
+
base later needs no code change. Every other band is read off the folders the
|
|
125
|
+
target already carries, which is the fallback's only evidence of what a target
|
|
126
|
+
was entitled to before it recorded a chain. One band can be reached by more than
|
|
127
|
+
one stack, so the test over-reports inside a folder the target holds, which
|
|
128
|
+
costs a line where under-reporting would cost the section its point.
|
|
129
|
+
|
|
130
|
+
A rule the target already holds is dropped by name. That is what keeps a rule the
|
|
131
|
+
toolkit moved between band folders out of the list, since a rename reaches this
|
|
132
|
+
read as an addition and only the name tells the two apart.
|
|
133
|
+
|
|
134
|
+
This closes the dangling-citation case as a side effect rather than checking for
|
|
135
|
+
one. The live instance is a rule citing a sibling authored after the target's
|
|
136
|
+
install, and the section names the sibling as new rather than naming the citation
|
|
137
|
+
as broken. That is enough for an operator to act on, and it is not a citation
|
|
138
|
+
check.
|
|
139
|
+
|
|
140
|
+
## The reverse walk
|
|
141
|
+
|
|
142
|
+
`reverse` is the one section built by walking the target rather than the
|
|
143
|
+
catalog. Every other surface enumerates toolkit-owned keys and asks whether the
|
|
144
|
+
target matches, so a folder the toolkit deleted appears in none of them. It
|
|
145
|
+
carries `unclaimed` and `historyUnavailable`.
|
|
146
|
+
|
|
147
|
+
`unclaimed` names a folder the target holds at a top-level path the toolkit once
|
|
148
|
+
shipped and has since deleted. The candidate roots come from the toolkit's own
|
|
149
|
+
history rather than from a list, so a root dropped later is covered without a
|
|
150
|
+
code change. Scoping to those roots is what keeps the walk useful: walking the
|
|
151
|
+
whole tree reports every project folder as unclaimed, which is true and says
|
|
152
|
+
nothing.
|
|
153
|
+
|
|
154
|
+
The managed gate above applies here too, and it is the one place it surprises.
|
|
155
|
+
A directory holding a dropped folder and nothing else reports an empty `reverse`
|
|
156
|
+
rather than the folder, because it carries none of the three markers. Read an
|
|
157
|
+
empty section on an unmanaged target as a walk that never ran rather than as a
|
|
158
|
+
clean result.
|
|
159
|
+
|
|
160
|
+
Each entry carries `rel`, a file count, and an `attribution` of `dropped`,
|
|
161
|
+
`project`, or `unattributed`. A dropped folder and one the project wrote are the
|
|
162
|
+
same bytes at the same path, so the verdict is traced from history rather than
|
|
163
|
+
guessed from the filesystem.
|
|
164
|
+
|
|
165
|
+
Content matching a version the toolkit published reads as `dropped` and carries
|
|
166
|
+
the `since` commit that published it. Names the toolkit shipped holding content
|
|
167
|
+
it never published read as `unattributed`, which is a state in its own right
|
|
168
|
+
rather than a soft yes. No overlap at all reads as `project`, and the render
|
|
169
|
+
drops those while the JSON keeps them.
|
|
170
|
+
|
|
171
|
+
Only files whose path the toolkit once held are hashed, so a project folder
|
|
172
|
+
colliding on a retired name costs the walk no reads. The cost is that a file the
|
|
173
|
+
toolkit shipped and the target renamed goes unmatched, the same limit the
|
|
174
|
+
`unmigrated` count carries.
|
|
175
|
+
|
|
176
|
+
## What counts toward the gate
|
|
177
|
+
|
|
178
|
+
`unmigrated` counts toward `--exit-code`, since running the relocation closes it.
|
|
179
|
+
`superseded` and every seed state are excluded, for the reason `orphaned` already
|
|
180
|
+
is: only the user can move content they wrote, so failing a job on it leaves the
|
|
181
|
+
job red with no mechanical remedy.
|
|
182
|
+
|
|
183
|
+
`newRules` is excluded on a different ground, since a command does close it. What
|
|
184
|
+
excludes it is that installing a rule changes what a project is governed by, so
|
|
185
|
+
gating on the count would pressure a target into adopting rules nobody chose.
|
|
186
|
+
`newSkills` is excluded because it needs no command at all.
|
|
187
|
+
|
|
188
|
+
The whole `reverse` section is excluded on the same grounds, and more strongly.
|
|
189
|
+
Every entry in it is a judgment about a file the project may own, and one of its
|
|
190
|
+
three verdicts is a labelled unknown by design. The unmigrated detection shipped
|
|
191
|
+
that exact false positive once, failing a push with no action that cleared it,
|
|
192
|
+
so this section reports and gates nothing.
|
package/docs/agents/index.md
CHANGED
|
@@ -8,18 +8,20 @@ category: Agent surface
|
|
|
8
8
|
|
|
9
9
|
CLI catalog and invocation rules for agents, split by command domain. Start with overview.
|
|
10
10
|
|
|
11
|
+
- [Architecture record](architecture-record.md): The four findings canon context audit reads off the architecture record, being the entry cap and length gates the record states for itself, the claim coverage report, and the word counts
|
|
11
12
|
- [Audits](audits.md): Running every health check as one set, what the single verdict means, the exit code each outcome takes, the retained baseline and the delta it reports, and which corpora are kept out of the record
|
|
12
13
|
- [Capture](capture.md): Rendering HTML sources to PNG, what the command asserts about fonts, and why the selector has no default
|
|
13
14
|
- [Census](census.md): Tracked-plus-untracked file count, a breakdown by extension, and a line total that skips whatever reads as binary
|
|
14
|
-
- [Command catalog](commands.md): Every
|
|
15
|
+
- [Command catalog](commands.md): Every top-level command with its purpose, each domain's subcommands and the page describing them, the browser commands, and the version skew report
|
|
15
16
|
- [Comments](comments.md): Comment density by language and kind, the two structural exclusions, and how the degradation sweep finds its vocabulary
|
|
16
|
-
- [Context audit checks](context-audit-checks.md): What each non-gating check reports, the unit each checkpoint is measured in, the architecture record's
|
|
17
|
+
- [Context audit checks](context-audit-checks.md): What each non-gating check reports, the unit each checkpoint is measured in, where the architecture record's findings are described, which folders each check reaches, and what moved to the attribute tier
|
|
17
18
|
- [Context audit](context-audit.md): Running the audit, its flags and folder scope, the exit codes, the citation gate, and the widened gate the seed stage runs
|
|
18
19
|
- [Doc classifier](context-classify.md): Classifying canonical-doc content as keep, replace/rewrite, history, or move in diff and sweep mode, the classifier setting pair, the record shape, and the exit codes
|
|
19
20
|
- [Self-stated counts](counts.md): Reading a sentence that asserts a closed catalog's size, how a match is decided, the plausibility filter that keeps a generic word from matching a subset, and why the sweep reports rather than gates
|
|
20
21
|
- [Demo](demo.md): Compiling a screencast draft into a runnable plan, driving a served application to a recording and a still, reading numbered frames back out of a recording, the pointer the recording paints, and what each refusal reports
|
|
21
22
|
- [Design board](design-board.md): Generating a static index over a project's design surfaces, what each panel reads, and which two stay toolkit-checkout-only
|
|
22
23
|
- [Docs](docs.md): How canon docs resolves the toolkit's own reference surface from an install root, and how a split domain is named
|
|
24
|
+
- [Drift surfaces](drift-surfaces.md): The six sections canon sync --check reports beside the per-domain scan, being seeds, superseded artifacts, unmigrated domains, new rules and skills, and the reverse walk, with the managed-target gate and what counts toward the exit code
|
|
23
25
|
- [Driver](driver.md): Walking a page through named interactions, the probe catalog and the false finding each one carries, why viewport heights are never defaulted, and what each refusal reports
|
|
24
26
|
- [Merge gate](gate.md): Running the gate this repository verifies a branch with, what the stage table holds and what stays a script, how the changed set scopes three stages, and why a stage that cannot read its input reports rather than passing
|
|
25
27
|
- [Indexes](indexes.md): Flags, exit codes, and JSON shape for canon indexes regen and canon indexes list, plus when regen auto-stages what it rewrote
|
|
@@ -27,7 +29,9 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
27
29
|
- [Intake](intake.md): Reading intake folder counts and items, the three read states an item can be in, landing a batch of selections in one cluster, the refusal reasons, and why a call is scoped to one file
|
|
28
30
|
- [Key Changes bijection](key-changes.md): Comparing the files a pull request body's Key Changes names against its own diff, the two directions and the split inside each that decides what is worth raising, the span rules the extractor was measured into, and the three refusals that separate a clean pass from a read that produced nothing
|
|
29
31
|
- [Label coverage](label-coverage.md): Reading a changed set against the pull request label map, the two tables it matches, how a gap is separated from a decision, and why an absent map is an answer
|
|
32
|
+
- [Markdown audit weight](markdown-audit-weight.md): The structural half of the markdown audit, being bullet and paragraph weight, run depth, the two cadence numbers, and the length ceiling, with the samples behind each checkpoint and why none of them gates
|
|
30
33
|
- [Markdown audit](markdown-audit.md): Running the audit over any markdown path, where its bans and checkpoints are read from, what each check reports, and why the ban half gates while the structural half reports
|
|
34
|
+
- [Migrate](migrate.md): What each canon migrate verb moves and rewrites, what it refuses, the markers that keep an old spelling, and the idempotence check a second run gives
|
|
31
35
|
- [Output shape](output-shape.md): Two framed shapes every command renders into, how JSON and --names modes keep stdout clean, and the exit discipline that lets piped output drain
|
|
32
36
|
- [Overview](overview.md): What this folder covers, the invocation rules every command inherits, and where domain behavior is documented instead
|
|
33
37
|
- [The pull request evidence comparison](pr-evidence.md): What canon pr evidence compares, the marker that lets it edit its own comment rather than duplicate it, the refusal reasons it names, and why the comparison anchors at the merge base rather than the previous push
|
|
@@ -35,8 +39,9 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
35
39
|
- [The pull request preview deploy](pr-preview.md): How canon pr preview finds a fenced Cloudflare Pages deploy, dispatches it on a pull request's branch, reads the alias the run prints, the refusal reasons it names, and why an unfenced deploy is refused before anything runs
|
|
36
40
|
- [Head-sensitive pull request reads](pr-reads.md): Resolving a branch tip from the remote rather than from the pull request object, reading what a review pass covered off its own marker rather than off GitHub's submission stamps, why an empty run list is not a pass, the refusal reasons each verb names, and what the remote read costs
|
|
37
41
|
- [Records push](records-push.md): Backing the record folders to a private remote and restoring them, which folders the payload carries, the one-time setup, the refusal reasons, and the hook that runs the push
|
|
42
|
+
- [Records stale](records-stale.md): Reading the memory pen as a review queue, what makes an entry due, how a cited path is read and resolved, the order entries come back in, and the exit codes and refusals
|
|
38
43
|
- [Records validate](records-validate.md): Validating the session records and the standards corpus, the per-kind checks, which root each kind defaults to, the exit codes, and the refusal reasons
|
|
39
|
-
- [Records](records.md): The two roots a record folder resolves at, migrating a record a frontmatter change orphaned, claiming the ordinal intake and groundwork share, reading each folder's size and growth, pruning stale scratch, and where validation and the private-remote backup are described
|
|
44
|
+
- [Records](records.md): The two roots a record folder resolves at, migrating a record a frontmatter change orphaned, claiming the ordinal intake and groundwork share, reading each folder's size and growth, pruning stale scratch, and where validation, the memory review queue, and the private-remote backup are described
|
|
40
45
|
- [Restated instructions](restated.md): Counting the instructions the always-loaded file and every path-scoped rule share with the seed, the shipped skill bodies, and each other, how a match is decided, the three classes, which surface a later edit starts from, and why the sweep reports rather than gates
|
|
41
46
|
- [Review classification](review-classification.md): Deciding whether a changed set needs the review pass, the two tests it runs, why an empty set refuses rather than skipping, and the written fallback a target on an older binary falls back to
|
|
42
47
|
- [Routing report](routing.md): Reading per CLAUDE.md section how many bullets name a path, what counts as naming one, when a rule counts as covering it, the two refusals, and why the verb reports rather than gates
|
|
@@ -51,7 +56,10 @@ CLI catalog and invocation rules for agents, split by command domain. Start with
|
|
|
51
56
|
- [State-scoped risk](state-scoped-risk.md): Reading committed state rather than an arriving change, the shipped-tree corpus the secret scan reads, what it keys on and how a deliberate value is exempted, the advisory check and its network failure mode, and why one gates while the other reports
|
|
52
57
|
- [Superseded values](superseded.md): Reading where the tree still asserts a value a changed convention no longer produces, why the sweep keys on the value rather than the file, the family stem behind a templated citation, the exemption marker, the blind spots it cannot reach, and why it reports rather than gates
|
|
53
58
|
- [Targets](targets.md): The projects this toolkit installed into, the record the install writes against the sweep that backs it, what bounds each answer, and the cross-target pull request read
|
|
54
|
-
- [Tasks](tasks.md):
|
|
59
|
+
- [Tasks archive](tasks-archive.md): Archiving a shipped task by stem or pull request, declining one decided against, the refusal reasons each carries, and how the plan and ready folder move with the task
|
|
60
|
+
- [Tasks plans](tasks-plans.md): The five verbs that read or write a task's plan, being where it sits and who cites it, whether it waits on the operator, the branch it derives, what a branch reached against what it declared, and writing its Plan line
|
|
61
|
+
- [Tasks validate](tasks-validate.md): Validating the board against the tree, the seven checks, the untested, claims, and unplaced arrays, the exit codes, and the refusal reasons
|
|
62
|
+
- [Tasks](tasks.md): Claiming the next phase label, recording a pull request number and closing an outcome, listing each task's readiness, and where archiving, the plan verbs, and board validation are described
|
|
55
63
|
- [Teach authoring](teach-authoring.md): Resolving what the next lesson needs before it is written, rendering a lesson body's blocks to HTML, and rewriting the root listing, a contents page, and each lesson's chrome and quiz stepper from its marker regions
|
|
56
64
|
- [Teach](teach.md): Listing learning workspaces with what their records schedule next, opening one with its required files, recording sources and glossary terms, where the lesson authoring verbs are described, the refusal reasons, and why every write here runs through a verb
|
|
57
65
|
- [Test order](test-order.md): Reading where an implementation reached history ahead of its test, how a pair is decided, the three verdicts, the coverage the pairing cannot reach, and why the check reports rather than gates
|
|
@@ -228,187 +228,8 @@ edit and a job counting those stays red with no remedy.
|
|
|
228
228
|
Six sections sit outside the per-domain scan, because each names something
|
|
229
229
|
that walk cannot see: `seeds`, `superseded`, `unmigrated`, `newSkills`,
|
|
230
230
|
`newRules`, and `reverse`. None of them produces a change, and no sync command
|
|
231
|
-
applies any of them.
|
|
232
|
-
|
|
233
|
-
about a different corpus.
|
|
234
|
-
|
|
235
|
-
All six report only against a toolkit-managed target, which is one carrying a
|
|
236
|
-
`.claude/` directory, a `CLAUDE.md`, or a domain still at the root layout. The
|
|
237
|
-
report says so through `managed` in the JSON and routes an unmanaged directory to
|
|
238
|
-
`canon init`. Seeds are why the gate exists, since they enumerate from the toolkit
|
|
239
|
-
source rather than from what a target installed, so an unmanaged directory would
|
|
240
|
-
otherwise report every seed as `missing`.
|
|
241
|
-
|
|
242
|
-
A root-layout domain counts as a marker on its own, because the detection fires
|
|
243
|
-
only on root files the toolkit ships and a project in the old layout is one the
|
|
244
|
-
toolkit installed. When `managed` is false every section comes back empty rather
|
|
245
|
-
than the render alone going quiet, so a consumer reading `--json` never acts on a
|
|
246
|
-
finding the rendered half withheld.
|
|
247
|
-
|
|
248
|
-
#### Seeds, superseded artifacts, and unmigrated domains
|
|
249
|
-
|
|
250
|
-
`seeds` classifies every seed the toolkit ships against the target's copy, as
|
|
251
|
-
`matching`, `stale`, `drifted`, or `missing`. `missing` has no per-domain
|
|
252
|
-
equivalent, since the domain walk lists what a target installed and cannot see a
|
|
253
|
-
file that never arrived. There is no `customized` verdict here, because that one
|
|
254
|
-
needs a stamp and seeds carry none, so a file history cannot attribute stays
|
|
255
|
-
`drifted`. Reconcile the section with `seed-sync`, which merges one
|
|
256
|
-
section at a time rather than replacing a file the project edits.
|
|
257
|
-
|
|
258
|
-
A markdown seed installs rewritten rather than copied, since the `stub: true`
|
|
259
|
-
marker the toolkit's own seed gate reads is stripped on the way in. The
|
|
260
|
-
comparison above runs against what the install would write, so a marked seed a
|
|
261
|
-
target never touched still reports `matching`. Every other seed copies byte for
|
|
262
|
-
byte.
|
|
263
|
-
|
|
264
|
-
`superseded` names a file a newer seed folder replaced, such as `.claude/TASKS.md`
|
|
265
|
-
against the `.canon/tasks/` that now ships. The entry carries `replacedBy` and
|
|
266
|
-
nothing else, and the file is never deleted, since the content belongs to the
|
|
267
|
-
project and only its author can decide where it moves. The list derives from the
|
|
268
|
-
seed tree rather than from a fixed set of filenames, so a folder added later is
|
|
269
|
-
covered without a code change. Only an exact stem matches, which leaves a
|
|
270
|
-
suffixed variant such as `TASKS-ARCHIVE.md` unreported.
|
|
271
|
-
|
|
272
|
-
No skill splits the file. The standard governing `replacedBy` is the one the
|
|
273
|
-
`appliesTo` the standards catalog declares, and `canon standards <name>` reads
|
|
274
|
-
its destination shape, so the split is the project's own to make.
|
|
275
|
-
|
|
276
|
-
`unmigrated` names a domain sitting at the root layout an older toolkit installed
|
|
277
|
-
to, with nothing at the path the current one reads. It carries `rootPath`,
|
|
278
|
-
`installPath`, and a file count. Without it a project holding `standards/` at its
|
|
279
|
-
root reports zero entries for that domain and reads as clean, which is the most
|
|
280
|
-
misleading state the report can produce.
|
|
281
|
-
|
|
282
|
-
The field currently names no domain. Standards and snippets are the two the
|
|
283
|
-
toolkit ever installed at a project root, and both closed their install channel,
|
|
284
|
-
so a project still holding a root `standards/` or `snippets/` folder is carrying
|
|
285
|
-
its own authoring surface rather than an unfinished install. Nothing proposes
|
|
286
|
-
moving either, and no command relocates the content. Move it yourself.
|
|
287
|
-
|
|
288
|
-
#### Rules the target never received
|
|
289
|
-
|
|
290
|
-
`newRules` names a rule the target could receive and its tree does not hold. A
|
|
291
|
-
sync refreshes the files a target already holds and adds none, so without this
|
|
292
|
-
section a project's rule set freezes at its install date while every file it
|
|
293
|
-
does hold reports as current. That is the report's most confident wrong
|
|
294
|
-
answer, since a clean result reads as a target holding everything the toolkit
|
|
295
|
-
publishes.
|
|
296
|
-
|
|
297
|
-
The list rides beside `newSkills`, which asks the same question about the plugin
|
|
298
|
-
catalog. Both are names rather than paths, and neither queues a change, because
|
|
299
|
-
the two remedies differ: a skill loads live from the plugin directory and needs
|
|
300
|
-
nothing run, while a rule reaches a target only when someone runs
|
|
301
|
-
`canon gov install`.
|
|
302
|
-
|
|
303
|
-
Read a clean section as reporting rather than as delivering. Nothing here
|
|
304
|
-
installs, nothing counts toward `--exit-code`, and a target can read the list and
|
|
305
|
-
act on none of it. The value stops at an operator reading it, which is the same
|
|
306
|
-
contract the skills list already sets.
|
|
307
|
-
|
|
308
|
-
Since `canon gov install` records the stack it resolved, a target carrying that
|
|
309
|
-
record answers this by comparing its current entitlement against its current
|
|
310
|
-
tree, with no anchor and no git diff involved. That is what lets the section
|
|
311
|
-
name a rule that shipped before the target's last sync: the anchor a sync
|
|
312
|
-
advances plays no part in the read, where an anchor-bound diff can never see a
|
|
313
|
-
rule on the far side of a window a later sync moved past it. The per-file
|
|
314
|
-
`missing` state `canon gov sync` reports comes from the same comparison, so a
|
|
315
|
-
rule the chain lists reaches both surfaces the same way.
|
|
316
|
-
|
|
317
|
-
A target stamped before governance recorded a chain falls back to the older
|
|
318
|
-
band-inference read below. The measurement there anchors on governance's own
|
|
319
|
-
stamp rather than on the oldest anchor across domains, since rules are
|
|
320
|
-
domain-scoped and a shared anchor would let another domain's sync move the
|
|
321
|
-
revision rules are measured from. A target carrying no chain and no governance anchor
|
|
322
|
-
reports nothing at all: it has no date to measure against, and diffing from the
|
|
323
|
-
start of history would read the whole catalog as new.
|
|
324
|
-
|
|
325
|
-
An anchor this toolkit cannot resolve reports nothing by the same route, and that
|
|
326
|
-
one is not visible. A stamp naming a revision the running clone has never seen,
|
|
327
|
-
which is what a registry install without history or a shallow clone produces,
|
|
328
|
-
fails the read and yields an empty list rather than a stated absence. It looks
|
|
329
|
-
identical to a target holding every rule the toolkit publishes. `newSkills`
|
|
330
|
-
behaves the same way, and neither carries the `historyUnavailable` flag the
|
|
331
|
-
per-domain scan uses to separate the two. Treat an empty section on a toolkit
|
|
332
|
-
that is not a full clone as unmeasured rather than clean. This gap does not
|
|
333
|
-
reach the chain-based read above, since it consults no anchor at all.
|
|
334
|
-
|
|
335
|
-
In the fallback, entitlement is filtered, because a stack does not receive
|
|
336
|
-
every rule. The base stack takes the `core` and `claude` folders whole and
|
|
337
|
-
every other stack extends it with individually named rules, so an unfiltered
|
|
338
|
-
list would tell a base consumer about rules it can never receive and train the
|
|
339
|
-
reader to skip the section.
|
|
340
|
-
|
|
341
|
-
The filter accepts a band on either of two grounds. A folder the base stack takes
|
|
342
|
-
whole is entitled to every target, read from the stack file so a folder added to
|
|
343
|
-
base later needs no code change. Every other band is read off the folders the
|
|
344
|
-
target already carries, which is the fallback's only evidence of what a target
|
|
345
|
-
was entitled to before it recorded a chain. One band can be reached by more than
|
|
346
|
-
one stack, so the test over-reports inside a folder the target holds, which
|
|
347
|
-
costs a line where under-reporting would cost the section its point.
|
|
348
|
-
|
|
349
|
-
A rule the target already holds is dropped by name. That is what keeps a rule the
|
|
350
|
-
toolkit moved between band folders out of the list, since a rename reaches this
|
|
351
|
-
read as an addition and only the name tells the two apart.
|
|
352
|
-
|
|
353
|
-
This closes the dangling-citation case as a side effect rather than checking for
|
|
354
|
-
one. The live instance is a rule citing a sibling authored after the target's
|
|
355
|
-
install, and the section names the sibling as new rather than naming the citation
|
|
356
|
-
as broken. That is enough for an operator to act on, and it is not a citation
|
|
357
|
-
check.
|
|
358
|
-
|
|
359
|
-
#### The reverse walk
|
|
360
|
-
|
|
361
|
-
`reverse` is the one section built by walking the target rather than the
|
|
362
|
-
catalog. Every other surface enumerates toolkit-owned keys and asks whether the
|
|
363
|
-
target matches, so a folder the toolkit deleted appears in none of them. It
|
|
364
|
-
carries `unclaimed` and `historyUnavailable`.
|
|
365
|
-
|
|
366
|
-
`unclaimed` names a folder the target holds at a top-level path the toolkit once
|
|
367
|
-
shipped and has since deleted. The candidate roots come from the toolkit's own
|
|
368
|
-
history rather than from a list, so a root dropped later is covered without a
|
|
369
|
-
code change. Scoping to those roots is what keeps the walk useful: walking the
|
|
370
|
-
whole tree reports every project folder as unclaimed, which is true and says
|
|
371
|
-
nothing.
|
|
372
|
-
|
|
373
|
-
The managed gate above applies here too, and it is the one place it surprises.
|
|
374
|
-
A directory holding a dropped folder and nothing else reports an empty `reverse`
|
|
375
|
-
rather than the folder, because it carries none of the three markers. Read an
|
|
376
|
-
empty section on an unmanaged target as a walk that never ran rather than as a
|
|
377
|
-
clean result.
|
|
378
|
-
|
|
379
|
-
Each entry carries `rel`, a file count, and an `attribution` of `dropped`,
|
|
380
|
-
`project`, or `unattributed`. A dropped folder and one the project wrote are the
|
|
381
|
-
same bytes at the same path, so the verdict is traced from history rather than
|
|
382
|
-
guessed from the filesystem.
|
|
383
|
-
|
|
384
|
-
Content matching a version the toolkit published reads as `dropped` and carries
|
|
385
|
-
the `since` commit that published it. Names the toolkit shipped holding content
|
|
386
|
-
it never published read as `unattributed`, which is a state in its own right
|
|
387
|
-
rather than a soft yes. No overlap at all reads as `project`, and the render
|
|
388
|
-
drops those while the JSON keeps them.
|
|
389
|
-
|
|
390
|
-
Only files whose path the toolkit once held are hashed, so a project folder
|
|
391
|
-
colliding on a retired name costs the walk no reads. The cost is that a file the
|
|
392
|
-
toolkit shipped and the target renamed goes unmatched, the same limit the
|
|
393
|
-
`unmigrated` count carries.
|
|
394
|
-
|
|
395
|
-
#### What counts toward the gate
|
|
396
|
-
|
|
397
|
-
`unmigrated` counts toward `--exit-code`, since running the relocation closes it.
|
|
398
|
-
`superseded` and every seed state are excluded, for the reason `orphaned` already
|
|
399
|
-
is: only the user can move content they wrote, so failing a job on it leaves the
|
|
400
|
-
job red with no mechanical remedy.
|
|
401
|
-
|
|
402
|
-
`newRules` is excluded on a different ground, since a command does close it. What
|
|
403
|
-
excludes it is that installing a rule changes what a project is governed by, so
|
|
404
|
-
gating on the count would pressure a target into adopting rules nobody chose.
|
|
405
|
-
`newSkills` is excluded because it needs no command at all.
|
|
406
|
-
|
|
407
|
-
The whole `reverse` section is excluded on the same grounds, and more strongly.
|
|
408
|
-
Every entry in it is a judgment about a file the project may own, and one of its
|
|
409
|
-
three verdicts is a labelled unknown by design. The unmigrated detection shipped
|
|
410
|
-
that exact false positive once, failing a push with no action that cleared it,
|
|
411
|
-
so this section reports and gates nothing.
|
|
231
|
+
applies any of them. What each reports, the managed-target gate they share, and
|
|
232
|
+
which count toward `--exit-code` are in `drift-surfaces.md`.
|
|
412
233
|
|
|
413
234
|
## Bootstrap
|
|
414
235
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markdown audit weight
|
|
3
|
+
description: The structural half of the markdown audit, being bullet and paragraph weight, run depth, the two cadence numbers, and the length ceiling, with the samples behind each checkpoint and why none of them gates
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Markdown audit weight
|
|
7
|
+
|
|
8
|
+
## Bullets, paragraphs, and depth
|
|
9
|
+
|
|
10
|
+
Bullet weight and depth are the checks that moved off `canon context audit`, carrying what they measured at the time. A top-level bullet reports past roughly 400 characters with continuation lines folded in and nested items left out. A run reports past roughly 40 rendered lines, measured at 80 columns, where a heading breaks one and so does a bold section marker taking the whole line at column zero, either ending in a colon, or holding one whole code span at any width, or running to 20 characters or fewer, skipping fenced blocks and exempting a flat peer list averaging under 130 characters a bullet and a run that is entirely table rows. Each file reports its longest run alone, so a second run past the checkpoint in the same file is never named.
|
|
11
|
+
|
|
12
|
+
Every weight and depth measure counts the text a reader is shown. A link reduces to its anchor text and an autolink drops whole, since no reader is shown either destination. A backticked path stays counted, which is where these measures part from the ban scan `markdown-audit.md` describes: that one blanks a code span so a standard quoting its own banned character does not report itself, and discounting the same span here would under-report a paragraph carrying several. One file holds both span sets and each answers its own question.
|
|
13
|
+
|
|
14
|
+
A code span is walked around rather than through, so a path quoting link or angle-bracket syntax keeps the width the page gives it. Masking inside one takes back the decision to count it, and the placeholders this toolkit writes are where that shows.
|
|
15
|
+
|
|
16
|
+
The paragraph check measures both halves of one rule. `markdown.md` caps a paragraph at four sentences, and a sentence cap on its own is satisfied by writing fewer and longer ones: 15 paragraphs in this corpus sit inside four sentences and past the weight checkpoint, and the heaviest of those runs 886 characters. The standard therefore states a weight beside the sentence cap, and the verb reads it as its own checkpoint.
|
|
17
|
+
|
|
18
|
+
A sentence boundary closes on terminal punctuation ahead of a capital or a code span. The capital is what keeps a version pin and a decimal from each reading as two sentences, and the code span is admitted beside it because a command name opening a sentence carries no capital to find.
|
|
19
|
+
|
|
20
|
+
The paragraph weight sits at 700 and the bullet weight at 400. Both shipped at 400, because the paragraph number was borrowed from the bullet rule when the two checks landed together, and each has since been read against a sample of its own. They are separate checkpoints in the standard and separate patterns in the parser, so a read that moves one leaves the other where it is.
|
|
21
|
+
|
|
22
|
+
### The sample behind the paragraph number
|
|
23
|
+
|
|
24
|
+
The checkpoint shipped at 400 as a borrowed number and was decided against a read of the prose it reports. Thirty-six findings were sampled, six from each of six weight bands, drawn at even spacing through each band ordered by path and line, and each was classed as prose a reader wants split or prose the checkpoint should not have reported.
|
|
25
|
+
|
|
26
|
+
Every band below was measured before the scan stopped counting link syntax as prose, so a paragraph sitting in one of these bands is heavier than a paragraph reported at the same number today. The re-sample in the section below re-reads the same range against the corrected measure and reaches the opposite verdict on it, which is the measure moving rather than the reader.
|
|
27
|
+
|
|
28
|
+
| Band | Wants the split | Reads as written |
|
|
29
|
+
| --------- | --------------- | ---------------- |
|
|
30
|
+
| 400 - 425 | 1 | 5 |
|
|
31
|
+
| 425 - 450 | 2 | 4 |
|
|
32
|
+
| 450 - 500 | 2 | 4 |
|
|
33
|
+
| 500 - 600 | 2 | 4 |
|
|
34
|
+
| 600 - 750 | 6 | 0 |
|
|
35
|
+
| Past 750 | 6 | 0 |
|
|
36
|
+
|
|
37
|
+
Precision is what moved the number rather than the finding count. Below 600 the checkpoint was right about seven of twenty-four sampled paragraphs, and past 600 it was right about all twelve. A checkpoint is a prompt to look, and a prompt wrong three times in four teaches a reader to stop looking. The distribution offers no seam to place the number against, with a median of 487 and a seventy-fifth percentile of 563, so the read is the whole of the evidence.
|
|
38
|
+
|
|
39
|
+
Nothing inside the 500 to 600 band separated the two classes by length, which is the reason the number did not land there. The two paragraphs wanting a split ran 543 and 590 characters against four reading well at 515, 532, 555, and 569.
|
|
40
|
+
|
|
41
|
+
The sample is thirty-six paragraphs against a reported population in the hundreds, and one reader classed all of them. Treat a band's rate as the order of magnitude it is rather than as a measured precision, and re-sample before moving the number again.
|
|
42
|
+
|
|
43
|
+
### The re-sample that moved the number to 700
|
|
44
|
+
|
|
45
|
+
That re-sample ran once the scan stopped counting link syntax as prose. Findings at 604, 633, and 677 characters each read as an ordinary four-sentence paragraph on one topic, density arrived around 760 and was plain by 860, and the move cut the weight half of the report roughly in half while leaving the sentence cap untouched.
|
|
46
|
+
|
|
47
|
+
A bullet, a heading, a table row, a blockquote, a blank line, and a fence each end a paragraph, so a heavy bullet is reported by the bullet check alone and never counted twice.
|
|
48
|
+
|
|
49
|
+
## Cadence
|
|
50
|
+
|
|
51
|
+
Uniform cadence is the failure a ban list cannot express. A ban set states negatives, and fragments, verbless clauses, and sentences that all run one length are each the absence of something, so no word added to a ban list reaches any of them. The shape layer already measured a bullet, a paragraph, and a run, and stopped one level above where that failure lives.
|
|
52
|
+
|
|
53
|
+
Cadence measures a paragraph on two numbers. The spread is the words between its longest and shortest sentence, and the opener count is the times one word opens a sentence in it. A spread of five words or under reads as one cadence, and a word opening more than two sentences is a pattern rather than a coincidence. Both come from `## Rhythm` in the `write-human` skill, which states them about prose a person reads, and this measures against that statement rather than setting a threshold of its own.
|
|
54
|
+
|
|
55
|
+
Words are counted off the text a reader is shown. A link contributes its anchor text, an autolink contributes nothing, and the sentence boundaries do not move under that masking, since the boundary pattern requires whitespace after the terminal punctuation and no destination carries any. An opening word is lowercased and stripped of punctuation, so a sentence opening on a backticked command name reports the command.
|
|
56
|
+
|
|
57
|
+
A paragraph carrying fewer than three sentences is skipped rather than scored. A two-sentence configuration note has no spread worth reading, and the opener rule is written about a third sentence turning a coincidence into a pattern, so neither number says anything before the floor. That is the cheap form of a wider exemption: a shape-aware one, exempting a short reference block by what it is rather than by how many sentences it holds, waits on a second case.
|
|
58
|
+
|
|
59
|
+
The unit is the paragraph and each file names its worst on each measure, which follows the depth check rather than setting a precedent. A file's flattest paragraph and its most repetitive one are named only when each crosses its checkpoint, so a file reading healthy names nothing rather than offering its least healthy paragraph as a finding.
|
|
60
|
+
|
|
61
|
+
Neither number gates and neither names a file wrong. This is a weaker claim than the one the weight checkpoints make, because a healthy range differs by surface: a catalog entry is several short sentences carrying one fact each, and a page arguing a decision is not, so one range applied across the corpus would report the surfaces that are correct. The run therefore states where the numbers came from beside them, and the counts are what a reader compares against.
|
|
62
|
+
|
|
63
|
+
A reading of that spread across the whole corpus is what backs the range above, taken once against this repository's own tracked markdown rather than against a target project's.
|
|
64
|
+
|
|
65
|
+
That reading travels with the command rather than staying here. `BASELINE` in `src/markdown/structure.ts` carries the overall share, the per-file range, and the ten-paragraph floor beneath which a file's own rate says nothing, and the run prints all four in the legend beside the rate it measured. A count with no range beside it reads as a finding, and naming that a healthy range differs by surface states that a range exists rather than what it looks like. This page is toolkit-internal, so a reader running the command in a project that installed no standards would otherwise have two counts and nothing to place them against.
|
|
66
|
+
|
|
67
|
+
Two of the rules `write-human` states are deliberately not implemented. A sentence's grammatical shape and whether it carries a finite verb each need a parse rather than a match, and an imperative would read as a defect under a pattern that approximated either. The verbless share is the measure closest to the reported symptom, which is exactly why shipping it wrong would discredit the two that hold.
|
|
68
|
+
|
|
69
|
+
The condition on that was something identifying a finite verb rather than guessing at one, and two parsers have now been run against it over 11,389 paragraph sentences. They disagree by a factor of four. `compromise` reports 2 percent and reads a fronted past participle as a finite verb, so `Measured at <sha> on <date>.` counts as carrying one. `wink-pos-tagger` reports 9 percent, fixes that class, and is still wrong on roughly three in four, because an imperative's verb tags as a proper noun and a noun-ambiguous predicate tags as a noun, which makes `Each maps to a skill.` read verbless. Separating those needs to know which token is the predicate, and that is syntax rather than a tag. The measure stays unimplemented, now against a mechanism rather than against the idea of one.
|
|
70
|
+
|
|
71
|
+
## Length
|
|
72
|
+
|
|
73
|
+
The Length step sums rendered lines over the whole source, frontmatter and fenced blocks included, and lists each document past the 300-line ceiling, longest first. A changelog and a document carrying a whole-line `<!-- canon-length-exempt: <reason> -->` outside a fence are counted in one line rather than listed. Each `--json` entry carries `renderedLines` and `exempt`, the stated reason or `null`, and `checkpoints` carries `ceiling`.
|