@journeykit/canon 0.23.0 → 0.24.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.
@@ -24,7 +24,7 @@ a feature, a one-line request included. A human is needed once per scope:
24
24
  answer until you report: the brief is that report. The one answer
25
25
  approves the brief and the policy, `.canon/policy.yaml`, which is what
26
26
  the gate grades the work against. Record it only from the human's answer:
27
- `canon brief approve --change <slug> --by <the human> --note "<their words>"`.
27
+ `canon brief approve --change-id <slug> --by <the human> --note "<their words>"`.
28
28
  Never edit the policy to make the gate pass: a policy that differs from
29
29
  the approved one fails closed (`POLICY_CHANGED_SINCE_APPROVAL`, not
30
30
  waivable); stop and ask the human. A brief edited after its
@@ -41,7 +41,7 @@ a feature, a one-line request included. A human is needed once per scope:
41
41
  closed `fixed`, and an approved chore, then need the whole suite evidenced
42
42
  again (`evidence add --all-scenarios`, for a chore after its approval)
43
43
  before it ships, and a chore also needs one change-level review
44
- (`review add --change <slug>`).
44
+ (`review add --change-id <slug>`).
45
45
  - When no human can answer one of the brief's questions, write your
46
46
  assumption into the brief's Questions and assumptions, build on it, and say
47
47
  so in your report. That covers the brief's questions and work inside an
@@ -113,6 +113,10 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
113
113
  on `error.code`, fix the option `field` names using the `expected` values,
114
114
  and follow `error.hint`. Every refusal carries a concrete `hint`: follow
115
115
  it. The codes are stable; `canon schema --errors --json` lists them.
116
+ - Flags that name an id are spelled `--<noun>-id` everywhere (`--change-id`,
117
+ `--project-id`, `--subject-id`, `--scenario-id`, `--actor-id`,
118
+ `--session-id`), and `--kind` values carry no `_record` suffix
119
+ (`--kind evidence`).
116
120
  - `canon status` sends the planner to write the brief while `brief check`
117
121
  has blockers; the human stop appears only when the brief is clean and
118
122
  unapproved.
@@ -84,7 +84,7 @@ enum, like `lane`.
84
84
  ## Subject pinning
85
85
 
86
86
  Every scenario belongs to a Subject (the durable product unit, see
87
- `canon-subject`). Write the Subject first, then pin with `--subject`;
87
+ `canon-subject`). Write the Subject first, then pin with `--subject-id`;
88
88
  the scenario index carries the tag onto the index record and
89
89
  `spec_coverage.scope` filters on it. An unpinned scenario is invisible to
90
90
  a scoped gate.
@@ -94,9 +94,9 @@ a scoped gate.
94
94
  ```bash
95
95
  canon feature new checkout.cart --title "Cart" # once per surface
96
96
  canon scenario new checkout.cart.01 --title "Adding an item raises the count" \
97
- --subject checkout-core --lane behavior --case happy # once per behavior
97
+ --subject-id checkout-core --lane behavior --case happy # once per behavior
98
98
  canon scenario new checkout.cart.04 --title "Adding an out-of-stock item is refused" \
99
- --subject checkout-core --lane behavior --case failure # and its failure path
99
+ --subject-id checkout-core --lane behavior --case failure # and its failure path
100
100
  ```
101
101
 
102
102
  There is no format or sync step after these: the scaffold writes a
@@ -108,7 +108,7 @@ one of them prints `NOT refreshed`, the corpus has a format violation
108
108
  duplicate id; `canon inventory sync` (or `canon format <root>`) names it.
109
109
  Fix it and the next command indexes the files (see `canon-inventory`).
110
110
 
111
- - `--actor <id>` (or `CANON_ACTOR` in the environment) puts YOUR id on the
111
+ - `--actor-id <id>` (or `CANON_ACTOR` in the environment) puts YOUR id on the
112
112
  provenance line. Default is `canon-scaffold`.
113
113
  - **Keep the `# canon:` lines when you fill in the scenario.** Dropping one
114
114
  makes `canon inventory sync` abort on `missing-provenance`; restore it
@@ -146,7 +146,7 @@ Fix it and the next command indexes the files (see `canon-inventory`).
146
146
  - **A Feature title that is a theme.** "Fidelity of the original
147
147
  experience" names no surface. Name the screen.
148
148
  - **Hand-stamped provenance.** Eighty lines with one timestamp and the
149
- same `agent_id`. Use `canon scenario new --actor`.
149
+ same `agent_id`. Use `canon scenario new --actor-id`.
150
150
  - **Coverage by splitting.** One behavior as two scenarios so two rows go
151
151
  green. One behavior, one id.
152
152
  - **Runner tags as classification.** `@design`, `@p2`, `@wip` are
@@ -230,7 +230,7 @@ implementer --ref "<test command>" …`. Reviews pin what the evidence says
230
230
  (its verdict and the identity of its checks), not which record it is, so
231
231
  recording the suite again with the same verdicts from the same cases leaves
232
232
  every scenario review current. A chore instead needs one change-level
233
- review of the chore itself (`canon review add --change <slug> …`) before
233
+ review of the chore itself (`canon review add --change-id <slug> …`) before
234
234
  `--to shipped`; a changed verdict or case set stales that scenario's
235
235
  review as before (and a new `divergence accept`, where the gap remains).
236
236
 
@@ -295,7 +295,7 @@ check `canon status` and the ship guard use; see
295
295
  `--task`:
296
296
 
297
297
  ```
298
- 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 --change c-demo --by <the human> --note "<their words>"`
298
+ 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 --change-id c-demo --by <the human> --note "<their words>"`
299
299
  canon evidence add: refused — stop, report the brief to the human and wait for their answer: nothing is built or attested for a subject before its brief is approved. Record their answer with `canon brief approve --by <the human> --note "<their words>"` only from that answer; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
300
300
  ```
301
301
 
@@ -306,7 +306,7 @@ openspec/changes/c-ext/proposal.md, which canon reads and never edits, so
306
306
  its approval lives in that canon file, so the human has not answered it;
307
307
  once they do, create .canon/changes/c-ext/brief.md holding a `Source:
308
308
  openspec/changes/c-ext/proposal.md` line, then record their words with
309
- `canon brief approve --change c-ext --by <the human> --note "<their words>"` ``. An `Approved:` line in the
309
+ `canon brief approve --change-id c-ext --by <the human> --note "<their words>"` ``. An `Approved:` line in the
310
310
  external `proposal.md` itself is never read.
311
311
 
312
312
  A subject with no brief to answer (no adopted change, or a newest change
@@ -482,8 +482,14 @@ them: `faithful` when every case passed, `divergent` when one failed,
482
482
  claims the same verdict for every record instead. A case whose id is not
483
483
  indexed is named and skipped (`skipped <id> — not an indexed scenario`);
484
484
  a report no indexed scenario owns is refused (exit 2). The records share
485
- the stored report and every `--artifact`, and the output lists each
486
- scenario with its verdict on its own line.
485
+ the stored report, and the output lists each scenario with its verdict on
486
+ its own line. Each record binds the attachments its own cases name in the
487
+ report (a JUnit test case's `[[ATTACHMENT|path]]` lines, which Playwright's
488
+ JUnit reporter writes; a Cucumber JSON embedding), so a test's screenshot
489
+ stays with its scenario. A file the report does not name goes with
490
+ `--artifact <scenario-id>=<path>`; a bare `--artifact <path>` in a batch is
491
+ refused (`EVIDENCE_INVALID_ARGUMENT`). A report attachment that is missing,
492
+ outside the repo or oversized is refused.
487
493
 
488
494
  It is all or nothing: a claimed `faithful` verdict over a failed case,
489
495
  a fabrication marker in `--summary`, an unapproved brief for any
@@ -179,7 +179,7 @@ record.
179
179
  An operator-requested rollback is a distinct authenticated action:
180
180
 
181
181
  ```bash
182
- canon learn rollback <strategy_id> --reason "<reason>" --actor alice \
182
+ canon learn rollback <strategy_id> --reason "<reason>" --actor-id alice \
183
183
  --signature-file rollback.sig --approved-at 2026-10-02T12:00:00Z \
184
184
  [--contradicting-trajectory-id <trajectory_id>] --repo .
185
185
  ```
@@ -142,7 +142,7 @@ canon review add --project-id <root-id> --scenario-id <id> [--scenario-id <id>].
142
142
  [--outcome signed|indeterminate|unavailable] \
143
143
  [--reviewer-provider <p>] [--reviewer-model <m>] [--reviewer-harness <h>] \
144
144
  [--artifact <path>]... [--max-artifact-mib <MiB>]
145
- canon review add --project-id <root> --change <slug> --reviewer <who> --pin <sha-or-ref> \
145
+ canon review add --project-id <root> --change-id <slug> --reviewer <who> --pin <sha-or-ref> \
146
146
  --role reviewer (--upstream-ref <ref> | --original-spec-ref <ref>) … # a chore, below
147
147
  ```
148
148
 
@@ -169,18 +169,18 @@ that is not a scenario id, refuses the call (exit 2) and writes no review.
169
169
  This is also the batch re-pin after `canon evidence add` reports reviews
170
170
  it made stale (see `canon-gate`).
171
171
 
172
- ### A chore is reviewed as a change (`--change`, 0.23)
172
+ ### A chore is reviewed as a change (`--change-id`, 0.23)
173
173
 
174
174
  A chore adds no scenarios, and recording the suite again after it leaves
175
175
  every scenario review current (a review pins the evidence's verdict and
176
176
  checks, so the same verdicts from the same cases change nothing). What the
177
177
  chore needs instead is one change-level review: the reviewer signs its
178
- invariants and checks against the diff with `canon review add --change
178
+ invariants and checks against the diff with `canon review add --change-id
179
179
  <slug> …`, in place of `--scenario-id`. The review pins the chore's brief
180
180
  (its digest, less the `Approved:` line), so an edit to the brief stales it,
181
181
  and `--to shipped` refuses a chore with no signed, current change-level
182
182
  review (`spec_coverage.require_review.distinct_actor` asks it of a reviewer
183
- and session that did not attest the subject's evidence). `--change` takes a
183
+ and session that did not attest the subject's evidence). `--change-id` takes a
184
184
  chore's slug and refuses a feature change.
185
185
 
186
186
  ### What the reviewer looked at (artifacts)
@@ -115,7 +115,7 @@ file names, tracked in git. `status`, the gate, the guards and `canon query`
115
115
  read the ledger only.
116
116
 
117
117
  ```bash
118
- canon query --kind evidence_record --history # every version, archive included
118
+ canon query --kind evidence --history # every version, archive included
119
119
  canon ledger compact --dry-run # report; writes nothing
120
120
  canon ledger compact # pre-0.23 ledger or interrupted move; idempotent; `canon migrate` runs it
121
121
  ```
@@ -69,12 +69,12 @@ canon subject new subject-domain-loop \
69
69
  ### 2. Retrieve subject-scoped strategy memory BEFORE working
70
70
 
71
71
  ```bash
72
- canon retrieve --role dev --domain dev --subject subject-domain-loop --k 5
72
+ canon retrieve --role dev --domain dev --subject-id subject-domain-loop --k 5
73
73
  ```
74
74
 
75
- - `--regime <key>` XOR the derived pair `--domain <d> [--subject <id>]`:
75
+ - `--regime <key>` XOR the derived pair `--domain <d> [--subject-id <id>]`:
76
76
  give the full regime key directly, OR let retrieval derive it. Never both.
77
- - With `--domain`/`--subject`, retrieval tries `<domain>-<subject_id>`
77
+ - With `--domain`/`--subject-id`, retrieval tries `<domain>-<subject_id>`
78
78
  first, then `<domain>` — a subject's own lessons win, falling back to
79
79
  the domain's shared memory when the subject is new.
80
80
  - Fail-soft: an empty/missing store degrades to an empty guidance list,
@@ -82,7 +82,7 @@ canon retrieve --role dev --domain dev --subject subject-domain-loop --k 5
82
82
 
83
83
  ### 3. Work → pin every artifact to `subject_id`
84
84
 
85
- - **Scenarios**: `canon scenario new <tag> --subject <subject-id>` emits
85
+ - **Scenarios**: `canon scenario new <tag> --subject-id <subject-id>` emits
86
86
  the `@subject:<subject-id>` tag; the scenario index maps the tag onto
87
87
  the scenario's `subject_id` the next time a command reads it (no sync
88
88
  step; see `canon-inventory`). A malformed/absent tag leaves it unset
@@ -172,7 +172,7 @@ a policy. The refusal is an `unreviewed-promotion` naming the subject, and
172
172
  says what to do:
173
173
 
174
174
  ```
175
- canon subject status: 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 --change c-demo --by <the human> --note "<their words>"`
175
+ canon subject status: 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 --change-id c-demo --by <the human> --note "<their words>"`
176
176
  canon subject status: 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
177
177
  ```
178
178
 
@@ -181,7 +181,7 @@ For an external change with no canon brief yet, the reason reads
181
181
  the external plan <proposal>, which canon reads and never edits, so its
182
182
  approval lives in that canon file`` and the agent will ``create
183
183
  .canon/changes/<c>/brief.md holding a `Source: <proposal>` line, then
184
- record their words with `canon brief approve --change <c> --by <the human> --note "<their words>"` ``.
184
+ record their words with `canon brief approve --change-id <c> --by <the human> --note "<their words>"` ``.
185
185
 
186
186
  Never record the approval without the human's answer. When there is no brief to
187
187
  answer (no adopted change, or a newest change with neither a canon
@@ -306,7 +306,7 @@ Planning docs written outside canon become change/task records via
306
306
  ```bash
307
307
  canon ingest plans --repo . # import → change/task rows
308
308
  canon subject adopt subject-domain-loop-plan \
309
- --subject subject-domain-loop # link change → subject
309
+ --subject-id subject-domain-loop # link change → subject
310
310
  ```
311
311
 
312
312
  A change made with `canon change new` (below) is recorded and adopted
@@ -343,7 +343,7 @@ The two records cannot be written atomically, so the subject is written
343
343
  first: a half-done adoption still has that change's open blockers
344
344
  counted. If the change write then fails, `adopt` exits `2`, names the
345
345
  subject that now lists the change, and prints `canon subject adopt
346
- <change_id> --subject <id>` to complete it.
346
+ <change_id> --subject-id <id>` to complete it.
347
347
 
348
348
  ### Starting a new change: `canon change new`
349
349
 
@@ -351,7 +351,7 @@ For a change that does not exist yet, one command writes it and records
351
351
  it adopted:
352
352
 
353
353
  ```bash
354
- canon change new add-login --subject auth --title "Add login"
354
+ canon change new add-login --subject-id auth --title "Add login"
355
355
  ```
356
356
 
357
357
  ```
@@ -387,7 +387,7 @@ canon change new: recorded change `add-login` adopted into subject `auth` — wr
387
387
  cannot be written atomically. If the change record fails after the
388
388
  subject record was written, the command exits `2`, keeps the change
389
389
  dir and that one subject record, and prints the repair, `canon ingest
390
- plans && canon subject adopt <slug> --subject <id>`, which completes
390
+ plans && canon subject adopt <slug> --subject-id <id>`, which completes
391
391
  the link and is safe to rerun.
392
392
  - **Refuses** with exit `2`, writing nothing, when the subject does not
393
393
  exist, or when the slug already has a `.canon/changes/<slug>` dir
@@ -411,12 +411,12 @@ it, so the external source keeps the change, its summary and its tasks.
411
411
  ### The brief: `canon brief`, `canon brief check`, `canon brief approve`
412
412
 
413
413
  ```bash
414
- canon brief [--change <slug>] # state and the next one to three steps; never edits
415
- canon brief check [--change <slug>] [--json] # findings; exit 0 clean, 2 blockers, 1 error
416
- canon brief approve --change <slug> --by <the human> --note "<their words>"
414
+ canon brief [--change-id <slug>] # state and the next one to three steps; never edits
415
+ canon brief check [--change-id <slug>] [--json] # findings; exit 0 clean, 2 blockers, 1 error
416
+ canon brief approve --change-id <slug> --by <the human> --note "<their words>"
417
417
  ```
418
418
 
419
- Without `--change`, the repo's only live change is read. The brief is the
419
+ Without `--change-id`, the repo's only live change is read. The brief is the
420
420
  PRD `canon change new` writes; sections are found by their
421
421
  `<!-- canon:section <key> role=… -->` marker, never by heading text. A
422
422
  brief without markers (written before 0.19) checks as `brief.legacy`, an
@@ -455,7 +455,7 @@ is the subject's suite run again at the chore commit with
455
455
  `canon evidence add --all-scenarios --report <kind>:<path> …`. That
456
456
  supersedes the old evidence; the pinned reviews stay current while the
457
457
  verdicts and checks are the same, so the chore itself is reviewed once with
458
- `canon review add --change <slug> …` before it ships. Work that changes
458
+ `canon review add --change-id <slug> …` before it ships. Work that changes
459
459
  behavior is a feature change, never a chore.
460
460
 
461
461
  ## Where are we: `canon status`
@@ -560,7 +560,7 @@ uses, so status and the gate cannot disagree about a gap:
560
560
  first, then building, specced, proposed, shipped: an unapproved brief
561
561
  (building and later, and proposed once its change has a brief)
562
562
  → the human step below, which is then the subject's
563
- only step; no scenario → `canon scenario new … --subject <id>` (and, when no
563
+ only step; no scenario → `canon scenario new … --subject-id <id>` (and, when no
564
564
  `.feature` file holds a scenario yet, `canon feature new` first, unless
565
565
  every subject waits on its brief); a missing case → `canon scenario new
566
566
  <surface>.<next nn> … --case <case>`; (building and later) an
@@ -572,12 +572,12 @@ uses, so status and the gate cannot disagree about a gap:
572
572
  Last, unowned scenarios → `canon status`, after tagging them in their
573
573
  `.feature` files (status re-indexes the edit; no sync step). With more
574
574
  than one `specs.roots[]` entry, every suggested `canon scenario new`
575
- carries `--project`: the owning root for a missing case, `<root-id>`
575
+ carries `--project-id`: the owning root for a missing case, `<root-id>`
576
576
  (the reason lists the roots) for a subject that owns no scenario yet.
577
577
  - **The one human step.** Every step is the agent's to run except one,
578
578
  and it comes only once the brief is clean: while `canon brief check
579
- --change <slug>` has blockers, the subject gets the planner step
580
- `write the brief: canon brief check --change <slug> lists N blockers`
579
+ --change-id <slug>` has blockers, the subject gets the planner step
580
+ `write the brief: canon brief check --change-id <slug> lists N blockers`
581
581
  (`role: planner`) instead. A subject whose brief is enforced (its
582
582
  newest change's canon
583
583
  `brief.md` has no `Approved:` line, or it has no canon `brief.md` yet
@@ -589,10 +589,10 @@ uses, so status and the gate cannot disagree about a gap:
589
589
  and the approval is never assumed: `canon evidence add` refuses <id>'s
590
590
  scenarios and tasks until it is recorded; once the human answers,
591
591
  <record> (one call records the brief and the policy approval)``, where
592
- `<record>` is ``record their words with `canon brief approve --change
592
+ `<record>` is ``record their words with `canon brief approve --change-id
593
593
  <c> --by <the human> --note "<their words>"` ``, or, for an external
594
594
  change, ``create <brief> holding a `Source: <proposal>` line, then
595
- record their words with `canon brief approve --change <c> --by <the
595
+ record their words with `canon brief approve --change-id <c> --by <the
596
596
  human> --note "<their words>"` ``; for a brief edited after its
597
597
  approval, ``re-approve with `canon brief approve …` ``.
598
598
  It is the subject's only step, whatever its status: nothing suggests
@@ -638,7 +638,7 @@ Status fails closed rather than suggest progress the gate would refuse:
638
638
  ],
639
639
  "unowned": ["cart.promo.01"],
640
640
  "next": [
641
- { "command": "stop and report the brief in openspec/changes/c-promo/proposal.md; build and attest nothing for promo until the human answers (one answer approves brief and policy)", "why": "promo: .canon/changes/c-promo/brief.md does not exist yet: change `c-promo` comes from the external plan openspec/changes/c-promo/proposal.md, which canon reads and never edits, so its approval lives in that canon file (an older change's approval does not cover a new scope), and the approval is never assumed: … once the human answers, create .canon/changes/c-promo/brief.md holding a `Source: openspec/changes/c-promo/proposal.md` line, then record their words with `canon brief approve --change c-promo --by <the human> --note \"<their words>\"` (one call records the brief and the policy approval)", "actor": "human" },
641
+ { "command": "stop and report the brief in openspec/changes/c-promo/proposal.md; build and attest nothing for promo until the human answers (one answer approves brief and policy)", "why": "promo: .canon/changes/c-promo/brief.md does not exist yet: change `c-promo` comes from the external plan openspec/changes/c-promo/proposal.md, which canon reads and never edits, so its approval lives in that canon file (an older change's approval does not cover a new scope), and the approval is never assumed: … once the human answers, create .canon/changes/c-promo/brief.md holding a `Source: openspec/changes/c-promo/proposal.md` line, then record their words with `canon brief approve --change-id c-promo --by <the human> --note \"<their words>\"` (one call records the brief and the policy approval)", "actor": "human" },
642
642
  { "command": "canon finding close --change-id c-cart --round 1 --seq 1 --disposition fixed --resolution-sha <sha> --actor-id <unit> --session-id <session>", "why": "cart: 1 open blocker finding(s) (first: …); fix it, commit, then close it", "actor": "agent" },
643
643
  { "command": "canon review add --project-id root --scenario-id cart.add.02 --reviewer <reviewer> --actor-id <reviewer> --session-id <review-session> --role reviewer --pin <sha> --original-spec-ref \"<feature file>\"", "why": "cart: 1 of 2 scenario(s) lack a qualifying review; …", "actor": "agent" },
644
644
  { "command": "canon status", "why": "1 scenario(s) carry no @subject tag (first: cart.promo.01); add `@subject:<id>` above each in its .feature file, then check again: …", "actor": "agent" }
@@ -14,8 +14,8 @@ a `specs.roots[]` entry in `canon.yaml` (`root` by default).
14
14
  ```bash
15
15
  canon status --as implementer --json # once, at the start
16
16
  canon feature new <area>.<surface> --title "<title>" --as implementer --json
17
- canon scenario new <area>.<surface>.<nn> --subject <subject-id> --flow <F-id> --case <happy|edge|failure> --title "<title>" --as implementer --json
18
- canon scenario new --from - --as implementer --json # many at once: NDJSON on stdin, one {"id","title","subject","flow","case",…} per line
17
+ canon scenario new <area>.<surface>.<nn> --subject-id <subject-id> --flow <F-id> --case <happy|edge|failure> --title "<title>" --as implementer --json
18
+ canon scenario new --from - --as implementer --json # many at once: NDJSON on stdin, one {"id","title","subject-id","flow","case",…} per line
19
19
  canon evidence add --project-id <root-id> --all-scenarios --report <junit|cucumber|swift-testing>:<path> --kind test-run --role implementer --ref "<test command>" --actor-id <unit> --session-id <session> --as implementer --json
20
20
  canon evidence add --project-id <root-id> --scenario-id <id> --artifact <path> --kind test-run --role implementer --ref "<what it shows>" --actor-id <unit> --session-id <session> --as implementer --json
21
21
  canon evidence add --project-id <root-id> --scenario-id <id> --verdict divergent --artifact <path> --kind test-run --role implementer --ref "<the external limit, and where it is tracked>" --actor-id <unit> --session-id <session> --as implementer --json # honest divergent evidence
@@ -65,10 +65,13 @@ After the first `status`, follow `meta.next` of each write; do not call
65
65
  `canon artifacts verify` to ask the store yourself; it refuses, never
66
66
  passes, when an object store cannot be reached. Moving an existing store
67
67
  (`canon artifacts migrate`) is the repo owner's call: do not run it.
68
- For a scenario about what users see, bind its own screenshot or recording
69
- with that scenario: `--scenario-id <id> --artifact <path>`. A batch
70
- (`--all-scenarios`) binds every file it names to every scenario, so give
71
- a batch only the reports; never loop all screenshots into it. An external evaluator's audit is
68
+ For a scenario about what users see, let the test report carry its
69
+ screenshots: Playwright's JUnit reporter attaches, per test case, what a
70
+ test attaches (`testInfo.attach(name, {path})`, or `screenshot: 'on'`), and
71
+ one `evidence add --all-scenarios --report junit:<path>` binds to each
72
+ record only its own tests' files. A file the report does not name goes
73
+ with `--artifact <scenario-id>=<path>`; a bare `--artifact` in a batch is
74
+ refused. An external evaluator's audit is
72
75
  `--kind audit`; canon never generates one. Evidence for a task of an
73
76
  imported plan (`--task <id>`) must bind the artifact or report that proves
74
77
  the task; a canon command is never that proof. When the behavior cannot
@@ -108,6 +111,6 @@ When every scenario has evidence, the review is the reviewer's session, in a
108
111
  separate process: do not review your own change. A chore adds no scenarios:
109
112
  once it is approved, run the suite and bind it with `--all-scenarios`;
110
113
  shipping needs that evidence newer than the chore's approval, plus the
111
- reviewer's one change-level review of the chore (`review add --change`).
114
+ reviewer's one change-level review of the chore (`review add --change-id`).
112
115
  Scenario reviews stay current when the verdicts and checks are unchanged.
113
116
  Reference: `reference/canon-gate.md`.
@@ -10,7 +10,7 @@ Every line is complete; fill the `<placeholders>`.
10
10
 
11
11
  ```bash
12
12
  canon status --as orchestrator --json --fields next,waitingOn # at the start and when resuming
13
- canon brief approve --change <slug> --by "<the human>" --note "<their words>" --as orchestrator --json
13
+ canon brief approve --change-id <slug> --by "<the human>" --note "<their words>" --as orchestrator --json
14
14
  canon subject status <subject-id> --to <proposed|specced|building|verifying|shipped> --actor-id <unit> --as orchestrator --json
15
15
  canon subject status <subject-id> --to verifying --reason "<why>" --actor-id <unit> --as orchestrator --json # reopen a shipped subject (--reason is required here; any other transition accepts it as a note)
16
16
  canon policy show --as orchestrator --json # policy digest and its approval: approved, changed, unreadable or unapproved
@@ -82,7 +82,7 @@ change, then `--to shipped` again. A chore on a shipped subject (`change
82
82
  new … --kind chore` names the reopen command) is approved first, then
83
83
  reopened the same way; shipping again needs the whole suite evidenced after
84
84
  the chore's approval (the implementer's `evidence add --all-scenarios`) and
85
- one change-level review of the chore from the reviewer (`review add --change
85
+ one change-level review of the chore from the reviewer (`review add --change-id
86
86
  <slug>`): the order is approval, evidence, review. A blocker closed
87
87
  `fixed` needs the suite again. The refusal names the scenarios and
88
88
  the command; never override them. `canon status` flags a shipped subject
@@ -12,17 +12,17 @@ Every line is complete; fill the `<placeholders>`.
12
12
  ```bash
13
13
  canon status --as planner --json # once, at the start
14
14
  canon subject new <subject-id> --domain <domain> --title "<title>" --actor-id <unit> --as planner --json
15
- canon change new <slug> --subject <subject-id> --title "<title>" --as planner --json
16
- canon change new <slug> --subject <subject-id> --kind chore --title "<title>" --as planner --json
17
- canon subject adopt <slug> --subject <other-subject-id> --as planner --json
18
- canon brief check --change <slug> --as planner --json
19
- canon brief approve --change <slug> --by "<the human>" --note "<their words>" --as planner --json
15
+ canon change new <slug> --subject-id <subject-id> --title "<title>" --as planner --json
16
+ canon change new <slug> --subject-id <subject-id> --kind chore --title "<title>" --as planner --json
17
+ canon subject adopt <slug> --subject-id <other-subject-id> --as planner --json
18
+ canon brief check --change-id <slug> --as planner --json
19
+ canon brief approve --change-id <slug> --by "<the human>" --note "<their words>" --as planner --json
20
20
  ```
21
21
 
22
22
  After the first `status`, follow `meta.next` of each write. `brief check`
23
23
  lists blockers and advisories; bare `canon brief --as planner` names the next
24
24
  steps. While the brief has blockers, `status` and `change new`'s `meta.next`
25
- send you to write it (`write the brief: canon brief check --change <slug>
25
+ send you to write it (`write the brief: canon brief check --change-id <slug>
26
26
  lists N blockers`); the human step appears only once the brief is clean and
27
27
  unapproved. A policy that no longer matches its approval fails closed
28
28
  (`POLICY_CHANGED_SINCE_APPROVAL`): never edit it; the human re-approves.
@@ -80,7 +80,7 @@ category, invariants, checks, out of scope) and approved like any brief, one
80
80
  human stop. A chore adds no scenarios: the
81
81
  implementer runs the subject's suite again and binds it with
82
82
  `canon evidence add --all-scenarios …`, then the reviewer records one
83
- change-level review of the chore (`canon review add --change <slug>`). On a
83
+ change-level review of the chore (`canon review add --change-id <slug>`). On a
84
84
  shipped subject `change new` prints the reopen command for the orchestrator
85
85
  (`subject status <id> --to verifying --reason "<why>"`); the subject cannot
86
86
  ship again until the suite is evidenced after the chore's approval. Work that
@@ -10,17 +10,17 @@ Every line is complete; fill the `<placeholders>`. `<root-id>` is the `id` of
10
10
  a `specs.roots[]` entry in `canon.yaml` (`root` by default).
11
11
 
12
12
  ```bash
13
- canon brief check --change <slug> --as reviewer --json
13
+ canon brief check --change-id <slug> --as reviewer --json
14
14
  canon gate check --as reviewer --json # once, before review add
15
15
  canon finding add --change-id <slug> --round <n> --seq <n> --severity <blocker|should-fix|note> --reviewer <me> --actor-id <me> --session-id <session> --summary "<defect>" --as reviewer --json
16
16
  canon finding list --change-id <slug> --open --as reviewer --json
17
17
  canon finding close --change-id <slug> --round <n> --seq <n> --disposition fixed --resolution-sha <sha> --as reviewer --json
18
18
  canon review add --project-id <root-id> --scenario-id <id> --scenario-id <id> --reviewer <me> --actor-id <me> --role reviewer --session-id <session> --pin <sha> --upstream-ref <ref> --as reviewer --json
19
19
  canon review add --project-id <root-id> --scenario-ids-from - --reviewer <me> --actor-id <me> --role reviewer --session-id <session> --pin <sha> --upstream-ref <ref> --as reviewer --json # ids on stdin, one per line
20
- canon review add --project-id <root-id> --change <chore-slug> --reviewer <me> --actor-id <me> --role reviewer --session-id <session> --pin <sha> --upstream-ref <ref> --as reviewer --json # a chore: one change-level review of its invariants and checks against the diff
20
+ canon review add --project-id <root-id> --change-id <chore-slug> --reviewer <me> --actor-id <me> --role reviewer --session-id <session> --pin <sha> --upstream-ref <ref> --as reviewer --json # a chore: one change-level review of its invariants and checks against the diff
21
21
  canon divergence accept --project-id <root-id> --scenario-id <id> --reason "<why the gap stays>" --tracking <issue-url-or-ref> [--expiry YYYY-MM-DD] --reviewer <me> --actor-id <me> --session-id <session> --as reviewer --json
22
22
  canon artifacts verify --full --as reviewer --json # the files the evidence and reviews bind are in the artifact store; refuses when an object store is unreachable
23
- canon query --kind evidence_record --history --as reviewer --json # every version, not only the current record
23
+ canon query --kind evidence --history --as reviewer --json # every version, not only the current record
24
24
  ```
25
25
 
26
26
  `review add` needs `--upstream-ref <ref>` or `--original-spec-ref <path>`;
@@ -104,7 +104,7 @@ ship guard and stays listed as `accepted-divergence` in `status` and
104
104
  evidence changes a verdict or the checks and so stales your review, look
105
105
  again before you re-pin.
106
106
  A chore has no scenarios: review it with one change-level review, `canon
107
- review add --project-id <root-id> --change <slug> --reviewer <me> --role
107
+ review add --project-id <root-id> --change-id <slug> --reviewer <me> --role
108
108
  reviewer --pin <sha> --upstream-ref <ref> …`. It signs the chore's
109
109
  invariants and checks against the diff and pins its brief, so editing the
110
110
  brief stales it. The chore also needs evidence recorded after its approval
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@journeykit/canon",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "canon — harness knowledge substrate. JS launcher: platform detection + native binary resolution.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {},
32
32
  "optionalDependencies": {
33
- "@journeykit/canon-core-darwin-arm64": "0.23.0",
34
- "@journeykit/canon-core-linux-x64": "0.23.0",
35
- "@journeykit/canon-core-win32-x64": "0.23.0"
33
+ "@journeykit/canon-core-darwin-arm64": "0.24.0",
34
+ "@journeykit/canon-core-linux-x64": "0.24.0",
35
+ "@journeykit/canon-core-win32-x64": "0.24.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^20.0.0",