Problem
Normalization strips identifiers and compares structure, so a PropertySignature-heavy interface body can reach the Jaccard threshold against a structurally similar but categorically different declaration (e.g. a class with mostly property declarations, or an object literal). These cross-category matches are rarely actionable — you cannot refactor an interface and a class into shared code the way you can two functions.
Proposed change
Optional, off-by-default constraint that two candidates only pair when their top-level candidate kind (or a coarse declaration category) matches:
- Entry already records nothing about kind today (
Entry in src/FileScanner.ts). Add the candidate root SyntaxKind (or a derived category: type-like / value-like / callable) to Entry.
- New option
--same-kind (or --same-category), parsed in src/Options.ts, gating pairs in matchingPairs (src/TypeScriptDuplicateFinder.ts) before the similarity test.
Decide the granularity: exact SyntaxKind is strict (ArrowFunction vs FunctionDeclaration would not match); a category map is more forgiving. Recommend a small category map with the exact-kind mode as a stricter opt-in.
Acceptance
- With the constraint on, an interface no longer clusters with a class of similar shape.
- Two functions (one arrow, one declaration) still cluster under category mode.
- Flag off -> behavior unchanged.
Related
False-positive-reduction set (#19-#24); codex-surfaced. Orthogonal to kind exclusion (#19, removes kinds entirely) and the diversity floor (#20).
Problem
Normalization strips identifiers and compares structure, so a
PropertySignature-heavy interface body can reach the Jaccard threshold against a structurally similar but categorically different declaration (e.g. a class with mostly property declarations, or an object literal). These cross-category matches are rarely actionable — you cannot refactor an interface and a class into shared code the way you can two functions.Proposed change
Optional, off-by-default constraint that two candidates only pair when their top-level candidate kind (or a coarse declaration category) matches:
Entryinsrc/FileScanner.ts). Add the candidate rootSyntaxKind(or a derived category: type-like / value-like / callable) toEntry.--same-kind(or--same-category), parsed insrc/Options.ts, gating pairs inmatchingPairs(src/TypeScriptDuplicateFinder.ts) before the similarity test.Decide the granularity: exact
SyntaxKindis strict (ArrowFunction vs FunctionDeclaration would not match); a category map is more forgiving. Recommend a small category map with the exact-kind mode as a stricter opt-in.Acceptance
Related
False-positive-reduction set (#19-#24); codex-surfaced. Orthogonal to kind exclusion (#19, removes kinds entirely) and the diversity floor (#20).