diff --git a/src/tests/test_tool_metadata.py b/src/tests/test_tool_metadata.py index 3be8832..1902b7c 100644 --- a/src/tests/test_tool_metadata.py +++ b/src/tests/test_tool_metadata.py @@ -79,3 +79,22 @@ def test_server_advertises_codealive_version_and_compact_instructions(): assert len(mcp.instructions.split()) <= 150 assert "DISCOVER → SEARCH → READ → EXPAND" in mcp.instructions assert "chat only when the user explicitly requests" in mcp.instructions.lower() + +@pytest.mark.asyncio +async def test_relationships_description_states_the_call_site_contract(): + """The three call-site rules are only enforceable through the tool description: the backend can + omit positions for a repository indexed before call sites shipped, and a model that reads a + missing position as "no call" draws the opposite conclusion from the truth.""" + # Arrange / Act + async with Client(mcp) as client: + tools = await client.list_tools() + + # Assert + description = {tool.name: tool for tool in tools}["get_artifact_relationships"].description + assert description is not None + assert "call_sites" in description + assert "call_site_count" in description + # Missing position means "not indexed yet", never "no call". + assert "never" in description.lower() + # No parameter enables them, so the model must not go hunting for one. + assert "no parameter" in description.lower() diff --git a/src/tools/artifact_relationships.py b/src/tools/artifact_relationships.py index 545a2db..8327c76 100644 --- a/src/tools/artifact_relationships.py +++ b/src/tools/artifact_relationships.py @@ -33,6 +33,17 @@ async def get_artifact_relationships( This is a graph expansion tool, not a search tool. Use identifiers returned by semantic_search, grep_search, fetch_artifacts, read_file, or prior relationship results. + + Call relationships also carry `call_sites` — each one a `position` written as + `path:line`, where the call is actually written — plus `call_site_count` for + how many exist in total. Read those exact lines instead of fetching the whole + caller. There is no parameter for this: positions come back whenever they are + known, so do not look for a flag. A call item with no `call_sites` means the position is not + indexed yet (the repository was indexed before call sites shipped, or that one + edge could not be located); it never means the call does not happen — the item + being listed at all is what says the call exists. A `confidence` on a site + appears only when the position is approximate; its absence means exact. For + incoming calls the file shown is the caller's file, not this artifact's. """ tool_name = "get_artifact_relationships" require_text(identifier, tool_name, "identifier")