@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.
Files changed (133) hide show
  1. package/dist/skills/SKILL.src.md +245 -89
  2. package/dist/skills/reference/brief-align.md +4 -2
  3. package/dist/skills/reference/brief-clarify.md +7 -5
  4. package/dist/skills/reference/brief-harden.md +4 -2
  5. package/dist/skills/reference/brief-polish.md +7 -5
  6. package/dist/skills/reference/brief-shape.md +4 -2
  7. package/dist/skills/reference/canon-artifact-ingest.md +11 -7
  8. package/dist/skills/reference/canon-authoring.md +16 -2
  9. package/dist/skills/reference/canon-context.md +21 -11
  10. package/dist/skills/reference/canon-fmt.md +10 -2
  11. package/dist/skills/reference/canon-gate.md +107 -69
  12. package/dist/skills/reference/canon-inventory.md +23 -15
  13. package/dist/skills/reference/canon-learn.md +23 -19
  14. package/dist/skills/reference/canon-plan-import.md +10 -7
  15. package/dist/skills/reference/canon-plugins.md +15 -8
  16. package/dist/skills/reference/canon-policy.md +20 -16
  17. package/dist/skills/reference/canon-report-dashboard.md +30 -19
  18. package/dist/skills/reference/canon-retrieve.md +13 -10
  19. package/dist/skills/reference/canon-review.md +96 -68
  20. package/dist/skills/reference/canon-session-ingest.md +7 -3
  21. package/dist/skills/reference/canon-storage.md +65 -39
  22. package/dist/skills/reference/canon-subject.md +116 -79
  23. package/dist/skills/reference/canon-vocab.md +1 -1
  24. package/dist/skills/reference/role-implementer.md +295 -64
  25. package/dist/skills/reference/role-orchestrator.md +547 -55
  26. package/dist/skills/reference/role-planner.md +189 -32
  27. package/dist/skills/reference/role-reviewer.md +257 -58
  28. package/dist/skills/scripts/canon-retrieve-pre-dispatch.sh +10 -5
  29. package/man/canon-adapter-authorize.1 +44 -0
  30. package/man/canon-adapter-validate.1 +44 -0
  31. package/man/canon-adapter.1 +46 -0
  32. package/man/canon-artifacts-move.1 +63 -0
  33. package/man/canon-artifacts-store.1 +54 -0
  34. package/man/canon-artifacts-verify.1 +48 -0
  35. package/man/canon-artifacts.1 +45 -0
  36. package/man/canon-brief-approve.1 +62 -0
  37. package/man/canon-brief-check.1 +44 -0
  38. package/man/canon-brief-show.1 +50 -0
  39. package/man/canon-brief.1 +63 -0
  40. package/man/canon-change-new.1 +66 -0
  41. package/man/canon-change.1 +42 -0
  42. package/man/canon-completion.1 +60 -0
  43. package/man/canon-context-pack-add.1 +47 -0
  44. package/man/canon-context-pack-show.1 +44 -0
  45. package/man/canon-context-pack-verify.1 +44 -0
  46. package/man/canon-context-pack.1 +50 -0
  47. package/man/canon-context.1 +44 -0
  48. package/man/canon-dashboard.1 +50 -0
  49. package/man/canon-demo-init.1 +44 -0
  50. package/man/canon-demo-review.1 +44 -0
  51. package/man/canon-demo.1 +47 -0
  52. package/man/canon-dispatch-begin.1 +80 -0
  53. package/man/canon-dispatch-diff.1 +41 -0
  54. package/man/canon-dispatch-end.1 +60 -0
  55. package/man/canon-dispatch.1 +45 -0
  56. package/man/canon-divergence-accept.1 +68 -0
  57. package/man/canon-divergence-add.1 +97 -0
  58. package/man/canon-divergence-defer.1 +71 -0
  59. package/man/canon-divergence-list.1 +56 -0
  60. package/man/canon-divergence-resolve.1 +68 -0
  61. package/man/canon-divergence.1 +51 -0
  62. package/man/canon-evidence-add.1 +168 -0
  63. package/man/canon-evidence-approval-payload.1 +65 -0
  64. package/man/canon-evidence-audit.1 +121 -0
  65. package/man/canon-evidence.1 +57 -0
  66. package/man/canon-export.1 +108 -0
  67. package/man/canon-feature-new.1 +62 -0
  68. package/man/canon-feature.1 +39 -0
  69. package/man/canon-finding-add.1 +196 -0
  70. package/man/canon-finding-close.1 +117 -0
  71. package/man/canon-finding-list.1 +59 -0
  72. package/man/canon-finding.1 +67 -0
  73. package/man/canon-format.1 +49 -0
  74. package/man/canon-gate-check.1 +44 -0
  75. package/man/canon-gate-install-hooks.1 +59 -0
  76. package/man/canon-gate-promote.1 +62 -0
  77. package/man/canon-gate.1 +50 -0
  78. package/man/canon-ingest-plans.1 +53 -0
  79. package/man/canon-ingest-records.1 +56 -0
  80. package/man/canon-ingest-sessions.1 +62 -0
  81. package/man/canon-ingest.1 +50 -0
  82. package/man/canon-init.1 +98 -0
  83. package/man/canon-inventory-sync.1 +50 -0
  84. package/man/canon-inventory.1 +39 -0
  85. package/man/canon-ledger-compact.1 +50 -0
  86. package/man/canon-ledger.1 +54 -0
  87. package/man/canon-migrate.1 +89 -0
  88. package/man/canon-plugin-sync.1 +53 -0
  89. package/man/canon-plugin.1 +39 -0
  90. package/man/canon-policy-approve.1 +50 -0
  91. package/man/canon-policy-show.1 +41 -0
  92. package/man/canon-policy.1 +52 -0
  93. package/man/canon-prompt-add.1 +47 -0
  94. package/man/canon-prompt-show.1 +41 -0
  95. package/man/canon-prompt.1 +43 -0
  96. package/man/canon-purge.1 +70 -0
  97. package/man/canon-query.1 +111 -0
  98. package/man/canon-regime-show.1 +50 -0
  99. package/man/canon-regime.1 +39 -0
  100. package/man/canon-report-build.1 +44 -0
  101. package/man/canon-report-check.1 +41 -0
  102. package/man/canon-report-snapshot.1 +47 -0
  103. package/man/canon-report.1 +45 -0
  104. package/man/canon-retrieve.1 +56 -0
  105. package/man/canon-review-change.1 +98 -0
  106. package/man/canon-review-scenario.1 +98 -0
  107. package/man/canon-review.1 +42 -0
  108. package/man/canon-scenario-new.1 +80 -0
  109. package/man/canon-scenario.1 +39 -0
  110. package/man/canon-schema.1 +63 -0
  111. package/man/canon-selftest.1 +69 -0
  112. package/man/canon-skills-check.1 +47 -0
  113. package/man/canon-skills-doctor.1 +47 -0
  114. package/man/canon-skills-install.1 +53 -0
  115. package/man/canon-skills-show.1 +104 -0
  116. package/man/canon-skills.1 +48 -0
  117. package/man/canon-status.1 +51 -0
  118. package/man/canon-strategy-approval-payload.1 +53 -0
  119. package/man/canon-strategy-promote.1 +59 -0
  120. package/man/canon-strategy-rollback.1 +62 -0
  121. package/man/canon-strategy.1 +45 -0
  122. package/man/canon-subject-adopt.1 +53 -0
  123. package/man/canon-subject-move.1 +80 -0
  124. package/man/canon-subject-new.1 +65 -0
  125. package/man/canon-subject-show.1 +44 -0
  126. package/man/canon-subject-unadopt.1 +63 -0
  127. package/man/canon-subject.1 +51 -0
  128. package/man/canon-task-done.1 +47 -0
  129. package/man/canon-task.1 +42 -0
  130. package/man/canon-tier-age.1 +50 -0
  131. package/man/canon-tier.1 +39 -0
  132. package/man/canon.1 +169 -0
  133. package/package.json +9 -5
@@ -5,7 +5,7 @@ that anyone other than the author looked at the work. Canon records that
5
5
  second look as two ledger kinds — a **Finding** per issue a reviewer
6
6
  raises, and a **Review** per scenario a reviewer signs off — and the
7
7
  opt-in `spec_coverage.require_review` policy makes `canon gate check` and
8
- `canon subject status` hold a subject until both are in order.
8
+ `canon subject move` hold a subject until both are in order.
9
9
 
10
10
  Both records are attestations: canon never checks a finding's summary
11
11
  against the code, or that a reviewer actually read the scenario. What the
@@ -17,7 +17,8 @@ state they are in.
17
17
  The order an agent follows to claim a subject done:
18
18
 
19
19
  1. **Test-run evidence** per owned scenario (`canon evidence add
20
- --scenario-id <id> --project-id <root-id> ... --session-id <session>`;
20
+ --scenario-id <id> --project-id <root-id> --session-id <session>` and the
21
+ rest of its options;
21
22
  final when it returns under `write: { promote: auto }`, which
22
23
  `canon init` writes, and followed by `canon gate promote` only under
23
24
  `write.promote: manual`). See `canon-gate`.
@@ -26,11 +27,11 @@ The order an agent follows to claim a subject done:
26
27
 
27
28
  ```bash
28
29
  canon finding add --change-id c-demo --round 1 --seq 1 \
29
- --severity blocker --disposition open --reviewer reviewer-2 \
30
+ --severity blocker --disposition open --actor-id reviewer-2 \
30
31
  --summary "unbounded subprocess wait" --session-id review-session-1
31
32
  # ... fix, commit ...
32
- canon finding close --change-id c-demo --round 1 --seq 1 \
33
- --disposition fixed --resolution-sha "$(git rev-parse HEAD)"
33
+ canon finding close c-demo --round 1 --seq 1 \
34
+ --disposition fixed --resolution-rev HEAD
34
35
  ```
35
36
 
36
37
  Under `write.promote: manual` (or no `write:` key), run
@@ -41,23 +42,27 @@ The order an agent follows to claim a subject done:
41
42
  the evidence is in (the review pins what it saw):
42
43
 
43
44
  ```bash
44
- canon review add --project-id root --scenario-id world.demo.01 \
45
- --reviewer reviewer-2 --actor-id reviewer-2 --role reviewer \
45
+ canon review scenario world.demo.01 --project-id root \
46
+ --actor-id reviewer-2 --role reviewer \
46
47
  --session-id review-session-1 \
47
- --pin "$(git rev-parse HEAD)" --upstream-ref "pr#41"
48
+ --rev HEAD --upstream-ref "pr#41"
48
49
  ```
49
50
 
50
- `review add` writes directly; there is nothing to promote. If the
51
+ `review scenario` writes directly; there is nothing to promote. If the
51
52
  reviewer could not reach a verdict, record that instead of signing:
52
- `--outcome indeterminate` (or `unavailable` when it could not run).
53
+ `--review-outcome indeterminate` (or `unavailable` when it could not run).
53
54
  Changing the scenario or re-attesting it afterwards makes the review
54
55
  stale; review it again. A reviewer of user-visible behavior attaches
55
56
  the screenshots or recordings it looked at with `--artifact <path>`
56
57
  (below).
57
58
 
58
- 4. **Move the subject**: `canon subject status <id> --to verifying`, later
59
+ 4. **Move the subject**: `canon subject move <id> --to verifying`, later
59
60
  `shipped`. See `canon-subject`.
60
61
 
62
+ **Done when:** `canon gate check` exits 0 (no `unreviewed-promotion`, no
63
+ `open-blocker`) and `canon status` shows the subject with every scenario
64
+ reviewed and `openBlockers: 0` (`data.subjects[]`).
65
+
61
66
  ## `canon finding add` / `canon finding close`
62
67
 
63
68
  A Finding's natural key is `(change_id, round, seq)`: the change under
@@ -66,14 +71,14 @@ round. `seq` is never auto-assigned; `finding add` refuses an occupied
66
71
  key, because two different findings under one key are two reviewers'
67
72
  work collapsed into one identity.
68
73
 
69
- ```bash
74
+ ```text
70
75
  canon finding add --change-id <c> --round <n> --seq <n> \
71
76
  --severity blocker|should-fix|note --disposition open \
72
- --reviewer <who> --summary "<one line>" \
73
- [--reviewed-sha <sha>] [--file-ref path/to/file.rs:120-134] [--scenario-id <id> …] [--actor-id <id>] [--session-id <id>]
74
- canon finding close --change-id <c> --round <n> --seq <n> \
75
- --disposition fixed --resolution-sha <sha> [--session-id <id>] # or rejected / deferred / open
76
- canon finding close --change-id <c> --round <n> --seq <n> \
77
+ --actor-id <who> --summary "<one line>" \
78
+ [--rev <rev>] [--resolution-rev <rev>] [--introduced-rev <rev>] [--file-ref path/to/file.rs:120-134] [--scenario-id <id>] [--session-id <id>]
79
+ canon finding close <c> --round <n> --seq <n> \
80
+ --disposition fixed --resolution-rev <rev> [--actor-id <id>] [--session-id <id>] # or rejected / deferred / open
81
+ canon finding close <c> --round <n> --seq <n> \
77
82
  --disposition rejected|deferred --reason "<why, one line>"
78
83
  ```
79
84
 
@@ -101,24 +106,34 @@ appends a second version at the same natural key — the first stays. Its
101
106
  `--actor-id` and `--session-id` name who authored the transition; the
102
107
  raiser's stay on the first version.
103
108
 
104
- Every sha flag (`--reviewed-sha`, `--resolution-sha`, `--introduced-by`)
105
- takes a full 40-character sha or a short one (4 or more lowercase hex
106
- characters). A short sha is resolved with `git rev-parse --verify
107
- <sha>^{commit}` in the repo, and the record stores the full sha. It is
108
- refused (exit `2`) when it names no commit, when more than one commit
109
- starts with it (pass more characters), when it only resolves by peeling a
110
- tag, or outside a git work tree.
109
+ Every commit option (`--rev`, `--resolution-rev`, `--introduced-rev`)
110
+ takes any git revision (`HEAD~1`, a branch, a tag, a full or short sha),
111
+ resolved with `git rev-parse --verify <rev>^{commit}`; the record stores
112
+ the full sha. `--rev` (the commit the round reviewed) defaults to `HEAD`,
113
+ and so does `--resolution-rev` on a `fixed` close; `--introduced-rev` has
114
+ no default and is only sourced, never guessed. A revision that names no
115
+ commit is refused (exit `2`). A finding recorded against uncommitted code
116
+ is allowed: the record carries the `codeTree` it saw and `worktreeDirty`.
117
+ Outside git, or in a repository with no commit, the write is refused with
118
+ `NO_COMMIT`.
119
+
120
+ Many findings at once: `--input` takes inline JSON, a file or `-`; an array
121
+ (or NDJSON) is a batch validated before any write. Keys are the option
122
+ names in camelCase (`changeId`, `actorId`, `resolutionRev`); `canon schema
123
+ finding add --json` shows the input schema and an example. An identical
124
+ repeat is `unchanged` (`meta.unchanged`) and writes nothing; a different
125
+ finding under an occupied key is `FINDING_SEQ_OCCUPIED`.
111
126
 
112
127
  ### A defect the author found in its own work
113
128
 
114
129
  Record it like any other finding, at the moment you find it and before
115
- review, with `--reviewer` and `--actor-id` set to your own id; never ask
130
+ review, with `--actor-id` set to your own id; never ask
116
131
  the reviewer to record it later under theirs. Nothing refuses a finding
117
132
  whose reviewer is also the implementer, and an open `blocker` the author
118
133
  raised blocks under `block_on_findings` exactly like a reviewer's.
119
- `--introduced-by` names the commit that introduced the defect, not who
120
- found it: `--introduced-by self` is a usage error (exit 2) that points at
121
- `--reviewer`.
134
+ `--introduced-rev` names the commit that introduced the defect, not who
135
+ found it: `--introduced-rev self` is a usage error (exit 2) that points at
136
+ `--actor-id`.
122
137
 
123
138
  ### Severities
124
139
 
@@ -139,7 +154,7 @@ text in the summary, not a field.
139
154
  | Disposition | Meaning |
140
155
  |---|---|
141
156
  | `open` | Raised and not yet dealt with. The default on `finding add`; `finding close --disposition open` reopens. |
142
- | `fixed` | Fixed by a commit. Requires `--resolution-sha <sha>` naming a commit this repo holds; only `fixed` may carry one. |
157
+ | `fixed` | Fixed by a commit. Carries `--resolution-rev <rev>` (default `HEAD`) naming a commit this repo holds; only `fixed` may carry one. |
143
158
  | `rejected` | The reviewer's point was considered and declined. Needs `--reason`. |
144
159
  | `deferred` | Accepted, but postponed to later work. Needs `--reason`. |
145
160
 
@@ -150,55 +165,68 @@ Every reader takes the **latest version per natural key**
150
165
  uses. A blocker raised `open` and later closed `fixed` counts as fixed; a
151
166
  fixed finding reopened with `--disposition open` counts as open again.
152
167
 
153
- ## `canon review add`
168
+ ## `canon review scenario`
154
169
 
155
- ```bash
156
- canon review add --project-id <root-id> --scenario-id <id> [--scenario-id <id>]... \
157
- [--scenario-ids-from <file|->] \
158
- --reviewer <who> --pin <sha-or-ref> --role <role> \
159
- (--upstream-ref <ref> | --original-spec-ref <ref>) [--actor-id <id>] [--session-id <id>] \
160
- [--outcome signed|indeterminate|unavailable] \
170
+ ```text
171
+ canon review scenario <scenario-id> [<scenario-id>] --project-id <root-id> \
172
+ --actor-id <who> [--rev <rev>] --role <role> \
173
+ (--upstream-ref <ref> | --original-spec-ref <ref>) [--session-id <id>] \
174
+ [--review-outcome signed|indeterminate|unavailable] \
161
175
  [--reviewer-provider <p>] [--reviewer-model <m>] [--reviewer-harness <h>] \
162
- [--artifact <path>]... [--max-artifact-mib <MiB>]
163
- canon review add --project-id <root> --change-id <slug> --reviewer <who> --pin <sha-or-ref> \
164
- --role reviewer (--upstream-ref <ref> | --original-spec-ref <ref>) … # a chore, below
176
+ [--artifact <path>] [--artifact <path>] [--max-artifact-mib <MiB>]
177
+ canon review change <slug> --project-id <root> --actor-id <who> [--rev <rev>] \
178
+ --role reviewer (--upstream-ref <ref> | --original-spec-ref <ref>) # a chore, below
165
179
  ```
166
180
 
167
181
  One attributed Review record per scenario, joined on
168
182
  `(project_id, scenario_id)` — both are required because two spec roots
169
183
  may carry the same scenario id. Exactly one provenance ref is required.
170
- `--actor-id` defaults to `canon`; `--session-id` fills `actor.session_id`.
184
+ `--actor-id` is the reviewer and is required; `--session-id` fills `actor.session_id`.
171
185
  A Review carries no verdict about the behavior; the `verifying → shipped`
172
186
  ship gate still refuses missing or `Divergent` evidence verdicts on its
173
- own (a `Divergent` one passes only while a reviewer's `canon divergence
187
+ own (a `Divergent` one passes only while a human's `canon divergence
174
188
  accept` holds). It is written directly to the ledger, with no staging step, and says
175
- so: `canon review add: wrote <path> (new) — written directly; nothing to
189
+ so: `canon review scenario: wrote <path> (new) — written directly; nothing to
176
190
  promote`.
177
191
 
192
+ `--rev` is the commit the review is about: any git revision, default
193
+ `HEAD`. The review records the full sha and the `codeTree` of the code it
194
+ saw (the tree with `.canon/`, the spec roots and `code.exclude` removed), and
195
+ `worktreeDirty` when that code is uncommitted. Reviewing uncommitted code is
196
+ allowed, and the commit made from it has the same code tree, so committing it
197
+ afterwards leaves the review as it was: a review is judged by its pins (the
198
+ scenario and what its evidence says), not by the commit. Outside git, or
199
+ with no commit, the write is refused with `NO_COMMIT`. An identical review
200
+ written again is `unchanged` (`meta.unchanged` under `--json`) and adds no
201
+ record.
202
+
203
+ **Done when:** `canon gate check` reports no `unreviewed-promotion` for the
204
+ scenarios you reviewed; a review that does not count shows up there with
205
+ its reason.
206
+
178
207
  ### Several scenarios in one call (0.18)
179
208
 
180
- `--scenario-id` is repeatable, and `--scenario-ids-from <file>` (`-` reads
181
- stdin) adds one id per line; `#` starts a comment and blank lines are
182
- skipped. One reviewer, pin, provenance ref and set of artifacts cover
209
+ The scenario operand is repeatable, and an `--input` array (see
210
+ `canon schema review scenario`) batches several calls. One reviewer, pin, provenance ref and set of artifacts cover
183
211
  every review; each review pins its own scenario and evidence, and each
184
212
  gets its own `pinned` and `wrote` line. The artifacts are stored once.
185
- It is all or nothing: a scenario with no record, or a line in the file
213
+ It is all or nothing: a scenario with no record, or an operand
186
214
  that is not a scenario id, refuses the call (exit 2) and writes no review.
187
215
  This is also the batch re-pin after `canon evidence add` reports reviews
188
216
  it made stale (see `canon-gate`).
189
217
 
190
- ### A chore is reviewed as a change (`--change-id`, 0.23)
218
+ ### A chore is reviewed as a change (`review change`, 0.23)
191
219
 
192
220
  A chore adds no scenarios, and recording the suite again after it leaves
193
221
  every scenario review current (a review pins the evidence's verdict and
194
222
  checks, so the same verdicts from the same cases change nothing). What the
195
223
  chore needs instead is one change-level review: the reviewer signs its
196
- invariants and checks against the diff with `canon review add --change-id
197
- <slug> …`, in place of `--scenario-id`. The review pins the chore's brief
224
+ invariants and checks against the diff with `canon review change
225
+ <slug>`, in place of `review scenario`. The review pins the chore's brief
198
226
  (its digest, less the `Approved:` line), so an edit to the brief stales it,
199
227
  and `--to shipped` refuses a chore with no signed, current change-level
200
228
  review (`spec_coverage.require_review.distinct_actor` asks it of a reviewer
201
- and session that did not attest the subject's evidence). `--change-id` takes a
229
+ and session that did not attest the subject's evidence). `review change` takes a
202
230
  chore's slug and refuses a feature change.
203
231
 
204
232
  ### What the reviewer looked at (artifacts)
@@ -218,8 +246,8 @@ review records each distinct file once, in the order given:
218
246
  "artifacts": [{"path": "reports/title.png", "sha256": "<64 hex>"}]
219
247
  ```
220
248
 
221
- The field is absent when no `--artifact` is given. `review add` prints
222
- `canon review add: artifact store holds <n> bound file(s) under
249
+ The field is absent when no `--artifact` is given. `review scenario` prints
250
+ `canon review scenario: artifact store holds <n> bound file(s) under
223
251
  .canon/artifacts/sha256/ (<k> newly stored) — commit them with the
224
252
  ledger`.
225
253
 
@@ -227,13 +255,13 @@ ledger`.
227
255
  review (the latest per `(project_id, scenario_id, reviewer)`, unless it
228
256
  went stale against its scenario) by the evidence rule (see `canon-gate`,
229
257
  "Bound evidence stays provable"). A missing blob whose working-tree file
230
- still matches is an advisory naming `canon evidence vault`, which stores
258
+ still matches is an advisory naming `canon artifacts store`, which stores
231
259
  it back. A missing blob with a changed or missing working-tree file, or
232
260
  an altered blob, is `stale-evidence` on the review's scenario, naming
233
261
  the review:
234
262
 
235
263
  ```
236
- stale-evidence world.demo.01 — review by `reviewer-2` (actor `reviewer-2`, 2026-10-11T09:00:00Z) bound file `reports/title.png` recorded sha256 <hex>; stored blob .canon/artifacts/sha256/<hex>: missing; working tree: <other hex> — the bound bytes are gone, look again and re-record the review with `canon review add --artifact <path>`
264
+ stale-evidence world.demo.01 — review by `reviewer-2` (actor `reviewer-2`, 2026-10-11T09:00:00Z) bound file `reports/title.png` recorded sha256 <hex>; stored blob .canon/artifacts/sha256/<hex>: missing; working tree: <other hex> — the bound bytes are gone, look again and re-record the review with `canon review scenario <scenario-id> --artifact <path>`
237
265
  ```
238
266
 
239
267
  The reviewer's later review replaces the earlier one, so its files are
@@ -245,7 +273,7 @@ screenshot shows.
245
273
 
246
274
  ### What the review saw (pins)
247
275
 
248
- `review add` reads the corpus and records `pins` on the review; the
276
+ `review scenario` reads the corpus and records `pins` on the review; the
249
277
  reviewer never types them:
250
278
 
251
279
  - `scenario_digest` — the scenario record's `scenario_digest`: a sha256
@@ -268,7 +296,7 @@ reviewer never types them:
268
296
  verdict from the same checks again leaves the review current. A scenario
269
297
  with no evidence yet is pinned with an empty list.
270
298
 
271
- It prints `canon review add: pinned <id> at scenario digest <12 hex> and the
299
+ It prints `canon review scenario: pinned <id> at scenario digest <12 hex> and the
272
300
  verdict and checks of its <n> role(s) of evidence; …` (`at source digest` for
273
301
  a file pin). A
274
302
  scenario with no record (never synced) is refused with exit 2 and nothing
@@ -284,15 +312,15 @@ final.
284
312
 
285
313
  ### The reviewer's outcome and runtime
286
314
 
287
- `--outcome` records how the reviewer's run ended: `signed` (the default:
315
+ `--review-outcome` records how the reviewer's run ended: `signed` (the default:
288
316
  an approval), `indeterminate` (it ran and reached no verdict) or
289
317
  `unavailable` (it could not run). Only `signed` counts; the other two
290
318
  are recorded so a failed review is visible, never mistaken for a
291
- sign-off or a rejection, and `review add` says so. `--reviewer-provider`,
319
+ sign-off or a rejection, and `review scenario` says so. `--reviewer-provider`,
292
320
  `--reviewer-model` and `--reviewer-harness` record the runtime that
293
321
  produced the review, as given. An empty or padded label is a usage error.
294
322
 
295
- `--session-id` (on `evidence add`, `review add`, `finding add` and
323
+ `--session-id` (on `evidence add`, `review scenario`, `finding add` and
296
324
  `finding close`) takes one opaque token: non-empty, no surrounding
297
325
  whitespace, no control characters. Anything else is a usage error
298
326
  (exit 2) and nothing is written.
@@ -361,8 +389,8 @@ A review written before 0.23 pins something the gate no longer compares: a
361
389
  count until `canon migrate` rewrites it to what the evidence says (see
362
390
  `canon-gate`). A review that was current under the rule it was written under
363
391
  becomes a current review; one that was stale stays stale, and its scenario
364
- needs a new `canon review add`, which pins what it saw and replaces the
365
- reviewer's earlier one. The gate, `canon status` and `canon subject status`
392
+ needs a new `canon review scenario`, which pins what it saw and replaces the
393
+ reviewer's earlier one. The gate, `canon status` and `canon subject move`
366
394
  print one advisory naming how many scenarios are waiting for `canon
367
395
  migrate`. In CI, check out full history (`fetch-depth: 0`) for the job that
368
396
  runs `canon migrate`, or a pre-0.15 review whose commit is missing is pinned
@@ -376,7 +404,7 @@ counting: a current signed review failing only `distinct_actor`, then a
376
404
  stale review, then non-signed outcomes.
377
405
 
378
406
  ```
379
- unreviewed-promotion world.demo.01 — no review record for this scenario; spec_coverage.require_review wants an independent review (`canon review add`) once its subject is claimed done
407
+ unreviewed-promotion world.demo.01 — no review record for this scenario; spec_coverage.require_review wants an independent review (`canon review scenario`) once its subject is claimed done
380
408
  ```
381
409
 
382
410
  or, when the only reviews are self-reviews:
@@ -397,13 +425,13 @@ review (`its spec changed`, `its evidence changed`, `its spec and its
397
425
  evidence changed`):
398
426
 
399
427
  ```
400
- unreviewed-promotion world.demo.01 — stale review by `reviewer-2`: its evidence changed (the latest evidence records are not the pinned ones) since the review; a pinned review counts only while what it saw is current — review it again (`canon review add`)
428
+ unreviewed-promotion world.demo.01 — stale review by `reviewer-2`: its evidence changed (the latest evidence records are not the pinned ones) since the review; a pinned review counts only while what it saw is current — review it again (`canon review scenario`)
401
429
  ```
402
430
 
403
431
  or, when every latest review recorded no sign-off:
404
432
 
405
433
  ```
406
- unreviewed-promotion world.demo.01 — no signed review: the latest review recorded no sign-off (`reviewer-2` indeterminate); an indeterminate or unavailable review is a gap, never an approval — run the review again and record `--outcome signed`
434
+ unreviewed-promotion world.demo.01 — no signed review: the latest review recorded no sign-off (`reviewer-2` indeterminate); an indeterminate or unavailable review is a gap, never an approval — run the review again and record `--review-outcome signed`
407
435
  ```
408
436
 
409
437
  A non-signed review is a gap even without `distinct_actor`.
@@ -416,7 +444,7 @@ subject's `change_ids` (`canon subject adopt`). The subject string is
416
444
  `<change_id>#<round>.<seq>`:
417
445
 
418
446
  ```
419
- open-blocker c-demo#1.1 — open blocker finding by `reviewer-2` on change `c-demo` (subject `demo-subject`): unbounded subprocess wait; fix it and `canon finding close --disposition fixed --resolution-sha <sha>`, or close it as rejected or deferred
447
+ open-blocker c-demo#1.1 — open blocker finding by `reviewer-2` on change `c-demo` (subject `demo-subject`): unbounded subprocess wait; fix it and `canon finding close <change> --round <n> --seq <n> --disposition fixed`, or close it as rejected or deferred
420
448
  ```
421
449
 
422
450
  Findings on changes no in-scope subject has adopted do not block.
@@ -435,11 +463,11 @@ review waivers: 1 advisory(ies) — not failing the gate:
435
463
 
436
464
  ## The status guard
437
465
 
438
- With `require_review` present, `canon subject status <id> --to <state>`
466
+ With `require_review` present, `canon subject move <id> --to <state>`
439
467
  prints on stderr which review checks it ran or skipped:
440
468
 
441
- ```
442
- canon subject status: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
469
+ ```stderr
470
+ canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
443
471
  ran unreviewed-promotion — every owned scenario needs a signed review, current with the spec and evidence it pinned, by an actor, and from a session, other than its evidence's
444
472
  ran open-blocker — 1 adopted change(s) checked for open blocker findings
445
473
  ```
@@ -15,7 +15,7 @@ no live database. Swap `hot` to postgres (the commented stanza `canon
15
15
  init` ships beside the sqlite one) once team-scale multi-agent
16
16
  concurrency outgrows sqlite's single-writer mode.
17
17
 
18
- ## `canon ingest sessions [--watch] [--interval-secs N] [--home <dir>] [--canon-yaml <path>] [--full] [--all-workspaces]`
18
+ ## `canon ingest sessions [--watch] [--interval-secs N] [--home <dir>] [--full] [--all-workspaces]`
19
19
 
20
20
  ```bash
21
21
  canon ingest sessions # one pass over this project's sources
@@ -25,6 +25,10 @@ canon ingest sessions --all-workspaces # machine-wide scan
25
25
  canon ingest sessions --home /custom # override the scan-root home ($HOME)
26
26
  ```
27
27
 
28
+ **Done when:** the run summary (below) ends with `malformed records … : 0`
29
+ and `canon query --kind session` lists the sessions; a rerun reports the
30
+ files as `skipped unchanged (watermark)` and writes nothing.
31
+
28
32
  ## The four adapters
29
33
 
30
34
  Registered in order: **`omp`** (omp/pi sessions), **`hermes`**,
@@ -179,7 +183,7 @@ canon query --kind event # filter detail.label == "user_directive"
179
183
  Each pass prints the active scope, one line per adapter, then totals:
180
184
 
181
185
  ```
182
- scope: project /Users/me/Workspace/canon (2 roots)
186
+ scope: project /path/to/repo (2 roots)
183
187
  omp: 3 file(s) scanned, 1 reparsed, 2 skipped unchanged (watermark), 4 row(s) parsed, 0 malformed record(s)
184
188
  claude-code: 1 file(s) scanned, 0 reparsed, 1 skipped unchanged (watermark), 0 row(s) parsed, 0 malformed record(s)
185
189
  sessions normalized: 4
@@ -208,7 +212,7 @@ events written: 37
208
212
 
209
213
  ## What this skill does NOT cover
210
214
 
211
- - Artifact/verdict ingestion (`canon ingest artifacts`) — a different
215
+ - Artifact/verdict ingestion (`canon ingest records`) — a different
212
216
  pipeline; see the `canon-artifact-ingest` skill.
213
217
  - Cost-parity computation — omp/pi's own cost is `0.0`/`Unknown` per the
214
218
  ported behavior.
@@ -79,18 +79,22 @@ re-selects the record but the destination write is a no-op. A kind
79
79
  split across two rungs (some aged, some not) still reads correctly —
80
80
  `canon query` fans out.
81
81
 
82
+ **Done when:** after `canon tier age --commit --plan-digest <digest from the
83
+ preview>`, a bare `canon tier age` previews no effect (`moved` is `0`).
84
+
82
85
  ## Running `canon tier age` / `canon query`
83
86
 
84
- Both take `--canon-yaml <path>` (default `canon.yaml` in the current
85
- directory).
87
+ Both read the `canon.yaml` of `--repo <dir>` (default: the nearest ancestor
88
+ directory holding one).
86
89
 
87
90
  ```bash
88
- # Preview what would move (read-only; writes/deletes nothing).
89
- canon tier age --dry-run
90
-
91
- # Apply every `aging:` rule once (the destructive move+delete).
91
+ # Preview what would move (the bare run is read-only; writes/deletes nothing).
92
92
  canon tier age
93
93
 
94
+ # Apply every `aging:` rule once (the destructive move+delete), with the
95
+ # `planDigest` the preview printed.
96
+ canon tier age --commit --plan-digest "$PLAN_DIGEST"
97
+
94
98
  # Read a kind, fanning out across its routed rung AND its aging
95
99
  # destination, merged by time. --kind is the kind wire string — the
96
100
  # same vocabulary as routing:/aging: (`change`, `handoff`, …).
@@ -116,8 +120,8 @@ read the ledger only.
116
120
 
117
121
  ```bash
118
122
  canon query --kind evidence --history # every version, archive included
119
- canon ledger compact --dry-run # report; writes nothing
120
- canon ledger compact # pre-0.23 ledger or interrupted move; idempotent; `canon migrate` runs it
123
+ canon ledger compact # preview; writes nothing
124
+ canon ledger compact --commit --plan-digest "$PLAN_DIGEST" # pre-0.23 ledger or interrupted move; idempotent; `canon migrate` runs it
121
125
  ```
122
126
 
123
127
  A crash between the write and the move leaves a readable ledger that the next
@@ -125,6 +129,9 @@ append or `canon ledger compact` finishes. The archive is local, not routed
125
129
  through `tiers:`; a `tiers.local.root` whose directory is not named `ledger`
126
130
  has no archive and keeps every version.
127
131
 
132
+ **Done when:** after `canon ledger compact --commit --plan-digest <digest
133
+ from the preview>`, a bare `canon ledger compact` previews no effect.
134
+
128
135
  ## Where artifact bytes live (`artifact_store:`)
129
136
 
130
137
  ```yaml
@@ -133,40 +140,40 @@ artifact_store: { backend: local } # default
133
140
  ```
134
141
 
135
142
  `local` is `.canon/artifacts/sha256/`, git-tracked and credential-free. An
136
- object-store tier gets `evidence add`, `review add` and `evidence vault`
143
+ object-store tier gets `evidence add`, `review scenario` and `artifacts store`
137
144
  uploads under `<prefix>sha256/<digest>` and keeps nothing locally. The gate
138
145
  and `canon artifacts verify [--full]` ask the store and refuse, never pass,
139
- when it cannot be reached. `canon artifacts migrate --to <tier> [--dry-run]`
146
+ when it cannot be reached. `canon artifacts move --tier <tier>` (a preview; `--commit --plan-digest <digest>` acts)
140
147
  uploads, reads back and verifies every local blob, then writes the
141
148
  `artifact_store:` block, removes the local copies and ignores
142
149
  `.canon/artifacts/`; commit the removals, `.gitignore` and `canon.yaml`. It is
143
150
  resumable and a second run finds nothing to do.
144
151
 
145
- ## What `canon report` does and doesn't read
152
+ ## What `canon report build` does and doesn't read
146
153
 
147
- canon exposes layered `stg_`/`int_`/`mart_` query views; `canon report`
154
+ canon exposes layered `stg_`/`int_`/`mart_` query views; `canon report build`
148
155
  builds its numbers from the `mart_` views. Those read ONLY local roots
149
156
  — the git ledger, the sqlite `hot` db file (local, no credential; read
150
- since 0.18) and a LOCAL `.canon/r2` parquet mirror. `canon report`
157
+ since 0.18) and a LOCAL `.canon/r2` parquet mirror. `canon report build`
151
158
  never opens a live DB connection or the live bucket, so:
152
159
 
153
- - Kinds routed to a postgres `hot` rung do NOT appear in `canon
154
- report`; kinds routed to `canon init`'s default sqlite `hot` rung do.
160
+ - Kinds routed to a postgres `hot` rung do NOT appear in `canon report
161
+ build`; kinds routed to `canon init`'s default sqlite `hot` rung do.
155
162
  - Kinds routed to `cold` (s3) appear only if a local `.canon/r2` mirror
156
163
  has been separately materialized — there is no automatic sync.
157
164
 
158
165
  These kinds are not lost: read them with `canon query --kind <kind>`.
159
166
  The gap is named loud, not under-counted — when any routed kind isn't
160
- report-readable, `canon report` renders a `## Kinds not read directly`
167
+ report-readable, `canon report build` renders a `## Kinds not read directly`
161
168
  section listing them and emits a matching stderr `WARN`.
162
169
 
163
170
  ## Retention, export, and access audit
164
171
 
165
- `canon purge --kind <kind> --before <RFC3339> (--plan | --confirm <planDigest>) [--repo <dir>] [--json]`
166
- is the canonical data-lifecycle boundary: `--plan` prints the removal set and
167
- its `planDigest` and deletes nothing; `--confirm <planDigest>` deletes only if
172
+ `canon purge --kind <kind> --before <RFC3339> [--commit --plan-digest <planDigest>] [--repo <dir>] [--json]`
173
+ is the canonical data-lifecycle boundary: the bare run previews: it prints the removal set and
174
+ its `planDigest` and deletes nothing; `--commit --plan-digest <planDigest>` deletes only if
168
175
  the plan recomputed now has the same digest (`PLAN_CHANGED`, exit 2, when the
169
- data moved), and a bare `purge` is refused (`PURGE_PLAN_REQUIRED`). The only purgeable kinds are
176
+ data moved). The only purgeable kinds are
170
177
  `session`, `run`, `event`, and `trajectory`; the cutoff applies to every
171
178
  routed rung and every configured aging destination, including retained
172
179
  historical versions. For `trajectory`, the command also purges the
@@ -179,14 +186,19 @@ an explicit `partial` result with matched/deleted counts and a nonzero
179
186
  status. Purge never rewrites Git history or deletes source transcript
180
187
  files.
181
188
 
189
+ **Done when:** after `canon purge --kind <kind> --before <time> --commit
190
+ --plan-digest <digest from the preview>`, a bare `canon purge` with the same
191
+ arguments previews an empty removal set.
192
+
182
193
  With `--json`, `purge` and `export` answer `{ "data", "meta" }` like every other
183
194
  command: `data` is the plan or manifest, `meta.next` the step after (a plan's is the
184
- human's review and `--confirm`), and an export's page state (`total`, `returned`,
185
- `nextCursor`) sits in `meta`. `export --json --out <file>` writes the manifest to the
186
- file and answers with `data: { out, kind, recordCount }`.
195
+ human's review and `--commit --plan-digest`), and an export's page state (`total`, `returned`,
196
+ `nextCursor`) sits in `meta`. `export --json --output <file>` writes the manifest to the
197
+ file and answers with `data: { output, kind, recordCount }`; `--dry-run`
198
+ answers with what it would write and writes nothing.
187
199
 
188
200
  `canon export --kind <kind> [--before <RFC3339>] [--after <RFC3339>]
189
- [--out <file>] [--json] [--limit <n> | --all] [--cursor <c>]` emits a versioned manifest containing source scope,
201
+ [--output <file>] [--json] [--limit <n> | --all] [--cursor <c>]` emits a versioned manifest containing source scope,
190
202
  counts, digests, and redacted metadata. It does not authorize backend access;
191
203
  credentials remain an operator prerequisite. New output files are mode
192
204
  `0600`. Raw event detail text is excluded unless `--include-sensitive` is
@@ -199,7 +211,7 @@ query:
199
211
 
200
212
  Every query, export, and purge appends an actor-stamped record to
201
213
  `.canon/audit/access.jsonl` (mode `0600` on creation) in the repository
202
- whose `canon.yaml` it read (through `--repo` or `--canon-yaml`), never in
214
+ whose `canon.yaml` it read (through `--repo`), never in
203
215
  the current directory; with no `canon.yaml` there is no audit and nothing
204
216
  is written. The log is local operator state: `canon init` keeps
205
217
  `.canon/audit/` out of git (below). `CANON_ACTOR` takes
@@ -212,7 +224,7 @@ record bodies.
212
224
  Four writes stage their record instead of committing it: `canon evidence
213
225
  add`, `canon finding add`, `canon finding close` and `canon divergence add`
214
226
  (under `.canon/ledger/_staging/`, one staging shape for every kind,
215
- committed by `canon gate promote`; `canon divergence promote` commits only
227
+ committed by `canon gate promote`; `canon gate promote --kind divergence` commits only
216
228
  the staged divergences). `canon divergence resolve|defer|accept` stage and
217
229
  promote their own record in the same run. `canon.yaml`'s
218
230
  `write:` section decides whether they promote in the same run:
@@ -240,7 +252,7 @@ line ends ``— run `canon gate promote` to commit it`` (`canon divergence
240
252
  promote` for a divergence), and the command exits `1`. With neither flag,
241
253
  a malformed `write:` section (anything but `promote: auto | manual`)
242
254
  refuses the write, exit `2`, before anything is staged. `canon init
243
- --check-config` reports `[PASS] write (promote: auto)`, `[not configured]
255
+ --check` reports `[PASS] write (promote: auto)`, `[not configured]
244
256
  write (promote: manual)`, or `[FAIL] write: …`. `canon gate promote` still
245
257
  works under `auto` and is idempotent: with nothing staged it prints
246
258
  `nothing staged` and exits `0`.
@@ -264,7 +276,7 @@ install|check|doctor` follow the section; `install` prunes projected files the b
264
276
  --providers=<list>` rewrites it in place. Without the section they use the
265
277
  install lock's providers, then the detected ones; nothing undetected is ever
266
278
  added. A present section that is not this shape, or names another harness,
267
- fails those commands (exit `1`), and `canon init --check-config` reports
279
+ fails those commands (exit `1`), and `canon init --check` reports
268
280
  `[PASS] skills (providers: …)`, `[not configured] skills (…)`, or
269
281
  `[FAIL] skills: …`.
270
282
 
@@ -278,13 +290,13 @@ or one whose recorded source digest differs from the file's current bytes,
278
290
  or when the index holds a scenario of a spec root that no `.feature` file
279
291
  of it declares any more.
280
292
 
281
- The commands that write records (`canon subject status`, `canon review
282
- add` and `canon evidence add`) rebuild a stale index on disk first: they
293
+ The commands that write records (`canon subject move`, `canon review
294
+ scenario`, `canon evidence add` and `canon artifacts store`) rebuild a stale index on disk first: they
283
295
  run `canon inventory sync`'s code on the changed files (validation still
284
296
  covers the whole root) and print one stderr line:
285
297
 
286
- ```
287
- canon evidence add: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
298
+ ```stderr
299
+ 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
288
300
  ```
289
301
 
290
302
  The commands that only read (`canon gate check`, `canon status`) write
@@ -299,8 +311,8 @@ the report panels then treat it as absent; re-adding the scenario writes
299
311
  a live generation that supersedes the tombstone. A root that fails to
300
312
  sync writes no tombstone either.
301
313
 
302
- ```
303
- canon evidence add: refreshed the scenario index from 1 scenario(s) no longer in any feature file (cart.pay.01): 1 record(s) written
314
+ ```stderr
315
+ canon artifacts store: refreshed the scenario index from 1 scenario(s) no longer in any feature file (cart.pay.01): 1 record(s) written
304
316
  ```
305
317
 
306
318
  `canon inventory sync` and every refresh hold an OS file lock on
@@ -317,8 +329,8 @@ still runs; `canon gate check` then fails with `uncovered-cell <root>`,
317
329
  the `verifying → shipped` guard refuses, and `canon status` lists only
318
330
  `canon inventory sync`:
319
331
 
320
- ```
321
- canon evidence add: found the scenario index stale for 1 changed feature file(s) (…): 0 record(s) written; NOT refreshed: root `root` (2 format violation(s), 0 sync error(s)) — `canon inventory sync` lists them
332
+ ```stderr
333
+ canon artifacts store: found the scenario index stale for 1 changed feature file(s) (…): 0 record(s) written; NOT refreshed: root `root` (2 format violation(s), 0 sync error(s)) — `canon inventory sync` lists them
322
334
  ```
323
335
 
324
336
  Nothing is written in a directory without `canon.yaml`. `canon inventory
@@ -328,7 +340,7 @@ tag diagnostics.
328
340
  ## The artifact store lock
329
341
 
330
342
  Every write to the evidence artifact store (`.canon/artifacts/sha256/`:
331
- `canon evidence add`, `canon review add`, `canon evidence vault`) holds an
343
+ `canon evidence add`, `canon review scenario`, `canon artifacts store`) holds an
332
344
  OS file lock on `.canon/artifact-store.lock` from its "already stored?"
333
345
  check through its last rename, so a write that fails and rolls back never
334
346
  removes a blob another writer published or counted as stored. A rollback
@@ -355,9 +367,23 @@ comment, only the missing ones):
355
367
  - `.canon/dashboard-snapshot/` — the snapshot `canon dashboard`
356
368
  regenerates on every run.
357
369
  - `.canon/learn/` and `.canon/r2/` — local learn scratch and the local
358
- object-store stand-in `canon report` writes.
370
+ object-store stand-in `canon report build` writes.
359
371
 
360
372
  A rerun on a repo that already has `canon.yaml` only refreshes
361
373
  `AGENTS.md`; `canon migrate` adds the lines an existing `.gitignore`
362
- lacks, and `canon skills doctor` and `canon init --check-config` name a
374
+ lacks, and `canon skills doctor` and `canon init --check` name a
363
375
  missing one.
376
+
377
+ ## Upgrading a 0.27 repository
378
+
379
+ `canon status`, `canon gate check` and `canon context` warn on a repo that
380
+ still holds 0.27 canon state and put `canon migrate --json` first in
381
+ `meta.next`. `canon migrate` is destructive-class: the bare run is a
382
+ preview (a report with `planDigest` and `effects[]`, exit 0, nothing
383
+ written); `canon migrate --commit --plan-digest <digest from the preview>`
384
+ acts, and only when the plan recomputed now has the same digest. Afterwards
385
+ run `canon skills install`, which writes the stub guide; the guide itself is
386
+ read with `canon skills show canon`.
387
+
388
+ **Done when:** `canon status` no longer warns about 0.27 state and
389
+ `canon migrate --json` is no longer the first step in `meta.next`.