@journeykit/canon 0.35.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 (120) hide show
  1. package/dist/skills/SKILL.src.md +29 -19
  2. package/dist/skills/reference/canon-authoring.md +3 -2
  3. package/dist/skills/reference/canon-gate.md +18 -14
  4. package/dist/skills/reference/canon-inventory.md +3 -1
  5. package/dist/skills/reference/canon-policy.md +3 -3
  6. package/dist/skills/reference/canon-report-dashboard.md +5 -5
  7. package/dist/skills/reference/canon-review.md +7 -6
  8. package/dist/skills/reference/canon-storage.md +2 -2
  9. package/dist/skills/reference/canon-subject.md +20 -19
  10. package/dist/skills/reference/role-implementer.md +5 -5
  11. package/dist/skills/reference/role-orchestrator.md +22 -21
  12. package/dist/skills/reference/role-planner.md +7 -7
  13. package/dist/skills/reference/role-reviewer.md +7 -7
  14. package/man/canon-adapter-authorize.1 +2 -2
  15. package/man/canon-adapter-validate.1 +2 -2
  16. package/man/canon-adapter.1 +2 -2
  17. package/man/canon-artifacts-move.1 +6 -6
  18. package/man/canon-artifacts-store.1 +2 -2
  19. package/man/canon-artifacts-verify.1 +2 -2
  20. package/man/canon-artifacts.1 +2 -2
  21. package/man/canon-brief-approve.1 +5 -4
  22. package/man/canon-brief-check.1 +2 -2
  23. package/man/canon-brief-show.1 +2 -2
  24. package/man/canon-brief.1 +2 -2
  25. package/man/canon-change-new.1 +2 -2
  26. package/man/canon-change.1 +2 -2
  27. package/man/canon-completion.1 +2 -2
  28. package/man/canon-context-pack-add.1 +2 -2
  29. package/man/canon-context-pack-show.1 +2 -2
  30. package/man/canon-context-pack-verify.1 +2 -2
  31. package/man/canon-context-pack.1 +2 -2
  32. package/man/canon-context.1 +2 -2
  33. package/man/canon-dashboard.1 +2 -2
  34. package/man/canon-demo-init.1 +2 -2
  35. package/man/canon-demo-review.1 +2 -2
  36. package/man/canon-demo.1 +2 -2
  37. package/man/canon-dispatch-begin.1 +2 -2
  38. package/man/canon-dispatch-diff.1 +2 -2
  39. package/man/canon-dispatch-end.1 +2 -2
  40. package/man/canon-dispatch.1 +2 -2
  41. package/man/canon-divergence-accept.1 +2 -2
  42. package/man/canon-divergence-add.1 +3 -3
  43. package/man/canon-divergence-defer.1 +3 -3
  44. package/man/canon-divergence-list.1 +2 -2
  45. package/man/canon-divergence-resolve.1 +3 -3
  46. package/man/canon-divergence.1 +2 -2
  47. package/man/canon-evidence-add.1 +5 -5
  48. package/man/canon-evidence-approval-payload.1 +3 -3
  49. package/man/canon-evidence-audit.1 +4 -4
  50. package/man/canon-evidence.1 +2 -2
  51. package/man/canon-export.1 +2 -2
  52. package/man/canon-feature-new.1 +2 -2
  53. package/man/canon-feature.1 +2 -2
  54. package/man/canon-finding-add.1 +3 -3
  55. package/man/canon-finding-close.1 +2 -2
  56. package/man/canon-finding-list.1 +2 -2
  57. package/man/canon-finding.1 +2 -2
  58. package/man/canon-format.1 +2 -2
  59. package/man/canon-gate-check.1 +2 -2
  60. package/man/canon-gate-install-hooks.1 +2 -2
  61. package/man/canon-gate-promote.1 +2 -2
  62. package/man/canon-gate.1 +2 -2
  63. package/man/canon-ingest-plans.1 +2 -2
  64. package/man/canon-ingest-records.1 +2 -2
  65. package/man/canon-ingest-sessions.1 +2 -2
  66. package/man/canon-ingest.1 +2 -2
  67. package/man/canon-init.1 +2 -2
  68. package/man/canon-inventory-sync.1 +2 -2
  69. package/man/canon-inventory.1 +2 -2
  70. package/man/canon-ledger-compact.1 +5 -5
  71. package/man/canon-ledger.1 +3 -3
  72. package/man/canon-migrate.1 +8 -8
  73. package/man/canon-plugin-sync.1 +2 -2
  74. package/man/canon-plugin.1 +2 -2
  75. package/man/canon-policy-approve.1 +2 -2
  76. package/man/canon-policy-show.1 +2 -2
  77. package/man/canon-policy.1 +2 -2
  78. package/man/canon-prompt-add.1 +2 -2
  79. package/man/canon-prompt-show.1 +2 -2
  80. package/man/canon-prompt.1 +2 -2
  81. package/man/canon-purge.1 +7 -7
  82. package/man/canon-query.1 +2 -2
  83. package/man/canon-regime-show.1 +2 -2
  84. package/man/canon-regime.1 +2 -2
  85. package/man/canon-report-build.1 +2 -2
  86. package/man/canon-report-check.1 +2 -2
  87. package/man/canon-report-snapshot.1 +2 -2
  88. package/man/canon-report.1 +2 -2
  89. package/man/canon-retrieve.1 +2 -2
  90. package/man/canon-review-change.1 +3 -3
  91. package/man/canon-review-scenario.1 +3 -3
  92. package/man/canon-review.1 +2 -2
  93. package/man/canon-scenario-new.1 +2 -2
  94. package/man/canon-scenario.1 +2 -2
  95. package/man/canon-schema.1 +10 -4
  96. package/man/canon-search.1 +2 -2
  97. package/man/canon-selftest.1 +2 -2
  98. package/man/canon-skills-check.1 +2 -2
  99. package/man/canon-skills-doctor.1 +2 -2
  100. package/man/canon-skills-install.1 +2 -2
  101. package/man/canon-skills-show.1 +2 -2
  102. package/man/canon-skills.1 +2 -2
  103. package/man/canon-status.1 +2 -2
  104. package/man/canon-strategy-approval-payload.1 +2 -2
  105. package/man/canon-strategy-promote.1 +2 -2
  106. package/man/canon-strategy-rollback.1 +2 -2
  107. package/man/canon-strategy.1 +2 -2
  108. package/man/canon-subject-adopt.1 +2 -2
  109. package/man/canon-subject-move.1 +2 -2
  110. package/man/canon-subject-new.1 +2 -2
  111. package/man/canon-subject-show.1 +2 -2
  112. package/man/canon-subject-unadopt.1 +3 -3
  113. package/man/canon-subject.1 +2 -2
  114. package/man/canon-task-done.1 +2 -2
  115. package/man/canon-task.1 +2 -2
  116. package/man/canon-tier-age.1 +5 -5
  117. package/man/canon-tier.1 +2 -2
  118. package/man/canon-trace.1 +2 -2
  119. package/man/canon.1 +3 -3
  120. 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,17 +211,27 @@ 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.2`), `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: ""`).
@@ -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`, `--fields` and `--json`, and keep `CANON_ROLE` as it was (`CURSOR_INVALID` with `error.reason` `ARGUMENTS_CHANGED` otherwise; `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`
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.
@@ -281,8 +291,8 @@ before anything is written, and that check reads no state: an invalid element wr
281
291
  its own code, `error.field` pointing at `/<i>/<key>` and no `data`. An element that fails when it runs (the object
282
292
  it names does not exist) stops the batch: exit 1, `BATCH_INCOMPLETE`, `error.field` exactly `/<i>`, the element
283
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
284
- `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 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, and `"+1"`, `"0x1"` and `1.0` in a document are `INVALID_VALUE`.
285
- `canon schema <command> --json` shows the leaf's `input`: the schema of one document and a complete `example`.
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.
286
296
 
287
297
  ```text
288
298
  canon scenario new --input '[{"operands":["auth.login.01"],"title":"Logs in","case":"happy"},{"operands":["auth.login.02"],"title":"Wrong password","case":"failure"}]'
@@ -338,7 +348,7 @@ canon init --providers=claude,codex
338
348
  canon skills install
339
349
  # any subset or none; rewrites skills.providers
340
350
  canon skills install --providers=claude,codex,omp,pi
341
- # read-only drift check; exit 1 (SKILLS_DRIFT) names each orphan, a projected file the bundle no longer ships
351
+ # read-only drift check; exit 1 (SKILLS_CHECK_FAILED) names each orphan, a projected file the bundle no longer ships
342
352
  canon skills check
343
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
344
354
  canon skills doctor
@@ -114,8 +114,9 @@ Fix it and the next command indexes the files (see `canon-inventory`).
114
114
  Many scenarios at once: `--input` takes inline JSON, a file or `-`. An
115
115
  array (or NDJSON) is a batch, validated whole before anything is written;
116
116
  each element holds `operands` (the scenario tag) and the other options as
117
- camelCase keys. `canon schema scenario new --json` shows `input`: the schema of one document
118
- 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`.
119
120
 
120
121
  ```text
121
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"}]'
@@ -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
 
@@ -225,9 +225,9 @@ canon divergence accept cart.add.01 --project root --reason "known gap" --tracki
225
225
 
226
226
  Accepting a scenario whose latest evidence is `divergent` as a known gap
227
227
  limited by something outside the change is a human-only act: with a role
228
- 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
229
229
  never a way to skip a fix.
230
- 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
231
231
  divergent and the session and actor differ from the evidence's. The record
232
232
  pins that evidence: new evidence for the scenario, or `--expiry` passing,
233
233
  ends it. While it holds, the ship guard counts the cell covered and
@@ -304,10 +304,10 @@ never rides along into a confirming audit. `--drop-attachment` and
304
304
  The approval is never assumed: the agent writes the brief, shows it to the
305
305
  human and asks, and builds nothing for that scope until the human answers.
306
306
  `canon evidence add` is the backstop for that rule (0.16 M7). It
307
- 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
308
308
  attests for has an enforced, unapproved brief: a change the record
309
309
  answers to (below) has a canon `.canon/changes/<change>/brief.md` with no `Approved:`
310
- line, was edited after its approval (`BRIEF_CHANGED_SINCE_APPROVAL`), or
310
+ line, was edited after its approval (`BRIEF_APPROVAL_STALE`), or
311
311
  there is no canon `brief.md` yet but the change comes from an
312
312
  external openspec plan with a `proposal.md` under the plan sources (the
313
313
  check `canon status` and the ship guard use; see
@@ -461,7 +461,7 @@ mentions. Each bound case is its own attachment with its name and
461
461
  outcome. `--report-case <name>` (repeatable; a Rust test by its
462
462
  function name) ADDS cases; it never hides the scenario's own. No match,
463
463
  or a `--report-case` naming no case, refuses (exit 2); a `faithful`
464
- 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
465
465
  must be inside the repository, are recorded by relative path, and are
466
466
  stored (see Bound evidence stays provable).
467
467
 
@@ -517,8 +517,9 @@ report (a JUnit test case's `[[ATTACHMENT|path]]` lines, which Playwright's
517
517
  JUnit reporter writes; a Cucumber JSON embedding), so a test's screenshot
518
518
  stays with its scenario. A file the report does not name goes with
519
519
  `--artifact <scenario-id>=<path>`; a bare `--artifact <path>` in a batch is
520
- refused (`EVIDENCE_INVALID_ARGUMENT`). A report attachment that is missing,
521
- 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`).
522
523
 
523
524
  It is all or nothing: a claimed `faithful` verdict over a failed case,
524
525
  a fabrication marker in `--summary`, an unapproved brief for any
@@ -536,13 +537,14 @@ or `-`; an array (or NDJSON) is a batch, validated element by element before
536
537
  the first write (a refusal writes nothing, exit 2). Keys are the option
537
538
  names in camelCase plus `operands`: one object per scenario, with
538
539
  `scenario`, `class`, `ref` and `role`. `canon schema evidence add --json`
539
- 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`,
540
542
  `unchanged` or `failed` in `data.items[]`.
541
543
 
542
544
  `--rev <rev>` names the commit the evidence ran against (default `HEAD`).
543
545
  Evidence for uncommitted code is recorded with its `codeTree` and
544
546
  `worktreeDirty`; outside git, or with no commit, the add is refused with
545
- `NO_COMMIT`.
547
+ `COMMIT_REQUIRED`.
546
548
 
547
549
  **Done when:** `canon gate check` shows no violation for the scenarios you
548
550
  recorded evidence for; each record's own output line says whether it was
@@ -697,7 +699,7 @@ aggregates every record bound to the task, on one line:
697
699
  (the latest `--summary`, or a default naming the latest passing record).
698
700
  Every other path — missing evidence, a `Divergent` verdict, a fabricated
699
701
  note on any of the task's records — leaves the row byte-unchanged and
700
- 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
701
703
  source is re-ingested so the record store's task status agrees with the
702
704
  checkbox (`canon query --kind task` reads `done`); a failed re-ingest is
703
705
  a stderr warning naming `canon ingest plans`, never a failed flip.
@@ -734,7 +736,7 @@ Staging → committed: every well-formed record under
734
736
  applies, assigned a monotonic per-(role, surface) `run_seq` (gap-free
735
737
  within one invocation, continuing from the committed max), and moved into
736
738
  the committed ledger. A malformed or unpartitionable candidate is refused
737
- — 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`
738
740
  prints the plan (target path + assigned `run_seq` per candidate) without
739
741
  writing or deleting.
740
742
 
@@ -789,8 +791,10 @@ It installs no git hook: copy the script into git's `pre-commit` hook
789
791
  agent hook files and the script, also under `--dry-run`. In `--json`,
790
792
  `installed` is true when an agent hook file changed and
791
793
  `preCommitScriptWritten` when the script was written. A `--repo` that is not an
792
- existing directory exits 2 with `HOOKS_INSTALL_FAILED` (also under `--dry-run`)
793
- 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.
794
798
 
795
799
  Prefer this over hand-editing `settings.json`/`hooks.json`.
796
800
 
@@ -164,7 +164,9 @@ specs:
164
164
  whole root aborts, 0 writes, violations reported.
165
165
  - **A root on the pre-0.17 layout** (a `.feature` file under
166
166
  `<root>/features/`) → a `layout-grammar` violation at path `features`;
167
- 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
168
170
  leftover `features/` directory is not a refusal.
169
171
  - **A duplicate `scenario_id`** within one root → that root aborts, 0
170
172
  writes, reported as a sync error (a distinct lane from fmt violations).
@@ -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
@@ -143,7 +143,7 @@ canon dashboard --snapshot /tmp/canon-snap --port 8080
143
143
  - Runs in any repo: the released binary carries the app (in canon's own
144
144
  checkout a built `packages/dashboard/dist` is used instead). It prints the
145
145
  panels URL and a briefs URL (`/briefs.html`), then serves until Ctrl-C.
146
- 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
147
147
  `--port 0`.
148
148
  - Without the `duckdb` CLI on `PATH` the server still runs; the panels page
149
149
  says why there is no snapshot and how to get one (it never shows demo
@@ -160,11 +160,11 @@ answer once and clicks Approve: one request carries every selected brief with
160
160
  the sha256 of the file the page read, and records exactly what `canon brief
161
161
  approve <id>+ --approver <name> --note <text>` records, the `Approved:` line
162
162
  bound to the brief digest and the policy approval, for each. A brief that
163
- changed after the page loaded (`BRIEF_CHANGED_SINCE_PAGE_LOAD`) or that has
164
- blockers refuses the whole request (409 `BRIEF_APPROVE_REFUSED`, naming each
165
- 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
166
166
  naming one brief the old way (`changeId`, `sha256`) is still accepted. The server is localhost only and
167
- refuses requests from other origins (`DASHBOARD_ORIGIN_REFUSED`).
167
+ refuses requests from other origins (`DASHBOARD_REQUEST_DENIED`).
168
168
 
169
169
  For an agent: when clean briefs are waiting, show them (`canon brief show
170
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
 
@@ -475,7 +476,7 @@ stderr: canon subject move: review guard for building → verifying (spec_covera
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
@@ -295,7 +295,7 @@ answer; without it init takes the harnesses whose
295
295
  `.claude`, `.codex`, `.omp` or `.pi` directory exists, and with none detected
296
296
  it writes only a commented example
297
297
  and installs nothing. `.agents` alone never selects Codex. `canon skills
298
- install|check|doctor` follow the section; `install` prunes projected files the bundle no longer ships when their bytes match the lock (a modified one stays, reported as `kept:`), `check` exits 1 (`SKILLS_DRIFT`) naming each orphan and `doctor` prints `orphan:` lines; `canon skills install
298
+ install|check|doctor` follow the section; `install` prunes projected files the bundle no longer ships when their bytes match the lock (a modified one stays, reported as `kept:`), `check` exits 1 (`SKILLS_CHECK_FAILED`) naming each orphan and `doctor` prints `orphan:` lines; `canon skills install
299
299
  --providers=<list>` rewrites it in place. Without the section they use the
300
300
  install lock's providers, then the detected ones; nothing undetected is ever
301
301
  added. A present section that is not this shape, or names another harness,
@@ -395,7 +395,7 @@ so a killed commit never leaves it held, and the file is removed only by a
395
395
  call that made it to take the lock and then ended refused (a refusal leaves
396
396
  no file and no `.git/info/exclude` line behind). A
397
397
  command that waited 30 s for it starts nothing: it exits `2` with
398
- `REPO_WRITE_BUSY` (retryable; run it again in a moment). The first
398
+ `REPO_LOCK_UNAVAILABLE` (retryable; run it again in a moment). The first
399
399
  call that needs the lock makes the file, in any repository.
400
400
 
401
401
  ## What `canon init` keeps out of git
@@ -71,7 +71,8 @@ canon subject new subject-domain-loop \
71
71
  subjects at once: `--input` takes inline JSON, a file or `-`; an array (or
72
72
  NDJSON) is a batch validated before any write, with `operands` holding the
73
73
  id and the other keys the option names in camelCase (`canon schema subject
74
- new --json` shows `input`: the schema of one document and a complete `example`). Writing an identical subject
74
+ new --json` shows `input`, its limits and a complete `example`; `canon schema subject new --schemas --json`
75
+ gives `Input`, the schema of one document). Writing an identical subject
75
76
  again is a no-op reported `unchanged` (`data.unchanged`).
76
77
 
77
78
  ### 2. Retrieve subject-scoped strategy memory BEFORE working
@@ -137,7 +138,7 @@ canon subject move subject-domain-loop --to shipped
137
138
 
138
139
  On success the status updates in place; `--json` prints the updated
139
140
  record. On a gate block it prints violations by failure class to stderr,
140
- exits 1, and the record is unchanged.
141
+ exits 2 (the code names the condition: `SUBJECT_APPROVAL_REQUIRED`, `EVIDENCE_STALE`, `LAYOUT_MIGRATION_REQUIRED` or `SUBJECT_INVALID`; several causes are `error.details[]`), and the record is unchanged.
141
142
 
142
143
  **Corpus-wide, the same join:** `canon gate check` with
143
144
  `.canon/policy.yaml`'s opt-in `spec_coverage` section generalizes this
@@ -166,7 +167,7 @@ from shipping, until every evidenced scenario has evidence recorded after
166
167
  the close or the approval; the refusal names the scenarios and the
167
168
  `canon evidence add --all-scenarios` command. Each refusal prints by
168
169
  failure class (`uncovered-cell`), carries a `hint`,
169
- exits 1, and the status stays `verifying`. `retired` is not gated.
170
+ exits 2, and the status stays `verifying`. `retired` is not gated.
170
171
 
171
172
  **The brief (0.16, 0.17, 0.19):** `verifying → shipped` also refuses where a brief
172
173
  exists and is not approved, read exactly as `canon status` reads it (one
@@ -174,7 +175,7 @@ shared check, so status says `ship` only when this passes): the subject's
174
175
  scope (every change the subject answers for, see below) has a canon `.canon/changes/<change>/brief.md`
175
176
  with no `Approved:` line outside HTML comments and code fences, whose
176
177
  `Approved:` line carries a digest the brief's text no longer matches
177
- (`BRIEF_CHANGED_SINCE_APPROVAL`; the brief was edited after the human
178
+ (`BRIEF_APPROVAL_STALE`; the brief was edited after the human
178
179
  answered), or has no canon `brief.md` yet but comes from an external
179
180
  openspec plan with a `proposal.md` under the plan sources. It also
180
181
  refuses while `canon brief check` has blocker findings for that change,
@@ -184,7 +185,7 @@ a policy. The refusal is an `unreviewed-promotion` naming the subject, and
184
185
  says what to do:
185
186
 
186
187
  ```output
187
- output: canon subject move: SUBJECT_GATE_VIOLATION — unreviewed-promotion demo-subject — verifying → shipped: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line; a human must answer the brief, and only from that answer the agent will record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
188
+ output: canon subject move: SUBJECT_INVALID — unreviewed-promotion demo-subject — verifying → shipped: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line; a human must answer the brief, and only from that answer the agent will record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
188
189
  output: canon subject move: refused — get the human's answer to the brief and record it with `canon brief approve`, or pass --override-reason <text> to move anyway; the waiver is recorded on the subject
189
190
  ```
190
191
 
@@ -211,7 +212,7 @@ This refusal is a backstop, and so is the evidence one: shipping is not
211
212
  the first thing an unapproved brief stops. The agent writes the brief,
212
213
  runs `canon brief check` until it has no blockers, then shows it to the
213
214
  human and asks, and nothing is built or attested for the subject until the human
214
- answers. `canon evidence add` refuses (exit 1, nothing staged) a
215
+ answers. `canon evidence add` refuses (exit 2, nothing staged) a
215
216
  scenario whose `@subject` owner, or a task whose change
216
217
  an adopting subject, has an enforced, unapproved brief, through the same
217
218
  check; see `canon-gate`.
@@ -223,7 +224,7 @@ check; see `canon-gate`.
223
224
  edited since, and even if the tags were removed; or (3) a *chore*, which has
224
225
  no scenario to tag and so governs from the moment it is adopted. They pass
225
226
  only when every one of them reads as approved now; an unapproved one and one
226
- edited after its approval (`BRIEF_CHANGED_SINCE_APPROVAL`) are named for
227
+ edited after its approval (`BRIEF_APPROVAL_STALE`) are named for
227
228
  different reasons, and the answer does not depend on the order the changes
228
229
  were adopted or approved. The ship guard's brief-structure check runs over
229
230
  all of them. When several block, the hint is one
@@ -245,7 +246,7 @@ answers only to the changes its tags name (counting only changes the subject
245
246
  adopted); another change's edit after its approval never blocks it. An untagged
246
247
  scenario (one whose tags were removed reads the same) answers to every adopted
247
248
  change with an `Approved:` line, a chore included, so an approved change edited
248
- since refuses it (`BRIEF_CHANGED_SINCE_APPROVAL`); an unapproved chore blocks
249
+ since refuses it (`BRIEF_APPROVAL_STALE`); an unapproved chore blocks
249
250
  reopen and ship, never evidence. When no adopted change has an approved line,
250
251
  a scenario with evidence recorded before the subject first adopted a change
251
252
  (and without a brief override) needs no brief, and one without answers to the
@@ -270,7 +271,7 @@ A target outside `require_review.scope` prints `skipped
270
271
  unreviewed-promotion — `specced` is not in require_review.scope`. A
271
272
  transition INTO an in-scope status with gaps — an owned scenario with no
272
273
  qualifying review (`unreviewed-promotion`), or an open blocker finding
273
- on an adopted change (`open-blocker`) — prints the violations, exits 1,
274
+ on an adopted change (`open-blocker`) — prints the violations, exits 2,
274
275
  leaves the record unchanged, and names `--override-reason`. `shipped`
275
276
  also refuses a `false-success` (a scenario whose latest audit is
276
277
  `refuted`) and, when `require_audit.scope` covers `shipped`, an owed
@@ -332,14 +333,14 @@ output: canon subject move: demo-subject → verifying — written directly; not
332
333
  - Inside the approved scope it needs no human: every change the subject
333
334
  answers for (tagged, approved or chore) has an approved brief, or there
334
335
  is no brief to answer.
335
- Otherwise it refuses, exit 1, naming the brief to approve, and
336
+ Otherwise it refuses, exit 2, naming the brief to approve, and
336
337
  `--override-reason` does not waive it:
337
338
  ``unreviewed-promotion demo-subject — shipped → verifying: reopening needs the approved scope, and the brief is not approved — .canon/changes/c-next/brief.md has no `Approved:` line; …``.
338
339
  - The review guard does not run on a reopen (it prints `skipped … — a
339
340
  reopen moves the subject back to fix its gaps; shipping again runs
340
341
  it`). `verifying → shipped` afterwards runs every guard above again.
341
- - A policy that fails closed (`POLICY_CHANGED_SINCE_APPROVAL`,
342
- `POLICY_APPROVAL_UNREADABLE`: see `canon-policy`) refuses the reopen and
342
+ - A policy that fails closed (`POLICY_APPROVAL_STALE`,
343
+ `POLICY_APPROVAL_CORRUPT`, `POLICY_APPROVAL_DENIED`: see `canon-policy`) refuses the reopen and
343
344
  the ship, and `--override-reason` does not waive it.
344
345
  - `canon change new` on a shipped subject prints the reopen command
345
346
  (`canon subject move <id> --to verifying --reason "<why it reopens>"`)
@@ -422,7 +423,7 @@ canon subject unadopt <S> --change <change> --json
422
423
 
423
424
  Removes the link on both records and keeps the change and its brief, so the
424
425
  draft can be adopted elsewhere (a `proposed` holding subject, say) while the
425
- live subject keeps shipping. It is refused with `SUBJECT_UNADOPT_REFUSED`
426
+ live subject keeps shipping. It is refused with `SUBJECT_CONFLICT` (reason `APPROVED_BRIEF` or `FLOW_TAGGED`)
426
427
  for a change whose brief carries an `Approved:` line, and while a scenario
427
428
  the subject owns carries a `@flow:<change>.*` tag (it would fall back to an
428
429
  older approval; remove or retag those scenarios first, the hint names them);
@@ -509,12 +510,12 @@ same answer and one timestamp on every brief and on the policy approval
509
510
  (0.31). Every slug is checked before anything is written (a brief that
510
511
  exists and reads, no blocker, a one-line name and answer, a body that does not
511
512
  end inside an open code fence); one refused slug refuses the call, exit 2
512
- `BRIEF_APPROVE_REFUSED` naming each refused slug with its own code, and
513
- nothing is written. A repeated slug counts once. With one slug the output is as
513
+ with the first refused slug's own code (`BRIEF_INVALID`, `BRIEF_NOT_FOUND`) and an
514
+ `error.details` entry for each refused slug, and nothing is written. A repeated slug counts once. With one slug the output is as
514
515
  before; with several, `--json` carries one entry per slug (`written`,
515
516
  `unchanged`, `failed`, `skipped`). A disk error while writing exits 1 and
516
517
  leaves the slugs already written approved. The call is human-only for every
517
- slug; the `HUMAN_ONLY` hint gives the human one line with all the slugs.
518
+ slug; the `ACTOR_DENIED` hint gives the human one line with all the slugs.
518
519
 
519
520
  Without the change operand, the repo's only live change is read. The brief is the
520
521
  PRD `canon change new` writes; sections are found by their English `##`
@@ -524,7 +525,7 @@ before. A brief with `<!-- canon:… -->` comments or Korean headings is in the
524
525
  0.30 format: `brief check` gives it one blocker (`brief.old-format`) and
525
526
  `canon migrate` rewrites it; `status`, `gate check`, `context` and `brief show`
526
527
  warn, and a command that writes and judges it is refused
527
- (`OLD_BRIEF_FORMAT`).
528
+ (`BRIEF_MIGRATION_REQUIRED`).
528
529
 
529
530
  - **Blockers (structure, `brief.*`)**: a missing, duplicated or
530
531
  out-of-order section; a flow with no steps or a duplicate step id;
@@ -549,7 +550,7 @@ warn, and a command that writes and judges it is refused
549
550
  `Approved: <who> <when> — "<words>" (brief sha256:<digest>)` into the
550
551
  brief and records the policy approval in the same call. It refuses
551
552
  (exit 2) while the check has structure blockers. Edit the brief
552
- afterwards and every reader says `BRIEF_CHANGED_SINCE_APPROVAL` until a
553
+ afterwards and every reader says `BRIEF_APPROVAL_STALE` until a
553
554
  human answers again and `approve` runs again. Run it only from the
554
555
  human's answer, with their words as `--note`.
555
556
 
@@ -619,7 +620,7 @@ uses, so status and the gate cannot disagree about a gap:
619
620
  `Approved: <who> <when> — "<the human's words>" (brief sha256:<digest>)`,
620
621
  the digest covering the brief without its `Approved:` lines. A brief
621
622
  edited after that reads `brief: not approved (<brief> changed after its
622
- approval (BRIEF_CHANGED_SINCE_APPROVAL))` and names the re-approval
623
+ approval (BRIEF_APPROVAL_STALE))` and names the re-approval
623
624
  command: the changed brief needs a new human answer. A line with no
624
625
  digest (written before 0.19) stays approved, with an `advisory:` to
625
626
  re-approve so it binds to the text. Fixes and follow-ups
@@ -10,7 +10,7 @@ build nothing meanwhile. The only waiver is `--override-reason
10
10
  the human's answer: canon records it on the evidence, echoes it in
11
11
  `data.overrides[]` and lists it in `status` for the human. Never use it to
12
12
  skip the wait yourself. `brief approve`, `policy approve` and `divergence
13
- accept` are the human's; they refuse you (`HUMAN_ONLY`) unless they record an
13
+ accept` are the human's; they refuse you (`ACTOR_DENIED`) unless they record an
14
14
  answer the human gave in the conversation (`--relayed-via`, the planner's
15
15
  procedure: `canon skills show role-planner`). You never run them without that
16
16
  answer, and never remove or unset your role (`env -u CANON_ROLE`, dropping
@@ -25,7 +25,7 @@ in your ids. Use only the options on a line; never guess one. Ask `canon schema
25
25
  <command> --json` only for a leaf this block does not list, or after a `USAGE` refusal.
26
26
 
27
27
  <!-- canon:generated commands-implementer begin -->
28
- Every leaf takes `--as <ROLE>` and `--json`; `--repo <DIR>` too, except `completion`, `schema`, `skills show`. `--input <JSON|FILE|->` runs a leaf from one JSON document (an array is a batch) and is only on the lines ending `[--input]`. Its document keys are the option names in camelCase, singular even when the option repeats (the value is then an array), and `operands` holds the operands. `--fields <FIELDS>` is a comma list of the paths `canon schema <COMMAND> --json` declares under `outputs[].fields.paths`; a path is the record's own key, spelled as the answer spells it.
28
+ Every leaf takes `--as <ROLE>` and `--json`; `--repo <DIR>` too, except `completion`, `schema`, `skills show`. `--input <JSON|FILE|->` runs a leaf from one JSON document (an array is a batch) and is only on the lines ending `[--input]`. Its document keys are the option names in camelCase, singular even when the option repeats (the value is then an array; none is the key left out, `[]` is refused), and `operands` holds the operands. `--fields <FIELDS>` is a comma list of the paths `canon schema <COMMAND> --json` declares under `outputs[].fields.paths`; a path is the record's own key, spelled as the answer spells it.
29
29
  A `usage:` line shows the syntax and is not itself a command to run (the runnable example under it is): `<X>` is a value, `[x]` optional, `a | b` a choice, `(a | b)` exactly one is required, `[--x <V>]*` may repeat, `<X>+` is one or more, `[--a --b <V>]` go together. An option that is not on the line does not exist: it is refused (`USAGE`).
30
30
 
31
31
  ```text
@@ -177,7 +177,7 @@ canon scenario new auth.login.02 --title "Sign out" --feature .canon/specs/kind=
177
177
  ```
178
178
  ```text
179
179
  # Describe canon's own commands
180
- usage: canon schema [<PATH>]* [--errors | --error <CODE> | --warning <CODE> | --warnings]
180
+ usage: canon schema [<PATH>]* [--schemas | --error <CODE> | --errors | --warning <CODE> | --warnings]
181
181
  ```
182
182
  ```bash
183
183
  canon schema evidence add --json
@@ -224,7 +224,7 @@ After the first `status`, follow `meta.next` of each write; do not call
224
224
  the commit it is about from `--rev` (default `HEAD`, any git revision). You
225
225
  need not commit first: code that is not committed yet is recorded with its
226
226
  `codeTree` and `worktreeDirty: true`, never refused. Outside git, or in a
227
- repo with no commits, a write that needs a commit refuses `NO_COMMIT`.
227
+ repo with no commits, a write that needs a commit refuses `COMMIT_REQUIRED`.
228
228
 
229
229
  The forms you reach for most (the story's ids; swap in yours):
230
230
 
@@ -253,7 +253,7 @@ canon evidence add --input '[{"scenario":"auth.login.01","class":"test-run","ref
253
253
  keys are the option names in camelCase plus `operands` (the scenario id);
254
254
  every element is validated before the first write, so a bad element
255
255
  writes nothing and `error.field` names it (`/1/case`).
256
- `canon schema scenario new --json` shows `input`: the schema of one document and a complete `example`.
256
+ `canon schema scenario new --json` shows `input` (its limits and a complete `example`); `canon schema scenario new --schemas --json` gives `Input`, the schema of one document.
257
257
  (`scenario new --from` is gone.) When the gate asks for a missing case
258
258
  (`require_cases`), add a new scenario; never retag an existing one. Every
259
259
  bug fix adds or extends a scenario. Canon indexes added, edited or deleted