@skill-map/spec 0.7.1 โ 0.9.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 +777 -3
- package/README.md +11 -13
- package/architecture.md +118 -35
- package/cli-contract.md +38 -25
- package/conformance/README.md +43 -14
- package/conformance/cases/kernel-empty-boot.json +3 -3
- package/conformance/coverage.md +20 -24
- package/db-schema.md +61 -6
- package/index.json +35 -77
- package/interfaces/security-scanner.md +1 -1
- package/job-events.md +75 -1
- package/package.json +1 -1
- package/plugin-author-guide.md +409 -51
- package/schemas/conformance-case.schema.json +14 -5
- package/schemas/execution-record.schema.json +8 -8
- package/schemas/extensions/action.schema.json +2 -2
- package/schemas/extensions/base.schema.json +5 -5
- package/schemas/extensions/extractor.schema.json +48 -0
- package/schemas/extensions/formatter.schema.json +29 -0
- package/schemas/extensions/hook.schema.json +44 -0
- package/schemas/extensions/provider.schema.json +51 -0
- package/schemas/extensions/rule.schema.json +1 -1
- package/schemas/frontmatter/base.schema.json +2 -2
- package/schemas/link.schema.json +4 -4
- package/schemas/node.schema.json +4 -4
- package/schemas/plugins-registry.schema.json +19 -4
- package/schemas/project-config.schema.json +2 -2
- package/schemas/scan-result.schema.json +3 -3
- package/conformance/cases/basic-scan.json +0 -17
- package/conformance/cases/orphan-detection.json +0 -22
- package/conformance/cases/rename-high.json +0 -21
- package/conformance/fixtures/minimal-claude/agents/reviewer.md +0 -16
- package/conformance/fixtures/minimal-claude/commands/status.md +0 -17
- package/conformance/fixtures/minimal-claude/hooks/pre-commit.md +0 -13
- package/conformance/fixtures/minimal-claude/notes/architecture.md +0 -11
- package/conformance/fixtures/minimal-claude/skills/hello.md +0 -22
- package/conformance/fixtures/orphan-after/skills/keep.md +0 -13
- package/conformance/fixtures/orphan-before/skills/keep.md +0 -13
- package/conformance/fixtures/orphan-before/skills/lonely.md +0 -13
- package/conformance/fixtures/rename-high-after/skills/bar.md +0 -14
- package/conformance/fixtures/rename-high-before/skills/foo.md +0 -14
- package/schemas/extensions/adapter.schema.json +0 -40
- package/schemas/extensions/audit.schema.json +0 -47
- package/schemas/extensions/detector.schema.json +0 -41
- package/schemas/extensions/renderer.schema.json +0 -29
- package/schemas/frontmatter/agent.schema.json +0 -17
- package/schemas/frontmatter/command.schema.json +0 -39
- package/schemas/frontmatter/hook.schema.json +0 -29
- package/schemas/frontmatter/note.schema.json +0 -11
- package/schemas/frontmatter/skill.schema.json +0 -37
package/conformance/coverage.md
CHANGED
|
@@ -8,35 +8,32 @@ This file is hand-maintained. A CI check before spec release compares the schema
|
|
|
8
8
|
|
|
9
9
|
| # | Schema | Case(s) | Status | Notes |
|
|
10
10
|
|---|---|---|---|---|
|
|
11
|
-
| 1 | `node.schema.json` | `
|
|
11
|
+
| 1 | `node.schema.json` | `kernel-empty-boot` (indirect) | ๐ก partial | Empty-boot validates the zero-filled ScanResult shape end-to-end. Direct cases that exercise populated `Node` rows are Provider-specific and live in the Provider's own conformance suite (see `provider:claude` for `basic-scan`). |
|
|
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
|
-
| 4 | `scan-result.schema.json` | `
|
|
14
|
+
| 4 | `scan-result.schema.json` | `kernel-empty-boot` | ๐ก partial | Zero-filled case asserted via empty-boot. Populated cases (rename / orphan branches) moved with the Claude Provider โ see `provider:claude` cases `basic-scan` / `rename-high` / `orphan-detection`. |
|
|
15
15
|
| 5 | `execution-record.schema.json` | โ | ๐ด missing | Blocked by Step 5 (history). Needs a case that runs a `deterministic` 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/settings.json` (optionally with a `.skill-map/settings.local.json` overlay), assert effective config after the layered 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
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
|
-
| 11 | `frontmatter/base.schema.json` | `basic-scan`
|
|
22
|
-
| 12 | `
|
|
23
|
-
| 13 | `
|
|
24
|
-
| 14 | `
|
|
25
|
-
| 15 | `
|
|
26
|
-
| 16 | `
|
|
27
|
-
| 17 | `
|
|
28
|
-
| 18 | `
|
|
29
|
-
| 19 | `
|
|
30
|
-
| 20 | `
|
|
31
|
-
| 21 | `
|
|
32
|
-
| 22 | `extensions/
|
|
33
|
-
| 23 | `
|
|
34
|
-
| 24 | `extensions/
|
|
35
|
-
|
|
36
|
-
|
|
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`; an audit declaring `mode` directly fails at load. |
|
|
38
|
-
| 28 | `extensions/renderer.schema.json` | โ | ๐ด missing | Case: `ascii` renderer manifest validates. |
|
|
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. |
|
|
21
|
+
| 11 | `frontmatter/base.schema.json` | โ | ๐ด missing | Universal frontmatter shape. Per-kind schemas (skill / agent / command / hook / note) are no longer in spec โ they relocated to the **Claude Provider** under `src/extensions/providers/claude/schemas/` in spec 0.8.0 (Phase 3 of plug-in model overhaul) and extend this base via `$ref`-by-`$id`. The cases that exercised it indirectly (`basic-scan` and friends) moved to the Provider in Phase 5 / A.13. Direct spec-level case still pending: fixture with min-required frontmatter only, no Provider needed (Provider-disabled mode + a single `notes/<file>.md` with `name: ...` + `description: ...`). |
|
|
22
|
+
| 12 | `summaries/skill.schema.json` | โ | ๐ด missing | Blocked by Step 10 (`skill-summarizer`). Case: submit summarizer, validate report. |
|
|
23
|
+
| 13 | `summaries/agent.schema.json` | โ | ๐ด missing | Blocked by Step 11. |
|
|
24
|
+
| 14 | `summaries/command.schema.json` | โ | ๐ด missing | Blocked by Step 11. |
|
|
25
|
+
| 15 | `summaries/hook.schema.json` | โ | ๐ด missing | Blocked by Step 11. |
|
|
26
|
+
| 16 | `summaries/note.schema.json` | โ | ๐ด missing | Blocked by Step 11. |
|
|
27
|
+
| 17 | `extensions/base.schema.json` | โ | ๐ด missing | Meta-case: every manifest under `src/extensions/` validates against the appropriate kind schema (which extends base via `allOf`). |
|
|
28
|
+
| 18 | `extensions/provider.schema.json` | โ | ๐ด missing | Case: the `claude` Provider manifest validates; a crafted invalid manifest (missing `kinds` or `explorationDir`) fails with `invalid-manifest`. |
|
|
29
|
+
| 19 | `extensions/extractor.schema.json` | โ | ๐ด missing | Case: `frontmatter` + `slash` + `at-directive` extractor manifests validate; an extractor emitting a disallowed `emitsLinkKinds` value fails. |
|
|
30
|
+
| 20 | `extensions/rule.schema.json` | โ | ๐ด missing | Case: `trigger-collision`, `broken-ref`, `superseded` manifests validate. |
|
|
31
|
+
| 21 | `extensions/action.schema.json` | โ | ๐ด missing | Case: a `deterministic` action manifest validates; a `probabilistic` action WITHOUT `promptTemplateRef` fails. |
|
|
32
|
+
| 22 | `extensions/formatter.schema.json` | โ | ๐ด missing | Case: `ascii` formatter manifest validates. |
|
|
33
|
+
| 23 | `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. |
|
|
34
|
+
| 24 | `extensions/hook.schema.json` | โ | ๐ด missing | Case: a `deterministic` hook manifest with `triggers: ['scan.completed']` validates; a hook declaring an unknown trigger (e.g. `scan.progress`) fails with `invalid-manifest` at load time. |
|
|
35
|
+
|
|
36
|
+
> **Note on Provider-owned schemas.** Per spec 0.8.0 Phase 3, the per-kind frontmatter schemas (`skill`, `agent`, `command`, `hook`, `note`) live with the Provider that emits them โ for the built-in Claude Provider, that is `src/extensions/providers/claude/schemas/`. Those schemas are NOT counted in the spec's coverage matrix above; they belong to the Provider's own conformance suite (Phase 5 / A.13 โ `src/extensions/providers/claude/conformance/coverage.md`). Phase 5 / A.13 also relocated the cases that exercised them (`basic-scan`, `rename-high`, `orphan-detection`) to the Provider's own `cases/` directory. The matrix shrinks from 28 to 23 rows accordingly. The Hook kind (A.11) brings it back up to 24.
|
|
40
37
|
|
|
41
38
|
Status legend: ๐ข covered (at least one case asserts the schema end-to-end) ยท ๐ก partial (covered only indirectly or via a sub-shape) ยท ๐ด missing.
|
|
42
39
|
|
|
@@ -48,14 +45,13 @@ These have their own conformance cases even though they are not JSON Schemas.
|
|
|
48
45
|
|---|---|---|---|---|
|
|
49
46
|
| 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
47
|
| B | Kernel empty-boot invariant | `kernel-empty-boot` | ๐ข covered | All extensions disabled โ empty ScanResult. |
|
|
51
|
-
| C | Audit mode derivation | `extension-mode-derivation` | ๐ deferred | Deferred to Step 10 (audit's effective mode is derived from `composes[]` at load time; full validation requires the job subsystem to verify dispatch routing). Sub-cases: (1) audit composing only deterministic primitives โ effective mode `deterministic`, runs synchronously inside `sm audit <id>`; (2) audit composing at least one probabilistic primitive โ effective mode `probabilistic`, dispatches as a job; (3) audit declaring `mode` directly in the manifest โ load-time error `invalid-manifest`; (4) audit composing a dangling reference โ load-time error `invalid-manifest`. See `architecture.md` ยงExecution modes. |
|
|
52
48
|
| 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. |
|
|
53
49
|
| D | Duplicate detection | โ | ๐ด missing | Blocked by Step 10. Two `sm job submit` with same `(action, version, node, contentHash)` โ second exits 3. |
|
|
54
50
|
| E | `--force` bypass | โ | ๐ด missing | Blocked by Step 10. |
|
|
55
51
|
| F | Nonce mismatch | โ | ๐ด missing | Blocked by Step 10. `sm record` with wrong nonce โ exit 4. |
|
|
56
52
|
| G | Reap | โ | ๐ด missing | Blocked by Step 10. Set TTL to 1s; claim; wait; next `sm job run` reaps with reason `abandoned`. |
|
|
57
53
|
| H | `run.*` event envelope for Skill agent | โ | ๐ด missing | Blocked by Step 10. Skill-agent flow emits synthetic `r-ext-*` run envelope around one job. |
|
|
58
|
-
| 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. |
|
|
54
|
+
| I | Rename heuristic | `rename-high`, `orphan-detection` (Provider-owned) | ๐ข 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. Cases moved with the Claude Provider in Phase 5 / A.13 (they reach a Provider's `kinds` catalog by construction); see [`src/extensions/providers/claude/conformance/`](../../src/extensions/providers/claude/conformance/). Medium / ambiguous branches are exercised by `src/test/rename-heuristic.test.ts` until the conformance schema grows richer assertions. |
|
|
59
55
|
| J | Plugin DDL rejection | โ | ๐ด missing | Blocked by Step 9. Plugin migration referencing `state_jobs` โ disabled with `invalid-manifest`. |
|
|
60
56
|
| K | Plugin prefix injection | โ | ๐ด missing | Blocked by Step 9. Plugin declares `CREATE TABLE foo` โ kernel applies as `plugin_<id>_foo`. |
|
|
61
57
|
| 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. |
|
|
@@ -64,4 +60,4 @@ These have their own conformance cases even though they are not JSON Schemas.
|
|
|
64
60
|
|
|
65
61
|
- **spec v0.x**: partial coverage acceptable. Every case added as the reference impl lands the verb that makes it runnable.
|
|
66
62
|
- **spec v1.0.0 release**: all rows above MUST be ๐ข covered or explicitly ๐ deferred to v1.1 with a linked issue.
|
|
67
|
-
- **CI check**: [`scripts/check-coverage.
|
|
63
|
+
- **CI check**: [`scripts/check-coverage.js`](../../scripts/check-coverage.js) compares `spec/schemas/**/*.schema.json` against the matrix above on every PR. A schema without a row here, or a row pointing at a missing schema, fails CI (exit 1 with a `::error::` annotation). Wired into `ci.yml` ยงvalidate and into `npm run spec:check`.
|
package/db-schema.md
CHANGED
|
@@ -73,7 +73,7 @@ One row per detected node, matching [`schemas/node.schema.json`](./schemas/node.
|
|
|
73
73
|
|---|---|---|---|
|
|
74
74
|
| `path` | TEXT | PRIMARY KEY | Relative path from scope root. Canonical node identifier. |
|
|
75
75
|
| `kind` | TEXT | NOT NULL, CHECK in (`skill`, `agent`, `command`, `hook`, `note`) | |
|
|
76
|
-
| `
|
|
76
|
+
| `provider` | TEXT | NOT NULL | Provider extension id. |
|
|
77
77
|
| `title` | TEXT | NULL | |
|
|
78
78
|
| `description` | TEXT | NULL | |
|
|
79
79
|
| `stability` | TEXT | CHECK in (`experimental`, `stable`, `deprecated`) OR NULL | Denormalized from frontmatter. |
|
|
@@ -93,7 +93,7 @@ One row per detected node, matching [`schemas/node.schema.json`](./schemas/node.
|
|
|
93
93
|
| `external_refs_count` | INTEGER | NOT NULL DEFAULT 0 | |
|
|
94
94
|
| `scanned_at` | INTEGER | NOT NULL | Unix ms. |
|
|
95
95
|
|
|
96
|
-
Indexes: `ix_scan_nodes_kind`, `
|
|
96
|
+
Indexes: `ix_scan_nodes_kind`, `ix_scan_nodes_provider`, `ix_scan_nodes_body_hash` (rename heuristic).
|
|
97
97
|
|
|
98
98
|
### `scan_links`
|
|
99
99
|
|
|
@@ -106,7 +106,7 @@ One row per detected link, matching [`schemas/link.schema.json`](./schemas/link.
|
|
|
106
106
|
| `target_path` | TEXT | NOT NULL | MAY point to a missing node (broken ref). |
|
|
107
107
|
| `kind` | TEXT | NOT NULL, CHECK in (`invokes`, `references`, `mentions`, `supersedes`) | |
|
|
108
108
|
| `confidence` | TEXT | NOT NULL, CHECK in (`high`, `medium`, `low`) | |
|
|
109
|
-
| `sources_json` | TEXT | NOT NULL | JSON array of
|
|
109
|
+
| `sources_json` | TEXT | NOT NULL | JSON array of extractor ids. |
|
|
110
110
|
| `original_trigger` | TEXT | NULL | |
|
|
111
111
|
| `normalized_trigger` | TEXT | NULL | |
|
|
112
112
|
| `location_line` | INTEGER | NULL | |
|
|
@@ -136,7 +136,7 @@ Indexes: `ix_scan_issues_rule_id`, `ix_scan_issues_severity`.
|
|
|
136
136
|
|
|
137
137
|
### `scan_meta`
|
|
138
138
|
|
|
139
|
-
Single-row table holding the metadata of the last persisted scan. Lets `loadScanResult` return the real `scope` / `roots` / `scannedAt` / `scannedBy` / `
|
|
139
|
+
Single-row table holding the metadata of the last persisted scan. Lets `loadScanResult` return the real `scope` / `roots` / `scannedAt` / `scannedBy` / `providers` / `stats.filesWalked|filesSkipped|durationMs` instead of synthesising them. Replaced atomically with the rest of the `scan_*` zone on every `sm scan`.
|
|
140
140
|
|
|
141
141
|
`nodesCount` / `linksCount` / `issuesCount` are not stored here โ they derive from `COUNT(*)` of the sibling tables.
|
|
142
142
|
|
|
@@ -149,13 +149,68 @@ Single-row table holding the metadata of the last persisted scan. Lets `loadScan
|
|
|
149
149
|
| `scanned_by_name` | TEXT | NOT NULL |
|
|
150
150
|
| `scanned_by_version` | TEXT | NOT NULL |
|
|
151
151
|
| `scanned_by_spec_version` | TEXT | NOT NULL |
|
|
152
|
-
| `
|
|
152
|
+
| `providers_json` | TEXT | NOT NULL | JSON array of Provider ids. |
|
|
153
153
|
| `stats_files_walked` | INTEGER | NOT NULL |
|
|
154
154
|
| `stats_files_skipped` | INTEGER | NOT NULL |
|
|
155
155
|
| `stats_duration_ms` | INTEGER | NOT NULL |
|
|
156
156
|
|
|
157
157
|
No indexes (single row).
|
|
158
158
|
|
|
159
|
+
### `scan_extractor_runs`
|
|
160
|
+
|
|
161
|
+
Fine-grained cache breadcrumbs for the incremental scan path. One row per `(node_path, extractor_id)` recording the body hash the Extractor saw the last time it ran against that node. Replace-all on every `sm scan` so rows for Extractors that were uninstalled since the last scan disappear automatically.
|
|
162
|
+
|
|
163
|
+
The orchestrator consults this table on `sm scan --changed`: a node-level cache hit (body+frontmatter unchanged) is upgraded to a full skip ONLY when every currently-registered Extractor (filtered by `applicableKinds`) has a row matching the prior body hash. A new Extractor registered between scans is detected by the absence of its row and runs over the cached node WITHOUT requiring a full cache invalidation. Without this table the cache silently bypassed any Extractor newly registered between scans โ a hard blocker for the probabilistic Extractor model where re-running an LLM Extractor against an unchanged body is the difference between a free and a paid scan.
|
|
164
|
+
|
|
165
|
+
| Column | Type | Constraint |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| `node_path` | TEXT | NOT NULL | FK semantically to `scan_nodes.path`; MAY be unenforced (the row is deleted in the same tx as the parent node when the file disappears). |
|
|
168
|
+
| `extractor_id` | TEXT | NOT NULL | Qualified id `<plugin_id>/<id>` per spec ยง A.6. |
|
|
169
|
+
| `body_hash_at_run` | TEXT | NOT NULL | The `node.body_hash` the Extractor processed; sha256, hex. |
|
|
170
|
+
| `ran_at` | INTEGER | NOT NULL | Unix milliseconds โ wall-clock when the Extractor finished or was last carried forward via cache reuse. Used for diagnostics + future GC of stale rows. |
|
|
171
|
+
|
|
172
|
+
Primary key: `(node_path, extractor_id)`. Indexes: `ix_scan_extractor_runs_node`, `ix_scan_extractor_runs_extractor`.
|
|
173
|
+
|
|
174
|
+
**Source-attribution interaction.** `scan_links.sources_json` carries the *short* extractor id the author wrote (e.g. `'slash'`); this table keys on the *qualified* form (`'claude/slash'`). When a cached link is reshaped on reuse the orchestrator strips short ids whose owning Extractor is no longer registered (audit trail accuracy: a removed extractor must not stay attributed); links whose sole source is an uninstalled Extractor disappear; links whose sources include a missing-but-still-registered Extractor are dropped so the missing Extractor can re-emit fresh.
|
|
175
|
+
|
|
176
|
+
### `node_enrichments`
|
|
177
|
+
|
|
178
|
+
Universal enrichment layer (A.8). Stores `ctx.enrichNode(partial)` outputs separately from the author-supplied frontmatter on `scan_nodes.frontmatter_json`, which the Extractor pipeline NEVER mutates.
|
|
179
|
+
|
|
180
|
+
One row per `(node_path, extractor_id)` pair an Extractor enriched. Both deterministic and probabilistic Extractors write here; only probabilistic rows participate in stale tracking โ when a body changes between scans, the kernel flags the surviving probabilistic row `stale = 1` (NOT deleted, preserving the LLM cost paid to produce it). Deterministic rows simply pisar via PRIMARY KEY conflict on the next re-extract through the A.9 cache.
|
|
181
|
+
|
|
182
|
+
| Column | Type | Constraint |
|
|
183
|
+
|---|---|---|
|
|
184
|
+
| `node_path` | TEXT | NOT NULL | FK semantically to `scan_nodes.path`; replaced when a rename heuristic fires (mirrors the `state_*` FK migration). |
|
|
185
|
+
| `extractor_id` | TEXT | NOT NULL | Qualified id `<plugin_id>/<id>` per spec ยง A.6. |
|
|
186
|
+
| `body_hash_at_enrichment` | TEXT | NOT NULL | The `node.body_hash` the Extractor saw when it produced this enrichment. The stale-flagging query keys on `body_hash_at_enrichment != node.body_hash`. |
|
|
187
|
+
| `value_json` | TEXT | NOT NULL | JSON-serialised `Partial<Node>` โ the cumulative merge of every `enrichNode(...)` call the Extractor made for this node within its `extract()` invocation. |
|
|
188
|
+
| `stale` | INTEGER | NOT NULL DEFAULT 0, CHECK in (0, 1) | `1` for probabilistic rows whose `body_hash_at_enrichment` no longer matches the live node body; `0` otherwise. Deterministic rows are never stale-flagged. |
|
|
189
|
+
| `enriched_at` | INTEGER | NOT NULL | Unix milliseconds โ when the Extractor produced this enrichment. Drives the read-time merge order (`ASC` โ last-write-wins per field) inside `mergeNodeWithEnrichments`. |
|
|
190
|
+
| `is_probabilistic` | INTEGER | NOT NULL DEFAULT 0, CHECK in (0, 1) | Denormalised from the Extractor manifest's `mode` field so the stale-flag query stays single-table without joining the live registry. |
|
|
191
|
+
|
|
192
|
+
Primary key: `(node_path, extractor_id)`. Indexes: `ix_node_enrichments_node`, `ix_node_enrichments_stale`.
|
|
193
|
+
|
|
194
|
+
**Persistence flow** (per `sm scan`):
|
|
195
|
+
|
|
196
|
+
1. **Rename migration** โ for every `RenameOp` from the rename heuristic, update `node_enrichments.node_path` from `op.from` to `op.to` so the audit trail tracks the file like `state_*` rows do.
|
|
197
|
+
2. **Drop-on-disappear** โ delete every row whose `node_path` is no longer in the live node set.
|
|
198
|
+
3. **Upsert** โ for every `(node_path, extractor_id)` pair the orchestrator emitted in this scan, upsert with `stale = 0` and the current `body_hash`. The PRIMARY KEY conflict refreshes `body_hash_at_enrichment` / `value_json` / `enriched_at` / `is_probabilistic` on every re-run.
|
|
199
|
+
4. **Stale flagging** โ sweep probabilistic rows: any prob row whose `body_hash_at_enrichment` differs from the live `scan_nodes.body_hash` AND was NOT just upserted gets `stale = 1`. Deterministic rows are never stale-flagged.
|
|
200
|
+
|
|
201
|
+
**Read-side `node.merged` view.** Rules / `sm check` / `sm export` consume `node.frontmatter` directly (deterministic CI-safe baseline). UI / future opt-in consumers call `mergeNodeWithEnrichments(node, enrichments)` which:
|
|
202
|
+
|
|
203
|
+
1. Filters `enrichments` to rows targeting this node AND not flagged stale.
|
|
204
|
+
2. Sorts by `enriched_at` ASC.
|
|
205
|
+
3. Spread-merges each `value` over the author frontmatter (last-write-wins per field).
|
|
206
|
+
|
|
207
|
+
Stale row visibility is opt-in via `mergeNodeWithEnrichments(node, enrichments, { includeStale: true })` so the UI can render a "stale (last value: โฆ)" marker without polluting the deterministic merge.
|
|
208
|
+
|
|
209
|
+
**Refresh verbs** (see [`cli-contract.md` ยงScan](./cli-contract.md#scan)):
|
|
210
|
+
|
|
211
|
+
- `sm refresh <node.path>` re-runs Extractors against a single node and upserts their enrichment rows. Stub state: deterministic Extractors run for real; probabilistic Extractors require the job subsystem (Step 10) and are skipped with a stderr advisory.
|
|
212
|
+
- `sm refresh --stale` batches the granular form across every node carrying at least one stale row. Same stub caveat.
|
|
213
|
+
|
|
159
214
|
---
|
|
160
215
|
|
|
161
216
|
## Table catalog: zone `state_`
|
|
@@ -193,7 +248,7 @@ Matching [`schemas/execution-record.schema.json`](./schemas/execution-record.sch
|
|
|
193
248
|
| Column | Type | Constraint |
|
|
194
249
|
|---|---|---|
|
|
195
250
|
| `id` | TEXT | PRIMARY KEY |
|
|
196
|
-
| `kind` | TEXT | NOT NULL, CHECK in (`action
|
|
251
|
+
| `kind` | TEXT | NOT NULL, CHECK in (`action`) |
|
|
197
252
|
| `extension_id` | TEXT | NOT NULL |
|
|
198
253
|
| `extension_version` | TEXT | NOT NULL |
|
|
199
254
|
| `node_ids_json` | TEXT | NOT NULL DEFAULT '[]' |
|
package/index.json
CHANGED
|
@@ -55,12 +55,12 @@
|
|
|
55
55
|
"path": "schemas/extensions/base.schema.json"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
"id": "extensions/
|
|
59
|
-
"path": "schemas/extensions/
|
|
58
|
+
"id": "extensions/provider",
|
|
59
|
+
"path": "schemas/extensions/provider.schema.json"
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
|
-
"id": "extensions/
|
|
63
|
-
"path": "schemas/extensions/
|
|
62
|
+
"id": "extensions/extractor",
|
|
63
|
+
"path": "schemas/extensions/extractor.schema.json"
|
|
64
64
|
},
|
|
65
65
|
{
|
|
66
66
|
"id": "extensions/rule",
|
|
@@ -71,38 +71,18 @@
|
|
|
71
71
|
"path": "schemas/extensions/action.schema.json"
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
|
-
"id": "extensions/
|
|
75
|
-
"path": "schemas/extensions/
|
|
74
|
+
"id": "extensions/formatter",
|
|
75
|
+
"path": "schemas/extensions/formatter.schema.json"
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
|
-
"id": "extensions/
|
|
79
|
-
"path": "schemas/extensions/
|
|
78
|
+
"id": "extensions/hook",
|
|
79
|
+
"path": "schemas/extensions/hook.schema.json"
|
|
80
80
|
}
|
|
81
81
|
],
|
|
82
82
|
"frontmatter": [
|
|
83
83
|
{
|
|
84
84
|
"id": "frontmatter/base",
|
|
85
85
|
"path": "schemas/frontmatter/base.schema.json"
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
"id": "frontmatter/skill",
|
|
89
|
-
"path": "schemas/frontmatter/skill.schema.json"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
"id": "frontmatter/agent",
|
|
93
|
-
"path": "schemas/frontmatter/agent.schema.json"
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
"id": "frontmatter/command",
|
|
97
|
-
"path": "schemas/frontmatter/command.schema.json"
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
"id": "frontmatter/hook",
|
|
101
|
-
"path": "schemas/frontmatter/hook.schema.json"
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
"id": "frontmatter/note",
|
|
105
|
-
"path": "schemas/frontmatter/note.schema.json"
|
|
106
86
|
}
|
|
107
87
|
],
|
|
108
88
|
"summaries": [
|
|
@@ -180,72 +160,50 @@
|
|
|
180
160
|
"casesDir": "conformance/cases",
|
|
181
161
|
"fixturesDir": "conformance/fixtures",
|
|
182
162
|
"cases": [
|
|
183
|
-
{
|
|
184
|
-
"id": "basic-scan",
|
|
185
|
-
"file": "conformance/cases/basic-scan.json"
|
|
186
|
-
},
|
|
187
163
|
{
|
|
188
164
|
"id": "kernel-empty-boot",
|
|
189
165
|
"file": "conformance/cases/kernel-empty-boot.json"
|
|
190
166
|
}
|
|
191
167
|
]
|
|
192
168
|
},
|
|
193
|
-
"specPackageVersion": "0.
|
|
169
|
+
"specPackageVersion": "0.9.0",
|
|
194
170
|
"integrity": {
|
|
195
171
|
"algorithm": "sha256",
|
|
196
172
|
"files": {
|
|
197
|
-
"CHANGELOG.md": "
|
|
198
|
-
"README.md": "
|
|
199
|
-
"architecture.md": "
|
|
200
|
-
"cli-contract.md": "
|
|
201
|
-
"conformance/README.md": "
|
|
202
|
-
"conformance/cases/
|
|
203
|
-
"conformance/
|
|
204
|
-
"conformance/cases/orphan-detection.json": "7fea6e866d775d09cadb70ccd764f6c8317ca61316c6d187a97cb2466db4e19e",
|
|
205
|
-
"conformance/cases/rename-high.json": "f23513893e25fc4259db06a497906137de981da775d8ab2ef262554d54af5f27",
|
|
206
|
-
"conformance/coverage.md": "a9580457cd868638676a450ace478438f832d057ab9c3ad64c088366afc07b7a",
|
|
207
|
-
"conformance/fixtures/minimal-claude/agents/reviewer.md": "d0dd681ba63838301e480116aa09825329f01832b0116de5c5476fdd8a5dcf54",
|
|
208
|
-
"conformance/fixtures/minimal-claude/commands/status.md": "3f36e053fd1c059ffd902f84a55be8a458c26072f97cb37dd7e97314ae2a9bf5",
|
|
209
|
-
"conformance/fixtures/minimal-claude/hooks/pre-commit.md": "ec9cec8ac4ce34d40ec055ffd90e8f06ea3e5764d6ec3ee84e0d97de71b930c7",
|
|
210
|
-
"conformance/fixtures/minimal-claude/notes/architecture.md": "5a7e6fdbb1556733dacebad63758057dc1e19090b5a983292c0c65e90b98bcf1",
|
|
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",
|
|
173
|
+
"CHANGELOG.md": "d793bcd3df7ffde80f5ad66c245d50d38aedf0a6a10146858877afbabe1ebf09",
|
|
174
|
+
"README.md": "bd30780525e75379eaeb5f8a903bdc601daf3862f3ec69dffc96c437e8d476fc",
|
|
175
|
+
"architecture.md": "c69a50e3e9b7d091799bd19cd9efe854a924c83bc2c8e79e0fcb727196151f6c",
|
|
176
|
+
"cli-contract.md": "1d09d047e07fd8793968259660012ebf64ab136967afead2d2666a59a40a020a",
|
|
177
|
+
"conformance/README.md": "07970f06c467e34413f07f6d8bec09ece892d1a903fa039d25b34a77e91187d2",
|
|
178
|
+
"conformance/cases/kernel-empty-boot.json": "ad4bbe9d637537625025c8bdb61285b1433568a2544b1ce0248f304ccff8c350",
|
|
179
|
+
"conformance/coverage.md": "eb57cd979bca59a252e3cd49796e068ac601169f859f32cdf37634486574c44c",
|
|
215
180
|
"conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
"interfaces/security-scanner.md": "e46d33d6e39b15672c8f7350f1cbd4755534510fe57c679c2b1d0be57577d818",
|
|
220
|
-
"job-events.md": "08796b7fbeb55e5b03cf3bc394224e70a23438a4d15a46ad1d70121c2c68b967",
|
|
181
|
+
"db-schema.md": "f570b7ec123a1bbe8936e111a3e3b0597855b2aff0cac82b89fa88d4233a4d73",
|
|
182
|
+
"interfaces/security-scanner.md": "4a982667008f233656f44c61ce9948e062432d3debdcbf7a134da03bd4139d7d",
|
|
183
|
+
"job-events.md": "831501bd696a2801e2d160b314eb49794d0ba553da4487e15c7dcc72a1c230f6",
|
|
221
184
|
"job-lifecycle.md": "1fe88b1a2ed204e41bb41ac172fbb3e912dccd0dd8a1f8ea8e21a681b336d6ee",
|
|
222
|
-
"plugin-author-guide.md": "
|
|
185
|
+
"plugin-author-guide.md": "2dcdf8c570342d94c2c8f8d47594715254e3956d7939443023f1d6420e2b30d0",
|
|
223
186
|
"plugin-kv-api.md": "04b2178f46fb88adeae9240df9c9e1761b660396072001dac32cd402e11a2d7d",
|
|
224
187
|
"prompt-preamble.md": "23a8eff0477fbbc46192a27781bc781bda4202bb9c669b7a7a002b0d668146b0",
|
|
225
|
-
"schemas/conformance-case.schema.json": "
|
|
226
|
-
"schemas/execution-record.schema.json": "
|
|
227
|
-
"schemas/extensions/action.schema.json": "
|
|
228
|
-
"schemas/extensions/
|
|
229
|
-
"schemas/extensions/
|
|
230
|
-
"schemas/extensions/
|
|
231
|
-
"schemas/extensions/
|
|
232
|
-
"schemas/extensions/
|
|
233
|
-
"schemas/extensions/rule.schema.json": "
|
|
234
|
-
"schemas/frontmatter/
|
|
235
|
-
"schemas/frontmatter/base.schema.json": "e68fbb85d3e873c4897af776eaf873860bd6e86b5abc1799e801d35c4f7937cf",
|
|
236
|
-
"schemas/frontmatter/command.schema.json": "7b8463ce9c83edd2e3073dd4cd1bbeec4b42e53b03b48bc9a59e540136c2de89",
|
|
237
|
-
"schemas/frontmatter/hook.schema.json": "4f935bb2a94c6b08795e7e10a473d5185e5abaa8c215152d41036291835b7aad",
|
|
238
|
-
"schemas/frontmatter/note.schema.json": "9806b371193c802803638682f9a625f8277152ad3ef68939eb5f05fff2ef65f4",
|
|
239
|
-
"schemas/frontmatter/skill.schema.json": "b99b8ab23bee01333b4a04946cd9fc13d373d827ef6ddfc7d058daf637f2f80b",
|
|
188
|
+
"schemas/conformance-case.schema.json": "7cd0f3aae5124f24be57cddb213d002d0466f79d06fd3da896075c8b28650410",
|
|
189
|
+
"schemas/execution-record.schema.json": "607e939bfcac4e18385ef93e27bbe28987ba35d5a7c67f3d6e4377ca819a9425",
|
|
190
|
+
"schemas/extensions/action.schema.json": "ec4c2fd74b73a140744c195da91d287a88bfecac206d029910ae0dcb0ab9ce35",
|
|
191
|
+
"schemas/extensions/base.schema.json": "e5c3406b88b0496a89791890b05083929429319d96b1f8cea0bec3ec9e3de8af",
|
|
192
|
+
"schemas/extensions/extractor.schema.json": "122d3f81ef91edcde9798e7dc8fcbf442a2996deea65aa4b03c9d5cb01ba2519",
|
|
193
|
+
"schemas/extensions/formatter.schema.json": "2ab092aa37ae349c69b93071ed4f0e131affb7bb5799516ca82c721262631b36",
|
|
194
|
+
"schemas/extensions/hook.schema.json": "7465c38e0765edf23e49d4f96c539d04323f1cf564af1c60ee637c79a6d39239",
|
|
195
|
+
"schemas/extensions/provider.schema.json": "27c627151fb98cf60763aaa122d807bbf007317f06bd31e92a2fca43c100e4b8",
|
|
196
|
+
"schemas/extensions/rule.schema.json": "8ff420bde498f50db114c352305d487c71aef2dd746fd0c24976ff6a09865c22",
|
|
197
|
+
"schemas/frontmatter/base.schema.json": "dfee192458765b8cb872ef9e7145ec31b9e07ceb19ee44be48af2172329e7a38",
|
|
240
198
|
"schemas/history-stats.schema.json": "23f472d1de06d23fc775aabba821f8375f347af4dc8d89ba567980d61a11f9de",
|
|
241
199
|
"schemas/issue.schema.json": "40f6f8abadcce0fd8eac9df27ffcc20b2fc9fda6970142ddb8e7e56b1760b9b1",
|
|
242
200
|
"schemas/job.schema.json": "582999899f8846f70c4d745d2813e53b97a4f5ccd3d8d163eeb68b201e7124e4",
|
|
243
|
-
"schemas/link.schema.json": "
|
|
244
|
-
"schemas/node.schema.json": "
|
|
245
|
-
"schemas/plugins-registry.schema.json": "
|
|
246
|
-
"schemas/project-config.schema.json": "
|
|
201
|
+
"schemas/link.schema.json": "0a95a24849a38b9ef5bad5361519a9f9e012b5bc3001289fad29d0851fceff6b",
|
|
202
|
+
"schemas/node.schema.json": "ef80251524ed8a295eb7e98e4399b36cdd1daf3eacd605cacd1ba25edd6f39fc",
|
|
203
|
+
"schemas/plugins-registry.schema.json": "5ca1d4970ae64f064f05c237a649d9f82d5edbeb7c121ec50cb4aaca13f4bc51",
|
|
204
|
+
"schemas/project-config.schema.json": "4f5b1ce01446d78ebf524d11c36e0a3ae101e69008c922a2b3f53fccfd1cb87f",
|
|
247
205
|
"schemas/report-base.schema.json": "a1021e9a59b4df9f99cd92454d797e88469766e7d49f52d231c4645ffdfdad8f",
|
|
248
|
-
"schemas/scan-result.schema.json": "
|
|
206
|
+
"schemas/scan-result.schema.json": "d1a8782e198bc9bb92dad247437aefa1b02f92ff8dca8562eaf2348fd7c5cf0c",
|
|
249
207
|
"schemas/summaries/agent.schema.json": "3d22558eeb170e00c4fc32018a810d27333cc632c9e528ff386100cfdfded087",
|
|
250
208
|
"schemas/summaries/command.schema.json": "2bffd606b24f7df9ccd13890af8725adfbfb8a2d7782fee1e0ac5250b9059117",
|
|
251
209
|
"schemas/summaries/hook.schema.json": "36f876f3b1a60d45be97a0848c79fd18744b434dfdcefc366f033b253d56268c",
|
package/job-events.md
CHANGED
|
@@ -163,6 +163,8 @@ Emitted when the runner is about to execute the job file.
|
|
|
163
163
|
|
|
164
164
|
`command` is implementation-defined free-form; it is descriptive, not invokable.
|
|
165
165
|
|
|
166
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Plugins MAY subscribe a `hook` extension to this event for pre-flight checks or audit logging. Reactions only โ hooks cannot block the spawn.
|
|
167
|
+
|
|
166
168
|
### `model.delta`
|
|
167
169
|
|
|
168
170
|
Emitted in `stream-output` mode only. Carries incremental model output.
|
|
@@ -235,6 +237,8 @@ Emitted when a job transitions to `completed`.
|
|
|
235
237
|
}
|
|
236
238
|
```
|
|
237
239
|
|
|
240
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). The most common hookable event: notification, billing, downstream dispatch.
|
|
241
|
+
|
|
238
242
|
### `job.failed`
|
|
239
243
|
|
|
240
244
|
Emitted when a job transitions to `failed` by any path.
|
|
@@ -256,6 +260,8 @@ Emitted when a job transitions to `failed` by any path.
|
|
|
256
260
|
|
|
257
261
|
`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
262
|
|
|
263
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Hook subscribers commonly use this event for alerting and retry triggers. Filter by `data.reason` to narrow to a specific failure mode.
|
|
264
|
+
|
|
259
265
|
### `run.summary`
|
|
260
266
|
|
|
261
267
|
Emitted once at the end of `sm job run`, after the last job event.
|
|
@@ -330,6 +336,8 @@ Emitted once when a scan begins (full, `--changed`, or `-n <node.path>`).
|
|
|
330
336
|
}
|
|
331
337
|
```
|
|
332
338
|
|
|
339
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Pre-scan setup, telemetry init.
|
|
340
|
+
|
|
333
341
|
#### `scan.progress`
|
|
334
342
|
|
|
335
343
|
Emitted periodically during a scan (implementation-defined cadence; SHOULD throttle to โฅ250 ms apart to keep WS traffic cheap).
|
|
@@ -367,6 +375,70 @@ Emitted once at scan end.
|
|
|
367
375
|
}
|
|
368
376
|
```
|
|
369
377
|
|
|
378
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Post-scan reaction (Slack notification, CI gate, summary email).
|
|
379
|
+
|
|
380
|
+
#### `extractor.completed`
|
|
381
|
+
|
|
382
|
+
Emitted once per registered Extractor, after the full walk completes. Aggregated, NOT per-node โ per-node fan-out lives in `scan.progress`, which is intentionally not hookable.
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"type": "extractor.completed",
|
|
387
|
+
"timestamp": 1745159455900,
|
|
388
|
+
"runId": "...",
|
|
389
|
+
"jobId": null,
|
|
390
|
+
"data": {
|
|
391
|
+
"extractorId": "core/external-url-counter"
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
`extractorId` is the qualified extension id (`<plugin-id>/<id>`).
|
|
397
|
+
|
|
398
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Extractor metrics, audit. Filter by `data.extractorId` to scope to a single Extractor.
|
|
399
|
+
|
|
400
|
+
#### `rule.completed`
|
|
401
|
+
|
|
402
|
+
Emitted once per registered Rule, after every issue has been validated.
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"type": "rule.completed",
|
|
407
|
+
"timestamp": 1745159455950,
|
|
408
|
+
"runId": "...",
|
|
409
|
+
"jobId": null,
|
|
410
|
+
"data": {
|
|
411
|
+
"ruleId": "core/superseded"
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
`ruleId` is the qualified extension id.
|
|
417
|
+
|
|
418
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Rule alerting, downstream tooling. Filter by `data.ruleId`.
|
|
419
|
+
|
|
420
|
+
#### `action.completed`
|
|
421
|
+
|
|
422
|
+
Emitted once per Action invocation, after the report has been recorded.
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
{
|
|
426
|
+
"type": "action.completed",
|
|
427
|
+
"timestamp": 1745159465500,
|
|
428
|
+
"runId": "...",
|
|
429
|
+
"jobId": "...",
|
|
430
|
+
"data": {
|
|
431
|
+
"actionId": "claude/skill-summarizer",
|
|
432
|
+
"node": { "path": "skills/my-skill.md", "kind": "skill" },
|
|
433
|
+
"jobResult": { "tokensIn": 2431, "tokensOut": 1072 }
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
`actionId` is the qualified extension id; `node` carries the target node summary (full `Node` shape per [`schemas/node.schema.json`](./schemas/node.schema.json) is forward-compatible). Lands alongside the job subsystem at Step 10.
|
|
439
|
+
|
|
440
|
+
> **Hookable** โ see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Action notification, integration glue. Filter by `data.actionId`.
|
|
441
|
+
|
|
370
442
|
### Issue events
|
|
371
443
|
|
|
372
444
|
Emitted by the scan after `scan.completed` when the new scan's issue set differs from the previous one. Enables a UI "issue inbox" to update incrementally without re-fetching the full list.
|
|
@@ -447,4 +519,6 @@ Consumers MUST ignore unknown fields (forward compatibility).
|
|
|
447
519
|
|
|
448
520
|
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.
|
|
449
521
|
|
|
450
|
-
The **non-job event families** (`scan.*`, `issue
|
|
522
|
+
The **non-job event families** (`scan.*`, `issue.*`, `extractor.completed`, `rule.completed`, `action.completed`) 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.
|
|
523
|
+
|
|
524
|
+
The **Hook curated trigger set** (eight hookable lifecycle events; see [`architecture.md` ยงHook ยท curated trigger set](./architecture.md#hook--curated-trigger-set)) is itself stable as of the same minor in which it lands: adding a hookable trigger is a minor bump, removing or renaming one is a major bump. The curation policy ("a hook subscribes only to a deliberately small set") is normative โ surface noise reduction is the entire point.
|