@erclx/canon 4.121.0 → 4.122.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 +1 -1
- 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-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 +1 -1
- package/claude/skills/memory-capture/REQUIREMENT.md +2 -2
- package/claude/skills/memory-capture/SKILL.md +5 -5
- package/claude/skills/memory-review/REQUIREMENT.md +1 -1
- package/claude/skills/memory-review/SKILL.md +5 -101
- package/claude/skills/memory-review/references/later-phases.md +108 -0
- 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/references/orchestrator-dispatch.md +1 -1
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -0
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +2 -2
- package/claude/skills/session-resume/REQUIREMENT.md +1 -1
- 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 +6 -80
- 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 +147 -0
- package/docs/agents/tasks-validate.md +131 -0
- package/docs/agents/tasks.md +6 -333
- package/docs/target-projects.md +3 -3
- package/docs/workflow/ai-workflow.md +32 -27
- 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/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/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 +28 -4
- package/src/tasks/record.ts +1 -1
- package/src/tasks/validate.ts +36 -3
- package/standards/memory.md +13 -1
- package/standards/tasks.md +1 -1
- package/tooling/astro/reference.md +1 -1
- package/tooling/base/configs/.husky/post-merge +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,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Decline a task
|
|
3
|
+
description: How task-board gathers the reason a task is decided against, runs canon tasks decline, routes each refusal, and clears prose naming the declined task
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Decline a task
|
|
7
|
+
|
|
8
|
+
The Decline mode of `task-board`. The session reads this file when the request names a task decided against.
|
|
9
|
+
|
|
10
|
+
A task decided against carries no `post-merge` hook of its own, so every decline request arrives here directly rather than through work the hook already did.
|
|
11
|
+
|
|
12
|
+
Do not move the file, edit `priority.md` or `backlog.md`, or regenerate the index by hand. `canon tasks decline` owns all three as one unit.
|
|
13
|
+
|
|
14
|
+
## Step 1: gather the reason
|
|
15
|
+
|
|
16
|
+
Ask for the reason when the request does not carry one, and stop rather than guessing: `❌ No reason. Say why the task is being declined.` The command takes it as `--reason <text>` and refuses without it, so gathering it here saves a round trip through that refusal.
|
|
17
|
+
|
|
18
|
+
## Step 2: run the decline
|
|
19
|
+
|
|
20
|
+
Pass the task's filename stem:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
canon tasks decline <stem> --reason "<text>" [--by <name>] --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The command refuses rather than reports, and the refusal reaches this skill through the record rather than through the exit, the same wrapper hazard `canon tasks archive` carries. Branch on `ok`, then on `reason`.
|
|
27
|
+
|
|
28
|
+
On success the record carries `from`, `to`, `priorityRowRemoved`, `backlogRowRemoved`, and `indexRegenerated`, where `backlogRowRemoved` is decline's own field since a task can be declined straight off `backlog.md` and archive never checks that file. It also carries `plan` when the task was the last live citation of a live plan, holding the `from` and `to` of the plan moved alongside it, the same shape `canon tasks archive` uses for its own `plan` field.
|
|
29
|
+
|
|
30
|
+
## Step 3: route on a refusal
|
|
31
|
+
|
|
32
|
+
- `no-match`: the stem does not name exactly one task. Either none matches, or exactly one starts with it and the full name is needed. Check the name against the listed stems.
|
|
33
|
+
- `ambiguous`: the stem is a prefix more than one task starts with, unlike archive's own `ambiguous`, which fires on a shared pull request. Decline takes no pull-request selector, so this is the only route to it. Pass the full stem.
|
|
34
|
+
- `bad-input`: the command line was wrong rather than the board. Read the message, fix the arguments, and run it again. Nothing on the board needs repair, which is what separates this from the two above.
|
|
35
|
+
|
|
36
|
+
Do not move a plan by hand from this skill. The command carries the plan with the task when no other live task cites it, and retargets the declined task's `Plan:` line at the new path. A second mover drifts into relocating the same file differently.
|
|
37
|
+
|
|
38
|
+
## Step 4: clear prose naming the task
|
|
39
|
+
|
|
40
|
+
The command drops the task's row from `.canon/tasks/priority.md` or `.canon/tasks/backlog.md` and leaves prose alone. Remove any sentence that still names the declined task or counts the rows that changed, since a stale count reads as board state.
|
|
@@ -9,7 +9,7 @@ argument-hint: <subject to learn, or the topic of a workspace to resume or promo
|
|
|
9
9
|
|
|
10
10
|
Run a learning workspace on one subject across sessions. The workspace holds what the learner has been through, so a session weeks later resumes from the folder rather than from the conversation.
|
|
11
11
|
|
|
12
|
-
The shape of the workspace is fixed by `${CLAUDE_SKILL_DIR}/../../standards/teach.md`. Read it before writing anything into the folder. The glossary answers to `${CLAUDE_SKILL_DIR}/../../standards/glossary.md
|
|
12
|
+
The shape of the workspace is fixed by `${CLAUDE_SKILL_DIR}/../../standards/teach.md`. Read it before writing anything into the folder. The glossary answers to `${CLAUDE_SKILL_DIR}/../../standards/glossary.md` wherever it lands. The pedagogy sits in `${CLAUDE_SKILL_DIR}/references/pedagogy.md`, the lesson craft in `${CLAUDE_SKILL_DIR}/references/lesson-craft.md`, and the promotion routing in `${CLAUDE_SKILL_DIR}/references/promotion.md`.
|
|
13
13
|
|
|
14
14
|
## Guards
|
|
15
15
|
|
|
@@ -77,9 +77,7 @@ A claim nothing was read for is the failure this step exists against. Where no s
|
|
|
77
77
|
|
|
78
78
|
Pick the next lesson from the learning records rather than from the subject's own order. The target is the band immediately past what the learner can already do unaided, which `${CLAUDE_SKILL_DIR}/references/pedagogy.md` states in full.
|
|
79
79
|
|
|
80
|
-
Open on what `due` reports as overdue, oldest date first, before anything new. Where nothing is overdue, open on retrieval of what the last session got wrong. A learner who cannot retrieve the previous lesson is not ready for the next one, and moving on anyway buys fluency that decays.
|
|
81
|
-
|
|
82
|
-
Reading the last record alone is what the schedule replaces. A topic missed three sessions ago and never revisited is invisible to that read and sits in `due` with a date already past, which is the whole reason the field exists.
|
|
80
|
+
Open on what `due` reports as overdue, oldest date first, before anything new. Where nothing is overdue, open on retrieval of what the last session got wrong. A learner who cannot retrieve the previous lesson is not ready for the next one, and moving on anyway buys fluency that decays. Never place from the last record alone, since a topic missed three sessions ago is invisible to that read and sits in `due` with a date already past.
|
|
83
81
|
|
|
84
82
|
## Step 4: write the lesson and the reference
|
|
85
83
|
|
|
@@ -103,69 +101,11 @@ It writes nothing and reports three things:
|
|
|
103
101
|
- `success`, the mission's success lines, carried here so Step 5 needs no second read.
|
|
104
102
|
- `quiz`, one entry per question, carrying `order` and `answer`.
|
|
105
103
|
|
|
106
|
-
Write the correct option first, then present the options in the order `order` reports, reading it as authored indices where `0` is the correct one. Take the order as given
|
|
107
|
-
|
|
108
|
-
### The quiz and the teach-back block
|
|
109
|
-
|
|
110
|
-
The quiz markup is a contract rather than a convention. `canon teach nav` splices a stepper into the lesson that gates on exactly the class names and nesting `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` states under `## Quiz construction`, so a quiz in any other shape shows every question at once and nothing reports it. That is the leak this shape closes: a later stem naming what an earlier question asked for answers it while both sit on screen.
|
|
111
|
-
|
|
112
|
-
Write each option as a `<label class="opt" data-k="<letter>">` holding a radio `<input>` and a `<span>`, every option in one question sharing a `name` and each question taking a different one, the correct option carrying `data-a="1"`, and one `.fb` block as the last child of the `.q`. Never write a `<button class="opt">` in a new lesson. That is the shape written before the stepper, kept working by an injected script the button itself still triggers, and a lesson mixing the two gets both mechanisms.
|
|
113
|
-
|
|
114
|
-
Then carry a teach-back block beside the quiz. A quiz is recognition and the pedagogy prefers production, so a lesson offering only a quiz tests the weak form. Ask for an explanation to a named audience, and carry a `<details>` listing what a complete explanation covers, closed by default, so a learner reading with no session in the room can grade themselves. The reference states both shapes in full.
|
|
115
|
-
|
|
116
|
-
Compose the quiz and the teach-back block as one string. Below, that string is the block list's last `raw` entry, followed only by `refs`, rather than markup written into the file by hand.
|
|
117
|
-
|
|
118
|
-
### Building the lesson body
|
|
119
|
-
|
|
120
|
-
Write the chrome as four empty marker pairs rather than composing it by hand: `<!-- canon:teach:style -->`/`<!-- /canon:teach:style -->` inside `<head>`, and `<!-- canon:teach:header -->`, `<!-- canon:teach:footnav -->`, and `<!-- canon:teach:scripts -->` each with its own close marker, in that order in `<body>`.
|
|
121
|
-
|
|
122
|
-
Build the authored `<h1>`, lede, body, and quiz as a JSON array of blocks rather than composing markup by hand, and render it through the verb rather than through a component import:
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
echo '[
|
|
126
|
-
{"type":"heading","level":1,"text":"<title>"},
|
|
127
|
-
{"type":"paragraph","lede":true,"text":"<the dek>"},
|
|
128
|
-
{"type":"paragraph","text":"<a body paragraph>"},
|
|
129
|
-
{"type":"paragraph","text":"<a claim resting on a source>","cites":[1]},
|
|
130
|
-
{"type":"list","ordered":true,"items":["<step one>","<step two>"]},
|
|
131
|
-
{"type":"raw","html":"<the quiz and teach-back block composed above>"},
|
|
132
|
-
{"type":"refs","items":[{"title":"<source name>","url":"<https URL>"}]}
|
|
133
|
-
]' | canon teach render --json
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
A `heading`, a `paragraph` (`lede: true` for the dek, `cites` for a claim resting on a source), a `list`, and the one `refs` block the cites number into cover the structural body. Reach for `raw` only where none of those can carry the content, never as a shortcut around composing one, and give the quiz and teach-back block the array's last `raw` entry every time, followed only by `refs`, since their fixed contract is not a components concern. Take the call's `html` field and write it between the header's close marker and the footnav's open marker, and nothing else anywhere in the file.
|
|
137
|
-
|
|
138
|
-
Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it, and never compose the lesson body by hand as a fallback. That is the state this section exists to end, and a target holds this skill body before it holds the verb, since a plugin skill reaches a target the moment it merges while the CLI reaches one only when a release publishes.
|
|
139
|
-
|
|
140
|
-
Then run:
|
|
141
|
-
|
|
142
|
-
```bash
|
|
143
|
-
canon teach nav <topic> --json
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
It fills every marker pair from what the workspace holds on disk: the embedded stylesheet, the header with its breadcrumb and jump menus, the prev/next footer nav, and the behavior scripts, and it rewrites the workspace's contents page and the teach-root listing in the same run. It refuses a lesson missing one of the four marker pairs by name rather than guessing at the boundary, so a marker dropped while writing the lesson is caught here rather than read back later as a lesson nothing links to. Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it, and never compose the chrome by hand as a fallback.
|
|
147
|
-
|
|
148
|
-
Seed the stylesheet through the verb rather than authoring a palette, on the first lesson in a workspace:
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
canon teach stylesheet <topic> --json
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
It writes the design tokens as custom properties and the components built on them, from the one source every other rendered surface reads. Add lesson rules under the seed and reach a value through its property rather than restating the hex, which is what let each workspace fork the palette from every other. It refuses to overwrite, so running it again on a workspace that has grown its own rules is safe and reports `written` as false.
|
|
104
|
+
Write the correct option first, then present the options in the order `order` reports, reading it as authored indices where `0` is the correct one. Take the order as given, since a lesson that reorders on its own judgment puts the answer back in the first slot.
|
|
155
105
|
|
|
156
|
-
|
|
106
|
+
### The quiz, the teach-back block, and the lesson body
|
|
157
107
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```bash
|
|
161
|
-
canon teach glossary <topic> --json \
|
|
162
|
-
--term "<term>=<definition, written without using the term>" \
|
|
163
|
-
--first-seen <the lesson or reference page this batch comes from>
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
`--term` repeats and one call writes the file once, which is what keeps a batch of terms from racing on it. A term already defined is refused, since a definition the subject has moved under is a revision of the entry rather than a second one.
|
|
167
|
-
|
|
168
|
-
Follow `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` for what makes a lesson worth returning to. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct.
|
|
108
|
+
Read `${CLAUDE_SKILL_DIR}/references/lesson-craft.md` before writing the lesson. `## Quiz construction` and `## Teach back` there fix the markup `canon teach nav`'s stepper gates on, so a quiz in any other shape shows every question at once and nothing reports it. `## Building the lesson body` carries the four marker pairs, the render, nav, stylesheet, and glossary verbs, and the rule against composing any of them by hand when a verb does not resolve. Keep every quiz answer the same length, so formatting leaks no clue about which one is correct.
|
|
169
109
|
|
|
170
110
|
### Hand over a link, never a path
|
|
171
111
|
|
|
@@ -209,37 +149,7 @@ Then restate the mission's success lines with what is now met, reading them from
|
|
|
209
149
|
|
|
210
150
|
Run this when the invocation asks for it, or offer it in one line when a mission finishes, since that is when the workspace stops growing and its reference pages stop changing. Never run it unasked mid-course.
|
|
211
151
|
|
|
212
|
-
Read `${CLAUDE_SKILL_DIR}/references/promotion.md` first. It carries what may be promoted, the routing test, both spellings of the wiki folder, the refusal when a project has none,
|
|
213
|
-
|
|
214
|
-
Propose and wait. A promoted page is public prose that needs a line naming who owns its subject, which is a judgment about ownership rather than a move a session makes on its own reading. Present one block per candidate page:
|
|
215
|
-
|
|
216
|
-
```plaintext
|
|
217
|
-
reference/<slug>.md → <destination path>
|
|
218
|
-
Subject owner: <who owns it, in a few words>
|
|
219
|
-
Still owed: <what the destination expects that the page does not carry yet>
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
Then stop and let the operator strike, redirect, or confirm each block.
|
|
223
|
-
|
|
224
|
-
Write nothing to a destination here. One skill owns the durable writes, and two skills editing one file at one step is the failure that rule exists against. Record each confirmed block in `.canon/tmp/handoff/teach-promotion/<slug>.md` at the main worktree root instead, appending when the file exists, with one H2 per destination naming its path, the source page beneath it, and the page body fenced:
|
|
225
|
-
|
|
226
|
-
````markdown
|
|
227
|
-
## <destination path>
|
|
228
|
-
|
|
229
|
-
Source: .canon/teach/<nn>-<topic>/reference/<slug>.md
|
|
230
|
-
|
|
231
|
-
```markdown
|
|
232
|
-
<the page body as it should land, with the source line the destination expects>
|
|
233
|
-
```
|
|
234
|
-
````
|
|
235
|
-
|
|
236
|
-
The body is fenced rather than written bare because a reference page carries headings of its own, and the reader splits this file on its H2 lines. An unfenced body turns every section heading in the page into a destination naming no path. Open the body fence with four backticks so a page carrying a fenced code block of its own still closes where it should, and widen both fences together if it carries a four-backtick fence.
|
|
237
|
-
|
|
238
|
-
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
239
|
-
|
|
240
|
-
The handoff is its own file rather than a shared one. The routed-facts file another skill writes is deleted by whichever pass folds it, so a second producer's unread work goes with it, and a sibling path costs the folding skill one more read and removes the interaction.
|
|
241
|
-
|
|
242
|
-
An append is a whole-file operation, so send it as a heredoc, per Step 0. Then tell the operator that `/docs-fold` folds the file in from a branch. The proposal costs nothing tracked and runs anywhere, while the page it describes is a tracked file, so the fold is a worktree operation and the workspace it came from is not.
|
|
152
|
+
Read `${CLAUDE_SKILL_DIR}/references/promotion.md` first. It carries what may be promoted, the routing test, both spellings of the wiki folder, the refusal when a project has none, what each destination expects a page to carry, and under `## Proposing and handing off` the proposal block, the handoff file this step writes in place of any destination, and how the operator is told to fold it. Propose and wait, and write nothing to a destination here.
|
|
243
153
|
|
|
244
154
|
## Output
|
|
245
155
|
|
|
@@ -254,15 +164,8 @@ Open: [<the url the serve verb reported>](<the same url>)
|
|
|
254
164
|
|
|
255
165
|
Omit the reference line where the lesson produced no durable page. The open line is the one line that is never omitted, since it is the only route the learner has into the page, and it carries what `canon serve` reported rather than a URL composed here. Where the verb refused, that line names the refusal instead of a link.
|
|
256
166
|
|
|
257
|
-
Write that line as a markdown link carrying the URL as both its text and its target, rather than as a bare URL and never inside backticks
|
|
167
|
+
Write that line as a markdown link carrying the URL as both its text and its target, rather than as a bare URL and never inside backticks, since a code span is text the reader has to copy.
|
|
258
168
|
|
|
259
169
|
Emit every path from the project root, in the form the project's instruction file sets.
|
|
260
170
|
|
|
261
|
-
A promotion pass reports
|
|
262
|
-
|
|
263
|
-
```plaintext
|
|
264
|
-
➡️ Promoting: .canon/teach/<nn>-<topic>/reference/<slug>.md → <destination path>
|
|
265
|
-
→ Confirmed pages wait at .canon/tmp/handoff/teach-promotion/<slug>.md. Run /docs-fold from a branch to fold them in.
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
A pass where the operator confirmed nothing writes no handoff file and reports that alone.
|
|
171
|
+
A promotion pass reports the shape `${CLAUDE_SKILL_DIR}/references/promotion.md` gives at the end of `## Proposing and handing off` instead.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Lesson craft reference
|
|
3
|
-
description: Typography, restraint, quiz construction,
|
|
3
|
+
description: Typography, restraint, quiz construction, what makes a lesson worth returning to, and the verbs that build the lesson body
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Lesson craft reference
|
|
@@ -121,3 +121,53 @@ Pick values the material needs rather than values the project happens to hold. I
|
|
|
121
121
|
- The lesson states what it assumes. A returning reader can tell in one line whether they are in the right place.
|
|
122
122
|
- The hard part is named as the hard part. Material that flattens everything to one difficulty gives a returning reader nothing to navigate by.
|
|
123
123
|
- Nothing depends on the session it was written in. A lesson referring to what was discussed is unreadable a week later.
|
|
124
|
+
|
|
125
|
+
## Building the lesson body
|
|
126
|
+
|
|
127
|
+
Step 4 of `teach-workspace` reads this section before writing a lesson, after the lesson verb has resolved its path and quiz order. Write the chrome as four empty marker pairs rather than composing it by hand: `<!-- canon:teach:style -->`/`<!-- /canon:teach:style -->` inside `<head>`, and `<!-- canon:teach:header -->`, `<!-- canon:teach:footnav -->`, and `<!-- canon:teach:scripts -->` each with its own close marker, in that order in `<body>`.
|
|
128
|
+
|
|
129
|
+
Build the authored `<h1>`, lede, body, and quiz as a JSON array of blocks rather than composing markup by hand, and render it through the verb rather than through a component import:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
echo '[
|
|
133
|
+
{"type":"heading","level":1,"text":"<title>"},
|
|
134
|
+
{"type":"paragraph","lede":true,"text":"<the dek>"},
|
|
135
|
+
{"type":"paragraph","text":"<a body paragraph>"},
|
|
136
|
+
{"type":"paragraph","text":"<a claim resting on a source>","cites":[1]},
|
|
137
|
+
{"type":"list","ordered":true,"items":["<step one>","<step two>"]},
|
|
138
|
+
{"type":"raw","html":"<the quiz and teach-back block composed above>"},
|
|
139
|
+
{"type":"refs","items":[{"title":"<source name>","url":"<https URL>"}]}
|
|
140
|
+
]' | canon teach render --json
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`## The block list` above states each type and where `raw` belongs. Take the call's `html` field and write it between the header's close marker and the footnav's open marker, and nothing else anywhere in the file.
|
|
144
|
+
|
|
145
|
+
Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it, and never compose the lesson body by hand as a fallback. That is the state this section exists to end, and a target holds this skill body before it holds the verb, since a plugin skill reaches a target the moment it merges while the CLI reaches one only when a release publishes.
|
|
146
|
+
|
|
147
|
+
Then run:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
canon teach nav <topic> --json
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
It fills every marker pair from what the workspace holds on disk: the embedded stylesheet, the header with its breadcrumb and jump menus, the prev/next footer nav, and the behavior scripts, and it rewrites the workspace's contents page and the teach-root listing in the same run. It refuses a lesson missing one of the four marker pairs by name rather than guessing at the boundary, so a marker dropped while writing the lesson is caught here rather than read back later as a lesson nothing links to. Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it, and never compose the chrome by hand as a fallback.
|
|
154
|
+
|
|
155
|
+
Seed the stylesheet through the verb rather than authoring a palette, on the first lesson in a workspace:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
canon teach stylesheet <topic> --json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
It writes the design tokens as custom properties and the components built on them, from the one source every other rendered surface reads. Add lesson rules under the seed and reach a value through its property rather than restating the hex, which is what let each workspace fork the palette from every other. It refuses to overwrite, so running it again on a workspace that has grown its own rules is safe and reports `written` as false.
|
|
162
|
+
|
|
163
|
+
Report it rather than proceeding silently when the verb does not resolve, which is an installed CLI predating it. Do not fall back to writing a palette by hand.
|
|
164
|
+
|
|
165
|
+
Add every term the lesson defines to `GLOSSARY.md` through the verb, which places the entries alphabetically in the shape the standard fixes:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
canon teach glossary <topic> --json \
|
|
169
|
+
--term "<term>=<definition, written without using the term>" \
|
|
170
|
+
--first-seen <the lesson or reference page this batch comes from>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`--term` repeats and one call writes the file once, which is what keeps a batch of terms from racing on it. A term already defined is refused, since a definition the subject has moved under is a revision of the entry rather than a second one.
|
|
@@ -50,3 +50,44 @@ Each destination gates prose the workspace does not, so name what the page still
|
|
|
50
50
|
- **The page promoted into a new context entry.** Entries are created deliberately, so a promotion proposing one is proposing a domain rather than moving a page.
|
|
51
51
|
- **The glossary split across destinations.** Terms drawn from one subject move together or not at all, since an entry defining a term the other half uses strands both.
|
|
52
52
|
- **The workspace emptied on promotion.** Promotion copies rather than moves. The workspace stays readable to the learner who built it, and the page's later life belongs to its destination.
|
|
53
|
+
|
|
54
|
+
## Proposing and handing off
|
|
55
|
+
|
|
56
|
+
Step 6 of `teach-workspace` reads this section once the routing above has placed each page. Propose and wait. A promoted page is public prose that needs a line naming who owns its subject, which is a judgment about ownership rather than a move a session makes on its own reading. Present one block per candidate page:
|
|
57
|
+
|
|
58
|
+
```plaintext
|
|
59
|
+
reference/<slug>.md → <destination path>
|
|
60
|
+
Subject owner: <who owns it, in a few words>
|
|
61
|
+
Still owed: <what the destination expects that the page does not carry yet>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Then stop and let the operator strike, redirect, or confirm each block.
|
|
65
|
+
|
|
66
|
+
Write nothing to a destination here. One skill owns the durable writes, and two skills editing one file at one step is the failure that rule exists against. Record each confirmed block in `.canon/tmp/handoff/teach-promotion/<slug>.md` at the main worktree root instead, appending when the file exists, with one H2 per destination naming its path, the source page beneath it, and the page body fenced:
|
|
67
|
+
|
|
68
|
+
````markdown
|
|
69
|
+
## <destination path>
|
|
70
|
+
|
|
71
|
+
Source: .canon/teach/<nn>-<topic>/reference/<slug>.md
|
|
72
|
+
|
|
73
|
+
```markdown
|
|
74
|
+
<the page body as it should land, with the source line the destination expects>
|
|
75
|
+
```
|
|
76
|
+
````
|
|
77
|
+
|
|
78
|
+
The body is fenced rather than written bare because a reference page carries headings of its own, and the reader splits this file on its H2 lines. An unfenced body turns every section heading in the page into a destination naming no path. Open the body fence with four backticks so a page carrying a fenced code block of its own still closes where it should, and widen both fences together if it carries a four-backtick fence.
|
|
79
|
+
|
|
80
|
+
Derive `<slug>` per `${CLAUDE_SKILL_DIR}/../../standards/slug.md`. Fall back to `latest` on an empty result.
|
|
81
|
+
|
|
82
|
+
The handoff is its own file rather than a shared one. The routed-facts file another skill writes is deleted by whichever pass folds it, so a second producer's unread work goes with it, and a sibling path costs the folding skill one more read and removes the interaction.
|
|
83
|
+
|
|
84
|
+
An append is a whole-file operation, so send it as a heredoc, per the skill's Step 0. Then tell the operator that `/context-fold` folds the file in from a branch. The proposal costs nothing tracked and runs anywhere, while the page it describes is a tracked file, so the fold is a worktree operation and the workspace it came from is not.
|
|
85
|
+
|
|
86
|
+
A promotion pass reports this shape in place of the skill's Output block, one line per page the operator confirmed and one naming the handoff:
|
|
87
|
+
|
|
88
|
+
```plaintext
|
|
89
|
+
➡️ Promoting: .canon/teach/<nn>-<topic>/reference/<slug>.md → <destination path>
|
|
90
|
+
→ Confirmed pages wait at .canon/tmp/handoff/teach-promotion/<slug>.md. Run /context-fold from a branch to fold them in.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
A pass where the operator confirmed nothing writes no handoff file and reports that alone.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Architecture record
|
|
3
|
+
description: 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
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Architecture record
|
|
7
|
+
|
|
8
|
+
Four findings from `canon context audit` read `canon/ARCHITECTURE.md` rather than a folder, and only the first two are facts. The other checks the audit runs are in `context-audit-checks.md`.
|
|
9
|
+
|
|
10
|
+
The entry cap check counts the record's decisions against the cap it states for itself, in a clause of the form `This record holds at most 12 decisions.` Like the length check, the cap belongs to the record rather than to the toolkit, so a record stating none is measured and never gated. A decision is a `###` heading outside a fenced block, so the template a standard shows does not count, and a heading carrying two decisions counts once. The JSON record carries what it read as `architecture.entryCap`, absent where the record states no cap, and the audit catalog counts a record past it as `recordOverCount`.
|
|
11
|
+
|
|
12
|
+
The length check compares the record against the ceiling it derives for itself, and only a record that states its own allowances has one. No standard sets a length rule for this document, so the numbers belong to whichever record declares them. The check reads a frame allowance and an allowance per decision out of the record's own prose and puts the ceiling at the frame plus the allowance times the decision count. The JSON record carries what it read as `architecture.allowances` and the reading as `architecture.lines` against `architecture.ceiling`.
|
|
13
|
+
|
|
14
|
+
A record stating no such rule is measured and reported and never gated, which is the ordinary shape of a project that wrote an architecture record and no convention about its length. Holding a pair of numbers in the toolkit and gating every project against them would fail a record on a ceiling that project never agreed to, and the framed line would credit the rule to a file that does not state it.
|
|
15
|
+
|
|
16
|
+
What the derivation costs where it does apply is that the ceiling rises when a decision is added and falls for nothing, so the check passes exactly when the file grew. It gates anyway, because a record that states a limit for itself and makes it computable from a count has turned it into a fact, which is what separates it from every judgment the audit reports. A rewrite of the declaring sentence past the clauses the check reads falls back to reporting rather than to a stale ceiling, so the failure shows up in the run's own output.
|
|
17
|
+
|
|
18
|
+
The coverage report classifies each decision as carrying a countable claim, a structural invariant, or neither, then reports each testable entry against whether it names a check that exists. A countable claim carries a figure a run could recompute, and an invariant quantifies over a named tree closely enough that a walk could falsify it. A check is a `scripts/**.sh` path the entry spells that is on disk, or a `canon` invocation matching a registered audit, so coverage reads the entry rather than the tree and a claim some check happens to cover without the entry saying so reads as unchecked.
|
|
19
|
+
|
|
20
|
+
Three limits are stated on every run rather than hidden. The countable signal reads digits alone, so a measured claim written in words reads as uncounted. Entries are counted by heading, and one heading holding several decisions counts once. Nothing is stored, so an entry rewritten tomorrow is classified afresh the next time the verb runs and no verdict goes stale.
|
|
21
|
+
|
|
22
|
+
The report gates nothing. Deciding whether a sentence states a claim is a judgment no parser settles, so the output names candidates for a reader. This answers a different question from the verification anchors `standards/architecture.md` describes, which record that one cited number was re-read. That mechanism says whether a marked figure held, and this one says how much of the record could be checked at all.
|
|
23
|
+
|
|
24
|
+
The third finding is a word count, measured in words rather than lines: one figure for the whole record and one per decision. `standards/architecture.md` asks a session to judge the file's weight by reading it rather than by counting it, and reads the word figure alongside that judgment when one is available. A paragraph written one source line to a paragraph passes the rendered-line measure other checks use while still reading heavy, which is the gap a word count closes without turning into a second cap.
|
|
25
|
+
|
|
26
|
+
The `## Risks / open questions` section is weighed the same way, reported apart from the whole-record figure since the standard singles it out for holding only what is still open. This finding gates nothing under any mode. The JSON record carries the whole-record figure as `architecture.words`, the section figure as `architecture.risksWords` where the record carries the heading, and the per-decision figure as `architecture.decisions[].words`.
|