Repository navigation
Flag learnings that name code that's gone - #731
Conversation
A learning whose touches: lists a file the checkout no longer has, or a file#Symbol no code-map symbol is named, is shown as "may be stale" in trail ask, MCP find_code, the prompt and file-touch hooks, and the session-start standing list. query gets a stale count next to notes. trail check flags notes.ts:419 twice; both are word matches: the line passes the learning's id to --replaces (what the replaces learning decided), and the Stop-hook check-name learning is unrelated.
🌱 graft blast radius5 areas changed → 10 areas can be affected. 35 dependent symbols, depth 2. flowchart TB
A0(("Session State Management<br/>10 symbols"))
A1(("Cloud Collaboration<br/>7 symbols"))
A2(("Telemetry Tracking<br/>3 symbols"))
A3(("Initialization Flow<br/>3 symbols"))
A4(("Notes Storage<br/>3 symbols"))
AX(("5 smaller areas<br/>9 symbols"))
classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
class A0,A1,A2,A3,A4 reached;
classDef tail fill:#EEF2F3,stroke:#9AA4A9,stroke-width:1px,color:#3A4247;
class AX tail;
Who knows this code — 11 people across 15 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 35 dependent symbols, grouped by areaSession State Management — 10 symbols in 10 files
Cloud Collaboration — 7 symbols in 4 files
Telemetry Tracking — 3 symbols in 3 files
Initialization Flow — 3 symbols in 3 files
Notes Storage — 3 symbols in 3 files
Ask Interface — 3 symbols in 1 file
MCP Integration — 3 symbols in 2 files
Engine Core — 1 symbol in 1 file
CLI Skills — 1 symbol in 1 file
Learning Sessions — 1 symbol in 1 file
Test signal per changed area — 2 ✓ · 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.
68 test suites also reference this code71 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. |
Trail Cloud has no code, so the CLI does the check and sends the gone touches per learning (`missing`, [] when all are there); the sync goes again when that list changes. The symbol check reads the touched file's text instead of the code map, the rule both sides now state the same way, and drops the 0.4s map load from hooks.
|
Reproduced on main: after renaming Main has moved, though: #747 changed Heads-up for whichever of this and #729 lands second: both add a different 5th parameter to |
Keeps both sides of learningsOnTouch: addHookSavings from #747 and the TOUCH_NOTES_CAP, dir arguments that mark stale learnings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
touches: comes from teammates' learning files, and what the stale check finds goes up at sync as missing. A ../ path, an absolute one or a symlink out of the repo could have probed any file on the machine (whether it exists, whether it holds a word). Resolve each path, follow symlinks, and skip it unless it stays inside the checkout. Also skip reading files over 2 MB for a symbol, and drop a private repo's name from the learnings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged with these commits on top:
Repro in a scratch repo with a scratch HOME: a learning that names |
…ale mark on one line notesOnTouch now takes dir before view, so the tests pass undefined for it. One-line mode dropped #731's "may be stale" warning entirely; it now says "may be stale" beside that learning's path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add trail summary one-line for the hook blocks * Count hook learnings' savings from the learnings, in either view Since #747 the tokens-saved counter read the savings line back out of the hook's text, and one-line mode has no such line, so with one-line on the counter stopped moving for learnings a hook brought. notesForPrompt and notesOnTouch now add learningSavedTokens(hits) to the session themselves, in both views, and the hooks no longer parse their own text. A learning title that reads like a savings line can't move the counter either. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fix summary-view.test.ts for notesOnTouch's dir argument; keep the stale mark on one line notesOnTouch now takes dir before view, so the tests pass undefined for it. One-line mode dropped #731's "may be stale" warning entirely; it now says "may be stale" beside that learning's path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Shrish Dwivedi <shrish@nanonets.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The issue: committed learnings name files and functions that were deleted since, and Claude was told to follow them as written.
Why: trail showed every learning as saved; nothing compared the code a learning names with the code that's there now.
The fix: each learning about to be shown has its
touches:checked against the code in the checkout (no LLM call); one that names gone code is marked "may be stale", with what's gone andtrail note --replaces <id>. The same list goes to Trail Cloud at sync.Moves: learnings reused, measured as
queryevents whosenotesis 1 or 2 (atrail askthat showed learnings), PostHog via Metabase db 11 (posthog_event_full_view): 136,557 from 1,074 people in the 7 days to 2026-10-29 12:15 IST, out of 193,148 asks in repos that keep learnings. This PR addsstale(0/1/2) next tonotes, so from the next release the same event counts how many shown learnings were stale. (learning_reusedisn't used: it left the code in #658.)What Claude sees
Shown in:
trail ask, MCPtrail_find_code, the prompt hook, the file-touch hook, and the standing learnings at session start (as an indentedmay be stale:line).The rule (one place; Trail Cloud shows what the CLI sends)
Only a learning's
touches:is judged, entry by entry:pathis gone when the checkout has no file or folder there.path#Symbolis gone when its path is, or when that file's text no longer has the name as a whole word (last part ofType.method,~Nstripped).Trail Cloud: it has no copy of the code, so
PUT /api/cli/learningsnow carriesmissingon each HEAD learning: the gone touches verbatim,[]when all are there, left out for branch copies and skills. The sync fingerprint includesmissing, so a deleted file re-sends unchanged learnings (every repo re-syncs once after upgrade, since the fingerprint changed). Today's server ignores the field (Goencoding/json, noDisallowUnknownFields), so this is safe before the trail-cloud side ships. The rule was agreed with the trail-cloud "Stale-learning cleanup" session.What I chose, and why
touches:only, not names in the text. Checking backticked names in the body against code-map symbols flagged 10 of 38 real learnings (Trail-Code + assign), and 9 of those names were still in the code: properties (costUsd), module variables (livePair), Node built-ins (execFileSync).touches:only ever holds what existed when the learning was saved, so a miss there is real: on this repo's main checkout, 3 of 29 learnings are flagged, all for the deletedsrc/ask/jev-ask.ts.query, notlearning_reused.stalesits besidenotes; allowlisted insrc/telemetry/contract.tsandTELEMETRY.md.trail check
Exits 1 with 1 conflict on
src/notes/notes.ts:419, a word match ("brings back replace file name"): the new line passes the learning's id to--replaces, which is what that learning decided.The learning this PR first added describes the code-map rule; the second one replaces it (
--replaces l-d70a9e57), since learnings aren't edited.Tests
test/trail-stale-learnings.test.ts(8 tests): file and folder present vs gone, symbol as a whole word vs gone, unmerged-branch learning, theaskline, the session-start line, the sync payload'smissingand the re-sync when it changes, the telemetry key.trail-upload-safety,trail-cloud,workspace-sync-skills) pass.npm test(scratch HOME): 4,143 tests, 4,131 pass, 3 fail. All 3 also fail on origin/main (19865ff) on this machine: two graft-to-trail moves and the "machine without trail" install line, which depend on whether trail is installed here.Follow-ups
trail noterecords only files intouches:, so a learning that names a function only in its text is flagged when the file goes, not when the function does. Recordingfile#Symbolfor backticked names the graph knows (ascodeAnchorsalready does for init) closes that.trail check?🤖 Generated with Claude Code