analysis.Coverage publishes three things: status, sources, and issues. The third is永 always empty, on every repository, in every mode, regardless of what happened during the scan.
Evidence
The only producer sets it to an empty slice and nothing ever adds to it — scanner/outcome.go:97:
coverage := analysis.Coverage{
Sources: append([]analysis.Source(nil), sources...),
Issues: []analysis.Issue{}, // never appended to, anywhere
}
rg -n "Issues" --type go finds only the declaration (analysis/contracts.go:47), the normalizer that clones and sorts it (contracts.go:52-74), and that one empty literal. There is no write path.
Confirmed behaviourally on every repo I tried, including ones with genuinely unresolvable references:
$ codemap --json --deps <repo with a missing local import> | jq .coverage
{"status": "complete", "sources": [{"name":"ast-grep","status":"authoritative"}], "issues": []}
Why it matters
The scanner drops references constantly and by design — unparseable import forms, targets absent from disk, ambiguous matches, macro-generated and dynamically-constructed paths. Every one of those is discarded with a bare continue / return nil. The contract then reports issues: [], which a consumer reads as "nothing was dropped."
This is the same defect class as #132 and #136, but at the contract layer rather than in one resolver: it is the field whose entire job is to disclose gaps, and it discloses nothing. It is also why #132 and #136 stayed invisible — had issues been real, a TypeScript repo losing 515 edges and a Python package losing all 31 intra-package imports would both have announced themselves.
NormalizeCoverage sorting and cloning a permanently-empty slice is a good indicator: the plumbing was built and the producer never was.
Scope note
The drop sites are in at least three places, in more than one resolver — the generic path in scanner/filegraph.go, the Rust path in scanner/rustgraph.go, and extraction-time discards in scanner/astgrep.go where if path != "" / if mod != "" guards throw matches away before resolution is even attempted. That last one is easy to miss because it happens upstream of anything that looks like resolution.
The distinction that decides whether this is useful or noise: a reference the scanner FAILED to resolve is not the same as one it INTENTIONALLY does not resolve. Go stdlib, third-party modules, and external crates are out of scope by design; reporting them produces hundreds of false entries on any real repo and makes the array worse than empty. I measured one implementation that got this wrong: 887 entries on this repository, all standard library.
Trap for whoever implements this
ImportReference.Line is populated from m.Range.Start.Line (scanner/astgrep.go:373), and ast-grep's range is 0-based. Today this is invisible because FileAnalysis.References is json:"-" and no surface exposes a line number. The moment issues carry Line, every reported line is off by one unless converted. Two separate implementations hit this.
Related: #132, #136 (both would have been disclosed by a working issues), #111 (per-query granularity), #133 (the consumer that makes it actionable).
analysis.Coveragepublishes three things:status,sources, andissues. The third is永 always empty, on every repository, in every mode, regardless of what happened during the scan.Evidence
The only producer sets it to an empty slice and nothing ever adds to it —
scanner/outcome.go:97:rg -n "Issues" --type gofinds only the declaration (analysis/contracts.go:47), the normalizer that clones and sorts it (contracts.go:52-74), and that one empty literal. There is no write path.Confirmed behaviourally on every repo I tried, including ones with genuinely unresolvable references:
Why it matters
The scanner drops references constantly and by design — unparseable import forms, targets absent from disk, ambiguous matches, macro-generated and dynamically-constructed paths. Every one of those is discarded with a bare
continue/return nil. The contract then reportsissues: [], which a consumer reads as "nothing was dropped."This is the same defect class as #132 and #136, but at the contract layer rather than in one resolver: it is the field whose entire job is to disclose gaps, and it discloses nothing. It is also why #132 and #136 stayed invisible — had
issuesbeen real, a TypeScript repo losing 515 edges and a Python package losing all 31 intra-package imports would both have announced themselves.NormalizeCoveragesorting and cloning a permanently-empty slice is a good indicator: the plumbing was built and the producer never was.Scope note
The drop sites are in at least three places, in more than one resolver — the generic path in
scanner/filegraph.go, the Rust path inscanner/rustgraph.go, and extraction-time discards inscanner/astgrep.gowhereif path != ""/if mod != ""guards throw matches away before resolution is even attempted. That last one is easy to miss because it happens upstream of anything that looks like resolution.The distinction that decides whether this is useful or noise: a reference the scanner FAILED to resolve is not the same as one it INTENTIONALLY does not resolve. Go stdlib, third-party modules, and external crates are out of scope by design; reporting them produces hundreds of false entries on any real repo and makes the array worse than empty. I measured one implementation that got this wrong: 887 entries on this repository, all standard library.
Trap for whoever implements this
ImportReference.Lineis populated fromm.Range.Start.Line(scanner/astgrep.go:373), and ast-grep's range is 0-based. Today this is invisible becauseFileAnalysis.Referencesisjson:"-"and no surface exposes a line number. The moment issues carryLine, every reported line is off by one unless converted. Two separate implementations hit this.Related: #132, #136 (both would have been disclosed by a working
issues), #111 (per-query granularity), #133 (the consumer that makes it actionable).