@journeykit/canon 0.34.0 → 0.36.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 (126) hide show
  1. package/dist/skills/SKILL.src.md +47 -30
  2. package/dist/skills/reference/canon-artifact-ingest.md +6 -3
  3. package/dist/skills/reference/canon-authoring.md +9 -5
  4. package/dist/skills/reference/canon-context.md +6 -3
  5. package/dist/skills/reference/canon-fmt.md +2 -1
  6. package/dist/skills/reference/canon-gate.md +29 -21
  7. package/dist/skills/reference/canon-inventory.md +16 -11
  8. package/dist/skills/reference/canon-plan-import.md +6 -3
  9. package/dist/skills/reference/canon-plugins.md +12 -6
  10. package/dist/skills/reference/canon-policy.md +3 -3
  11. package/dist/skills/reference/canon-report-dashboard.md +11 -8
  12. package/dist/skills/reference/canon-review.md +8 -7
  13. package/dist/skills/reference/canon-session-ingest.md +12 -6
  14. package/dist/skills/reference/canon-storage.md +47 -17
  15. package/dist/skills/reference/canon-subject.md +45 -35
  16. package/dist/skills/reference/role-implementer.md +33 -33
  17. package/dist/skills/reference/role-orchestrator.md +83 -77
  18. package/dist/skills/reference/role-planner.md +28 -28
  19. package/dist/skills/reference/role-reviewer.md +29 -29
  20. package/man/canon-adapter-authorize.1 +2 -2
  21. package/man/canon-adapter-validate.1 +2 -2
  22. package/man/canon-adapter.1 +2 -2
  23. package/man/canon-artifacts-move.1 +6 -6
  24. package/man/canon-artifacts-store.1 +2 -2
  25. package/man/canon-artifacts-verify.1 +2 -2
  26. package/man/canon-artifacts.1 +2 -2
  27. package/man/canon-brief-approve.1 +5 -4
  28. package/man/canon-brief-check.1 +2 -2
  29. package/man/canon-brief-show.1 +2 -2
  30. package/man/canon-brief.1 +2 -2
  31. package/man/canon-change-new.1 +2 -2
  32. package/man/canon-change.1 +2 -2
  33. package/man/canon-completion.1 +2 -2
  34. package/man/canon-context-pack-add.1 +2 -2
  35. package/man/canon-context-pack-show.1 +2 -2
  36. package/man/canon-context-pack-verify.1 +2 -2
  37. package/man/canon-context-pack.1 +2 -2
  38. package/man/canon-context.1 +2 -2
  39. package/man/canon-dashboard.1 +2 -2
  40. package/man/canon-demo-init.1 +2 -2
  41. package/man/canon-demo-review.1 +2 -2
  42. package/man/canon-demo.1 +2 -2
  43. package/man/canon-dispatch-begin.1 +2 -2
  44. package/man/canon-dispatch-diff.1 +2 -2
  45. package/man/canon-dispatch-end.1 +2 -2
  46. package/man/canon-dispatch.1 +2 -2
  47. package/man/canon-divergence-accept.1 +2 -2
  48. package/man/canon-divergence-add.1 +3 -3
  49. package/man/canon-divergence-defer.1 +3 -3
  50. package/man/canon-divergence-list.1 +2 -2
  51. package/man/canon-divergence-resolve.1 +3 -3
  52. package/man/canon-divergence.1 +2 -2
  53. package/man/canon-evidence-add.1 +5 -5
  54. package/man/canon-evidence-approval-payload.1 +3 -3
  55. package/man/canon-evidence-audit.1 +4 -4
  56. package/man/canon-evidence.1 +2 -2
  57. package/man/canon-export.1 +2 -2
  58. package/man/canon-feature-new.1 +2 -2
  59. package/man/canon-feature.1 +2 -2
  60. package/man/canon-finding-add.1 +3 -3
  61. package/man/canon-finding-close.1 +2 -2
  62. package/man/canon-finding-list.1 +2 -2
  63. package/man/canon-finding.1 +2 -2
  64. package/man/canon-format.1 +2 -2
  65. package/man/canon-gate-check.1 +2 -2
  66. package/man/canon-gate-install-hooks.1 +2 -2
  67. package/man/canon-gate-promote.1 +2 -2
  68. package/man/canon-gate.1 +2 -2
  69. package/man/canon-ingest-plans.1 +2 -2
  70. package/man/canon-ingest-records.1 +2 -2
  71. package/man/canon-ingest-sessions.1 +2 -2
  72. package/man/canon-ingest.1 +2 -2
  73. package/man/canon-init.1 +7 -7
  74. package/man/canon-inventory-sync.1 +2 -2
  75. package/man/canon-inventory.1 +2 -2
  76. package/man/canon-ledger-compact.1 +5 -5
  77. package/man/canon-ledger.1 +3 -3
  78. package/man/canon-migrate.1 +8 -8
  79. package/man/canon-plugin-sync.1 +2 -2
  80. package/man/canon-plugin.1 +2 -2
  81. package/man/canon-policy-approve.1 +2 -2
  82. package/man/canon-policy-show.1 +2 -2
  83. package/man/canon-policy.1 +2 -2
  84. package/man/canon-prompt-add.1 +2 -2
  85. package/man/canon-prompt-show.1 +2 -2
  86. package/man/canon-prompt.1 +2 -2
  87. package/man/canon-purge.1 +7 -7
  88. package/man/canon-query.1 +2 -2
  89. package/man/canon-regime-show.1 +2 -2
  90. package/man/canon-regime.1 +2 -2
  91. package/man/canon-report-build.1 +2 -2
  92. package/man/canon-report-check.1 +2 -2
  93. package/man/canon-report-snapshot.1 +2 -2
  94. package/man/canon-report.1 +2 -2
  95. package/man/canon-retrieve.1 +2 -2
  96. package/man/canon-review-change.1 +3 -3
  97. package/man/canon-review-scenario.1 +3 -3
  98. package/man/canon-review.1 +2 -2
  99. package/man/canon-scenario-new.1 +2 -2
  100. package/man/canon-scenario.1 +2 -2
  101. package/man/canon-schema.1 +10 -4
  102. package/man/canon-search.1 +2 -2
  103. package/man/canon-selftest.1 +2 -2
  104. package/man/canon-skills-check.1 +2 -2
  105. package/man/canon-skills-doctor.1 +2 -2
  106. package/man/canon-skills-install.1 +2 -2
  107. package/man/canon-skills-show.1 +5 -5
  108. package/man/canon-skills.1 +2 -2
  109. package/man/canon-status.1 +2 -2
  110. package/man/canon-strategy-approval-payload.1 +2 -2
  111. package/man/canon-strategy-promote.1 +2 -2
  112. package/man/canon-strategy-rollback.1 +2 -2
  113. package/man/canon-strategy.1 +2 -2
  114. package/man/canon-subject-adopt.1 +2 -2
  115. package/man/canon-subject-move.1 +2 -2
  116. package/man/canon-subject-new.1 +2 -2
  117. package/man/canon-subject-show.1 +2 -2
  118. package/man/canon-subject-unadopt.1 +3 -3
  119. package/man/canon-subject.1 +2 -2
  120. package/man/canon-task-done.1 +2 -2
  121. package/man/canon-task.1 +2 -2
  122. package/man/canon-tier-age.1 +5 -5
  123. package/man/canon-tier.1 +2 -2
  124. package/man/canon-trace.1 +2 -2
  125. package/man/canon.1 +3 -3
  126. package/package.json +4 -4
@@ -49,15 +49,15 @@ a feature, a one-line request included. A human is needed once per scope:
49
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
50
  (one or more slugs, each with its own `--digest`, one answer for all, nothing written if any is refused).
51
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
52
+ A digest that no longer matches the brief is `RELAY_DIGEST_STALE`: show
53
+ it again. Without `--relayed-via` an agent role gets `ACTOR_DENIED`, and so
54
54
  does a repo whose `canon.yaml` says `approval: { relay: deny }`: then the
55
55
  human runs the call themselves. Never remove or unset your role
56
56
  (`env -u CANON_ROLE`, dropping `--as`) to run it yourself.
57
57
  Never edit the policy to make the gate pass: a policy that differs from
58
- the approved one fails closed (`POLICY_CHANGED_SINCE_APPROVAL`, not
58
+ the approved one fails closed (`POLICY_APPROVAL_STALE`, not
59
59
  waivable); stop and ask the human. A brief edited after its
60
- approval is not approved (`BRIEF_CHANGED_SINCE_APPROVAL`): it needs a new
60
+ approval is not approved (`BRIEF_APPROVAL_STALE`): it needs a new
61
61
  answer. The ship guard and `canon evidence add` refuse an unapproved or
62
62
  edited brief, but those are backstops: the stop itself is at step 1.
63
63
  - **Approval is scoped.** Evidence for a scenario tagged `@flow:<change>.<F-id>`
@@ -120,7 +120,7 @@ the record carries, so a review of a working tree survives the commit made
120
120
  from it; a review is judged by what it pins (the scenario and what its
121
121
  evidence says), never by the commit or the code tree. Outside a git work
122
122
  tree, or in a repo with no commits, a command that needs a commit refuses
123
- `NO_COMMIT`.
123
+ `COMMIT_REQUIRED`.
124
124
 
125
125
  ### Evidence follows the code
126
126
 
@@ -181,7 +181,7 @@ names the stores not read.
181
181
 
182
182
  canon cannot detect a role; you declare it. Pass `--as <role>` or set
183
183
  `CANON_ROLE=planner|implementer|reviewer|orchestrator`; a flag wins over the
184
- variable, and an unknown value is refused (`UNKNOWN_ROLE`).
184
+ variable, and an unknown value is refused (`ROLE_INVALID`).
185
185
 
186
186
  - **A role is set, or you were spawned as one:** load only
187
187
  `canon skills show role-<role>` and do that role's steps. `canon status`
@@ -211,30 +211,40 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
211
211
  your complete command set, every option of every leaf included. Run `canon schema <command> --json` only for a
212
212
  command it does not list, or after a `USAGE` refusal (read `error.field`
213
213
  and `error.expected` first). `canon schema --json` is the tree of every group and command
214
- with its `effect` and `x-canon.roles` (`--as <role>` lists one role's, and `x-canon.as` names it); `canon schema <group> --json` lists a group's
215
- commands; `canon schema <command> --json` is one command in full: `options` (each with
216
- `valueType`, a typed `default`, `possibleValues`, `env`, `flagOnly`), `errors`, `outputs`
217
- with the JSON Schema of each report in `schemas`, `input` (the schema of one `--input`
218
- document and a complete `example`) and `examples`. The first line of every `--help`
219
- points at it.
214
+ with its `effect` and `x-canon.roles` (`--as <role>` lists one role's, and `x-canon.as` names it);
215
+ its `options` define once the options that two or more commands share (`--repo`, `--as`, `--actor`, …)
216
+ and a command names them. `canon schema <group> --json` lists a group's
217
+ commands; `canon schema <command> --json` is the call surface of one command and nothing
218
+ else: `options` (each name of a tree option, or an object with `valueType`, a typed
219
+ `default`, `possibleValues`, `env`, `flagOnly`), `operands`, `constraints`, `validators`, `errors`,
220
+ `outputs`, `input` (what one `--input` document is and a complete `example`) and `examples`.
221
+ A member at its default is absent. `--json` is always accepted, `--input` when the command
222
+ has `input`, `--fields` when an output has `fields`, and the codes `USAGE` (with canon's
223
+ finer `*_INVALID`/`*_REQUIRED` argument codes), `INTERNAL`, `INPUT_*`, `BATCH_INCOMPLETE`,
224
+ `PLAN_STALE` (with `--commit`) and `CURSOR_INVALID` (with `--cursor`) can come without
225
+ being listed. `--commit` and `--plan-digest` are listed on exactly the commands that offer
226
+ them: a command that lists `commit` previews on a bare run. `canon schema <command> --schemas --json`
227
+ gives the JSON Schema of each report in `schemas`, `Input` (the schema of one `--input`
228
+ document) and `rejects` (what each validator refuses, in order); `#/schemas/<Name>` in
229
+ the command document resolves there. The first line of every `--help` points at it.
220
230
  - Pass `--json` and read stdout as one document, nothing on stderr. Success is
221
231
  `{"ok":true,"data":…,"meta":…}`; failure is
222
232
  `{"ok":false,"error":{…},"meta":…}` (a check that fails keeps its report in
223
233
  `data`). `meta` carries `tool`, `toolVersion`, `contract` (`atip/1`),
224
- `contractVersion` (`1.1`), `schemaVersion`,
234
+ `contractVersion` (`1.4`), `schemaVersion`,
225
235
  `command`, and when present `next`, `warnings` (`[{code, message}]`) and
226
236
  `page`; a repeated write that changed nothing reports `data.unchanged: true`.
227
237
  Absent members are omitted, never `null` or `[]` (a value you sent empty comes back as `received: ""`).
228
238
  Read the members you know and ignore the ones you do not: a later canon
229
239
  adds members, and a value of a closed set you have not seen (a `severity`, an
230
240
  `outcome`, a `reason`) is one item to leave out, never a reason to reject the document. A paged list puts
231
- `meta.page.nextCursor` on the call's `meta.next` as `--cursor <nextCursor>`;
232
- no `nextCursor` means no more.
241
+ `meta.page.nextCursor` in the first entry of the call's `meta.next` as `--cursor=<nextCursor>`
242
+ (run that entry as it is); no `nextCursor` means no more.
233
243
  On failure branch on `error.code`, and on `error.reason` where the code has
234
244
  reasons (`INPUT_INVALID` says `NOT_JSON`, `UNKNOWN_KEY`, `STDIN_TTY`, … so you
235
245
  know whether to fix the JSON or the shell); fix the option `error.field` names
236
246
  using the `error.expected` values (`field` is an option name, or a JSON
237
- pointer such as `/items/2/scenario` into an `--input` document), and
247
+ pointer such as `/2/scenario` into an `--input` document, `/<index>/<key>` in a batch), and
238
248
  follow `error.hint`: it is one runnable command line that starts with `canon`, the
239
249
  same with `<PLACEHOLDER>`s you fill in, or one sentence. The codes
240
250
  are stable; `canon schema --errors --json` lists them with their reasons and
@@ -243,7 +253,7 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
243
253
  - **Exit codes:** only 0, 1 and 2 exist: 0 ok; 1 the command ran and its answer
244
254
  is negative or incomplete (a failed check, a violation, `unverifiable` when
245
255
  nothing was examined, a partly failed batch); 2 refused to run (usage,
246
- `CONFIG_MISSING`, an id or file that does not exist, an invalid argument).
256
+ `CONFIG_REQUIRED`, an id or file that does not exist, an invalid argument).
247
257
  A refusal leaves the tree unchanged.
248
258
  - Repeating a write is safe: a record that already exists with identical
249
259
  content is reported `unchanged` (`data.unchanged`), not duplicated.
@@ -258,13 +268,13 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
258
268
  has blockers; the approval step appears only when the brief is clean and
259
269
  unapproved.
260
270
  - Page long lists with `--limit <n>` and `--cursor <nextCursor>` (`--all`
261
- for everything); a cursor holds only for the call that issued it, so change nothing but `--limit`, `--all` and `--fields` (`CURSOR_INVALID` with `error.reason` `ARGUMENTS_CHANGED` otherwise). Project fields with `--fields a,b`
271
+ for everything); a cursor holds only for the call that issued it, so change nothing but `--limit`, `--all`, `--fields` and `--json`, and keep `CANON_ROLE` as it was; the next call is `meta.next[0].argv` as it stands (the arguments you gave and the cursor, never a default). An argument you add is a change even when it states the default (`--repo .`): canon binds an explicit default to the cursor (`CURSOR_INVALID` with `error.reason` `ARGUMENTS_CHANGED`, `error.field` `--cursor`; `FOREIGN` for a cursor of another command or another canon version: start again from the first page). `--limit`, `--cursor`, `--all` and `--fields` are flags: an `--input` document key of that name is `INPUT_INVALID` with `reason` `FLAG_ONLY_KEY`. Project fields with `--fields a,b`
262
272
  (`status`, `export`, `query`, `finding list`, `divergence list`, `context`): the paths `canon schema <command> --json` lists under `outputs[].fields`, spelled as the answer spells them; `meta.fields` lists what was kept.
263
273
  - `--override-reason <text>` is the only way to proceed past a waivable
264
274
  refusal; it is recorded, echoed in `data.overrides[]` and listed by `status`
265
275
  for the human. There is no `--force`. `brief approve`, `policy approve`,
266
276
  `divergence accept` and the `migrate --commit` that re-binds `Approved:`
267
- lines record a human's decision and refuse every agent role (`HUMAN_ONLY`)
277
+ lines record a human's decision and refuse every agent role (`ACTOR_DENIED`)
268
278
  unless they record the explicit answer the human gave you, with
269
279
  `--relayed-via <tool>` (show, ask, record, as for the brief; `canon skills
270
280
  show role-planner`); never unset your role to run one.
@@ -277,11 +287,12 @@ the positional arguments. An object is one invocation; a JSON array (or NDJSON
277
287
  from a file or stdin) is a batch, run in order and answered with
278
288
  `data.items[]` (`index`, `status` of `written`, `unchanged`, `failed` or
279
289
  `skipped`, and that element's `data` or `error`). A batch is validated whole
280
- before anything is written: an invalid element writes nothing and exits 2,
281
- `error.field` pointing at `/items/<i>/<key>`; a write that fails stops there
282
- (exit 1, `BATCH_INCOMPLETE`) and re-running the same batch reports the finished elements
283
- `unchanged`. A typo in a key is refused (`INPUT_INVALID`, `field` naming the key), never dropped.
284
- `canon schema <command> --json` shows the leaf's `input`: the schema of one document and a complete `example`.
290
+ before anything is written, and that check reads no state: an invalid element writes nothing and exits 2 with
291
+ its own code, `error.field` pointing at `/<i>/<key>` and no `data`. An element that fails when it runs (the object
292
+ it names does not exist) stops the batch: exit 1, `BATCH_INCOMPLETE`, `error.field` exactly `/<i>`, the element
293
+ `failed` with its own `error` (no `data`), the later ones `skipped`, and the earlier ones done (not undone). Re-running the same batch reports the finished elements
294
+ `unchanged`. A typo in a key is refused (`INPUT_INVALID`, `field` naming the key), never dropped; a document with several problems reports them all, the first as the error (`field` is the first `error.details` entry's) and every one in `error.details` in the order the document wrote its keys, and a value outside a closed set is `INPUT_INVALID` too (`reason` `INVALID_VALUE`, `field` the key), not `USAGE`. Every non-empty line of an NDJSON file is a document (a `#` line is not a comment). Integers compare by number: `1`, `"1"` and `--round +1` are one value, `"+1"`, `"0x1"` and `1.0` in a document are `INVALID_VALUE`, and an integer beyond ±9007199254740991 is refused as a number and as a string, in a document (`INVALID_VALUE`, `field` its pointer) and on the command line (`USAGE`). `--input` may give a required option and the command line only the operand; an option given in both with different values is `INPUT_CONFLICT` at the key's pointer. A repeatable option's none is the key left out: `[]` is refused (`INPUT_INVALID`, `reason` `INVALID_VALUE`, `field` the key's pointer), as is `[]` for any other option and for `operands`.
295
+ `canon schema <command> --json` shows the leaf's `input` (what one document is, and a complete `example`); `canon schema <command> --schemas --json` gives `Input`, the JSON Schema of one document.
285
296
 
286
297
  ```text
287
298
  canon scenario new --input '[{"operands":["auth.login.01"],"title":"Logs in","case":"happy"},{"operands":["auth.login.02"],"title":"Wrong password","case":"failure"}]'
@@ -329,12 +340,18 @@ and `canon context` warn when the repo holds 0.27-era state and put
329
340
  ## Setup and provider projection
330
341
 
331
342
  ```bash
332
- canon init # canon.yaml, starter policy (--policy light|standard|strict, default strict; see canon-policy), AGENTS.md block, commented plans examples
333
- canon init --providers=claude,codex # harnesses for the canon skill; without it init asks on a terminal, else takes the detected .claude/.codex/.omp/.pi
334
- canon skills install # follows canon.yaml skills.providers (else the install lock's, else the detected ones; none detected installs nothing); prunes projected files the bundle no longer ships when their bytes match the lock, keeps a modified one and reports `kept:`
335
- canon skills install --providers=claude,codex,omp,pi # any subset or none; rewrites skills.providers
336
- canon skills check # read-only drift check; exit 1 (SKILLS_DRIFT) names each orphan, a projected file the bundle no longer ships
337
- canon skills doctor # diagnostics, incl. a stray canon projection for an unselected provider and a projection a formatter rewrote, and `orphan:` lines for projected files the bundle no longer ships; never deletes user files
343
+ # canon.yaml, starter policy (--policy light|standard|strict, default strict; see canon-policy), AGENTS.md block, commented plans examples
344
+ canon init
345
+ # harnesses for the canon skill; without it init takes the detected .claude/.codex/.omp/.pi (it never asks)
346
+ canon init --providers=claude,codex
347
+ # follows canon.yaml skills.providers (else the install lock's, else the detected ones; none detected installs nothing); prunes projected files the bundle no longer ships when their bytes match the lock, keeps a modified one and reports `kept:`
348
+ canon skills install
349
+ # any subset or none; rewrites skills.providers
350
+ canon skills install --providers=claude,codex,omp,pi
351
+ # read-only drift check; exit 1 (SKILLS_CHECK_FAILED) names each orphan, a projected file the bundle no longer ships
352
+ canon skills check
353
+ # diagnostics, incl. a stray canon projection for an unselected provider and a projection a formatter rewrote, and `orphan:` lines for projected files the bundle no longer ships; never deletes user files
354
+ canon skills doctor
338
355
  ```
339
356
 
340
357
  `install` writes, per selected harness, a short `SKILL.md` stub (this file's
@@ -9,9 +9,12 @@ verdicts, and writes idempotently.
9
9
  ## `canon ingest records [--repo <dir>] [--watch]`
10
10
 
11
11
  ```bash
12
- canon ingest records # one pass over the repo's artifacts
13
- canon ingest records --repo ../svc # a specific repo
14
- canon ingest records --watch # poll loop
12
+ # one pass over the repo's artifacts
13
+ canon ingest records
14
+ # a specific repo
15
+ canon ingest records --repo ../svc
16
+ # poll loop
17
+ canon ingest records --watch
15
18
  ```
16
19
 
17
20
  Source roots resolve from `canon.yaml`'s `artifacts.sources` config
@@ -92,11 +92,14 @@ a scoped gate.
92
92
  ## The commands — and the one thing you never type
93
93
 
94
94
  ```bash
95
- canon feature new checkout.cart --title "Cart" # once per surface
95
+ # once per surface
96
+ canon feature new checkout.cart --title "Cart"
97
+ # once per behavior
96
98
  canon scenario new checkout.cart.01 --title "Adding an item raises the count" \
97
- --subject checkout-core --lane behavior --case happy # once per behavior
99
+ --subject checkout-core --lane behavior --case happy
100
+ # and its failure path
98
101
  canon scenario new checkout.cart.04 --title "Adding an out-of-stock item is refused" \
99
- --subject checkout-core --lane behavior --case failure # and its failure path
102
+ --subject checkout-core --lane behavior --case failure
100
103
  ```
101
104
 
102
105
  There is no format or sync step after these: the scaffold writes a
@@ -111,8 +114,9 @@ Fix it and the next command indexes the files (see `canon-inventory`).
111
114
  Many scenarios at once: `--input` takes inline JSON, a file or `-`. An
112
115
  array (or NDJSON) is a batch, validated whole before anything is written;
113
116
  each element holds `operands` (the scenario tag) and the other options as
114
- camelCase keys. `canon schema scenario new --json` shows `input`: the schema of one document
115
- and a complete `example`. There is no `--from`.
117
+ camelCase keys. `canon schema scenario new --json` shows `input` (its limits and a complete
118
+ `example`); `canon schema scenario new --schemas --json` gives `Input`, the schema of one
119
+ document. There is no `--from`.
116
120
 
117
121
  ```text
118
122
  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"}]'
@@ -13,9 +13,12 @@ deterministic authoring surface.
13
13
  ## `canon context [--repo <dir>] [--json]`
14
14
 
15
15
  ```bash
16
- canon context # compact human outline (prompt-injectable)
17
- canon context --json # the full machine-readable surface
18
- canon context --repo ../other # resolve a specific repo's surface
16
+ # compact human outline (prompt-injectable)
17
+ canon context
18
+ # the full machine-readable surface
19
+ canon context --json
20
+ # resolve a specific repo's surface
21
+ canon context --repo ../other
19
22
  ```
20
23
 
21
24
  The outline opens with a short header, then a blank line, then the
@@ -9,7 +9,8 @@ rewrites or mutates the corpus — it only validates and reports.
9
9
  ## Running
10
10
 
11
11
  ```bash
12
- canon format spec # e.g. a consumer repo's spec/
12
+ # e.g. a consumer repo's spec/
13
+ canon format spec
13
14
  ```
14
15
 
15
16
  With no operand, `canon format` validates every `specs.roots[]` entry of
@@ -28,7 +28,7 @@ Every violation carries one of these stable, grep-able strings:
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
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). |
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`, `EVIDENCE_NOTE_INVALID`, exit 2). |
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
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
 
@@ -42,8 +42,10 @@ corpus and runs them, printing every violation grouped by failure class.
42
42
  when `--release` is passed.
43
43
 
44
44
  ```bash
45
- canon gate check --repo . # ordinary evaluation
46
- canon gate check --repo . --release # + trust-below-required
45
+ # ordinary evaluation
46
+ canon gate check --repo .
47
+ # + trust-below-required
48
+ canon gate check --repo . --release
47
49
  ```
48
50
 
49
51
  Exit `0` clean, `1` gate-red (any violation), `2` usage/load failure
@@ -223,9 +225,9 @@ canon divergence accept cart.add.01 --project root --reason "known gap" --tracki
223
225
 
224
226
  Accepting a scenario whose latest evidence is `divergent` as a known gap
225
227
  limited by something outside the change is a human-only act: with a role
226
- declared (`--as`, `CANON_ROLE`) the leaf is refused with `HUMAN_ONLY`. It is
228
+ declared (`--as`, `CANON_ROLE`) the leaf is refused with `ACTOR_DENIED`. It is
227
229
  never a way to skip a fix.
228
- Refused (`DIVERGENCE_ACCEPT_REFUSED`) unless the latest verdict is
230
+ Refused (`DIVERGENCE_CONFLICT` when the evidence is not divergent, `DIVERGENCE_DENIED` when the actor or session attested it) unless the latest verdict is
229
231
  divergent and the session and actor differ from the evidence's. The record
230
232
  pins that evidence: new evidence for the scenario, or `--expiry` passing,
231
233
  ends it. While it holds, the ship guard counts the cell covered and
@@ -302,10 +304,10 @@ never rides along into a confirming audit. `--drop-attachment` and
302
304
  The approval is never assumed: the agent writes the brief, shows it to the
303
305
  human and asks, and builds nothing for that scope until the human answers.
304
306
  `canon evidence add` is the backstop for that rule (0.16 M7). It
305
- refuses (exit `1`, nothing staged or stored) while a subject the record
307
+ refuses (exit `2`, nothing staged or stored) while a subject the record
306
308
  attests for has an enforced, unapproved brief: a change the record
307
309
  answers to (below) has a canon `.canon/changes/<change>/brief.md` with no `Approved:`
308
- line, was edited after its approval (`BRIEF_CHANGED_SINCE_APPROVAL`), or
310
+ line, was edited after its approval (`BRIEF_APPROVAL_STALE`), or
309
311
  there is no canon `brief.md` yet but the change comes from an
310
312
  external openspec plan with a `proposal.md` under the plan sources (the
311
313
  check `canon status` and the ship guard use; see
@@ -314,8 +316,8 @@ check `canon status` and the ship guard use; see
314
316
  `--task`:
315
317
 
316
318
  ```stderr
317
- 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>"`
318
- canon evidence add: refused — stop and get the human's answer to the brief: nothing is built or attested for a subject before its brief is approved. Show it (`canon brief show --body`), ask with the harness question tool, and on their explicit approval record it with `canon brief approve --approver <their name> --note "<their words>" --relayed-via <the question tool> --actor <your actor id> --digest <change>=<the digest shown>` (or they approve on `canon dashboard`); never unset your role to run it; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
319
+ stderr: 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>"`
320
+ stderr: canon evidence add: refused — stop and get the human's answer to the brief: nothing is built or attested for a subject before its brief is approved. Show it (`canon brief show --body`), ask with the harness question tool, and on their explicit approval record it with `canon brief approve --approver <their name> --note "<their words>" --relayed-via <the question tool> --actor <your actor id> --digest <change>=<the digest shown>` (or they approve on `canon dashboard`); never unset your role to run it; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
319
321
  ```
320
322
 
321
323
  For a change from an external plan with no canon brief yet, the first
@@ -459,7 +461,7 @@ mentions. Each bound case is its own attachment with its name and
459
461
  outcome. `--report-case <name>` (repeatable; a Rust test by its
460
462
  function name) ADDS cases; it never hides the scenario's own. No match,
461
463
  or a `--report-case` naming no case, refuses (exit 2); a `faithful`
462
- verdict when ANY bound case failed or was skipped refuses (exit 1). Files
464
+ verdict when ANY bound case failed or was skipped refuses (exit 2). Files
463
465
  must be inside the repository, are recorded by relative path, and are
464
466
  stored (see Bound evidence stays provable).
465
467
 
@@ -515,8 +517,9 @@ report (a JUnit test case's `[[ATTACHMENT|path]]` lines, which Playwright's
515
517
  JUnit reporter writes; a Cucumber JSON embedding), so a test's screenshot
516
518
  stays with its scenario. A file the report does not name goes with
517
519
  `--artifact <scenario-id>=<path>`; a bare `--artifact <path>` in a batch is
518
- refused (`EVIDENCE_INVALID_ARGUMENT`). A report attachment that is missing,
519
- outside the repo or oversized is refused.
520
+ refused (`EVIDENCE_ARGUMENT_CONFLICT`). A report attachment that is missing,
521
+ outside the repo or oversized is refused (`EVIDENCE_BINDING_NOT_FOUND`,
522
+ `EVIDENCE_BINDING_DENIED`, `EVIDENCE_BINDING_INVALID`).
520
523
 
521
524
  It is all or nothing: a claimed `faithful` verdict over a failed case,
522
525
  a fabrication marker in `--summary`, an unapproved brief for any
@@ -534,13 +537,14 @@ or `-`; an array (or NDJSON) is a batch, validated element by element before
534
537
  the first write (a refusal writes nothing, exit 2). Keys are the option
535
538
  names in camelCase plus `operands`: one object per scenario, with
536
539
  `scenario`, `class`, `ref` and `role`. `canon schema evidence add --json`
537
- shows `input`: the schema of one document and a complete `example`. Each element reports `written`,
540
+ shows `input` (its limits and a complete `example`) and `canon schema evidence add --schemas --json`
541
+ gives `Input`, the schema of one document. Each element reports `written`,
538
542
  `unchanged` or `failed` in `data.items[]`.
539
543
 
540
544
  `--rev <rev>` names the commit the evidence ran against (default `HEAD`).
541
545
  Evidence for uncommitted code is recorded with its `codeTree` and
542
546
  `worktreeDirty`; outside git, or with no commit, the add is refused with
543
- `NO_COMMIT`.
547
+ `COMMIT_REQUIRED`.
544
548
 
545
549
  **Done when:** `canon gate check` shows no violation for the scenarios you
546
550
  recorded evidence for; each record's own output line says whether it was
@@ -553,7 +557,7 @@ current pinned review saw, `canon evidence add` prints one line per
553
557
  review it makes stale (its verdict or checks differ from what the review saw), with the command that re-pins it:
554
558
 
555
559
  ```stderr
556
- 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 root --actor reviewer-2 --role reviewer --original-spec-ref specs/kind=feature/area=cart/add.feature
560
+ stderr: 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 root --actor reviewer-2 --role reviewer --original-spec-ref specs/kind=feature/area=cart/add.feature
557
561
  ```
558
562
 
559
563
  The decision is the gate's own (the same stale-review rule `canon gate
@@ -695,7 +699,7 @@ aggregates every record bound to the task, on one line:
695
699
  (the latest `--summary`, or a default naming the latest passing record).
696
700
  Every other path — missing evidence, a `Divergent` verdict, a fabricated
697
701
  note on any of the task's records — leaves the row byte-unchanged and
698
- exits `1` with the blocking violation on stderr. After a flip, the plan
702
+ exits `2` with the blocking violation on stderr. After a flip, the plan
699
703
  source is re-ingested so the record store's task status agrees with the
700
704
  checkbox (`canon query --kind task` reads `done`); a failed re-ingest is
701
705
  a stderr warning naming `canon ingest plans`, never a failed flip.
@@ -732,13 +736,15 @@ Staging → committed: every well-formed record under
732
736
  applies, assigned a monotonic per-(role, surface) `run_seq` (gap-free
733
737
  within one invocation, continuing from the committed max), and moved into
734
738
  the committed ledger. A malformed or unpartitionable candidate is refused
735
- — exit `1`, no `run_seq` consumed, the file left in place. `--dry-run`
739
+ — exit `2` (`PROMOTION_INVALID`; several are `error.details[]`), no `run_seq` consumed, the file left in place. A refusal carries no `data`. `--dry-run`
736
740
  prints the plan (target path + assigned `run_seq` per candidate) without
737
741
  writing or deleting.
738
742
 
739
743
  ```bash
740
- canon gate promote --repo . # land every staged candidate
741
- canon gate promote --repo . --dry-run # preview only
744
+ # land every staged candidate
745
+ canon gate promote --repo .
746
+ # preview only
747
+ canon gate promote --repo . --dry-run
742
748
  ```
743
749
 
744
750
  Which writes need this step: `evidence add`, `finding add` and `finding
@@ -785,8 +791,10 @@ It installs no git hook: copy the script into git's `pre-commit` hook
785
791
  agent hook files and the script, also under `--dry-run`. In `--json`,
786
792
  `installed` is true when an agent hook file changed and
787
793
  `preCommitScriptWritten` when the script was written. A `--repo` that is not an
788
- existing directory exits 2 with `HOOKS_INSTALL_FAILED` (also under `--dry-run`)
789
- and creates nothing.
794
+ existing directory exits 2 with `HOOKS_REPO_INVALID` (also under `--dry-run`)
795
+ and creates nothing. When the install writes the first hook file and then cannot
796
+ write the second, it exits 1 with `HOOKS_INSTALL_INCOMPLETE`: the first file
797
+ stays, `meta.next` leads with `canon status`, then run the install again.
790
798
 
791
799
  Prefer this over hand-editing `settings.json`/`hooks.json`.
792
800
 
@@ -14,7 +14,7 @@ same code this command runs, scoped to the changed files, and say so in one
14
14
  stderr line:
15
15
 
16
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
+ stderr: 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
18
18
  ```
19
19
 
20
20
  `canon status` and `canon gate check` are read commands and write nothing:
@@ -76,14 +76,14 @@ author .feature corpus (canon scenario new)
76
76
  scenario index # refreshed by the writers; `canon inventory sync` rebuilds it
77
77
  │
78
78
  ▼
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
81
- canon gate check [--release] # trust-ladder / staleness / coverage — see canon-gate
79
+ review: canon review scenario # attests a review — see canon-inventory downstream / canon-gate
80
+ diverge: canon divergence add|resolve|defer|accept|list # tracks/resolves a divergence
81
+ gate: canon gate check [--release] # trust-ladder / staleness / coverage — see canon-gate
82
82
  │
83
83
  ▼
84
- canon ingest records # with artifacts.native_records: true in canon.yaml —
85
- # feeds review/divergence verdicts into the flywheel
86
- # (see canon-artifact-ingest)
84
+ ingest: canon ingest records # with artifacts.native_records: true in canon.yaml —
85
+ # feeds review/divergence verdicts into the flywheel
86
+ # (see canon-artifact-ingest)
87
87
  ```
88
88
 
89
89
  Every stage after the index joins on the SAME `(project_id, scenario_id)`
@@ -92,9 +92,12 @@ pair it materializes — one identity scheme, no second one.
92
92
  ## `canon inventory sync [--repo <dir>] [--spec-root <dir>]`
93
93
 
94
94
  ```bash
95
- canon inventory sync # every canon.yaml specs.roots[] entry
96
- canon inventory sync --repo ../svc # a specific repo
97
- canon inventory sync --spec-root ./specs # ad hoc: ignore canon.yaml entirely
95
+ # every canon.yaml specs.roots[] entry
96
+ canon inventory sync
97
+ # a specific repo
98
+ canon inventory sync --repo ../svc
99
+ # ad hoc: ignore canon.yaml entirely
100
+ canon inventory sync --spec-root ./specs
98
101
  ```
99
102
 
100
103
  Per configured root, in order:
@@ -161,7 +164,9 @@ specs:
161
164
  whole root aborts, 0 writes, violations reported.
162
165
  - **A root on the pre-0.17 layout** (a `.feature` file under
163
166
  `<root>/features/`) → a `layout-grammar` violation at path `features`;
164
- the root aborts, 0 writes, exit 1. Run `canon migrate`. An empty
167
+ the root aborts, 0 writes, exit 2 (`INVENTORY_INVALID`, each violation in
168
+ `error.details`; exit 1 `INVENTORY_INCOMPLETE` when an earlier root was
169
+ indexed first). Run `canon migrate`. An empty
165
170
  leftover `features/` directory is not a refusal.
166
171
  - **A duplicate `scenario_id`** within one root → that root aborts, 0
167
172
  writes, reported as a sync error (a distinct lane from fmt violations).
@@ -64,9 +64,12 @@ canon ingest plans --dialect openspec --plan-source ../other-repo
64
64
  ## 2. Run the import
65
65
 
66
66
  ```bash
67
- canon ingest plans # .canon/changes/ + every configured source
68
- canon ingest plans --json # machine-readable outcome
69
- canon ingest plans --repo ../svc # a specific repo root
67
+ # .canon/changes/ + every configured source
68
+ canon ingest plans
69
+ # machine-readable outcome
70
+ canon ingest plans --json
71
+ # a specific repo root
72
+ canon ingest plans --repo ../svc
70
73
  ```
71
74
 
72
75
  Per source the summary reports `changes_parsed`/`tasks_parsed`,
@@ -49,9 +49,12 @@ overlays:
49
49
  Drive it through the sync command (never hand-write records):
50
50
 
51
51
  ```bash
52
- canon plugin sync porting # every canon.yaml specs.roots[] entry
53
- canon plugin sync porting --repo ../svc # a specific repo
54
- canon plugin sync porting --spec-root ./specs # ad hoc: ignore canon.yaml
52
+ # every canon.yaml specs.roots[] entry
53
+ canon plugin sync porting
54
+ # a specific repo
55
+ canon plugin sync porting --repo ../svc
56
+ # ad hoc: ignore canon.yaml
57
+ canon plugin sync porting --spec-root ./specs
55
58
  ```
56
59
 
57
60
  `canon plugin sync <plugin-id>` resolves the manifest, then for each
@@ -70,9 +73,12 @@ error; the next step (3) reads the overlay back.
70
73
  ## 3. Project a read
71
74
 
72
75
  ```bash
73
- canon query --kind scenario --plugin porting # human table, projected fields appended
74
- canon query --kind scenario --plugin porting --json # merged record bodies
75
- canon query --kind scenario # no --plugin: byte-identical to the core view
76
+ # human table, projected fields appended
77
+ canon query --kind scenario --plugin porting
78
+ # merged record bodies
79
+ canon query --kind scenario --plugin porting --json
80
+ # no --plugin: byte-identical to the core view
81
+ canon query --kind scenario
76
82
  ```
77
83
 
78
84
  `--plugin <id>` folds the plugin's overlay records (latest-by-
@@ -76,7 +76,7 @@ A human approves the policy after reviewing `.canon/policy.yaml`, in the
76
76
  same answer that approves a subject's brief (0.16; see the skill's working
77
77
  loop). `canon brief approve` records both in one call. `canon policy
78
78
  approve` is a human's decision: with a role declared (`--as` or `CANON_ROLE`)
79
- it is refused with `HUMAN_ONLY` (exit 2, not retryable) unless it records the
79
+ it is refused with `ACTOR_DENIED` (exit 2, not retryable) unless it records the
80
80
  answer the human gave in the conversation: show them `.canon/policy.yaml`, ask,
81
81
  and on an explicit approval run it (the steps are in `canon skills show role-planner`) with `--relayed-via <tool>`, `--actor`,
82
82
  `--approver` and `--note` (their name and words); the file then carries `relay`
@@ -117,8 +117,8 @@ unreviewed-promotion policy — policy changed since approval: .canon/policy.yam
117
117
  ```
118
118
 
119
119
  `canon gate check` exits `1`; `canon subject move` (the ship guard and
120
- the reopen) refuses with `POLICY_CHANGED_SINCE_APPROVAL`, or
121
- `POLICY_APPROVAL_UNREADABLE` for an unreadable approval, and
120
+ the reopen) refuses with `POLICY_APPROVAL_STALE`, or
121
+ `POLICY_APPROVAL_CORRUPT` (or `POLICY_APPROVAL_DENIED` when the file may not be read) for a broken approval, and
122
122
  `--override-reason` does not waive either. A policy never approved stays
123
123
  an advisory. `canon status` prints the same text as a `warning:` line (and
124
124
  in `--json` `warnings`). The record names who approved which bytes and
@@ -40,7 +40,8 @@ Renders the current ten-panel report to `<repo>/.canon/REPORT.md`.
40
40
  subcommand uses — omit it (or pass `.`) to run from any subdirectory.
41
41
 
42
42
  ```bash
43
- canon report build # writes .canon/REPORT.md
43
+ # writes .canon/REPORT.md
44
+ canon report build
44
45
  canon report build --repo /path/to/repo
45
46
  ```
46
47
 
@@ -67,7 +68,8 @@ committed `.canon/REPORT.md`:
67
68
  `canon report build`).
68
69
 
69
70
  ```bash
70
- canon report check # wire into CI exactly like canon format / canon gate check
71
+ # wire into CI exactly like canon format / canon gate check
72
+ canon report check
71
73
  ```
72
74
 
73
75
  Wire it as a CI step or pre-push hook the same way `canon gate
@@ -126,7 +128,8 @@ canon report snapshot /tmp/canon-snap
126
128
  Serves the dashboard web app locally, pointed at a real snapshot:
127
129
 
128
130
  ```bash
129
- canon dashboard # regenerates a fresh snapshot every run, serves it
131
+ # regenerates a fresh snapshot every run, serves it
132
+ canon dashboard
130
133
  canon dashboard --snapshot /tmp/canon-snap --port 8080
131
134
  ```
132
135
 
@@ -140,7 +143,7 @@ canon dashboard --snapshot /tmp/canon-snap --port 8080
140
143
  - Runs in any repo: the released binary carries the app (in canon's own
141
144
  checkout a built `packages/dashboard/dist` is used instead). It prints the
142
145
  panels URL and a briefs URL (`/briefs.html`), then serves until Ctrl-C.
143
- A taken port fails with `DASHBOARD_PORT_IN_USE`: pass `--port <n>` or
146
+ A taken port fails with `DASHBOARD_PORT_UNAVAILABLE`: pass `--port <n>` or
144
147
  `--port 0`.
145
148
  - Without the `duckdb` CLI on `PATH` the server still runs; the panels page
146
149
  says why there is no snapshot and how to get one (it never shows demo
@@ -157,11 +160,11 @@ answer once and clicks Approve: one request carries every selected brief with
157
160
  the sha256 of the file the page read, and records exactly what `canon brief
158
161
  approve <id>+ --approver <name> --note <text>` records, the `Approved:` line
159
162
  bound to the brief digest and the policy approval, for each. A brief that
160
- changed after the page loaded (`BRIEF_CHANGED_SINCE_PAGE_LOAD`) or that has
161
- blockers refuses the whole request (409 `BRIEF_APPROVE_REFUSED`, naming each
162
- refused brief): nothing is written and the page says to read it again. A request
163
+ changed after the page loaded (`BRIEF_PAGE_STALE`) or that has
164
+ blockers refuses the whole request (409, the first refused brief's own code such as `BRIEF_INVALID`, with an
165
+ `error.details` entry for each refused brief): nothing is written and the page says to read it again. A request
163
166
  naming one brief the old way (`changeId`, `sha256`) is still accepted. The server is localhost only and
164
- refuses requests from other origins (`DASHBOARD_ORIGIN_REFUSED`).
167
+ refuses requests from other origins (`DASHBOARD_REQUEST_DENIED`).
165
168
 
166
169
  For an agent: when clean briefs are waiting, show them (`canon brief show
167
170
  <slug> --body`), ask with the harness question tool, and tell the human they
@@ -89,7 +89,7 @@ in the JSON. Give the reason when you reject or defer: it is the only record
89
89
  of why the finding was not fixed.
90
90
 
91
91
  `--scenario` (repeatable, each a scenario the index knows; refused with
92
- `FINDING_UNKNOWN_SCENARIO` otherwise) names the scenarios the finding is
92
+ `SCENARIO_NOT_FOUND` otherwise) names the scenarios the finding is
93
93
  about. After a `fixed` close, fresh evidence for those scenarios alone
94
94
  re-verifies the fix; a finding naming none asks every evidenced scenario of
95
95
  the subject, as before. `finding close` copies the list.
@@ -116,14 +116,15 @@ needs it or `--introduced-unknown` (never both). A revision that names no
116
116
  commit is refused (exit `2`). A finding recorded against uncommitted code
117
117
  is allowed: the record carries the `codeTree` it saw and `worktreeDirty`.
118
118
  Outside git, or in a repository with no commit, the write is refused with
119
- `NO_COMMIT`.
119
+ `COMMIT_REQUIRED`.
120
120
 
121
121
  Many findings at once: `--input` takes inline JSON, a file or `-`; an array
122
122
  (or NDJSON) is a batch validated before any write. Keys are the option
123
123
  names in camelCase (`change`, `actor`, `resolutionRev`); `canon schema
124
- finding add --json` shows `input`: the schema of one document and a complete `example`. An identical
124
+ finding add --json` shows `input` (its limits and a complete `example`) and `canon schema finding add
125
+ --schemas --json` gives `Input`, the schema of one document. An identical
125
126
  repeat is `unchanged` (`data.unchanged`) and writes nothing; a different
126
- finding under an occupied key is `FINDING_SEQ_OCCUPIED`.
127
+ finding under an occupied key is `FINDING_EXISTS`.
127
128
 
128
129
  ### A defect the author found in its own work
129
130
 
@@ -197,7 +198,7 @@ saw (the tree with `.canon/`, the spec roots and `code.exclude` removed), and
197
198
  allowed, and the commit made from it has the same code tree, so committing it
198
199
  afterwards leaves the review as it was: a review is judged by its pins (the
199
200
  scenario and what its evidence says), not by the commit. Outside git, or
200
- with no commit, the write is refused with `NO_COMMIT`. An identical review
201
+ with no commit, the write is refused with `COMMIT_REQUIRED`. An identical review
201
202
  written again is `unchanged` (`data.unchanged` under `--json`) and adds no
202
203
  record.
203
204
 
@@ -468,14 +469,14 @@ With `require_review` present, `canon subject move <id> --to <state>`
468
469
  prints on stderr which review checks it ran or skipped:
469
470
 
470
471
  ```stderr
471
- canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
472
+ stderr: canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
472
473
  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
473
474
  ran open-blocker — 1 adopted change(s) checked for open blocker findings
474
475
  ```
475
476
 
476
477
  A target status outside the scope prints `skipped unreviewed-promotion —
477
478
  `specced` is not in require_review.scope`. A transition into an in-scope
478
- status with gaps prints the violations, exits 1, leaves the record
479
+ status with gaps prints the violations, exits 2, leaves the record
479
480
  unchanged, and names `--override-reason`.
480
481
 
481
482
  `--override-reason "<one line>"` waives ONLY `unreviewed-promotion` and