diff --git a/src/tests/test_tool_metadata.py b/src/tests/test_tool_metadata.py index 6692845..4a76785 100644 --- a/src/tests/test_tool_metadata.py +++ b/src/tests/test_tool_metadata.py @@ -80,6 +80,25 @@ def test_server_advertises_codealive_version_and_compact_instructions(): 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() + def test_imported_server_selects_single_span_ownership_without_main(): import os 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") diff --git a/uv.lock b/uv.lock index 4f12639..70b136b 100644 --- a/uv.lock +++ b/uv.lock @@ -48,15 +48,15 @@ wheels = [ [[package]] name = "anyio" -version = "4.14.1" +version = "4.15.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.15'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/d2/f4d173e22df740bc37b1db102b386ba719b66e95b0f0d751f556b387e6d2/anyio-4.15.1.tar.gz", hash = "sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94", size = 276966, upload-time = "2026-09-05T10:42:39.44Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" }, + { url = "https://files.pythonhosted.org/packages/12/b8/4bd346e22b28902df4d651910f5242c28d84e4a5c2435ca5c3f797ed7e2e/anyio-4.15.1-py3-none-any.whl", hash = "sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101", size = 132079, upload-time = "2026-09-05T10:42:37.923Z" }, ] [[package]]