Problem
--min-nodes filters by raw node count, but a large candidate can still be near-uniform boilerplate. An interface body is mostly PropertySignature + type keyword/reference repeated; a config object is mostly PropertyAssignment. These clear the node-count bar yet carry little structural information, so they reach the Jaccard threshold against any similarly-shaped block and produce low-actionability clusters.
Proposed change
Add a kind-diversity floor alongside the existing minNodes/minLines gate.
NormalizedNode already walks tags and tracks count. Compute, per candidate, either the count of distinct node tags or the Shannon entropy of the tag distribution over the subtree.
- Expose it where entries are built in
src/FileScanner.ts (scanFile, around the candidateRootKinds.has(...) && hashes.length - rangeStart >= minNodes check, ~L62), and drop candidates below the floor.
- Add
--min-distinct-kinds <n> (or --min-kind-entropy <x>), parsed in Options.parse, defaulting to off so current behavior is preserved unless opted in.
Acceptance
- A 30-member interface no longer clusters with an unrelated 30-member interface once the floor is set.
- A 25-node function with varied control flow still qualifies.
Related
Complements the candidate-kind exclusion issue — that removes whole kinds, this filters uniform instances of kinds you still want to scan.
Problem
--min-nodesfilters by raw node count, but a large candidate can still be near-uniform boilerplate. An interface body is mostlyPropertySignature+ type keyword/reference repeated; a config object is mostlyPropertyAssignment. These clear the node-count bar yet carry little structural information, so they reach the Jaccard threshold against any similarly-shaped block and produce low-actionability clusters.Proposed change
Add a kind-diversity floor alongside the existing
minNodes/minLinesgate.NormalizedNodealready walks tags and trackscount. Compute, per candidate, either the count of distinct node tags or the Shannon entropy of the tag distribution over the subtree.src/FileScanner.ts(scanFile, around thecandidateRootKinds.has(...) && hashes.length - rangeStart >= minNodescheck, ~L62), and drop candidates below the floor.--min-distinct-kinds <n>(or--min-kind-entropy <x>), parsed inOptions.parse, defaulting to off so current behavior is preserved unless opted in.Acceptance
Related
Complements the candidate-kind exclusion issue — that removes whole kinds, this filters uniform instances of kinds you still want to scan.