@journeykit/canon 0.26.0 → 0.27.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.
@@ -58,21 +58,19 @@ bytes no longer match the approved digest, or the approval cannot be read,
58
58
  the gate fails closed: the violation is reported and the exit is `1` (see
59
59
  `canon-policy`).
60
60
 
61
- Before it reads the scenario index, the gate rebuilds any stale part of
62
- it from the changed `.feature` files (the same code `canon inventory
63
- sync` runs) and says so in one stderr line, silent when the index is
64
- fresh:
65
-
66
- ```
67
- canon gate check: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
68
- ```
69
-
70
- A root that fails to sync (format violations, a duplicate id) is named
71
- instead, ending ``NOT refreshed: root `x` (N format violation(s), 0 sync
72
- error(s)) — `canon inventory sync` lists them``, and the gate fails
73
- closed: it adds `uncovered-cell <root> — the scenario index for spec root
74
- `<root>` is stale and could not be refreshed (…); `canon inventory sync`
75
- lists the problems to fix` and exits 1, since the index it would grade
61
+ The gate is a read command: it writes nothing. A scenario index that is
62
+ stale (a `.feature` file added, edited or deleted since the last sync) is
63
+ graded as the refresh would leave it, built in memory from the changed
64
+ files with the code `canon inventory sync` runs; the index on disk is
65
+ brought up to date by the next command that writes (`canon evidence add`,
66
+ `canon review add`, `canon subject status`) or by `canon inventory sync`.
67
+ It prints no refresh line.
68
+
69
+ A root that fails to sync (format violations, a duplicate id) cannot be
70
+ graded in memory either, and the gate fails closed: it adds
71
+ `uncovered-cell <root> — the scenario index for spec root `<root>` is
72
+ stale and could not be refreshed (…); `canon inventory sync` lists the
73
+ problems to fix` and exits 1, since the index it would grade
76
74
  does not hold the edits. The `verifying → shipped` guard refuses with
77
75
  the same violation, and `canon status` lists the sync as its only step.
78
76
  Fix what the sync lists and run the gate again. See `canon-storage`
@@ -6,21 +6,25 @@ records every downstream stage joins against.
6
6
 
7
7
  ## You rarely run it yourself
8
8
 
9
- Since 0.16 the commands that read the index refresh it first:
10
- `canon status`, `canon gate check`, `canon evidence add`,
11
- `canon review add` and `canon subject status` index added, edited and
12
- deleted `.feature` files themselves, with the same code this command runs,
13
- scoped to the changed files, and say so in one stderr line:
9
+ Since 0.16 the commands that read the index see added, edited and deleted
10
+ `.feature` files without a sync step. `canon evidence add`, `canon review
11
+ add` and `canon subject status` refresh the index on disk first, with the
12
+ same code this command runs, scoped to the changed files, and say so in one
13
+ stderr line:
14
14
 
15
15
  ```
16
- canon status: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
16
+ canon evidence add: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
17
17
  ```
18
18
 
19
+ `canon status` and `canon gate check` are read commands and write nothing:
20
+ they grade the index as that refresh would leave it, built in memory, and
21
+ print no line.
22
+
19
23
  So the working loop has no sync step and no `canon format` step: write the
20
24
  scenario (`canon scenario new` writes it format-clean) and run the next
21
25
  command. Run `canon inventory sync` when:
22
26
 
23
- - a reader prints `NOT refreshed` — a root has a format violation (a
27
+ - a command prints `NOT refreshed` — a root has a format violation (a
24
28
  hand-written `Feature:`/`Scenario:` header with no `# canon:` provenance
25
29
  comment, an emptied file, …) or a duplicate id, so its files were not
26
30
  indexed. `canon gate check` then fails (`uncovered-cell <root>`),
@@ -57,7 +61,7 @@ and the openspec source `canon init` wrote is removed only after every
57
61
  pointer brief is written and nothing unread is left under
58
62
  `openspec/changes/` (each unread directory is named).
59
63
 
60
- The reader's refresh treats a file as stale when its latest index
64
+ The refresh treats a file as stale when its latest index
61
65
  generation has another `source_digest` or `scenario_digest`. A
62
66
  generation written before 0.15 has no `scenario_digest`, so a repo that
63
67
  kept an old index gets it rewritten on the first read.
@@ -68,7 +72,7 @@ kept an old index gets it rewritten on the first read.
68
72
  author .feature corpus (canon scenario new)
69
73
  │
70
74
  ▼
71
- scenario index # refreshed by every reader; `canon inventory sync` rebuilds it
75
+ scenario index # refreshed by the writers; `canon inventory sync` rebuilds it
72
76
  │
73
77
  ▼
74
78
  canon review add # attests a review — see canon-inventory downstream / canon-gate
@@ -272,21 +272,27 @@ fails those commands (exit `1`), and `canon init --check-config` reports
272
272
 
273
273
  `canon inventory sync` materializes one `Scenario` record per
274
274
  `(project_id, scenario_id)` under `.canon/ledger/kind=scenario/`. The
275
- index is derived — a pure function of the `.feature` files — so the
276
- commands that read it rebuild it first: `canon gate check`, `canon
277
- status`, `canon subject status`, `canon review add` and `canon evidence
278
- add`. The index is stale when a `.feature` file holds a scenario with no
279
- live index record, or one whose recorded source digest differs from the
280
- file's current bytes, or when the index holds a scenario of a spec root
281
- that no `.feature` file of it declares any more. The reader then runs
282
- `canon inventory sync`'s code on the changed files (validation still
283
- covers the whole root) and prints one stderr line:
275
+ index is derived — a pure function of the `.feature` files. The index is
276
+ stale when a `.feature` file holds a scenario with no live index record,
277
+ or one whose recorded source digest differs from the file's current bytes,
278
+ or when the index holds a scenario of a spec root that no `.feature` file
279
+ of it declares any more.
280
+
281
+ The commands that write records (`canon subject status`, `canon review
282
+ add` and `canon evidence add`) rebuild a stale index on disk first: they
283
+ run `canon inventory sync`'s code on the changed files (validation still
284
+ covers the whole root) and print one stderr line:
284
285
 
285
286
  ```
286
- canon status: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
287
+ canon evidence add: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
287
288
  ```
288
289
 
289
- A deleted scenario is not erased: `canon inventory sync` — and a reader's
290
+ The commands that only read (`canon gate check`, `canon status`) write
291
+ nothing: they grade a stale index as the refresh would leave it, built in
292
+ memory, and print no refresh line. `canon query --kind scenario` and the
293
+ report panels read the index on disk as it is.
294
+
295
+ A deleted scenario is not erased: `canon inventory sync` — and a writer's
290
296
  refresh, identically — appends a tombstone, a new generation of its
291
297
  record with `removed: true`. The gate, `canon status`, `canon query` and
292
298
  the report panels then treat it as absent; re-adding the scenario writes
@@ -294,7 +300,7 @@ a live generation that supersedes the tombstone. A root that fails to
294
300
  sync writes no tombstone either.
295
301
 
296
302
  ```
297
- canon status: refreshed the scenario index from 1 scenario(s) no longer in any feature file (cart.pay.01): 1 record(s) written
303
+ canon evidence add: refreshed the scenario index from 1 scenario(s) no longer in any feature file (cart.pay.01): 1 record(s) written
298
304
  ```
299
305
 
300
306
  `canon inventory sync` and every refresh hold an OS file lock on
@@ -303,17 +309,16 @@ index one change twice; a refresh that waited checks staleness again and
303
309
  is silent if another run already did the work. The lock is released when
304
310
  its holder exits, however it exits, so it never goes stale; a writer
305
311
  gives up after 30 s with a message naming the file (`canon inventory
306
- sync` exits `2`; a reader skips the refresh and still runs).
312
+ sync` exits `2`; a writer's refresh is skipped and the command still runs).
307
313
 
308
314
  A fresh index prints nothing. A root that fails to sync (format
309
315
  violations, a duplicate id) is named and left as it was, and the command
310
316
  still runs; `canon gate check` then fails with `uncovered-cell <root>`,
311
317
  the `verifying → shipped` guard refuses, and `canon status` lists only
312
- `canon inventory sync`, while the reporting readers (`query`, `context`)
313
- keep only this line:
318
+ `canon inventory sync`:
314
319
 
315
320
  ```
316
- canon gate check: found the scenario index stale for 1 changed feature file(s) (…): 0 record(s) written; NOT refreshed: root `root` (2 format violation(s), 0 sync error(s)) — `canon inventory sync` lists them
321
+ canon evidence add: found the scenario index stale for 1 changed feature file(s) (…): 0 record(s) written; NOT refreshed: root `root` (2 format violation(s), 0 sync error(s)) — `canon inventory sync` lists them
317
322
  ```
318
323
 
319
324
  Nothing is written in a directory without `canon.yaml`. `canon inventory
@@ -21,11 +21,13 @@ authored in one place:
21
21
  adopt`.
22
22
  - **Scenarios**: the `@subject:<id>` tag on each Gherkin scenario,
23
23
  indexed onto `Scenario.subject_id` by the scenario index (rebuilt by
24
- `canon inventory sync`, and refreshed by every command that reads it).
24
+ `canon inventory sync`, and refreshed on disk by the commands that write
25
+ records; `canon status` and `canon gate check` read it as the refresh
26
+ would leave it, without writing).
25
27
  The Subject record carries no scenario list — the spec corpus is the
26
28
  only source, and the Subjects report panel, `spec_coverage.scope`, and
27
29
  the shipped gate all read it from there. To link a scenario, tag it;
28
- the next `canon status` or `canon gate check` indexes the tag. There is
30
+ the next `canon status` or `canon gate check` reads the tag. There is
29
31
  no subject-side command for it.
30
32
 
31
33
  ## The 4-step loop
@@ -609,9 +611,9 @@ uses, so status and the gate cannot disagree about a gap:
609
611
  unreadable one → `canon init --check-config`; a scenario tagged with a
610
612
  subject that has no record → `canon subject new <that id>`; no subject
611
613
  at all → `canon subject new`; subjects and `.feature` scenarios but no
612
- scenario records → `canon inventory sync` (status refreshes the index
613
- itself first, so this means the refresh refused on a format violation
614
- or a duplicate id, which the sync names). Then per subject, verifying
614
+ scenario records → `canon inventory sync` (status reads the index as a
615
+ refresh would leave it, so this means the refresh would be refused on a
616
+ format violation or a duplicate id, which the sync names). Then per subject, verifying
615
617
  first, then building, specced, proposed, shipped: an unapproved brief
616
618
  (building and later, and proposed once its change has a brief)
617
619
  → the human step below, which is then the subject's
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@journeykit/canon",
3
- "version": "0.26.0",
3
+ "version": "0.27.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.26.0",
34
- "@journeykit/canon-core-linux-x64": "0.26.0",
35
- "@journeykit/canon-core-win32-x64": "0.26.0"
33
+ "@journeykit/canon-core-darwin-arm64": "0.27.0",
34
+ "@journeykit/canon-core-linux-x64": "0.27.0",
35
+ "@journeykit/canon-core-win32-x64": "0.27.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^20.0.0",