Summary
change(operation:"tests") reports no covering tests when a test reaches a changed MCP handler through the project's string-keyed tool dispatcher. The tests are real and executable, but the graph loses the registration/invocation hop.
Reproduction
For these changed symbols:
internal/mcp/tools_coding.go::Server.registerCodingTools
internal/mcp/tools_fileops.go::readPhysicalFileEvidence
internal/mcp/tools_fileops.go::Server.handleReadFile
change.tests returned:
coverage_note: 0/3 changed symbols have test coverage
total_files: 0
uncovered: [registerCodingTools, readPhysicalFileEvidence, handleReadFile]
However internal/mcp/read_file_physical_evidence_test.go directly exercises the public tool contract through calls such as:
callTool(t, srv, "read_file", map[string]any{...})
and the focused suite and race suite both pass:
go test ./internal/mcp -run '^TestReadFilePhysicalEvidence' -count=1
go test -race ./internal/mcp -run '^TestReadFilePhysicalEvidence' -count=1
Missing graph path
The runtime path is approximately:
TestReadFilePhysicalEvidence*
-> callTool(..., "read_file", ...)
-> tool registry lookup
-> registration "read_file" -> Server.handleReadFile
A conventional static call graph sees callTool but does not join the string literal to the matching tool registration and handler.
Impact
change.tests produces false-negative coverage for MCP handlers;
change.contract then warns that no covering tests exist and recommends broader package tests;
- the same gap applies to routers, RPC dispatchers, command buses, plugin registries, and other string-keyed callback systems.
Suggested feature
Emit dynamic-dispatch test edges by joining:
- registration keys to handler symbols, for example
"read_file" -> Server.handleReadFile;
- test call-site string literals to the same registration key;
- the resulting test-to-handler path as an
EdgeTests or an explicitly typed dynamic-dispatch edge consumed by change.tests.
Expose provenance so callers can distinguish evidence quality:
{
"coverage_source": "registry_dispatch",
"dispatcher": "callTool",
"registration_key": "read_file",
"handler": "Server.handleReadFile"
}
Acceptance criteria
- the physical-evidence tests are returned as targets for
Server.handleReadFile;
- ordinary direct-call test edges remain unchanged;
- ambiguous or computed registration keys are reported with lower confidence rather than asserted as exact;
- test fixtures cover direct calls, exact string-key dispatch, aliases, unknown keys, and non-test callers.
Environment
Summary
change(operation:"tests")reports no covering tests when a test reaches a changed MCP handler through the project's string-keyed tool dispatcher. The tests are real and executable, but the graph loses the registration/invocation hop.Reproduction
For these changed symbols:
change.testsreturned:However
internal/mcp/read_file_physical_evidence_test.godirectly exercises the public tool contract through calls such as:and the focused suite and race suite both pass:
Missing graph path
The runtime path is approximately:
A conventional static call graph sees
callToolbut does not join the string literal to the matching tool registration and handler.Impact
change.testsproduces false-negative coverage for MCP handlers;change.contractthen warns that no covering tests exist and recommends broader package tests;Suggested feature
Emit dynamic-dispatch test edges by joining:
"read_file" -> Server.handleReadFile;EdgeTestsor an explicitly typed dynamic-dispatch edge consumed bychange.tests.Expose provenance so callers can distinguish evidence quality:
{ "coverage_source": "registry_dispatch", "dispatcher": "callTool", "registration_key": "read_file", "handler": "Server.handleReadFile" }Acceptance criteria
Server.handleReadFile;Environment
v0.63.2+6a2905e