@journeykit/canon 0.21.0 → 0.22.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.
- package/dist/skills/SKILL.src.md +11 -6
- package/dist/skills/reference/canon-authoring.md +3 -0
- package/dist/skills/reference/canon-gate.md +38 -8
- package/dist/skills/reference/canon-inventory.md +2 -2
- package/dist/skills/reference/canon-policy.md +33 -11
- package/dist/skills/reference/canon-review.md +2 -1
- package/dist/skills/reference/canon-subject.md +27 -8
- package/dist/skills/reference/role-implementer.md +17 -4
- package/dist/skills/reference/role-orchestrator.md +16 -5
- package/dist/skills/reference/role-planner.md +9 -2
- package/dist/skills/reference/role-reviewer.md +25 -0
- package/package.json +4 -4
package/dist/skills/SKILL.src.md
CHANGED
|
@@ -25,7 +25,9 @@ a feature, a one-line request included. A human is needed once per scope:
|
|
|
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
27
|
`canon brief approve --change <slug> --by <the human> --note "<their words>"`.
|
|
28
|
-
Never edit the policy to make the gate pass
|
|
28
|
+
Never edit the policy to make the gate pass: a policy that differs from
|
|
29
|
+
the approved one fails closed (`POLICY_CHANGED_SINCE_APPROVAL`, not
|
|
30
|
+
waivable); stop and ask the human. A brief edited after its
|
|
29
31
|
approval is not approved (`BRIEF_CHANGED_SINCE_APPROVAL`): it needs a new
|
|
30
32
|
answer. The ship guard and `canon evidence add` refuse an unapproved or
|
|
31
33
|
edited brief, but those are backstops: the stop itself is at step 1.
|
|
@@ -35,7 +37,9 @@ a feature, a one-line request included. A human is needed once per scope:
|
|
|
35
37
|
implement, evidence, independent review. A follow-up that adds or changes
|
|
36
38
|
a step of the brief edits the brief: that is a scope change and needs a
|
|
37
39
|
new answer. A follow-up on a shipped subject reopens it
|
|
38
|
-
(`canon subject status <id> --to verifying --reason "<why>"`)
|
|
40
|
+
(`canon subject status <id> --to verifying --reason "<why>"`); a fix
|
|
41
|
+
closed `fixed`, and an approved chore, then need the whole suite evidenced
|
|
42
|
+
again (`evidence add --all-scenarios`) and re-reviewed before it ships.
|
|
39
43
|
- When no human can answer one of the brief's questions, write your
|
|
40
44
|
assumption into the brief's Questions and assumptions, build on it, and say
|
|
41
45
|
so in your report. That covers the brief's questions and work inside an
|
|
@@ -87,10 +91,11 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
87
91
|
- Pass `--json` and read stdout as one document. On failure it is
|
|
88
92
|
`{"error":{"code","message","hint","retryable","field","expected"}}`: branch
|
|
89
93
|
on `error.code`, fix the option `field` names using the `expected` values,
|
|
90
|
-
and follow `error.hint`.
|
|
91
|
-
lists them.
|
|
92
|
-
-
|
|
93
|
-
|
|
94
|
+
and follow `error.hint`. Every refusal carries a concrete `hint`: follow
|
|
95
|
+
it. The codes are stable; `canon schema --errors --json` lists them.
|
|
96
|
+
- `canon status` sends the planner to write the brief while `brief check`
|
|
97
|
+
has blockers; the human stop appears only when the brief is clean and
|
|
98
|
+
unapproved.
|
|
94
99
|
- Page long lists with `--limit <n>` and `--cursor <nextCursor>` (`--all`
|
|
95
100
|
for everything), and project fields with `--fields a,b` (`status`, `export`,
|
|
96
101
|
`query`, `finding list`, `divergence status`, `context`).
|
|
@@ -110,6 +110,9 @@ Fix it and the next command indexes the files (see `canon-inventory`).
|
|
|
110
110
|
|
|
111
111
|
- `--actor <id>` (or `CANON_ACTOR` in the environment) puts YOUR id on the
|
|
112
112
|
provenance line. Default is `canon-scaffold`.
|
|
113
|
+
- **Keep the `# canon:` lines when you fill in the scenario.** Dropping one
|
|
114
|
+
makes `canon inventory sync` abort on `missing-provenance`; restore it
|
|
115
|
+
from git history or a sibling scenario (the error shows its shape).
|
|
113
116
|
- **Never hand-type, move, or edit a `# canon:` line.** The scaffold
|
|
114
117
|
writes it directly above the scenario's tags:
|
|
115
118
|
|
|
@@ -21,15 +21,15 @@ Every violation carries one of these stable, grep-able strings:
|
|
|
21
21
|
|
|
22
22
|
| Class | Meaning |
|
|
23
23
|
|---|---|
|
|
24
|
-
| `uncovered-cell` | Either a policy-required evidence cell (role × artifact) with no matching record, or — with `spec_coverage` enabled — a spec scenario that is unimplemented or mismatched, or a feature surface missing a `require_cases` case. The detail string distinguishes them. Coverage means "a test exists", not "a test passed": even a `Divergent` verdict satisfies the role-cell form. |
|
|
25
|
-
| `unreviewed-promotion` | An artifact tagged `reviewed` has no matching ledger review record — or, with `spec_coverage.require_review` set, an in-scope scenario has no qualifying `Review`: none at all, only self-reviews, only stale reviews (the spec or evidence it pinned changed since), or only `indeterminate`/`unavailable` ones. See `canon-review`. |
|
|
24
|
+
| `uncovered-cell` | Either a policy-required evidence cell (role × artifact) with no matching record, or — with `spec_coverage` enabled — a spec scenario that is unimplemented or mismatched, or a feature surface missing a `require_cases` case. The detail string distinguishes them. Coverage means "a test exists", not "a test passed": even a `Divergent` verdict satisfies the role-cell form. At `verifying → shipped`, a `Divergent` latest verdict is `uncovered-cell` unless a reviewer accepted it (see Accepted divergence below), and a chore's approval, like a blocker closed `fixed`, needs every evidenced scenario evidenced again afterwards (see Re-verification below). |
|
|
25
|
+
| `unreviewed-promotion` | An artifact tagged `reviewed` has no matching ledger review record — or, with `spec_coverage.require_review` set, an in-scope scenario has no qualifying `Review`: none at all, only self-reviews, only stale reviews (the spec or evidence it pinned changed since), or only `indeterminate`/`unavailable` ones. Also, subject `policy`: the policy changed since its approval or its approval is unreadable (fails closed; see `canon-policy`). See `canon-review`. |
|
|
26
26
|
| `trust-below-required` | Achieved trust level is below `policy.yaml`'s `trust_required` for its class — RELEASE-scoped only (`canon gate check --release`); never fires on an ordinary run. |
|
|
27
27
|
| `stale-evidence` | A passing record degraded to stale: its declared surface changed since its `evidence_sha`, or HEAD moved past `staleness.max_commits_behind`. Only degrades an already-green record. Also: a file bound to a latest evidence record whose bytes are gone — no intact blob in `.canon/artifacts/sha256/` and no working-tree copy with the recorded digest — or a file bound to an in-effect review with no intact blob (see Bound evidence stays provable below). |
|
|
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 gate task <task_id>` was asked to flip a checkbox with no matching, non-`Divergent` evidence record. |
|
|
31
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 (`canon evidence add: refused — fabricated-evidence …`, exit 1). |
|
|
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. Subject string `<change_id>#<round>.<seq>`. See `canon-review`. |
|
|
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 add --kind 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
|
|
|
35
35
|
## `canon gate check [--repo <dir>] [--release]`
|
|
@@ -51,11 +51,12 @@ Exit `0` clean, `1` gate-red (any violation), `2` usage/load failure
|
|
|
51
51
|
resolves through the nearest-ancestor `canon.yaml` walk, so it reads the
|
|
52
52
|
repo ROOT's `.canon/policy.yaml` and `.canon/ledger` from any subdirectory.
|
|
53
53
|
|
|
54
|
-
When `.canon/policy.yaml` exists but has no approval,
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
When `.canon/policy.yaml` exists but has no approval, the gate prints
|
|
55
|
+
`advisory: policy not approved: …` after its result, naming
|
|
56
|
+
`canon policy approve --by <who>`; the exit code is unchanged. When its
|
|
57
|
+
bytes no longer match the approved digest, or the approval cannot be read,
|
|
58
|
+
the gate fails closed: the violation is reported and the exit is `1` (see
|
|
59
|
+
`canon-policy`).
|
|
59
60
|
|
|
60
61
|
Before it reads the scenario index, the gate rebuilds any stale part of
|
|
61
62
|
it from the changed `.feature` files (the same code `canon inventory
|
|
@@ -200,6 +201,35 @@ Malformed rows in those three kinds do NOT surface as
|
|
|
200
201
|
`malformed-evidence`; they are kept off the evidence violation set on
|
|
201
202
|
purpose, so enabling nothing changes no existing verdict.
|
|
202
203
|
|
|
204
|
+
### Accepted divergence and re-verification
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
canon divergence accept --project-id <root-id> --scenario-id <id> --reason "<why>" --tracking <issue-url-or-ref> [--expiry YYYY-MM-DD] --reviewer <me> --actor-id <me> --session-id <session> --as reviewer
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
A reviewer accepts a scenario whose latest evidence is `divergent` as a
|
|
211
|
+
known gap limited by something outside the change; never to skip a fix.
|
|
212
|
+
Refused (`DIVERGENCE_ACCEPT_REFUSED`) unless the latest verdict is
|
|
213
|
+
divergent and the session and actor differ from the evidence's. The record
|
|
214
|
+
pins that evidence: new evidence for the scenario, or `--expiry` passing,
|
|
215
|
+
ends it. While it holds, the ship guard counts the cell covered and
|
|
216
|
+
`status` and `gate check` keep listing it, never silently:
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
accepted divergences: 1 known gap(s) — not failing the gate:
|
|
220
|
+
accepted-divergence demo.page.02 — https://example.test/issues/1 (no expiry)
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Re-verification is one rule with two triggers: a blocker whose latest
|
|
224
|
+
disposition is `fixed`, and a chore change once approved, keep the subject
|
|
225
|
+
from shipping until every one of its evidenced scenarios has evidence
|
|
226
|
+
recorded after the close or the approval. The refusal names the scenarios
|
|
227
|
+
and the batch command: `canon evidence add --project-id <root-id>
|
|
228
|
+
--all-scenarios --report <format>:<path> --kind test-run --role
|
|
229
|
+
implementer --ref "<test command>" …`. That evidence stales the pinned
|
|
230
|
+
reviews, so a re-review follows (and a new `divergence accept`, where the
|
|
231
|
+
gap remains).
|
|
232
|
+
|
|
203
233
|
### Audit records (`--kind audit`)
|
|
204
234
|
|
|
205
235
|
canon never generates or runs an audit. An external evaluator does, and
|
|
@@ -72,7 +72,7 @@ scenario index # refreshed by every reader; `canon inventory sy
|
|
|
72
72
|
│
|
|
73
73
|
▼
|
|
74
74
|
canon review add # attests a review — see canon-inventory downstream / canon-gate
|
|
75
|
-
canon divergence {add,promote,resolve,defer,status} # tracks/resolves a divergence
|
|
75
|
+
canon divergence {add,promote,resolve,defer,accept,status} # tracks/resolves a divergence
|
|
76
76
|
canon gate check [--release] # trust-ladder / staleness / coverage — see canon-gate
|
|
77
77
|
│
|
|
78
78
|
▼
|
|
@@ -158,7 +158,7 @@ specs:
|
|
|
158
158
|
|
|
159
159
|
- **Review** — `canon review add` attests a verdict against a synced
|
|
160
160
|
scenario. (See `canon-inventory` downstream commands and each command's `--help`.)
|
|
161
|
-
- **Divergence** — `canon divergence {add,promote,resolve,defer,status}`
|
|
161
|
+
- **Divergence** — `canon divergence {add,promote,resolve,defer,accept,status}`
|
|
162
162
|
tracks/resolves divergences against synced scenarios.
|
|
163
163
|
- **Gate** — `canon gate check` enforces trust-ladder / staleness /
|
|
164
164
|
coverage over the corpus (see `canon-gate`).
|
|
@@ -101,21 +101,43 @@ its result:
|
|
|
101
101
|
advisory: policy not approved: .canon/policy.yaml has no approval record (.canon/policy.approval.json); a human reviews it and runs `canon policy approve --by <who>`
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
Once the policy's bytes no longer match the approved digest,
|
|
105
|
-
|
|
104
|
+
Once the policy's bytes no longer match the approved digest, or the
|
|
105
|
+
approval file cannot be read, the gate fails closed instead:
|
|
106
106
|
|
|
107
107
|
```
|
|
108
|
-
|
|
108
|
+
unreviewed-promotion policy — policy changed since approval: .canon/policy.yaml is sha256:<now>, but `<who>` approved sha256:<then> at <time>; … (--override-reason does not waive it); the human re-approves the policy in force with `canon policy approve --by <human> --note "<words>"`, or restore the approved .canon/policy.yaml (and .canon/policy.approval.json) from git
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
`
|
|
114
|
-
`--
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
`canon gate check` exits `1`; `canon subject status` (the ship guard and
|
|
112
|
+
the reopen) refuses with `POLICY_CHANGED_SINCE_APPROVAL`, or
|
|
113
|
+
`POLICY_APPROVAL_UNREADABLE` for an unreadable approval, and
|
|
114
|
+
`--override-reason` does not waive either. A policy never approved stays
|
|
115
|
+
an advisory. `canon status` prints the same text as a `warning:` line (and
|
|
116
|
+
in `--json` `warnings`). canon cannot tell whether a human or an agent
|
|
117
|
+
ran `policy approve`, so the record names who approved which bytes and
|
|
118
|
+
the gate fails when that no longer holds. An agent never edits the policy
|
|
119
|
+
to pass the gate: it stops and asks the human, who re-approves or restores
|
|
120
|
+
it. An agent runs `canon policy approve` only to record a human's answer,
|
|
121
|
+
never without one and never on its own behalf.
|
|
122
|
+
|
|
123
|
+
## `canon policy show [--json]`
|
|
124
|
+
|
|
125
|
+
Prints the policy path and current digest, and the approval state
|
|
126
|
+
(`approved`, `changed`, `unreadable` or `unapproved`) with the approver,
|
|
127
|
+
time and approved digest:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
policy: .canon/policy.yaml
|
|
131
|
+
digest: sha256:37ea…
|
|
132
|
+
approval: approved
|
|
133
|
+
approved by: Ann
|
|
134
|
+
approved at: 2026-10-17T04:57:45Z
|
|
135
|
+
approved digest: sha256:37ea…
|
|
136
|
+
note: ok
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
For `changed` and `unreadable` it adds `gate: fails closed (…)` with the
|
|
140
|
+
human's way out. Read-only; it writes nothing.
|
|
119
141
|
|
|
120
142
|
## The closed CEL profile
|
|
121
143
|
|
|
@@ -150,7 +150,8 @@ may carry the same scenario id. Exactly one provenance ref is required.
|
|
|
150
150
|
`--actor-id` defaults to `canon`; `--session-id` fills `actor.session_id`.
|
|
151
151
|
A Review carries no verdict about the behavior; the `verifying → shipped`
|
|
152
152
|
ship gate still refuses missing or `Divergent` evidence verdicts on its
|
|
153
|
-
own
|
|
153
|
+
own (a `Divergent` one passes only while a reviewer's `canon divergence
|
|
154
|
+
accept` holds). It is written directly to the ledger, with no staging step, and says
|
|
154
155
|
so: `canon review add: wrote <path> (new) — written directly; nothing to
|
|
155
156
|
promote`.
|
|
156
157
|
|
|
@@ -146,7 +146,14 @@ owns must also carry a scenario of each required `@case:` (e.g. one
|
|
|
146
146
|
`@case:failure`) — attested golden-path scenarios alone do not ship. A
|
|
147
147
|
Subject with no tagged scenario is refused rather than shipped on an
|
|
148
148
|
empty set; so is one whose `scenario` records route away from the
|
|
149
|
-
gate's rung.
|
|
149
|
+
gate's rung. A `Divergent` latest verdict is refused as `uncovered-cell`
|
|
150
|
+
unless a reviewer accepted it (`canon divergence accept`, see
|
|
151
|
+
`canon-gate`): the hint names both ways out. Re-verification: a blocker
|
|
152
|
+
closed `fixed` keeps blocking, and a chore's approval keeps the subject
|
|
153
|
+
from shipping, until every evidenced scenario has evidence recorded after
|
|
154
|
+
the close or the approval; the refusal names the scenarios and the
|
|
155
|
+
`canon evidence add --all-scenarios …` command. Each refusal prints by
|
|
156
|
+
failure class (`uncovered-cell`), carries a `hint`,
|
|
150
157
|
exits 1, and the status stays `verifying`. `retired` is not gated.
|
|
151
158
|
|
|
152
159
|
**The brief (0.16, 0.17, 0.19):** `verifying → shipped` also refuses where a brief
|
|
@@ -265,11 +272,13 @@ canon subject status: reopened `demo-subject` from shipped, recorded by `impl`:
|
|
|
265
272
|
canon subject status: demo-subject → verifying — written directly; nothing to promote
|
|
266
273
|
```
|
|
267
274
|
|
|
268
|
-
- `--reason "<one line>"` is required for `shipped → verifying`
|
|
269
|
-
|
|
270
|
-
record carries it with the actor
|
|
275
|
+
- `--reason "<one line>"` is required for `shipped → verifying` (exit 2
|
|
276
|
+
without it, as for a blank one) and optional on every other transition,
|
|
277
|
+
where it is an audit note. The new record carries it with the actor as
|
|
278
|
+
`status_reason: { reason: …, actor: { agent_id: impl } }`; a reopen also
|
|
279
|
+
records the change the work goes into:
|
|
271
280
|
`reopen: { reason: …, change: c-demo, actor: { agent_id: impl } }`. The
|
|
272
|
-
next status write clears
|
|
281
|
+
next status write clears both, as it clears a waiver.
|
|
273
282
|
- Inside the approved scope it needs no human: the subject's newest
|
|
274
283
|
adopted change's brief is approved, or there is no brief to answer.
|
|
275
284
|
Otherwise it refuses, exit 1, naming the brief to approve, and
|
|
@@ -278,6 +287,12 @@ canon subject status: demo-subject → verifying — written directly; nothing t
|
|
|
278
287
|
- The review guard does not run on a reopen (it prints `skipped … — a
|
|
279
288
|
reopen moves the subject back to fix its gaps; shipping again runs
|
|
280
289
|
it`). `verifying → shipped` afterwards runs every guard above again.
|
|
290
|
+
- A policy that fails closed (`POLICY_CHANGED_SINCE_APPROVAL`,
|
|
291
|
+
`POLICY_APPROVAL_UNREADABLE`: see `canon-policy`) refuses the reopen and
|
|
292
|
+
the ship, and `--override-reason` does not waive it.
|
|
293
|
+
- `canon change new` on a shipped subject prints the reopen command
|
|
294
|
+
(`canon subject status <id> --to verifying --reason "<why it reopens>"`)
|
|
295
|
+
in its output and `meta.next`.
|
|
281
296
|
- `canon status` flags a shipped subject whose gate went red (whatever
|
|
282
297
|
`verifying → shipped` would now refuse it on) and its only step is
|
|
283
298
|
this reopen.
|
|
@@ -561,10 +576,14 @@ uses, so status and the gate cannot disagree about a gap:
|
|
|
561
576
|
than one `specs.roots[]` entry, every suggested `canon scenario new`
|
|
562
577
|
carries `--project`: the owning root for a missing case, `<root-id>`
|
|
563
578
|
(the reason lists the roots) for a subject that owns no scenario yet.
|
|
564
|
-
- **The one human step.** Every step is the agent's to run except one
|
|
565
|
-
|
|
579
|
+
- **The one human step.** Every step is the agent's to run except one,
|
|
580
|
+
and it comes only once the brief is clean: while `canon brief check
|
|
581
|
+
--change <slug>` has blockers, the subject gets the planner step
|
|
582
|
+
`write the brief: canon brief check --change <slug> lists N blockers`
|
|
583
|
+
(`role: planner`) instead. A subject whose brief is enforced (its
|
|
584
|
+
newest change's canon
|
|
566
585
|
`brief.md` has no `Approved:` line, or it has no canon `brief.md` yet
|
|
567
|
-
and comes from an external openspec `proposal.md`) gets
|
|
586
|
+
and comes from an external openspec `proposal.md`) and clean gets
|
|
568
587
|
`human: stop and report the brief in <brief>; build and attest nothing for <id> until the human answers (one answer approves brief and policy)`,
|
|
569
588
|
where `<brief>` is the canon `brief.md`, or the external `proposal.md`
|
|
570
589
|
when no canon brief exists yet. Its reason reads ``<id>: <why
|
|
@@ -18,6 +18,7 @@ canon scenario new <area>.<surface>.<nn> --subject <subject-id> --flow <F-id> --
|
|
|
18
18
|
canon scenario new --from - --as implementer --json # many at once: NDJSON on stdin, one {"id","title","subject","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
|
+
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
|
|
21
22
|
canon finding add --change-id <slug> --round <n> --seq <n> --severity <blocker|should-fix|note> --reviewer <unit> --actor-id <unit> --session-id <session> --summary "<defect>" --as implementer --json
|
|
22
23
|
canon inventory sync --as implementer --json # only after a write printed NOT refreshed
|
|
23
24
|
canon gate promote --as implementer --json # only with write.promote: manual
|
|
@@ -39,7 +40,8 @@ After the first `status`, follow `meta.next` of each write; do not call
|
|
|
39
40
|
violation or a duplicate id: it names each problem). Specs live at
|
|
40
41
|
`<root>/kind=feature/area=<area>/<surface>.feature` under a `specs.roots[]`
|
|
41
42
|
root (default `.canon/specs`); `reference/canon-authoring.md` has the
|
|
42
|
-
scaffold.
|
|
43
|
+
scaffold. When you fill in a scenario, keep its `# canon: {...}` provenance
|
|
44
|
+
lines: dropping one aborts `inventory sync` on `missing-provenance`.
|
|
43
45
|
2. **Units.** Give each unit its own actor id and session id and pass them on
|
|
44
46
|
everything it records. A delegated unit attests its own work; never attest
|
|
45
47
|
another unit's work under your id.
|
|
@@ -56,7 +58,11 @@ After the first `status`, follow `meta.next` of each write; do not call
|
|
|
56
58
|
or recording (`--artifact <path>`). An external evaluator's audit is
|
|
57
59
|
`--kind audit`; canon never generates one. Evidence for a task of an
|
|
58
60
|
imported plan (`--task <id>`) must bind the artifact or report that proves
|
|
59
|
-
the task; a canon command is never that proof.
|
|
61
|
+
the task; a canon command is never that proof. When the behavior cannot
|
|
62
|
+
match the scenario because of something outside this change, record the
|
|
63
|
+
evidence `divergent` and say why in `--ref`; never record `faithful` to
|
|
64
|
+
pass. A reviewer may accept the tracked gap (`canon divergence accept`);
|
|
65
|
+
fixing the behavior and recording again is the other way out.
|
|
60
66
|
5. **Promote.** Under `write: { promote: auto }` (what `canon init` writes)
|
|
61
67
|
the record is final when `evidence add` returns. Only with
|
|
62
68
|
`write.promote: manual` (or no `write:` key) follow it with
|
|
@@ -64,6 +70,13 @@ After the first `status`, follow `meta.next` of each write; do not call
|
|
|
64
70
|
6. **A new record makes a signed review stale.** The add prints the reviewer
|
|
65
71
|
and the `canon review add … --pin <sha>` that re-pins it; that is the
|
|
66
72
|
reviewer's call. Do not run it yourself.
|
|
73
|
+
7. **After a fix or a chore, record the whole suite again.** A blocker the
|
|
74
|
+
reviewer closed `fixed`, and an approved chore, are not done until every
|
|
75
|
+
evidenced scenario has evidence newer than the close or the approval:
|
|
76
|
+
run the suite and bind it with `canon evidence add --all-scenarios …`
|
|
77
|
+
(the shipping refusal names the scenarios and this command). The
|
|
78
|
+
re-review follows; a scenario whose gap was accepted is accepted again
|
|
79
|
+
by the reviewer once new evidence supersedes the old.
|
|
67
80
|
|
|
68
81
|
## Retry safety
|
|
69
82
|
|
|
@@ -76,5 +89,5 @@ response, run it again.
|
|
|
76
89
|
When every scenario has evidence, the review is the reviewer's session, in a
|
|
77
90
|
separate process: do not review your own change. A chore adds no scenarios:
|
|
78
91
|
run the suite again and bind it with `--all-scenarios`, which supersedes the
|
|
79
|
-
old evidence and makes pinned reviews stale
|
|
80
|
-
`reference/canon-gate.md`.
|
|
92
|
+
old evidence and makes pinned reviews stale; shipping needs that evidence
|
|
93
|
+
newer than the chore's approval. Reference: `reference/canon-gate.md`.
|
|
@@ -12,7 +12,8 @@ Every line is complete; fill the `<placeholders>`.
|
|
|
12
12
|
canon status --as orchestrator --json --fields next,waitingOn # at the start and when resuming
|
|
13
13
|
canon brief approve --change <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
|
-
canon subject status <subject-id> --to verifying --reason "<why>" --actor-id <unit> --as orchestrator --json #
|
|
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
|
+
canon policy show --as orchestrator --json # policy digest and its approval: approved, changed, unreadable or unapproved
|
|
16
17
|
canon gate check --as orchestrator --json
|
|
17
18
|
```
|
|
18
19
|
|
|
@@ -57,9 +58,14 @@ When `status` or `meta.next` shows a step with `actor: human` (the brief's
|
|
|
57
58
|
approval), stop everything for that scope, report the brief to the human in
|
|
58
59
|
its language, and wait. Do not start the implementer before the answer.
|
|
59
60
|
Record the answer with `brief approve`. Never approve it yourself and never
|
|
60
|
-
edit the policy to pass the gate.
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
edit the policy to pass the gate. A policy that no longer matches the
|
|
62
|
+
approval fails closed (`POLICY_CHANGED_SINCE_APPROVAL`, or
|
|
63
|
+
`POLICY_APPROVAL_UNREADABLE`): the ship guard and the reopen refuse, and
|
|
64
|
+
`--override-reason` does not waive it. Run `canon policy show`, then stop and
|
|
65
|
+
ask the human to re-approve (`canon policy approve --by <human>`) or restore
|
|
66
|
+
the approved policy from git; never edit the policy yourself. Inside an
|
|
67
|
+
approved scope never stop for a human: fixes, follow-ups and re-reviews go
|
|
68
|
+
straight to the implementer and reviewer in the same change.
|
|
63
69
|
|
|
64
70
|
## Move the subject
|
|
65
71
|
|
|
@@ -69,7 +75,12 @@ evidence or reviews, open blockers, an unapproved brief); fix the gap rather
|
|
|
69
75
|
than overriding. Move to `shipped` yourself once its guard passes, unless the
|
|
70
76
|
brief says the human ships. A follow-up on a shipped subject goes back to
|
|
71
77
|
`verifying` with `--reason`, then the implementer and reviewer in the same
|
|
72
|
-
change, then `--to shipped` again.
|
|
78
|
+
change, then `--to shipped` again. A chore on a shipped subject (`change
|
|
79
|
+
new … --kind chore` names the reopen command) is approved first, then
|
|
80
|
+
reopened the same way; shipping again needs the whole suite evidenced after
|
|
81
|
+
the chore's approval (`evidence add --all-scenarios`) and a re-review. A
|
|
82
|
+
blocker closed `fixed` needs the same. The refusal names the scenarios and
|
|
83
|
+
the command; never override them. `canon status` flags a shipped subject
|
|
73
84
|
whose gate went red. A bad `--to` fails with `error.field` `--to` and
|
|
74
85
|
`error.expected` listing the states.
|
|
75
86
|
|
|
@@ -21,7 +21,11 @@ canon brief approve --change <slug> --by "<the human>" --note "<their words>" --
|
|
|
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
|
-
steps.
|
|
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>
|
|
26
|
+
lists N blockers`); the human step appears only once the brief is clean and
|
|
27
|
+
unapproved. A policy that no longer matches its approval fails closed
|
|
28
|
+
(`POLICY_CHANGED_SINCE_APPROVAL`): never edit it; the human re-approves.
|
|
25
29
|
|
|
26
30
|
## Steps
|
|
27
31
|
|
|
@@ -75,7 +79,10 @@ can observe: `change new … --kind chore`. Its brief is short (intent,
|
|
|
75
79
|
category, invariants, checks, out of scope) and approved like any brief, one
|
|
76
80
|
human stop. A chore adds no scenarios: the
|
|
77
81
|
implementer runs the subject's suite again and binds it with
|
|
78
|
-
`canon evidence add --all-scenarios …`, then a re-review follows.
|
|
82
|
+
`canon evidence add --all-scenarios …`, then a re-review follows. On a
|
|
83
|
+
shipped subject `change new` prints the reopen command for the orchestrator
|
|
84
|
+
(`subject status <id> --to verifying --reason "<why>"`); the subject cannot
|
|
85
|
+
ship again until the suite is evidenced after the chore's approval. Work that
|
|
79
86
|
changes behavior is never a chore: it is a feature change.
|
|
80
87
|
|
|
81
88
|
## Hand-off
|
|
@@ -17,6 +17,7 @@ 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 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
|
|
20
21
|
```
|
|
21
22
|
|
|
22
23
|
`review add` needs `--upstream-ref <ref>` or `--original-spec-ref <path>`;
|
|
@@ -56,6 +57,27 @@ what you could not run: a reviewer that cannot run the tests says so and
|
|
|
56
57
|
does not sign off; record that instead (`--outcome indeterminate`, or
|
|
57
58
|
`unavailable` when you could not run).
|
|
58
59
|
|
|
60
|
+
## Check the checks
|
|
61
|
+
|
|
62
|
+
Passing is not enough: read each bound test against its scenario's Then
|
|
63
|
+
steps. Record a finding (`finding add`) when a check pins behavior the
|
|
64
|
+
scenario does not require, or skips a Then step the scenario states: such a
|
|
65
|
+
test passes without proving the scenario. Do this before you sign.
|
|
66
|
+
|
|
67
|
+
## Accept a known gap
|
|
68
|
+
|
|
69
|
+
`divergence accept` is for a scenario whose honest evidence is `divergent`
|
|
70
|
+
and whose gap is limited by something outside this change (an upstream
|
|
71
|
+
limit, a platform bug) and is tracked there: give the reason and the
|
|
72
|
+
`--tracking` reference, and an `--expiry` when the limit should be gone by
|
|
73
|
+
a date. Never use it to skip a fix you can make in this change. It is your
|
|
74
|
+
step, from a session that did not attest the evidence
|
|
75
|
+
(`DIVERGENCE_ACCEPT_REFUSED` otherwise). The acceptance pins that evidence:
|
|
76
|
+
new evidence for the scenario, or its expiry, ends it, and you accept (or
|
|
77
|
+
the implementer fixes) again. An accepted gap counts as covered for the
|
|
78
|
+
ship guard and stays listed as `accepted-divergence` in `status` and
|
|
79
|
+
`gate check`.
|
|
80
|
+
|
|
59
81
|
## Record
|
|
60
82
|
|
|
61
83
|
- Every defect is a finding; `finding list` shows round, seq, severity and
|
|
@@ -64,6 +86,9 @@ does not sign off; record that instead (`--outcome indeterminate`, or
|
|
|
64
86
|
- Sign off in one batch with `review add`, all or nothing. It writes
|
|
65
87
|
directly; nothing to promote. canon stores and re-checks attached bytes
|
|
66
88
|
and never compares images.
|
|
89
|
+
- A blocker you close `fixed` stays blocking until the implementer records
|
|
90
|
+
the whole suite again (`evidence add --all-scenarios`); re-review after
|
|
91
|
+
it, since new evidence makes your pinned review stale.
|
|
67
92
|
- Fixes you ask for return as a re-review of the same change. When a new
|
|
68
93
|
evidence record makes your review stale, look again before you re-pin.
|
|
69
94
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@journeykit/canon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.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.
|
|
34
|
-
"@journeykit/canon-core-linux-x64": "0.
|
|
35
|
-
"@journeykit/canon-core-win32-x64": "0.
|
|
33
|
+
"@journeykit/canon-core-darwin-arm64": "0.22.0",
|
|
34
|
+
"@journeykit/canon-core-linux-x64": "0.22.0",
|
|
35
|
+
"@journeykit/canon-core-win32-x64": "0.22.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@types/node": "^20.0.0",
|