Skip to content

feat: heading-anchored snippet extraction in resolve_concern - #2

Merged
Koed00 merged 11 commits into
mainfrom
feature/heading-anchored-snippets
Jun 19, 2026
Merged

Koed00 merged 11 commits into
mainfrom
feature/heading-anchored-snippets

Conversation

@Koed00

@Koed00 Koed00 commented Jun 19, 2026

Copy link
Copy Markdown
Owner

Summary

Extends resolve_concern (shipped in #1) to narrow returned snippets to the heading-anchored section containing the match, instead of returning whole-file content up to the 8000-char cap.

  • New pure function extractHeadingAnchoredSnippet(content, concern): string | null in src/core/concern-matcher.ts — regex-based heading detection + line-array slicing (ADR-006), no new dependency.
  • Wired into all three snippet-building call sites (feature files, ADR files, CLAUDE.md) inside matchConcernInSnapshot. Falls back to the existing whole-file behavior unchanged when a file has no markdown headings (zero regression).
  • Multi-section resolution: the most keyword-dense matching section wins, except a section's structural ancestor (e.g. a lone H1 title spanning the whole file) is excluded from competing against its own descendants unless the ancestor has a genuine match in its own text.

Why

Originated from a DIVERGE round prompted by live dogfooding resolve_concern: a query for "concern matching" against this repo's own wave-decisions.md returned the entire file (truncated at 8000 chars) instead of the specific section discussing the topic. Scored highest (4.35/5) of 5 candidate improvements on Job Fit + Architecture Fit.

What a reviewer should know

  • A real bug was found and fixed mid-cycle via dogfooding, not just tests: the first implementation let a document's top-level H1 title section always win the density comparison over its own subsections (its occurrence count summed every nested match). Fixed via excludeStructuralAncestors; full root-cause writeup in docs/feature/heading-anchored-snippets/distill/upstream-issues.md.
  • A separate, pre-existing config gap was discovered and fixed: stryker.config.mjs never included concern-matcher.ts in its mutation-testing scope since that file was created in the prior concern-based-querying feature — meaning ~all of resolve_concern's core logic had zero mutation coverage until now. Fixed the config and backfilled tests to restore the project's ≥80% gate (final: 80.08% on the file, 85.75% project-wide).
  • Full nWave wave trace (DIVERGE → DISCUSS → DESIGN → DISTILL → DELIVER) is under docs/feature/heading-anchored-snippets/. Evolution summary: docs/evolution/heading-anchored-snippets-evolution.md.

Test plan

  • 369/369 tests passing (npm test)
  • npm run build (tsc strict, noUncheckedIndexedAccess) clean
  • npm run check:arch (dependency-cruiser core/shell boundary) clean
  • Mutation testing: 80.08% on concern-matcher.ts, 85.75% project-wide (threshold 80%)
  • Live dogfood re-confirmed post-fix: snippet for the motivating query narrowed from 7696 → 1124 chars on this repo's own wave-decisions.md
  • DES integrity verification: 2/2 roadmap steps with complete TDD traces

Ilan Steemers and others added 11 commits June 19, 2026 13:05
…acts

DIVERGE round identified heading-anchored snippet extraction as the
highest-impact next improvement to resolve_concern, fixing whole-file
snippet dumps on multi-section nWave files. DISCUSS, DESIGN (ADR-006),
and DISTILL waves completed and peer-reviewed (approved). Acceptance
tests confirmed RED (not BROKEN) against current production code.
vitest's esbuild transpile doesn't type-check, so tsc errors in the new
heading-extraction code were caught only at build time, not by the TDD
cycle's test runs.

Step-ID: 01-01
…-section bug

Live dogfood check during the post-merge integration gate found that a
section's ancestor (e.g. a document's top-level H1 title heading) always
wins the multi-section density comparison over its own descendants,
because its occurrence count is the sum of all nested subsections'
occurrences. This defeats the feature's purpose for the most common
nWave file shape (# Title + multiple ## D-xxx: subsections), including
this repo's own wave-decisions.md files.

See docs/feature/heading-anchored-snippets/distill/upstream-issues.md
Issue 1 for full analysis.
Adversarial review found the escape hatch (an ancestor section retains
candidacy when its own text genuinely matches the concern) had no test
proving it works, only tests proving the inverse case (pure ancestor
with zero own-text matches gets excluded). Confirmed with user: density
comparison among a genuinely-matching ancestor and its descendant is
correct by design (validated by ADR-005's own live dogfood behavior).
concern-matcher.ts was missing from stryker.config.mjs's mutate scope
since it was first created -- this backfills coverage for both the
pre-existing concern-based-querying logic and the newer
heading-anchored-snippets logic now that the config gap is fixed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file was missing from stryker.config.mjs's mutate list since it
was first created in the concern-based-querying feature -- it had zero
mutation coverage despite the project's per-feature mutation testing
strategy requiring >=80%. Discovered during this feature's DELIVER
mutation-testing phase; closed alongside test coverage additions in a
separate commit.
@Koed00
Koed00 force-pushed the feature/heading-anchored-snippets branch from 8c948c7 to 83c1bf3 Compare June 19, 2026 11:06
@Koed00
Koed00 merged commit 722863c into main Jun 19, 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