Say where every declaration is - #30
Merged
Merged
Conversation
The extraction knew which file a class was in and nothing narrower. An agent told about a controller still had to search the file for it, and the walkthrough in #23 cannot exist at all without this: every claim in one is supposed to carry a file:line a reader can open and check. Entities, controllers, actions and methods now carry a one-based line, taken from the identifier token rather than from the declaration's span. A span begins at the first attribute, and Customer sits behind a doc comment and four of them, so the two answers are four lines apart -- and only one of them is the line anybody means. Actions and methods carry their own file as well as their own line, because a partial controller's members need not be declared in the file the controller itself is cited at. The MCP tools name the file once and then cite members by line alone. That was found by reading a rendered response rather than the assertions: the first version repeated a hundred characters of absolute path on every action and every helper method, which on a controller with eight actions would have spent a paragraph of an agent's context on one file name. A member in a different file is still given in full -- exactly the case where a reader would otherwise open the wrong one. The tests read the fixture back off disk and require the cited line to contain the declaration, across every sample project. It is the only assertion that catches an off-by-one or a span that started at an attribute. 355 tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W45tzJFX3NoSrk7svtQeKT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First step of #23. Nothing in the model knew a line number, and the walkthrough cannot exist without one.
Why this is the first thing
The design in #23 rests on a single promise: every claim in a walkthrough carries a
file:linea reader can open and check. That is what separates a traced account from a plausible one, and it is why the graph is extracted rather than generated.The extraction knew which file a class was in and nothing narrower. So there was nothing to cite with.
It is also worth having on its own.
xaf_entityandxaf_controllerhanded an agent a name, a base class and a body of code, and never said where any of it was — the agent's next move was to search the project for the thing it had just been given.The one decision that matters
The line comes from the identifier token, not from the declaration's span.
A span begins at the first attribute.
Customerin the XPO fixture sits behind a doc comment and four attributes:Both answers are correct about the syntax. Only one is the line anybody means, and they are four apart.
SourceLine.Oftakes aSyntaxTokenfor exactly this reason, and returns zero rather than one when there is no source to point at — one is a plausible-looking claim about a file, and zero is not a line, so nothing renders it as though it were.Actions and methods carry their own file, not just their own line. A partial controller — the shape the XAF designer generates — can declare a method in a different file from the one the class is cited at. Borrowing the controller's path would produce a citation that opens the wrong file.
What an agent now sees
The file is named once. That came out of reading a rendered response rather than the assertions — the first version repeated a hundred characters of absolute path on every action and every helper method, which on a controller with eight actions spends a paragraph of an agent's context window on one file name. The same reasoning
MaxCodeLengthalready encodes.A member in a different file is still printed in full, because that is precisely the case where a reader following
line 31would open the wrong one.The tests
The important one does not assert a number. It reads the fixture back off disk and requires the cited line to contain the declaration — across every entity and every controller in all seven sample projects:
That is the only assertion that catches both ways this goes wrong silently: an off-by-one from a zero-based line, and a span that started at an attribute. Plus explicit pins on the
Customerattribute case, on an action being cited at its own field rather than at its class, and on the rendered MCP response naming the file exactly once.355 tests, zero warnings.
What is not here
The slice itself —
ProcessSlice.From(project, seed, depth), the call and reference graph, unresolved edges. That is the substantial half of phase 1 and it goes in its own pull request, on top of this.🤖 Generated with Claude Code
https://claude.ai/code/session_01W45tzJFX3NoSrk7svtQeKT