@skill-map/spec 0.8.0 → 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 CHANGED
@@ -1,5 +1,110 @@
1
1
  # Spec changelog
2
2
 
3
+ ## 0.9.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 88afe24: Cleanup pass post-v0.8.0 — finishing the renames and wiring the
8
+ conformance kill-switches.
9
+
10
+ **Pre-1.0 minor bump** per `spec/versioning.md` § Pre-1.0. The schema
11
+ field rename below is technically breaking, but ships as a minor while
12
+ the spec stays `0.Y.Z`.
13
+
14
+ ## Spec changes (`@skill-map/spec`)
15
+
16
+ ### Breaking — `conformance-case.schema.json`
17
+
18
+ - **Rename `setup.disableAllDetectors` → `setup.disableAllExtractors`.**
19
+ Finishes the kind rename Detector → Extractor introduced in 0.8.0
20
+ (Phase 2 of the plug-in model overhaul). The previous name was the
21
+ last residue and it never reached a release where anything consumed
22
+ it.
23
+ - **`setup.disableAll{Providers,Extractors,Rules}` are now consumed
24
+ end-to-end.** Until this release the three toggles were declared in
25
+ the schema and accepted by the runner, but the runner never threaded
26
+ them anywhere — the `kernel-empty-boot` case happened to pass
27
+ because its fixture is empty. The runner now injects
28
+ `SKILL_MAP_DISABLE_ALL_{PROVIDERS,EXTRACTORS,RULES}=1` into the
29
+ child process environment when the matching toggle is `true`, and
30
+ the CLI's scan composer drops every extension of the disabled kind
31
+ from the in-scan pipeline regardless of granularity gates and
32
+ `--no-built-ins`. Each toggle now has a docstring on the schema
33
+ property pointing at the env-var convention.
34
+ - `kernel-empty-boot` case updated for the rename.
35
+ - `conformance/README.md` example updated.
36
+
37
+ ### Non-breaking — copy fixes
38
+
39
+ - Comments and docstrings across `architecture.md` and friends already
40
+ refer to "Extractor" everywhere; only the schema field stayed on the
41
+ old name. No prose changes in this bump.
42
+
43
+ ## CLI changes (`@skill-map/cli`)
44
+
45
+ ### Breaking — `IDiscoveredPlugin.status` enum
46
+
47
+ - **Rename `'loaded'` → `'enabled'`.** The schema enum
48
+ (`plugins-registry.schema.json`) already used `enabled` since 0.8.0;
49
+ the runtime drifted to `loaded` and has now been pulled back so the
50
+ runtime status matches the spec contract. `'disabled'`, the
51
+ semantic pair, was already aligned. Every consumer (`sm plugins
52
+ list`, `sm plugins doctor`, `sm db prune` plugin filter, runtime
53
+ plugin composer) updated. No published consumers exist.
54
+
55
+ ### Non-breaking — sweep cleanup
56
+
57
+ - Old `Detector` / `detector` references (kind name, manifest field
58
+ names, JSDoc, comments, test fixture filenames, test variable
59
+ names) replaced with `Extractor` / `extractor` across the
60
+ production code and test suite. Excludes historical CHANGELOG
61
+ entries, explicit migration notes ("Renamed from Detector"), and
62
+ test data strings whose semantics are independent of the kind
63
+ name (e.g. `'@FooDetector'` in trigger normalization tests).
64
+ - A residual reference to "an audit reading `ScanResult.issues`" in
65
+ `validate-all`'s docstring rewritten without the removed kind name.
66
+
67
+ ## Tests
68
+
69
+ - `plugin-runtime-branches.test.ts` — five new unit tests covering
70
+ the env-var kill-switch in `composeScanExtensions` (per kind, all
71
+ three together, and stray-value resilience).
72
+ - `conformance-disable-flags.test.ts` — four new e2e tests pointing
73
+ the runner at a populated fixture with each toggle in turn (and a
74
+ baseline) so a regression in the env-var pipeline shows up
75
+ structurally rather than relying on the empty-fixture coincidence.
76
+
77
+ ## [Unreleased]
78
+
79
+ ### Minor (breaking, pre-1.0)
80
+
81
+ - **`conformance-case.schema.json` — rename `setup.disableAllDetectors`
82
+ → `setup.disableAllExtractors`.** Finishes the kind rename Detector →
83
+ Extractor introduced in 0.8.0 (Phase 2 of the plug-in model
84
+ overhaul). The previous name was a residue from an unfinished sweep
85
+ and never reached a release that consumed it.
86
+ - **`setup.disableAll{Providers,Extractors,Rules}` are now wired
87
+ end-to-end.** Until this release the toggles were declared in the
88
+ schema but the runner threaded them nowhere; the `kernel-empty-boot`
89
+ case happened to pass because its fixture is empty. The runner now
90
+ injects `SKILL_MAP_DISABLE_ALL_{PROVIDERS,EXTRACTORS,RULES}=1` into
91
+ the child process environment per toggle, and the CLI's scan
92
+ composer drops every extension of the disabled kind from the
93
+ in-scan pipeline (overriding granularity gates and `--no-built-ins`).
94
+ Migration: any case JSON authored against the unwired schema needs
95
+ to swap `disableAllDetectors` for `disableAllExtractors`; behaviour
96
+ changes only when the toggles were already `true` (those cases will
97
+ now actually disable the kind, where previously they relied on
98
+ fixture content for the same outcome).
99
+
100
+ ### Patch
101
+
102
+ - Updated `conformance/cases/kernel-empty-boot.json` for the field
103
+ rename above.
104
+ - Updated `conformance/README.md` example for the field rename above.
105
+ - Schema docstrings added to each `disableAll*` property documenting
106
+ the env-var convention the runner uses.
107
+
3
108
  ## 0.8.0
4
109
 
5
110
  ### Minor Changes
@@ -83,36 +188,32 @@
83
188
  - **H3 — `--dry-run` semantics unified across `init` / `db reset`
84
189
  / `db restore`.** The new spec §Dry-run codifies the "no
85
190
  writes, reads OK" contract; three verbs that did not previously
86
- expose a preview now do:
87
- - `sm init --dry-run` — previews the would-create lines for
88
- `.skill-map/`, `settings.json`, `settings.local.json`,
89
- `.skill-mapignore`, the `.gitignore` entries that would be
90
- appended (deduped against the existing file), the DB
91
- provisioning, and the first-scan trigger. Honours `--force`
92
- for the would-overwrite preview. Re-init over an existing
93
- scope without `--force` still exits 2 (same gate as live).
94
- - `sm db reset --dry-run` (default + `--state`) — opens the DB
95
- read-only, computes the row count per `scan_*` (and `state_*`
96
- when `--state`) table, and prints them. No `DELETE`
97
- statements issued. Bypasses the `--state` confirmation prompt
98
- entirely.
99
- - `sm db reset --hard --dry-run` — reports the DB file path and
100
- size that would be unlinked; missing-file case prints a clear
101
- no-op line instead of an error.
102
- - `sm db restore <src> --dry-run` — validates the source exists
103
- (still exits 5 if missing), reports the source size and
104
- whether the target would be created or overwritten, plus the
105
- WAL / SHM sidecars that would be dropped. Bypasses the
106
- confirmation prompt.
107
- Implementation: new helper `previewGitignoreEntries(scopeRoot,
191
+ expose a preview now do: - `sm init --dry-run` — previews the would-create lines for
192
+ `.skill-map/`, `settings.json`, `settings.local.json`,
193
+ `.skill-mapignore`, the `.gitignore` entries that would be
194
+ appended (deduped against the existing file), the DB
195
+ provisioning, and the first-scan trigger. Honours `--force`
196
+ for the would-overwrite preview. Re-init over an existing
197
+ scope without `--force` still exits 2 (same gate as live). - `sm db reset --dry-run` (default + `--state`) — opens the DB
198
+ read-only, computes the row count per `scan_*` (and `state_*`
199
+ when `--state`) table, and prints them. No `DELETE`
200
+ statements issued. Bypasses the `--state` confirmation prompt
201
+ entirely. - `sm db reset --hard --dry-run` reports the DB file path and
202
+ size that would be unlinked; missing-file case prints a clear
203
+ no-op line instead of an error. - `sm db restore <src> --dry-run` — validates the source exists
204
+ (still exits 5 if missing), reports the source size and
205
+ whether the target would be created or overwritten, plus the
206
+ WAL / SHM sidecars that would be dropped. Bypasses the
207
+ confirmation prompt.
208
+ Implementation: new helper `previewGitignoreEntries(scopeRoot,
108
209
  entries)` in `init.ts` mirrors `ensureGitignoreEntries` parsing
109
- so the preview tracks the live outcome exactly. Texts moved
110
- into `cli/i18n/init.texts.ts` and `cli/i18n/db.texts.ts` per
111
- the N4 pattern. **9 new tests** under `init-cli.test.ts` (5
112
- cases) and `db-cli.test.ts` (9 cases) cover the previews + the
113
- spec invariants ("DB file checksum unchanged after dry-run",
114
- "scope directory absent after dry-run", "source-not-found
115
- still exits 5", "confirmation prompt skipped under dry-run").
210
+ so the preview tracks the live outcome exactly. Texts moved
211
+ into `cli/i18n/init.texts.ts` and `cli/i18n/db.texts.ts` per
212
+ the N4 pattern. **9 new tests** under `init-cli.test.ts` (5
213
+ cases) and `db-cli.test.ts` (9 cases) cover the previews + the
214
+ spec invariants ("DB file checksum unchanged after dry-run",
215
+ "scope directory absent after dry-run", "source-not-found
216
+ still exits 5", "confirmation prompt skipped under dry-run").
116
217
  - **H1 — Centralised exit codes.** New `cli/util/exit-codes.ts`
117
218
  exporting `ExitCode` (`Ok` / `Issues` / `Error` / `Duplicate` /
118
219
  `NonceMismatch` / `NotFound`) and the type alias `TExitCode`.
@@ -247,53 +348,53 @@ the`CamelCasePlugin`; raw SQL fragments must use snake_case to
247
348
  a real i18n library, the strings move as-is. Functions would
248
349
  have to be re-shaped first.
249
350
 
250
- Helper at `kernel/util/tx.ts`. Contract:
251
-
252
- - Every `{{name}}` token MUST have a matching key in the vars
253
- object — missing key throws (silent fallback hides
254
- forgotten args in production).
255
- - `null` / `undefined` values throw — caller coerces
256
- upstream.
257
- - Whitespace inside the braces tolerated (`{{ name }}`) so
258
- long templates wrap cleanly across `+`-joined lines.
259
- - Plural / conditional logic does NOT live in the template;
260
- the caller picks `*_singular` vs `*_plural` keys.
261
-
262
- Files created:
263
-
264
- - `kernel/util/tx.ts` — the helper itself, with 13 tests in
265
- `test/tx.test.ts` (single / multi token, whitespace,
266
- missing / null / undefined keys, identifier shapes, error
267
- truncation).
268
- - `kernel/i18n/orchestrator.texts.ts` — frontmatter
269
- malformed/invalid templates, `extension.error` payloads,
270
- root validation errors.
271
- - `kernel/i18n/plugin-loader.texts.ts` — every `load-error` /
272
- `invalid-manifest` / `incompatible-spec` reason, plus the
273
- import timeout message.
274
- - `cli/i18n/scan.texts.ts` — `sm scan` flag-clash / scan
275
- failure / guard / summary templates, plus the `sm scan
276
- compare-with` dump-load errors.
277
- - `cli/i18n/watch.texts.ts` — `sm watch` lifecycle templates.
278
- - `cli/i18n/init.texts.ts` — `sm init` templates including
279
- the `--dry-run` previews and the singular/plural pair for
351
+ Helper at `kernel/util/tx.ts`. Contract:
352
+
353
+ - Every `{{name}}` token MUST have a matching key in the vars
354
+ object — missing key throws (silent fallback hides
355
+ forgotten args in production).
356
+ - `null` / `undefined` values throw — caller coerces
357
+ upstream.
358
+ - Whitespace inside the braces tolerated (`{{ name }}`) so
359
+ long templates wrap cleanly across `+`-joined lines.
360
+ - Plural / conditional logic does NOT live in the template;
361
+ the caller picks `*_singular` vs `*_plural` keys.
362
+
363
+ Files created:
364
+
365
+ - `kernel/util/tx.ts` — the helper itself, with 13 tests in
366
+ `test/tx.test.ts` (single / multi token, whitespace,
367
+ missing / null / undefined keys, identifier shapes, error
368
+ truncation).
369
+ - `kernel/i18n/orchestrator.texts.ts` — frontmatter
370
+ malformed/invalid templates, `extension.error` payloads,
371
+ root validation errors.
372
+ - `kernel/i18n/plugin-loader.texts.ts` — every `load-error` /
373
+ `invalid-manifest` / `incompatible-spec` reason, plus the
374
+ import timeout message.
375
+ - `cli/i18n/scan.texts.ts` — `sm scan` flag-clash / scan
376
+ failure / guard / summary templates, plus the `sm scan
377
+
378
+ compare-with`dump-load errors.
379
+ -`cli/i18n/watch.texts.ts`—`sm watch`lifecycle templates.
380
+ -`cli/i18n/init.texts.ts`—`sm init`templates including
381
+ the`--dry-run`previews and the singular/plural pair for
280
382
  gitignore updates.
281
- - `cli/i18n/db.texts.ts` — `sm db reset` / `sm db restore`
282
- templates including their `--dry-run` previews.
283
- - `cli/i18n/cli-progress-emitter.texts.ts` the
284
- `extension.error: ...` stderr line.
285
-
286
- String content moved verbatim every existing test that
287
- matches on stderr / stdout content keeps passing. Trivial
288
- single-token strings (`'No issues.\n'`) and rare per-handler
289
- bespoke phrases stay inline; the pattern is now established
290
- for whoever wants to migrate them in a follow-up.
291
-
292
- Note on `ui/` divergence: today the two workspaces use
293
- different shapes for their text tables (functions in `ui/`,
294
- templates in `cli/`). Aligning them is a follow-up the day a
295
- real i18n library lands, both converge on its native shape.
296
- The CLI shape is closer to the eventual destination.
383
+ -`cli/i18n/db.texts.ts`—`sm db reset`/`sm db restore` templates including their`--dry-run`previews.
384
+ -`cli/i18n/cli-progress-emitter.texts.ts`— the
385
+ `extension.error: ...` stderr line.
386
+
387
+ String content moved verbatim — every existing test that
388
+ matches on stderr / stdout content keeps passing. Trivial
389
+ single-token strings (`'No issues.\n'`) and rare per-handler
390
+ bespoke phrases stay inline; the pattern is now established
391
+ for whoever wants to migrate them in a follow-up.
392
+
393
+ Note on `ui/` divergence: today the two workspaces use
394
+ different shapes for their text tables (functions in `ui/`,
395
+ templates in `cli/`). Aligning them is a follow-up — the day a
396
+ real i18n library lands, both converge on its native shape.
397
+ The CLI shape is closer to the eventual destination.
297
398
 
298
399
  - **N6 — `TIssueSeverity` aliased to `Severity`.** SQLite schema
299
400
  type now reads `type TIssueSeverity = Severity` instead of
@@ -941,9 +1042,9 @@ kind, normalizedTrigger)` and prints one row per group with the
941
1042
  (`Links out (12, 9 unique)`). When N > 1 detector emits the same
942
1043
  logical link, the row also gets a `(×N)` suffix.
943
1044
 
944
- `--json` output is byte-identical to before — raw rows, no merge.
945
- Storage is byte-identical to before. The grouping is purely a
946
- read-time presentation choice for human eyes.
1045
+ `--json` output is byte-identical to before — raw rows, no merge.
1046
+ Storage is byte-identical to before. The grouping is purely a
1047
+ read-time presentation choice for human eyes.
947
1048
 
948
1049
  **Spec changes (patch)**:
949
1050
 
@@ -64,7 +64,7 @@ A case is a JSON document with this shape:
64
64
 
65
65
  "setup": {
66
66
  "disableAllProviders": false,
67
- "disableAllDetectors": false,
67
+ "disableAllExtractors": false,
68
68
  "disableAllRules": false
69
69
  },
70
70
 
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "$schema": "https://skill-map.dev/spec/v0/conformance-case.schema.json",
3
3
  "id": "kernel-empty-boot",
4
- "description": "With every Provider, detector, and rule disabled, scanning an empty scope MUST return a valid, zero-filled ScanResult. Enforces the kernel boot invariant from architecture.md.",
4
+ "description": "With every Provider, extractor, and rule disabled, scanning an empty scope MUST return a valid, zero-filled ScanResult. Enforces the kernel boot invariant from architecture.md.",
5
5
  "setup": {
6
6
  "disableAllProviders": true,
7
- "disableAllDetectors": true,
7
+ "disableAllExtractors": true,
8
8
  "disableAllRules": true
9
9
  },
10
10
  "invoke": {
@@ -60,4 +60,4 @@ These have their own conformance cases even though they are not JSON Schemas.
60
60
 
61
61
  - **spec v0.x**: partial coverage acceptable. Every case added as the reference impl lands the verb that makes it runnable.
62
62
  - **spec v1.0.0 release**: all rows above MUST be 🟢 covered or explicitly 🟠 deferred to v1.1 with a linked issue.
63
- - **CI check**: [`scripts/check-coverage.mjs`](../../scripts/check-coverage.mjs) 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`.
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/index.json CHANGED
@@ -166,26 +166,26 @@
166
166
  }
167
167
  ]
168
168
  },
169
- "specPackageVersion": "0.8.0",
169
+ "specPackageVersion": "0.9.0",
170
170
  "integrity": {
171
171
  "algorithm": "sha256",
172
172
  "files": {
173
- "CHANGELOG.md": "04766216f59e532c4c4b144087be5b47da8097f4f45aba847a033d5cc01e01cf",
173
+ "CHANGELOG.md": "d793bcd3df7ffde80f5ad66c245d50d38aedf0a6a10146858877afbabe1ebf09",
174
174
  "README.md": "bd30780525e75379eaeb5f8a903bdc601daf3862f3ec69dffc96c437e8d476fc",
175
175
  "architecture.md": "c69a50e3e9b7d091799bd19cd9efe854a924c83bc2c8e79e0fcb727196151f6c",
176
176
  "cli-contract.md": "1d09d047e07fd8793968259660012ebf64ab136967afead2d2666a59a40a020a",
177
- "conformance/README.md": "4a77b4251ebe708692f5c14d2420f740dd4f1743b6f080f0b6e0c1faac179a50",
178
- "conformance/cases/kernel-empty-boot.json": "e56ed102f4ff745acb4ee4c3ebdea20a84b4bf17c8bec85eb1ef4bd471f2afbe",
179
- "conformance/coverage.md": "317636edefeed5d6488bcc8f228a4c8bf72f02087a9afcfc142cd102c761c31b",
177
+ "conformance/README.md": "07970f06c467e34413f07f6d8bec09ece892d1a903fa039d25b34a77e91187d2",
178
+ "conformance/cases/kernel-empty-boot.json": "ad4bbe9d637537625025c8bdb61285b1433568a2544b1ce0248f304ccff8c350",
179
+ "conformance/coverage.md": "eb57cd979bca59a252e3cd49796e068ac601169f859f32cdf37634486574c44c",
180
180
  "conformance/fixtures/preamble-v1.txt": "1e0aeef224b64477bdc13a949c3ad402e68249caf499ecdba1302371677c068b",
181
181
  "db-schema.md": "f570b7ec123a1bbe8936e111a3e3b0597855b2aff0cac82b89fa88d4233a4d73",
182
- "interfaces/security-scanner.md": "e46d33d6e39b15672c8f7350f1cbd4755534510fe57c679c2b1d0be57577d818",
182
+ "interfaces/security-scanner.md": "4a982667008f233656f44c61ce9948e062432d3debdcbf7a134da03bd4139d7d",
183
183
  "job-events.md": "831501bd696a2801e2d160b314eb49794d0ba553da4487e15c7dcc72a1c230f6",
184
184
  "job-lifecycle.md": "1fe88b1a2ed204e41bb41ac172fbb3e912dccd0dd8a1f8ea8e21a681b336d6ee",
185
- "plugin-author-guide.md": "c2633043c423935ec45ef2e1f11dd153762b6b01b45820d9963ff68bd135b67a",
185
+ "plugin-author-guide.md": "2dcdf8c570342d94c2c8f8d47594715254e3956d7939443023f1d6420e2b30d0",
186
186
  "plugin-kv-api.md": "04b2178f46fb88adeae9240df9c9e1761b660396072001dac32cd402e11a2d7d",
187
187
  "prompt-preamble.md": "23a8eff0477fbbc46192a27781bc781bda4202bb9c669b7a7a002b0d668146b0",
188
- "schemas/conformance-case.schema.json": "ca35a1303c48043f60bbe5fc6c9d9bb88dac0f7fd381f42f596fc6dbb1d4a532",
188
+ "schemas/conformance-case.schema.json": "7cd0f3aae5124f24be57cddb213d002d0466f79d06fd3da896075c8b28650410",
189
189
  "schemas/execution-record.schema.json": "607e939bfcac4e18385ef93e27bbe28987ba35d5a7c67f3d6e4377ca819a9425",
190
190
  "schemas/extensions/action.schema.json": "ec4c2fd74b73a140744c195da91d287a88bfecac206d029910ae0dcb0ab9ce35",
191
191
  "schemas/extensions/base.schema.json": "e5c3406b88b0496a89791890b05083929429319d96b1f8cea0bec3ec9e3de8af",
@@ -28,7 +28,7 @@ Example manifest:
28
28
  "id": "security-snyk",
29
29
  "version": "1.0.0",
30
30
  "specCompat": "^1.0.0",
31
- "extensions": ["extensions/snyk.action.mjs"],
31
+ "extensions": ["extensions/snyk.action.js"],
32
32
  "tags": ["kind:scanner", "vendor:snyk"]
33
33
  }
34
34
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-map/spec",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -14,7 +14,7 @@ This guide is **descriptive prose**, not the normative contract. The normative p
14
14
  my-plugin/
15
15
  ├── plugin.json ← manifest (required)
16
16
  └── extensions/
17
- └── extractor.mjs ← one file per declared extension
17
+ └── extractor.js ← one file per declared extension
18
18
  ```
19
19
 
20
20
  ```jsonc
@@ -23,12 +23,12 @@ my-plugin/
23
23
  "id": "my-plugin",
24
24
  "version": "1.0.0",
25
25
  "specCompat": "^1.0.0",
26
- "extensions": ["./extensions/extractor.mjs"]
26
+ "extensions": ["./extensions/extractor.js"]
27
27
  }
28
28
  ```
29
29
 
30
30
  ```javascript
31
- // my-plugin/extensions/extractor.mjs
31
+ // my-plugin/extensions/extractor.js
32
32
  export default {
33
33
  id: 'my-extractor',
34
34
  kind: 'extractor',
@@ -150,8 +150,8 @@ In your own plugin's `plugin.json`, set `granularity` only when you opt into the
150
150
  "specCompat": "^1.0.0",
151
151
  "granularity": "extension",
152
152
  "extensions": [
153
- "./extensions/orphan-skill-rule.mjs",
154
- "./extensions/csv-formatter.mjs"
153
+ "./extensions/orphan-skill-rule.js",
154
+ "./extensions/csv-formatter.js"
155
155
  ]
156
156
  }
157
157
  ```
@@ -625,7 +625,7 @@ import { test } from 'node:test';
625
625
  import { strictEqual } from 'node:assert';
626
626
  import { runExtractorOnFixture, node } from '@skill-map/testkit';
627
627
 
628
- import extractor from '../extensions/extractor.mjs';
628
+ import extractor from '../extensions/extractor.js';
629
629
 
630
630
  test('emits one reference per [[ref:<name>]] token', async () => {
631
631
  const { links } = await runExtractorOnFixture(extractor, {
@@ -31,9 +31,18 @@
31
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
- "disableAllProviders": { "type": "boolean" },
35
- "disableAllDetectors": { "type": "boolean" },
36
- "disableAllRules": { "type": "boolean" },
34
+ "disableAllProviders": {
35
+ "type": "boolean",
36
+ "description": "When true, the runner injects `SKILL_MAP_DISABLE_ALL_PROVIDERS=1` into the child process environment, dropping every Provider extension (built-in and user-plugin) before scan composition."
37
+ },
38
+ "disableAllExtractors": {
39
+ "type": "boolean",
40
+ "description": "When true, the runner injects `SKILL_MAP_DISABLE_ALL_EXTRACTORS=1` into the child process environment, dropping every Extractor extension before scan composition."
41
+ },
42
+ "disableAllRules": {
43
+ "type": "boolean",
44
+ "description": "When true, the runner injects `SKILL_MAP_DISABLE_ALL_RULES=1` into the child process environment, dropping every Rule extension before scan composition."
45
+ },
37
46
  "priorScans": {
38
47
  "type": "array",
39
48
  "description": "Ordered staging scans, each running before the next. For step N, the runner first replaces the scope's Provider 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.",