@journeykit/canon 0.31.0 → 0.33.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/index.js +4 -0
- package/dist/skills/SKILL.src.md +52 -25
- package/dist/skills/reference/brief-align.md +2 -2
- package/dist/skills/reference/brief-clarify.md +2 -2
- package/dist/skills/reference/brief-harden.md +2 -2
- package/dist/skills/reference/brief-polish.md +4 -4
- package/dist/skills/reference/brief-shape.md +2 -2
- package/dist/skills/reference/canon-context.md +1 -1
- package/dist/skills/reference/canon-gate.md +5 -5
- package/dist/skills/reference/canon-policy.md +7 -4
- package/dist/skills/reference/canon-report-dashboard.md +7 -4
- package/dist/skills/reference/canon-review.md +2 -2
- package/dist/skills/reference/canon-storage.md +4 -3
- package/dist/skills/reference/canon-subject.md +18 -16
- package/dist/skills/reference/role-implementer.md +12 -10
- package/dist/skills/reference/role-orchestrator.md +44 -29
- package/dist/skills/reference/role-planner.md +68 -29
- package/dist/skills/reference/role-reviewer.md +24 -16
- package/man/canon-adapter-authorize.1 +2 -2
- package/man/canon-adapter-validate.1 +2 -2
- package/man/canon-adapter.1 +2 -2
- package/man/canon-artifacts-move.1 +3 -3
- package/man/canon-artifacts-store.1 +2 -2
- package/man/canon-artifacts-verify.1 +2 -2
- package/man/canon-artifacts.1 +2 -2
- package/man/canon-brief-approve.1 +12 -3
- package/man/canon-brief-check.1 +2 -2
- package/man/canon-brief-show.1 +6 -3
- package/man/canon-brief.1 +2 -2
- package/man/canon-change-new.1 +2 -2
- package/man/canon-change.1 +2 -2
- package/man/canon-completion.1 +2 -2
- package/man/canon-context-pack-add.1 +2 -2
- package/man/canon-context-pack-show.1 +2 -2
- package/man/canon-context-pack-verify.1 +2 -2
- package/man/canon-context-pack.1 +2 -2
- package/man/canon-context.1 +2 -2
- package/man/canon-dashboard.1 +2 -2
- package/man/canon-demo-init.1 +2 -2
- package/man/canon-demo-review.1 +2 -2
- package/man/canon-demo.1 +2 -2
- package/man/canon-dispatch-begin.1 +2 -2
- package/man/canon-dispatch-diff.1 +2 -2
- package/man/canon-dispatch-end.1 +2 -2
- package/man/canon-dispatch.1 +2 -2
- package/man/canon-divergence-accept.1 +12 -3
- package/man/canon-divergence-add.1 +2 -2
- package/man/canon-divergence-defer.1 +2 -2
- package/man/canon-divergence-list.1 +2 -2
- package/man/canon-divergence-resolve.1 +2 -2
- package/man/canon-divergence.1 +2 -2
- package/man/canon-evidence-add.1 +2 -2
- package/man/canon-evidence-approval-payload.1 +2 -2
- package/man/canon-evidence-audit.1 +2 -2
- package/man/canon-evidence.1 +2 -2
- package/man/canon-export.1 +2 -2
- package/man/canon-feature-new.1 +2 -2
- package/man/canon-feature.1 +2 -2
- package/man/canon-finding-add.1 +2 -2
- package/man/canon-finding-close.1 +2 -2
- package/man/canon-finding-list.1 +2 -2
- package/man/canon-finding.1 +2 -2
- package/man/canon-format.1 +2 -2
- package/man/canon-gate-check.1 +2 -2
- package/man/canon-gate-install-hooks.1 +2 -2
- package/man/canon-gate-promote.1 +2 -2
- package/man/canon-gate.1 +2 -2
- package/man/canon-ingest-plans.1 +2 -2
- package/man/canon-ingest-records.1 +2 -2
- package/man/canon-ingest-sessions.1 +2 -2
- package/man/canon-ingest.1 +2 -2
- package/man/canon-init.1 +2 -2
- package/man/canon-inventory-sync.1 +2 -2
- package/man/canon-inventory.1 +2 -2
- package/man/canon-ledger-compact.1 +2 -2
- package/man/canon-ledger.1 +2 -2
- package/man/canon-migrate.1 +15 -3
- package/man/canon-plugin-sync.1 +2 -2
- package/man/canon-plugin.1 +2 -2
- package/man/canon-policy-approve.1 +9 -3
- package/man/canon-policy-show.1 +2 -2
- package/man/canon-policy.1 +2 -2
- package/man/canon-prompt-add.1 +2 -2
- package/man/canon-prompt-show.1 +2 -2
- package/man/canon-prompt.1 +2 -2
- package/man/canon-purge.1 +2 -2
- package/man/canon-query.1 +2 -2
- package/man/canon-regime-show.1 +2 -2
- package/man/canon-regime.1 +2 -2
- package/man/canon-report-build.1 +2 -2
- package/man/canon-report-check.1 +2 -2
- package/man/canon-report-snapshot.1 +2 -2
- package/man/canon-report.1 +2 -2
- package/man/canon-retrieve.1 +2 -2
- package/man/canon-review-change.1 +2 -2
- package/man/canon-review-scenario.1 +2 -2
- package/man/canon-review.1 +2 -2
- package/man/canon-scenario-new.1 +2 -2
- package/man/canon-scenario.1 +2 -2
- package/man/canon-schema.1 +2 -2
- package/man/canon-search.1 +2 -2
- package/man/canon-selftest.1 +2 -2
- package/man/canon-skills-check.1 +2 -2
- package/man/canon-skills-doctor.1 +2 -2
- package/man/canon-skills-install.1 +2 -2
- package/man/canon-skills-show.1 +2 -2
- package/man/canon-skills.1 +2 -2
- package/man/canon-status.1 +2 -2
- package/man/canon-strategy-approval-payload.1 +2 -2
- package/man/canon-strategy-promote.1 +2 -2
- package/man/canon-strategy-rollback.1 +2 -2
- package/man/canon-strategy.1 +2 -2
- package/man/canon-subject-adopt.1 +2 -2
- package/man/canon-subject-move.1 +2 -2
- package/man/canon-subject-new.1 +2 -2
- package/man/canon-subject-show.1 +2 -2
- package/man/canon-subject-unadopt.1 +2 -2
- package/man/canon-subject.1 +2 -2
- package/man/canon-task-done.1 +2 -2
- package/man/canon-task.1 +2 -2
- package/man/canon-tier-age.1 +2 -2
- package/man/canon-tier.1 +2 -2
- package/man/canon-trace.1 +2 -2
- package/man/canon.1 +2 -2
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { spawnSync, execSync } from "node:child_process";
|
|
5
5
|
import { existsSync, readdirSync, realpathSync } from "node:fs";
|
|
6
|
+
import { constants as osConstants } from "node:os";
|
|
6
7
|
import { resolve, join, basename } from "node:path";
|
|
7
8
|
import { fileURLToPath } from "node:url";
|
|
8
9
|
var binaryName = process.platform === "win32" ? "canon.exe" : "canon";
|
|
@@ -165,4 +166,7 @@ var result = spawnSync(binary, process.argv.slice(2), {
|
|
|
165
166
|
if (result.error) {
|
|
166
167
|
console.error(`canon: failed to run ${binary}: ${result.error.message}`);
|
|
167
168
|
}
|
|
169
|
+
if (result.status === null && result.signal) {
|
|
170
|
+
process.exit(128 + (osConstants.signals[result.signal] ?? 0));
|
|
171
|
+
}
|
|
168
172
|
process.exit(result.status ?? 1);
|
package/dist/skills/SKILL.src.md
CHANGED
|
@@ -26,18 +26,34 @@ a feature, a one-line request included. A human is needed once per scope:
|
|
|
26
26
|
|
|
27
27
|
- **The approval** (step 1). For a new subject or a scope change, the
|
|
28
28
|
human must approve the brief. Write the brief,
|
|
29
|
-
run `canon brief check` until it reports no blockers, then
|
|
30
|
-
|
|
29
|
+
run `canon brief check` until it reports no blockers, then show it, ask and
|
|
30
|
+
record the answer: build nothing for that scope (no
|
|
31
31
|
scenarios, code or evidence) before the human answers. The approval is
|
|
32
32
|
the one thing you never assume, even when the human said they cannot
|
|
33
|
-
answer until you
|
|
33
|
+
answer until you show it. The one answer
|
|
34
34
|
approves the brief and the policy, `.canon/policy.yaml`, which is what
|
|
35
35
|
the gate grades the work against. The human may also approve it on the `canon dashboard` briefs page; you never use that form.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
1. **Show** with `canon brief show <slug> --body`: the brief file's bytes and,
|
|
37
|
+
last, `digest: sha256:<hex>`. Send it to the human's own view without
|
|
38
|
+
retyping it (omp: redirect it to `out://`, which is off for subagents and
|
|
39
|
+
non-TUI sessions and caps at 64 KiB; there, and in a harness with no such
|
|
40
|
+
channel, leave the tool output visible). A subagent has no question tool:
|
|
41
|
+
the orchestrator shows, asks and records.
|
|
42
|
+
2. **Ask** with the harness question tool (`ask` in omp, `AskUserQuestion` in
|
|
43
|
+
Claude Code, otherwise in the chat): approve or request changes, several
|
|
44
|
+
briefs in one question.
|
|
45
|
+
3. **Count only an explicit approval.** A question or a condition is a
|
|
46
|
+
revision request (change the brief, check, show and ask again); no answer
|
|
47
|
+
records nothing.
|
|
48
|
+
4. **Record it** with the relay option:
|
|
49
|
+
`canon brief approve <slug> <slug> --approver <their name> --note "<their words>" --relayed-via <ask|AskUserQuestion|chat> --actor <your actor id> --digest <slug>=<digest shown>`
|
|
50
|
+
(one or more slugs, each with its own `--digest`, one answer for all, nothing written if any is refused).
|
|
51
|
+
The `Approved:` line then carries `(relayed by <role> <actor> via <tool>)`.
|
|
52
|
+
A digest that no longer matches the brief is `RELAY_DIGEST_MISMATCH`: show
|
|
53
|
+
it again. Without `--relayed-via` an agent role gets `HUMAN_ONLY`, and so
|
|
54
|
+
does a repo whose `canon.yaml` says `approval: { relay: deny }`: then the
|
|
55
|
+
human runs the call themselves. Never remove or unset your role
|
|
56
|
+
(`env -u CANON_ROLE`, dropping `--as`) to run it yourself.
|
|
41
57
|
Never edit the policy to make the gate pass: a policy that differs from
|
|
42
58
|
the approved one fails closed (`POLICY_CHANGED_SINCE_APPROVAL`, not
|
|
43
59
|
waivable); stop and ask the human. A brief edited after its
|
|
@@ -74,7 +90,7 @@ a feature, a one-line request included. A human is needed once per scope:
|
|
|
74
90
|
so in your report. That covers the brief's questions and work inside an
|
|
75
91
|
approved scope, never the approval itself.
|
|
76
92
|
|
|
77
|
-
1. **Brief.** The planner writes the PRD brief (`.canon/changes/<slug>/brief.md`), checks it with `canon brief check`,
|
|
93
|
+
1. **Brief.** The planner writes the PRD brief (`.canon/changes/<slug>/brief.md`), checks it with `canon brief check`, shows it to the human, asks, and records their explicit approval. `canon skills show role-planner`
|
|
78
94
|
2. **Subject.** `canon subject new`, then `canon change new` (`--change-kind chore` for work that alters no behavior); the change writes the brief skeleton. `canon skills show role-planner`
|
|
79
95
|
3. **Scenarios.** `canon scenario new --flow <F-id> --case <case>` per behavior of a flow step, failure paths (`--case failure`) included; many at once with `--input` (below). `canon skills show role-implementer`
|
|
80
96
|
4. **Units.** Split the work; one unit is one flow step's slice with a named verify command, and each unit has its own actor id and session id, passed on everything it records. A unit never attests another unit's work.
|
|
@@ -170,7 +186,7 @@ variable, and an unknown value is refused (`UNKNOWN_ROLE`).
|
|
|
170
186
|
- **A role is set, or you were spawned as one:** load only
|
|
171
187
|
`canon skills show role-<role>` and do that role's steps. `canon status`
|
|
172
188
|
and `meta.next` then show only your role's steps, and count the others in
|
|
173
|
-
`waitingOn`; `canon schema --as <role>` lists only your role's commands.
|
|
189
|
+
`data.waitingOn`; `canon schema --as <role>` lists only your role's commands.
|
|
174
190
|
Do not load another role's guide.
|
|
175
191
|
- **No role (one agent doing everything):** follow `canon status` and load
|
|
176
192
|
each role guide as its phase starts: planner for steps 1–2,
|
|
@@ -185,8 +201,11 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
185
201
|
|
|
186
202
|
- Start a session with `canon status`: where each subject stands and the next
|
|
187
203
|
commands. After that, do not call it only to learn the next step: every
|
|
188
|
-
write returns `meta.next` (`[{command, argv,
|
|
189
|
-
steps `status` would give, narrowed to what the write touched.
|
|
204
|
+
write returns `meta.next` (`[{command, argv, reason, x-canon: {actor, role}}]`), the same
|
|
205
|
+
steps `status` would give, narrowed to what the write touched. Each entry is
|
|
206
|
+
runnable: `argv` is the command without `canon` (with `--json` when you
|
|
207
|
+
called in JSON mode). Guidance that needs a value you must fill in is not a
|
|
208
|
+
next entry; it is in the error `hint` or the report text. `x-canon.actor: human`
|
|
190
209
|
marks a step only the human takes.
|
|
191
210
|
- Your role guide's **Commands** block (`canon skills show role-<role>`) is
|
|
192
211
|
your complete command set, every option of every leaf included. Run `canon schema <command> --json` only for a
|
|
@@ -195,20 +214,25 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
195
214
|
- Pass `--json` and read stdout as one document, nothing on stderr. Success is
|
|
196
215
|
`{"ok":true,"data":…,"meta":…}`; failure is
|
|
197
216
|
`{"ok":false,"error":{…},"meta":…}` (a check that fails keeps its report in
|
|
198
|
-
`data`). `meta` carries `
|
|
199
|
-
`
|
|
217
|
+
`data`). `meta` carries `tool`, `toolVersion`, `contract` (`atip/1`), `schemaVersion`,
|
|
218
|
+
`command`, and when present `next`, `warnings` (`[{code, message}]`) and
|
|
219
|
+
`page`; a repeated write that changed nothing reports `data.unchanged: true`.
|
|
220
|
+
Absent members are omitted, never `null` or `[]`. A paged list puts
|
|
221
|
+
`meta.page.nextCursor` on the call's `meta.next` as `--cursor <nextCursor>`;
|
|
222
|
+
no `nextCursor` means no more.
|
|
200
223
|
On failure branch on `error.code`, fix the option `error.field` names
|
|
201
224
|
using the `error.expected` values (`field` is an option name, or a JSON
|
|
202
225
|
pointer such as `/items/2/scenario` into an `--input` document), and
|
|
203
226
|
follow `error.hint`: every refusal carries a working invocation. The codes
|
|
204
227
|
are stable; `canon schema --errors --json` lists them and
|
|
205
228
|
`canon schema --error <CODE>` explains one.
|
|
206
|
-
- **Exit codes:** 0 ok; 1 the command
|
|
207
|
-
|
|
229
|
+
- **Exit codes:** only 0, 1 and 2 exist: 0 ok; 1 the command ran and its answer
|
|
230
|
+
is negative or incomplete (a failed check, a violation, `unverifiable` when
|
|
231
|
+
nothing was examined, a partly failed batch); 2 refused to run (usage,
|
|
208
232
|
`CONFIG_MISSING`, an id or file that does not exist, an invalid argument).
|
|
209
233
|
A refusal leaves the tree unchanged.
|
|
210
234
|
- Repeating a write is safe: a record that already exists with identical
|
|
211
|
-
content is reported `unchanged` (`
|
|
235
|
+
content is reported `unchanged` (`data.unchanged`), not duplicated.
|
|
212
236
|
- An option that takes an id is the bare noun (`--change add-login`,
|
|
213
237
|
`--scenario auth.login.01`, `--actor reviewer-1`, `--project root`,
|
|
214
238
|
`--session s-1`), and an `--input` document key is that name without `Id`
|
|
@@ -217,16 +241,19 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
217
241
|
(`canon subject move <id> --to verifying`, `canon change new <slug>`), and
|
|
218
242
|
`--kind` values carry no `_record` suffix (`--kind evidence`).
|
|
219
243
|
- `canon status` sends the planner to write the brief while `brief check`
|
|
220
|
-
has blockers; the
|
|
244
|
+
has blockers; the approval step appears only when the brief is clean and
|
|
221
245
|
unapproved.
|
|
222
246
|
- Page long lists with `--limit <n>` and `--cursor <nextCursor>` (`--all`
|
|
223
247
|
for everything), and project fields with `--fields a,b` (`status`, `export`,
|
|
224
248
|
`query`, `finding list`, `divergence list`, `context`).
|
|
225
249
|
- `--override-reason <text>` is the only way to proceed past a waivable
|
|
226
250
|
refusal; it is recorded, echoed in `data.overrides[]` and listed by `status`
|
|
227
|
-
for the human. There is no `--force`. `brief approve`, `policy approve
|
|
228
|
-
`divergence accept`
|
|
229
|
-
|
|
251
|
+
for the human. There is no `--force`. `brief approve`, `policy approve`,
|
|
252
|
+
`divergence accept` and the `migrate --commit` that re-binds `Approved:`
|
|
253
|
+
lines record a human's decision and refuse every agent role (`HUMAN_ONLY`)
|
|
254
|
+
unless they record the explicit answer the human gave you, with
|
|
255
|
+
`--relayed-via <tool>` (show, ask, record, as for the brief; `canon skills
|
|
256
|
+
show role-planner`); never unset your role to run one.
|
|
230
257
|
|
|
231
258
|
### Many records at once: `--input`
|
|
232
259
|
|
|
@@ -238,8 +265,8 @@ from a file or stdin) is a batch, run in order and answered with
|
|
|
238
265
|
`skipped`, and that element's `data` or `error`). A batch is validated whole
|
|
239
266
|
before anything is written: an invalid element writes nothing and exits 2,
|
|
240
267
|
`error.field` pointing at `/items/<i>/<key>`; a write that fails stops there
|
|
241
|
-
(exit 1) and re-running the same batch reports the finished elements
|
|
242
|
-
`unchanged`. A typo in a key is refused (`
|
|
268
|
+
(exit 1, `BATCH_INCOMPLETE`) and re-running the same batch reports the finished elements
|
|
269
|
+
`unchanged`. A typo in a key is refused (`INPUT_INVALID`, `field` naming the key), never dropped.
|
|
243
270
|
`canon schema <command> --json` shows the leaf's input schema and an example.
|
|
244
271
|
|
|
245
272
|
```text
|
|
@@ -257,7 +284,7 @@ The five commands that delete or rewrite existing data (`canon purge`,
|
|
|
257
284
|
`canon tier age`, `canon ledger compact`, `canon artifacts move`,
|
|
258
285
|
`canon migrate`) act in two steps. The bare run previews: it writes nothing,
|
|
259
286
|
exits 0 and prints the effects and a `planDigest`. Read the effects, then act
|
|
260
|
-
with `--commit --plan-digest <planDigest>`. It refuses (`
|
|
287
|
+
with `--commit --plan-digest <planDigest>`. It refuses (`PLAN_STALE`) when
|
|
261
288
|
the plan differs from the one you previewed, so run the preview again. Appends
|
|
262
289
|
and state transitions (`gate promote`, `subject move`) run directly. Where a
|
|
263
290
|
preview helps elsewhere (`init`, `skills install`, `export`, `inventory sync`,
|
|
@@ -343,7 +370,7 @@ current step needs.
|
|
|
343
370
|
| Name | What it is for |
|
|
344
371
|
| --- | --- |
|
|
345
372
|
| `canon` | This core guide: the loop, driving the CLI, routing. |
|
|
346
|
-
| `role-planner` | Planner steps 1–2: subject, change, PRD brief, the
|
|
373
|
+
| `role-planner` | Planner steps 1–2: subject, change, PRD brief, the approval. |
|
|
347
374
|
| `role-implementer` | Implementer steps 3–6: scenarios, units, code, evidence. |
|
|
348
375
|
| `role-reviewer` | Reviewer step 7: findings and signed reviews in a separate session. |
|
|
349
376
|
| `role-orchestrator` | Orchestrator step 8: dispatch, transitions, resuming, upgrading. |
|
|
@@ -33,7 +33,7 @@ A chore adds no scenarios and has no flow: this pass does not apply to it.
|
|
|
33
33
|
|
|
34
34
|
## Next
|
|
35
35
|
|
|
36
|
-
Implement, evidence and review (loop steps 5 to 7). If the brief had to change, the human answers again
|
|
36
|
+
Implement, evidence and review (loop steps 5 to 7). If the brief had to change, the human answers again: show the brief, ask, and record an explicit approval with `--relayed-via` (`canon skills show role-planner`).
|
|
37
37
|
|
|
38
38
|
## Invariants (every brief pass)
|
|
39
39
|
|
|
@@ -41,4 +41,4 @@ Implement, evidence and review (loop steps 5 to 7). If the brief had to change,
|
|
|
41
41
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
42
42
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
43
43
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
44
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
44
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -33,7 +33,7 @@ Every open line is a question with a proposed default or a stated assumption. `c
|
|
|
33
33
|
|
|
34
34
|
## Next
|
|
35
35
|
|
|
36
|
-
`harden` if the flow changed; otherwise
|
|
36
|
+
`harden` if the flow changed; otherwise put the questions and the brief to the human and ask; record an explicit approval with `brief approve` with `--relayed-via <tool>` (`canon skills show role-planner`).
|
|
37
37
|
|
|
38
38
|
## Invariants (every brief pass)
|
|
39
39
|
|
|
@@ -41,4 +41,4 @@ Every open line is a question with a proposed default or a stated assumption. `c
|
|
|
41
41
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
42
42
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
43
43
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
44
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
44
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -34,7 +34,7 @@ brief has none of them: harden its Invariants and Checks instead.
|
|
|
34
34
|
|
|
35
35
|
## Next
|
|
36
36
|
|
|
37
|
-
`align` (`canon skills show brief-align`) once scenarios exist; `polish` (`canon skills show brief-polish`) for prose; otherwise
|
|
37
|
+
`align` (`canon skills show brief-align`) once scenarios exist; `polish` (`canon skills show brief-polish`) for prose; otherwise show the brief to the human and ask (`canon skills show role-planner`).
|
|
38
38
|
|
|
39
39
|
## Invariants (every brief pass)
|
|
40
40
|
|
|
@@ -42,4 +42,4 @@ brief has none of them: harden its Invariants and Checks instead.
|
|
|
42
42
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
43
43
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
44
44
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
45
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
45
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Make the brief something a human reads once and understands. Run it whenever
|
|
4
4
|
`canon brief check` reports `prose.*` advisories; `canon status` and
|
|
5
|
-
`meta.next` name it before the
|
|
5
|
+
`meta.next` name it before the approval step. It never blocks approval, and it
|
|
6
6
|
is not finished by silencing rules: it is finished when the brief reads
|
|
7
7
|
plainly and each advisory is gone or waived with a reason.
|
|
8
8
|
|
|
@@ -218,7 +218,7 @@ uses the section key `brief`.
|
|
|
218
218
|
1. Fix the mode problems above, then the findings, section by section.
|
|
219
219
|
2. Run `canon brief check <slug> --json`: the findings are in `data.findings[]`.
|
|
220
220
|
3. Repeat until no advisory remains, or each remaining one is waived with a reason.
|
|
221
|
-
4. Stop and
|
|
221
|
+
4. Stop polishing and show the brief to the human (`canon brief show <slug> --body`), in the brief's language, and ask. Do not loop further: a clean run says nothing about whether the brief is good, only that these counts are within budget.
|
|
222
222
|
|
|
223
223
|
## NEVER
|
|
224
224
|
|
|
@@ -236,7 +236,7 @@ uses the section key `brief`.
|
|
|
236
236
|
|
|
237
237
|
## Next
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
Show the brief to the human and ask (`canon brief show <slug> --body`, then the harness question tool); record an explicit approval with `brief approve` with `--relayed-via <tool>` (`canon skills show role-planner`).
|
|
240
240
|
|
|
241
241
|
## Invariants (every brief pass)
|
|
242
242
|
|
|
@@ -244,4 +244,4 @@ Report to the human, who approves with `canon brief approve` (theirs; agent role
|
|
|
244
244
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
245
245
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
246
246
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
247
|
-
- Write in the brief's language (detected from the text, or `language:` in `canon.yaml` when set). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
247
|
+
- Write in the brief's language (detected from the text, or `language:` in `canon.yaml` when set). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -69,7 +69,7 @@ prints the guidance of each empty one (in `language:`). A wrong heading
|
|
|
69
69
|
|
|
70
70
|
## Next
|
|
71
71
|
|
|
72
|
-
`clarify` if the Questions section still has open lines; `harden` if flow and detail disagree; otherwise
|
|
72
|
+
`clarify` if the Questions section still has open lines; `harden` if flow and detail disagree; otherwise show the brief to the human and ask; record an explicit approval with `brief approve` with `--relayed-via <tool>` (`canon skills show role-planner`).
|
|
73
73
|
|
|
74
74
|
## Invariants (every brief pass)
|
|
75
75
|
|
|
@@ -77,4 +77,4 @@ prints the guidance of each empty one (in `language:`). A wrong heading
|
|
|
77
77
|
- Explaining writes nothing. Asked what a finding means or what a pass would do, answer in chat and leave the brief untouched.
|
|
78
78
|
- No pass requires another as a prerequisite. Run the one the findings or the human point at, in any order.
|
|
79
79
|
- A pass closes only the findings it rechecked: rerun `canon brief check` after the edit and report a finding as closed only when it is gone from that run. Never claim a rule you did not rerun.
|
|
80
|
-
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer and
|
|
80
|
+
- Write in the brief's language (detected from the text; `language:` in `canon.yaml` overrides it). Edits touch `.canon/changes/<slug>/brief.md` only. A brief edited after approval is not approved: it needs a new human answer, shown and asked again, and a new `canon brief approve` (recorded with `--relayed-via` from that answer).
|
|
@@ -35,7 +35,7 @@ and what to run next. `--json` prints the `{ok, data, meta}` envelope: the
|
|
|
35
35
|
header adds no field, and `policy.spec_coverage`/`policy.diagnostics`
|
|
36
36
|
already carry the same fact. `--fields <list>` keeps only the named
|
|
37
37
|
top-level fields (`kinds`, `enums`, `policy`, `review`, …); an unknown name is
|
|
38
|
-
`
|
|
38
|
+
`USAGE` (exit 2; `field` is `--fields`, `expected` lists the selectable fields).
|
|
39
39
|
|
|
40
40
|
On a repository that still holds 0.27 canon state, `canon context` warns
|
|
41
41
|
and puts `canon migrate --json` first in `meta.next`: run `canon migrate`
|
|
@@ -299,9 +299,9 @@ never rides along into a confirming audit. `--drop-attachment` and
|
|
|
299
299
|
|
|
300
300
|
### Nothing is attested before the brief is approved (`--override-reason`)
|
|
301
301
|
|
|
302
|
-
The approval is never assumed: the agent writes the brief,
|
|
303
|
-
|
|
304
|
-
`canon evidence add` is the backstop for that
|
|
302
|
+
The approval is never assumed: the agent writes the brief, shows it to the
|
|
303
|
+
human and asks, and builds nothing for that scope until the human answers.
|
|
304
|
+
`canon evidence add` is the backstop for that rule (0.16 M7). It
|
|
305
305
|
refuses (exit `1`, nothing staged or stored) while a subject the record
|
|
306
306
|
attests for has an enforced, unapproved brief: a change the record
|
|
307
307
|
answers to (below) has a canon `.canon/changes/<change>/brief.md` with no `Approved:`
|
|
@@ -315,7 +315,7 @@ check `canon status` and the ship guard use; see
|
|
|
315
315
|
|
|
316
316
|
```stderr
|
|
317
317
|
canon evidence add: unreviewed-promotion demo-subject — evidence for world.demo.01: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line, so the human has not answered it; once they do, record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
|
|
318
|
-
canon evidence add: refused — stop
|
|
318
|
+
canon evidence add: refused — stop and get the human's answer to the brief: nothing is built or attested for a subject before its brief is approved. Show it (`canon brief show --body`), ask with the harness question tool, and on their explicit approval record it with `canon brief approve --approver <their name> --note "<their words>" --relayed-via <the question tool> --actor <your actor id> --digest <change>=<the digest shown>` (or they approve on `canon dashboard`); never unset your role to run it; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
|
|
319
319
|
```
|
|
320
320
|
|
|
321
321
|
For a change from an external plan with no canon brief yet, the first
|
|
@@ -347,7 +347,7 @@ brief_override:
|
|
|
347
347
|
Under `--json` the same waiver is `data.overrides[]` (`code` of the waived
|
|
348
348
|
refusal, `reason` verbatim), so a caller sees what its `--override-reason`
|
|
349
349
|
let through; a repeat of an identical record is `unchanged`
|
|
350
|
-
(`
|
|
350
|
+
(`data.unchanged`) and records no second override. `--override-reason`
|
|
351
351
|
exists on `subject move` too (see `canon-subject`).
|
|
352
352
|
|
|
353
353
|
A blank or multi-line reason exits 2; an override when nothing refused is
|
|
@@ -75,10 +75,13 @@ canon policy approve --approver <who> [--note <text>] [--repo <dir>]
|
|
|
75
75
|
A human approves the policy after reviewing `.canon/policy.yaml`, in the
|
|
76
76
|
same answer that approves a subject's brief (0.16; see the skill's working
|
|
77
77
|
loop). `canon brief approve` records both in one call. `canon policy
|
|
78
|
-
approve` is a human
|
|
79
|
-
it is refused with `HUMAN_ONLY` (exit 2, not retryable)
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
approve` is a human's decision: with a role declared (`--as` or `CANON_ROLE`)
|
|
79
|
+
it is refused with `HUMAN_ONLY` (exit 2, not retryable) unless it records the
|
|
80
|
+
answer the human gave in the conversation: show them `.canon/policy.yaml`, ask,
|
|
81
|
+
and on an explicit approval run it (the steps are in `canon skills show role-planner`) with `--relayed-via <tool>`, `--actor`,
|
|
82
|
+
`--approver` and `--note` (their name and words); the file then carries `relay`
|
|
83
|
+
(role, actor, tool). The human may run it themselves, for a policy-only change
|
|
84
|
+
or after the brief answer, supplying `--approver` and `--note`. It
|
|
82
85
|
writes `.canon/policy.approval.json` directly (nothing to promote):
|
|
83
86
|
|
|
84
87
|
```json
|
|
@@ -163,10 +163,13 @@ refused brief): nothing is written and the page says to read it again. A request
|
|
|
163
163
|
naming one brief the old way (`changeId`, `sha256`) is still accepted. The server is localhost only and
|
|
164
164
|
refuses requests from other origins (`DASHBOARD_ORIGIN_REFUSED`).
|
|
165
165
|
|
|
166
|
-
For an agent
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
`canon brief approve` only from the
|
|
166
|
+
For an agent: when clean briefs are waiting, show them (`canon brief show
|
|
167
|
+
<slug> --body`), ask with the harness question tool, and tell the human they
|
|
168
|
+
can approve them in `canon dashboard` (briefs page) instead. An agent never
|
|
169
|
+
clicks Approve or fills the form; it runs `canon brief approve` only from the
|
|
170
|
+
human's explicit answer, with `--relayed-via`. The page lists the approvals an
|
|
171
|
+
agent recorded for the human under "Approved through an agent" (`relayed` in
|
|
172
|
+
`GET /api/briefs`), with the role, actor and tool of each.
|
|
170
173
|
|
|
171
174
|
The dashboard renders SEVEN panels — trust matrix, session costs, role
|
|
172
175
|
memory, flywheel funnel, review burn-down, review rounds, review totals.
|
|
@@ -122,7 +122,7 @@ Many findings at once: `--input` takes inline JSON, a file or `-`; an array
|
|
|
122
122
|
(or NDJSON) is a batch validated before any write. Keys are the option
|
|
123
123
|
names in camelCase (`change`, `actor`, `resolutionRev`); `canon schema
|
|
124
124
|
finding add --json` shows the input schema and an example. An identical
|
|
125
|
-
repeat is `unchanged` (`
|
|
125
|
+
repeat is `unchanged` (`data.unchanged`) and writes nothing; a different
|
|
126
126
|
finding under an occupied key is `FINDING_SEQ_OCCUPIED`.
|
|
127
127
|
|
|
128
128
|
### A defect the author found in its own work
|
|
@@ -198,7 +198,7 @@ allowed, and the commit made from it has the same code tree, so committing it
|
|
|
198
198
|
afterwards leaves the review as it was: a review is judged by its pins (the
|
|
199
199
|
scenario and what its evidence says), not by the commit. Outside git, or
|
|
200
200
|
with no commit, the write is refused with `NO_COMMIT`. An identical review
|
|
201
|
-
written again is `unchanged` (`
|
|
201
|
+
written again is `unchanged` (`data.unchanged` under `--json`) and adds no
|
|
202
202
|
record.
|
|
203
203
|
|
|
204
204
|
**Done when:** `canon gate check` reports no `unreviewed-promotion` for the
|
|
@@ -104,7 +104,8 @@ canon query --kind handoff --since 2026-06-01T00:00:00Z
|
|
|
104
104
|
canon query --kind trajectory --json
|
|
105
105
|
|
|
106
106
|
# Page a long result and keep only the fields you need; `meta` carries
|
|
107
|
-
# returned, total,
|
|
107
|
+
# `page` = {returned, total, nextCursor}; a present `nextCursor` means more, and
|
|
108
|
+
# `meta.next` repeats the call with `--cursor <nextCursor>` (`--all` returns everything).
|
|
108
109
|
canon query --kind trajectory --json --limit 50 --fields at,kind
|
|
109
110
|
canon query --kind trajectory --json --limit 50 --cursor <nextCursor>
|
|
110
111
|
```
|
|
@@ -189,7 +190,7 @@ section listing them and emits a matching stderr `WARN`.
|
|
|
189
190
|
`canon purge --kind <kind> --before <RFC3339> [--commit --plan-digest <planDigest>] [--repo <dir>] [--json]`
|
|
190
191
|
is the canonical data-lifecycle boundary: the bare run previews: it prints the removal set and
|
|
191
192
|
its `planDigest` and deletes nothing; `--commit --plan-digest <planDigest>` deletes only if
|
|
192
|
-
the plan recomputed now has the same digest (`
|
|
193
|
+
the plan recomputed now has the same digest (`PLAN_STALE`, exit 2, when the
|
|
193
194
|
data moved). The only purgeable kinds are
|
|
194
195
|
`session`, `run`, `event`, and `trajectory`; the cutoff applies to every
|
|
195
196
|
routed rung and every configured aging destination, including retained
|
|
@@ -210,7 +211,7 @@ arguments previews an empty removal set.
|
|
|
210
211
|
With `--json`, `purge` and `export` answer `{ "data", "meta" }` like every other
|
|
211
212
|
command: `data` is the plan or manifest, `meta.next` the step after (a plan's is the
|
|
212
213
|
human's review and `--commit --plan-digest`), and an export's page state (`total`, `returned`,
|
|
213
|
-
`nextCursor`) sits in `meta`. `export --json --output <file>` writes the manifest to the
|
|
214
|
+
`nextCursor`) sits in `meta.page`. `export --json --output <file>` writes the manifest to the
|
|
214
215
|
file and answers with `data: { output, kind, recordCount }`; `--dry-run`
|
|
215
216
|
answers with what it would write and writes nothing.
|
|
216
217
|
|
|
@@ -71,7 +71,7 @@ canon subject new subject-domain-loop \
|
|
|
71
71
|
NDJSON) is a batch validated before any write, with `operands` holding the
|
|
72
72
|
id and the other keys the option names in camelCase (`canon schema subject
|
|
73
73
|
new --json` shows the schema and an example). Writing an identical subject
|
|
74
|
-
again is a no-op reported `unchanged` (`
|
|
74
|
+
again is a no-op reported `unchanged` (`data.unchanged`).
|
|
75
75
|
|
|
76
76
|
### 2. Retrieve subject-scoped strategy memory BEFORE working
|
|
77
77
|
|
|
@@ -207,8 +207,8 @@ the transition, not the check.
|
|
|
207
207
|
|
|
208
208
|
This refusal is a backstop, and so is the evidence one: shipping is not
|
|
209
209
|
the first thing an unapproved brief stops. The agent writes the brief,
|
|
210
|
-
runs `canon brief check` until it has no blockers, then
|
|
211
|
-
|
|
210
|
+
runs `canon brief check` until it has no blockers, then shows it to the
|
|
211
|
+
human and asks, and nothing is built or attested for the subject until the human
|
|
212
212
|
answers. `canon evidence add` refuses (exit 1, nothing staged) a
|
|
213
213
|
scenario whose `@subject` owner, or a task whose change
|
|
214
214
|
an adopting subject, has an enforced, unapproved brief, through the same
|
|
@@ -547,7 +547,7 @@ warn, and a command that writes and judges it is refused
|
|
|
547
547
|
human answers again and `approve` runs again. Run it only from the
|
|
548
548
|
human's answer, with their words as `--note`.
|
|
549
549
|
|
|
550
|
-
The optional refinement passes that fix findings before the
|
|
550
|
+
The optional refinement passes that fix findings before the approval step are
|
|
551
551
|
listed in `role-planner.md` in this directory.
|
|
552
552
|
|
|
553
553
|
A **chore** (`canon change new --change-kind chore`) changes how the subject is
|
|
@@ -688,7 +688,7 @@ uses, so status and the gate cannot disagree about a gap:
|
|
|
688
688
|
newest change's canon
|
|
689
689
|
`brief.md` has no `Approved:` line, or it has no canon `brief.md` yet
|
|
690
690
|
and comes from an external openspec `proposal.md`) and clean gets
|
|
691
|
-
`human:
|
|
691
|
+
`human: show the brief in <brief> to the human and ask; build and attest nothing for <id> until the human answers (one answer approves brief and policy)`,
|
|
692
692
|
where `<brief>` is the canon `brief.md`, or the external `proposal.md`
|
|
693
693
|
when no canon brief exists yet. Its reason reads ``<id>: <why
|
|
694
694
|
unanswered> (an older change's approval does not cover a new scope),
|
|
@@ -747,21 +747,23 @@ Status fails closed rather than suggest progress the gate would refuse:
|
|
|
747
747
|
```
|
|
748
748
|
|
|
749
749
|
The steps that follow are not in `data`: they are `meta.next`, most useful
|
|
750
|
-
first, with `
|
|
750
|
+
first, with `data.nextOmitted` counting what was cut and `data.waitingOn`
|
|
751
751
|
(with a declared role, `--as`) counting the steps each other owner holds:
|
|
752
752
|
|
|
753
753
|
```json
|
|
754
754
|
"next": [
|
|
755
|
-
{ "command": "
|
|
756
|
-
{ "command": "canon
|
|
757
|
-
{ "command": "canon status", "argv": ["
|
|
755
|
+
{ "command": "canon brief show c-promo --json", "argv": ["brief", "show", "c-promo", "--json"], "reason": "promo: the brief is not approved; build and attest nothing for promo until the human answers", "x-canon": { "actor": "human" } },
|
|
756
|
+
{ "command": "canon gate check --json", "argv": ["gate", "check", "--json"], "reason": "cart: 1 open blocker finding(s); fix it, commit, then close it with `canon finding close`", "x-canon": { "actor": "agent", "role": "implementer" } },
|
|
757
|
+
{ "command": "canon status --json", "argv": ["status", "--json"], "reason": "1 scenario(s) carry no @subject tag (first: cart.promo.01); add `@subject:<id>` above each in its .feature file, then check again", "x-canon": { "actor": "agent", "role": "planner" } }
|
|
758
758
|
]
|
|
759
759
|
```
|
|
760
760
|
|
|
761
|
-
`argv` is the command
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
761
|
+
`argv` is the command without the executable (`canon` + `argv` is the call),
|
|
762
|
+
and carries `--json` when you called in JSON mode. Every next entry is
|
|
763
|
+
runnable as it stands: guidance that needs a value only you know (an actor id,
|
|
764
|
+
a session, the human's words) is not a next entry, it is in the error `hint`
|
|
765
|
+
or the report text. On a repository that still holds 0.27 canon state,
|
|
766
|
+
`canon status` warns (`data.warnings`, `meta.warnings` as `[{code, message}]`) and puts `canon
|
|
765
767
|
migrate --json` first in `meta.next`: run `canon migrate`, then `canon
|
|
766
768
|
migrate --commit --plan-digest <digest from the preview>`, then `canon
|
|
767
769
|
skills install`.
|
|
@@ -792,14 +794,14 @@ only the pending drafts, and `flow` lists each flow step of every tagged
|
|
|
792
794
|
change as `{ "id", "change", "scenarios": [{ id, title, failure, evidenced,
|
|
793
795
|
review }], "gaps" }`.
|
|
794
796
|
|
|
795
|
-
Each `meta.next` entry's `actor` is `agent`
|
|
796
|
-
|
|
797
|
+
Each `meta.next` entry's `x-canon.actor` is `agent` or `human` (a step only the
|
|
798
|
+
human takes; its `reason` says what to get from them).
|
|
797
799
|
|
|
798
800
|
`policy.spec_coverage` has the shape `canon context --json` prints
|
|
799
801
|
(`null` when absent, `{"invalid": …}` when unusable). `statusVersion`
|
|
800
802
|
changes only when a field changes meaning or is removed. It became `2`
|
|
801
803
|
in 0.16, when `next[].command` stopped always being a command line
|
|
802
|
-
(`actor`
|
|
804
|
+
(`actor` told which), and `brief` was added alongside. It is `3` since
|
|
803
805
|
0.17, when `brief.proposal` was removed: the canon `brief.md` is
|
|
804
806
|
`brief.brief`, with `briefExists` and `source`. It is `4` since 0.31, when the
|
|
805
807
|
`brief` object became the `briefs` list.
|
|
@@ -4,15 +4,17 @@ You build inside an approved scope: scenarios, code, tests and evidence.
|
|
|
4
4
|
Declare the role with `CANON_ROLE=implementer` (or `--as implementer`); `--role`
|
|
5
5
|
on what you record then defaults to `implementer`.
|
|
6
6
|
Build nothing before the brief is approved: `canon evidence add` refuses an
|
|
7
|
-
unapproved brief's scenarios. If it is not approved,
|
|
8
|
-
|
|
7
|
+
unapproved brief's scenarios. If it is not approved, tell the orchestrator or planner, who show it to the human and ask;
|
|
8
|
+
build nothing meanwhile. The only waiver is `--override-reason
|
|
9
9
|
"<why>"`, for the case where you were told to attest while the brief waits for
|
|
10
10
|
the human's answer: canon records it on the evidence, echoes it in
|
|
11
11
|
`data.overrides[]` and lists it in `status` for the human. Never use it to
|
|
12
12
|
skip the wait yourself. `brief approve`, `policy approve` and `divergence
|
|
13
|
-
accept` are the human's; they refuse you (`HUMAN_ONLY`)
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
accept` are the human's; they refuse you (`HUMAN_ONLY`) unless they record an
|
|
14
|
+
answer the human gave in the conversation (`--relayed-via`, the planner's
|
|
15
|
+
procedure: `canon skills show role-planner`). You never run them without that
|
|
16
|
+
answer, and never remove or unset your role (`env -u CANON_ROLE`, dropping
|
|
17
|
+
`--as`) to get past the refusal.
|
|
16
18
|
|
|
17
19
|
## Commands
|
|
18
20
|
|
|
@@ -218,7 +220,7 @@ canon trace add-login_1_1
|
|
|
218
220
|
<!-- canon:generated commands-implementer end -->
|
|
219
221
|
|
|
220
222
|
After the first `status`, follow `meta.next` of each write; do not call
|
|
221
|
-
`canon status` again to learn the next step. Every record you write takes
|
|
223
|
+
`canon status` again to learn the next step. Each `meta.next` entry is runnable: run `canon` + its `argv`; guidance that needs a value you must fill in is in the error `hint` or the report text, not in `meta.next`. Every record you write takes
|
|
222
224
|
the commit it is about from `--rev` (default `HEAD`, any git revision). You
|
|
223
225
|
need not commit first: code that is not committed yet is recorded with its
|
|
224
226
|
`codeTree` and `worktreeDirty: true`, never refused. Outside git, or in a
|
|
@@ -318,7 +320,7 @@ canon evidence add --input '[{"scenario":"auth.login.01","class":"test-run","ref
|
|
|
318
320
|
match the scenario because of something outside this change, record the
|
|
319
321
|
evidence `divergent` and say why in `--ref`; never record `faithful` to
|
|
320
322
|
pass. The human accepts the tracked gap (`canon divergence accept`
|
|
321
|
-
refuses agent roles); fixing the behavior and recording again is the
|
|
323
|
+
refuses agent roles unless it records their explicit answer); fixing the behavior and recording again is the
|
|
322
324
|
other way out.
|
|
323
325
|
5. **Promote.** Under `write: { promote: auto }` (what `canon init` writes)
|
|
324
326
|
the record is final when `evidence add` returns. Only with
|
|
@@ -361,15 +363,15 @@ not another evidence step.
|
|
|
361
363
|
|---|---|
|
|
362
364
|
| "The suite is slow; record `faithful` to pass." | `faithful` over a failed case is refused; a limit outside this change is recorded `divergent` with the reason in `--ref`. |
|
|
363
365
|
| "I fixed it, the test would pass." | Run the test red first and bind it, then green. Evidence is a claim; the history is what the reviewer reads. |
|
|
364
|
-
| "The brief is as good as approved." | `evidence add` refuses an unapproved brief's scenarios.
|
|
366
|
+
| "The brief is as good as approved." | `evidence add` refuses an unapproved brief's scenarios. Tell the orchestrator or planner, who show it to the human and ask; build nothing meanwhile. |
|
|
365
367
|
| "I will attest the other unit's work under my id." | Each unit records under its own actor id and session id. |
|
|
366
368
|
| "I was told this twice already." | A correction repeated across runs belongs in a scenario, the policy or a gate; tell the orchestrator. |
|
|
367
|
-
| "I will accept the divergence myself." |
|
|
369
|
+
| "I will accept the divergence myself." | The human accepts a gap: report the scenario, the reason and the tracking reference so they are asked, and never record an answer they did not give. |
|
|
368
370
|
|
|
369
371
|
## Retry safety
|
|
370
372
|
|
|
371
373
|
`evidence add` is content-keyed: repeating it with identical input returns
|
|
372
|
-
the existing record with `
|
|
374
|
+
the existing record with `data.unchanged: true` instead of a duplicate (a
|
|
373
375
|
batch reports that element `unchanged`). After a timeout or a lost
|
|
374
376
|
response, run the same command again. `scenario new` is not: an existing
|
|
375
377
|
scenario id is refused (`SCENARIO_TAG_EXISTS`) and nothing changes, so check
|