Skip to content

feat(scanner): Recover Cargo topology on scan failure - #117

Merged
JordanCoin merged 4 commits into
JordanCoin:mainfrom
reneleonhardt:feat/scanner-cargo-fallback
Aug 12, 2026
Merged

feat(scanner): Recover Cargo topology on scan failure#117
JordanCoin merged 4 commits into
JordanCoin:mainfrom
reneleonhardt:feat/scanner-cargo-fallback

Conversation

@reneleonhardt

Copy link
Copy Markdown
Contributor

What does this PR do?

When ast-grep fails or times out, the scanner recovers the Rust dependency graph from cargo metadata instead of failing hard:

  • buildFileGraphWithFallback runs the primary scan, and on an ast-grepIncompleteScanError builds a fallback ScanOutcome from cargo metadata (buildCargoFallbackOutcome).
  • The fallback outcome carries honest provenance (Sources: [{name: "ast-grep", status: timeout|failed}, {name: "rust-cargo", status: fallback}]) so coverage and fail-closed behavior stay consistent with the scan contract.
  • Conditional dependencies are identified (cargoDependencyIsConditional) and reported as conditional edges.

Review follow-ups included

  • fix(scanner): Normalize null Cargo targetscargo metadata entries with null target fields no longer crash or produce malformed edges.
  • fix(scanner): return context.Canceled when the fallback file scan fails on a pre-cancelled context — a pre-cancelled caller receives context.Canceled (the primary error is still preserved for real scan failures).

CLI / MCP surface

No new CLI commands or arguments, and no new MCP tools. Behavior of existing surface:

  • codemap --deps <path> on a Rust repository returns the recovered graph with rust-cargo fallback provenance instead of a hard error when ast-grep is unavailable or times out.
  • MCP get_dependencies returns the same fallback outcome with its provenance.

Coverage provenance notes

The fallback only engages on an ast-grep failure; a successful scan remains authoritative. Degraded outcomes are bounded and deterministic, matching the fail-closed contract.

Developed with carefully directed, manually reviewed AI assistance.

reneleonhardtand others added 4 commits August 8, 2026 22:57
When ast-grep fails or times out, recover the Rust dependency graph from `cargo metadata` instead of failing hard. The fallback outcome carries honest provenance (ast-grep `timeout|failed` plus a `rust-cargo` fallback source) so coverage and fail-closed behavior stay consistent with the scan contract. Conditional dependencies are identified and reported as conditional edges.
`cargo metadata` entries with null target fields no longer crash or produce malformed edges.
…ls on a pre-cancelled context
Preserve the primary ast-grep error for real scan failures; honour caller
cancellation when ScanFiles fails because the context was already cancelled.
Co-Authored-By: Whale integration <whale@local>
scanForGraphOutcome only delegated to scanForGraphOutcomeWithFilters with an
empty Filters{} and had no callers; staticcheck U1000.
@reneleonhardt
reneleonhardtforce-pushed the feat/scanner-cargo-fallback branch from f01d812 to 7d14431CompareAugust 8, 2026 20:59
@JordanCoin

Copy link
Copy Markdown
Owner

Heads-up before these land: #117 and #118 don't compile together, in either merge order. Both are green in CI because each is built against main, not against the other.

Git auto-merges them with no textual conflict — the collision is semantic:

main today:

funcdiscoverCargoManifests(rootstring, files []FileInfo) []string

#118 changes the signature:

funcdiscoverCargoManifests(ctx context.Context, rootstring, files []FileInfo) ([]string, error)

#117 adds a new caller (scanner/cargofallback.go:72) using the old one:

manifests:=discoverCargoManifests(root, files)

Result whichever way round they go:

scanner/cargofallback.go:72:15: assignment mismatch: 1 variable but discoverCargoManifests returns 2 values
scanner/cargofallback.go:72:44: not enough arguments in call to discoverCargoManifests
have (string, []FileInfo)
want (context.Context, string, []FileInfo)

Verified by merging both into a scratch worktree in each order and building.

The fix is one line in buildCargoFallbackOutcome, which already has a ctx in scope:

manifests, err:=discoverCargoManifests(ctx, root, files)
iferr!=nil {
returnScanOutcome{}, err
}

Simplest is to fix it in whichever of the two you'd like to merge second. No need to change anything else — #115, #116 and #119 are unaffected, and all five merge cleanly apart from this.

@reneleonhardt

reneleonhardt commented Aug 9, 2026

Copy link
Copy Markdown
ContributorAuthor

If you want to merge them both, can you just merge this one first? That was the order for the integration stack of my next wave, I'll fix the other one then 😅

Or you can just update yourself, edits are enabled as always.

@JordanCoinJordanCoin left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the full Cargo fallback path and provenance handling at 7d14431. The fallback is bounded, preserves the primary failure when unavailable, reports partial evidence honestly, and the full scanner suite passes. This should land before #118, which must then update its changed discoverCargoManifests caller. No blocking finding in this PR — approved.

@JordanCoin
JordanCoin merged commit 930fda2 into JordanCoin:mainAug 12, 2026
12 checks passed
@reneleonhardt
reneleonhardt deleted the feat/scanner-cargo-fallback branch August 12, 2026 07:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@reneleonhardt@JordanCoin