Skip to content

fix(roles): stop emitting dead-* verdicts for declarative-only languages (#2385) - #2525

Merged
carlos-alm merged 1 commit into
mainfrom
fix/issue-2385
Aug 15, 2026
Merged

fix(roles): stop emitting dead-* verdicts for declarative-only languages (#2385)#2525
carlos-alm merged 1 commit into
mainfrom
fix/issue-2385

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Summary

For languages where call resolution is intentionally absent (Terraform/HCL), role classification emitted dead-unresolved for every symbol — a 100% false-positive verdict by construction, since HCL has no functions, classes, or call graph at all: every node always has fanIn === 0 regardless 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.0 benchmark 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: added isDeclarativeLanguageNode (checks the node's file extension against .tf/.hcl) and gated it at the top of classifyNodeRole, 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 classified leaf unconditionally — reusing the existing role rather than introducing a new enum value, since leaf already carries exactly this "not judged by call-graph reachability" semantic elsewhere in this file (and gets the same low ROLE_WEIGHTS score, 0.2, appropriate for infra-as-code declarations).
  • crates/codegraph-core/src/graph/classifiers/roles.rs: mirrored the identical carve-out in classify_node, so the native and WASM engines stay in parity.
  • Added test coverage in both engines: tests/graph/classifiers/roles.test.ts (JS, both .tf and .hcl, including an exported node) and a new Rust unit test hcl_resource_with_zero_fan_in_is_leaf_not_dead.

Verification

  • lint: pass
  • cargo fmt -- --check / cargo clippy --workspace --all-targets -- -D warnings: pass
  • npx vitest run tests/graph/ tests/integration/roles.test.ts tests/unit/roles.test.ts: 300/300 pass
  • cargo 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 chain
  • Manually reproduced the issue's exact Terraform fixture (KMS key + S3 bucket + SSE config + output, all cross-referenced) against a freshly built native addon (napi build, not the stale prebuilt one) and the WASM engine: all 4 symbols now classify leaf instead of dead-unresolved, confirmed identical across both engines

Also filed

Closes #2385

…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
@greptile-apps

greptile-apps Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR prevents Terraform/HCL declarations from receiving misleading call-graph-based dead-code verdicts while preserving native and TypeScript classifier parity.

  • Adds an early leaf classification for .tf and .hcl nodes in both role-classification engines.
  • Adds TypeScript coverage for both declarative extensions and Rust coverage for Terraform resources.

Confidence Score: 5/5

The 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

Filename Overview
src/graph/classifiers/roles.ts Adds a declarative-extension predicate and classifies Terraform/HCL nodes as leaf before call-graph-based role logic.
crates/codegraph-core/src/graph/classifiers/roles.rs Mirrors the declarative-language carve-out in the native classifier and adds a focused Rust regression test.
tests/graph/classifiers/roles.test.ts Verifies that exported and unexported nodes from both .tf and .hcl files are classified as leaf.

Reviews (1): Last reviewed commit: "fix(roles): stop emitting dead-* verdict..." | Re-trigger Greptile

@github-actions

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

2 functions changed5 callers affected across 2 files

  • isDeclarativeLanguageNode in src/graph/classifiers/roles.ts:93 (4 transitive callers)
  • classifyNodeRole in src/graph/classifiers/roles.ts:366 (4 transitive callers)

@carlos-alm
carlos-alm merged commit 524a193 into main Aug 15, 2026
34 checks passed
@carlos-alm
carlos-alm deleted the fix/issue-2385 branch August 15, 2026 20:57
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(roles): dead-code verdicts emitted for parse-only languages (HCL) where call resolution is absent by design

1 participant