Skip to content

feat(map): add optional SCC condensation view - #633

Open
elefthei wants to merge 1 commit into
trailhq:mainfrom
elefthei:feat/scc-condensation-map
Open

elefthei wants to merge 1 commit into
trailhq:mainfrom
elefthei:feat/scc-condensation-map

Conversation

@elefthei

Copy link
Copy Markdown

Summary

  • Add explicit graft map [dir] --scc / trail map [dir] --scc and MCP graft_repo_map { "scc": true } views. CLI --scc --json serializes the direct { components, edges } result.
  • Isolate iterative Tarjan analysis in src/graph/scc.ts, using the existing directed dependency relations and exact node IDs. Include files, isolates, self-recursive singletons, and every inter-component dependency, without transitive reduction or input mutation.
  • Retain every member's definition location and every original supporting edge (including bundled links). Mark only count-1 links as candidate abstraction boundaries; counts are stored dependencies, not call sites.
  • Reject directory budgets and workspace-parent SCC requests before refresh; workspace children and custom graph directories work through the existing CLI/MCP adapters. Keep the six-tool inventory, ordinary map behavior, core graph algorithms, and main skill/template unchanged. Update README/changelog and the one-line MCP discovery hint.
  • Repository import rules required static adapter imports rather than the plan's lazy imports; SCC computation still runs only on a literal explicit opt-in.

Verification

  • npm ci: installed missing dev dependencies; prepare/build completed on Node v26.11.1.
  • env DO_NOT_TRACK=1 GRAFT_NO_TRAIL_SWITCH=1 node --import tsx --test test/graph-scc.test.ts test/mcp-tools.test.ts: 28/28 passed, no skips. Covers exact partitions/anchors, input reversal and immutability, complete provenance, empty input, a 20,000-node directed path, and real MCP rejected-request/no-refresh then accepted-request/source-edit refresh behavior. The new freshness regression failed before implementation and passed afterward.
  • node node_modules/typescript/bin/tsc --noEmit -p tsconfig.json: passed.
  • Protected SHA-256 baseline comparison after implementation and smoke: all 12 files unchanged, including the main skill/template, directory map/build/traversal/ranking/types/relations/workspace modules, and MCP server/tool names.
  • node --import tsx .scc-smoke.mjs (throwaway script, removed): passed against real commands and actual JSON-lines stdio MCP servers. Exact fixture produced 5 components, 3 links, 2 singleton boundaries; preserved both A→B dependencies and the direct A→c link. Verified complete CLI text/JSON, graft/trail aliases, unchanged ordinary text/JSON and wiring bytes, initialization hint, six schemas with optional boolean, canonical/legacy MCP aliases, scc:false, budget conflicts, missing graphs, custom graph directories, workspace-parent errors without refreshing stale children, child-root CLI/MCP success, and ordinary per-child workspace maps. MCP waited for initialization, collected responses by ID, enforced a 15-second deadline, and terminated children.
  • Seeded throwaway smoke: 500 directed graphs matched a mutual-reachability SCC reference and retained all cross-component edge provenance.
  • env DO_NOT_TRACK=1 GRAFT_NO_TRAIL_SWITCH=1 npm test: 1,441 passed / 1,448 total; 7 failed, no skips. Full suite is not clean. Failures are outside SCC surfaces: one migration test in graft-to-trail.test.ts, one migration test in hosts-trail.test.ts, three session/note-routing tests in trail-home.test.ts, and stale-cache timing plus migration-nudge tests in upkeep-hooks.test.ts. This run included GRAFT_NO_TRAIL_SWITCH=1, which explicitly disables migration (src/upkeep-run.ts:75); no unrelated code/tests were changed. Scoped SCC/MCP verification above passed afterward.

Closes #632

@trailhq-graft

trailhq-graft Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

3 areas changed → 1 area can be affected. 1 dependent symbol, depth 2.
Tests: no test reaches Strongly Connected Components; 1 area updated its tests.
Tag: @anirudhkumar-nanonets — 3 of 4 areas · @shhdwi — 3 of 4 areas

flowchart TB
  A0(("MCP Server<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0 reached;
Loading
Can be affected Symbols Nearest hop Reached from
MCP Server 1 src/mcp/server.ts:L73-L155 startMcpServer — calls, depth 1 MCP Tool Integration
Who knows this code — 2 people across 4 areas
Area Who knows it
MCP Tool Integration · changed @shhdwi — 15 commits, last 3d ago · @anirudhkumar-nanonets — 9 commits, last 3d ago
Command Line Interface · changed @anirudhkumar-nanonets — 58 commits, last yesterday · @shhdwi — 26 commits, last yesterday
MCP Server · affected @anirudhkumar-nanonets — 6 commits, last 3d ago · @shhdwi — 2 commits, last 3mo ago
Strongly Connected Components · changed only you — nobody else has touched these files

Ownership is git history over each area's own files, weighted towards recent work (120-day half-life). Merge commits and bots are dropped, and you are dropped from your own PR. A name with no @ has no GitHub handle in its commit email — tag them by hand, or add a .mailmap entry. A suggestion from history, not a CODEOWNERS rule.

All 1 dependent symbol, grouped by area

MCP Server — 1 symbol in 1 file

  • src/mcp/server.ts:L73-L155 — startMcpServer (calls, depth 1)
    111: instructions: upkeep.length ? `${upkeep.join('\n')}\n\n${mcpInstructions()}` : mcpInstructions(),
Test signal per changed area — 1 ✓ · 1 ✗ · 1 –

Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.

  • ✓ MCP Tool Integration — 1 of 3 reached · 1 test file changed here: test/mcp-tools.test.ts
    • not reached: mcpInstructions, callSingleTool
  • – Command Line Interface — no function, method or class changed here
  • ✗ Strongly Connected Components — 0 of 2 reached · no test file reaches it
    • not reached: discover, label
4 test suites also reference this code

4 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.

  • test/graph-follow-submodules.test.ts
  • test/graph-load.test.ts
  • test/graph-refresh.test.ts
  • test/graph-seed.test.ts

⚠️ 2 changed files not in the graph (CHANGELOG.md, README.md) — no parser claims the extension, or the index predates the file.

graft blast · origin/main...HEAD · depth 2 · 8 changed files

Open the interactive graph → — click an area to see its dependent symbols at file:line.

github-actions Bot added a commit that referenced this pull request Oct 17, 2026

This branch has not been deployed

No deployments
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.

Feature: SCC condensation DAG for graft map using Tarjan's algorithm

1 participant