# description
Canonical output of `sm scan --json` (and the data shape sent over WebSocket scan events). Self-describing and versioned; consumers MUST check `schemaVersion` before parsing.

# properties.schemaVersion.description
Scan result shape version. Bumped only on breaking changes to this schema.

# properties.scannedAt.description
Unix milliseconds when the scan started.

# properties.scannedBy.description
Implementation metadata. Optional so that synthetic fixtures can omit it.

# properties.scannedBy.properties.specVersion.description
Spec version that this scan conforms to (e.g. `0.1.0`).

# properties.roots.description
Filesystem roots that were walked during this scan, as absolute or scope-root-relative paths.

# properties.providers.description
Provider ids that participated in classification. Empty if no Provider matched.

# properties.tokenizer.description
Resolved offline tokenizer (encoder) that produced the per-node token counts in this scan, one of the closed allow-list in `project-config.schema.json#/properties/tokenizer` (`cl100k_base` default, `o200k_base`). Mirrors `scan_meta.tokenizer`. Reported so consumers know which encoder the counts came from; the incremental scan compares the persisted value against the resolved one and force-recomputes counts when they differ. Absent on synthetic fixtures and when tokenization was disabled.

# properties.activeProvider.description
Active provider LENS this scan ran under: the id of the gated Provider whose grammar the corpus was read with (see `architecture.md` §Active-lens scope for providers), `null` when no lens is resolvable. Mirrors `scan_meta.active_provider`. Reported so consumers know which lens produced the classification; the incremental scan compares the persisted value against the resolved one and re-classifies every node when they differ (the lens decides which Provider claims a file, as which kind). Absent on synthetic fixtures.

# properties.scanCeiling.description
Effective walk ceiling for this scan (`--max-scan <N>` override on `sm scan` / `sm watch` / `sm serve`, else `scan.maxScan` from settings, default 5000). The scan walks, parses, analyzes, and reference-validates the full corpus up to this number, so references resolve across the whole project regardless of how many nodes the map renders. Mirrors `scan_meta.scan_ceiling`. Absent on synthetic fixtures.

# properties.scanTruncated.description
True when the walker reached `scanCeiling` and dropped files in stable provider-walker order, false otherwise. Reported so the UI raises the persistent 'scan truncated' banner pointing at the `.skillmapignore` editor. Mirrors `scan_meta.scan_truncated`. Absent on synthetic fixtures.

# properties.maxRenderNodes.description
Effective map render cap for this scan (`--max-nodes <N>` override, else `scan.maxNodes` from settings, default 256). Does NOT bound the scan (the full corpus up to `scanCeiling` is persisted and the folders tree shows all of it); it only bounds the graph projection. The UI projects the selected folder branch capped at this number and raises an in-view banner when a branch exceeds it. Mirrors `scan_meta.max_render_nodes`. Absent on synthetic fixtures.

# properties.oversizedFiles.description
Files the walker skipped because their on-disk size exceeded `scan.maxFileSizeBytes` (default 1 MiB). Reported so the CLI / serve terminal can warn and the UI can raise a banner. Each entry is the root-relative, forward-slash path (same form as `node.path`) plus the file's byte size. Skipped files are never read, parsed, or indexed as nodes. Empty when no file exceeded the limit; defaults to `[]`.

# properties.oversizedFiles.items.properties.path.description
Root-relative, forward-slash path of the skipped file (same form as `node.path`).

# properties.oversizedFiles.items.properties.bytes.description
On-disk size of the skipped file, in bytes.

# properties.stats.properties.filesSkipped.description
Files walked but not classified by any Provider.

# properties.stats.properties.filesOversized.description
Files skipped before reading because their on-disk size exceeded `scan.maxFileSizeBytes`. Equals `oversizedFiles.length`. Absent on synthetic fixtures that bypass the walker.