fix(scanner): Keep ast-grep authoritative, dedupe coverage notes - #108
Conversation
Maintainer re-review (issue 5209011799) flagged two coverage-line issues: - ast-grep was demoted to mixed with a Rust-specific detail whenever a scan contained Rust files, degrading Go analysis in Go+Rust monorepos and duplicating the Rust caveat across sources. ast-grep extraction is not degraded, so it stays authoritative; rust-cargo owns the caveat. - AddSource appended every source detail to Notes with no dedup, so a shared caveat printed twice. Notes and rendered details are now deduped at record time and at render time. newDepsProject mirrors the production shape (ast-grep authoritative + rust-cargo mixed carrying the note) instead of attaching the note to ast-grep. Covered by TestAstGrepScanDirectoryRustStaysAuthoritative, TestGraphCoverageAddSourceDedupesSharedDetail, TestDepgraphRendersSharedCoverageDetailOnce, and TestNewDepsProjectRustCaveatOwnedByRustCargoSource. Co-authored-by: GPT-5.6 Sol <codex@openai.com>
There was a problem hiding this comment.
Pull request overview
Keeps ast-grep provenance authoritative while assigning Rust resolution caveats to rust-cargo and deduplicating user-facing coverage notes.
Changes:
- Corrects Rust coverage source ownership.
- Deduplicates coverage notes in scanner and rendered output.
- Adds regression coverage and ignores runtime caches.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Ignores .cache/ runtime state. |
scanner/astgrep.go |
Keeps successful ast-grep scans authoritative. |
scanner/astgrep_test.go |
Tests Rust scan provenance. |
scanner/contracts_test.go |
Tests default Rust coverage sources. |
scanner/outcome.go |
Deduplicates coverage notes. |
scanner/outcome_test.go |
Tests shared-detail deduplication. |
scanner/types.go |
Assigns the Rust caveat to rust-cargo. |
render/depgraph.go |
Deduplicates rendered source details. |
render/depgraph_test.go |
Tests single rendering of shared details. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… not dedupe Copilot review (discussion_r3740917133) on PR JordanCoin#108: the render comment claimed NormalizeCoverage dedupes source tuples, but it only sorts by name/status/detail (analysis/contracts.go). Reword to describe the sorting behavior; the dedup lives at render time via slices.Contains.
JordanCoin
left a comment
There was a problem hiding this comment.
Verified on a real two-crate Cargo workspace rather than from the description:
#106 — ast-grep is now authoritative; only rust-cargo carries the Rust caveat. Coverage still correctly reports partial, so the honesty is preserved while the attribution is fixed.
#107 — the coverage line prints the caveat once.
No regression on a Go-only repo: still complete with a single authoritative ast-grep source.
Deduping at AddSource rather than at the renderer is the right call — every consumer (MCP coverage_notes, --importers, intent, watch state) inherits it, instead of each render path needing its own fix. Full suite green, vet clean. Thanks for turning these around before I'd even finished filing them.
Follow-up to #105, closing the two open findings from the maintainer re-review on the coverage line.
What this PR does
Both findings were in the coverage line — cosmetic but user-facing:
1. The Rust note printed twice.
ast-grepandrust-cargoboth carried an identicalDetail, andGraphCoverage.AddSourceappended each source's detail toNoteswith no dedup. A two-crate workspace rendered:2.
ast-grepwas labeledmixedcarrying a Rust-specific detail. TheDetectLanguage(...) == "rust"loop inscanner/astgrep.godemoted ast-grep's source status even though its extraction is not degraded — the macro/#[path]/string-routed caveat is a Rust resolution gap, whichrust-cargoowns. Consequences: on a Go+Rust monorepo the Go analysis was reported degraded too, and the same sentence landed on two sources, producing the duplicate in (1).Changes
scanner/astgrep.go— ast-grep staysauthoritativeon a successful scan regardless of language; the Rust caveat is no longer attached to its source. The file graph already recordsrust-cargo(mixed, with the caveat) for Rust repos, so coverage remainspartialwhere it should.scanner/outcome.go—GraphCoverage.AddSourcerecords each source detail once (dedup before append), so everyNotesconsumer (MCP structuredcoverage_notes,--importers, intent, watch state) inherits the dedup.render/depgraph.go—renderCoverageLinerenders each detail once, so a shared caveat prints a single warning in the text output even if two sources carry it.scanner/types.go— the defaultnewDepsProjectcoverage mirrors the production shape (ast-grepauthoritative+rust-cargomixedcarrying the note) instead of attaching the note to ast-grep.Before / after
JSON sources before:
{"name": "ast-grep", "status": "mixed", "detail": "Rust macro-generated, ..."} {"name": "cargo-metadata", "status": "authoritative"} {"name": "rust-cargo", "status": "mixed", "detail": "Rust macro-generated, ..."}JSON sources after — the list reads as what each tool actually contributed:
{"name": "ast-grep", "status": "authoritative"} {"name": "cargo-metadata", "status": "authoritative"} {"name": "rust-cargo", "status": "mixed", "detail": "Rust macro-generated, ..."}Regression tests
TestAstGrepScanDirectoryRustStaysAuthoritative— Rust scans keep ast-grepauthoritativewith no Rust detail.TestGraphCoverageAddSourceDedupesSharedDetail— shared caveat recorded once across sources.TestDepgraphRendersSharedCoverageDetailOnce— a shared detail renders once in text output.TestNewDepsProjectRustCaveatOwnedByRustCargoSource— default coverage shape matches production.Verification
go build ./...,go vet ./scanner ./render ./analysis .,gofmtclean.scannercoverage/contract tests and renderTestDepgraph*pass.Developed with carefully directed, manually reviewed AI assistance.
Co-authored-by: GPT-5.6 Sol codex@openai.com