@journeykit/canon 0.23.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/skills/SKILL.src.md +6 -2
- package/dist/skills/reference/canon-authoring.md +5 -5
- package/dist/skills/reference/canon-gate.md +16 -7
- package/dist/skills/reference/canon-learn.md +1 -1
- package/dist/skills/reference/canon-review.md +11 -5
- package/dist/skills/reference/canon-storage.md +1 -1
- package/dist/skills/reference/canon-subject.md +22 -22
- package/dist/skills/reference/role-implementer.md +10 -7
- package/dist/skills/reference/role-orchestrator.md +2 -2
- package/dist/skills/reference/role-planner.md +7 -7
- package/dist/skills/reference/role-reviewer.md +11 -7
- package/package.json +4 -4
package/dist/skills/SKILL.src.md
CHANGED
|
@@ -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
|
|
@@ -223,14 +223,17 @@ accepted divergences: 1 known gap(s) — not failing the gate:
|
|
|
223
223
|
Re-verification is one rule with two triggers: a blocker whose latest
|
|
224
224
|
disposition is `fixed`, and a chore change once approved, keep the subject
|
|
225
225
|
from shipping until every one of its evidenced scenarios has evidence
|
|
226
|
-
recorded after the close or the approval.
|
|
227
|
-
|
|
226
|
+
recorded after the close or the approval. A blocker that names its
|
|
227
|
+
scenarios (`finding add --scenario-id`) asks only those, and the refusal
|
|
228
|
+
names them with the per-scenario command (`canon evidence add --project-id
|
|
229
|
+
<root-id> --scenario-id <id> --report <format>:<path> …`). Otherwise the
|
|
230
|
+
refusal names the scenarios and the batch command: `canon evidence add --project-id <root-id>
|
|
228
231
|
--all-scenarios --report <format>:<path> --kind test-run --role
|
|
229
232
|
implementer --ref "<test command>" …`. Reviews pin what the evidence says
|
|
230
233
|
(its verdict and the identity of its checks), not which record it is, so
|
|
231
234
|
recording the suite again with the same verdicts from the same cases leaves
|
|
232
235
|
every scenario review current. A chore instead needs one change-level
|
|
233
|
-
review of the chore itself (`canon review add --change <slug> …`) before
|
|
236
|
+
review of the chore itself (`canon review add --change-id <slug> …`) before
|
|
234
237
|
`--to shipped`; a changed verdict or case set stales that scenario's
|
|
235
238
|
review as before (and a new `divergence accept`, where the gap remains).
|
|
236
239
|
|
|
@@ -295,7 +298,7 @@ check `canon status` and the ship guard use; see
|
|
|
295
298
|
`--task`:
|
|
296
299
|
|
|
297
300
|
```
|
|
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>"`
|
|
301
|
+
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
302
|
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
303
|
```
|
|
301
304
|
|
|
@@ -306,7 +309,7 @@ openspec/changes/c-ext/proposal.md, which canon reads and never edits, so
|
|
|
306
309
|
its approval lives in that canon file, so the human has not answered it;
|
|
307
310
|
once they do, create .canon/changes/c-ext/brief.md holding a `Source:
|
|
308
311
|
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
|
|
312
|
+
`canon brief approve --change-id c-ext --by <the human> --note "<their words>"` ``. An `Approved:` line in the
|
|
310
313
|
external `proposal.md` itself is never read.
|
|
311
314
|
|
|
312
315
|
A subject with no brief to answer (no adopted change, or a newest change
|
|
@@ -482,8 +485,14 @@ them: `faithful` when every case passed, `divergent` when one failed,
|
|
|
482
485
|
claims the same verdict for every record instead. A case whose id is not
|
|
483
486
|
indexed is named and skipped (`skipped <id> — not an indexed scenario`);
|
|
484
487
|
a report no indexed scenario owns is refused (exit 2). The records share
|
|
485
|
-
the stored report and
|
|
486
|
-
|
|
488
|
+
the stored report, and the output lists each scenario with its verdict on
|
|
489
|
+
its own line. Each record binds the attachments its own cases name in the
|
|
490
|
+
report (a JUnit test case's `[[ATTACHMENT|path]]` lines, which Playwright's
|
|
491
|
+
JUnit reporter writes; a Cucumber JSON embedding), so a test's screenshot
|
|
492
|
+
stays with its scenario. A file the report does not name goes with
|
|
493
|
+
`--artifact <scenario-id>=<path>`; a bare `--artifact <path>` in a batch is
|
|
494
|
+
refused (`EVIDENCE_INVALID_ARGUMENT`). A report attachment that is missing,
|
|
495
|
+
outside the repo or oversized is refused.
|
|
487
496
|
|
|
488
497
|
It is all or nothing: a claimed `faithful` verdict over a failed case,
|
|
489
498
|
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
|
```
|
|
@@ -70,11 +70,17 @@ work collapsed into one identity.
|
|
|
70
70
|
canon finding add --change-id <c> --round <n> --seq <n> \
|
|
71
71
|
--severity blocker|should-fix|note --disposition open \
|
|
72
72
|
--reviewer <who> --summary "<one line>" \
|
|
73
|
-
[--reviewed-sha <sha>] [--file-ref path/to/file.rs:120-134] [--actor-id <id>] [--session-id <id>]
|
|
73
|
+
[--reviewed-sha <sha>] [--file-ref path/to/file.rs:120-134] [--scenario-id <id> …] [--actor-id <id>] [--session-id <id>]
|
|
74
74
|
canon finding close --change-id <c> --round <n> --seq <n> \
|
|
75
75
|
--disposition fixed --resolution-sha <sha> [--session-id <id>] # or rejected / deferred / open
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
`--scenario-id` (repeatable, each a scenario the index knows; refused with
|
|
79
|
+
`FINDING_UNKNOWN_SCENARIO` otherwise) names the scenarios the finding is
|
|
80
|
+
about. After a `fixed` close, fresh evidence for those scenarios alone
|
|
81
|
+
re-verifies the fix; a finding naming none asks every evidenced scenario of
|
|
82
|
+
the subject, as before. `finding close` copies the list.
|
|
83
|
+
|
|
78
84
|
Both stage a candidate. Under `write: { promote: auto }` (what
|
|
79
85
|
`canon init` writes) the same run promotes it and the success line names
|
|
80
86
|
the committed record (``wrote kind=finding/… — staged and promoted in this
|
|
@@ -142,7 +148,7 @@ canon review add --project-id <root-id> --scenario-id <id> [--scenario-id <id>].
|
|
|
142
148
|
[--outcome signed|indeterminate|unavailable] \
|
|
143
149
|
[--reviewer-provider <p>] [--reviewer-model <m>] [--reviewer-harness <h>] \
|
|
144
150
|
[--artifact <path>]... [--max-artifact-mib <MiB>]
|
|
145
|
-
canon review add --project-id <root> --change <slug> --reviewer <who> --pin <sha-or-ref> \
|
|
151
|
+
canon review add --project-id <root> --change-id <slug> --reviewer <who> --pin <sha-or-ref> \
|
|
146
152
|
--role reviewer (--upstream-ref <ref> | --original-spec-ref <ref>) … # a chore, below
|
|
147
153
|
```
|
|
148
154
|
|
|
@@ -169,18 +175,18 @@ that is not a scenario id, refuses the call (exit 2) and writes no review.
|
|
|
169
175
|
This is also the batch re-pin after `canon evidence add` reports reviews
|
|
170
176
|
it made stale (see `canon-gate`).
|
|
171
177
|
|
|
172
|
-
### A chore is reviewed as a change (`--change`, 0.23)
|
|
178
|
+
### A chore is reviewed as a change (`--change-id`, 0.23)
|
|
173
179
|
|
|
174
180
|
A chore adds no scenarios, and recording the suite again after it leaves
|
|
175
181
|
every scenario review current (a review pins the evidence's verdict and
|
|
176
182
|
checks, so the same verdicts from the same cases change nothing). What the
|
|
177
183
|
chore needs instead is one change-level review: the reviewer signs its
|
|
178
|
-
invariants and checks against the diff with `canon review add --change
|
|
184
|
+
invariants and checks against the diff with `canon review add --change-id
|
|
179
185
|
<slug> …`, in place of `--scenario-id`. The review pins the chore's brief
|
|
180
186
|
(its digest, less the `Approved:` line), so an edit to the brief stales it,
|
|
181
187
|
and `--to shipped` refuses a chore with no signed, current change-level
|
|
182
188
|
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
|
|
189
|
+
and session that did not attest the subject's evidence). `--change-id` takes a
|
|
184
190
|
chore's slug and refuses a feature change.
|
|
185
191
|
|
|
186
192
|
### 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
|
|
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,
|
|
69
|
-
|
|
70
|
-
(
|
|
71
|
-
|
|
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
|
-
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
|
|
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>" --scenario-id <id> --scenario-id <id> --as reviewer --json # one --scenario-id per scenario the defect is about
|
|
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
|
|
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>`;
|
|
@@ -97,14 +97,18 @@ ship guard and stays listed as `accepted-divergence` in `status` and
|
|
|
97
97
|
- Sign off in one batch with `review add`, all or nothing. It writes
|
|
98
98
|
directly; nothing to promote. canon stores and re-checks attached bytes
|
|
99
99
|
and never compares images.
|
|
100
|
-
-
|
|
101
|
-
|
|
100
|
+
- Pass `--scenario-id` for each scenario a finding is about. A blocker you
|
|
101
|
+
close `fixed` then stays blocking until the implementer records evidence
|
|
102
|
+
again for those scenarios alone (`evidence add --scenario-id <id> …`); the
|
|
103
|
+
close inherits the list. A blocker naming no scenario asks for the whole
|
|
104
|
+
suite again (`evidence add --all-scenarios`), which on a big suite is
|
|
105
|
+
a long e2e run for a one-scenario fix, so name them. Your pinned review
|
|
102
106
|
stays current when the new evidence says the same, otherwise look again.
|
|
103
107
|
- Fixes you ask for return as a re-review of the same change. When new
|
|
104
108
|
evidence changes a verdict or the checks and so stales your review, look
|
|
105
109
|
again before you re-pin.
|
|
106
110
|
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
|
|
111
|
+
review add --project-id <root-id> --change-id <slug> --reviewer <me> --role
|
|
108
112
|
reviewer --pin <sha> --upstream-ref <ref> …`. It signs the chore's
|
|
109
113
|
invariants and checks against the diff and pins its brief, so editing the
|
|
110
114
|
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.
|
|
3
|
+
"version": "0.24.1",
|
|
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.
|
|
34
|
-
"@journeykit/canon-core-linux-x64": "0.
|
|
35
|
-
"@journeykit/canon-core-win32-x64": "0.
|
|
33
|
+
"@journeykit/canon-core-darwin-arm64": "0.24.1",
|
|
34
|
+
"@journeykit/canon-core-linux-x64": "0.24.1",
|
|
35
|
+
"@journeykit/canon-core-win32-x64": "0.24.1"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^20.0.0",
|