Skip to content

feat(scan): LLM-scale corpus scanning — Tiers A/B/C (stats, digest, search-text, summarize, topics, clusters)#82

Merged
sjames merged 3 commits into
mainfrom
feat/llm-scan-tiers
Jul 4, 2026
Merged

feat(scan): LLM-scale corpus scanning — Tiers A/B/C (stats, digest, search-text, summarize, topics, clusters)#82
sjames merged 3 commits into
mainfrom
feat/llm-scan-tiers

Conversation

@sjames

@sjames sjames commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Adds a progressive, read-only, offline, deterministic toolkit for letting an LLM scan and summarize a model with tens of thousands of requirements without ever reading 15k files. The guiding pattern is aggregate → narrow → drill → summarize. Every capability is a first-class CLI subcommand and a read-only MCP tool returning the same JSON as --json; the reporting ones are on the run_report allow-list.

Built requirement-first (7 new REQ-TRS-*, 7 new TC-TRS-*, 3 ADRs) with new integration harnesses. qual/ validates clean; the full syscribe suite (147 tests), clippy, and the workspace build are green.

Tier A — shape (ADR-SYS-STATS-001)

  • stats (REQ-TRS-OUT-021) — corpus-shape facet histograms (status, reqDomain, sil/asil, package, tags) plus coverage & orphan rollups; --group-by, --where/--status/--tag, --config lens. Reuses coverage_summary + validator reverse indices, so coverage equals matrix.

Tier B — slice & retrieve (ADR-SYS-SCAN-001)

  • digest (REQ-TRS-OUT-022) — token-budgeted, one compact line per requirement (NDJSON or {total,offset,rows}), cursor-paged, sharing the stats scoping.
  • search-text (REQ-TRS-SEARCH-001) — ranked full-text over body+name via an in-memory Okapi BM25 inverted index (no external engine, no persisted index), best-first with marked snippets.

Tier C — meaning (ADR-SYS-SCAN-002)

  • summarize (REQ-TRS-OUT-023) — bottom-up per-package hierarchical rollup (count, status split, TF-IDF "about" terms, representative one-liners), extractive (not an LLM summary), with a content-hash cache (version-guarded) under the git-ignored .syscribe/cache/.
  • topics (REQ-TRS-SEARCH-002) — distinctive per-package keywords via TF-IDF.
  • clusters (REQ-TRS-SEARCH-003) — cross-package topical clustering via TF-IDF cosine k-means, deterministic (farthest-first init, no random seed).

Design decisions worth a look

Two deliberate deviations keep the tool a single offline binary (documented in the ADRs; both heavier options deferred as opt-in):

  • BM25 in-memory, not tantivy — a pure-Rust inverted index over short docs builds sub-second at load; avoids a heavy dep + on-disk index format.
  • Extractive summaries + TF-IDF clustering, not LLM calls / neural embeddings — preserves determinism (so the cache and tests are meaningful), offline operation, and reproducibility. The structured extract summarize emits is exactly the scaffold an LLM abstractively summarizes from.

Notes for reviewers

  • Shared textstats module owns the TF-IDF core; a stopword filter keeps labels as content words (not "the"/"shall") while search-text keeps its literal tokenizer.
  • Ranking/clustering use deterministic tie-breaks (qname) so CLI and MCP orderings match regardless of element load order.

🤖 Generated with Claude Code

sjames added 3 commits July 4, 2026 00:51
…iers A+B)

Add three read-only, LLM-facing capabilities for models with tens of
thousands of requirements, each a first-class CLI subcommand mirrored by a
read-only MCP tool (and on the run_report allow-list):

- stats (REQ-TRS-OUT-021): corpus-shape facet histograms (status, reqDomain,
  sil/asil, package, tags) plus coverage and orphan rollups; --group-by,
  --where/--status/--tag scoping, --config projection lens. Reuses
  coverage_summary and the validator reverse indices; coverage numbers equal
  matrix. ADR-SYS-STATS-001.

- digest (REQ-TRS-OUT-022): token-budgeted, one compact line per requirement
  (NDJSON, or {total,offset,rows} under --json), cursor-paged, sharing the
  stats scoping. The "dump the slice" companion to stats.

- search-text (REQ-TRS-SEARCH-001): ranked full-text over element body+name via
  an in-memory Okapi BM25 inverted index (no external engine, no persisted
  index — ADR-SYS-SCAN-001), best-first with marked snippets. Complements the
  identifier-fuzzy search tool.

Requirement-first: REQ-TRS-OUT-021/022, REQ-TRS-SEARCH-001 (+ SEARCH prefix)
with TC-TRS-OUT-021/022 and TC-TRS-SEARCH-001. New integration harnesses
(tests/{stats,digest,ftsearch}.rs, 29 tests). qual/ validates clean; full
suite, clippy and workspace build green.
Add three deterministic, offline, read-only capabilities that convey what a
requirement corpus *means* (Tier C), each a first-class CLI subcommand mirrored
by a read-only MCP tool. A shared textstats module owns the TF-IDF core (with a
stopword filter so labels are content words, not "the"/"shall").

- summarize (REQ-TRS-OUT-023): bottom-up per-package rollup — count, status
  split, TF-IDF "about" terms, one-line extracts of representative requirements
  — nested through the hierarchy. Extractive (not an LLM summary); each node's
  fields are cached under .syscribe/cache/summaries.json keyed by a subtree
  content hash, with a cache-version guard so a logic change invalidates a stale
  hit. --scope/--depth/--config. On the run_report allow-list.

- topics (REQ-TRS-SEARCH-002): distinctive per-package keywords via TF-IDF,
  demoting vocabulary common to every package.

- clusters (REQ-TRS-SEARCH-003): topical clustering via TF-IDF cosine k-means,
  surfacing cross-package themes. Deterministic farthest-first init (no random
  seed); --k validated (>=1) and clamped to the element count.

Design ADR-SYS-SCAN-002 records the deliberate offline/deterministic choices:
extractive (not LLM) summaries and TF-IDF cosine (not neural embeddings), so the
tool stays a single offline binary; both heavier options are deferred as opt-in.

Requirement-first: REQ-TRS-OUT-023, REQ-TRS-SEARCH-002/003 with TC-TRS-OUT-023,
TC-TRS-SEARCH-002/003. New harnesses (tests/{summarize,topics,clusters}.rs, 15
tests). qual/ validates clean; full suite (147), clippy and workspace green.
Promote the six requirements added in this PR out of draft to `verified`
(each has a passing verifying TC-TRS-*), and their six verifying TestCases to
`approved`, so coverage counts them as verifying rather than planned.

`verified` (not `approved`/`implemented`) is deliberate: these are tool
self-requirements qualified by TestCase verification, not by an architecture
`satisfies:` layer — the whole qual/ self-model has no architecture model — so
`approved`/`implemented` would trip W300 ("no satisfying architecture element")
on every one. `verified` reflects reality and keeps qual/ clean: 0 errors, no
W300/W305 on the promoted set.
@sjames
sjames merged commit 901f298 into main Jul 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant