@journeykit/canon 0.27.0 → 0.29.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 +245 -89
- package/dist/skills/reference/brief-align.md +4 -2
- package/dist/skills/reference/brief-clarify.md +7 -5
- package/dist/skills/reference/brief-harden.md +4 -2
- package/dist/skills/reference/brief-polish.md +7 -5
- package/dist/skills/reference/brief-shape.md +4 -2
- package/dist/skills/reference/canon-artifact-ingest.md +11 -7
- package/dist/skills/reference/canon-authoring.md +16 -2
- package/dist/skills/reference/canon-context.md +21 -11
- package/dist/skills/reference/canon-fmt.md +10 -2
- package/dist/skills/reference/canon-gate.md +107 -69
- package/dist/skills/reference/canon-inventory.md +23 -15
- package/dist/skills/reference/canon-learn.md +23 -19
- package/dist/skills/reference/canon-plan-import.md +10 -7
- package/dist/skills/reference/canon-plugins.md +15 -8
- package/dist/skills/reference/canon-policy.md +20 -16
- package/dist/skills/reference/canon-report-dashboard.md +30 -19
- package/dist/skills/reference/canon-retrieve.md +13 -10
- package/dist/skills/reference/canon-review.md +96 -68
- package/dist/skills/reference/canon-session-ingest.md +7 -3
- package/dist/skills/reference/canon-storage.md +65 -39
- package/dist/skills/reference/canon-subject.md +116 -79
- package/dist/skills/reference/canon-vocab.md +1 -1
- package/dist/skills/reference/role-implementer.md +295 -64
- package/dist/skills/reference/role-orchestrator.md +547 -55
- package/dist/skills/reference/role-planner.md +189 -32
- package/dist/skills/reference/role-reviewer.md +257 -58
- package/dist/skills/scripts/canon-retrieve-pre-dispatch.sh +10 -5
- package/man/canon-adapter-authorize.1 +44 -0
- package/man/canon-adapter-validate.1 +44 -0
- package/man/canon-adapter.1 +46 -0
- package/man/canon-artifacts-move.1 +63 -0
- package/man/canon-artifacts-store.1 +54 -0
- package/man/canon-artifacts-verify.1 +48 -0
- package/man/canon-artifacts.1 +45 -0
- package/man/canon-brief-approve.1 +62 -0
- package/man/canon-brief-check.1 +44 -0
- package/man/canon-brief-show.1 +50 -0
- package/man/canon-brief.1 +63 -0
- package/man/canon-change-new.1 +66 -0
- package/man/canon-change.1 +42 -0
- package/man/canon-completion.1 +60 -0
- package/man/canon-context-pack-add.1 +47 -0
- package/man/canon-context-pack-show.1 +44 -0
- package/man/canon-context-pack-verify.1 +44 -0
- package/man/canon-context-pack.1 +50 -0
- package/man/canon-context.1 +44 -0
- package/man/canon-dashboard.1 +50 -0
- package/man/canon-demo-init.1 +44 -0
- package/man/canon-demo-review.1 +44 -0
- package/man/canon-demo.1 +47 -0
- package/man/canon-dispatch-begin.1 +80 -0
- package/man/canon-dispatch-diff.1 +41 -0
- package/man/canon-dispatch-end.1 +60 -0
- package/man/canon-dispatch.1 +45 -0
- package/man/canon-divergence-accept.1 +68 -0
- package/man/canon-divergence-add.1 +97 -0
- package/man/canon-divergence-defer.1 +71 -0
- package/man/canon-divergence-list.1 +56 -0
- package/man/canon-divergence-resolve.1 +68 -0
- package/man/canon-divergence.1 +51 -0
- package/man/canon-evidence-add.1 +168 -0
- package/man/canon-evidence-approval-payload.1 +65 -0
- package/man/canon-evidence-audit.1 +121 -0
- package/man/canon-evidence.1 +57 -0
- package/man/canon-export.1 +108 -0
- package/man/canon-feature-new.1 +62 -0
- package/man/canon-feature.1 +39 -0
- package/man/canon-finding-add.1 +196 -0
- package/man/canon-finding-close.1 +117 -0
- package/man/canon-finding-list.1 +59 -0
- package/man/canon-finding.1 +67 -0
- package/man/canon-format.1 +49 -0
- package/man/canon-gate-check.1 +44 -0
- package/man/canon-gate-install-hooks.1 +59 -0
- package/man/canon-gate-promote.1 +62 -0
- package/man/canon-gate.1 +50 -0
- package/man/canon-ingest-plans.1 +53 -0
- package/man/canon-ingest-records.1 +56 -0
- package/man/canon-ingest-sessions.1 +62 -0
- package/man/canon-ingest.1 +50 -0
- package/man/canon-init.1 +98 -0
- package/man/canon-inventory-sync.1 +50 -0
- package/man/canon-inventory.1 +39 -0
- package/man/canon-ledger-compact.1 +50 -0
- package/man/canon-ledger.1 +54 -0
- package/man/canon-migrate.1 +89 -0
- package/man/canon-plugin-sync.1 +53 -0
- package/man/canon-plugin.1 +39 -0
- package/man/canon-policy-approve.1 +50 -0
- package/man/canon-policy-show.1 +41 -0
- package/man/canon-policy.1 +52 -0
- package/man/canon-prompt-add.1 +47 -0
- package/man/canon-prompt-show.1 +41 -0
- package/man/canon-prompt.1 +43 -0
- package/man/canon-purge.1 +70 -0
- package/man/canon-query.1 +111 -0
- package/man/canon-regime-show.1 +50 -0
- package/man/canon-regime.1 +39 -0
- package/man/canon-report-build.1 +44 -0
- package/man/canon-report-check.1 +41 -0
- package/man/canon-report-snapshot.1 +47 -0
- package/man/canon-report.1 +45 -0
- package/man/canon-retrieve.1 +56 -0
- package/man/canon-review-change.1 +98 -0
- package/man/canon-review-scenario.1 +98 -0
- package/man/canon-review.1 +42 -0
- package/man/canon-scenario-new.1 +80 -0
- package/man/canon-scenario.1 +39 -0
- package/man/canon-schema.1 +63 -0
- package/man/canon-selftest.1 +69 -0
- package/man/canon-skills-check.1 +47 -0
- package/man/canon-skills-doctor.1 +47 -0
- package/man/canon-skills-install.1 +53 -0
- package/man/canon-skills-show.1 +104 -0
- package/man/canon-skills.1 +48 -0
- package/man/canon-status.1 +51 -0
- package/man/canon-strategy-approval-payload.1 +53 -0
- package/man/canon-strategy-promote.1 +59 -0
- package/man/canon-strategy-rollback.1 +62 -0
- package/man/canon-strategy.1 +45 -0
- package/man/canon-subject-adopt.1 +53 -0
- package/man/canon-subject-move.1 +80 -0
- package/man/canon-subject-new.1 +65 -0
- package/man/canon-subject-show.1 +44 -0
- package/man/canon-subject-unadopt.1 +63 -0
- package/man/canon-subject.1 +51 -0
- package/man/canon-task-done.1 +47 -0
- package/man/canon-task.1 +42 -0
- package/man/canon-tier-age.1 +50 -0
- package/man/canon-tier.1 +39 -0
- package/man/canon.1 +169 -0
- package/package.json +9 -5
|
@@ -27,10 +27,10 @@ Every violation carries one of these stable, grep-able strings:
|
|
|
27
27
|
| `stale-evidence` | A passing record degraded to stale: its declared surface changed since its `evidence_sha`, or HEAD moved past `staleness.max_commits_behind`. Only degrades an already-green record. Also: a file bound to a latest evidence record whose bytes are gone — no intact blob in `.canon/artifacts/sha256/` and no working-tree copy with the recorded digest — or a file bound to an in-effect review with no intact blob (see Bound evidence stays provable below). |
|
|
28
28
|
| `malformed-evidence` | A candidate record doesn't parse, is misfiled, or carries an unparseable interim tag. Malformed evidence is no evidence. |
|
|
29
29
|
| `flagged` | The human-only `flagged` overlay is set — never green regardless of passing evidence. |
|
|
30
|
-
| `unevidenced-flip` | `canon
|
|
31
|
-
| `fabricated-evidence` | An evidence note contains a blocklisted marker (`"would pass"`, `"TBD"`, `"n/a"`) standing as a whole word — never inside a path, a file name, a URL or a longer word, so `pack.json/atlas` is not `n/a` — or a bare `verified` claim with no attached command result. `canon evidence add` refuses such a note before writing (
|
|
30
|
+
| `unevidenced-flip` | `canon task done <task_id>` was asked to flip a checkbox with no matching, non-`Divergent` evidence record. |
|
|
31
|
+
| `fabricated-evidence` | An evidence note contains a blocklisted marker (`"would pass"`, `"TBD"`, `"n/a"`) standing as a whole word — never inside a path, a file name, a URL or a longer word, so `pack.json/atlas` is not `n/a` — or a bare `verified` claim with no attached command result. `canon evidence add` refuses such a note before writing (refused with `fabricated-evidence`, exit 1). |
|
|
32
32
|
| `open-blocker` | With `spec_coverage.require_review` set (and `block_on_findings`, the default), a Finding whose latest version is severity `blocker`, disposition `open`, on a change an in-scope subject adopted — or closed `fixed` while an evidenced scenario of the subject has no evidence recorded after the close (re-verification). Subject string `<change_id>#<round>.<seq>`. See `canon-review`. |
|
|
33
|
-
| `false-success` | The latest audit record (`canon evidence
|
|
33
|
+
| `false-success` | The latest audit record (`canon evidence audit`) of a scenario says `refuted`: an external evaluator found a counterexample to the claimed success. Always on, regardless of policy or sampling, and takes precedence over any declared faithful verdict; only a newer audit (`confirmed` or `indeterminate`) clears it. The detail names the evaluator, its version, its sha256 and the counterexample paths. |
|
|
34
34
|
|
|
35
35
|
## `canon gate check [--repo <dir>] [--release]`
|
|
36
36
|
|
|
@@ -53,17 +53,27 @@ repo ROOT's `.canon/policy.yaml` and `.canon/ledger` from any subdirectory.
|
|
|
53
53
|
|
|
54
54
|
When `.canon/policy.yaml` exists but has no approval, the gate prints
|
|
55
55
|
`advisory: policy not approved: …` after its result, naming
|
|
56
|
-
`canon policy approve --
|
|
56
|
+
`canon policy approve --approver <who>`; the exit code is unchanged. When its
|
|
57
57
|
bytes no longer match the approved digest, or the approval cannot be read,
|
|
58
58
|
the gate fails closed: the violation is reported and the exit is `1` (see
|
|
59
59
|
`canon-policy`).
|
|
60
60
|
|
|
61
|
+
On a repository that still holds 0.27 canon state, `canon gate check` (like
|
|
62
|
+
`canon status` and `canon context`) warns and puts `canon migrate --json`
|
|
63
|
+
first in `meta.next`: run `canon migrate` (a preview), then `canon migrate
|
|
64
|
+
--commit --plan-digest <digest from the preview>`, then `canon skills
|
|
65
|
+
install`. Read the whole result with `--json`: `data.violations` lists the
|
|
66
|
+
failures by class and `meta.next` the steps.
|
|
67
|
+
|
|
68
|
+
**Done when:** `canon gate check` exits `0` with no violation; `canon status`
|
|
69
|
+
repeats the result and names what is still open.
|
|
70
|
+
|
|
61
71
|
The gate is a read command: it writes nothing. A scenario index that is
|
|
62
72
|
stale (a `.feature` file added, edited or deleted since the last sync) is
|
|
63
73
|
graded as the refresh would leave it, built in memory from the changed
|
|
64
74
|
files with the code `canon inventory sync` runs; the index on disk is
|
|
65
75
|
brought up to date by the next command that writes (`canon evidence add`,
|
|
66
|
-
`canon review
|
|
76
|
+
`canon review scenario`, `canon subject move`) or by `canon inventory sync`.
|
|
67
77
|
It prints no refresh line.
|
|
68
78
|
|
|
69
79
|
A root that fails to sync (format violations, a duplicate id) cannot be
|
|
@@ -119,11 +129,11 @@ A present section, even `require_evidence: false` or a malformed one
|
|
|
119
129
|
|
|
120
130
|
- **Unimplemented** — no `EvidenceRecord` carries the scenario's
|
|
121
131
|
`(project_id, scenario_id)`. Author one with
|
|
122
|
-
`canon evidence add --scenario-id <id> --project-id <root-id>`;
|
|
123
|
-
|
|
124
|
-
scenario id. `--summary` is allowed here too (scanned for fabrication
|
|
132
|
+
`canon evidence add --scenario-id <id> --project-id <root-id>`; the
|
|
133
|
+
root id is needed once more than one spec root is configured, because
|
|
134
|
+
two roots may carry the same scenario id. `--summary` is allowed here too (scanned for fabrication
|
|
125
135
|
markers like a task's); it is a row suffix only when the record also
|
|
126
|
-
names a `--task`. A record carrying both `--task` and `--scenario-id`
|
|
136
|
+
names a `--task-id`. A record carrying both `--task-id` and `--scenario-id`
|
|
127
137
|
is one attestation answering both joins: it counts for the task cell
|
|
128
138
|
and for the scenario cell (verdicts, the shipped gate, the review gate).
|
|
129
139
|
- **Mismatched** — the folded divergence state is `open`,
|
|
@@ -141,12 +151,12 @@ A present section, even `require_evidence: false` or a malformed one
|
|
|
141
151
|
case). This is the gap evidence presence cannot see: every scenario
|
|
142
152
|
attested, none of them specifying a refusal. Untagged scenarios satisfy
|
|
143
153
|
no case, so an unclassified corpus is reported, not passed. Works with
|
|
144
|
-
`require_evidence: false` too. `canon subject
|
|
154
|
+
`require_evidence: false` too. `canon subject move <id> --to shipped`
|
|
145
155
|
applies the same rule to the scenarios the subject owns.
|
|
146
156
|
- **Independent review** (`require_review`) — scenarios whose subject is
|
|
147
157
|
in `require_review.scope` (default `[verifying, shipped]`; `[]` = every
|
|
148
158
|
scenario; independent of `scope` above) need a `Review` record
|
|
149
|
-
(`canon review
|
|
159
|
+
(`canon review scenario`) whose latest version per reviewer is `signed`,
|
|
150
160
|
still matches the scenario digest and latest evidence it pinned
|
|
151
161
|
(a review written before 0.15 has no pins and skips this check), and,
|
|
152
162
|
when `distinct_actor` (default `true`), is by a reviewer and actor
|
|
@@ -171,7 +181,7 @@ A present section, even `require_evidence: false` or a malformed one
|
|
|
171
181
|
- **Sampled audits** (`require_audit`) — a deterministic sample of
|
|
172
182
|
in-scope scenarios (`require_audit.scope`, default `[verifying,
|
|
173
183
|
shipped]`; `exclude_lanes` applies) must carry an external audit
|
|
174
|
-
(`canon evidence
|
|
184
|
+
(`canon evidence audit`, see Audit records below). A sampled
|
|
175
185
|
scenario whose latest audit is missing or `indeterminate` is
|
|
176
186
|
`uncovered-cell`:
|
|
177
187
|
|
|
@@ -202,11 +212,13 @@ purpose, so enabling nothing changes no existing verdict.
|
|
|
202
212
|
### Accepted divergence and re-verification
|
|
203
213
|
|
|
204
214
|
```bash
|
|
205
|
-
canon divergence accept --project-id
|
|
215
|
+
canon divergence accept cart.add.01 --project-id root --reason "known gap" --tracking "issue#12" --expiry 2026-12-31 --actor-id reviewer-2 --role reviewer --session-id review-session-1
|
|
206
216
|
```
|
|
207
217
|
|
|
208
|
-
|
|
209
|
-
|
|
218
|
+
Accepting a scenario whose latest evidence is `divergent` as a known gap
|
|
219
|
+
limited by something outside the change is a human-only act: with a role
|
|
220
|
+
declared (`--as`, `CANON_ROLE`) the leaf is refused with `HUMAN_ONLY`. It is
|
|
221
|
+
never a way to skip a fix.
|
|
210
222
|
Refused (`DIVERGENCE_ACCEPT_REFUSED`) unless the latest verdict is
|
|
211
223
|
divergent and the session and actor differ from the evidence's. The record
|
|
212
224
|
pins that evidence: new evidence for the scenario, or `--expiry` passing,
|
|
@@ -224,36 +236,36 @@ from shipping until every one of its evidenced scenarios has evidence
|
|
|
224
236
|
recorded after the close or the approval. A blocker that names its
|
|
225
237
|
scenarios (`finding add --scenario-id`) asks only those, and the refusal
|
|
226
238
|
names them with the per-scenario command (`canon evidence add --project-id
|
|
227
|
-
<root-id> --scenario-id <id> --report <format>:<path
|
|
239
|
+
<root-id> --scenario-id <id> --report <format>:<path>` plus `--class`, `--role` and `--ref`). Otherwise the
|
|
228
240
|
refusal names the scenarios and the batch command: `canon evidence add --project-id <root-id>
|
|
229
|
-
--all-scenarios --report <format>:<path> --
|
|
230
|
-
implementer --ref "<test command>"
|
|
241
|
+
--all-scenarios --report <format>:<path> --class test-run --role
|
|
242
|
+
implementer --ref "<test command>"`. Reviews pin what the evidence says
|
|
231
243
|
(its verdict and the identity of its checks), not which record it is, so
|
|
232
244
|
recording the suite again with the same verdicts from the same cases leaves
|
|
233
245
|
every scenario review current. A chore instead needs one change-level
|
|
234
|
-
review of the chore itself (`canon review
|
|
246
|
+
review of the chore itself (`canon review change <slug>`) before
|
|
235
247
|
`--to shipped`; a changed verdict or case set stales that scenario's
|
|
236
248
|
review as before (and a new `divergence accept`, where the gap remains).
|
|
237
249
|
|
|
238
|
-
### Audit records (
|
|
250
|
+
### Audit records (`canon evidence audit`)
|
|
239
251
|
|
|
240
252
|
canon never generates or runs an audit. An external evaluator does, and
|
|
241
253
|
canon records its result:
|
|
242
254
|
|
|
243
255
|
```bash
|
|
244
|
-
canon evidence add --
|
|
256
|
+
canon evidence audit cart.add.01 --project-id root \
|
|
245
257
|
--ref "judge run 42" --role reviewer \
|
|
246
258
|
--evaluator-id judge --evaluator-version 1.2 \
|
|
247
|
-
--evaluator-digest
|
|
259
|
+
--evaluator-digest 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 \
|
|
248
260
|
--audit-result refuted --report junit:audit/counterexample.xml
|
|
249
261
|
```
|
|
250
262
|
|
|
251
|
-
-
|
|
252
|
-
`--evaluator-digest` (sha256, 64 lowercase hex)
|
|
253
|
-
confirmed|refuted|indeterminate`,
|
|
254
|
-
|
|
255
|
-
`--approval-*`; the
|
|
256
|
-
All refusals exit `2`.
|
|
263
|
+
- `evidence audit` requires the scenario operand, `--ref`, `--evaluator-id`,
|
|
264
|
+
`--evaluator-version`, `--evaluator-digest` (sha256, 64 lowercase hex)
|
|
265
|
+
and `--audit-result confirmed|refuted|indeterminate`, with `--project-id`
|
|
266
|
+
where several spec roots exist. It takes no `--task-id`, `--verdict`,
|
|
267
|
+
`--surface-ref` or `--approval-*`; the evaluator flags exist on no other
|
|
268
|
+
command. All refusals exit `2`.
|
|
257
269
|
- The record carries `audit: {evaluator_id, evaluator_version,
|
|
258
270
|
evaluator_digest, result}`; its verdict is derived (`confirmed` →
|
|
259
271
|
faithful, `refuted` → divergent, `indeterminate` → not-applicable).
|
|
@@ -263,10 +275,10 @@ canon evidence add --kind audit --project-id root --scenario-id cart.add.01 \
|
|
|
263
275
|
- Audits fold apart: per `(project_id, scenario_id)` there is a latest
|
|
264
276
|
declared record and a latest audit. An audit never becomes the
|
|
265
277
|
scenario's latest declared verdict.
|
|
266
|
-
- `canon subject
|
|
278
|
+
- `canon subject move <id> --to shipped` refuses `false-success`, and an
|
|
267
279
|
owed sampled audit when `require_audit.scope` covers `shipped`.
|
|
268
280
|
- `canon status` shows an `audits` section (sampled / confirmed / owed /
|
|
269
|
-
refuted) and suggests `canon evidence
|
|
281
|
+
refuted) and suggests `canon evidence audit` in `next:`.
|
|
270
282
|
|
|
271
283
|
### A record binds what its own write names
|
|
272
284
|
|
|
@@ -275,7 +287,7 @@ canon evidence add --kind audit --project-id root --scenario-id cart.add.01 \
|
|
|
275
287
|
from an earlier record, in a single add or in a suite batch
|
|
276
288
|
(`--all-scenarios`), and no drop is recorded: history keeps the earlier
|
|
277
289
|
records, and a new record is reviewed on its own files. An audit
|
|
278
|
-
(
|
|
290
|
+
(`canon evidence audit`) replaces a refutation the same way, so a counterexample
|
|
279
291
|
never rides along into a confirming audit. `--drop-attachment` and
|
|
280
292
|
`--drop-reason` no longer exist.
|
|
281
293
|
|
|
@@ -293,11 +305,11 @@ external openspec plan with a `proposal.md` under the plan sources (the
|
|
|
293
305
|
check `canon status` and the ship guard use; see
|
|
294
306
|
`canon-subject`; which changes a scenario answers to is scoped by its `@flow:<change>.<F-id>` tags, described there). The subjects are the scenario's `@subject` owner for
|
|
295
307
|
`--scenario-id`, and every subject adopting the task's change for
|
|
296
|
-
`--task`:
|
|
308
|
+
`--task-id`:
|
|
297
309
|
|
|
298
|
-
```
|
|
299
|
-
canon evidence add: unreviewed-promotion demo-subject — evidence for world.demo.01: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line, so the human has not answered it; once they do, record their words with `canon brief approve
|
|
300
|
-
canon evidence add: refused — stop, report the brief to the human and wait for their answer: nothing is built or attested for a subject before its brief is approved. Record their answer with `canon brief approve --
|
|
310
|
+
```stderr
|
|
311
|
+
canon evidence add: unreviewed-promotion demo-subject — evidence for world.demo.01: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line, so the human has not answered it; once they do, record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
|
|
312
|
+
canon evidence add: refused — stop, report the brief to the human and wait for their answer: nothing is built or attested for a subject before its brief is approved. Record their answer with `canon brief approve --approver <the human> --note "<their words>"` only from that answer; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
|
|
301
313
|
```
|
|
302
314
|
|
|
303
315
|
For a change from an external plan with no canon brief yet, the first
|
|
@@ -307,13 +319,13 @@ openspec/changes/c-ext/proposal.md, which canon reads and never edits, so
|
|
|
307
319
|
its approval lives in that canon file, so the human has not answered it;
|
|
308
320
|
once they do, create .canon/changes/c-ext/brief.md holding a `Source:
|
|
309
321
|
openspec/changes/c-ext/proposal.md` line, then record their words with
|
|
310
|
-
`canon brief approve
|
|
322
|
+
`canon brief approve c-ext --approver <the human> --note "<their words>"` ``. An `Approved:` line in the
|
|
311
323
|
external `proposal.md` itself is never read.
|
|
312
324
|
|
|
313
325
|
A subject with no brief to answer (no adopted change, or a newest change
|
|
314
326
|
with neither a canon `brief.md` nor an external `proposal.md`) and a
|
|
315
327
|
scenario no subject owns are unaffected.
|
|
316
|
-
`canon review
|
|
328
|
+
`canon review scenario` and `canon finding add` are never refused.
|
|
317
329
|
`--override-reason "<one line>"` attests anyway, prints the `waived …`
|
|
318
330
|
lines and `override recorded by `<actor>` for the N brief refusal(s)
|
|
319
331
|
above: <reason>`, and records on the evidence record:
|
|
@@ -326,6 +338,12 @@ brief_override:
|
|
|
326
338
|
actor: { agent_id: lead } # from --actor-id
|
|
327
339
|
```
|
|
328
340
|
|
|
341
|
+
Under `--json` the same waiver is `data.overrides[]` (`code` of the waived
|
|
342
|
+
refusal, `reason` verbatim), so a caller sees what its `--override-reason`
|
|
343
|
+
let through; a repeat of an identical record is `unchanged`
|
|
344
|
+
(`meta.unchanged`) and records no second override. `--override-reason`
|
|
345
|
+
exists on `subject move` too (see `canon-subject`).
|
|
346
|
+
|
|
329
347
|
A blank or multi-line reason exits 2; an override when nothing refused is
|
|
330
348
|
not recorded. `canon status` lists each such record as a `warning:`, and
|
|
331
349
|
`canon gate check` prints them after the result without failing:
|
|
@@ -337,7 +355,7 @@ brief overrides: 1 evidence record(s) attested before their brief was approved
|
|
|
337
355
|
|
|
338
356
|
### Review-waiver advisories
|
|
339
357
|
|
|
340
|
-
A subject moved into a review-scoped status with `canon subject
|
|
358
|
+
A subject moved into a review-scoped status with `canon subject move <id> --to <state>
|
|
341
359
|
--override-reason` (see `canon-subject`) keeps the `unreviewed-promotion`
|
|
342
360
|
and `open-blocker` gaps its waiver recorded visible without failing the
|
|
343
361
|
gate. Only those exact `(class, subject)` pairs are waived; a gap that
|
|
@@ -351,7 +369,7 @@ review waivers: 1 advisory(ies) — not failing the gate:
|
|
|
351
369
|
|
|
352
370
|
The waiver lasts only until the subject's next status write.
|
|
353
371
|
|
|
354
|
-
`canon subject
|
|
372
|
+
`canon subject move <id> --to shipped` also refuses where a brief exists and
|
|
355
373
|
is not approved (the subject's scope, its newest adopted change walking back past pending drafts
|
|
356
374
|
no scenario is tagged `@flow:<change>.*` for, has a canon
|
|
357
375
|
`brief.md` with no `Approved:` line or one the brief's text no longer
|
|
@@ -414,13 +432,13 @@ what backed the claim:
|
|
|
414
432
|
```bash
|
|
415
433
|
# any file: a Playwright trace, screenshots, an agent QA log — by sha256
|
|
416
434
|
canon evidence add --scenario-id cart.add.04 --project-id root \
|
|
417
|
-
--
|
|
435
|
+
--class agent-qa --ref "stagehand run 7" --role implementer \
|
|
418
436
|
--artifact test-results/cart-trace.zip
|
|
419
437
|
# a JUnit XML or Cucumber JSON report: also records the matched case + outcome
|
|
420
|
-
canon evidence add
|
|
421
|
-
canon evidence add
|
|
438
|
+
canon evidence add --scenario-id cart.add.04 --project-id root --class test-run --ref "cargo nextest run" --role implementer --report junit:target/nextest/default/junit.xml
|
|
439
|
+
canon evidence add --scenario-id cart.add.04 --project-id root --class test-run --ref "cucumber-js" --role implementer --report cucumber:reports/cucumber.json
|
|
422
440
|
# a Swift Testing event stream (swift test --experimental-event-stream-output <path>)
|
|
423
|
-
canon evidence add
|
|
441
|
+
canon evidence add --scenario-id cart.add.04 --project-id root --class test-run --ref "swift test" --role implementer --report swift-testing:.build/events.jsonl
|
|
424
442
|
```
|
|
425
443
|
|
|
426
444
|
A case is bound when the scenario id is its OWN: the first
|
|
@@ -474,7 +492,7 @@ One test run proves many scenarios. Bind it once:
|
|
|
474
492
|
```bash
|
|
475
493
|
canon evidence add --project-id root --all-scenarios \
|
|
476
494
|
--report junit:target/nextest/default/junit.xml \
|
|
477
|
-
--
|
|
495
|
+
--class test-run --ref "cargo nextest run" --role implementer
|
|
478
496
|
```
|
|
479
497
|
|
|
480
498
|
Each indexed scenario of `--project-id` that owns a case (the rule above)
|
|
@@ -497,30 +515,50 @@ It is all or nothing: a claimed `faithful` verdict over a failed case,
|
|
|
497
515
|
a fabrication marker in `--summary`, an unapproved brief for any
|
|
498
516
|
scenario's subject refuses the whole batch, and nothing is written. Each
|
|
499
517
|
record binds only what the batch names (nothing is carried forward).
|
|
500
|
-
`--scenario-id`, `--task`,
|
|
501
|
-
`--report-case`,
|
|
518
|
+
`--scenario-id`, `--task-id`,
|
|
519
|
+
`--report-case`, `canon evidence audit` and the approval flags name one subject
|
|
502
520
|
and are refused with `--all-scenarios`.
|
|
503
521
|
|
|
504
522
|
A task's evidence with `--report` and no `--scenario-id` binds EVERY case
|
|
505
523
|
in the report, so a `faithful` verdict needs all of them to pass.
|
|
506
524
|
|
|
525
|
+
Many records at once without a report: `--input` takes inline JSON, a file
|
|
526
|
+
or `-`; an array (or NDJSON) is a batch, validated element by element before
|
|
527
|
+
the first write (a refusal writes nothing, exit 2). Keys are the option
|
|
528
|
+
names in camelCase plus `operands`: one object per scenario, with
|
|
529
|
+
`scenarioId`, `class`, `ref` and `role`. `canon schema evidence add --json`
|
|
530
|
+
shows the input schema and an example. Each element reports `written`,
|
|
531
|
+
`unchanged` or `failed` in `data.items[]`.
|
|
532
|
+
|
|
533
|
+
`--rev <rev>` names the commit the evidence ran against (default `HEAD`).
|
|
534
|
+
Evidence for uncommitted code is recorded with its `codeTree` and
|
|
535
|
+
`worktreeDirty`; outside git, or with no commit, the add is refused with
|
|
536
|
+
`NO_COMMIT`.
|
|
537
|
+
|
|
538
|
+
**Done when:** `canon gate check` shows no violation for the scenarios you
|
|
539
|
+
recorded evidence for; each record's own output line says whether it was
|
|
540
|
+
written or `unchanged`.
|
|
541
|
+
|
|
507
542
|
### A write that makes a review stale says so (0.18)
|
|
508
543
|
|
|
509
544
|
When new evidence (one record or a batch) supersedes the evidence a
|
|
510
545
|
current pinned review saw, `canon evidence add` prints one line per
|
|
511
546
|
review it makes stale (its verdict or checks differ from what the review saw), with the command that re-pins it:
|
|
512
547
|
|
|
513
|
-
```
|
|
514
|
-
canon evidence add: review by `reviewer-2` of cart.add.01 is now stale (this record's verdict or checks differ from what it saw); re-pin it: canon review
|
|
548
|
+
```stderr
|
|
549
|
+
canon evidence add: review by `reviewer-2` of cart.add.01 is now stale (this record's verdict or checks differ from what it saw); re-pin it: canon review scenario cart.add.01 --project-id root --actor-id reviewer-2 --role reviewer --original-spec-ref specs/kind=feature/area=cart/add.feature
|
|
515
550
|
```
|
|
516
551
|
|
|
517
552
|
The decision is the gate's own (the same stale-review rule `canon gate
|
|
518
553
|
check` reports). The command repeats the review's reviewer, actor, role,
|
|
519
|
-
session, provenance ref, runtime labels and artifacts,
|
|
520
|
-
|
|
554
|
+
session, provenance ref, runtime labels and artifacts, at the default
|
|
555
|
+
`--rev` (`HEAD`). A record that is only staged says
|
|
521
556
|
the review "goes stale once this evidence is promoted": promote first,
|
|
522
|
-
then re-
|
|
523
|
-
scenarios re-
|
|
557
|
+
then re-review. The reviewer re-reviews before re-pinning; several
|
|
558
|
+
scenarios re-review in one `canon review scenario` (see `canon-review`).
|
|
559
|
+
|
|
560
|
+
**Done when:** `canon gate check` reports no stale review for the scenarios
|
|
561
|
+
you recorded evidence for; the re-review's own output says `pinned`.
|
|
524
562
|
|
|
525
563
|
## Bound evidence stays provable (the artifact store)
|
|
526
564
|
|
|
@@ -534,11 +572,11 @@ raise the limit with `--max-artifact-mib <N>`.
|
|
|
534
572
|
Where those bytes live is `canon.yaml`'s `artifact_store: { backend: local |
|
|
535
573
|
<s3 tier>, prefix: artifacts/ }` (default `local`: the directory above,
|
|
536
574
|
git-tracked, no credentials). With an object-store tier, `evidence add`,
|
|
537
|
-
`review
|
|
575
|
+
`review scenario` and `artifacts store` upload each blob under
|
|
538
576
|
`<prefix>sha256/<digest>` and keep nothing locally. `canon gate check` and
|
|
539
577
|
`canon artifacts verify [--full]` ask the store (a HEAD per digest; `--full`
|
|
540
578
|
downloads and re-hashes) and refuse, never pass, when it cannot be reached.
|
|
541
|
-
`canon artifacts
|
|
579
|
+
`canon artifacts move --tier <tier>` (a preview; `--commit --plan-digest` acts) moves an existing local
|
|
542
580
|
store; it is the repo owner's decision. See `canon-storage`.
|
|
543
581
|
|
|
544
582
|
`canon gate check` re-checks every file bound to a LATEST evidence record
|
|
@@ -548,11 +586,11 @@ store; it is the repo owner's decision. See `canon-storage`.
|
|
|
548
586
|
after the working-tree file is rewritten (a smoke script that rewrites
|
|
549
587
|
`reports/smoke.json` on every run no longer orphans the record);
|
|
550
588
|
- no blob, but the working-tree path still hashes to the recorded digest
|
|
551
|
-
→ clean, with an advisory naming `canon
|
|
589
|
+
→ clean, with an advisory naming `canon artifacts store` (records from
|
|
552
590
|
before the store existed):
|
|
553
591
|
|
|
554
592
|
```
|
|
555
|
-
evidence artifacts: 1 bound file(s) not in the artifact store — not failing the gate; run `canon
|
|
593
|
+
evidence artifacts: 1 bound file(s) not in the artifact store — not failing the gate; run `canon artifacts store` to store them before the working tree changes:
|
|
556
594
|
unstored cart.add.01 reports/junit.xml (sha256 b7cb…) is verified against the working tree only
|
|
557
595
|
```
|
|
558
596
|
- anything else → `stale-evidence` naming the path, the recorded digest,
|
|
@@ -568,7 +606,7 @@ subject's status, and a repo with no `spec_coverage` would otherwise never
|
|
|
568
606
|
have its bindings checked. A superseded record is not checked —
|
|
569
607
|
re-attesting is the fix.
|
|
570
608
|
|
|
571
|
-
Files bound to a review (`canon review
|
|
609
|
+
Files bound to a review (`canon review scenario --artifact`, see
|
|
572
610
|
`canon-review`) are checked by the same rule for every CURRENT in-effect
|
|
573
611
|
review: the latest per `(project_id, scenario_id, reviewer)`, less any
|
|
574
612
|
that went stale against its scenario (its spec or evidence pin moved). A stale review is
|
|
@@ -585,7 +623,7 @@ Anything else is `stale-evidence` on the review's scenario, and the
|
|
|
585
623
|
detail names the review: ``review by `<reviewer>` (actor `<id>`,
|
|
586
624
|
<time>)``.
|
|
587
625
|
|
|
588
|
-
`canon
|
|
626
|
+
`canon artifacts store [--max-artifact-mib <N>]` stores the bytes for
|
|
589
627
|
existing evidence records and current reviews (a superseded review's files are not vaulted): every attachment whose
|
|
590
628
|
working-tree file still matches its digest is copied in, and everything
|
|
591
629
|
else is listed as not stored, with both digests. It exits `0` whenever it
|
|
@@ -621,7 +659,7 @@ Malformed `risk_tiers` sections produce a stable `uncovered-cell` policy
|
|
|
621
659
|
violation (`risk_tiers policy-invalid: ...`) instead of degrading to an
|
|
622
660
|
empty clean map.
|
|
623
661
|
|
|
624
|
-
## `canon
|
|
662
|
+
## `canon task done <task_id> [--repo <dir>]`
|
|
625
663
|
|
|
626
664
|
For imported external plans, and for a `tasks.md` that already exists in
|
|
627
665
|
a canon change. `canon change new` writes no `tasks.md` (0.19), and
|
|
@@ -640,7 +678,7 @@ task at all is a loud failure naming every source consulted. A repo with
|
|
|
640
678
|
no `.canon/changes/` and `sources: []` is refused: "this repo configures
|
|
641
679
|
no plan sources (no `.canon/changes` and no `plans.sources` entries in
|
|
642
680
|
canon.yaml) … write the change with `canon change new`, or list your
|
|
643
|
-
external plans under `plans.sources`" (`canon dispatch --task` says the
|
|
681
|
+
external plans under `plans.sources`" (`canon dispatch begin --task-id` says the
|
|
644
682
|
same).
|
|
645
683
|
It requires
|
|
646
684
|
a matching non-`Divergent` evidence record, and flips `- [ ]` → `- [x]`
|
|
@@ -654,7 +692,7 @@ exits `1` with the blocking violation on stderr. After a flip, the plan
|
|
|
654
692
|
source is re-ingested so the record store's task status agrees with the
|
|
655
693
|
checkbox (`canon query --kind task` reads `done`); a failed re-ingest is
|
|
656
694
|
a stderr warning naming `canon ingest plans`, never a failed flip.
|
|
657
|
-
The success line is `canon
|
|
695
|
+
The success line is `canon task done: <task_id> flipped — written
|
|
658
696
|
directly; nothing to promote`. An already-`[x]` row is an idempotent no-op (exit `0`). An unknown
|
|
659
697
|
`task_id` is reported (exit `1`).
|
|
660
698
|
|
|
@@ -662,19 +700,19 @@ A flip on evidence that cannot prove the task still succeeds, but warns
|
|
|
662
700
|
on stderr: when none of the task's evidence records binds a file and one
|
|
663
701
|
of them cites a canon command as its `--ref` (`canon gate check`,
|
|
664
702
|
`canon status`), the warning says to bind the artifact or report that
|
|
665
|
-
proves the task (`canon evidence add --task <id> --artifact <path>` or
|
|
703
|
+
proves the task (`canon evidence add --task-id <id> --artifact <path>` or
|
|
666
704
|
`--report <format>:<path>`). A canon command reports on canon's own
|
|
667
705
|
records, so it is never the proof of a task.
|
|
668
706
|
|
|
669
707
|
```bash
|
|
670
|
-
canon
|
|
708
|
+
canon task done my-change#5.2 --repo .
|
|
671
709
|
```
|
|
672
710
|
|
|
673
711
|
This is canon's own authority for the checkbox grammar — always flip
|
|
674
|
-
through `canon
|
|
712
|
+
through `canon task done`, never by hand.
|
|
675
713
|
|
|
676
714
|
Canon only reads external plans, with this one exception: for a task
|
|
677
|
-
from an external plan source, `canon
|
|
715
|
+
from an external plan source, `canon task done` flips the checkbox in
|
|
678
716
|
that plan's own `tasks.md` (or plan document). It is the one place canon
|
|
679
717
|
writes into an external plan; their briefs and approvals still live in
|
|
680
718
|
`.canon/changes/<change>/brief.md`. (Open for the maintainer: record
|
|
@@ -711,8 +749,8 @@ commits everything staged. It stays safe to run anyway: with nothing
|
|
|
711
749
|
staged it prints
|
|
712
750
|
`nothing staged` and exits `0`. `divergence add` stages for `canon
|
|
713
751
|
gate promote` and names it, under the same `write:` rule. Every
|
|
714
|
-
other write — `review
|
|
715
|
-
`
|
|
752
|
+
other write — `review scenario`, `subject new|adopt|move`, `change new`, `scenario new`, `feature new`,
|
|
753
|
+
`task done` (it edits the plan document and re-ingests it)
|
|
716
754
|
— is final when it returns, and its success line ends `— written
|
|
717
755
|
directly; nothing to promote`. Full promote-on-write contract:
|
|
718
756
|
`canon-storage` (Staged writes and promotion). `divergence resolve|defer|accept` stage and promote their own record in the same run and end `— staged and promoted in this run; nothing to promote`.
|
|
@@ -737,7 +775,7 @@ canon gate install-hooks --repo . --event PreToolUse --matcher Edit --command "c
|
|
|
737
775
|
|
|
738
776
|
Prefer this over hand-editing `settings.json`/`hooks.json`.
|
|
739
777
|
|
|
740
|
-
## `canon gate
|
|
778
|
+
## `canon selftest --suite trust-spine-gate`
|
|
741
779
|
|
|
742
780
|
Runs the shipped fixture corpus — one fixture per failure class (ten,
|
|
743
781
|
including `false-success`), each a
|
|
@@ -747,7 +785,7 @@ deliberately broken corpus proving that class fires and ONLY that class
|
|
|
747
785
|
check` run's green.
|
|
748
786
|
|
|
749
787
|
```bash
|
|
750
|
-
canon gate
|
|
788
|
+
canon selftest --suite trust-spine-gate
|
|
751
789
|
```
|
|
752
790
|
|
|
753
791
|
## Reading a violation
|
|
@@ -7,13 +7,14 @@ records every downstream stage joins against.
|
|
|
7
7
|
## You rarely run it yourself
|
|
8
8
|
|
|
9
9
|
Since 0.16 the commands that read the index see added, edited and deleted
|
|
10
|
-
`.feature` files without a sync step. `canon evidence add`, `canon
|
|
11
|
-
|
|
10
|
+
`.feature` files without a sync step. `canon evidence add`, `canon evidence
|
|
11
|
+
audit`, `canon artifacts store`, `canon divergence accept`, `canon review
|
|
12
|
+
scenario` and `canon subject move` refresh the index on disk first, with the
|
|
12
13
|
same code this command runs, scoped to the changed files, and say so in one
|
|
13
14
|
stderr line:
|
|
14
15
|
|
|
15
|
-
```
|
|
16
|
-
canon
|
|
16
|
+
```stderr
|
|
17
|
+
canon artifacts store: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
|
|
17
18
|
```
|
|
18
19
|
|
|
19
20
|
`canon status` and `canon gate check` are read commands and write nothing:
|
|
@@ -44,8 +45,8 @@ not the index already holds its scenarios, `shipped` is refused, and
|
|
|
44
45
|
fix it; run `canon migrate`, which moves `features/kind=feature/` to
|
|
45
46
|
`<root>/kind=feature/`.
|
|
46
47
|
|
|
47
|
-
`canon migrate
|
|
48
|
-
`canon migrate
|
|
48
|
+
`canon migrate` prints the plan without writing anything, and
|
|
49
|
+
`canon migrate --commit --plan-digest <digest>` applies it. Commit first: it refuses while a path it
|
|
49
50
|
moves has uncommitted changes, and when a destination already exists.
|
|
50
51
|
A root at the repo-level `specs` moves to `.canon/specs`, and
|
|
51
52
|
`canon.yaml` records `former_roots: [specs]`, so reviews pinned before
|
|
@@ -68,19 +69,19 @@ kept an old index gets it rewritten on the first read.
|
|
|
68
69
|
|
|
69
70
|
## Where the index sits in the loop
|
|
70
71
|
|
|
71
|
-
```
|
|
72
|
+
```text
|
|
72
73
|
author .feature corpus (canon scenario new)
|
|
73
74
|
│
|
|
74
75
|
▼
|
|
75
76
|
scenario index # refreshed by the writers; `canon inventory sync` rebuilds it
|
|
76
77
|
│
|
|
77
78
|
▼
|
|
78
|
-
canon review
|
|
79
|
-
canon divergence
|
|
79
|
+
canon review scenario # attests a review — see canon-inventory downstream / canon-gate
|
|
80
|
+
canon divergence add|resolve|defer|accept|list # tracks/resolves a divergence
|
|
80
81
|
canon gate check [--release] # trust-ladder / staleness / coverage — see canon-gate
|
|
81
82
|
│
|
|
82
83
|
▼
|
|
83
|
-
canon ingest
|
|
84
|
+
canon ingest records # with artifacts.native_records: true in canon.yaml —
|
|
84
85
|
# feeds review/divergence verdicts into the flywheel
|
|
85
86
|
# (see canon-artifact-ingest)
|
|
86
87
|
```
|
|
@@ -98,7 +99,7 @@ canon inventory sync --spec-root ./specs # ad hoc: ignore canon.yaml entirely
|
|
|
98
99
|
|
|
99
100
|
Per configured root, in order:
|
|
100
101
|
|
|
101
|
-
1. **Validate** — runs `canon format
|
|
102
|
+
1. **Validate** — runs `canon format` over the root. ANY violation
|
|
102
103
|
(missing provenance, layout-grammar, …) ABORTS THE WHOLE ROOT: zero
|
|
103
104
|
records written for it, the violation(s) reported. Never a partial sync.
|
|
104
105
|
2. **Scan** — walks `<root>/kind=feature/area=<area>/<surface>.feature`, pairing each
|
|
@@ -124,6 +125,13 @@ The scenario index shape is deliberately general: `title` +
|
|
|
124
125
|
`source_digest`, nothing else. It carries no coverage field — coverage
|
|
125
126
|
stays `canon gate check`'s own authority (see `canon-gate`).
|
|
126
127
|
|
|
128
|
+
`--dry-run` runs the same validation and reports what would be written
|
|
129
|
+
without writing. A rerun that finds every digest unchanged writes nothing.
|
|
130
|
+
|
|
131
|
+
**Done when:** `canon inventory sync` exits `0` with no violation or sync
|
|
132
|
+
error for the root, and `canon query --kind scenario` lists the scenarios;
|
|
133
|
+
`canon status` then reads the index without a `NOT refreshed` line.
|
|
134
|
+
|
|
127
135
|
## `specs.roots[]` config (`canon.yaml`)
|
|
128
136
|
|
|
129
137
|
```yaml
|
|
@@ -149,7 +157,7 @@ specs:
|
|
|
149
157
|
|
|
150
158
|
## Sync-abort causes
|
|
151
159
|
|
|
152
|
-
- **A `canon format
|
|
160
|
+
- **A `canon format` validation violation** in the root's corpus →
|
|
153
161
|
whole root aborts, 0 writes, violations reported.
|
|
154
162
|
- **A root on the pre-0.17 layout** (a `.feature` file under
|
|
155
163
|
`<root>/features/`) → a `layout-grammar` violation at path `features`;
|
|
@@ -160,12 +168,12 @@ specs:
|
|
|
160
168
|
|
|
161
169
|
## How the index feeds the rest
|
|
162
170
|
|
|
163
|
-
- **Review** — `canon review
|
|
171
|
+
- **Review** — `canon review scenario` attests a verdict against a synced
|
|
164
172
|
scenario. (See `canon-inventory` downstream commands and each command's `--help`.)
|
|
165
|
-
- **Divergence** — `canon divergence
|
|
173
|
+
- **Divergence** — `canon divergence add|resolve|defer|accept|list`
|
|
166
174
|
tracks/resolves divergences against synced scenarios.
|
|
167
175
|
- **Gate** — `canon gate check` enforces trust-ladder / staleness /
|
|
168
176
|
coverage over the corpus (see `canon-gate`).
|
|
169
|
-
- **Ingest** — `canon ingest
|
|
177
|
+
- **Ingest** — `canon ingest records` with `artifacts.native_records:
|
|
170
178
|
true` in `canon.yaml` feeds review/divergence verdicts into the
|
|
171
179
|
reward flywheel (see `canon-artifact-ingest`).
|