Repository navigation
Conversation
|
Hi — second PR from a first-time contributor, this one fixes #438 (the more severe one): |
🌱 graft blast radius1 area changed → 4 areas can be affected. 12 dependent symbols, depth 2. flowchart TB
A0(("Pull Request Review<br/>4 symbols"))
A1(("Graph Refresh CLI<br/>3 symbols"))
A2(("CLI Engine Integration<br/>3 symbols"))
A3(("MCP Server Tools<br/>2 symbols"))
classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
class A0,A1,A2,A3 reached;
Who knows this code — 3 people across 5 areas
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 All 12 dependent symbols, grouped by areaPull Request Review — 4 symbols in 4 files
Graph Refresh CLI — 3 symbols in 2 files
CLI Engine Integration — 3 symbols in 2 files
MCP Server Tools — 2 symbols in 2 files
Test signal per changed area — 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.
54 test suites also reference this code66 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.
Open the interactive graph → — click an area to see its dependent symbols at file:line. |
|
Reproduced on main: running |
… when a rebuild empties it (trailhq#438) `graft ask` without its repo-root positional anchors the refresh on the cwd. When that root is unrelated to the graph's home, the drift probe reads "every file changed" and the rebuild writes an empty graph over a valid one — with the per-file cards surviving to mask the damage. The fingerprint now records the root its build ran on, and the refresh gate compares it against the root a query resolved, as real paths: macOS symlinks /tmp to /private/tmp, so a graph built through one name and queried through the other is the same graph, and comparing lexically would refuse to refresh it on every query from then on. A mismatch leaves the graph untouched and the note names the one argument that makes the refresh honest. A seeded worktree re-homes its copied sidecar, since the seed copies the parent checkout's fingerprint verbatim and its prints are the diff base the worktree wants. Behind that guard there is a safety net for the case it cannot catch: a legitimate-looking refresh that still empties the graph, because every source was deleted or an --only-dir whitelist no longer matches. The rebuild succeeded, so that is not an error — but "silently emptied" is the worst failure mode there is, because the cards survive and the graph looks intact until a query misses. The note says what the root now contains and what to run. Refs trailhq#438
28b45f3 to
01bb163
Compare
|
All three done, rebased onto current
There is a test for it: it builds a graph root, links a second name at it, and asserts the two compare equal and produce no guard note. It skips itself where the platform refuses to create the link, which is Windows without developer mode — and on this machine it does refuse, so that leg is covered by the lexical tests rather than exercised here. On verification: The wider suite is where I want to be straight with you rather than quote a number. A full run here reports 4504 tests / 57 failed, and the same run on an unmodified |
What
Fixes #438:
graft --dir graft/demo ask "who calls utilFn"— without the repo-root positional — silently wipes the graph.queryRootfalls back to walking up from the cwd, the freshness check anchors on that root, its unrelated file set reads as "every file changed", and the rebuild writesnodeCount: 0, edgeCount: 0over a valid graph in under a second. The per-file cards survive, so the damage is invisible until a query misses, and the exit code stays 0.Changes
version1 → 2, so pre-ask without the repo-root positional silently wipes the graph: freshness check anchors on cwd and rebuilds 0 nodes (cards survive) #438 caches read as unknown and fall back to one honest rebuild instead of serving stale bags forever).ensureFreshGraph): before any drift probe or rebuild, the recorded root is compared with the root the query resolved. On a mismatch the graph is left untouched and the caller gets an actionable note —graph was built for <root>, not <cwd> — answering from the existing graph; to refresh it, pass its root: graft ask <query> <root>— instead of a wiped graph.graft buildfrom the right root — "silently emptied" is the worst failure mode here because the cards mask it.Validation
Windows 11:
test/graph-root-guard.test.ts, run locally: no recorded root is not treated as a move; the same root matches through trailing slashes and.segments; a mismatch note names both roots and the corrected invocation; write/read round-trip records the root; a v1 sidecar reads as null (forces one honest rebuild);restampFingerprintRootre-homes a seeded sidecar and is a no-op on a missing cache dir. Each test fails to import without the source change.tsc --noEmitclean.ensureFreshGraphwiring (guard placement, seed re-stamp call, safety net) is what CI on Linux/macOS exercises.Deliberately not included
graft ask <query> <root>,graft build … <entry>) work unchanged.