@skill-map/spec 0.37.0 → 0.38.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,37 @@
1
1
  # Spec changelog
2
2
 
3
+ ## 0.38.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d3c47b2: Adds a hard cap on the number of files `sm scan` and `sm watch` accept after `.skillmapignore` filtering, plus a persistent UI banner that fires when the graph crosses the recommended limit. Default cap is **256 nodes**. Override per invocation with `--max-nodes <N>` (bidirectional: raises OR lowers the cap).
8
+
9
+ **Spec (`spec/schemas/project-config.schema.json`)**: new `scan.maxNodes` integer field (default 256, minimum 1). Documented in `spec/cli-contract.md` §Scan / Node cap.
10
+
11
+ **Spec (`spec/schemas/scan-result.schema.json`)**: ScanResult envelope gains two optional fields, `recommendedNodeLimit` (effective cap that produced this scan) and `overrideMaxNodes` (per-invocation override or `null`). Absent on legacy / synthetic fixtures.
12
+
13
+ **Kernel walker (`src/kernel/orchestrator/walk.ts`)**: `walkAndExtract` accepts `recommendedNodeLimit` + `overrideMaxNodes` and stops accepting classified nodes once `accum.nodes.length >= effectiveLimit`. Result envelope echoes both values plus a `capReached: boolean` derived signal so callers can phrase a "scan capped" notice without re-deriving it.
14
+
15
+ **DB schema (`src/migrations/001_initial.sql`)**: `scan_meta` gains two columns, `recommended_node_limit` and `override_max_nodes` (nullable). Edited inline per the project's greenfield rule, no new migration file. The persistence layer (`scan-persistence.ts`, `scan-load.ts`) serialises / deserialises both columns; synthetic envelopes default `recommendedNodeLimit` to 256.
16
+
17
+ **CLI surface (`src/cli/commands/scan.ts`, `src/cli/commands/watch.ts`, `src/core/runtime/scan-runner.ts`, `src/core/watcher/runtime.ts`)**: new `--max-nodes <N>` flag on `sm scan` and `sm watch` (and the alias `sm scan --watch`). Validates integer ≥ 1, anything else exits 2 with a §3.1b two-line block. When a real scan caps, the CLI prints a yellow notice naming both escape routes the user has: edit `.skillmapignore` (preferred) or re-run with a higher `--max-nodes`. `sm refresh` operates on a single already-classified node, so the cap does not apply there.
18
+
19
+ **BFF (`src/server/routes/scan.ts`, `src/kernel/adapters/sqlite/scan-load.ts`)**: `GET /api/scan` and `POST /api/scan` propagate the two new fields verbatim from `scan_meta`. The empty-DB fallback returns the design default (256) and a `null` override so the SPA reads the same field shape on cold boot as on populated DBs.
20
+
21
+ **SPA (`ui/src/app/components/oversized-banner/`)**: new `<sm-oversized-banner>` component mounted in the shell next to `<sm-demo-banner>`. Visibility is purely derived from the loaded `ScanResult`, three render modes drive the body copy:
22
+
23
+ - **capped** (red), `stats.filesWalked > effectiveLimit`. Files were dropped.
24
+ - **overLimit** (yellow), `nodesCount > recommendedNodeLimit` with an override above the recommendation. Graph is bigger than recommended, allowed through.
25
+ - **atLimit** (yellow), `nodesCount >= recommendedNodeLimit` without an override above. Soft warning at the recommended cap.
26
+
27
+ The CTA opens Settings → Project (Ignored patterns section) so the operator can trim `.skillmapignore` without leaving the SPA. No dismiss state, the banner stays until a re-scan brings the graph back under the recommended limit.
28
+
29
+ **Tests**: new unit tests for the walker cap (`walk-node-cap.spec.ts`, 4 cases covering default cap fire, override above, override below, and project-below-limit) and for the banner (`oversized-banner.spec.ts`, 6 cases covering all three modes + hide + CTA emit). Existing `buildScan` helpers in three integration specs now reset `cmd.maxNodes` so the Clipanion marker object does not leak into manually-instantiated commands.
30
+
31
+ ## User-facing
32
+
33
+ New `--max-nodes <N>` on `sm scan` / `sm watch` / `sm serve` caps how many files the walker accepts (default 256, bidirectional). Past the limit, a persistent banner links to **Settings → Project** to trim `.skillmapignore`.
34
+
3
35
  ## 0.37.0
4
36
 
5
37
  ### Minor Changes
package/cli-contract.md CHANGED
@@ -283,6 +283,8 @@ The three privacy-sensitive keys above PLUS `allowEditSmFiles` are members of `P
283
283
 
284
284
  The watcher subscribes to the same roots that `sm scan` walks and respects `.skillmapignore` plus `config.ignore` exactly as the one-shot scan does. Filesystem events are grouped using `scan.watch.debounceMs` (default 300ms) before the watcher re-runs the incremental scan and persists. `SIGINT` / `SIGTERM` close the watcher cleanly. Exit code on clean shutdown is 0.
285
285
 
286
+ **Node cap** (`--max-nodes <N>`): on `sm scan` and `sm watch` (alias `sm scan --watch`), a hard cap on the number of files the walker accepts after `.skillmapignore` filtering, before extractors run. Default comes from `scan.maxNodes` (default 256). The flag is a full override of the setting and is **bidirectional**: it can raise the cap (`--max-nodes 1000` on a 312-file repo) or lower it (`--max-nodes 100` cuts deeper than the default). When the walker reaches the cap, additional files are dropped in stable provider-walker order and the scan is marked oversized in `scan_meta` (columns `recommended_node_limit` and `override_max_nodes`), the resulting `ScanResult` envelope carries `recommendedNodeLimit` and `overrideMaxNodes` so the UI raises a persistent banner pointing at the `.skillmapignore` editor in Settings → Project. The CLI prints a human-mode notice naming both escapes: edit `.skillmapignore` (preferred, trims permanently) or re-run with `--max-nodes <N>` (force, graph quality may degrade past the recommended limit). `sm refresh` operates on a single already-classified node, so the cap does not apply there. Validation: integer ≥ 1, anything else exits `2` operational.
287
+
286
288
  Exit: 0 on clean (or clean watcher shutdown), 1 if error-severity issues exist (one-shot scan only, the watcher does not flip exit code based on per-batch issues), 2 on operational error.
287
289
 
288
290
  ---
package/index.json CHANGED
@@ -174,14 +174,14 @@
174
174
  }
175
175
  ]
176
176
  },
177
- "specPackageVersion": "0.37.0",
177
+ "specPackageVersion": "0.38.0",
178
178
  "integrity": {
179
179
  "algorithm": "sha256",
180
180
  "files": {
181
- "CHANGELOG.md": "bb9d5ba9168a2f72a1d0fbda347f5e5813a90f63f77a534b48952044858050f3",
181
+ "CHANGELOG.md": "ecd667be3c62b547ac786dc864763778d7591ff43ccdf5c80d40647d299f3498",
182
182
  "README.md": "1c4b0ea58c4324f301043e9f5c36976a382d0bd2bc405a2e4e18463b0c50d946",
183
183
  "architecture.md": "b9fba6c60ecd32ad2440c804dc9d47b7211873add6dea73401e13dc26bfee277",
184
- "cli-contract.md": "a9da7c2c74a6f5400b4e8941099dd1861d53905964bd470c0c39ba74b4495710",
184
+ "cli-contract.md": "d7d16ff61e53ba282660111c01b4d92c756c4c429944701bf79035d62408c972",
185
185
  "conformance/README.md": "6871dde25b5770ed945284c9e0f749e0768ec3f5ba4966bdb215985789e43887",
186
186
  "conformance/cases/extractor-emits-signal.json": "34b4808c232d66a0eea0f5db7632a746681432b4f0995b6bf39e8d675538451c",
187
187
  "conformance/cases/kernel-empty-boot.json": "2a5be9c93143d07a16d998df09dcc8fa4ea2d2f9a0bff6417573ed5a770352c1",
@@ -238,11 +238,11 @@
238
238
  "schemas/node.schema.json": "4d7c107ed9cd2f1b7cc4d716c547c06a00ed776bd6092d3979cac634cb5326a5",
239
239
  "schemas/plugins-doctor.schema.json": "bb03eedf5b462b661938a44fe48635705ec13e30a2381ba122c60412416b507d",
240
240
  "schemas/plugins-registry.schema.json": "bca763ec61419e001a5c0a4b00a2da77996bfd8113be3fcf8aaa2fa70ff65fef",
241
- "schemas/project-config.schema.json": "f2a38a82fe47c8a965e6b73208e9be996d3d3545fdcd92f8a136f1d1e5abd3fb",
241
+ "schemas/project-config.schema.json": "253991718f714bf9409279410067b9c0c0da71e32a1b889d2f30559a0030c369",
242
242
  "schemas/refresh-report.schema.json": "54519b8caf86ba84c182f9565be9b5084bc1631ae05e9217ee18f34c0039fff3",
243
243
  "schemas/report-base-deterministic.schema.json": "9d318d0181d121097c906ef3af1c52d71c782740bd04cf23418d7627ce2c3ed5",
244
244
  "schemas/report-base.schema.json": "a1021e9a59b4df9f99cd92454d797e88469766e7d49f52d231c4645ffdfdad8f",
245
- "schemas/scan-result.schema.json": "214bc12fbb9946642cbba3b23513dade60e7d6a5b6a9ed3dd0818f135b450185",
245
+ "schemas/scan-result.schema.json": "2ac5edeb607e0f7c26036c65066effefcbaa5a6d8534b2f42fa4e44a3964a9f6",
246
246
  "schemas/sidecar.schema.json": "8856c387477340efbdd0a585d74bfb07a99ba15b9ce593cc67d9efebc67c6bfc",
247
247
  "schemas/signal.schema.json": "7a9d36f13ee6fa269da7ab97e45d9831d10e0570e3f61005617128b423a4d4d8",
248
248
  "schemas/summaries/agent.schema.json": "bf540f9a804f2b43756ab33b7deb0462620d26e88cc9379c75a5f87d3b1b47d8",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skill-map/spec",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "JSON Schemas, prose contracts, and conformance suite for the skill-map specification.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -55,6 +55,11 @@
55
55
  "minimum": 1,
56
56
  "description": "Files larger than this are skipped with an `info`-level log entry. Default 1048576 (1 MiB). Protects against scanning accidental binary drops or generated artefacts."
57
57
  },
58
+ "maxNodes": {
59
+ "type": "integer",
60
+ "minimum": 1,
61
+ "description": "Hard cap on the number of files the scan accepts after `.skillmapignore` filtering, before extractors run. Default 256. When the walker reaches the cap, additional files are dropped in stable provider-walker order and the scan is marked oversized in `scan_meta` (the UI raises a persistent banner pointing at the `.skillmapignore` editor in Settings → Project). Override per invocation with `--max-nodes N` on `sm scan` / `sm watch`, bidirectional (raises OR lowers the limit, the flag is a full override of this setting)."
62
+ },
58
63
  "watch": {
59
64
  "type": "object",
60
65
  "additionalProperties": false,
@@ -37,6 +37,16 @@
37
37
  "description": "Provider ids that participated in classification. Empty if no Provider matched.",
38
38
  "items": { "type": "string" }
39
39
  },
40
+ "recommendedNodeLimit": {
41
+ "type": "integer",
42
+ "minimum": 1,
43
+ "description": "Effective recommended cap on the number of files the walker accepted during this scan (`scan.maxNodes` from settings, default 256). Reported so the UI can decide whether to raise the persistent 'oversized graph' banner: a scan is oversized when `stats.filesWalked >= recommendedNodeLimit`. Absent on synthetic fixtures."
44
+ },
45
+ "overrideMaxNodes": {
46
+ "type": ["integer", "null"],
47
+ "minimum": 1,
48
+ "description": "Override applied via `--max-nodes <N>` on the verb that ran the scan (`sm scan`, `sm refresh`, `sm watch`), or `null` when no override was passed and the value above came from the setting. The override is bidirectional: it can raise the cap above the recommended limit (the UI banner stays visible until a re-scan lands below the recommended limit) or lower it (the banner also fires if `filesWalked` reaches the lowered override). Absent on synthetic fixtures."
49
+ },
40
50
  "nodes": {
41
51
  "type": "array",
42
52
  "items": { "$ref": "node.schema.json" }