@skill-map/spec 0.52.0 → 0.54.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 +32 -0
- package/README.md +12 -10
- package/architecture.md +154 -150
- package/cli-contract.md +138 -141
- package/conformance/README.md +9 -9
- package/conformance/cases/sidecar-end-to-end.json +3 -5
- package/conformance/coverage.md +5 -5
- package/db-schema.md +72 -72
- package/index.json +20 -19
- package/interfaces/security-scanner.md +25 -25
- package/job-events.md +43 -43
- package/job-lifecycle.md +32 -36
- package/package.json +2 -1
- package/plugin-author-guide.md +97 -125
- package/plugin-kv-api.md +22 -23
- package/plugin-quickstart.md +96 -0
- package/prompt-preamble.md +6 -6
- package/schemas/extensions/action.schema.json +6 -0
- package/schemas/project-config.schema.json +4 -0
- package/telemetry.md +120 -136
- package/versioning.md +12 -12
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Security scanner interface
|
|
2
2
|
|
|
3
|
-
Normative contract for third-party security-scanning plugins (Snyk, Socket, custom rulesets,
|
|
3
|
+
Normative contract for third-party security-scanning plugins (Snyk, Socket, custom rulesets, similar). A security scanner is NOT a new extension kind, it is a **convention over the existing `Action` kind**, defined so that:
|
|
4
4
|
|
|
5
5
|
- Multiple vendors can ship interoperable scanners.
|
|
6
6
|
- `sm findings` can aggregate findings across scanners uniformly.
|
|
7
|
-
- The UI can present a single "Security" panel regardless of which scanners are
|
|
7
|
+
- The UI can present a single "Security" panel regardless of which scanners are present.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
## Why a convention, not a new kind
|
|
12
12
|
|
|
13
|
-
The six extension kinds are locked ([`architecture.md`](../architecture.md)).
|
|
13
|
+
The six extension kinds are locked ([`architecture.md`](../architecture.md)). A seventh for "security" would conflate concerns: scanners are actions that produce a specialized report. A convention lets any Action opt into the scanner surface with no kernel changes.
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
@@ -33,13 +33,13 @@ Example manifest:
|
|
|
33
33
|
}
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
The kernel does NOT enforce the `security-` prefix, any Action may produce findings
|
|
36
|
+
The kernel does NOT enforce the `security-` prefix, any Action may produce findings conforming to this schema. But `sm findings --security` and the UI's Security panel filter by prefix **OR** the `tags` label.
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
40
40
|
## Input
|
|
41
41
|
|
|
42
|
-
The Action receives a standard invocation: a single node, or (via `--all`)
|
|
42
|
+
The Action receives a standard invocation: a single node, or (via `--all`) the set of nodes matching the Action's `preconditions`. Scanners typically set:
|
|
43
43
|
|
|
44
44
|
```json
|
|
45
45
|
{
|
|
@@ -47,15 +47,15 @@ The Action receives a standard invocation: a single node, or (via `--all`) a set
|
|
|
47
47
|
}
|
|
48
48
|
```
|
|
49
49
|
|
|
50
|
-
i.e. applies to every node. A scanner MAY narrow to specific kinds if the vendor's check only applies to,
|
|
50
|
+
i.e. applies to every node. A scanner MAY narrow to specific kinds if the vendor's check only applies to, e.g., shell-hook content.
|
|
51
51
|
|
|
52
|
-
Scanners are **deterministic-mode** Actions by default: no LLM involvement. The Action runs its own logic (HTTP request to a vendor API, local regex scan, dependency check) and writes a report. Scanners MAY also be `probabilistic` Actions if
|
|
52
|
+
Scanners are **deterministic-mode** Actions by default: no LLM involvement. The Action runs its own logic (HTTP request to a vendor API, local regex scan, dependency check) and writes a report. Scanners MAY also be `probabilistic` Actions if they rely on model analysis; the same report shape applies.
|
|
53
53
|
|
|
54
54
|
---
|
|
55
55
|
|
|
56
56
|
## Output: the `SecurityReport` shape
|
|
57
57
|
|
|
58
|
-
Every scanner MUST produce a report conforming to this shape
|
|
58
|
+
Every scanner MUST produce a report conforming to this shape, extending [`report-base.schema.json`](../schemas/report-base.schema.json) with scanner-specific fields.
|
|
59
59
|
|
|
60
60
|
```jsonc
|
|
61
61
|
{
|
|
@@ -113,7 +113,7 @@ Every scanner MUST produce a report conforming to this shape. It extends [`repor
|
|
|
113
113
|
| `version` | string (semver) | Scanner version at run time. |
|
|
114
114
|
| `vendor` | string | Human-readable vendor name. |
|
|
115
115
|
| `ranAt` | integer | Unix ms. |
|
|
116
|
-
| `durationMs` | integer |
|
|
116
|
+
| `durationMs` | integer | Scan duration. |
|
|
117
117
|
|
|
118
118
|
**Finding** (`findings[]`), ZERO OR MORE. Each finding MUST include:
|
|
119
119
|
|
|
@@ -121,14 +121,14 @@ Every scanner MUST produce a report conforming to this shape. It extends [`repor
|
|
|
121
121
|
|---|---|---|
|
|
122
122
|
| `id` | string | Globally unique finding id. Convention: `<scannerId>:<vendorFindingId>`. |
|
|
123
123
|
| `severity` | enum | `error` / `warn` / `info`. Maps to deterministic issue severity for aggregation. |
|
|
124
|
-
| `category` | string |
|
|
124
|
+
| `category` | string | A normative category below, or a vendor-specific string prefixed `vendor:`. |
|
|
125
125
|
| `title` | string | Short human-readable summary. |
|
|
126
126
|
| `description` | string | Longer explanation; markdown-friendly. |
|
|
127
127
|
| `nodePath` | string | The `node.path` this finding references. |
|
|
128
128
|
| `locations` | array\|null | Optional in-file locations. Each has `line` (required), `column`, `length`, `raw`. |
|
|
129
129
|
| `references` | array\|null | External URLs (CVE, advisory, blog post). |
|
|
130
130
|
| `remediation` | object\|null | `summary` (string), `autofixable` (boolean). Autofix is advisory, the kernel does not invoke it. |
|
|
131
|
-
| `meta` | object\|null | Vendor-specific free-form
|
|
131
|
+
| `meta` | object\|null | Vendor-specific free-form: CVSS, CWE, CPE, etc. |
|
|
132
132
|
|
|
133
133
|
**Stats** (`stats.*`), REQUIRED summary:
|
|
134
134
|
|
|
@@ -149,34 +149,34 @@ A `category` value SHOULD be one of these for interoperability:
|
|
|
149
149
|
- `outdated`, version pinned well below current, not exploited but due for upgrade.
|
|
150
150
|
- `policy-violation`, organization-level analyzer (naming, banned words, required disclaimer).
|
|
151
151
|
|
|
152
|
-
Vendors MAY introduce their own category
|
|
152
|
+
Vendors MAY introduce their own category prefixed `vendor:<slug>` (e.g. `vendor:socket:supply-chain`). Consumers that don't understand a vendor category MUST treat it as opaque but still display it.
|
|
153
153
|
|
|
154
154
|
---
|
|
155
155
|
|
|
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`](../db-schema.md)`.report_path` points to the JSON
|
|
159
|
+
- The report is persisted through the normal action report mechanism ([`state_executions`](../db-schema.md)`.report_path` points to the JSON).
|
|
160
160
|
- `sm findings --security` aggregates findings from reports whose action id starts with `security-`, merging across scanners, deduplicating by `finding.id`.
|
|
161
|
-
- Implementations MAY also surface findings at scan time via a companion Analyzer (e.g. `security-findings-stale` flags nodes whose last
|
|
161
|
+
- Implementations MAY also surface findings at scan time via a companion Analyzer (e.g. `security-findings-stale` flags nodes whose last scan exceeds a threshold). Recommended but not normative.
|
|
162
162
|
|
|
163
163
|
---
|
|
164
164
|
|
|
165
165
|
## Deduplication
|
|
166
166
|
|
|
167
|
-
Finding ids MUST be stable: re-running the same scanner against unchanged input MUST produce the same `finding.id` values. This
|
|
167
|
+
Finding ids MUST be stable: re-running the same scanner against unchanged input MUST produce the same `finding.id` values. This lets:
|
|
168
168
|
|
|
169
|
-
- `sm findings --since <date>`
|
|
170
|
-
- The UI
|
|
171
|
-
- Aggregators
|
|
169
|
+
- `sm findings --since <date>` show only new findings.
|
|
170
|
+
- The UI diff scan-to-scan.
|
|
171
|
+
- Aggregators dedupe identical reports from multiple provider instances.
|
|
172
172
|
|
|
173
|
-
The convention `<scannerId>:<vendorFindingId>` ensures cross-scanner uniqueness while staying
|
|
173
|
+
The convention `<scannerId>:<vendorFindingId>` ensures cross-scanner uniqueness while staying readable.
|
|
174
174
|
|
|
175
175
|
---
|
|
176
176
|
|
|
177
177
|
## Aggregation into `sm findings`
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
On `sm findings --security`, the kernel:
|
|
180
180
|
|
|
181
181
|
1. Queries `state_executions` for actions whose id starts with `security-`.
|
|
182
182
|
2. For each, loads the most recent report (per `(actionId, nodeId)`).
|
|
@@ -184,7 +184,7 @@ When a consumer calls `sm findings --security`, the kernel:
|
|
|
184
184
|
4. Emits a normalized list: each entry includes `scanner`, `finding`, and `lastRanAt`.
|
|
185
185
|
5. Applies optional filters: `--severity`, `--category`, `--node`, `--since`.
|
|
186
186
|
|
|
187
|
-
The consumer sees a flat list
|
|
187
|
+
The consumer sees a flat list regardless of how many scanners produced it.
|
|
188
188
|
|
|
189
189
|
---
|
|
190
190
|
|
|
@@ -202,15 +202,15 @@ 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 4 of the spec bootstrap completes. Until then, this document is the normative source and vendors SHOULD derive their
|
|
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 validator from it.
|
|
206
206
|
|
|
207
|
-
This is the only `summaries/*` schema that does NOT correspond to a node kind; it corresponds to an action category
|
|
207
|
+
This is the only `summaries/*` schema that does NOT correspond to a node kind; it corresponds to an action category.
|
|
208
208
|
|
|
209
209
|
---
|
|
210
210
|
|
|
211
211
|
## Compliance
|
|
212
212
|
|
|
213
|
-
A scanner
|
|
213
|
+
A scanner whose report does NOT conform to `SecurityReport` is still a valid Action, but does NOT show up in `sm findings --security` or the UI Security panel; conforming is what unlocks the aggregation surface.
|
|
214
214
|
|
|
215
215
|
`sm plugins doctor` MAY emit a warning for Actions prefixed `security-` whose most recent report does not parse as `SecurityReport`.
|
|
216
216
|
|
|
@@ -221,7 +221,7 @@ A scanner that produces a report NOT conforming to `SecurityReport` is still a v
|
|
|
221
221
|
- [`../architecture.md`](../architecture.md), extension kinds (Action) and the kernel contract.
|
|
222
222
|
- [`../job-lifecycle.md`](../job-lifecycle.md), job submit/claim/record flow for scanner invocations.
|
|
223
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
|
|
224
|
+
- [`../db-schema.md`](../db-schema.md), `state_executions`, where scanner reports are persisted.
|
|
225
225
|
|
|
226
226
|
---
|
|
227
227
|
|
package/job-events.md
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
# Job events
|
|
2
2
|
|
|
3
|
-
Canonical event stream emitted during job execution. Every implementation MUST emit these events in the order described, with the shapes
|
|
3
|
+
Canonical event stream emitted during job execution. Every implementation MUST emit these events in the order described, with the shapes below. Consumers: the CLI pretty printer, the `--json` ndjson output, the Server's WebSocket broadcaster, any third-party integration.
|
|
4
4
|
|
|
5
|
-
This document is **normative**. The
|
|
5
|
+
This document is **normative**. The event types, payload shapes, and ordering analyzers are stable contracts.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Transport
|
|
10
10
|
|
|
11
|
-
Events are records
|
|
11
|
+
Events are records the kernel produces through `ProgressEmitterPort` (see [`architecture.md`](./architecture.md)). An implementation MUST provide three output adapters:
|
|
12
12
|
|
|
13
13
|
| Adapter | Purpose | Format |
|
|
14
14
|
|---|---|---|
|
|
15
15
|
| `pretty` | Default TTY output. Human-readable, colored, line-based progress. | Free-form; not normative. |
|
|
16
16
|
| `stream-output` | Pretty + model tokens inline. Debugging mode. | Free-form; not normative. |
|
|
17
|
-
| `json` | Machine-readable ndjson. One event per line
|
|
17
|
+
| `json` | Machine-readable ndjson. One event per line, each a complete JSON object. | **Normative.** Matches the shapes below. |
|
|
18
18
|
|
|
19
|
-
The Server exposes the same events over WebSocket (`/ws`) using the same JSON shapes; each event is a single
|
|
19
|
+
The Server exposes the same events over WebSocket (`/ws`) using the same JSON shapes; each event is a single WS text frame.
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
@@ -38,11 +38,11 @@ Every event is a JSON object with this envelope:
|
|
|
38
38
|
|---|---|---|
|
|
39
39
|
| `type` | always | One of the canonical event types below. |
|
|
40
40
|
| `timestamp` | always | Unix milliseconds when the event was emitted. |
|
|
41
|
-
| `runId` | always | Identifier of the invocation that emitted the event. CLI runner loops use `r-YYYYMMDD-HHMMSS-XXXX`; synthetic or non-job runs
|
|
41
|
+
| `runId` | always | Identifier of the invocation that emitted the event. CLI runner loops use `r-YYYYMMDD-HHMMSS-XXXX`; synthetic or non-job runs add one mode segment: `r-<mode>-YYYYMMDD-HHMMSS-XXXX`. Canonical modes: `ext` (external Skill claims), `scan` (scan runs), `check` (standalone issue recomputations). |
|
|
42
42
|
| `jobId` | when job-scoped | The job the event refers to. Null for run-level events (`run.*`). |
|
|
43
|
-
| `data` | per-event | Event-specific payload, shape
|
|
43
|
+
| `data` | per-event | Event-specific payload, shape below. |
|
|
44
44
|
|
|
45
|
-
Implementations MUST include every envelope field in every event, even if `jobId` is null.
|
|
45
|
+
Implementations MUST include every envelope field in every event, even if `jobId` is null.
|
|
46
46
|
|
|
47
47
|
Unknown fields in `data` MUST be ignored by consumers (forward compatibility).
|
|
48
48
|
|
|
@@ -50,11 +50,11 @@ Unknown fields in `data` MUST be ignored by consumers (forward compatibility).
|
|
|
50
50
|
|
|
51
51
|
## Event catalog
|
|
52
52
|
|
|
53
|
-
Emitted in roughly this order during
|
|
53
|
+
Emitted in roughly this order during `sm job run --all`. The sequence may interleave for parallel runs (deferred to post-`v1.0`).
|
|
54
54
|
|
|
55
55
|
### `run.started`
|
|
56
56
|
|
|
57
|
-
Emitted once at the start of every `sm job run
|
|
57
|
+
Emitted once at the start of every `sm job run`.
|
|
58
58
|
|
|
59
59
|
```json
|
|
60
60
|
{
|
|
@@ -72,7 +72,7 @@ Emitted once at the start of every `sm job run` invocation.
|
|
|
72
72
|
|
|
73
73
|
- `mode`: what the runner was asked to do.
|
|
74
74
|
- `maxJobs`: cap on concurrent drain (`--max N` or null).
|
|
75
|
-
- `filter`: resolved filter predicate
|
|
75
|
+
- `filter`: resolved filter predicate (free-form object).
|
|
76
76
|
|
|
77
77
|
### `run.reap.started`
|
|
78
78
|
|
|
@@ -105,7 +105,7 @@ Emitted after auto-reap finishes.
|
|
|
105
105
|
}
|
|
106
106
|
```
|
|
107
107
|
|
|
108
|
-
- `reapedIds` lists
|
|
108
|
+
- `reapedIds` lists jobs transitioned from `running` to `failed`. May be empty.
|
|
109
109
|
|
|
110
110
|
### `job.claimed`
|
|
111
111
|
|
|
@@ -161,13 +161,13 @@ Emitted when the runner is about to execute the job content.
|
|
|
161
161
|
}
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
-
`command` is implementation-defined free-form;
|
|
164
|
+
`command` is implementation-defined free-form; descriptive, not invokable. `contentHash` references the `state_job_contents` row the runner is about to execute, letting observers correlate the spawn with the rendered content (in DB, not on disk).
|
|
165
165
|
|
|
166
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Plugins MAY subscribe a `hook` extension
|
|
166
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Plugins MAY subscribe a `hook` extension for pre-flight checks or audit logging. Reactions only, hooks cannot block the spawn.
|
|
167
167
|
|
|
168
168
|
### `model.delta`
|
|
169
169
|
|
|
170
|
-
Emitted in `stream-output` mode only
|
|
170
|
+
Emitted in `stream-output` mode only; carries incremental model output.
|
|
171
171
|
|
|
172
172
|
```json
|
|
173
173
|
{
|
|
@@ -182,7 +182,7 @@ Emitted in `stream-output` mode only. Carries incremental model output.
|
|
|
182
182
|
}
|
|
183
183
|
```
|
|
184
184
|
|
|
185
|
-
Consumers of the canonical `json` output MAY receive these events if the runner
|
|
185
|
+
Consumers of the canonical `json` output MAY receive these events if the runner emitted them. `pretty` and `json` adapters MAY drop `model.delta` events for brevity.
|
|
186
186
|
|
|
187
187
|
### `job.callback.received`
|
|
188
188
|
|
|
@@ -202,11 +202,11 @@ Emitted inside `sm record` when the callback arrives and passes nonce validation
|
|
|
202
202
|
}
|
|
203
203
|
```
|
|
204
204
|
|
|
205
|
-
`executionId` references the just-written `state_executions` row whose `report_json` carries the report payload. Consumers
|
|
205
|
+
`executionId` references the just-written `state_executions` row whose `report_json` carries the report payload. Consumers needing the content fetch it via `sm history --json` or the DB; the event stays small.
|
|
206
206
|
|
|
207
|
-
`runId`
|
|
207
|
+
`runId` is the run that originally claimed the job. If `record` is called from outside a CLI run (canonical case: a Skill agent that called `sm job claim` + `sm record` without entering `sm job run`), the kernel MUST synthesize a `runId` of the form `r-ext-YYYYMMDD-HHMMSS-XXXX` (same timestamp + 4-hex shape as real run ids, `r-ext-` prefix reserved for externally-driven claims).
|
|
208
208
|
|
|
209
|
-
Synthetic-run envelope: when a Skill agent claims a job, the kernel MUST emit, on the server's WebSocket and in the `--json` ndjson stream if active
|
|
209
|
+
Synthetic-run envelope: when a Skill agent claims a job, the kernel MUST emit a full envelope covering that claim, on the server's WebSocket and in the `--json` ndjson stream if active:
|
|
210
210
|
|
|
211
211
|
```
|
|
212
212
|
run.started (mode="external")
|
|
@@ -217,7 +217,7 @@ run.started (mode="external")
|
|
|
217
217
|
→ run.summary
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
`run.started.data.mode` carries the literal `external` so UI consumers can render skill-driven work differently from CLI-driven work. `run.summary` closes the synthetic run as soon as the callback is processed; one synthetic run always wraps exactly one job. This keeps the WebSocket broadcaster's contract ("every job event lives inside a run envelope") intact across both runner paths.
|
|
221
221
|
|
|
222
222
|
### `job.completed`
|
|
223
223
|
|
|
@@ -239,9 +239,9 @@ Emitted when a job transitions to `completed`.
|
|
|
239
239
|
}
|
|
240
240
|
```
|
|
241
241
|
|
|
242
|
-
`executionId` references the `state_executions` row
|
|
242
|
+
`executionId` references the `state_executions` row holding the report payload (in `report_json`). The full report is intentionally NOT inlined; events stay small, consumers query the row.
|
|
243
243
|
|
|
244
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set).
|
|
244
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Most common hookable event: notification, billing.
|
|
245
245
|
|
|
246
246
|
### `job.failed`
|
|
247
247
|
|
|
@@ -262,9 +262,9 @@ Emitted when a job transitions to `failed` by any path.
|
|
|
262
262
|
}
|
|
263
263
|
```
|
|
264
264
|
|
|
265
|
-
`reason` enum matches [`execution-record.schema.json`](./schemas/execution-record.schema.json) `failureReason`. `message` is human-readable free-form
|
|
265
|
+
`reason` enum matches [`execution-record.schema.json`](./schemas/execution-record.schema.json) `failureReason`. `message` is human-readable free-form, MAY be truncated for display.
|
|
266
266
|
|
|
267
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set).
|
|
267
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Common use: alerting and retry triggers. Filter by `data.reason` to narrow to a specific failure mode.
|
|
268
268
|
|
|
269
269
|
### `run.summary`
|
|
270
270
|
|
|
@@ -310,15 +310,15 @@ run.started
|
|
|
310
310
|
|
|
311
311
|
A parallel implementation MAY interleave per-job sequences across different `jobId` values, but MUST preserve ordering within a single `jobId`.
|
|
312
312
|
|
|
313
|
-
`job.failed` with reason `abandoned` MAY appear without a matching `job.claimed` in the current run
|
|
313
|
+
`job.failed` with reason `abandoned` MAY appear without a matching `job.claimed` in the current run: it refers to a job claimed in a previous run that expired before the next reap.
|
|
314
314
|
|
|
315
315
|
---
|
|
316
316
|
|
|
317
317
|
## Non-job events (Stability: experimental)
|
|
318
318
|
|
|
319
|
-
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
|
|
319
|
+
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: a scan gets an `r-scan-YYYYMMDD-HHMMSS-XXXX` id, an issue recomputation outside a scan an `r-check-...` id, following the same `r-<mode>-...` shape as the external-Skill envelope (`r-ext-...`).
|
|
320
320
|
|
|
321
|
-
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
|
|
321
|
+
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 to `stable` is a minor spec bump; field-shape changes before `stable` are allowed without a major bump (per [`versioning.md`](./versioning.md) §Pre-1.0).
|
|
322
322
|
|
|
323
323
|
### Scan events
|
|
324
324
|
|
|
@@ -379,11 +379,11 @@ Emitted once at scan end.
|
|
|
379
379
|
}
|
|
380
380
|
```
|
|
381
381
|
|
|
382
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Post-scan reaction (Slack notification, CI gate
|
|
382
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Post-scan reaction (Slack notification, CI gate).
|
|
383
383
|
|
|
384
384
|
#### `extractor.completed`
|
|
385
385
|
|
|
386
|
-
Emitted once per registered Extractor, after the full walk
|
|
386
|
+
Emitted once per registered Extractor, after the full walk. Aggregated, NOT per-node; per-node fan-out lives in `scan.progress`, which is intentionally not hookable.
|
|
387
387
|
|
|
388
388
|
```json
|
|
389
389
|
{
|
|
@@ -399,11 +399,11 @@ Emitted once per registered Extractor, after the full walk completes. Aggregated
|
|
|
399
399
|
|
|
400
400
|
`extractorId` is the qualified extension id (`<plugin-id>/<id>`).
|
|
401
401
|
|
|
402
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Extractor metrics
|
|
402
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Extractor metrics. Filter by `data.extractorId` to scope to one Extractor.
|
|
403
403
|
|
|
404
404
|
#### `analyzer.completed`
|
|
405
405
|
|
|
406
|
-
Emitted once per registered Analyzer, after every issue
|
|
406
|
+
Emitted once per registered Analyzer, after every issue is validated.
|
|
407
407
|
|
|
408
408
|
```json
|
|
409
409
|
{
|
|
@@ -419,11 +419,11 @@ Emitted once per registered Analyzer, after every issue has been validated.
|
|
|
419
419
|
|
|
420
420
|
`analyzerId` is the qualified extension id.
|
|
421
421
|
|
|
422
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Analyzer alerting
|
|
422
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Analyzer alerting. Filter by `data.analyzerId`.
|
|
423
423
|
|
|
424
424
|
#### `action.completed`
|
|
425
425
|
|
|
426
|
-
Emitted once per Action invocation, after the report
|
|
426
|
+
Emitted once per Action invocation, after the report is recorded.
|
|
427
427
|
|
|
428
428
|
```json
|
|
429
429
|
{
|
|
@@ -439,13 +439,13 @@ Emitted once per Action invocation, after the report has been recorded.
|
|
|
439
439
|
}
|
|
440
440
|
```
|
|
441
441
|
|
|
442
|
-
`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
|
|
442
|
+
`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 at Step 10 with the job subsystem.
|
|
443
443
|
|
|
444
|
-
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Action notification
|
|
444
|
+
> **Hookable**, see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set). Per-Action notification. Filter by `data.actionId`.
|
|
445
445
|
|
|
446
446
|
### Issue events
|
|
447
447
|
|
|
448
|
-
Emitted by the scan after `scan.completed` when the new scan's issue set differs from the previous
|
|
448
|
+
Emitted by the scan after `scan.completed` when the new scan's issue set differs from the previous. Lets a UI "issue inbox" update incrementally without re-fetching the full list.
|
|
449
449
|
|
|
450
450
|
#### `issue.added`
|
|
451
451
|
|
|
@@ -466,7 +466,7 @@ Emitted by the scan after `scan.completed` when the new scan's issue set differs
|
|
|
466
466
|
|
|
467
467
|
#### `issue.resolved`
|
|
468
468
|
|
|
469
|
-
Emitted when an issue present in the previous scan is absent from the new
|
|
469
|
+
Emitted when an issue present in the previous scan is absent from the new.
|
|
470
470
|
|
|
471
471
|
```json
|
|
472
472
|
{
|
|
@@ -481,7 +481,7 @@ Emitted when an issue present in the previous scan is absent from the new one.
|
|
|
481
481
|
}
|
|
482
482
|
```
|
|
483
483
|
|
|
484
|
-
Issue diffing is keyed on `(analyzerId, nodeIds sorted, message)
|
|
484
|
+
Issue diffing is keyed on `(analyzerId, nodeIds sorted, message)`: same key → same issue. A payload change on the same key emits no event; consumers re-read full issue detail from `sm check`.
|
|
485
485
|
|
|
486
486
|
---
|
|
487
487
|
|
|
@@ -501,7 +501,7 @@ If an event payload cannot be serialized (internal bug), the implementation MUST
|
|
|
501
501
|
}
|
|
502
502
|
```
|
|
503
503
|
|
|
504
|
-
Consumers MAY treat `emitter.error` as a soft failure (log and continue). Implementations MUST NOT crash the run
|
|
504
|
+
Consumers MAY treat `emitter.error` as a soft failure (log and continue). Implementations MUST NOT crash the run on a serialization failure.
|
|
505
505
|
|
|
506
506
|
---
|
|
507
507
|
|
|
@@ -515,14 +515,14 @@ Consumers MAY treat `emitter.error` as a soft failure (log and continue). Implem
|
|
|
515
515
|
|
|
516
516
|
## Stability
|
|
517
517
|
|
|
518
|
-
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
|
|
518
|
+
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.
|
|
519
519
|
|
|
520
|
-
**Adding** fields to `data` is a minor bump
|
|
520
|
+
**Adding** fields to `data` is a minor bump; changing a field's type or removing a field is a major bump.
|
|
521
521
|
|
|
522
522
|
Consumers MUST ignore unknown fields (forward compatibility).
|
|
523
523
|
|
|
524
524
|
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.
|
|
525
525
|
|
|
526
|
-
The **non-job event families** (`scan.*`, `issue.*`, `extractor.completed`, `analyzer.completed`, `action.completed`) are
|
|
526
|
+
The **non-job event families** (`scan.*`, `issue.*`, `extractor.completed`, `analyzer.completed`, `action.completed`) are **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.
|
|
527
527
|
|
|
528
|
-
The **Hook curated trigger set** (eight hookable lifecycle events; see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set)) is
|
|
528
|
+
The **Hook curated trigger set** (eight hookable lifecycle events; see [`architecture.md` §Hook · curated trigger set](./architecture.md#hook--curated-trigger-set)) is stable as of the 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 point.
|