@skill-map/spec 0.5.0 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,115 @@
1
1
  # Spec changelog
2
2
 
3
+ ## 0.6.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9a89124: Step 5.1 — Persist scan-result metadata in a new `scan_meta` table so
8
+ `loadScanResult` returns real values for `scope` / `roots` / `scannedAt` /
9
+ `scannedBy` / `adapters` / `stats.filesWalked` / `stats.filesSkipped` /
10
+ `stats.durationMs` instead of the synthetic envelope shipped at Step 4.7.
11
+
12
+ **Spec change (additive, minor)**:
13
+
14
+ - New `scan_meta` table in zone `scan_*`, single-row (CHECK `id = 1`).
15
+ Columns: `scope`, `roots_json`, `scanned_at`, `scanned_by_name`,
16
+ `scanned_by_version`, `scanned_by_spec_version`, `adapters_json`,
17
+ `stats_files_walked`, `stats_files_skipped`, `stats_duration_ms`.
18
+ `nodesCount` / `linksCount` / `issuesCount` are not stored — they are
19
+ derived from `COUNT(*)` of the sibling tables.
20
+ - Replaced atomically with the rest of `scan_*` on every `sm scan`.
21
+
22
+ **Runtime change**:
23
+
24
+ - New kernel migration `002_scan_meta.sql`.
25
+ - `IScanMetaTable` added to `src/kernel/adapters/sqlite/schema.ts` and
26
+ bound in `IDatabase`.
27
+ - `persistScanResult` writes the row (and deletes prior rows in the same
28
+ transaction).
29
+ - `loadScanResult` reads from `scan_meta` when the row exists; degrades
30
+ to the previous synthetic envelope when it does not (DB freshly
31
+ migrated, never scanned, or pre-5.1 snapshot).
32
+ - The Step 4.7 follow-up notes in `scan-load.ts` documenting the
33
+ synthetic envelope are simplified to describe both branches.
34
+
35
+ Test count: 151 → 154 (+3 covering meta round-trip, replace-all
36
+ single-row invariant, and synthetic-fallback on empty DB).
37
+
38
+ - 9a89124: Step 5.7 — Conformance coverage for the rename heuristic.
39
+
40
+ **Spec change (additive, minor)**:
41
+
42
+ - `spec/schemas/conformance-case.schema.json` gains
43
+ `setup.priorScans: Array<{ fixture, flags? }>` — an ordered list of
44
+ staging scans the runner executes BEFORE the main `invoke`. Each
45
+ step replaces every non-`.skill-map/` directory in the scope with
46
+ the named fixture and runs `sm scan` (with optional flags). The DB
47
+ persists across steps because `.skill-map/` is preserved between
48
+ swaps. After the last step, the runner copies the top-level
49
+ `fixture` and runs the case's `invoke`.
50
+
51
+ Required to express scenarios that need a prior snapshot (rename
52
+ heuristic, future incremental cases). The schema is purely
53
+ additive — every existing case keeps passing without modification.
54
+
55
+ - Two new conformance cases under `spec/conformance/cases/`:
56
+
57
+ - **`rename-high`** — moving a single file with identical body
58
+ triggers a high-confidence auto-rename. Asserts:
59
+ `stats.nodesCount === 1`, `stats.issuesCount === 0`,
60
+ `nodes[0].path === skills/bar.md`. Verifies the spec invariant
61
+ that high-confidence renames emit NO issue.
62
+ - **`orphan-detection`** — deleting a file with no replacement
63
+ emits exactly one `orphan` issue (severity `info`). Asserts the
64
+ `ruleId` and `severity` directly.
65
+
66
+ - Four new fixture directories under `spec/conformance/fixtures/`:
67
+ `rename-high-before/`, `rename-high-after/`,
68
+ `orphan-before/`, `orphan-after/`.
69
+
70
+ - `spec/conformance/coverage.md`: row I (Rename heuristic) flips
71
+ from `🔴 missing` to `🟢 covered`. Notes the medium / ambiguous
72
+ branches stay covered by `src/test/rename-heuristic.test.ts` for
73
+ now (assertion vocabulary in the schema is not rich enough to
74
+ express "the issues array contains an item with ruleId X and
75
+ data.confidence === 'medium'" — when the conformance schema gains
76
+ array-filter assertions, those branches can land here too).
77
+
78
+ **Runtime change**:
79
+
80
+ - `src/conformance/index.ts` runner: implements `setup.priorScans`.
81
+ Helper `replaceFixture(scope, specRoot, fixture)` clears every
82
+ top-level entry in the scope except `.skill-map/`, then copies the
83
+ named fixture on top. Used by both staging steps and the main
84
+ `fixture` phase.
85
+ - `src/test/conformance.test.ts`: includes the two new cases in the
86
+ Step-0b subset. Total conformance cases passing in CI: 1 → 3.
87
+
88
+ **`spec/index.json`** regenerated (50 → 57 files). `npm run spec:check`
89
+ green.
90
+
91
+ Test count: 201 → 203 (+2 conformance cases). The Step 5 totals close
92
+ at: 151 → 203 (+52 across 7 sub-steps).
93
+
94
+ ### Patch Changes
95
+
96
+ - dacd4d9: Move the auto-generated CLI reference from `docs/cli-reference.md` to
97
+ `context/cli-reference.md`. Spec change is editorial: `cli-contract.md`
98
+ references the file path in three spots (`--format md` description, the
99
+ NORMATIVE introspection section, and the "Related" link list); all three
100
+ updated to the new location. No schema or behavioural change.
101
+
102
+ Reference impl: `scripts/build-cli-reference.mjs` writes to the new path,
103
+ the `cli:reference` / `cli:check` npm scripts point there, and `sm help`
104
+ output (which embeds the path in the `--format md` flag description) is
105
+ regenerated. The `docs/` folder is gone.
106
+
107
+ ## 0.5.1
108
+
109
+ ### Patch Changes
110
+
111
+ - 18d758a: Editorial pass across spec/ and src/ docs: convert relative-path text references (e.g. `plugin-kv-api.md`, `schemas/node.schema.json`) to proper markdown links, so they resolve on GitHub and in renderers. No normative or behavioural changes — prose, schemas, and CLI contract are unchanged.
112
+
3
113
  ## 0.5.0
4
114
 
5
115
  ### Minor Changes
@@ -123,7 +233,7 @@
123
233
  - `issue.*`: `issue.added`, `issue.resolved` — emitted after `scan.completed` when the new scan's issue set differs from the previous one. Diff key: `(ruleId, nodeIds sorted, message)`.
124
234
  - Synthetic run ids follow the existing `r-<mode>-YYYYMMDD-HHMMSS-XXXX` pattern (`r-scan-...`, `r-check-...`) alongside `r-ext-...` for external Skill claims.
125
235
 
126
- These families ship at Step 12 of the reference impl alongside the WebSocket broadcaster. Marking them experimental keeps the shape mutable until real UI consumers exercise the stream; promotion to `stable` is a later minor bump.
236
+ These families ship at Step 13 of the reference impl alongside the WebSocket broadcaster. Marking them experimental keeps the shape mutable until real UI consumers exercise the stream; promotion to `stable` is a later minor bump.
127
237
 
128
238
  Classification: minor per §Pre-1.0. All additions are optional fields in a permissive config schema and new event types outside the stable job family — zero impact on existing implementations. Matching `ROADMAP.md` §Notable config keys and §Progress events updates land in the same change.
129
239
 
@@ -149,7 +259,7 @@
149
259
  - **Exempt** verbs (sub-millisecond, informational): `sm --version`, `sm --help`, `sm version`, `sm help`, `sm config get`, `sm config list`, `sm config show`.
150
260
  - Measurement spans from after arg-parsing to before terminal write.
151
261
  - **cli-contract.md** `sm history stats` entry: flags enumerated (`--since`, `--until`, `--period`, `--top`) and schema referenced.
152
- - **Coverage matrix**: row `29` for `history-stats.schema.json` (blocked by Step 4); artifact row `L` for the elapsed-time reporting invariant (blocked by Step 3).
262
+ - **Coverage matrix**: row `29` for `history-stats.schema.json` (blocked by Step 5); artifact row `L` for the elapsed-time reporting invariant (blocked by Step 4).
153
263
 
154
264
  Classification: minor per §Pre-1.0. The elapsed-time contract introduces a SHOULD-emit line that didn't exist before — no existing consumer breaks, and the line goes to stderr where it doesn't clash with stdout JSON.
155
265
 
@@ -225,7 +335,7 @@
225
335
 
226
336
  **Breaking (pre-1.0 minor per `versioning.md` §Pre-1.0):**
227
337
 
228
- - **Remove** `history.retentionDays`. The field promised execution-record GC, but `ROADMAP.md` §Step 6 and the job-retention section make it explicit that `state_executions` is append-only in `v0.1` and that the kernel does not use this key. Declaring a config key whose behaviour is "silently ignored" is worse than not declaring it — consumers would wire it in and never see an effect. The field will be re-introduced in a later minor bump when the GC path actually lands, with a concrete default and enforcement semantics.
338
+ - **Remove** `history.retentionDays`. The field promised execution-record GC, but `ROADMAP.md` §Step 7 and the job-retention section make it explicit that `state_executions` is append-only in `v0.1` and that the kernel does not use this key. Declaring a config key whose behaviour is "silently ignored" is worse than not declaring it — consumers would wire it in and never see an effect. The field will be re-introduced in a later minor bump when the GC path actually lands, with a concrete default and enforcement semantics.
229
339
 
230
340
  **Editorial:**
231
341
 
@@ -237,7 +347,7 @@
237
347
 
238
348
  - 93ffe34: Promote the trigger-normalization pipeline (Decision #21) from implicit to normative in `spec/architecture.md`.
239
349
 
240
- Before this change, `link.trigger` carried `originalTrigger` and `normalizedTrigger` fields (defined in `schemas/link.schema.json`), and the `trigger-collision` rule keyed on the normalized value — but no spec prose documented **how** to normalize. The pipeline lived only in `AGENTS.md §Decisions already locked` and in `ROADMAP.md` as a one-line Step 6 bullet. That left implementations free to diverge, which silently breaks the `trigger-collision` rule across implementations (two conforming CLIs could disagree on whether `hacer-review` and `Hacer Review` collide).
350
+ Before this change, `link.trigger` carried `originalTrigger` and `normalizedTrigger` fields (defined in `schemas/link.schema.json`), and the `trigger-collision` rule keyed on the normalized value — but no spec prose documented **how** to normalize. The pipeline lived only in `AGENTS.md §Decisions already locked` and in `ROADMAP.md` as a one-line Step 7 bullet. That left implementations free to diverge, which silently breaks the `trigger-collision` rule across implementations (two conforming CLIs could disagree on whether `hacer-review` and `Hacer Review` collide).
241
351
 
242
352
  Added under `architecture.md §Extension kinds`, paralleling the existing `Adapter · defaultRefreshAction` subsection:
243
353
 
@@ -390,7 +500,7 @@
390
500
  - Referenced in `conformance/README.md` (§"Cases explicitly referenced elsewhere in the spec"). Entry moved from "pending" to "current" in the case inventory.
391
501
  - Registered in `spec/index.json` and the integrity block (SHA256 regenerated).
392
502
 
393
- The second pending case, `preamble-bitwise-match`, is deferred to Step 9 (requires `sm job preview` from the job subsystem).
503
+ The second pending case, `preamble-bitwise-match`, is deferred to Step 10 (requires `sm job preview` from the job subsystem).
394
504
 
395
505
  - 4e0aec4: Initial public spec surface (`v0.1.0`):
396
506
 
package/README.md CHANGED
@@ -24,15 +24,15 @@ This document is the **source of truth**. The reference implementation under `..
24
24
  - Logging format, telemetry, or distribution channels.
25
25
  - Plugin marketplace mechanics.
26
26
 
27
- These are implementation decisions. The reference impl picks them (see `../CLAUDE.md` and `../ROADMAP.md`); other implementations may pick differently and still conform.
27
+ These are implementation decisions. The reference impl picks them (see [`../AGENTS.md`](../AGENTS.md) and [`../ROADMAP.md`](../ROADMAP.md)); other implementations may pick differently and still conform.
28
28
 
29
29
  ## Properties
30
30
 
31
31
  - **Machine-readable**: all domain shapes are JSON Schemas. Validate from any language that has a JSON Schema validator.
32
32
  - **Human-readable**: prose documents for each subsystem, with examples.
33
- - **Independently versioned**: spec `v1.0.0` can be implemented by CLI `v0.3.2`. See `versioning.md`.
33
+ - **Independently versioned**: spec `v1.0.0` can be implemented by CLI `v0.3.2`. See [`versioning.md`](./versioning.md).
34
34
  - **Platform-neutral**: no platform (Claude Code, Obsidian, …) is privileged. Each is expressed as an adapter extension.
35
- - **Conformance-tested**: every conforming implementation passes the suite under `conformance/`. Pass/fail is binary.
35
+ - **Conformance-tested**: every conforming implementation passes the suite under [`conformance/`](./conformance/README.md). Pass/fail is binary.
36
36
 
37
37
  ## Naming conventions
38
38
 
@@ -49,17 +49,17 @@ The SQL persistence layer is the sole exception: tables, columns, and migration
49
49
  spec/ ← published as @skill-map/spec
50
50
  ├── README.md ← this file
51
51
  ├── CHANGELOG.md ← spec history (independent from CLI)
52
- ├── versioning.md ← evolution policy
52
+ ├── [versioning.md](./versioning.md) ← evolution policy
53
53
  ├── package.json ← npm manifest for @skill-map/spec
54
54
  ├── index.json ← machine-readable manifest + per-file sha256 (generated)
55
55
 
56
- ├── architecture.md ← hexagonal ports & adapters
57
- ├── cli-contract.md ← verbs, flags, exit codes, JSON introspection
58
- ├── job-events.md ← canonical event stream schema
59
- ├── prompt-preamble.md ← canonical injection-mitigation preamble (verbatim normative)
60
- ├── db-schema.md ← table catalog (kernel-owned)
61
- ├── plugin-kv-api.md ← ctx.store contract for storage mode A
62
- ├── job-lifecycle.md ← queued → running → completed | failed
56
+ ├── [architecture.md](./architecture.md) ← hexagonal ports & adapters
57
+ ├── [cli-contract.md](./cli-contract.md) ← verbs, flags, exit codes, JSON introspection
58
+ ├── [job-events.md](./job-events.md) ← canonical event stream schema
59
+ ├── [prompt-preamble.md](./prompt-preamble.md) ← canonical injection-mitigation preamble (verbatim normative)
60
+ ├── [db-schema.md](./db-schema.md) ← table catalog (kernel-owned)
61
+ ├── [plugin-kv-api.md](./plugin-kv-api.md) ← ctx.store contract for storage mode A
62
+ ├── [job-lifecycle.md](./job-lifecycle.md) ← queued → running → completed | failed
63
63
 
64
64
  ├── schemas/ ← 29 JSON Schemas, draft 2020-12, camelCase keys
65
65
  │ ├── node.schema.json ┐
@@ -99,26 +99,27 @@ spec/ ← published as @skill-map/spec
99
99
  │ └── note.schema.json ┘
100
100
 
101
101
  ├── interfaces/
102
- │ └── security-scanner.md ← convention over the Action kind (NOT a 7th extension kind)
103
- └── conformance/
104
- ├── fixtures/ controlled MD corpora + preamble-v1.txt
105
- └── cases/ declarative test cases: basic-scan, kernel-empty-boot
106
- (preamble-bitwise-match deferred to ../ROADMAP.md Step 9)
102
+ │ └── [security-scanner.md](./interfaces/security-scanner.md) ← convention over the Action kind (NOT a 7th extension kind)
103
+ ├── [conformance/](./conformance/README.md)
104
+ ├── [coverage.md](./conformance/coverage.md) schema-to-case coverage matrix
105
+ │ ├── fixtures/ controlled MD corpora + preamble-v1.txt
106
+ │ └── cases/ ← declarative test cases: basic-scan, kernel-empty-boot
107
+ │ (preamble-bitwise-match deferred to ../ROADMAP.md Step 10)
107
108
  ```
108
109
 
109
110
  ## How to read this spec
110
111
 
111
- - **Building a tool or plugin that consumes skill-map output?** Start with `schemas/scan-result.schema.json` and `schemas/node.schema.json`.
112
- - **Building a custom detector, rule, or renderer?** Read `architecture.md`, then the relevant schema.
113
- - **Building an alternative CLI implementation?** Read `cli-contract.md` and run `conformance/`.
114
- - **Integrating a new platform (adapter)?** Read `architecture.md` §adapters, then the Claude adapter source in `../src/extensions/adapters/claude/` as a worked example.
115
- - **Shipping a job-running runner?** Read `job-events.md`, `job-lifecycle.md`, `prompt-preamble.md`.
112
+ - **Building a tool or plugin that consumes skill-map output?** Start with [`schemas/scan-result.schema.json`](./schemas/scan-result.schema.json) and [`schemas/node.schema.json`](./schemas/node.schema.json).
113
+ - **Building a custom detector, rule, or renderer?** Read [`architecture.md`](./architecture.md), then the relevant schema under [`schemas/extensions/`](./schemas/extensions/).
114
+ - **Building an alternative CLI implementation?** Read [`cli-contract.md`](./cli-contract.md) and run [`conformance/`](./conformance/README.md).
115
+ - **Integrating a new platform (adapter)?** Read [`architecture.md`](./architecture.md) §adapters, then the Claude adapter source in `../src/extensions/adapters/claude/` as a worked example.
116
+ - **Shipping a job-running runner?** Read [`job-events.md`](./job-events.md), [`job-lifecycle.md`](./job-lifecycle.md), [`prompt-preamble.md`](./prompt-preamble.md).
116
117
 
117
118
  ## Relationship to the reference implementation
118
119
 
119
- The reference implementation (`../src/`) is one conforming consumer of this spec. It ships the CLI binary `sm`, a built-in SQLite storage adapter, and a bundle of default extensions.
120
+ The reference implementation ([`../src/`](../src/README.md)) is one conforming consumer of this spec. It ships the CLI binary `sm`, a built-in SQLite storage adapter, and a bundle of default extensions.
120
121
 
121
- The reference impl has no privileged access to the spec. Breaking changes to the spec must follow `versioning.md` regardless of reference-impl convenience.
122
+ The reference impl has no privileged access to the spec. Breaking changes to the spec must follow [`versioning.md`](./versioning.md) regardless of reference-impl convenience.
122
123
 
123
124
  When spec and reference impl disagree, the spec wins. File an issue; one of them is wrong.
124
125
 
@@ -162,7 +163,7 @@ console.log(actual === index.integrity.files[file] ? 'ok' : 'drift');
162
163
 
163
164
  ### JSON Schema Store
164
165
 
165
- The schemas will be registered on JSON Schema Store once the canonical URLs under `skill-map.dev/spec/v0/` are stable (Step 13).
166
+ The schemas will be registered on JSON Schema Store once the canonical URLs under `skill-map.dev/spec/v0/` are stable (Step 14).
166
167
 
167
168
  ## License
168
169
 
package/architecture.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Normative description of skill-map's internal boundaries: the **kernel**, the **ports** it exposes, the **adapters** that drive and serve it, and the six **extension kinds** that live outside the kernel.
4
4
 
5
- Any conforming implementation — reference or third-party — MUST respect these boundaries. The conformance suite under `conformance/` enforces them.
5
+ Any conforming implementation — reference or third-party — MUST respect these boundaries. The conformance suite under [`conformance/`](./conformance/README.md) enforces them.
6
6
 
7
7
  ---
8
8
 
@@ -47,11 +47,11 @@ An implementation MUST expose these five ports. Each is an interface (TypeScript
47
47
 
48
48
  Persistence for all kernel tables in all three zones (`scan_*`, `state_*`, `config_*`). Exposes typed repositories, not raw SQL. Implementations MAY back this with SQLite, Postgres, in-memory, or anything else, as long as:
49
49
 
50
- - Transactional semantics for atomic claim (see `job-lifecycle.md`).
50
+ - Transactional semantics for atomic claim (see [`job-lifecycle.md`](./job-lifecycle.md)).
51
51
  - Migration application with `PRAGMA user_version`-equivalent tracking.
52
52
  - Read isolation sufficient to avoid phantom reads across a single scan write.
53
53
 
54
- The reference impl backs this with `node:sqlite` + Kysely + `CamelCasePlugin`.
54
+ The reference impl backs this with `node:sqlite` + Kysely + `CamelCasePlugin`. See [`db-schema.md`](./db-schema.md) for the full table catalog.
55
55
 
56
56
  ### `FilesystemPort`
57
57
 
@@ -77,13 +77,13 @@ Two reference implementations:
77
77
  - `ClaudeCliRunner` — subprocess `claude -p < jobfile`.
78
78
  - `MockRunner` — deterministic fake for tests.
79
79
 
80
- The **Skill agent** does NOT implement this port: it is a peer driving adapter (alongside CLI and Server) that runs inside an LLM session and consumes `sm job claim` + `sm record` as a kernel client. The name "Skill runner" is descriptive, not structural — only the `ClaudeCliRunner` (and its test fake) implement `RunnerPort`. See `job-lifecycle.md`.
80
+ The **Skill agent** does NOT implement this port: it is a peer driving adapter (alongside CLI and Server) that runs inside an LLM session and consumes `sm job claim` + `sm record` as a kernel client. The name "Skill runner" is descriptive, not structural — only the `ClaudeCliRunner` (and its test fake) implement `RunnerPort`. See [`job-lifecycle.md`](./job-lifecycle.md).
81
81
 
82
82
  ### `ProgressEmitterPort`
83
83
 
84
84
  Emits progress events during long operations (scans, job runs). Consumers: CLI pretty printer, `--json` ndjson, Server's WebSocket broadcaster.
85
85
 
86
- Operations: `emit(event)`, `subscribe(listener)`. Events are defined in `job-events.md`.
86
+ Operations: `emit(event)`, `subscribe(listener)`. Events are defined in [`job-events.md`](./job-events.md).
87
87
 
88
88
  ---
89
89
 
@@ -92,8 +92,8 @@ Operations: `emit(event)`, `subscribe(listener)`. Events are defined in `job-eve
92
92
  The kernel is the only component that:
93
93
  - Maintains the extension registry.
94
94
  - Runs the scan orchestrator.
95
- - Validates scan output against `scan-result.schema.json`.
96
- - Applies the canonical prompt preamble to job files (`prompt-preamble.md`).
95
+ - Validates scan output against [`scan-result.schema.json`](./schemas/scan-result.schema.json).
96
+ - Applies the canonical prompt preamble to job files ([`prompt-preamble.md`](./prompt-preamble.md)).
97
97
  - Enforces duplicate-prevention and atomic-claim invariants for jobs.
98
98
  - Persists execution records.
99
99
 
@@ -117,7 +117,7 @@ No extension is privileged. The Claude adapter ships bundled with the reference
117
117
 
118
118
  ## Extension kinds
119
119
 
120
- Six kinds, all first-class, all loaded through the same registry. Each kind has a JSON Schema describing its manifest shape under `spec/schemas/extensions/<kind>.schema.json`. Implementations MUST validate every extension manifest against the schema for its declared kind at load time; validation failure → the extension is skipped with status `invalid-manifest`.
120
+ Six kinds, all first-class, all loaded through the same registry. Each kind has a JSON Schema describing its manifest shape under [`schemas/extensions/`](./schemas/extensions/). Implementations MUST validate every extension manifest against the schema for its declared kind at load time; validation failure → the extension is skipped with status `invalid-manifest`.
121
121
 
122
122
  | Kind | Role | Input | Output |
123
123
  |---|---|---|---|
@@ -134,7 +134,7 @@ Every `Adapter` extension MUST declare a map `defaultRefreshAction: { <kind>: <a
134
134
 
135
135
  ### Detector · trigger normalization
136
136
 
137
- Detectors that emit invocation-style links (slashes, at-directives, command names) populate the `link.trigger` block defined in `schemas/link.schema.json`:
137
+ Detectors that emit invocation-style links (slashes, at-directives, command names) populate the `link.trigger` block defined in [`schemas/link.schema.json`](./schemas/link.schema.json):
138
138
 
139
139
  - `originalTrigger` — the exact source text the detector saw, byte-for-byte. Used only for display.
140
140
  - `normalizedTrigger` — the output of the pipeline below. Used for equality and collision detection — the built-in `trigger-collision` rule keys on this field.
@@ -171,7 +171,7 @@ Characters outside the separator set that are not letters or digits (e.g. `/`, `
171
171
 
172
172
  1. An extension declares its kind in its module export and its manifest. Kind mismatch → load-error.
173
173
  2. An extension MAY declare `preconditions` — predicates that must be satisfied for the extension to be offered (e.g., `action.requires: ["kind=skill"]`).
174
- 3. An extension MUST NOT retain state across invocations. Scoped persistence goes through `ctx.store` (storage mode `kv`) or the plugin's dedicated tables (`dedicated`).
174
+ 3. An extension MUST NOT retain state across invocations. Scoped persistence goes through `ctx.store` (storage mode `kv`) or the plugin's dedicated tables (`dedicated`). See [`plugin-kv-api.md`](./plugin-kv-api.md).
175
175
  4. An extension MUST NOT import another extension directly. Cross-extension communication goes through the kernel's registry lookup.
176
176
  5. An extension MUST provide a sibling test file. The reference impl treats a missing test as a contract-check failure; other impls MAY relax this to a warning.
177
177
 
@@ -248,6 +248,19 @@ This is what makes "CLI-first" a coherent rule: every CLI verb is a kernel funct
248
248
 
249
249
  ---
250
250
 
251
+ ## See also
252
+
253
+ - [`cli-contract.md`](./cli-contract.md) — verb surface of the CLI driving adapter.
254
+ - [`db-schema.md`](./db-schema.md) — table catalog backing `StoragePort`.
255
+ - [`job-lifecycle.md`](./job-lifecycle.md) — state machine for jobs, atomic claim, TTL/reap.
256
+ - [`job-events.md`](./job-events.md) — event stream emitted through `ProgressEmitterPort`.
257
+ - [`prompt-preamble.md`](./prompt-preamble.md) — canonical injection-mitigation preamble for job files.
258
+ - [`plugin-kv-api.md`](./plugin-kv-api.md) — `ctx.store` contract for extension persistence.
259
+ - [`versioning.md`](./versioning.md) — spec/impl version independence and semver policy.
260
+ - [`interfaces/security-scanner.md`](./interfaces/security-scanner.md) — convention over the Action kind for security scanners.
261
+
262
+ ---
263
+
251
264
  ## Stability
252
265
 
253
266
  The **port list** is stable as of spec v1.0.0. Adding a sixth port is a major bump.
package/cli-contract.md CHANGED
@@ -121,7 +121,7 @@ Exit: 0 if all green, 1 if warnings, 2 if any `error`-level problem.
121
121
  Self-describing introspection.
122
122
 
123
123
  - `human` (default): pretty terminal output.
124
- - `md`: canonical markdown for documentation sites. Implementations MUST NOT hand-maintain equivalent markdown; `docs/cli-reference.md` (in the reference impl) is regenerated from this output in CI.
124
+ - `md`: canonical markdown for documentation sites. Implementations MUST NOT hand-maintain equivalent markdown; `context/cli-reference.md` (in the reference impl) is regenerated from this output in CI.
125
125
  - `json`: structured surface dump. Shape:
126
126
 
127
127
  ```json
@@ -314,7 +314,7 @@ Destructive verbs (`reset --state`, `reset --hard`, `restore`) require interacti
314
314
  ### Introspection
315
315
 
316
316
  - `sm help --format json` — structured CLI surface dump.
317
- - `sm help --format md` — canonical markdown, CI-enforced for the reference impl's `docs/cli-reference.md`.
317
+ - `sm help --format md` — canonical markdown, CI-enforced for the reference impl's `context/cli-reference.md`.
318
318
 
319
319
  These two formats are NORMATIVE: any change to verbs, flags, or exit codes MUST reflect in `--format json` output immediately. Third-party consumers rely on this.
320
320
 
@@ -384,6 +384,17 @@ The `done in …` stderr line, its format grammar, and the `elapsedMs` field con
384
384
 
385
385
  ---
386
386
 
387
+ ## See also
388
+
389
+ - [`architecture.md`](./architecture.md) — CLI as a driving adapter; kernel-first design; dependency rules.
390
+ - [`job-lifecycle.md`](./job-lifecycle.md) — state machine behind `sm job` verbs.
391
+ - [`job-events.md`](./job-events.md) — event stream emitted via `--json` and `--stream-output`.
392
+ - [`db-schema.md`](./db-schema.md) — tables behind `sm db` verbs.
393
+ - [`../context/cli-reference.md`](../context/cli-reference.md) — auto-generated reference from `sm help --format md`.
394
+ - [`conformance/`](./conformance/README.md) — test suite exercising CLI behavior.
395
+
396
+ ---
397
+
387
398
  ## Stability
388
399
 
389
400
  The **verb list** is stable as of spec v1.0.0. Adding a verb is a minor bump. Removing a verb is a major bump.
@@ -2,7 +2,7 @@
2
2
 
3
3
  Language-neutral test suite the specification demands. A conforming implementation passes every case; failing any case is a conformance bug.
4
4
 
5
- This directory is **stub-level** as of spec v0.1.0. Two cases ship (`basic-scan`, `kernel-empty-boot`) with a single shared fixture (`minimal-claude`). The shape below is normative; the case count expands before spec-v1.0.0 (see `versioning.md`).
5
+ This directory is **stub-level** as of spec v0.1.0. Two cases ship (`basic-scan`, `kernel-empty-boot`) with a single shared fixture (`minimal-claude`). The shape below is normative; the case count expands before spec-v1.0.0 (see [`../versioning.md`](../versioning.md)). See [`coverage.md`](./coverage.md) for the full schema-to-case matrix.
6
6
 
7
7
  ---
8
8
 
@@ -33,7 +33,7 @@ Fixtures are read-only inputs. Cases declare what to invoke and what to assert.
33
33
 
34
34
  ## Case format
35
35
 
36
- Cases are validated against [`schemas/conformance-case.schema.json`](../schemas/conformance-case.schema.json). That file is the normative shape; this section is the human-readable walkthrough. Include `"$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json"` in every case file for IDE support.
36
+ Cases are validated against [`conformance-case.schema.json`](../schemas/conformance-case.schema.json). That file is the normative shape; this section is the human-readable walkthrough. Include `"$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json"` in every case file for IDE support.
37
37
 
38
38
  A case is a JSON document with this shape:
39
39
 
@@ -106,7 +106,7 @@ Cases explicitly referenced elsewhere in the spec (landing before v1.0):
106
106
 
107
107
  | Id | Source | Verifies |
108
108
  |---|---|---|
109
- | `preamble-bitwise-match` | `prompt-preamble.md` | Rendered job files contain `preamble-v1.txt` byte-for-byte. Deferred to Step 9 (requires `sm job preview`). |
109
+ | `preamble-bitwise-match` | `prompt-preamble.md` | Rendered job files contain `preamble-v1.txt` byte-for-byte. Deferred to Step 10 (requires `sm job preview`). |
110
110
 
111
111
  ---
112
112
 
@@ -132,6 +132,15 @@ The reference implementation's runner will ship under `src/conformance/` during
132
132
 
133
133
  ---
134
134
 
135
+ ## See also
136
+
137
+ - [`coverage.md`](./coverage.md) — schema-to-case coverage matrix and release gates.
138
+ - [`../versioning.md`](../versioning.md) — what constitutes a major/minor/patch change to the suite.
139
+ - [`../architecture.md`](../architecture.md) — kernel empty-boot invariant exercised by `kernel-empty-boot`.
140
+ - [`../prompt-preamble.md`](../prompt-preamble.md) — verbatim text checked by `preamble-bitwise-match` (deferred).
141
+
142
+ ---
143
+
135
144
  ## Stability
136
145
 
137
146
  - The **case format** above is stable as of the first spec release that includes the suite. Adding an assertion type is a minor bump. Removing or changing one is a major bump.
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
3
+ "id": "orphan-detection",
4
+ "description": "Deleting a file with no replacement triggers the orphan branch of the rename heuristic: exactly one issue with ruleId `orphan` is emitted, severity `info`, naming the dead path. The remaining survivor node is reported normally.",
5
+ "fixture": "orphan-after",
6
+ "setup": {
7
+ "priorScans": [
8
+ { "fixture": "orphan-before" }
9
+ ]
10
+ },
11
+ "invoke": {
12
+ "verb": "scan",
13
+ "flags": ["--changed", "--json"]
14
+ },
15
+ "assertions": [
16
+ { "type": "exit-code", "value": 0 },
17
+ { "type": "json-path", "path": "$.stats.nodesCount", "equals": 1 },
18
+ { "type": "json-path", "path": "$.stats.issuesCount", "equals": 1 },
19
+ { "type": "json-path", "path": "$.issues[0].ruleId", "equals": "orphan" },
20
+ { "type": "json-path", "path": "$.issues[0].severity", "equals": "info" }
21
+ ]
22
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
3
+ "id": "rename-high",
4
+ "description": "Moving a single file with identical body across the rename triggers a high-confidence auto-rename: NO issue is emitted (per spec/db-schema.md §Rename detection), the new path is the only node in the result, and the rename heuristic operates silently.",
5
+ "fixture": "rename-high-after",
6
+ "setup": {
7
+ "priorScans": [
8
+ { "fixture": "rename-high-before" }
9
+ ]
10
+ },
11
+ "invoke": {
12
+ "verb": "scan",
13
+ "flags": ["--changed", "--json"]
14
+ },
15
+ "assertions": [
16
+ { "type": "exit-code", "value": 0 },
17
+ { "type": "json-path", "path": "$.stats.nodesCount", "equals": 1 },
18
+ { "type": "json-path", "path": "$.stats.issuesCount", "equals": 0 },
19
+ { "type": "json-path", "path": "$.nodes[0].path", "equals": "skills/bar.md" }
20
+ ]
21
+ }
@@ -1,6 +1,6 @@
1
1
  # Conformance coverage
2
2
 
3
- Authoritative map of JSON Schemas in `spec/schemas/` to the conformance cases that exercise them. Every schema MUST have at least one case before spec v1.0.0 ships — missing case → missing release (AGENTS.md §Rules for AI agents editing spec/).
3
+ Authoritative map of JSON Schemas in [`../schemas/`](../schemas/) to the conformance cases that exercise them. Every schema MUST have at least one case before spec v1.0.0 ships — missing case → missing release ([`../../AGENTS.md`](../../AGENTS.md) §Rules for AI agents editing spec/).
4
4
 
5
5
  This file is hand-maintained. A CI check before spec release compares the schema inventory against this table and fails if any schema lacks a case.
6
6
 
@@ -12,10 +12,10 @@ This file is hand-maintained. A CI check before spec release compares the schema
12
12
  | 2 | `link.schema.json` | — | 🔴 missing | Needs fixture with at least one `invokes` + `references` + `mentions` link, both `high`/`medium`/`low` confidence. |
13
13
  | 3 | `issue.schema.json` | — | 🔴 missing | Needs fixture triggering `trigger-collision` + `broken-ref` + `superseded`. |
14
14
  | 4 | `scan-result.schema.json` | `basic-scan`, `kernel-empty-boot` | 🟢 covered | Zero-filled (empty-boot) + populated (minimal-claude) both asserted. |
15
- | 5 | `execution-record.schema.json` | — | 🔴 missing | Blocked by Step 4 (history). Needs a case that runs a `local` action and inspects `state_executions` via `sm history --json`. |
15
+ | 5 | `execution-record.schema.json` | — | 🔴 missing | Blocked by Step 5 (history). Needs a case that runs a `local` action and inspects `state_executions` via `sm history --json`. |
16
16
  | 6 | `project-config.schema.json` | — | 🔴 missing | Case: init a scope, write a partial `.skill-map.json`, assert effective config after merge. |
17
17
  | 7 | `plugins-registry.schema.json` | — | 🔴 missing | Two sub-cases required: (a) `PluginManifest` validation via `sm plugins show --json`; (b) aggregate `PluginsRegistry` via `sm plugins list --json`. |
18
- | 8 | `job.schema.json` | — | 🔴 missing | Blocked by Step 9 (job system). Needs a case that submits a local action (no LLM), inspects `sm job show --json`. |
18
+ | 8 | `job.schema.json` | — | 🔴 missing | Blocked by Step 10 (job system). Needs a case that submits a local action (no LLM), inspects `sm job show --json`. |
19
19
  | 9 | `report-base.schema.json` | — | 🔴 missing | Indirect coverage once any summarizer case lands. Direct contract case: validate a handcrafted minimal report ({confidence, safety}) against the base schema. |
20
20
  | 10 | `conformance-case.schema.json` | — | 🔴 missing | Self-referential: every `*.json` under `cases/` MUST validate against this schema. Add a meta-case that enumerates + validates all cases. |
21
21
  | 11 | `frontmatter/base.schema.json` | `basic-scan` (indirect) | 🟡 partial | Covered via every kind schema's `allOf`. Direct case: fixture with min-required frontmatter only. |
@@ -24,11 +24,11 @@ This file is hand-maintained. A CI check before spec release compares the schema
24
24
  | 14 | `frontmatter/command.schema.json` | `basic-scan` | 🟢 covered | One command in `minimal-claude`. |
25
25
  | 15 | `frontmatter/hook.schema.json` | `basic-scan` | 🟢 covered | One hook in `minimal-claude`. |
26
26
  | 16 | `frontmatter/note.schema.json` | `basic-scan` | 🟢 covered | One note in `minimal-claude`. |
27
- | 17 | `summaries/skill.schema.json` | — | 🔴 missing | Blocked by Step 9 (`skill-summarizer`). Case: submit summarizer, validate report. |
28
- | 18 | `summaries/agent.schema.json` | — | 🔴 missing | Blocked by Step 10. |
29
- | 19 | `summaries/command.schema.json` | — | 🔴 missing | Blocked by Step 10. |
30
- | 20 | `summaries/hook.schema.json` | — | 🔴 missing | Blocked by Step 10. |
31
- | 21 | `summaries/note.schema.json` | — | 🔴 missing | Blocked by Step 10. |
27
+ | 17 | `summaries/skill.schema.json` | — | 🔴 missing | Blocked by Step 10 (`skill-summarizer`). Case: submit summarizer, validate report. |
28
+ | 18 | `summaries/agent.schema.json` | — | 🔴 missing | Blocked by Step 11. |
29
+ | 19 | `summaries/command.schema.json` | — | 🔴 missing | Blocked by Step 11. |
30
+ | 20 | `summaries/hook.schema.json` | — | 🔴 missing | Blocked by Step 11. |
31
+ | 21 | `summaries/note.schema.json` | — | 🔴 missing | Blocked by Step 11. |
32
32
  | 22 | `extensions/base.schema.json` | — | 🔴 missing | Meta-case: every manifest under `src/extensions/` validates against the appropriate kind schema (which extends base via `allOf`). |
33
33
  | 23 | `extensions/adapter.schema.json` | — | 🔴 missing | Case: the `claude` adapter manifest validates; a crafted invalid manifest (missing `defaultRefreshAction`) fails with `invalid-manifest`. |
34
34
  | 24 | `extensions/detector.schema.json` | — | 🔴 missing | Case: `frontmatter` + `slash` + `at-directive` detector manifests validate; a detector emitting a disallowed `emitsLinkKinds` value fails. |
@@ -36,7 +36,7 @@ This file is hand-maintained. A CI check before spec release compares the schema
36
36
  | 26 | `extensions/action.schema.json` | — | 🔴 missing | Case: a `local` action manifest validates; an `invocation-template` action WITHOUT `promptTemplateRef` fails. |
37
37
  | 27 | `extensions/audit.schema.json` | — | 🔴 missing | Case: `validate-all` audit manifest validates; an audit referencing a non-existent rule id in `composes` fails at load with `invalid-manifest`. |
38
38
  | 28 | `extensions/renderer.schema.json` | — | 🔴 missing | Case: `ascii` renderer manifest validates. |
39
- | 29 | `history-stats.schema.json` | — | 🔴 missing | Blocked by Step 4 (history). Case: seed `state_executions` with a deterministic fixture, run `sm history stats --json --since <T0> --until <T1> --period month --top 5`, assert the document validates and that `totals.executionsCount == sum(perAction.executionsCount)` and `errorRates.global == totals.failedCount / totals.executionsCount`. Percentiles (`p95`/`p99`) intentionally omitted in v1 — add later as a minor bump without breaking consumers. |
39
+ | 29 | `history-stats.schema.json` | — | 🔴 missing | Blocked by Step 5 (history). Case: seed `state_executions` with a deterministic fixture, run `sm history stats --json --since <T0> --until <T1> --period month --top 5`, assert the document validates and that `totals.executionsCount == sum(perAction.executionsCount)` and `errorRates.global == totals.failedCount / totals.executionsCount`. Percentiles (`p95`/`p99`) intentionally omitted in v1 — add later as a minor bump without breaking consumers. |
40
40
 
41
41
  Status legend: 🟢 covered (at least one case asserts the schema end-to-end) · 🟡 partial (covered only indirectly or via a sub-shape) · 🔴 missing.
42
42
 
@@ -46,18 +46,18 @@ These have their own conformance cases even though they are not JSON Schemas.
46
46
 
47
47
  | # | Artifact | Case | Status | Notes |
48
48
  |---|---|---|---|---|
49
- | A | Preamble verbatim text | `preamble-bitwise-match` | 🟠 deferred | Deferred to Step 9 (needs `sm job preview` to render a job file). Fixture: `fixtures/preamble-v1.txt` (already present, byte-identical to `prompt-preamble.md` source). |
49
+ | A | Preamble verbatim text | `preamble-bitwise-match` | 🟠 deferred | Deferred to Step 10 (needs `sm job preview` to render a job file). Fixture: `fixtures/preamble-v1.txt` (already present, byte-identical to `prompt-preamble.md` source). |
50
50
  | B | Kernel empty-boot invariant | `kernel-empty-boot` | 🟢 covered | All extensions disabled → empty ScanResult. |
51
- | C | Atomic-claim race safety | — | 🔴 missing | Blocked by Step 9. Two concurrent `sm job claim` invocations against a single queued row — exactly one MUST succeed. |
52
- | D | Duplicate detection | — | 🔴 missing | Blocked by Step 9. Two `sm job submit` with same `(action, version, node, contentHash)` — second exits 3. |
53
- | E | `--force` bypass | — | 🔴 missing | Blocked by Step 9. |
54
- | F | Nonce mismatch | — | 🔴 missing | Blocked by Step 9. `sm record` with wrong nonce → exit 4. |
55
- | G | Reap | — | 🔴 missing | Blocked by Step 9. Set TTL to 1s; claim; wait; next `sm job run` reaps with reason `abandoned`. |
56
- | H | `run.*` event envelope for Skill agent | — | 🔴 missing | Blocked by Step 9. Skill-agent flow emits synthetic `r-ext-*` run envelope around one job. |
57
- | I | Rename heuristic | | 🔴 missing | Blocked by Step 4. Move a file; same-`body_hash` high-confidence auto-rename; `state_*` FK rows migrated; no issue emitted. |
58
- | J | Plugin DDL rejection | — | 🔴 missing | Blocked by Step 8. Plugin migration referencing `state_jobs` → disabled with `invalid-manifest`. |
59
- | K | Plugin prefix injection | — | 🔴 missing | Blocked by Step 8. Plugin declares `CREATE TABLE foo` → kernel applies as `plugin_<id>_foo`. |
60
- | L | Elapsed-time reporting | — | 🔴 missing | Blocked by Step 3 (first real verb work). Run any in-scope verb; stderr last line MUST match `/^done in (\d+ms\|\d+\.\d+s\|\d+m \d+s)$/`. In-scope verb with `--json` returning an object MUST carry `elapsedMs`. Exempt verb (`sm version`) MUST NOT emit the line. |
51
+ | C | Atomic-claim race safety | — | 🔴 missing | Blocked by Step 10. Two concurrent `sm job claim` invocations against a single queued row — exactly one MUST succeed. |
52
+ | D | Duplicate detection | — | 🔴 missing | Blocked by Step 10. Two `sm job submit` with same `(action, version, node, contentHash)` — second exits 3. |
53
+ | E | `--force` bypass | — | 🔴 missing | Blocked by Step 10. |
54
+ | F | Nonce mismatch | — | 🔴 missing | Blocked by Step 10. `sm record` with wrong nonce → exit 4. |
55
+ | G | Reap | — | 🔴 missing | Blocked by Step 10. Set TTL to 1s; claim; wait; next `sm job run` reaps with reason `abandoned`. |
56
+ | H | `run.*` event envelope for Skill agent | — | 🔴 missing | Blocked by Step 10. Skill-agent flow emits synthetic `r-ext-*` run envelope around one job. |
57
+ | I | Rename heuristic | `rename-high`, `orphan-detection` | 🟢 covered | High-confidence rename emits no issue and the new path is the sole node. Orphan branch emits exactly one `orphan` issue (severity `info`) when a deleted node has no replacement. Medium / ambiguous branches are exercised by `src/test/rename-heuristic.test.ts` until the conformance schema grows richer assertions. |
58
+ | J | Plugin DDL rejection | — | 🔴 missing | Blocked by Step 9. Plugin migration referencing `state_jobs` → disabled with `invalid-manifest`. |
59
+ | K | Plugin prefix injection | — | 🔴 missing | Blocked by Step 9. Plugin declares `CREATE TABLE foo` → kernel applies as `plugin_<id>_foo`. |
60
+ | L | Elapsed-time reporting | — | 🔴 missing | Blocked by Step 4 (first real verb work). Run any in-scope verb; stderr last line MUST match `/^done in (\d+ms\|\d+\.\d+s\|\d+m \d+s)$/`. In-scope verb with `--json` returning an object MUST carry `elapsedMs`. Exempt verb (`sm version`) MUST NOT emit the line. |
61
61
 
62
62
  ## Release gates
63
63
 
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: orphan-keep
3
+ description: Fixture node that survives across before/after, so the after-state still has at least one node.
4
+ metadata:
5
+ version: 1.0.0
6
+ stability: stable
7
+ author: conformance
8
+ ---
9
+
10
+ # Survivor
11
+
12
+ Keeps the after-state graph non-empty so we can assert that the orphan
13
+ issue is the only one emitted.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: orphan-keep
3
+ description: Fixture node that survives across before/after, so the after-state still has at least one node.
4
+ metadata:
5
+ version: 1.0.0
6
+ stability: stable
7
+ author: conformance
8
+ ---
9
+
10
+ # Survivor
11
+
12
+ Keeps the after-state graph non-empty so we can assert that the orphan
13
+ issue is the only one emitted.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: orphan-lonely
3
+ description: Fixture node that gets deleted in the after-state to trigger the orphan path.
4
+ metadata:
5
+ version: 1.0.0
6
+ stability: stable
7
+ author: conformance
8
+ ---
9
+
10
+ # Orphan lonely body
11
+
12
+ This file disappears in `orphan-after`. With no replacement matching
13
+ its hashes, the rename heuristic emits an `orphan` issue.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: rename-high-foo
3
+ description: Fixture node for the high-confidence rename conformance case.
4
+ metadata:
5
+ version: 1.0.0
6
+ stability: stable
7
+ author: conformance
8
+ ---
9
+
10
+ # Rename high body
11
+
12
+ Body content kept identical between the before and after fixtures so
13
+ the body hash matches across the rename. Move it to `bar.md` to trigger
14
+ a high-confidence auto-rename.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: rename-high-foo
3
+ description: Fixture node for the high-confidence rename conformance case.
4
+ metadata:
5
+ version: 1.0.0
6
+ stability: stable
7
+ author: conformance
8
+ ---
9
+
10
+ # Rename high body
11
+
12
+ Body content kept identical between the before and after fixtures so
13
+ the body hash matches across the rename. Move it to `bar.md` to trigger
14
+ a high-confidence auto-rename.
package/db-schema.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Database schema
2
2
 
3
- Normative catalog of tables owned by the kernel. Plugins MAY add their own tables under a strict prefix (see `plugin-kv-api.md`). An implementation MUST provision every kernel table described here and MUST reject writes that violate the stated constraints.
3
+ Normative catalog of tables owned by the kernel. Plugins MAY add their own tables under a strict prefix (see [`plugin-kv-api.md`](./plugin-kv-api.md)). An implementation MUST provision every kernel table described here and MUST reject writes that violate the stated constraints.
4
4
 
5
5
  The spec assumes a relational, SQL-like store but is **engine-agnostic**. The reference implementation uses SQLite (`node:sqlite`) + Kysely + `CamelCasePlugin`. Alternative backends (Postgres, DuckDB, in-memory) are permitted as long as:
6
6
 
7
- - Atomic single-statement transitions are available for the job claim (see `job-lifecycle.md`).
7
+ - Atomic single-statement transitions are available for the job claim (see [`job-lifecycle.md`](./job-lifecycle.md)).
8
8
  - Migrations track applied versions per scope.
9
9
  - Read isolation avoids phantom reads inside a single scan write.
10
10
 
@@ -67,7 +67,7 @@ Domain types exposed to driving adapters use `camelCase`. The SQLite reference i
67
67
 
68
68
  ### `scan_nodes`
69
69
 
70
- One row per detected node, matching `schemas/node.schema.json`.
70
+ One row per detected node, matching [`schemas/node.schema.json`](./schemas/node.schema.json).
71
71
 
72
72
  | Column | Type | Constraint | Notes |
73
73
  |---|---|---|---|
@@ -97,7 +97,7 @@ Indexes: `ix_scan_nodes_kind`, `ix_scan_nodes_adapter`, `ix_scan_nodes_body_hash
97
97
 
98
98
  ### `scan_links`
99
99
 
100
- One row per detected link, matching `schemas/link.schema.json`.
100
+ One row per detected link, matching [`schemas/link.schema.json`](./schemas/link.schema.json).
101
101
 
102
102
  | Column | Type | Constraint | Notes |
103
103
  |---|---|---|---|
@@ -118,7 +118,7 @@ Indexes: `ix_scan_links_source_path`, `ix_scan_links_target_path`, `ix_scan_link
118
118
 
119
119
  ### `scan_issues`
120
120
 
121
- One row per rule-emitted issue, matching `schemas/issue.schema.json`.
121
+ One row per rule-emitted issue, matching [`schemas/issue.schema.json`](./schemas/issue.schema.json).
122
122
 
123
123
  | Column | Type | Constraint | Notes |
124
124
  |---|---|---|---|
@@ -134,13 +134,35 @@ One row per rule-emitted issue, matching `schemas/issue.schema.json`.
134
134
 
135
135
  Indexes: `ix_scan_issues_rule_id`, `ix_scan_issues_severity`.
136
136
 
137
+ ### `scan_meta`
138
+
139
+ Single-row table holding the metadata of the last persisted scan. Lets `loadScanResult` return the real `scope` / `roots` / `scannedAt` / `scannedBy` / `adapters` / `stats.filesWalked|filesSkipped|durationMs` instead of synthesising them. Replaced atomically with the rest of the `scan_*` zone on every `sm scan`.
140
+
141
+ `nodesCount` / `linksCount` / `issuesCount` are not stored here — they derive from `COUNT(*)` of the sibling tables.
142
+
143
+ | Column | Type | Constraint |
144
+ |---|---|---|
145
+ | `id` | INTEGER | PRIMARY KEY, CHECK `id = 1` |
146
+ | `scope` | TEXT | NOT NULL, CHECK in (`project`, `global`) |
147
+ | `roots_json` | TEXT | NOT NULL | JSON array of strings (filesystem roots walked). |
148
+ | `scanned_at` | INTEGER | NOT NULL | Unix milliseconds. |
149
+ | `scanned_by_name` | TEXT | NOT NULL |
150
+ | `scanned_by_version` | TEXT | NOT NULL |
151
+ | `scanned_by_spec_version` | TEXT | NOT NULL |
152
+ | `adapters_json` | TEXT | NOT NULL | JSON array of adapter ids. |
153
+ | `stats_files_walked` | INTEGER | NOT NULL |
154
+ | `stats_files_skipped` | INTEGER | NOT NULL |
155
+ | `stats_duration_ms` | INTEGER | NOT NULL |
156
+
157
+ No indexes (single row).
158
+
137
159
  ---
138
160
 
139
161
  ## Table catalog: zone `state_`
140
162
 
141
163
  ### `state_jobs`
142
164
 
143
- Matching `schemas/job.schema.json`.
165
+ Matching [`schemas/job.schema.json`](./schemas/job.schema.json). See [`job-lifecycle.md`](./job-lifecycle.md) for the state machine and transitions.
144
166
 
145
167
  | Column | Type | Constraint |
146
168
  |---|---|---|
@@ -166,7 +188,7 @@ Indexes: `ix_state_jobs_status`, `ix_state_jobs_action_node_hash` (unique partia
166
188
 
167
189
  ### `state_executions`
168
190
 
169
- Matching `schemas/execution-record.schema.json`.
191
+ Matching [`schemas/execution-record.schema.json`](./schemas/execution-record.schema.json).
170
192
 
171
193
  | Column | Type | Constraint |
172
194
  |---|---|---|
@@ -192,7 +214,7 @@ Indexes: `ix_state_executions_extension_id`, `ix_state_executions_started_at`, `
192
214
 
193
215
  ### `state_summaries`
194
216
 
195
- One row per `(node_id, summarizer_action_id)`. See `schemas/summaries/`.
217
+ One row per `(node_id, summarizer_action_id)`. See [`schemas/summaries/`](./schemas/summaries/).
196
218
 
197
219
  | Column | Type | Constraint |
198
220
  |---|---|---|
@@ -223,7 +245,7 @@ Primary key: `(node_id, provider_id)`. Indexes: `ix_state_enrichments_stale_afte
223
245
 
224
246
  ### `state_plugin_kvs`
225
247
 
226
- Shared key-value store for plugins that declared storage mode `kv`. See `plugin-kv-api.md` for the accessor contract.
248
+ Shared key-value store for plugins that declared storage mode `kv`. See [`plugin-kv-api.md`](./plugin-kv-api.md) for the accessor contract.
227
249
 
228
250
  | Column | Type | Constraint |
229
251
  |---|---|---|
@@ -294,11 +316,11 @@ The kernel ALSO maintains `PRAGMA user_version` (or the engine equivalent) as a
294
316
 
295
317
  ## Plugin storage
296
318
 
297
- Two modes declared in `plugin.json` (see `schemas/plugins-registry.schema.json`).
319
+ Two modes declared in `plugin.json` (see [`schemas/plugins-registry.schema.json`](./schemas/plugins-registry.schema.json)).
298
320
 
299
321
  | Mode | Manifest | Backing |
300
322
  |---|---|---|
301
- | **KV** (mode A) | `"storage": { "mode": "kv" }` | Shared `state_plugin_kvs`. See `plugin-kv-api.md`. |
323
+ | **KV** (mode A) | `"storage": { "mode": "kv" }` | Shared `state_plugin_kvs`. See [`plugin-kv-api.md`](./plugin-kv-api.md). |
302
324
  | **Dedicated** (mode B) | `"storage": { "mode": "dedicated", "tables": [...], "migrations": [...] }` | Plugin-owned tables, prefixed `plugin_<normalized_id>_`. |
303
325
 
304
326
  Normalization of `plugin_id` for the prefix:
@@ -386,6 +408,15 @@ Failures are reported with suggested remediation (e.g., "run `sm db migrate`", "
386
408
 
387
409
  ---
388
410
 
411
+ ## See also
412
+
413
+ - [`architecture.md`](./architecture.md) — `StoragePort` interface definition and dependency rules.
414
+ - [`plugin-kv-api.md`](./plugin-kv-api.md) — `ctx.store` accessor for mode A / mode B persistence.
415
+ - [`job-lifecycle.md`](./job-lifecycle.md) — atomic claim and TTL/reap semantics that drive `state_jobs`.
416
+ - [`cli-contract.md`](./cli-contract.md) — `sm db` verb surface (reset, backup, restore, migrate).
417
+
418
+ ---
419
+
389
420
  ## Stability
390
421
 
391
422
  The **three-zone model** and the **naming conventions** are stable as of spec v1.0.0. Adding a fourth zone is a major bump.
package/index.json CHANGED
@@ -190,31 +190,38 @@
190
190
  }
191
191
  ]
192
192
  },
193
- "specPackageVersion": "0.5.0",
193
+ "specPackageVersion": "0.6.0",
194
194
  "integrity": {
195
195
  "algorithm": "sha256",
196
196
  "files": {
197
- "CHANGELOG.md": "adf0e49a213a8996cc2689749c47f2ed27cb9d31b40c18cece07b6d6ef94cd28",
198
- "README.md": "a233e6b5ab1c41c13cb4790485f0514f7c111880eb70165e77e1253999069120",
199
- "architecture.md": "be4085b7bbb3476f8a9d6df940b5794839b936ac5dd1921203a91558b008c7bc",
200
- "cli-contract.md": "7657b6e60089afdd3644e7e38d96593158349259ab105d76199ce5eb65993cae",
201
- "conformance/README.md": "4e41ff823b55ce3c274a033c5152ae0b2759fc714a714d7815593d8be84c8a4c",
197
+ "CHANGELOG.md": "e74921b61ca835c4ebc8f2a4814d2c9513a59ce47c8c719b4d17865b39d93cba",
198
+ "README.md": "8bd57e02d9a9d3f0a4efd18c0f0bd1f4bbe13eb206add0317659e48eab435e7e",
199
+ "architecture.md": "99f9d6a1a90e6c96d3c8a6f36c2650da4a1af0a1bc21173ea8eb2c492008539a",
200
+ "cli-contract.md": "bab14bb72ddd8a57e00808f7f12741c63a33da99055b278e4407ab9b4bb7e2c1",
201
+ "conformance/README.md": "79c5e63f18a368951dc9f3e31e9bf9574de3f8b97150b2d75365d4febd8eb6dc",
202
202
  "conformance/cases/basic-scan.json": "24623da0cad8c8c54b3ff9b09820ea1276fe8b8f0fc680bf6e8abeb4edb8e424",
203
203
  "conformance/cases/kernel-empty-boot.json": "175524674b14d993d29f10080d7697074b3a2eee25b359ff903344d73c6acc98",
204
- "conformance/coverage.md": "405a7ee093d6e54993ec5d9e061489f8b924829c7688fe56951bebf87abb2fae",
204
+ "conformance/cases/orphan-detection.json": "7fea6e866d775d09cadb70ccd764f6c8317ca61316c6d187a97cb2466db4e19e",
205
+ "conformance/cases/rename-high.json": "f23513893e25fc4259db06a497906137de981da775d8ab2ef262554d54af5f27",
206
+ "conformance/coverage.md": "a67fb38c69765bb3cafb78c75e211c530ab00a88d8ccf0254335d3b6d4f69b8d",
205
207
  "conformance/fixtures/minimal-claude/agents/reviewer.md": "d0dd681ba63838301e480116aa09825329f01832b0116de5c5476fdd8a5dcf54",
206
208
  "conformance/fixtures/minimal-claude/commands/status.md": "3f36e053fd1c059ffd902f84a55be8a458c26072f97cb37dd7e97314ae2a9bf5",
207
209
  "conformance/fixtures/minimal-claude/hooks/pre-commit.md": "ec9cec8ac4ce34d40ec055ffd90e8f06ea3e5764d6ec3ee84e0d97de71b930c7",
208
210
  "conformance/fixtures/minimal-claude/notes/architecture.md": "5a7e6fdbb1556733dacebad63758057dc1e19090b5a983292c0c65e90b98bcf1",
209
211
  "conformance/fixtures/minimal-claude/skills/hello.md": "8598074020430f294ff1eac39876302448f004b6c48446d453092159319bcbee",
212
+ "conformance/fixtures/orphan-after/skills/keep.md": "a6fdc33104cb2e8092f386a427784685eee1c8d7cb8fddb934cf65984143c7fd",
213
+ "conformance/fixtures/orphan-before/skills/keep.md": "a6fdc33104cb2e8092f386a427784685eee1c8d7cb8fddb934cf65984143c7fd",
214
+ "conformance/fixtures/orphan-before/skills/lonely.md": "4ba2bb336fa46644d2b0dfef4c3b97879ecbf693b825a5348f032d1af049d80a",
210
215
  "conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
211
- "db-schema.md": "17de515904b8869ea0fe8d3cd608423376396bed6281b784ee1670f184d29f2c",
212
- "interfaces/security-scanner.md": "468f8ee412594b14b389c36cefa9ca75a5dec652adbf03ab8bbc7f57ca980253",
213
- "job-events.md": "090733b47dc0bbe62d790a87a29f2a13fe1dbcb9d6a89ea16e1ecff2293e3972",
214
- "job-lifecycle.md": "793d34de0793596be17d2ed9042eeb4d532e805bceee25d9f9da0c3cb0b34b1c",
215
- "plugin-kv-api.md": "fe0c02dcc7eaee0ad711f16247df076fa62348710ee1088e1234764dd3cec82e",
216
- "prompt-preamble.md": "9b7478ddce0a77043983f35932677d702319348048fe5d6b1c60257bd1c9f605",
217
- "schemas/conformance-case.schema.json": "2740874e00269de6d8121300339401d0283197b6d97dcd77538ec5d108b14de2",
216
+ "conformance/fixtures/rename-high-after/skills/bar.md": "16f7678829c7702f8ebaeef920a891756da198466a1884badd8d8b4a7d1bab6a",
217
+ "conformance/fixtures/rename-high-before/skills/foo.md": "16f7678829c7702f8ebaeef920a891756da198466a1884badd8d8b4a7d1bab6a",
218
+ "db-schema.md": "e9b436b143e2e56985c69498c7d48527bde0baa441be586e2740a4051b366c2d",
219
+ "interfaces/security-scanner.md": "81dc3dc2c439a75f4603b6d52e714f44ac564032c8aa424385ebbf4502adae3e",
220
+ "job-events.md": "08796b7fbeb55e5b03cf3bc394224e70a23438a4d15a46ad1d70121c2c68b967",
221
+ "job-lifecycle.md": "1fe88b1a2ed204e41bb41ac172fbb3e912dccd0dd8a1f8ea8e21a681b336d6ee",
222
+ "plugin-kv-api.md": "04b2178f46fb88adeae9240df9c9e1761b660396072001dac32cd402e11a2d7d",
223
+ "prompt-preamble.md": "23a8eff0477fbbc46192a27781bc781bda4202bb9c669b7a7a002b0d668146b0",
224
+ "schemas/conformance-case.schema.json": "d69c501bbca079da0ca87685eb4cbdbc2e405334469fc937929ca9134e01a2b3",
218
225
  "schemas/execution-record.schema.json": "ec0f3acf1d0ce099c059d73eb434936bfd1bcf12023693bd572efb2a7352faa6",
219
226
  "schemas/extensions/action.schema.json": "c7520d3cefecf75d27d3e04473821fd6e5dc5a7924eede147f74275ba6caccad",
220
227
  "schemas/extensions/adapter.schema.json": "429b865e738664bb437ac62690a2d7282ce992339fbb300417c73625f5cdb7c8",
@@ -243,7 +250,7 @@
243
250
  "schemas/summaries/hook.schema.json": "36f876f3b1a60d45be97a0848c79fd18744b434dfdcefc366f033b253d56268c",
244
251
  "schemas/summaries/note.schema.json": "ae510f3ee1b6092c1061625e425c9bb7de9c9caa3f3774770c148f658d505753",
245
252
  "schemas/summaries/skill.schema.json": "f01bab92c51d64ee23e61587e42cf0dc5b37a2f518f5b12b3d1d456390338aa8",
246
- "versioning.md": "76a38d6b7e245a80274173a3cef791a04432e6ae3017ea3f66d7a37eb550fccf"
253
+ "versioning.md": "996e62006423edc01151a6f7869605f76c5e1454cc30b38d9f616925b5bcfb64"
247
254
  }
248
255
  }
249
256
  }
@@ -10,7 +10,7 @@ Normative contract for third-party security-scanning plugins (Snyk, Socket, cust
10
10
 
11
11
  ## Why a convention, not a new kind
12
12
 
13
- The six extension kinds are locked (`architecture.md`). Adding a seventh for "security" would conflate concerns: scanners are really actions that produce a specialized report. A convention lets any Action opt into the scanner surface without kernel changes.
13
+ The six extension kinds are locked ([`architecture.md`](../architecture.md)). Adding a seventh for "security" would conflate concerns: scanners are really actions that produce a specialized report. A convention lets any Action opt into the scanner surface without kernel changes.
14
14
 
15
15
  ---
16
16
 
@@ -55,7 +55,7 @@ Scanners are **local-mode** Actions by default: no LLM involvement. The Action r
55
55
 
56
56
  ## Output: the `SecurityReport` shape
57
57
 
58
- Every scanner MUST produce a report conforming to this shape. It extends `report-base.schema.json` with scanner-specific fields.
58
+ Every scanner MUST produce a report conforming to this shape. It extends [`report-base.schema.json`](../schemas/report-base.schema.json) with scanner-specific fields.
59
59
 
60
60
  ```jsonc
61
61
  {
@@ -156,7 +156,7 @@ Vendors MAY introduce their own category with the prefix `vendor:<slug>` (e.g. `
156
156
  ## Runtime model
157
157
 
158
158
  - Scanners are invoked through the standard job system: `sm job submit security-snyk -n <node.path>` or `sm job submit security-snyk --all`.
159
- - The report is persisted through the normal action report mechanism (`state_executions.report_path` points to the JSON file).
159
+ - The report is persisted through the normal action report mechanism ([`state_executions`](../db-schema.md)`.report_path` points to the JSON file).
160
160
  - `sm findings --security` aggregates findings from reports whose action id starts with `security-`, merging across scanners, deduplicating by `finding.id`.
161
161
  - Implementations MAY also surface findings at scan time via a companion Rule (e.g. `security-findings-stale` flags nodes whose last security scan is older than a threshold). This is recommended but not normative.
162
162
 
@@ -202,7 +202,7 @@ The Web UI's Security panel:
202
202
 
203
203
  ## Schema file location
204
204
 
205
- The JSON Schema for `SecurityReport` lives at `spec/schemas/summaries/security.schema.json` once Step 3 of the spec bootstrap completes. Until then, this document is the normative source and vendors SHOULD derive their own validator from it.
205
+ The JSON Schema for `SecurityReport` lives at `spec/schemas/summaries/security.schema.json` once Step 4 of the spec bootstrap completes. Until then, this document is the normative source and vendors SHOULD derive their own validator from it.
206
206
 
207
207
  This is the only `summaries/*` schema that does NOT correspond to a node kind; it corresponds to an action category instead.
208
208
 
@@ -216,6 +216,15 @@ A scanner that produces a report NOT conforming to `SecurityReport` is still a v
216
216
 
217
217
  ---
218
218
 
219
+ ## See also
220
+
221
+ - [`../architecture.md`](../architecture.md) — extension kinds (Action) and the kernel contract.
222
+ - [`../job-lifecycle.md`](../job-lifecycle.md) — job submit/claim/record flow for scanner invocations.
223
+ - [`../prompt-preamble.md`](../prompt-preamble.md) — `report-base` shape (safety + confidence) that scanner reports extend.
224
+ - [`../db-schema.md`](../db-schema.md) — `state_executions` where scanner reports are persisted.
225
+
226
+ ---
227
+
219
228
  ## Stability
220
229
 
221
230
  **Stability: experimental** as of spec v0.x. Field names and conventions MAY tighten before v1.0 once real scanner implementations (Snyk, Socket, custom) ship and reveal shape needs.
package/job-events.md CHANGED
@@ -8,7 +8,7 @@ This document is **normative**. The set of event types, their payload shapes, an
8
8
 
9
9
  ## Transport
10
10
 
11
- Events are records produced by the kernel through `ProgressEmitterPort` (see `architecture.md`). An implementation MUST provide three output adapters:
11
+ Events are records produced by the kernel through `ProgressEmitterPort` (see [`architecture.md`](./architecture.md)). An implementation MUST provide three output adapters:
12
12
 
13
13
  | Adapter | Purpose | Format |
14
14
  |---|---|---|
@@ -254,7 +254,7 @@ Emitted when a job transitions to `failed` by any path.
254
254
  }
255
255
  ```
256
256
 
257
- `reason` enum matches `execution-record.failureReason`. `message` is human-readable free-form; MAY be truncated for display.
257
+ `reason` enum matches [`execution-record.schema.json`](./schemas/execution-record.schema.json) `failureReason`. `message` is human-readable free-form; MAY be truncated for display.
258
258
 
259
259
  ### `run.summary`
260
260
 
@@ -308,7 +308,7 @@ A parallel implementation MAY interleave per-job sequences across different `job
308
308
 
309
309
  These event families cover kernel activity other than job execution. They share the common envelope (`type`, `timestamp`, `runId`, `jobId`, `data`). For non-job events `jobId` is always `null`; `runId` identifies the invocation that produced the event — a scan gets an `r-scan-YYYYMMDD-HHMMSS-XXXX` id, an issue recomputation outside a scan gets an `r-check-...` id, following the same `r-<mode>-...` shape as the external-Skill synthetic envelope (`r-ext-...`).
310
310
 
311
- The **shapes below are experimental through spec v0.x**. The reference impl starts emitting them at Step 12 alongside the WebSocket broadcaster; once real consumers exercise the stream, the fields lock. Bumping them to `stable` is a minor spec bump; changes to field shapes before `stable` are allowed without a major bump (per `versioning.md` §Pre-1.0).
311
+ The **shapes below are experimental through spec v0.x**. The reference impl starts emitting them at Step 13 alongside the WebSocket broadcaster; once real consumers exercise the stream, the fields lock. Bumping them to `stable` is a minor spec bump; changes to field shapes before `stable` are allowed without a major bump (per [`versioning.md`](./versioning.md) §Pre-1.0).
312
312
 
313
313
  ### Scan events
314
314
 
@@ -429,6 +429,14 @@ Consumers MAY treat `emitter.error` as a soft failure (log and continue). Implem
429
429
 
430
430
  ---
431
431
 
432
+ ## See also
433
+
434
+ - [`architecture.md`](./architecture.md) — `ProgressEmitterPort` definition.
435
+ - [`job-lifecycle.md`](./job-lifecycle.md) — state machine that drives these events.
436
+ - [`cli-contract.md`](./cli-contract.md) — `--json` and `--stream-output` flag semantics.
437
+
438
+ ---
439
+
432
440
  ## Stability
433
441
 
434
442
  The **job event type list** (`run.*`, `job.*`, `model.delta`, `emitter.error`) is stable as of spec v1.0.0. Adding a new event type is a minor bump. Removing or renaming one is a major bump.
@@ -439,4 +447,4 @@ Consumers MUST ignore unknown fields (forward compatibility).
439
447
 
440
448
  The envelope (`type`, `timestamp`, `runId`, `jobId`, `data`) is stable. Adding an envelope field is a major bump because every consumer would need to handle it.
441
449
 
442
- The **non-job event families** (`scan.*`, `issue.*`) are marked **experimental** across spec v0.x. They ship alongside the WebSocket broadcaster at Step 12 of the reference impl; shapes may tighten before a stable tag lands. Once promoted to `stable` (a minor spec bump), the same add/remove/rename semantics as the job events apply.
450
+ The **non-job event families** (`scan.*`, `issue.*`) are marked **experimental** across spec v0.x. They ship alongside the WebSocket broadcaster at Step 13 of the reference impl; shapes may tighten before a stable tag lands. Once promoted to `stable` (a minor spec bump), the same add/remove/rename semantics as the job events apply.
package/job-lifecycle.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Job lifecycle
2
2
 
3
- Normative state machine for jobs. A `Job` (see `schemas/job.schema.json`) is the runtime instance of an `Action` applied to one or more `Node`s. Every job moves through this lifecycle exactly once.
3
+ Normative state machine for jobs. A `Job` (see [`schemas/job.schema.json`](./schemas/job.schema.json)) is the runtime instance of an `Action` applied to one or more `Node`s. Every job moves through this lifecycle exactly once.
4
4
 
5
5
  ---
6
6
 
@@ -56,7 +56,7 @@ Any other transition attempt MUST be rejected and MUST NOT mutate state. Impleme
56
56
  5. Compute `ttlSeconds` per §TTL resolution below. Frozen on `state_jobs.ttlSeconds` for the life of this job.
57
57
  6. Resolve `priority` (integer, default `0`). Precedence (lowest → highest): action manifest `defaultPriority` → user config `jobs.perActionPriority.<actionId>` → flag `--priority <n>`. Higher runs first; ties broken by `createdAt ASC`. Negative values are permitted and run after the default bucket. The resolved value is frozen on `state_jobs.priority` at submit time and is immutable for the life of the job.
58
58
  7. Generate `nonce` (implementation-chosen; MUST be cryptographically random, ≥ 128 bits of entropy).
59
- 8. Render the job file at `.skill-map/jobs/<id>.md`, applying the canonical preamble (see `prompt-preamble.md`).
59
+ 8. Render the job file at `.skill-map/jobs/<id>.md`, applying the canonical preamble (see [`prompt-preamble.md`](./prompt-preamble.md)).
60
60
  9. Insert a row in `state_jobs` with `status = 'queued'`, `createdAt = now`.
61
61
  10. Return the job id.
62
62
 
@@ -166,9 +166,9 @@ Negative or zero values MUST be rejected with exit 2 at submit time.
166
166
  2. Compare the supplied nonce against `state_jobs.nonce`. Mismatch → exit 4 without mutation.
167
167
  3. If `state_jobs.status != 'running'` → exit 2 with message "job not in running state". This catches late callbacks after a reap.
168
168
  4. If `--status completed`: validate the report file against the action's declared report schema. On validation failure → transition to `failed` with reason `report-invalid`; DO NOT stay `running`.
169
- 5. Write the execution record (see `schemas/execution-record.schema.json`) with the full metrics.
169
+ 5. Write the execution record (see [`schemas/execution-record.schema.json`](./schemas/execution-record.schema.json)) with the full metrics.
170
170
  6. Transition the job to the terminal state.
171
- 7. Emit `job.callback.received` followed by `job.completed` or `job.failed`.
171
+ 7. Emit `job.callback.received` followed by `job.completed` or `job.failed` (see [`job-events.md`](./job-events.md)).
172
172
 
173
173
  The nonce is the sole authentication factor. A compromised nonce allows forged callbacks for that single job. Nonces MUST be generated per-job; never reused; never logged at info level or above.
174
174
 
@@ -236,6 +236,16 @@ Config controls (`jobs.retention.completed`, `jobs.retention.failed`):
236
236
 
237
237
  ---
238
238
 
239
+ ## See also
240
+
241
+ - [`architecture.md`](./architecture.md) — `RunnerPort` definition; driving-adapter peer rule for Skill agents.
242
+ - [`job-events.md`](./job-events.md) — canonical event stream emitted during job execution.
243
+ - [`prompt-preamble.md`](./prompt-preamble.md) — verbatim preamble prepended to every rendered job file.
244
+ - [`db-schema.md`](./db-schema.md) — `state_jobs` and `state_executions` table catalogs.
245
+ - [`cli-contract.md`](./cli-contract.md) — `sm job` verb surface and exit codes.
246
+
247
+ ---
248
+
239
249
  ## Stability
240
250
 
241
251
  The state machine diagram above is **stable** as of spec v1.0.0. Adding a new state is a major bump. Adding a new terminal reason (`failureReason` enum value) is a minor bump.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-map/spec",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/plugin-kv-api.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Plugin KV API
2
2
 
3
- Normative contract for plugin-accessible persistence. Two modes exist (see `db-schema.md` for the catalog entries):
3
+ Normative contract for plugin-accessible persistence. Two modes exist (see [`db-schema.md`](./db-schema.md) for the catalog entries):
4
4
 
5
5
  - **Mode A — KV**: plugin uses the kernel-provided `ctx.store.*` accessor. Backed by the shared `state_plugin_kvs` table.
6
6
  - **Mode B — Dedicated**: plugin owns its own tables with the `plugin_<normalizedId>_` prefix, migrated by the kernel.
@@ -54,7 +54,7 @@ Operations MAY be additionally scoped by `nodePath`:
54
54
  - **Global KV (no `nodePath`)**: `{pluginId, nodePath: null, key}`. One row per plugin + key.
55
55
  - **Node-scoped KV (with `nodePath`)**: `{pluginId, nodePath: "<path>", key}`. One row per plugin + node + key.
56
56
 
57
- Both scopes share the same underlying `state_plugin_kvs` table (see `db-schema.md`). The `nodePath` column is nullable; implementations MUST use a sentinel empty string internally when the backing engine rejects NULL in composite primary keys.
57
+ Both scopes share the same underlying `state_plugin_kvs` table (see [`db-schema.md`](./db-schema.md)). The `nodePath` column is nullable; implementations MUST use a sentinel empty string internally when the backing engine rejects NULL in composite primary keys.
58
58
 
59
59
  ### Semantics
60
60
 
@@ -102,7 +102,7 @@ Errors MUST NOT leak backend-specific details (SQL strings, file paths) to plugi
102
102
 
103
103
  ## Mode B: dedicated tables
104
104
 
105
- Mode B is governed by `db-schema.md` (catalog rules + triple protection). This section restates the API surface.
105
+ Mode B is governed by [`db-schema.md`](./db-schema.md) (catalog rules + triple protection). This section restates the API surface.
106
106
 
107
107
  ### Declaration
108
108
 
@@ -147,7 +147,7 @@ Mode B plugins MAY call `db.transaction(async (tx) => { ... })`. The kernel prov
147
147
  - Index and constraint prefixes are similarly injected.
148
148
  - A failing plugin migration disables only that plugin (`status: load-error`); other plugins and the kernel continue.
149
149
 
150
- See `db-schema.md` for the normative migration rules.
150
+ See [`db-schema.md`](./db-schema.md) for the normative migration rules.
151
151
 
152
152
  ---
153
153
 
@@ -168,7 +168,7 @@ Non-normative; descriptive guidance for plugin authors.
168
168
  - Your data model is actually tabular (cache with TTL, observation log, provider registry).
169
169
  - You are willing to own migrations forever.
170
170
 
171
- A plugin MUST declare **exactly one** storage mode. Mixing modes in the same plugin is forbidden. The `plugins-registry.schema.json` enforces this at the manifest level (`storage` is a `oneOf` between `kv` and `dedicated`), and at runtime `ctx.store` exposes either the `KvStore` or the `DedicatedStore` shape — never both. A plugin that needs both KV-like and relational access MUST use mode B and implement KV-style rows as a dedicated table.
171
+ A plugin MUST declare **exactly one** storage mode. Mixing modes in the same plugin is forbidden. The [`plugins-registry.schema.json`](./schemas/plugins-registry.schema.json) enforces this at the manifest level (`storage` is a `oneOf` between `kv` and `dedicated`), and at runtime `ctx.store` exposes either the `KvStore` or the `DedicatedStore` shape — never both. A plugin that needs both KV-like and relational access MUST use mode B and implement KV-style rows as a dedicated table.
172
172
 
173
173
  ---
174
174
 
@@ -201,6 +201,13 @@ Post-v1.0 work: signed manifest, sandboxed worker-thread isolation, per-plugin D
201
201
 
202
202
  ---
203
203
 
204
+ ## See also
205
+
206
+ - [`db-schema.md`](./db-schema.md) — table catalog, migration rules, triple protection for mode B.
207
+ - [`architecture.md`](./architecture.md) — extension contract rules and `ctx.store` injection via the kernel.
208
+
209
+ ---
210
+
204
211
  ## Stability
205
212
 
206
213
  - The `KvStore` interface (method names, options, return shapes) is **stable** as of spec v1.0.0.
@@ -99,10 +99,10 @@ The preamble establishes a promise from the model:
99
99
 
100
100
  - Every report MUST be valid JSON.
101
101
  - Every report MUST contain `safety` and `confidence` at the top level.
102
- - `safety` MUST conform to `schemas/report-base.schema.json#/properties/safety`.
102
+ - `safety` MUST conform to [`schemas/report-base.schema.json`](./schemas/report-base.schema.json)`#/properties/safety`.
103
103
  - `confidence` MUST be a number in `[0.0, 1.0]`.
104
104
 
105
- The kernel validates every report against the action's declared schema (which MUST extend `report-base.schema.json`). A report that lacks `safety` or `confidence`, or whose values are of the wrong shape, is rejected; the job transitions to `failed` with reason `report-invalid` (see `job-lifecycle.md`).
105
+ The kernel validates every report against the action's declared schema (which MUST extend [`report-base.schema.json`](./schemas/report-base.schema.json)). A report that lacks `safety` or `confidence`, or whose values are of the wrong shape, is rejected; the job transitions to `failed` with reason `report-invalid` (see [`job-lifecycle.md`](./job-lifecycle.md)).
106
106
 
107
107
  Implementations MUST NOT tolerate the absence of `safety`. If a model returns a report without it, the failure is the runner's problem to surface, not the kernel's to tolerate.
108
108
 
@@ -125,13 +125,13 @@ Implementations MUST NOT modify the preamble text at runtime (e.g., based on loc
125
125
 
126
126
  ## Versioning the preamble
127
127
 
128
- The preamble text is a **normative artifact** of the spec. Any change follows `versioning.md`:
128
+ The preamble text is a **normative artifact** of the spec. Any change follows [`versioning.md`](./versioning.md):
129
129
 
130
130
  - Editorial fixes to examples (none exist today, keep it that way) — patch bump.
131
131
  - Tightening the instructions (e.g., adding a new refusal clause) — minor bump.
132
- - Changing the shape the model must emit (`safety` structure) — major bump, because it propagates to `report-base.schema.json`.
132
+ - Changing the shape the model must emit (`safety` structure) — major bump, because it propagates to [`report-base.schema.json`](./schemas/report-base.schema.json).
133
133
 
134
- Every spec release that modifies the preamble MUST record the rationale in `CHANGELOG.md`.
134
+ Every spec release that modifies the preamble MUST record the rationale in [`CHANGELOG.md`](./CHANGELOG.md).
135
135
 
136
136
  ---
137
137
 
@@ -147,6 +147,15 @@ Defense-in-depth: the deterministic rule `injection-pattern` (shipped as a built
147
147
 
148
148
  ---
149
149
 
150
+ ## See also
151
+
152
+ - [`job-lifecycle.md`](./job-lifecycle.md) — submit flow that renders job files with the preamble.
153
+ - [`architecture.md`](./architecture.md) — kernel's role in applying the preamble.
154
+ - [`interfaces/security-scanner.md`](./interfaces/security-scanner.md) — `SecurityReport` convention that extends `report-base`.
155
+ - [`conformance/`](./conformance/README.md) — `preamble-bitwise-match` case (deferred to Step 10).
156
+
157
+ ---
158
+
150
159
  ## Stability
151
160
 
152
- The verbatim text above is **stable** as of spec v1.0.0. It is reproduced in the conformance suite as `conformance/fixtures/preamble-v1.txt`. Any implementation whose rendered job files do not contain this text verbatim fails the conformance check `preamble-bitwise-match`.
161
+ The verbatim text above is **stable** as of spec v1.0.0. It is reproduced in the conformance suite as [`conformance/fixtures/preamble-v1.txt`](./conformance/fixtures/preamble-v1.txt). Any implementation whose rendered job files do not contain this text verbatim fails the conformance check `preamble-bitwise-match`.
@@ -28,12 +28,32 @@
28
28
  },
29
29
  "setup": {
30
30
  "type": "object",
31
- "description": "Pre-invocation toggles. All default to `false`.",
31
+ "description": "Pre-invocation toggles and ordered staging steps. All toggles default to `false`. `priorScans`, when present, run BEFORE the main `invoke` so a case can establish a prior snapshot the heuristic-driven verbs (e.g. `sm scan` rename detection) can react to.",
32
32
  "additionalProperties": false,
33
33
  "properties": {
34
34
  "disableAllAdapters": { "type": "boolean" },
35
35
  "disableAllDetectors": { "type": "boolean" },
36
- "disableAllRules": { "type": "boolean" }
36
+ "disableAllRules": { "type": "boolean" },
37
+ "priorScans": {
38
+ "type": "array",
39
+ "description": "Ordered staging scans, each running before the next. For step N, the runner first replaces the scope's adapter content with `priorScans[N].fixture`, then invokes `sm scan` with the supplied flags. After the last step, the runner copies the top-level `fixture` (overwriting again) and runs the main `invoke`. The DB persists across all steps because `.skill-map/` is preserved between fixture swaps.",
40
+ "items": {
41
+ "type": "object",
42
+ "required": ["fixture"],
43
+ "additionalProperties": false,
44
+ "properties": {
45
+ "fixture": {
46
+ "type": "string",
47
+ "description": "Folder under `conformance/fixtures/` to copy into the scope, replacing every non-`.skill-map/` directory."
48
+ },
49
+ "flags": {
50
+ "type": "array",
51
+ "description": "Flags passed to `sm scan`. Default: empty (full scan).",
52
+ "items": { "type": "string" }
53
+ }
54
+ }
55
+ }
56
+ }
37
57
  }
38
58
  },
39
59
  "invoke": {
package/versioning.md CHANGED
@@ -28,7 +28,7 @@ Rule of thumb: if a strict v1 implementation could fail a v1.X conformance run,
28
28
  All of the following are normative and governed by this policy:
29
29
 
30
30
  - Every JSON Schema in `schemas/` (fields, types, required, enums, defaults, `additionalProperties`).
31
- - Every MUST / SHOULD / MAY statement in prose documents (`architecture.md`, `cli-contract.md`, `job-events.md`, `prompt-preamble.md`, `db-schema.md`, `plugin-kv-api.md`, `job-lifecycle.md`).
31
+ - Every MUST / SHOULD / MAY statement in prose documents ([`architecture.md`](./architecture.md), [`cli-contract.md`](./cli-contract.md), [`job-events.md`](./job-events.md), [`prompt-preamble.md`](./prompt-preamble.md), [`db-schema.md`](./db-schema.md), [`plugin-kv-api.md`](./plugin-kv-api.md), [`job-lifecycle.md`](./job-lifecycle.md)).
32
32
  - Exit codes, verb names, required flags, canonical error messages marked "normative".
33
33
  - Conformance fixtures and cases — removing or tightening a case is major.
34
34
 
@@ -77,9 +77,9 @@ The first stable commitment is `spec-v1.0.0`. In the current reference roadmap,
77
77
  ## Change process
78
78
 
79
79
  1. PR proposes a spec change. Include rationale and classification (patch/minor/major).
80
- 2. If major, PR includes a migration note draft for `CHANGELOG.md`.
80
+ 2. If major, PR includes a migration note draft for [`CHANGELOG.md`](./CHANGELOG.md).
81
81
  3. If the change affects reference-impl behavior, a companion PR in `src/` lands the implementation behind the bumped `specCompat`.
82
- 4. Merge order: spec change first, implementation second. An implementation MUST NOT ship a feature that is not yet in the spec (see `AGENTS.md`: "Every feature: update spec/ first, then src/").
82
+ 4. Merge order: spec change first, implementation second. An implementation MUST NOT ship a feature that is not yet in the spec (see [`../AGENTS.md`](../AGENTS.md): "Every feature: update spec/ first, then src/").
83
83
  5. Tag spec release (`spec-vX.Y.Z`) independent from any CLI tag.
84
84
 
85
85
  ## Canonical URLs