fix(roles): stop emitting dead-* verdicts for declarative-only languages (#2385) - #2525
Merged
Conversation
…ges (#2385) Terraform/HCL has no functions, classes, or call graph by design -- every symbol always has fanIn 0, so role classification flagged every resource as dead-unresolved regardless of whether it was actively referenced. This is not the same as a language where call resolution is simply not implemented yet (those genuinely have dead code a future resolver could find); a declarative-only language's fanIn carries zero dead-code signal at all. Both the JS and Rust classifiers now classify every node in a declarative-only-language file (.tf/.hcl) as leaf unconditionally, mirroring the existing carve-out for interface/type declaration members that can never be judged by call-graph reachability either. docs check acknowledged: internal role-classification bugfix, no README/CLAUDE.md/ROADMAP surface area changed. Impact: 2 functions changed, 5 affected
Contributor
Greptile SummaryThe PR prevents Terraform/HCL declarations from receiving misleading call-graph-based dead-code verdicts while preserving native and TypeScript classifier parity.
Confidence Score: 5/5The PR appears safe to merge, with the declarative-language carve-out consistently implemented across both engines. The supported Terraform/HCL extensions, emitted node kinds, and shared file-path inputs align with the new classification logic, and no blocking or independently actionable issue remains. Important Files Changed
Reviews (1): Last reviewed commit: "fix(roles): stop emitting dead-* verdict..." | Re-trigger Greptile |
Contributor
Codegraph Impact Analysis2 functions changed → 5 callers affected across 2 files
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
For languages where call resolution is intentionally absent (Terraform/HCL), role classification emitted
dead-unresolvedfor every symbol — a 100% false-positive verdict by construction, since HCL has no functions, classes, or call graph at all: every node always hasfanIn === 0regardless of how many times a resource is actually referenced elsewhere in the same file (only reference-tracking, not call-tracking, would show that — and HCL produces no reference edges either). This invites destructive action: an agent or human reading "132 dead symbols" in a Terraform repo could try to delete live infrastructure.This is explicitly not the same situation as a language where call resolution is simply not implemented yet (e.g. bash/ruby/lua carry real dead code a future resolver could find, hence their
0.0/0.0benchmark thresholds reflect an engineering gap, not a language-capability gap). HCL's absence of call edges is by design — the README support matrix already documents it as parse-only.Changes
src/graph/classifiers/roles.ts: addedisDeclarativeLanguageNode(checks the node's file extension against.tf/.hcl) and gated it at the top ofclassifyNodeRole, mirroring the existing carve-out for interface/type declaration members that can never be judged by call-graph reachability either. Declarative-language nodes are now classifiedleafunconditionally — reusing the existing role rather than introducing a new enum value, sinceleafalready carries exactly this "not judged by call-graph reachability" semantic elsewhere in this file (and gets the same lowROLE_WEIGHTSscore, 0.2, appropriate for infra-as-code declarations).crates/codegraph-core/src/graph/classifiers/roles.rs: mirrored the identical carve-out inclassify_node, so the native and WASM engines stay in parity.tests/graph/classifiers/roles.test.ts(JS, both.tfand.hcl, including an exported node) and a new Rust unit testhcl_resource_with_zero_fan_in_is_leaf_not_dead.Verification
cargo fmt -- --check/cargo clippy --workspace --all-targets -- -D warnings: passnpx vitest run tests/graph/ tests/integration/roles.test.ts tests/unit/roles.test.ts: 300/300 passcargo test --package codegraph-core graph::classifiers::roles: 15/15 pass (including the new test)codegraph diff-impact --staged: 2 functions changed, 5 callers affected — contained to the role-classification call chainnapi build, not the stale prebuilt one) and the WASM engine: all 4 symbols now classifyleafinstead ofdead-unresolved, confirmed identical across both enginesAlso filed
module-reference edges never materialize) as a separate, distinct piece of resolver work not part of this dead-code classification fixCloses #2385