@journeykit/canon 0.27.0 → 0.29.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 +245 -89
- package/dist/skills/reference/brief-align.md +4 -2
- package/dist/skills/reference/brief-clarify.md +7 -5
- package/dist/skills/reference/brief-harden.md +4 -2
- package/dist/skills/reference/brief-polish.md +7 -5
- package/dist/skills/reference/brief-shape.md +4 -2
- package/dist/skills/reference/canon-artifact-ingest.md +11 -7
- package/dist/skills/reference/canon-authoring.md +16 -2
- package/dist/skills/reference/canon-context.md +21 -11
- package/dist/skills/reference/canon-fmt.md +10 -2
- package/dist/skills/reference/canon-gate.md +107 -69
- package/dist/skills/reference/canon-inventory.md +23 -15
- package/dist/skills/reference/canon-learn.md +23 -19
- package/dist/skills/reference/canon-plan-import.md +10 -7
- package/dist/skills/reference/canon-plugins.md +15 -8
- package/dist/skills/reference/canon-policy.md +20 -16
- package/dist/skills/reference/canon-report-dashboard.md +30 -19
- package/dist/skills/reference/canon-retrieve.md +13 -10
- package/dist/skills/reference/canon-review.md +96 -68
- package/dist/skills/reference/canon-session-ingest.md +7 -3
- package/dist/skills/reference/canon-storage.md +65 -39
- package/dist/skills/reference/canon-subject.md +116 -79
- package/dist/skills/reference/canon-vocab.md +1 -1
- package/dist/skills/reference/role-implementer.md +295 -64
- package/dist/skills/reference/role-orchestrator.md +547 -55
- package/dist/skills/reference/role-planner.md +189 -32
- package/dist/skills/reference/role-reviewer.md +257 -58
- package/dist/skills/scripts/canon-retrieve-pre-dispatch.sh +10 -5
- package/man/canon-adapter-authorize.1 +44 -0
- package/man/canon-adapter-validate.1 +44 -0
- package/man/canon-adapter.1 +46 -0
- package/man/canon-artifacts-move.1 +63 -0
- package/man/canon-artifacts-store.1 +54 -0
- package/man/canon-artifacts-verify.1 +48 -0
- package/man/canon-artifacts.1 +45 -0
- package/man/canon-brief-approve.1 +62 -0
- package/man/canon-brief-check.1 +44 -0
- package/man/canon-brief-show.1 +50 -0
- package/man/canon-brief.1 +63 -0
- package/man/canon-change-new.1 +66 -0
- package/man/canon-change.1 +42 -0
- package/man/canon-completion.1 +60 -0
- package/man/canon-context-pack-add.1 +47 -0
- package/man/canon-context-pack-show.1 +44 -0
- package/man/canon-context-pack-verify.1 +44 -0
- package/man/canon-context-pack.1 +50 -0
- package/man/canon-context.1 +44 -0
- package/man/canon-dashboard.1 +50 -0
- package/man/canon-demo-init.1 +44 -0
- package/man/canon-demo-review.1 +44 -0
- package/man/canon-demo.1 +47 -0
- package/man/canon-dispatch-begin.1 +80 -0
- package/man/canon-dispatch-diff.1 +41 -0
- package/man/canon-dispatch-end.1 +60 -0
- package/man/canon-dispatch.1 +45 -0
- package/man/canon-divergence-accept.1 +68 -0
- package/man/canon-divergence-add.1 +97 -0
- package/man/canon-divergence-defer.1 +71 -0
- package/man/canon-divergence-list.1 +56 -0
- package/man/canon-divergence-resolve.1 +68 -0
- package/man/canon-divergence.1 +51 -0
- package/man/canon-evidence-add.1 +168 -0
- package/man/canon-evidence-approval-payload.1 +65 -0
- package/man/canon-evidence-audit.1 +121 -0
- package/man/canon-evidence.1 +57 -0
- package/man/canon-export.1 +108 -0
- package/man/canon-feature-new.1 +62 -0
- package/man/canon-feature.1 +39 -0
- package/man/canon-finding-add.1 +196 -0
- package/man/canon-finding-close.1 +117 -0
- package/man/canon-finding-list.1 +59 -0
- package/man/canon-finding.1 +67 -0
- package/man/canon-format.1 +49 -0
- package/man/canon-gate-check.1 +44 -0
- package/man/canon-gate-install-hooks.1 +59 -0
- package/man/canon-gate-promote.1 +62 -0
- package/man/canon-gate.1 +50 -0
- package/man/canon-ingest-plans.1 +53 -0
- package/man/canon-ingest-records.1 +56 -0
- package/man/canon-ingest-sessions.1 +62 -0
- package/man/canon-ingest.1 +50 -0
- package/man/canon-init.1 +98 -0
- package/man/canon-inventory-sync.1 +50 -0
- package/man/canon-inventory.1 +39 -0
- package/man/canon-ledger-compact.1 +50 -0
- package/man/canon-ledger.1 +54 -0
- package/man/canon-migrate.1 +89 -0
- package/man/canon-plugin-sync.1 +53 -0
- package/man/canon-plugin.1 +39 -0
- package/man/canon-policy-approve.1 +50 -0
- package/man/canon-policy-show.1 +41 -0
- package/man/canon-policy.1 +52 -0
- package/man/canon-prompt-add.1 +47 -0
- package/man/canon-prompt-show.1 +41 -0
- package/man/canon-prompt.1 +43 -0
- package/man/canon-purge.1 +70 -0
- package/man/canon-query.1 +111 -0
- package/man/canon-regime-show.1 +50 -0
- package/man/canon-regime.1 +39 -0
- package/man/canon-report-build.1 +44 -0
- package/man/canon-report-check.1 +41 -0
- package/man/canon-report-snapshot.1 +47 -0
- package/man/canon-report.1 +45 -0
- package/man/canon-retrieve.1 +56 -0
- package/man/canon-review-change.1 +98 -0
- package/man/canon-review-scenario.1 +98 -0
- package/man/canon-review.1 +42 -0
- package/man/canon-scenario-new.1 +80 -0
- package/man/canon-scenario.1 +39 -0
- package/man/canon-schema.1 +63 -0
- package/man/canon-selftest.1 +69 -0
- package/man/canon-skills-check.1 +47 -0
- package/man/canon-skills-doctor.1 +47 -0
- package/man/canon-skills-install.1 +53 -0
- package/man/canon-skills-show.1 +104 -0
- package/man/canon-skills.1 +48 -0
- package/man/canon-status.1 +51 -0
- package/man/canon-strategy-approval-payload.1 +53 -0
- package/man/canon-strategy-promote.1 +59 -0
- package/man/canon-strategy-rollback.1 +62 -0
- package/man/canon-strategy.1 +45 -0
- package/man/canon-subject-adopt.1 +53 -0
- package/man/canon-subject-move.1 +80 -0
- package/man/canon-subject-new.1 +65 -0
- package/man/canon-subject-show.1 +44 -0
- package/man/canon-subject-unadopt.1 +63 -0
- package/man/canon-subject.1 +51 -0
- package/man/canon-task-done.1 +47 -0
- package/man/canon-task.1 +42 -0
- package/man/canon-tier-age.1 +50 -0
- package/man/canon-tier.1 +39 -0
- package/man/canon.1 +169 -0
- package/package.json +9 -5
|
@@ -13,18 +13,18 @@ trajectories into retrievable, promotable insights. Two tiers:
|
|
|
13
13
|
## Rebuilding strategy memory
|
|
14
14
|
|
|
15
15
|
Strategy memory is re-derived from the current trajectory set as part of
|
|
16
|
-
`canon ingest
|
|
16
|
+
`canon ingest records` (see `canon-artifact-ingest`): after it
|
|
17
17
|
persists a repo's verdict trajectories, it re-derives the distilled
|
|
18
18
|
strategies. This is NON-DESTRUCTIVE — a rebuild never drops a
|
|
19
19
|
hand-promoted strategy the trajectory rows don't touch. There is no
|
|
20
|
-
standalone
|
|
21
|
-
`promote`.
|
|
20
|
+
standalone rebuild command under `canon strategy`; its subcommands are
|
|
21
|
+
`promote`, `approval-payload` and `rollback`.
|
|
22
22
|
|
|
23
|
-
# `canon
|
|
23
|
+
# `canon strategy promote <strategy_id> [--repo <dir>] [--evaluation <path> --approval <path>] [--signature-file <path>] [--dry-run]`
|
|
24
24
|
|
|
25
25
|
The production activation path is a signed, paired-evaluation workflow:
|
|
26
26
|
|
|
27
|
-
1. Run `canon ingest
|
|
27
|
+
1. Run `canon ingest records`. Ingest resolves covering verdicts and rebuilds
|
|
28
28
|
newly distilled strategies as `lifecycle: quarantined`.
|
|
29
29
|
2. Check eligibility with the configured `occurrence` or `crn` gate. This is
|
|
30
30
|
only a prerequisite; occurrence alone MUST NOT activate a strategy.
|
|
@@ -44,14 +44,14 @@ The production activation path is a signed, paired-evaluation workflow:
|
|
|
44
44
|
5. Produce the unsigned approval payload:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
canon
|
|
48
|
-
--
|
|
47
|
+
canon strategy approval-payload 01J8ZQ4W7K2M5N6P8R0S3T9VXY --evaluation evaluation.json \
|
|
48
|
+
--approver alice --approval-at 2026-10-02T12:00:00Z --repo .
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
With `--json` the payload is `.data` of the `{ "data", "meta" }` envelope, and
|
|
52
52
|
`meta.next` names the human signing step. The `data` contains the evaluation digest, RFC3339 `approved_at`,
|
|
53
53
|
subject `strategy:<strategy_id>`, namespace
|
|
54
|
-
`canon-learning-approval-v1`, and `payload_hex`. `
|
|
54
|
+
`canon-learning-approval-v1`, and `payload_hex`. `approval-payload` never
|
|
55
55
|
reads a private key and never sets `verified`.
|
|
56
56
|
6. Decode `payload_hex` to the exact canonical JSON bytes. The signed object
|
|
57
57
|
is:
|
|
@@ -97,12 +97,12 @@ The production activation path is a signed, paired-evaluation workflow:
|
|
|
97
97
|
8. Activate only with both evidence files:
|
|
98
98
|
|
|
99
99
|
```bash
|
|
100
|
-
canon
|
|
100
|
+
canon strategy promote 01J8ZQ4W7K2M5N6P8R0S3T9VXY --repo . \
|
|
101
101
|
--evaluation evaluation.json --approval approval.json
|
|
102
102
|
# Or attach an armored signature file and recompute the approval digest:
|
|
103
|
-
canon
|
|
103
|
+
canon strategy promote 01J8ZQ4W7K2M5N6P8R0S3T9VXY --repo . \
|
|
104
104
|
--evaluation evaluation.json --approval approval.json \
|
|
105
|
-
--signature approval.sig
|
|
105
|
+
--signature-file approval.sig
|
|
106
106
|
```
|
|
107
107
|
|
|
108
108
|
`--evaluation` and `--approval` MUST be supplied together. A quarantined
|
|
@@ -123,6 +123,10 @@ An unknown `strategy_id` fails nonzero. A candidate's lifecycle defaults to
|
|
|
123
123
|
The old public writer is retained only for already-`active` items; it is not a
|
|
124
124
|
way to activate new or legacy candidates.
|
|
125
125
|
|
|
126
|
+
**Done when:** `canon strategy promote <strategy_id>` exits `0` and
|
|
127
|
+
`canon retrieve` returns the strategy for its regime (a quarantined
|
|
128
|
+
candidate stays out of retrieval).
|
|
129
|
+
|
|
126
130
|
### The eligibility gates: `crn` vs `occurrence`
|
|
127
131
|
|
|
128
132
|
A role's eligibility gate is a `canon.yaml` `learn:`-section choice:
|
|
@@ -160,11 +164,11 @@ A role with no explicit `promotion.<role>` entry defaults to
|
|
|
160
164
|
|
|
161
165
|
Both gates read resolved `verdict_record.outcome`, not raw verdict rows.
|
|
162
166
|
`Pending` trajectories neither corroborate nor contradict. `canon ingest
|
|
163
|
-
|
|
167
|
+
records` is therefore always first:
|
|
164
168
|
|
|
165
169
|
```bash
|
|
166
|
-
canon ingest
|
|
167
|
-
canon
|
|
170
|
+
canon ingest records
|
|
171
|
+
canon strategy promote 01J8ZQ4W7K2M5N6P8R0S3T9VXY --evaluation evaluation.json --approval approval.json
|
|
168
172
|
```
|
|
169
173
|
|
|
170
174
|
### Demotion versus authenticated rollback
|
|
@@ -178,15 +182,15 @@ record.
|
|
|
178
182
|
|
|
179
183
|
An operator-requested rollback is a distinct authenticated action:
|
|
180
184
|
|
|
181
|
-
```
|
|
182
|
-
canon
|
|
183
|
-
--signature-file rollback.sig --
|
|
185
|
+
```text
|
|
186
|
+
canon strategy rollback <strategy_id> --reason "<reason>" --actor-id alice \
|
|
187
|
+
--signature-file rollback.sig --approval-at 2026-10-02T12:00:00Z \
|
|
184
188
|
[--contradicting-trajectory-id <trajectory_id>] --repo .
|
|
185
189
|
```
|
|
186
190
|
|
|
187
191
|
`--signature-file` is an armored SSH detached signature over the
|
|
188
192
|
`canon-learning-approval-v1` payload bound to
|
|
189
|
-
`strategy:<id>:rollback:<sha256(reason)>`, actor, and `--
|
|
193
|
+
`strategy:<id>:rollback:<sha256(reason)>`, actor, and `--approval-at`.
|
|
190
194
|
`actor` MUST be listed in policy-pinned `approval.allowed_signers`; verification
|
|
191
195
|
uses that file and `ssh-keygen -Y verify`. Successful rollback writes durable
|
|
192
196
|
provenance, sets lifecycle `rolled_back`, and records the optional contradicting
|
|
@@ -203,7 +207,7 @@ not upgrade legacy rows or establish measured uplift.
|
|
|
203
207
|
|
|
204
208
|
## How verdicts feed scoring
|
|
205
209
|
|
|
206
|
-
Verdicts arrive from `canon ingest
|
|
210
|
+
Verdicts arrive from `canon ingest records` (see
|
|
207
211
|
`canon-artifact-ingest`), persisted regime-keyed
|
|
208
212
|
(`<role>/<repo>/<area>/<hash>`). Each verdict scores its covering
|
|
209
213
|
trajectory into `Success` / `Failure` / `RolledBack` / `Pending`; the
|
|
@@ -13,8 +13,8 @@ one, and neither can `canon gate`.
|
|
|
13
13
|
one `<slug>/` directory per change holding `brief.md` (and a `tasks.md`
|
|
14
14
|
only when someone adds one: an optional work note), written by
|
|
15
15
|
`canon change new` (see `canon-subject`). Every plan reader —
|
|
16
|
-
`canon ingest plans`, `canon
|
|
17
|
-
`canon dispatch --task`, `canon status` and the brief check — reads it
|
|
16
|
+
`canon ingest plans`, `canon task done`, `canon evidence add --task-id`,
|
|
17
|
+
`canon dispatch begin --task-id`, `canon status` and the brief check — reads it
|
|
18
18
|
first whenever the directory exists, with no `plans:` entry. Being first,
|
|
19
19
|
it owns a change id an external source also carries (the external copy
|
|
20
20
|
is the later duplicate, skipped and counted under `duplicate_change_id`).
|
|
@@ -27,7 +27,7 @@ document and holds the human's `Approved:` line, written by
|
|
|
27
27
|
skips that directory and the external source keeps the change id.
|
|
28
28
|
|
|
29
29
|
`plans.sources` lists only EXTERNAL plans — documents you prepare outside
|
|
30
|
-
canon, which canon only reads. The one exception: `canon
|
|
30
|
+
canon, which canon only reads. The one exception: `canon task done`
|
|
31
31
|
flips the task's checkbox in an external plan's `tasks.md` (see
|
|
32
32
|
`canon-gate`). Their briefs and approvals live in
|
|
33
33
|
`.canon/changes/<change>/brief.md`, never in the external document.
|
|
@@ -58,7 +58,7 @@ single ad hoc import, reading only the source it names; either flag alone
|
|
|
58
58
|
fails loud):
|
|
59
59
|
|
|
60
60
|
```bash
|
|
61
|
-
canon ingest plans --dialect openspec --source ../other-repo
|
|
61
|
+
canon ingest plans --dialect openspec --plan-source ../other-repo
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
## 2. Run the import
|
|
@@ -78,11 +78,14 @@ the adapter's `unmapped` drop counts, and `malformed` (structurally
|
|
|
78
78
|
broken constructs). A source whose content is byte-identical to its last
|
|
79
79
|
successful run is `skipped_unchanged` — re-importing writes zero records.
|
|
80
80
|
|
|
81
|
+
**Done when:** `canon ingest plans` exits `0` with `malformed` and
|
|
82
|
+
`changes_unwritten` at `0` for every source; step 3 lists the imported rows.
|
|
83
|
+
|
|
81
84
|
## 3. Read the imported rows
|
|
82
85
|
|
|
83
86
|
```bash
|
|
84
|
-
canon query --kind change
|
|
85
|
-
canon query --kind task
|
|
87
|
+
canon query --kind change --json
|
|
88
|
+
canon query --kind task --json
|
|
86
89
|
```
|
|
87
90
|
|
|
88
91
|
No dialect/plugin filter exists or is needed — an imported `change`/
|
|
@@ -181,7 +184,7 @@ downstream reader's job.
|
|
|
181
184
|
`.canon/changes/<slug>/brief.md` (no `tasks.md`) and adopts the change
|
|
182
185
|
into a subject (see `canon-subject`); it never scaffolds an openspec
|
|
183
186
|
change dir. This skill covers IMPORTING plans.
|
|
184
|
-
- **`canon gate check`/`canon
|
|
187
|
+
- **`canon gate check`/`canon task done`** (the hand-authored one-task-at-
|
|
185
188
|
a-time path this complements at bulk) — see `canon-gate`.
|
|
186
189
|
- **Wiring an imported `Task`/`Change` into a `canon gate` decision** —
|
|
187
190
|
out of scope; needs its own reviewed change.
|
|
@@ -61,17 +61,21 @@ matching; no field outside envelope ∪ join-key ∪ declared), then writes.
|
|
|
61
61
|
The on-disk path is derived from the join-key field values in declared
|
|
62
62
|
order plus a body digest — a byte-identical resubmission dedupes to the
|
|
63
63
|
same path; a different body for the same join key appends at a new path,
|
|
64
|
-
never overwriting.
|
|
64
|
+
never overwriting. `--dry-run` validates and reports what would be written
|
|
65
|
+
without writing; an identical rerun writes nothing and reports `unchanged`.
|
|
66
|
+
|
|
67
|
+
**Done when:** `canon plugin sync <plugin-id>` exits `0` with no validation
|
|
68
|
+
error; the next step (3) reads the overlay back.
|
|
65
69
|
|
|
66
70
|
## 3. Project a read
|
|
67
71
|
|
|
68
72
|
```bash
|
|
69
|
-
canon query --kind scenario --plugin porting # human table, projected fields appended
|
|
70
|
-
canon query --kind scenario --plugin porting --json # merged record bodies
|
|
71
|
-
canon query --kind scenario # no --plugin: byte-identical to the core view
|
|
73
|
+
canon query --kind scenario --plugin-id porting # human table, projected fields appended
|
|
74
|
+
canon query --kind scenario --plugin-id porting --json # merged record bodies
|
|
75
|
+
canon query --kind scenario # no --plugin-id: byte-identical to the core view
|
|
72
76
|
```
|
|
73
77
|
|
|
74
|
-
`--plugin <id>` folds the plugin's overlay records (latest-by-
|
|
78
|
+
`--plugin-id <id>` folds the plugin's overlay records (latest-by-
|
|
75
79
|
`(join_key, at)`) onto each queried core record. Fail-soft everywhere:
|
|
76
80
|
|
|
77
81
|
- No overlay record for a core key → that record projects UNMODIFIED (no
|
|
@@ -81,9 +85,12 @@ canon query --kind scenario # no --plugin: byte-identi
|
|
|
81
85
|
SKIPPED + diagnosed; siblings still project.
|
|
82
86
|
- An absent plugin/manifest → the unmodified core view + a diagnostic,
|
|
83
87
|
never a process error.
|
|
84
|
-
- Omitting `--plugin` is byte-identical to `canon query`'s output without
|
|
88
|
+
- Omitting `--plugin-id` is byte-identical to `canon query`'s output without
|
|
85
89
|
plugins — it's a purely additive layer.
|
|
86
90
|
|
|
91
|
+
**Done when:** the projected table or JSON shows the plugin's fields on the
|
|
92
|
+
scenarios you synced.
|
|
93
|
+
|
|
87
94
|
## The `porting` worked example
|
|
88
95
|
|
|
89
96
|
`porting` moves the `covered`/`surface_ref` fields off the core
|
|
@@ -91,7 +98,7 @@ canon query --kind scenario # no --plugin: byte-identi
|
|
|
91
98
|
|
|
92
99
|
1. `.canon/plugins/porting/plugin.yaml` — the manifest above.
|
|
93
100
|
2. Its overlay source reads a spec root's `inventory/**/*.yaml` (the same
|
|
94
|
-
inventory files `canon format
|
|
101
|
+
inventory files `canon format` covers) and, for every
|
|
95
102
|
`(project_id, scenario_id)` `canon inventory sync` would index, emits
|
|
96
103
|
one candidate: `covered = true` iff that `scenario_id` appears in ANY
|
|
97
104
|
inventory entry's `covered_by` list; `surface_ref` = every inventory-
|
|
@@ -101,7 +108,7 @@ canon query --kind scenario # no --plugin: byte-identi
|
|
|
101
108
|
(zero new files) and a genuine coverage edit supersedes the prior
|
|
102
109
|
overlay via latest-`at`-wins.
|
|
103
110
|
3. `canon plugin sync porting` writes/dedupes those candidates.
|
|
104
|
-
4. `canon query --kind scenario --plugin porting [--json]` projects
|
|
111
|
+
4. `canon query --kind scenario --plugin-id porting [--json]` projects
|
|
105
112
|
`covered`/`surface_ref` back onto each scenario.
|
|
106
113
|
|
|
107
114
|
`canon gate check`'s verdicts are byte-identical with and without a
|
|
@@ -69,15 +69,16 @@ statuses (see `canon-gate`).
|
|
|
69
69
|
## Approving the policy
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
|
-
canon policy approve --
|
|
72
|
+
canon policy approve --approver <who> [--note <text>] [--repo <dir>]
|
|
73
73
|
```
|
|
74
74
|
|
|
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
|
-
loop). `canon brief approve` records both in one call
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
loop). `canon brief approve` records both in one call. `canon policy
|
|
78
|
+
approve` is a human-only leaf: with a role declared (`--as` or `CANON_ROLE`)
|
|
79
|
+
it is refused with `HUMAN_ONLY` (exit 2, not retryable), and no flag grants
|
|
80
|
+
it to an agent. The human runs it themselves, for a policy-only change or
|
|
81
|
+
after the brief answer, supplying `--approver` and `--note`. It
|
|
81
82
|
writes `.canon/policy.approval.json` directly (nothing to promote):
|
|
82
83
|
|
|
83
84
|
```json
|
|
@@ -91,34 +92,37 @@ writes `.canon/policy.approval.json` directly (nothing to promote):
|
|
|
91
92
|
|
|
92
93
|
Commit it with the policy: the file is tracked, and neither canon's
|
|
93
94
|
`.gitignore` nor the one `canon init` writes ignores it. Running the
|
|
94
|
-
command again replaces the
|
|
95
|
-
|
|
95
|
+
command again replaces the one approval file (replay-safe). With no
|
|
96
|
+
`.canon/policy.yaml` it is
|
|
97
|
+
refused (exit `2`), and so is an empty `--approver`.
|
|
98
|
+
|
|
99
|
+
**Done when:** `canon policy show` reports `approval: approved` and
|
|
100
|
+
`canon gate check` no longer prints `policy not approved`.
|
|
96
101
|
|
|
97
102
|
While a policy exists with no approval, `canon gate check` prints after
|
|
98
103
|
its result:
|
|
99
104
|
|
|
100
105
|
```
|
|
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 --
|
|
106
|
+
advisory: policy not approved: .canon/policy.yaml has no approval record (.canon/policy.approval.json); a human reviews it and runs `canon policy approve --approver <who>`
|
|
102
107
|
```
|
|
103
108
|
|
|
104
109
|
Once the policy's bytes no longer match the approved digest, or the
|
|
105
110
|
approval file cannot be read, the gate fails closed instead:
|
|
106
111
|
|
|
107
112
|
```
|
|
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 --
|
|
113
|
+
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 --approver <human> --note "<words>"`, or restore the approved .canon/policy.yaml (and .canon/policy.approval.json) from git
|
|
109
114
|
```
|
|
110
115
|
|
|
111
|
-
`canon gate check` exits `1`; `canon subject
|
|
116
|
+
`canon gate check` exits `1`; `canon subject move` (the ship guard and
|
|
112
117
|
the reopen) refuses with `POLICY_CHANGED_SINCE_APPROVAL`, or
|
|
113
118
|
`POLICY_APPROVAL_UNREADABLE` for an unreadable approval, and
|
|
114
119
|
`--override-reason` does not waive either. A policy never approved stays
|
|
115
120
|
an advisory. `canon status` prints the same text as a `warning:` line (and
|
|
116
|
-
in `--json` `warnings`).
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
in `--json` `warnings`). The record names who approved which bytes and
|
|
122
|
+
the gate fails when that no longer holds, whoever ran `policy approve`.
|
|
123
|
+
An agent never edits the policy
|
|
119
124
|
to pass the gate: it stops and asks the human, who re-approves or restores
|
|
120
|
-
it.
|
|
121
|
-
never without one and never on its own behalf.
|
|
125
|
+
it.
|
|
122
126
|
|
|
123
127
|
## `canon policy show [--json]`
|
|
124
128
|
|
|
@@ -251,7 +255,7 @@ read as a big-endian u64, are less than `rate · 2^64` — computed exactly,
|
|
|
251
255
|
as a comparison against `ceil(rate · 2^64)`, so `rate: 0` samples nothing
|
|
252
256
|
and `rate: 1` samples everything. A sampled in-scope scenario whose
|
|
253
257
|
latest audit is missing or `indeterminate` is `uncovered-cell`; with
|
|
254
|
-
`shipped` in `scope`, `canon subject
|
|
258
|
+
`shipped` in `scope`, `canon subject move <id> --to shipped` also refuses
|
|
255
259
|
it. `canon context` and the `canon status` policy line show
|
|
256
260
|
`require_audit=(rate=… seed=`…` scope=…)`.
|
|
257
261
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# canon-report-dashboard
|
|
2
2
|
|
|
3
|
-
canon's single status surface: `canon report` renders TEN panels to
|
|
4
|
-
markdown, `canon report
|
|
3
|
+
canon's single status surface: `canon report build` renders TEN panels to
|
|
4
|
+
markdown, `canon report snapshot` exports the same ten marts to
|
|
5
5
|
Parquet, and `canon dashboard` serves a small zero-network web app that
|
|
6
6
|
renders SEVEN of them from such a snapshot. Neither surface computes an
|
|
7
7
|
aggregate itself — both read canon's precomputed
|
|
@@ -24,24 +24,24 @@ file to those literals. Copy a claim; do not paraphrase it.
|
|
|
24
24
|
|
|
25
25
|
`.canon/REPORT.md` carries a leading `<!-- GENERATED by \`canon report\` …
|
|
26
26
|
DO NOT EDIT. -->` comment. If it looks stale or wrong, the fix is
|
|
27
|
-
**always** re-running `canon report` (or fixing the underlying
|
|
27
|
+
**always** re-running `canon report build` (or fixing the underlying
|
|
28
28
|
ledger/policy it renders) — never hand-editing the file. The report
|
|
29
29
|
header embeds only input-derived digests (corpus hash, policy hash,
|
|
30
30
|
ledger-head hash) and **no timestamp, no `source_git_sha`**, so a
|
|
31
31
|
committed report is reproducible from named inputs and `canon report
|
|
32
|
-
|
|
33
|
-
only in
|
|
32
|
+
check` can byte-diff it deterministically. `source_git_sha` belongs
|
|
33
|
+
only in `report snapshot`'s `manifest.json` (below), which is never
|
|
34
34
|
drift-checked.
|
|
35
35
|
|
|
36
|
-
## `canon report [--repo <dir>]`
|
|
36
|
+
## `canon report build [--repo <dir>]`
|
|
37
37
|
|
|
38
38
|
Renders the current ten-panel report to `<repo>/.canon/REPORT.md`.
|
|
39
39
|
`--repo` resolves through the nearest-`canon.yaml`-ancestor walk every
|
|
40
40
|
subcommand uses — omit it (or pass `.`) to run from any subdirectory.
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
canon report
|
|
44
|
-
canon report --repo /path/to/repo
|
|
43
|
+
canon report build # writes .canon/REPORT.md
|
|
44
|
+
canon report build --repo /path/to/repo
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
Between the digest header and the first panel, the report may also
|
|
@@ -51,26 +51,35 @@ probe, and an empty set renders NO section at all — so a repo routing
|
|
|
51
51
|
nothing to a not-directly-readable backend renders exactly as before
|
|
52
52
|
the section existed.
|
|
53
53
|
|
|
54
|
-
|
|
54
|
+
**Done when:** `canon report build` exits `0` and `canon report check`
|
|
55
|
+
then exits `0` (no `DRIFT`).
|
|
56
|
+
|
|
57
|
+
## `canon report check` — the CI drift gate
|
|
55
58
|
|
|
56
59
|
Regenerates the report in memory and byte-compares it against the
|
|
57
60
|
committed `.canon/REPORT.md`:
|
|
58
61
|
|
|
59
|
-
- `MISSING` (exit 1) — no report has ever been written; run `canon report` first.
|
|
62
|
+
- `MISSING` (exit 1) — no report has ever been written; run `canon report build` first.
|
|
60
63
|
- no drift (exit 0) — the committed file is byte-identical to what the
|
|
61
64
|
current inputs would render now.
|
|
62
65
|
- `DRIFT` (exit 1) — the committed file disagrees with current inputs
|
|
63
66
|
(hand-edited, or the corpus/policy/ledger moved and nobody re-ran
|
|
64
|
-
`canon report`).
|
|
67
|
+
`canon report build`).
|
|
65
68
|
|
|
66
69
|
```bash
|
|
67
|
-
canon report
|
|
70
|
+
canon report check # wire into CI exactly like canon format / canon gate check
|
|
68
71
|
```
|
|
69
72
|
|
|
70
73
|
Wire it as a CI step or pre-push hook the same way `canon gate
|
|
71
|
-
install-hooks` wires `canon gate check`; run `canon report
|
|
74
|
+
install-hooks` wires `canon gate check`; run `canon report check`
|
|
72
75
|
directly wherever CI already runs those.
|
|
73
76
|
|
|
77
|
+
**Done when:** `canon report check` exits `0` in CI on the committed
|
|
78
|
+
`.canon/REPORT.md`; `DRIFT` or `MISSING` means run `canon report build`
|
|
79
|
+
and commit the result.
|
|
80
|
+
|
|
81
|
+
## `canon report snapshot <dir>`
|
|
82
|
+
|
|
74
83
|
Exports all ten views to `<dir>/<table>.parquet` plus a
|
|
75
84
|
`<dir>/manifest.json`. One explicit `COPY` per view — the exported
|
|
76
85
|
columns are each view's own `SELECT` list, wider than the curated column
|
|
@@ -107,9 +116,11 @@ corpus/policy/ledger digests the report header renders, so a snapshot's
|
|
|
107
116
|
provenance is comparable to a report's without re-deriving anything.
|
|
108
117
|
|
|
109
118
|
```bash
|
|
110
|
-
canon report
|
|
119
|
+
canon report snapshot /tmp/canon-snap
|
|
111
120
|
```
|
|
112
121
|
|
|
122
|
+
**Done when:** `<dir>/manifest.json` exists and lists the exported tables.
|
|
123
|
+
|
|
113
124
|
## `canon dashboard [--repo <dir>] [--snapshot <dir>] [--port <n>]`
|
|
114
125
|
|
|
115
126
|
Serves the dashboard web app locally, pointed at a real snapshot:
|
|
@@ -119,7 +130,7 @@ canon dashboard # regenerates a fresh snapshot every run,
|
|
|
119
130
|
canon dashboard --snapshot /tmp/canon-snap --port 8080
|
|
120
131
|
```
|
|
121
132
|
|
|
122
|
-
- `--snapshot` omitted: `canon dashboard` calls `canon report
|
|
133
|
+
- `--snapshot` omitted: `canon dashboard` calls `canon report snapshot`
|
|
123
134
|
itself every run, into the conventional `.canon/dashboard-snapshot`
|
|
124
135
|
scratch directory — always fresh.
|
|
125
136
|
- `--snapshot <dir>` given: served AS-IS when `<dir>` already has a
|
|
@@ -141,11 +152,11 @@ canon dashboard --snapshot /tmp/canon-snap --port 8080
|
|
|
141
152
|
`Approved:` line, or edited since) with its intent, outcome, flow steps,
|
|
142
153
|
acceptance, questions and assumptions, and its `canon brief check`
|
|
143
154
|
blockers and advisories. The human types their name and their answer and
|
|
144
|
-
clicks Approve: that records exactly what `canon brief approve
|
|
145
|
-
<id> --
|
|
155
|
+
clicks Approve: that records exactly what `canon brief approve
|
|
156
|
+
<id> --approver <name> --note <text>` records, the `Approved:` line bound to the
|
|
146
157
|
brief digest and the policy approval. It is refused when the brief changed
|
|
147
158
|
after the page loaded (`BRIEF_CHANGED_SINCE_PAGE_LOAD`: reload) or while it
|
|
148
|
-
has blockers (`
|
|
159
|
+
has blockers (`BRIEF_APPROVE_REFUSED`). The server is localhost only and
|
|
149
160
|
refuses requests from other origins (`DASHBOARD_ORIGIN_REFUSED`).
|
|
150
161
|
|
|
151
162
|
For an agent the human stop is unchanged: when clean briefs are waiting,
|
|
@@ -220,7 +231,7 @@ computes it; nothing here is derived a second time.
|
|
|
220
231
|
window down by `EvidenceRecord.verdict`. `divergence_open_running_total` is
|
|
221
232
|
a running `opened - resolved` event count, NOT the number open now —
|
|
222
233
|
the two differ whenever one `resolved` record closes several findings on a
|
|
223
|
-
scenario. For current state per scenario, run `canon divergence
|
|
234
|
+
scenario. For current state per scenario, run `canon divergence list`.
|
|
224
235
|
|
|
225
236
|
- **Scope status** (`mart_scope_status`) —
|
|
226
237
|
Every specified scenario × evidence-verified × plan-carried × spec-covered (`mart_scope_status`). Driven by the spec corpus, so a scenario no plan task declares still appears — with a NULL `task_id`, which is the worklist entry.
|
|
@@ -4,30 +4,30 @@
|
|
|
4
4
|
`canon-learn`) at task-dispatch time. It is a fail-soft, advisory-only
|
|
5
5
|
read: it NEVER blocks a dispatch and NEVER gates reproducibility.
|
|
6
6
|
|
|
7
|
-
## `canon retrieve --role <r> --regime <k> [--
|
|
7
|
+
## `canon retrieve --for-role <r> --regime <k> [--limit <n>] [--repo <dir>] [--json]`
|
|
8
8
|
|
|
9
9
|
Prints the top-`k` retrievable strategies stored for `regime_key = <k>`
|
|
10
10
|
(active strategies plus backward-compatible legacy rows without a lifecycle;
|
|
11
11
|
guardrails are just strategies distilled from a failure-polarity verdict),
|
|
12
|
-
newest-distilled first, capped at `--
|
|
12
|
+
newest-distilled first, capped at `--limit` (default 5). Demoted,
|
|
13
13
|
quarantined, rejected, and rolled-back rows are not retrievable.
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
canon retrieve --role dev --regime dev/canon/join-spine/9c93d024b1a2
|
|
17
|
-
canon retrieve --role dev --regime dev/canon/join-spine/9c93d024b1a2 --
|
|
16
|
+
canon retrieve --for-role dev --regime dev/canon/join-spine/9c93d024b1a2
|
|
17
|
+
canon retrieve --for-role dev --regime dev/canon/join-spine/9c93d024b1a2 --limit 3 --json
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
- `--regime` is the FULL `regime_key` string
|
|
21
21
|
(`<role>/<repo>/<area>/<hash>`) — the same serialization the write side
|
|
22
22
|
produces.
|
|
23
|
-
- Assembling `--regime` in a script or hook? Use `canon regime
|
|
24
|
-
--role <r> --repo <r> --area <a> --hash <h>`: it runs canon's ONE
|
|
23
|
+
- Assembling `--regime` in a script or hook? Use `canon regime show
|
|
24
|
+
--role-segment <r> --repo-name <r> --area <a> --hash <h>`: it runs canon's ONE
|
|
25
25
|
canonical `regime_key` serializer and prints the validated key, so a
|
|
26
26
|
caller routes through the exact normalizer the write path uses instead
|
|
27
27
|
of a drifting shell slug. Exits `2` with empty stdout on a malformed
|
|
28
28
|
result (empty segment / bad `<hash>`) — a clean fail-soft branch for
|
|
29
29
|
`|| exit 0` callers.
|
|
30
|
-
- `--role` MUST equal `--regime`'s leading segment — a mismatch is a
|
|
30
|
+
- `--for-role` MUST equal `--regime`'s leading segment — a mismatch is a
|
|
31
31
|
clean usage error, exit `2` (mirroring `canon gate check`'s
|
|
32
32
|
0-clean/1-red/2-usage convention), never a panic or a silently-ignored
|
|
33
33
|
mismatch.
|
|
@@ -36,7 +36,7 @@ canon retrieve --role dev --regime dev/canon/join-spine/9c93d024b1a2 --k 3 --jso
|
|
|
36
36
|
`canon.yaml` `learn:` section names the store root (`.canon/learn` by
|
|
37
37
|
default); a repo with no `canon.yaml` still works, defaulting cleanly.
|
|
38
38
|
|
|
39
|
-
**FAIL-SOFT, always exit `0`** once `--role`/`--regime` agree: a store
|
|
39
|
+
**FAIL-SOFT, always exit `0`** once `--for-role`/`--regime` agree: a store
|
|
40
40
|
outage, an empty/nonexistent store, or a malformed on-disk row all
|
|
41
41
|
degrade to an empty guidance list — never a nonzero exit or an error a
|
|
42
42
|
caller must handle.
|
|
@@ -46,8 +46,8 @@ caller must handle.
|
|
|
46
46
|
A generic, fail-soft, advisory-only shell script that fires at a
|
|
47
47
|
PreToolUse-equivalent point for a `task`-shaped dispatch (Claude Code's
|
|
48
48
|
`Task` tool / Codex's equivalent). It reads the tool's `subagent_type`
|
|
49
|
-
as `--role`, assembles `--regime` by routing its repo/area segments
|
|
50
|
-
through `canon regime
|
|
49
|
+
as `--for-role`, assembles `--regime` by routing its repo/area segments
|
|
50
|
+
through `canon regime show` (so it never re-derives the join key with a
|
|
51
51
|
drifting shell slug), calls `canon retrieve --json`, and emits the
|
|
52
52
|
result as a `PreToolUse` `hookSpecificOutput.additionalContext` JSON
|
|
53
53
|
envelope on stdout — Claude Code's convention for surfacing advisory
|
|
@@ -76,6 +76,9 @@ timeout}]}` entry into BOTH `<repo>/.claude/settings.json` and
|
|
|
76
76
|
`<repo>/.codex/hooks.json`, additive and idempotent — see the
|
|
77
77
|
`canon-gate` skill for `install-hooks`'s full contract.
|
|
78
78
|
|
|
79
|
+
**Done when:** the hook entry is in both `settings.json` and `hooks.json`;
|
|
80
|
+
running `canon gate install-hooks` again changes nothing.
|
|
81
|
+
|
|
79
82
|
## Replay vs. live retrieval
|
|
80
83
|
|
|
81
84
|
A run manifest records `injected_guidance` — a full SNAPSHOT (each entry
|