Skip to content

trail: overlap only after an edit to a shared function - #617

Merged
anirudhkumar-nanonets merged 1 commit into
mainfrom
feat/overlap-after-edit
Oct 15, 2026
Merged

anirudhkumar-nanonets merged 1 commit into
mainfrom
feat/overlap-after-edit

Conversation

@anirudhkumar-nanonets

Copy link
Copy Markdown
Collaborator

Moves: none of the project's metrics directly. learnings_committed is the main number, and this doesn't change what gets committed. It stops trail from putting false alarms in front of people during the assign rollout, where overlap lines were the first thing a teammate saw.

Why

On 15 Oct every overlap line trail showed in a session was wrong. fix/trail-release-prep and fix/npm12-grammars had been squash-merged as #595 and #594. Their branches were still on origin, so git's history called them unmerged, and trail flagged them as open work. The lines also fired on files guessed from the prompt rather than code anyone was editing. They flagged src/cli.ts on a prompt that matched no code at all, and they only said which file was shared, never what the clash was.

What changes

Merged or closed branches aren't open work. refreshBranches now skips a branch when:

  • merging it into the default branch would change nothing (git merge-tree --write-tree), which is how a squash merge looks, or
  • its GitHub pull request was merged or closed on the branch's current tip. Only the detached background refresh asks gh. The result is kept in the cache, so the session-start refresh never waits on GitHub. Without gh, or off GitHub, the merge-tree check still applies.

A branch that gets new commits after its merge or close shows up again.

Overlap comes after an edit, at the function level. The prompt hook and trail ask no longer print overlap lines. After Claude edits a file that a teammate's open branch also changes, the post-edit hook parses both versions of the file and compares the function each change lands in. It does the same for a top-level declaration such as const defaultRetryMax, since the graph has no node for constants. It ignores imports. The parse runs only for a file some branch changes, so most edits cost one cache read.

When both changes land in the same function, Claude gets the function, the branch, its commit message (quoted as data, cleaned to one line) and the git diff command to read the change. It's asked to tell the user in its own words, starting with 🔀 trail · , whether the two clash:

🔀 trail · Shrish is also changing readPackageName() on fix/trail-release-prep. It's only a comment, so there's no clash.

Each branch and function is mentioned once per session. trail check's file-level line keeps its place before a PR, now with the 🔀 trail mark and without merged branches.

Tests

  • New trail-edit-overlap:
    • a squash-merged branch drops out, then returns when someone pushes to it again
    • a closed PR's tip drops out
    • an edit to the function a branch changes is an overlap, and one to another function in the same file isn't
    • a shared top-level constant is an overlap, and shared imports aren't
    • the hook end to end, mentioning it once per session
    • the directive's wording, commit message cleaning, and the line parsing for diffs and edit tools
  • Updated trail-cloud for the new mark. Removed the prompt-overlap test along with overlapsForPrompt.
  • Full suite on my Mac: 1,422 pass, 3 fail, 1 skipped. The 3 failures are graft-to-trail tests, and they fail the same way on main here, because trail is installed globally on this machine for a demo. CI has no global trail.

🤖 Generated with Claude Code

@trailhq-graft

trailhq-graft Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

🌱 graft blast radius

4 areas changed → 3 areas can be affected. 7 dependent symbols, depth 2.
Tests: no test reaches Claude Session State, Post-Ask Hooks; Ask Formatting has tests the diff did not touch; 1 area updated its tests.
Tag: @shhdwi — 6 of 7 areas · Buseong Kim — Ask Formatting

flowchart TB
  A0(("Tool Invocation<br/>3 symbols"))
  A1(("Workspace Sync<br/>3 symbols"))
  A2(("Workspace Query<br/>1 symbol"))
  classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
  class A0,A1,A2 reached;
Loading
Can be affected Symbols Nearest hop Reached from
Tool Invocation 3 src/mcp/tools.ts:L248-L330 callSingleTool — calls, depth 1 Ask Formatting
Workspace Sync 3 src/cloud/workspace-sync.ts:L102-L116 syncRepo — calls, depth 1 Edit Overlap Detection
Workspace Query 1 src/graph/workspace-cli.ts:L102-L111 runWorkspaceAsk — calls, depth 1 Ask Formatting
Who knows this code — 2 people across 7 areas
Area Who knows it
Ask Formatting · changed @shhdwi — 16 commits, last 3mo ago · Buseong Kim — 3 commits, last 2mo ago
Claude Session State · changed @shhdwi — 17 commits, last yesterday
Post-Ask Hooks · changed @shhdwi — 25 commits, last yesterday
Tool Invocation · affected @shhdwi — 15 commits, last yesterday
Workspace Sync · affected @shhdwi — 1 commit, last yesterday
Workspace Query · affected @shhdwi — 5 commits, last yesterday
Edit Overlap Detection · 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 7 dependent symbols, grouped by area

Tool Invocation — 3 symbols in 1 file

  • src/mcp/tools.ts:L248-L330 — callSingleTool (calls, depth 1)
    262: return { text: formatAsk(r), isError: false };
  • src/mcp/tools.ts:L154-L200 — callWorkspaceTool (calls, depth 1)
    167: return { text: formatAsk(r), isError: false };
  • src/mcp/tools.ts:L217-L245 — callTool (calls, depth 2)

Workspace Sync — 3 symbols in 1 file

  • src/cloud/workspace-sync.ts:L102-L116 — syncRepo (calls, depth 1)
    109: if (opts.fetch !== false) refreshBranches(place.checkout);
  • src/cloud/workspace-sync.ts:L261-L267 — runSyncChild (calls, depth 2)
  • src/cloud/workspace-sync.ts:L119-L131 — syncWorkspaceRepos (calls, depth 2)

Workspace Query — 1 symbol in 1 file

  • src/graph/workspace-cli.ts:L102-L111 — runWorkspaceAsk (calls, depth 1)
    110: else process.stdout.write(formatAsk(r));
Test signal per changed area — 1 ✓ · 1 ⚠ · 2 ✗

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.

  • ⚠ Ask Formatting — 1 of 1 reached · 4 test files reach it, none changed here
  • ✓ Edit Overlap Detection — 7 of 16 reached · 2 test files changed here: test/trail-cloud.test.ts, test/trail-edit-overlap.test.ts
    • not reached: closedPrHeads, onBase, overlapMark, declaredOn, git, landedIn, lineAt, symbolOf, …1 more
  • ✗ Claude Session State — 0 of 3 reached · no test file reaches it
    • not reached: handlePostEdit, editOverlap, main
  • ✗ Post-Ask Hooks — 0 of 1 reached · no test file reaches it
    • not reached: afterAsk
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/ask-fusion.test.ts
  • test/ask.test.ts
  • test/regression-single-repo.test.ts
  • test/workspace.test.ts

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

graft blast · origin/main...HEAD · depth 2 · 11 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 15, 2026
@anirudhkumar-nanonets
anirudhkumar-nanonets merged commit de4d201 into main Oct 15, 2026
8 checks passed
github-actions Bot added a commit that referenced this pull request Oct 15, 2026
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