@journeykit/canon 0.30.0 → 0.32.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/dist/skills/SKILL.src.md +77 -32
- package/dist/skills/reference/brief-align.md +2 -2
- package/dist/skills/reference/brief-clarify.md +2 -2
- package/dist/skills/reference/brief-harden.md +2 -2
- package/dist/skills/reference/brief-polish.md +8 -8
- package/dist/skills/reference/brief-shape.md +40 -9
- package/dist/skills/reference/canon-authoring.md +6 -6
- package/dist/skills/reference/canon-gate.md +45 -36
- package/dist/skills/reference/canon-learn.md +2 -2
- package/dist/skills/reference/canon-plan-import.md +2 -2
- package/dist/skills/reference/canon-plugins.md +6 -6
- package/dist/skills/reference/canon-policy.md +7 -4
- package/dist/skills/reference/canon-report-dashboard.md +17 -10
- package/dist/skills/reference/canon-review.md +24 -24
- package/dist/skills/reference/canon-storage.md +2 -2
- package/dist/skills/reference/canon-subject.md +137 -103
- package/dist/skills/reference/role-implementer.md +52 -36
- package/dist/skills/reference/role-orchestrator.md +68 -38
- package/dist/skills/reference/role-planner.md +99 -45
- package/dist/skills/reference/role-reviewer.md +69 -43
- package/man/canon-adapter-authorize.1 +2 -2
- package/man/canon-adapter-validate.1 +2 -2
- package/man/canon-adapter.1 +2 -2
- package/man/canon-artifacts-move.1 +2 -2
- package/man/canon-artifacts-store.1 +2 -2
- package/man/canon-artifacts-verify.1 +2 -2
- package/man/canon-artifacts.1 +2 -2
- package/man/canon-brief-approve.1 +17 -5
- package/man/canon-brief-check.1 +2 -2
- package/man/canon-brief-show.1 +6 -3
- package/man/canon-brief.1 +8 -7
- package/man/canon-change-new.1 +4 -4
- package/man/canon-change.1 +3 -3
- package/man/canon-completion.1 +2 -2
- package/man/canon-context-pack-add.1 +2 -2
- package/man/canon-context-pack-show.1 +2 -2
- package/man/canon-context-pack-verify.1 +2 -2
- package/man/canon-context-pack.1 +2 -2
- package/man/canon-context.1 +2 -2
- package/man/canon-dashboard.1 +2 -2
- package/man/canon-demo-init.1 +2 -2
- package/man/canon-demo-review.1 +2 -2
- package/man/canon-demo.1 +2 -2
- package/man/canon-dispatch-begin.1 +10 -10
- package/man/canon-dispatch-diff.1 +2 -2
- package/man/canon-dispatch-end.1 +2 -2
- package/man/canon-dispatch.1 +2 -2
- package/man/canon-divergence-accept.1 +15 -6
- package/man/canon-divergence-add.1 +6 -6
- package/man/canon-divergence-defer.1 +6 -6
- package/man/canon-divergence-list.1 +2 -2
- package/man/canon-divergence-resolve.1 +6 -6
- package/man/canon-divergence.1 +2 -2
- package/man/canon-evidence-add.1 +16 -16
- package/man/canon-evidence-approval-payload.1 +10 -10
- package/man/canon-evidence-audit.1 +10 -10
- package/man/canon-evidence.1 +3 -3
- package/man/canon-export.1 +2 -2
- package/man/canon-feature-new.1 +6 -6
- package/man/canon-feature.1 +2 -2
- package/man/canon-finding-add.1 +11 -11
- package/man/canon-finding-close.1 +8 -8
- package/man/canon-finding-list.1 +4 -4
- package/man/canon-finding.1 +4 -4
- package/man/canon-format.1 +2 -2
- package/man/canon-gate-check.1 +2 -2
- package/man/canon-gate-install-hooks.1 +2 -2
- package/man/canon-gate-promote.1 +2 -2
- package/man/canon-gate.1 +2 -2
- package/man/canon-ingest-plans.1 +2 -2
- package/man/canon-ingest-records.1 +4 -4
- package/man/canon-ingest-sessions.1 +2 -2
- package/man/canon-ingest.1 +2 -2
- package/man/canon-init.1 +2 -2
- package/man/canon-inventory-sync.1 +2 -2
- package/man/canon-inventory.1 +2 -2
- package/man/canon-ledger-compact.1 +2 -2
- package/man/canon-ledger.1 +2 -2
- package/man/canon-migrate.1 +20 -3
- package/man/canon-plugin-sync.1 +2 -2
- package/man/canon-plugin.1 +2 -2
- package/man/canon-policy-approve.1 +9 -3
- package/man/canon-policy-show.1 +2 -2
- package/man/canon-policy.1 +2 -2
- package/man/canon-prompt-add.1 +2 -2
- package/man/canon-prompt-show.1 +2 -2
- package/man/canon-prompt.1 +2 -2
- package/man/canon-purge.1 +2 -2
- package/man/canon-query.1 +5 -5
- package/man/canon-regime-show.1 +2 -2
- package/man/canon-regime.1 +2 -2
- package/man/canon-report-build.1 +2 -2
- package/man/canon-report-check.1 +2 -2
- package/man/canon-report-snapshot.1 +2 -2
- package/man/canon-report.1 +2 -2
- package/man/canon-retrieve.1 +5 -5
- package/man/canon-review-change.1 +6 -6
- package/man/canon-review-scenario.1 +6 -6
- package/man/canon-review.1 +2 -2
- package/man/canon-scenario-new.1 +10 -10
- package/man/canon-scenario.1 +2 -2
- package/man/canon-schema.1 +2 -2
- package/man/canon-search.1 +104 -0
- package/man/canon-selftest.1 +2 -2
- package/man/canon-skills-check.1 +2 -2
- package/man/canon-skills-doctor.1 +2 -2
- package/man/canon-skills-install.1 +2 -2
- package/man/canon-skills-show.1 +2 -2
- package/man/canon-skills.1 +2 -2
- package/man/canon-status.1 +7 -2
- package/man/canon-strategy-approval-payload.1 +2 -2
- package/man/canon-strategy-promote.1 +2 -2
- package/man/canon-strategy-rollback.1 +5 -5
- package/man/canon-strategy.1 +2 -2
- package/man/canon-subject-adopt.1 +4 -4
- package/man/canon-subject-move.1 +5 -5
- package/man/canon-subject-new.1 +5 -5
- package/man/canon-subject-show.1 +2 -2
- package/man/canon-subject-unadopt.1 +5 -5
- package/man/canon-subject.1 +2 -2
- package/man/canon-task-done.1 +2 -2
- package/man/canon-task.1 +2 -2
- package/man/canon-tier-age.1 +2 -2
- package/man/canon-tier.1 +2 -2
- package/man/canon-trace.1 +56 -0
- package/man/canon.1 +8 -2
- package/package.json +4 -4
package/dist/skills/SKILL.src.md
CHANGED
|
@@ -26,33 +26,54 @@ a feature, a one-line request included. A human is needed once per scope:
|
|
|
26
26
|
|
|
27
27
|
- **The approval** (step 1). For a new subject or a scope change, the
|
|
28
28
|
human must approve the brief. Write the brief,
|
|
29
|
-
run `canon brief check` until it reports no blockers, then
|
|
30
|
-
|
|
29
|
+
run `canon brief check` until it reports no blockers, then show it, ask and
|
|
30
|
+
record the answer: build nothing for that scope (no
|
|
31
31
|
scenarios, code or evidence) before the human answers. The approval is
|
|
32
32
|
the one thing you never assume, even when the human said they cannot
|
|
33
|
-
answer until you
|
|
33
|
+
answer until you show it. The one answer
|
|
34
34
|
approves the brief and the policy, `.canon/policy.yaml`, which is what
|
|
35
35
|
the gate grades the work against. The human may also approve it on the `canon dashboard` briefs page; you never use that form.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
1. **Show** with `canon brief show <slug> --body`: the brief file's bytes and,
|
|
37
|
+
last, `digest: sha256:<hex>`. Send it to the human's own view without
|
|
38
|
+
retyping it (omp: redirect it to `out://`, which is off for subagents and
|
|
39
|
+
non-TUI sessions and caps at 64 KiB; there, and in a harness with no such
|
|
40
|
+
channel, leave the tool output visible). A subagent has no question tool:
|
|
41
|
+
the orchestrator shows, asks and records.
|
|
42
|
+
2. **Ask** with the harness question tool (`ask` in omp, `AskUserQuestion` in
|
|
43
|
+
Claude Code, otherwise in the chat): approve or request changes, several
|
|
44
|
+
briefs in one question.
|
|
45
|
+
3. **Count only an explicit approval.** A question or a condition is a
|
|
46
|
+
revision request (change the brief, check, show and ask again); no answer
|
|
47
|
+
records nothing.
|
|
48
|
+
4. **Record it** with the relay option:
|
|
49
|
+
`canon brief approve <slug> <slug> --approver <their name> --note "<their words>" --relayed-via <ask|AskUserQuestion|chat> --actor <your actor id> --digest <slug>=<digest shown>`
|
|
50
|
+
(one or more slugs, each with its own `--digest`, one answer for all, nothing written if any is refused).
|
|
51
|
+
The `Approved:` line then carries `(relayed by <role> <actor> via <tool>)`.
|
|
52
|
+
A digest that no longer matches the brief is `RELAY_DIGEST_MISMATCH`: show
|
|
53
|
+
it again. Without `--relayed-via` an agent role gets `HUMAN_ONLY`, and so
|
|
54
|
+
does a repo whose `canon.yaml` says `approval: { relay: deny }`: then the
|
|
55
|
+
human runs the call themselves. Never remove or unset your role
|
|
56
|
+
(`env -u CANON_ROLE`, dropping `--as`) to run it yourself.
|
|
40
57
|
Never edit the policy to make the gate pass: a policy that differs from
|
|
41
58
|
the approved one fails closed (`POLICY_CHANGED_SINCE_APPROVAL`, not
|
|
42
59
|
waivable); stop and ask the human. A brief edited after its
|
|
43
60
|
approval is not approved (`BRIEF_CHANGED_SINCE_APPROVAL`): it needs a new
|
|
44
61
|
answer. The ship guard and `canon evidence add` refuse an unapproved or
|
|
45
62
|
edited brief, but those are backstops: the stop itself is at step 1.
|
|
46
|
-
- **Approval is scoped.** Evidence for a scenario
|
|
47
|
-
changes its
|
|
48
|
-
on a live subject waits on its own scenarios
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
- **Approval is scoped.** Evidence for a scenario tagged `@flow:<change>.<F-id>`
|
|
64
|
+
needs the approval of the changes its tags name only, so a new unapproved
|
|
65
|
+
change on a live subject waits on its own scenarios; an untagged scenario
|
|
66
|
+
answers to every change with an `Approved:` line (an edited one refuses); `change new` and
|
|
67
|
+
`subject adopt` warn when the subject is live. `canon subject unadopt <subject-id> --change <change>`
|
|
68
|
+
takes a draft change back off (refused once approved). The subject
|
|
69
|
+
answers for every adopted change that is tagged (a scenario of the subject
|
|
70
|
+
is tagged `@flow:<change>.*`), has an `Approved:` line, or is a chore:
|
|
71
|
+
reopen and ship pass only when all of them are approved now, whatever the
|
|
72
|
+
order they were adopted or approved in, and `canon status` lists one entry
|
|
73
|
+
per such change in `briefs`. A pending draft (never approved, not a chore,
|
|
74
|
+
tagged by no scenario) blocks nothing and the transition prints one line
|
|
75
|
+
naming every draft; a draft a scenario is tagged for blocks until it is
|
|
76
|
+
approved. `canon skills show canon-subject`
|
|
56
77
|
- **Inside an approved scope, never stop for a human.** Fixes, follow-ups,
|
|
57
78
|
review rounds and re-reviews stay in the approved change (never
|
|
58
79
|
`canon change new`: a new change is a new scope) and go straight on: scenario,
|
|
@@ -69,7 +90,7 @@ a feature, a one-line request included. A human is needed once per scope:
|
|
|
69
90
|
so in your report. That covers the brief's questions and work inside an
|
|
70
91
|
approved scope, never the approval itself.
|
|
71
92
|
|
|
72
|
-
1. **Brief.** The planner writes the PRD brief (`.canon/changes/<slug>/brief.md`), checks it with `canon brief check`,
|
|
93
|
+
1. **Brief.** The planner writes the PRD brief (`.canon/changes/<slug>/brief.md`), checks it with `canon brief check`, shows it to the human, asks, and records their explicit approval. `canon skills show role-planner`
|
|
73
94
|
2. **Subject.** `canon subject new`, then `canon change new` (`--change-kind chore` for work that alters no behavior); the change writes the brief skeleton. `canon skills show role-planner`
|
|
74
95
|
3. **Scenarios.** `canon scenario new --flow <F-id> --case <case>` per behavior of a flow step, failure paths (`--case failure`) included; many at once with `--input` (below). `canon skills show role-implementer`
|
|
75
96
|
4. **Units.** Split the work; one unit is one flow step's slice with a named verify command, and each unit has its own actor id and session id, passed on everything it records. A unit never attests another unit's work.
|
|
@@ -110,7 +131,7 @@ needs its change-level review alone. What counts as code is `code.exclude` in
|
|
|
110
131
|
`canon status`, `meta.next` and the refusal hint lead with one batch over
|
|
111
132
|
every report, for example
|
|
112
133
|
`canon evidence add --all-scenarios --report junit:a.xml --report junit:b.xml --role implementer`
|
|
113
|
-
(with the real report paths, and `--project
|
|
134
|
+
(with the real report paths, and `--project <id>` when the repo has several
|
|
114
135
|
spec roots), never a loop per scenario. With a `--report`, `--class` defaults
|
|
115
136
|
to `test-run` and `--ref` to the report paths, and the bound cases decide the
|
|
116
137
|
verdict: any failed case `divergent`, a skipped one and none failed
|
|
@@ -137,6 +158,25 @@ refuse, never pass, when it cannot be reached. Moving an existing store with
|
|
|
137
158
|
`canon artifacts move --tier <tier>` is the repo owner's decision, not a step
|
|
138
159
|
of the loop.
|
|
139
160
|
|
|
161
|
+
### Search and trace
|
|
162
|
+
|
|
163
|
+
`canon search "<text>"` finds a record, a brief section or flow step, or a
|
|
164
|
+
scenario's text (title, steps, tables, `Examples`, the Background and Rule it
|
|
165
|
+
inherits) and lists each hit with its neighbors in the record graph: the
|
|
166
|
+
records it names or that name it, the review loop around a finding, the brief
|
|
167
|
+
step a scenario covers. A reference no committed source holds is a neighbor
|
|
168
|
+
marked `placeholder`, never an error. `--kind` (repeatable) keeps hits of those
|
|
169
|
+
kinds, `--expand <N>` sets the hops (default 1), `--limit <N>` the hits (default
|
|
170
|
+
20). Korean is found from three characters; a shorter text is found as a part of
|
|
171
|
+
a node's text, in id order. The text is read as typed: quotes and `AND` are not
|
|
172
|
+
syntax. `canon trace <finding key|review id|sha>` follows the review, finding,
|
|
173
|
+
fix, re-review and evidence chain of a loop in time order, the archive's
|
|
174
|
+
earlier versions included. Both read, and first refresh, a derived index,
|
|
175
|
+
`.canon/index/search.db`: gitignored, never a source of records, safe to delete
|
|
176
|
+
(the next run rebuilds it, and only `data.index.rebuilt` differs). Records still
|
|
177
|
+
staged, and those in postgres or an object store, are not in it; `data.index`
|
|
178
|
+
names the stores not read.
|
|
179
|
+
|
|
140
180
|
## Know your role
|
|
141
181
|
|
|
142
182
|
canon cannot detect a role; you declare it. Pass `--as <role>` or set
|
|
@@ -175,7 +215,7 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
175
215
|
`warnings` and, for a repeated write that changed nothing, `unchanged: true`.
|
|
176
216
|
On failure branch on `error.code`, fix the option `error.field` names
|
|
177
217
|
using the `error.expected` values (`field` is an option name, or a JSON
|
|
178
|
-
pointer such as `/items/2/
|
|
218
|
+
pointer such as `/items/2/scenario` into an `--input` document), and
|
|
179
219
|
follow `error.hint`: every refusal carries a working invocation. The codes
|
|
180
220
|
are stable; `canon schema --errors --json` lists them and
|
|
181
221
|
`canon schema --error <CODE>` explains one.
|
|
@@ -185,22 +225,27 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
185
225
|
A refusal leaves the tree unchanged.
|
|
186
226
|
- Repeating a write is safe: a record that already exists with identical
|
|
187
227
|
content is reported `unchanged` (`meta.unchanged`), not duplicated.
|
|
188
|
-
-
|
|
189
|
-
`--
|
|
190
|
-
`--session-
|
|
228
|
+
- An option that takes an id is the bare noun (`--change add-login`,
|
|
229
|
+
`--scenario auth.login.01`, `--actor reviewer-1`, `--project root`,
|
|
230
|
+
`--session s-1`), and an `--input` document key is that name without `Id`
|
|
231
|
+
(`scenario`, `actor`; the stored record and report JSON keep `scenario_id`,
|
|
232
|
+
`scenarioId`). The primary object of a command is its operand
|
|
191
233
|
(`canon subject move <id> --to verifying`, `canon change new <slug>`), and
|
|
192
234
|
`--kind` values carry no `_record` suffix (`--kind evidence`).
|
|
193
235
|
- `canon status` sends the planner to write the brief while `brief check`
|
|
194
|
-
has blockers; the
|
|
236
|
+
has blockers; the approval step appears only when the brief is clean and
|
|
195
237
|
unapproved.
|
|
196
238
|
- Page long lists with `--limit <n>` and `--cursor <nextCursor>` (`--all`
|
|
197
239
|
for everything), and project fields with `--fields a,b` (`status`, `export`,
|
|
198
240
|
`query`, `finding list`, `divergence list`, `context`).
|
|
199
241
|
- `--override-reason <text>` is the only way to proceed past a waivable
|
|
200
242
|
refusal; it is recorded, echoed in `data.overrides[]` and listed by `status`
|
|
201
|
-
for the human. There is no `--force`. `brief approve`, `policy approve
|
|
202
|
-
`divergence accept`
|
|
203
|
-
|
|
243
|
+
for the human. There is no `--force`. `brief approve`, `policy approve`,
|
|
244
|
+
`divergence accept` and the `migrate --commit` that re-binds `Approved:`
|
|
245
|
+
lines record a human's decision and refuse every agent role (`HUMAN_ONLY`)
|
|
246
|
+
unless they record the explicit answer the human gave you, with
|
|
247
|
+
`--relayed-via <tool>` (show, ask, record, as for the brief; `canon skills
|
|
248
|
+
show role-planner`); never unset your role to run one.
|
|
204
249
|
|
|
205
250
|
### Many records at once: `--input`
|
|
206
251
|
|
|
@@ -218,8 +263,8 @@ before anything is written: an invalid element writes nothing and exits 2,
|
|
|
218
263
|
|
|
219
264
|
```text
|
|
220
265
|
canon scenario new --input '[{"operands":["auth.login.01"],"title":"Logs in","case":"happy"},{"operands":["auth.login.02"],"title":"Wrong password","case":"failure"}]'
|
|
221
|
-
canon evidence add --input '[{"
|
|
222
|
-
canon finding add --input '[{"
|
|
266
|
+
canon evidence add --input '[{"scenario":"auth.login.01","class":"test-run","ref":"npm test","role":"implementer"},{"scenario":"auth.login.02","class":"test-run","ref":"npm test","role":"implementer"}]'
|
|
267
|
+
canon finding add --input '[{"change":"add-login","round":1,"seq":1,"severity":"note","actor":"reviewer-1","summary":"Token is logged"},{"change":"add-login","round":1,"seq":2,"severity":"blocker","introducedUnknown":true,"actor":"reviewer-1","summary":"No rate limit"}]'
|
|
223
268
|
```
|
|
224
269
|
|
|
225
270
|
`--input` never carries `--commit` or `--plan-digest`, and the destructive
|
|
@@ -293,10 +338,10 @@ on the list.
|
|
|
293
338
|
|
|
294
339
|
- **Fix a bug:** the approved change if there is one, else the planner (`canon change new`); first a failing run of the scenario (`canon scenario new --case failure`, then `canon evidence add`), then the fix. `canon skills show role-implementer`.
|
|
295
340
|
- **Add or change a feature:** `canon subject new`, `canon change new`, then the brief. `canon skills show role-planner`.
|
|
296
|
-
- **Pure refactor, dependency, build, CI or infra:** `canon change new <slug> --subject
|
|
341
|
+
- **Pure refactor, dependency, build, CI or infra:** `canon change new <slug> --subject <id> --change-kind chore`; data or interface changes are not chores. `canon skills show role-planner`.
|
|
297
342
|
- **Review someone's change:** `CANON_ROLE=reviewer`, `canon brief check <slug>`. `canon skills show role-reviewer`.
|
|
298
343
|
- **Resume:** `canon status --json`, then follow `meta.next`. `canon skills show role-orchestrator`.
|
|
299
|
-
- **Plan more work on a live subject:** `canon change new <slug> --subject
|
|
344
|
+
- **Plan more work on a live subject:** `canon change new <slug> --subject <id>` (it warns until the brief is approved; `canon subject unadopt` parks a draft). `canon skills show canon-subject`, `canon skills show role-planner`.
|
|
300
345
|
- **Upgrade canon in a repo:** `canon migrate` (previews), then `canon migrate --commit --plan-digest <digest>`, then `canon skills install`. See "Upgrading a repo from 0.27" above and `canon skills show role-orchestrator`.
|
|
301
346
|
|
|
302
347
|
**Done when:** you have named your role and loaded its guide, and `canon status --json` lists your next step in `meta.next`.
|
|
@@ -317,7 +362,7 @@ current step needs.
|
|
|
317
362
|
| Name | What it is for |
|
|
318
363
|
| --- | --- |
|
|
319
364
|
| `canon` | This core guide: the loop, driving the CLI, routing. |
|
|
320
|
-
| `role-planner` | Planner steps 1–2: subject, change, PRD brief, the
|
|
365
|
+
| `role-planner` | Planner steps 1–2: subject, change, PRD brief, the approval. |
|
|
321
366
|
| `role-implementer` | Implementer steps 3–6: scenarios, units, code, evidence. |
|
|
322
367
|
| `role-reviewer` | Reviewer step 7: findings and signed reviews in a separate session. |
|
|
323
368
|
| `role-orchestrator` | Orchestrator step 8: dispatch, transitions, resuming, upgrading. |
|
|
@@ -33,7 +33,7 @@ A chore adds no scenarios and has no flow: this pass does not apply to it.
|
|
|
33
33
|
|
|
34
34
|
## Next
|
|
35
35
|
|
|
36
|
-
Implement, evidence and review (loop steps 5 to 7). If the brief had to change, the human answers again
|
|
36
|
+
Implement, evidence and review (loop steps 5 to 7). If the brief had to change, the human answers again: show the brief, ask, and record an explicit approval with `--relayed-via` (`canon skills show role-planner`).
|
|
37
37
|
|
|
38
38
|
## Invariants (every brief pass)
|
|
39
39
|
|
|
@@ -41,4 +41,4 @@ Implement, evidence and review (loop steps 5 to 7). If the brief had to change,
|
|
|
41
41
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
42
42
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
43
43
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
44
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
44
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -33,7 +33,7 @@ Every open line is a question with a proposed default or a stated assumption. `c
|
|
|
33
33
|
|
|
34
34
|
## Next
|
|
35
35
|
|
|
36
|
-
`harden` if the flow changed; otherwise
|
|
36
|
+
`harden` if the flow changed; otherwise put the questions and the brief to the human and ask; record an explicit approval with `brief approve` with `--relayed-via <tool>` (`canon skills show role-planner`).
|
|
37
37
|
|
|
38
38
|
## Invariants (every brief pass)
|
|
39
39
|
|
|
@@ -41,4 +41,4 @@ Every open line is a question with a proposed default or a stated assumption. `c
|
|
|
41
41
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
42
42
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
43
43
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
44
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
44
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -34,7 +34,7 @@ brief has none of them: harden its Invariants and Checks instead.
|
|
|
34
34
|
|
|
35
35
|
## Next
|
|
36
36
|
|
|
37
|
-
`align` (`canon skills show brief-align`) once scenarios exist; `polish` (`canon skills show brief-polish`) for prose; otherwise
|
|
37
|
+
`align` (`canon skills show brief-align`) once scenarios exist; `polish` (`canon skills show brief-polish`) for prose; otherwise show the brief to the human and ask (`canon skills show role-planner`).
|
|
38
38
|
|
|
39
39
|
## Invariants (every brief pass)
|
|
40
40
|
|
|
@@ -42,4 +42,4 @@ brief has none of them: harden its Invariants and Checks instead.
|
|
|
42
42
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
43
43
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
44
44
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
45
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
45
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Make the brief something a human reads once and understands. Run it whenever
|
|
4
4
|
`canon brief check` reports `prose.*` advisories; `canon status` and
|
|
5
|
-
`meta.next` name it before the
|
|
5
|
+
`meta.next` name it before the approval step. It never blocks approval, and it
|
|
6
6
|
is not finished by silencing rules: it is finished when the brief reads
|
|
7
7
|
plainly and each advisory is gone or waived with a reason.
|
|
8
8
|
|
|
@@ -151,7 +151,7 @@ still draws a finding. Never waive the rule for the whole section.
|
|
|
151
151
|
|
|
152
152
|
- en. Before: "On 3 March the team agreed on a grid as the default view." After: "The default view is a grid."
|
|
153
153
|
- ko. 전: "3월 3일 회의에서 기본 보기를 격자로 하기로 했다." 후: "기본 보기는 격자다."
|
|
154
|
-
- waive one date:
|
|
154
|
+
- waive one date: frontmatter entry `rule: prose.decision-history`, `section: detail`, `reason: "연체 요금은 2026-12-01부터 적용되는 동작이다"`, `match: "2026-12-01"`
|
|
155
155
|
|
|
156
156
|
What it misses: a decision written in other words ("회의에서 정한 대로" is not
|
|
157
157
|
listed on purpose, it reads as behavior). Over-reports: a date that is
|
|
@@ -209,8 +209,8 @@ uses the section key `brief`.
|
|
|
209
209
|
|
|
210
210
|
- `canon brief check --json`: read the `prose.*` findings, then the sections they sit in. Fix by section, not by rule.
|
|
211
211
|
- A finding is a prompt to reread, not a verdict. When the flagged text is the precise term (a state name, a quoted label, a command), keep it and waive that rule in that section:
|
|
212
|
-
|
|
213
|
-
To waive one finding and keep the rest of the rule live in that section, add the text the finding names
|
|
212
|
+
an entry of the frontmatter `waive` list: `- rule: <rule-id>`, `section: <section-key>`, `reason: "<reason>"`.
|
|
213
|
+
To waive one finding and keep the rest of the rule live in that section, add the text the finding names as `match: "<text>"` (an empty reason or match, an unknown rule id or an unknown key is a blocker).
|
|
214
214
|
A waiver is right when the text is a quotation or a fixed term, and wrong when it excuses a sentence you could simply rewrite. One rule, one section, a reason the human can read.
|
|
215
215
|
|
|
216
216
|
## The loop
|
|
@@ -218,13 +218,13 @@ uses the section key `brief`.
|
|
|
218
218
|
1. Fix the mode problems above, then the findings, section by section.
|
|
219
219
|
2. Run `canon brief check <slug> --json`: the findings are in `data.findings[]`.
|
|
220
220
|
3. Repeat until no advisory remains, or each remaining one is waived with a reason.
|
|
221
|
-
4. Stop and
|
|
221
|
+
4. Stop polishing and show the brief to the human (`canon brief show <slug> --body`), in the brief's language, and ask. Do not loop further: a clean run says nothing about whether the brief is good, only that these counts are within budget.
|
|
222
222
|
|
|
223
223
|
## NEVER
|
|
224
224
|
|
|
225
225
|
- Never change meaning: no flow step, rule, limit or failure path added, removed or softened while rewording.
|
|
226
226
|
- Never rewrite to dodge a rule (a near synonym, a list used to hide a long sentence); say the concrete thing.
|
|
227
|
-
- Never touch flow ids or subheadings, and never polish the
|
|
227
|
+
- Never touch flow ids or subheadings, and never polish the headings.
|
|
228
228
|
- Never translate the brief to match a `language:` setting.
|
|
229
229
|
- Never treat a clean run as a claim about who wrote the brief.
|
|
230
230
|
|
|
@@ -236,7 +236,7 @@ uses the section key `brief`.
|
|
|
236
236
|
|
|
237
237
|
## Next
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
Show the brief to the human and ask (`canon brief show <slug> --body`, then the harness question tool); record an explicit approval with `brief approve` with `--relayed-via <tool>` (`canon skills show role-planner`).
|
|
240
240
|
|
|
241
241
|
## Invariants (every brief pass)
|
|
242
242
|
|
|
@@ -244,4 +244,4 @@ Report to the human, who approves with `canon brief approve` (theirs; agent role
|
|
|
244
244
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
245
245
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
246
246
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
247
|
-
- Write in the brief's language (detected from the text, or `language:` in `canon.yaml` when set). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
247
|
+
- Write in the brief's language (detected from the text, or `language:` in `canon.yaml` when set). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -8,26 +8,57 @@ check reports `brief.section-missing`, `brief.section-duplicate`,
|
|
|
8
8
|
|
|
9
9
|
## Scope
|
|
10
10
|
|
|
11
|
-
`.canon/changes/<slug>/brief.md`: section
|
|
11
|
+
`.canon/changes/<slug>/brief.md`: section headings, order, and leftover
|
|
12
12
|
template text. A feature brief runs intent → outcome → flow → detail →
|
|
13
13
|
acceptance → questions → out-of-scope; a chore brief runs intent → category →
|
|
14
|
-
invariants → checks → out-of-scope (
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
invariants → checks → out-of-scope (`kind: chore` in the frontmatter). Sections
|
|
15
|
+
are found by their English `##` heading, whatever the brief's language; a
|
|
16
|
+
`##` line that is not one of the headings below is body text of the section
|
|
17
|
+
before it. `language:` only picks the language of the prose rules and the
|
|
18
|
+
guidance.
|
|
19
|
+
|
|
20
|
+
| Section | Heading | Role | What goes in it |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| intent | `## Intent` | context | What problem this solves, for whom, and why now. One to three sentences. |
|
|
23
|
+
| outcome | `## Desired outcome` | normative | What is observably true once this ships, from the user's side. |
|
|
24
|
+
| flow | `## User flow` | normative | A numbered list; each item starts with its id and reads sees → does → becomes: `1. F1 The user sees … → does … → becomes …`. |
|
|
25
|
+
| detail | `## Step detail` | normative | One `### F1 …` subheading per flow step, in the flow's order: rules, states and edge cases of that step. |
|
|
26
|
+
| acceptance | `## Acceptance` | normative | Per step: what must be observable, and which failure path is covered. Do not write scenario ids here. |
|
|
27
|
+
| questions | `## Questions and assumptions` | question | What is unresolved and what you assumed; anything that could change policy goes here. Write `None.` if nothing. |
|
|
28
|
+
| out-of-scope | `## Out of scope` | context | What this change deliberately does not do. Write `None.` if nothing. |
|
|
29
|
+
| category (chore) | `## Category` | context | Exactly one of `refactor`, `dependency`, `build`, `ci`, `infra`. |
|
|
30
|
+
| invariants (chore) | `## Invariants` | normative | What must not change: behavior, public interfaces, data, outputs. A change that alters any of them is a feature, not a chore. |
|
|
31
|
+
| checks (chore) | `## Checks` | normative | How you show the invariants held: the suite that is run again at the chore commit, and anything else you compare. |
|
|
32
|
+
|
|
33
|
+
`canon change new` writes the brief with these headings and nothing under
|
|
34
|
+
them: an empty section is a section not yet written, and `canon brief show`
|
|
35
|
+
prints the guidance of each empty one (in `language:`). A wrong heading
|
|
36
|
+
(`## Intnet`, `## intent`) is reported with the nearest heading.
|
|
17
37
|
|
|
18
38
|
## Inspect
|
|
19
39
|
|
|
20
40
|
- `canon brief check --json`: each finding names the rule, section key, line and hint.
|
|
21
|
-
- Every section present once, in order, with its
|
|
41
|
+
- Every section present once, in order, with its exact English heading; no `TODO`/`TBD`; no empty section (write `None.` where nothing applies).
|
|
22
42
|
- The flow is a numbered list with ids `F1`, `F2`, … each reading sees → does → becomes.
|
|
23
43
|
- Intent describes what the product does today and Outcome what is true after; leftover implementation paths belong in a `Source:` line or nowhere.
|
|
24
44
|
- A chore's category is exactly one of `refactor`, `dependency`, `build`, `ci`, `infra`; its invariants and checks say something.
|
|
25
|
-
-
|
|
45
|
+
- Waivers live in the frontmatter, visible on the page, and the approval covers them:
|
|
46
|
+
```
|
|
47
|
+
---
|
|
48
|
+
waive:
|
|
49
|
+
- rule: prose.length
|
|
50
|
+
section: brief
|
|
51
|
+
reason: "why the rule does not apply"
|
|
52
|
+
match: "optional text the finding contains"
|
|
53
|
+
---
|
|
54
|
+
```
|
|
55
|
+
Each entry has a known `rule`, a `section` key (or `brief`) and a non-empty `reason`; an unknown key is a blocker. Adding one after the approval is a change after the approval.
|
|
56
|
+
- A brief that still has `<!-- canon:… -->` comments or Korean headings is in the old format: `canon migrate` (preview first) rewrites it, and the human runs `--commit` when it re-binds an approval.
|
|
26
57
|
|
|
27
58
|
## NEVER
|
|
28
59
|
|
|
29
60
|
- Never fill a section with text you made up to silence a placeholder: write what the request and the repo support, and put the rest in Questions.
|
|
30
|
-
- Never delete a section,
|
|
61
|
+
- Never delete a section, rename a heading to another role, or add a global waiver to pass. A waiver is one rule in one section with a reason the human can read.
|
|
31
62
|
- Never turn a chore's missing invariants into "none" to pass: behavior-changing work is a feature change.
|
|
32
63
|
|
|
33
64
|
## Verify
|
|
@@ -38,7 +69,7 @@ marker, never by heading text.
|
|
|
38
69
|
|
|
39
70
|
## Next
|
|
40
71
|
|
|
41
|
-
`clarify` if the Questions section still has open lines; `harden` if flow and detail disagree; otherwise
|
|
72
|
+
`clarify` if the Questions section still has open lines; `harden` if flow and detail disagree; otherwise show the brief to the human and ask; record an explicit approval with `brief approve` with `--relayed-via <tool>` (`canon skills show role-planner`).
|
|
42
73
|
|
|
43
74
|
## Invariants (every brief pass)
|
|
44
75
|
|
|
@@ -46,4 +77,4 @@ marker, never by heading text.
|
|
|
46
77
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
47
78
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
48
79
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
49
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
80
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -84,7 +84,7 @@ enum, like `lane`.
|
|
|
84
84
|
## Subject pinning
|
|
85
85
|
|
|
86
86
|
Every scenario belongs to a Subject (the durable product unit, see
|
|
87
|
-
`canon-subject`). Write the Subject first, then pin with `--subject
|
|
87
|
+
`canon-subject`). Write the Subject first, then pin with `--subject`;
|
|
88
88
|
the scenario index carries the tag onto the index record and
|
|
89
89
|
`spec_coverage.scope` filters on it. An unpinned scenario is invisible to
|
|
90
90
|
a scoped gate.
|
|
@@ -94,9 +94,9 @@ a scoped gate.
|
|
|
94
94
|
```bash
|
|
95
95
|
canon feature new checkout.cart --title "Cart" # once per surface
|
|
96
96
|
canon scenario new checkout.cart.01 --title "Adding an item raises the count" \
|
|
97
|
-
--subject
|
|
97
|
+
--subject checkout-core --lane behavior --case happy # once per behavior
|
|
98
98
|
canon scenario new checkout.cart.04 --title "Adding an out-of-stock item is refused" \
|
|
99
|
-
--subject
|
|
99
|
+
--subject checkout-core --lane behavior --case failure # and its failure path
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
There is no format or sync step after these: the scaffold writes a
|
|
@@ -115,10 +115,10 @@ camelCase keys. `canon schema scenario new --json` shows the input schema
|
|
|
115
115
|
and an example. There is no `--from`.
|
|
116
116
|
|
|
117
117
|
```text
|
|
118
|
-
canon scenario new --input '[{"operands":["checkout.cart.01"],"title":"Adding an item raises the count","
|
|
118
|
+
canon scenario new --input '[{"operands":["checkout.cart.01"],"title":"Adding an item raises the count","subject":"checkout-core","lane":"behavior","case":"happy"},{"operands":["checkout.cart.04"],"title":"Adding an out-of-stock item is refused","subject":"checkout-core","lane":"behavior","case":"failure"}]'
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
- `--actor
|
|
121
|
+
- `--actor <id>` (or `CANON_ACTOR` in the environment) puts YOUR id on the
|
|
122
122
|
provenance line. Default is `canon-scaffold`.
|
|
123
123
|
- **Keep the `# canon:` lines when you fill in the scenario.** Dropping one
|
|
124
124
|
makes `canon inventory sync` abort on `missing-provenance`; restore it
|
|
@@ -160,7 +160,7 @@ wait for evidence, which `canon gate check` reports.
|
|
|
160
160
|
- **A Feature title that is a theme.** "Fidelity of the original
|
|
161
161
|
experience" names no surface. Name the screen.
|
|
162
162
|
- **Hand-stamped provenance.** Eighty lines with one timestamp and the
|
|
163
|
-
same `agent_id`. Use `canon scenario new --actor
|
|
163
|
+
same `agent_id`. Use `canon scenario new --actor`.
|
|
164
164
|
- **Coverage by splitting.** One behavior as two scenarios so two rows go
|
|
165
165
|
green. One behavior, one id.
|
|
166
166
|
- **Runner tags as classification.** `@design`, `@p2`, `@wip` are
|