Summary
codegraph exports <f> -T --json (and the dead-export classification it feeds) reports zero-consumer / dead-export for interfaces and types that are demonstrably imported and used elsewhere via import type { X } from .... The underlying import graph (codegraph deps) correctly records the cross-file edge — the gap is specifically in how exports/dead-role attributes "consumers."
Repro
$ codegraph exports src/domain/graph/builder/cha.ts -T --json
Shows:
{
"name": "ChaContext",
"kind": "interface",
"line": 18,
"consumers": [],
"consumerCount": 0
}
But:
$ codegraph deps src/domain/graph/builder/cha.ts --json
Correctly shows importedBy: [src/domain/graph/builder/stages/build-edges.ts, src/domain/graph/builder/stages/native-orchestrator.ts], and grepping those files confirms import type { ChaContext } from '../cha.js' followed by real usage as a type annotation (e.g. build-edges.ts:47,692,804,1470, native-orchestrator.ts:49,1148,1273).
So the same underlying file-level import edge is correctly tracked by deps, but exports's per-symbol consumer count doesn't credit import type-only usages, producing a false "dead export" for ChaContext.
Same root cause reproduces on other type-only exports, e.g. ExtractParametersOptions.typeMap in src/extractors/helpers.ts.
Impact
Any interface/type that is only ever used as a type annotation (never constructed or called) — a very common and idiomatic TypeScript pattern — is misclassified as dead code by codegraph roles --role dead / flagged with consumerCount: 0 by codegraph exports, even when actively relied upon across the codebase.
Suggested fix
When computing per-symbol consumers for exports, credit import type { X } edges (and other type-position usages: type annotations, generic type arguments, extends/implements clauses) as consumers, not just call/construct edges. The file-level import graph already has this data (as shown by codegraph deps) — the gap is in how the per-symbol consumer list is derived from it.
Workaround used (during /titan-gauntlet audit)
Cross-checked exports-flagged dead types/interfaces against codegraph deps importedBy lists + manual grep for import type before treating anything as a genuine dead-code finding.
Summary
codegraph exports <f> -T --json(and the dead-export classification it feeds) reports zero-consumer / dead-export for interfaces and types that are demonstrably imported and used elsewhere viaimport type { X } from .... The underlying import graph (codegraph deps) correctly records the cross-file edge — the gap is specifically in howexports/dead-role attributes "consumers."Repro
Shows:
{ "name": "ChaContext", "kind": "interface", "line": 18, "consumers": [], "consumerCount": 0 }But:
Correctly shows
importedBy: [src/domain/graph/builder/stages/build-edges.ts, src/domain/graph/builder/stages/native-orchestrator.ts], and grepping those files confirmsimport type { ChaContext } from '../cha.js'followed by real usage as a type annotation (e.g.build-edges.ts:47,692,804,1470,native-orchestrator.ts:49,1148,1273).So the same underlying file-level import edge is correctly tracked by
deps, butexports's per-symbol consumer count doesn't creditimport type-only usages, producing a false "dead export" forChaContext.Same root cause reproduces on other type-only exports, e.g.
ExtractParametersOptions.typeMapinsrc/extractors/helpers.ts.Impact
Any interface/type that is only ever used as a type annotation (never constructed or called) — a very common and idiomatic TypeScript pattern — is misclassified as dead code by
codegraph roles --role dead/ flagged withconsumerCount: 0bycodegraph exports, even when actively relied upon across the codebase.Suggested fix
When computing per-symbol consumers for
exports, creditimport type { X }edges (and other type-position usages: type annotations, generic type arguments,extends/implementsclauses) as consumers, not just call/construct edges. The file-level import graph already has this data (as shown bycodegraph deps) — the gap is in how the per-symbol consumer list is derived from it.Workaround used (during /titan-gauntlet audit)
Cross-checked
exports-flagged dead types/interfaces againstcodegraph depsimportedBy lists + manual grep forimport typebefore treating anything as a genuine dead-code finding.