Skip to content

docs(plan): codemap impact — symbol/file blast-radius walker#49

Merged
SutuSebastian merged 2 commits intomainfrom
docs/plan-impact
May 3, 2026
Merged

docs(plan): codemap impact — symbol/file blast-radius walker#49
SutuSebastian merged 2 commits intomainfrom
docs/plan-impact

Conversation

@SutuSebastian
Copy link
Copy Markdown
Contributor

@SutuSebastian SutuSebastian commented May 3, 2026

Summary

Why

Post-PR #47 (codemap watch), the remaining high-friction agent loop is "what's the blast radius if I change X?" — agents currently compose WITH RECURSIVE SQL by hand, which they do unreliably and without depth/cycle bounds. impact is to the dep / calls graph what show (PR #39) was for symbol lookup: replaces hand-rolled SQL with one verb.

See docs/plans/impact.md for the full design — sketched API, output envelope, 10 decisions (D1-D10), 5 tracers, perf considerations, alternatives rejected, and out-of-scope list.

Test plan

  • CodeRabbit reviews the design choices (especially D2 — graph-backend split, D6 — cycle detection in SQLite, D7 — output shape uniformity)
  • Once approved + merged, follow-up PR implements Tracers 1-5

Summary by CodeRabbit

  • Documentation
    • Added comprehensive plan for new codemap impact <target> CLI command to analyze symbol and file dependency relationships with configurable traversal depth.
    • Updated roadmap with corresponding backlog item for the planned feature.

…/callees, depth-bounded, multi-graph)

Replaces the "agent composes WITH RECURSIVE by hand" tax — `impact` is to the dep/calls graph what `show` (PR #39) was for symbol lookup. Single verb, multi-backend (calls + dependencies + imports), depth- and limit-bounded, cycle-detected. Pure transport-agnostic engine reused by CLI / MCP / HTTP per the post-PR #41 layering.

Plan only — implementation lands in a follow-up PR after review.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 3, 2026

⚠️ No Changeset found

Latest commit: f0309a5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

Warning

Rate limit exceeded

@SutuSebastian has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 50 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a68ee62a-44c2-494b-90b8-41812e8ff904

📥 Commits

Reviewing files that changed from the base of the PR and between d566df7 and f0309a5.

📒 Files selected for processing (1)
  • docs/plans/impact.md
📝 Walkthrough

Walkthrough

This PR adds documentation for a proposed codemap impact <target> CLI command that computes symbol and file blast radius by recursively walking dependency, call, and import graphs. A detailed design plan with implementation specifics, output formats, and scope boundaries is added alongside a roadmap entry.

Changes

Codemap Impact Feature Plan

Layer / File(s) Summary
Plan Definition
docs/plans/impact.md
Complete design document for the codemap impact command, specifying CLI surface, output JSON structure, graph backends (dependencies, calls, imports), target resolution rules, direction/depth semantics, SQL-and-JS implementation split, performance considerations, and explicit out-of-scope boundaries.
Roadmap Integration
docs/roadmap.md
Backlog entry added for codemap impact <target> referencing the full plan document.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~8 minutes

Poem

🐰 A curious plan hops into view,
Blast radius walks, both old and new!
Graphs recursive, symbols traced,
Impact mapped and scope embraced. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: adding a plan document for a new 'codemap impact' command that implements a symbol/file blast-radius walker. The title is specific, clear, and directly reflects the primary purpose of this documentation-focused PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/plan-impact

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 52 minutes and 50 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@SutuSebastian
Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 3, 2026

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/plans/impact.md`:
- Line 24: Update the broken markdown anchor for the link "[§
Alternatives](`#alternatives`)" so it matches the actual heading slug in the
document: locate the heading that corresponds to the Alternatives section (e.g.,
"Alternatives", "Alternatives considered", or similar) and replace the fragment
"#alternatives" in the link with the exact slug generated from that heading
(matching Markdown heading-to-slug rules) so the jump link navigates correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 969944aa-1548-4684-a540-38a4285a9ee3

📥 Commits

Reviewing files that changed from the base of the PR and between e4ae070 and d566df7.

📒 Files selected for processing (2)
  • docs/plans/impact.md
  • docs/roadmap.md

Comment thread docs/plans/impact.md Outdated
@SutuSebastian SutuSebastian merged commit c76f09a into main May 3, 2026
10 checks passed
@SutuSebastian SutuSebastian deleted the docs/plan-impact branch May 3, 2026 09:30
SutuSebastian added a commit that referenced this pull request May 3, 2026
…of PR #49 plan) (#50)

* feat(impact): pure transport-agnostic walker engine (Tracer 1)

application/impact-engine.ts — single WITH RECURSIVE per (direction, backend),
JS-side merge + dedup + summary. Backends:

- calls (symbol-level, up=callers / down=callees)
- dependencies (file-level)
- imports (file-level, resolved_path only)

Plan §D2 backend split, §D6 cycle detection (path-string + instr), §D8 edge
tags. 27 unit tests cover: walks (up/down/both), depth caps, limit caps,
self-loop + 3-cycle, file-vs-symbol resolution, --via skipped_backends.

* feat(impact): cmd-impact.ts CLI verb wired into main + bootstrap (Tracer 2)

- src/cli/cmd-impact.ts — parser + runner mirroring cmd-show.ts shape
- main.ts dispatch, bootstrap.ts validateIndexModeArgs + printCliUsage
- 14 parser tests cover happy paths + 9 error cases (--depth/limit/direction/via validation)

Smoke: `bun src/index.ts impact src/db.ts --direction up --depth 1` lists
the real fan-in on this repo (every file in src/ that depends on db.ts).
`bun src/index.ts impact handleQuery --json --summary` returns the summary
shape ready for jq pipelines.

* feat(impact): MCP impact tool wired through tool-handlers (Tracer 3)

- impactArgsSchema + handleImpact in tool-handlers.ts (Zod + ToolResult shape)
- registerImpactTool in mcp-server.ts (one-line wrapper, like show/snippet)
- 5 MCP integration tests (tools/list, symbol target, file target, summary
  trims matches but keeps summary.nodes count, Zod rejects float depth)

HTTP POST /tool/impact lights up automatically next tracer via the existing
http-server.ts dispatcher (one switch arm).

* feat(impact): HTTP POST /tool/impact dispatcher (Tracer 4)

- TOOL_NAMES gains 'impact' (auto-listed in /tools)
- dispatchTool switch arm with Zod validation (400 on bad body)
- 4 integration tests: happy path, missing target, non-int depth, bad direction enum

Both transports (MCP + HTTP) now expose impact via the same handleImpact
pure function.

* docs(impact): sync README + architecture + glossary + agent rule/skill + changeset (Tracer 5)

- README.md: new 'Impact analysis' code block + impact in MCP tools list
- docs/architecture.md: 'Impact wiring' section + impact-engine in application/ inventory
- docs/glossary.md: 'codemap impact / impact tool' entry under I (full envelope spec)
- docs/roadmap.md: drop the impact backlog item (it shipped)
- docs/research/fallow.md: Adjacent-shipped bullet referencing PR #49 (plan) + #50 (impl)
- .agents/rules/codemap.md + templates/agents/rules/codemap.md: new table row + 'Impact' paragraph + impact in MCP tools list (Rule 10 lockstep)
- .agents/skills/codemap/SKILL.md + templates/agents/skills/codemap/SKILL.md: impact tool description (Rule 10 lockstep)
- .changeset/codemap-impact.md: minor — full design rationale + decisions
- docs/plans/impact.md: deleted per docs-governance Rule 3 (canonical descriptions now live in architecture / glossary / README)

* chore(impact): slim self-authored comments per concise-comments rule

Re-read every comment authored in this PR; cut/slim ones a teammate could
re-derive in <30s. Targets:

- impact-engine.ts: drop trivial type doc, slim findImpact JSDoc, slim
  termination heuristic from 6 lines → 2, drop redundant inline notes
- cmd-impact.ts + tool-handlers.ts: shorten the --summary trim explanation

No behaviour change; checks green (89 tests + lint + typecheck).

* chore(impact): apply CodeRabbit nitpicks 1+4

- impact-engine.ts:333 — one-line comment explaining empty-string file_path
  fallback (external/dynamic call sites)
- impact-engine.test.ts:209 — strengthen exact-fit limit test from
  not.toBe('limit') to toBe('exhausted')

Pushed back on nitpicks 2+3 (hallucinated — see PR comment) and 5 (style;
deterministic order is fine to lock).
SutuSebastian added a commit that referenced this pull request May 3, 2026
…(v1.x backlog) (#51)

* docs(plan): codemap audit --base <ref> — worktree + reindex strategy (v1.x backlog)

Plan for the next-best agent-value loop: PR-review structural-diff. Replaces today's 3-step --baseline dance with one verb. Reuses 90% of the existing audit infrastructure (PR #33); only new piece is the worktree+reindex snapshot path.

Cache-by-resolved-sha; LRU 5/500 MiB; mutual-exclusive with --baseline; per-delta override compatible. Hard error on non-git projects (no graceful fallback — there's no meaningful 'ref' without git).

Plan only — implementation follows after CodeRabbit review per the impact (#49#50) / watch (#46#47) workflow.

* docs(plan): address CodeRabbit findings — atomic cache populate (D11), worktree-as-cache lifecycle clarity, TS type widening callout

- D1/D2/D8 rewritten: worktree IS the cache entry (kept until LRU evicts);
  cleanup runs only on reindex failure rollback OR LRU eviction. The
  earlier ambiguity (D2 said 'cache by sha' while D8 said 'remove in
  finally') is resolved.
- D11 added: atomic cache populate via per-pid temp dir + POSIX rename
  → free single-flight semantics; no lock files needed. Same pattern
  for eviction. Closes the race CodeRabbit flagged on concurrent
  CI matrix runs against the same sha.
- AuditBase TS type widening to discriminated union called out
  explicitly above the Decisions table (Tracer 1 ships it).
- CODEMAP_AUDIT_CACHE_SIZE env var mention dropped — was promising an
  unimplemented config knob; v1 hardcodes the limits, defer to v1.x+.
SutuSebastian added a commit that referenced this pull request May 4, 2026
…age` table) (#56)

* docs(plan): static coverage ingestion (Istanbul JSON → `coverage` table)

Plans the C.11 candidate from `research/fallow.md` — `codemap ingest-coverage <path>`
reads Istanbul `coverage-final.json` into two new tables (`coverage` symbol-level +
`file_coverage` rollup), joinable to `symbols` for the killer "what's structurally
dead AND untested?" recipe in one query.

Resolves the open question from `fallow.md § 6` ("symbols column vs separate table?")
in favour of a separate table with `ON DELETE CASCADE` (D1) — coverage shape evolves
independently of structural columns; LEFT JOIN keeps NULL semantics explicit; rows
survive `--full` reindex via the `query_baselines` precedent (D6).

Key decisions:
- Istanbul JSON in v1; LCOV in v1.x; raw V8 traces never (D3, fallow's paid moat).
- One-shot `ingest-coverage` verb decoupled from `codemap` index runs (D4) — coverage
  cadence (per `bun test --coverage`) ≠ index cadence (per file edit).
- Statement coverage only in v1 (D5); branch/function deferred until a consumer asks.
- MCP/HTTP exposure as a query column, not a separate `coverage` tool (D9) — composes
  with every existing recipe + ad-hoc SQL.
- `codemap audit --delta coverage` deferred to v1.x (D10) — raw schema first.

Five-tracer plan: schema bump → engine → CLI verb → fixture + golden recipe → docs.
Plan only — implementation follows after CodeRabbit review per the established
workflow (PRs #46/47, #49/50, #51/52, #53/54).

* docs(plan): fact-check fixes — drop hallucinated SQL/projection/runner claims

Self-audit against the actual codebase surfaced four claims that didn't hold:

1. Killer recipe SQL referenced `callee_id` — `calls` is name-keyed
   (`callee_name TEXT`, no symbol-id FK; see `db.ts` `CallRow`). Rewrote
   the "no callers" predicate as `NOT EXISTS (… WHERE callee_name = s.name)`.
2. D7 claimed line-range projection is "the same `markers` already uses" —
   `markers` is line-pinned (`line_number INTEGER`), no projection.
   Reworded as "novel for this plan" with the actual mechanic spelled out.
3. D3 listed `bun test --coverage` as an Istanbul JSON emitter — `bun test
   --help` shows only `text` / `lcov` reporters today. Removed bun from the
   Istanbul-emitters list; left vitest/jest/c8/nyc with the explicit reporter
   flags they need.
4. D12 contradicted D6 ("rows absent until re-ingest" vs "rows survive
   `--full`"). Reconciled: empty is the correct initial state on first bump;
   subsequent bumps preserve via the `dropAll()` exclusion. Quoted the
   `lessons.md` policy verbatim instead of paraphrasing.

* docs(plan): v2 — fix CASCADE hazard + innermost-wins projection + nits

Self-grilling found two real schema design holes that would block execution:

1. **D6 CASCADE hazard.** Original draft keyed `coverage` on
   `symbol_id REFERENCES symbols(id) ON DELETE CASCADE`. Every `--full`
   reindex calls `dropAll()` → drops `symbols` → CASCADE wipes coverage,
   regardless of whether `coverage` itself was excluded from `dropAll()`.
   Recreated `symbols` get fresh auto-increment IDs anyway → coverage
   permanently lost without re-ingest. Fix: natural-key PK
   `(file_path, name, line_start)` — no FK to `symbols.id`. Survives the
   `symbols` drop-recreate cycle. Trade-off: orphan rows when files are
   deleted; cleaned by one explicit `DELETE FROM coverage WHERE file_path
   NOT IN (SELECT path FROM files)` after every ingest.

2. **D7 overlapping symbols.** Original draft: `line_start ≤ stmt_line ≤
   line_end` matches every enclosing scope. With nested symbols (class
   methods inside classes, closures inside functions), one Istanbul
   statement projects onto 3+ symbols, inflating `total_statements` 2-3×.
   Fix: innermost-wins via `(line_end - line_start) ASC LIMIT 1`. New
   `skipped.statements_no_symbol` counter for statements that fall outside
   every symbol range (top-level expressions, side-effect imports).

Nits cleared in the same pass:

- D2: drop `file_coverage` rollup table from v1 (aggregateable via
  GROUP BY on the symbol-level table; doubling sources of truth without
  a benchmark is premature). Promote to v1.x with a real query.
- D11: spec the `total_statements = 0 → coverage_pct IS NULL` edge case
  + document the cross-file name-collision lossiness in the killer recipe.
- Drop `--prune` flag (orphan cleanup is unconditional, no flag needed).
- Drop per-row `source` column (single meta key sufficient; one ingest
  at a time).
- Update killer recipe SQL to use the natural-key 3-column join.
- Drop made-up "~50 LoC LCOV ingester" estimate and "<50 ms / <1 ms /
  ~500 KB" performance numbers (no benchmark backed them).
- Tracer 1 / 2 / 3 acceptance criteria updated to match the new schema.

Plan is now ready for tracer-1 implementation. CodeRabbit pass deferred
(rate-limited 57m).

* docs(plan): tighten Bun-native API references (file read + perf note)

Plan correctly inherits the established Node vs Bun runtime split, but the
single tracer-3 reference understated it. Now:

- Tracer 3 cites `packaging.md § Node vs Bun` as the canonical pattern
  source instead of pointing at config.ts in passing.
- Performance section calls out the actual lever — `Bun.file(path).json()`
  uses Bun's native JSON parser, materially faster than V8 `JSON.parse`
  on multi-MB Istanbul payloads (real coverage files for medium codebases
  routinely hit several MB).

No new Bun-native API surfaces are added — the feature doesn't need
globbing, file writes, spawn, or hashing beyond what the existing engines
already use through their abstractions.

* docs(plan): v3 — ship LCOV in v1 + drop --source flag + bundle killer recipe

The "fully capable, no half-way APIs" principle reshapes three things:

1. **LCOV ingester ships in v1** alongside Istanbul. Original draft deferred
   LCOV to v1.x, which would exclude `bun test --coverage` users — i.e.
   codemap's own primary runtime. That's the textbook half-baked surface
   the principle bans. Two parser front-ends share one `upsertCoverageRows`
   core; LCOV is regex tokenizing over `SF:` / `DA:` / `end_of_record`.
   Tracer 2 splits into 2a (shared core + Istanbul parser) and 2b (LCOV
   parser), both writing identical normalised CoverageRow[] into the same
   upsert path.

2. **`--source istanbul|lcov` flag dropped.** Auto-detection from extension
   (`.json` → istanbul, `.info` → lcov, directory → probe both, error on
   ambiguous) is unambiguous; a flag for "tell codemap what it can already
   see" is API noise. Misnamed files can be renamed (one-liner) cheaper
   than codemap can grow a flag.

3. **Killer recipe ships as bundled `untested-and-dead.{sql,md}`** in
   `templates/recipes/`. Per the recipes-as-content registry (PR #37), the
   high-value queries become first-class agent surface. A buried doc
   snippet would be invisible to agents at session start; the bundled
   recipe shows up in `--recipes-json` and gets a `codemap query --recipe
   untested-and-dead` direct invocation.

Tracer 4 also fans out: Istanbul + LCOV fixtures cover the same partial
coverage shape; three golden recipes (`coverage-istanbul.json`,
`coverage-lcov.json`, `untested-and-dead.json`) prove format equivalence.
Out-of-scope, alternatives, performance section, title, and goal
statement all updated to match.

* docs(plan): v4 — agent-journey audit + bundled recipe shelf (D13)

Walked every D / OOS / tracer item against "fully capable + agent
first-class + no half-baked APIs". Found three half-baked surfaces:

1. **D2 deferral leaks "compose GROUP BY yourself" onto the agent.**
   Deferring the `file_coverage` table is correct (no benchmark proves
   it's needed) — but the agent-facing answer for "rank files by
   coverage" was missing. Fix: keep table deferral, ship a bundled
   `files-by-coverage.{sql,md}` recipe so the GROUP BY view IS
   first-class.

2. **D11 name-collision lossiness was acknowledged but unmitigated.**
   The killer recipe's `callee_name = s.name` cross-file lossiness
   was documented in the recipe SQL comment, but the recipe `.md`
   didn't give the agent any narrowing pattern. Now D11 ships three
   concrete narrowing patterns in the `.md` (file_path scope, default-
   export filter, exported-only restriction) so the agent has
   workable mitigations on day one.

3. **Missing recipe shelf for common agent questions.** Walking the
   journey: only "What's structurally dead AND untested?" had a recipe;
   "Rank files by coverage" and "Worst-covered exported symbols" forced
   ad-hoc SQL. Three recipes fully cover the agent journey end-to-end.

New D13 codifies the bundled-recipe principle: every common agent
question gets a `--recipe` verb. Three v1 recipes:
- `untested-and-dead.{sql,md}` (killer, with name-collision mitigations)
- `files-by-coverage.{sql,md}` (replaces D2's table deferral)
- `worst-covered-exports.{sql,md}` (top-N agent ask)

Each `.md` carries a frontmatter `actions` block (per PR #26) so agents
get per-row follow-up hints. All three appear in `--recipes-json`
automatically — agents discover them at session start.

New "Agent journey" section makes the principle visible: a table mapping
every common agent question to the v1 verb that answers it. If a row
ever shows "compose SQL yourself" without a recipe, the surface is
half-baked and needs a recipe before tracer 1 ships.

Tracer 4 expanded: ships all three recipes + five golden snapshots
(adds files-by-coverage.json + worst-covered-exports.json on top of the
three existing). Tracer 5 expanded: glossary + agent rule trigger
table gain three new rows.

Plan now passes the principle audit end-to-end.
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