Summary
Checker::is_string for PHP lists String2 (id 25), which is the string
type keyword, not a string literal. So bca find string reports a hit on
every PHP file carrying a string type annotation.
Evidence
The same distinction is already drawn correctly one predicate over:
php_bool_terminal_kinds! (big-code-analysis-ast/src/macros/kind_sets.rs)
deliberately excludes Float2 (id 52) with a comment saying it is the
float type keyword rather than a literal. String2 is the same shape and
is included in is_string.
Why it is its own issue
This is Checker::is_string, not a metric terminal set — a different
predicate with different consumers (bca find, bca count). Nothing in the
ABC/Halstead path is affected, which is why the 2026-09-14 batch left it
alone rather than widening a metric fix into a classifier change.
It is nonetheless the .claude/rules/grammar-dispatch.md §7 case: sibling
predicates classifying the same node differently drift silently, and each
reads as internally consistent from its own side.
Before fixing
- Confirm with
bca dump which id a string type annotation versus a string
literal actually carries at the pinned grammar, and enumerate every
numeric-suffix alias of both (§1).
- Cross-walk the §7 pairs named in the rule:
is_string ↔ get_op_type
string classification, and check whether Halstead currently agrees or
disagrees with is_string here.
- Check the sibling languages in the same group — Java, C#, Kotlin and Groovy
all have type keywords that could be spelled as a literal-looking kind.
Related
Resolution
Status: Fixed (pending merge)
Commit: c755fafa on branch fix/issue-1474
Root cause: PhpCode::is_string listed Php::String2 (kind_id 25),
the string type keyword — a node the grammar emits only as the sole
child of a primitive_type wrapper. bca find -t string / bca count string reach that predicate through is_string_with_code, so every PHP
type annotation was reported as a string literal. #288's two
justifications for the arm had both been retired already: #1293 moved
String2 into get_op_type's primitive_type-suppression arm, and
#1261 removed the identical keyword aliases from TypeScript and TSX.
PHP was the only language affected — Java, C#, Kotlin and Groovy spell
their string types as type_identifier / predefined_type and list
none of them, and the JS-family String2 aliases are literals. Measured
corpus impact: php/strings.php 24 → 12 hits, php/classes.php
27 → 8 (earlier triage in this thread estimated 24 → 8, which was
wrong).
Summary
Checker::is_stringfor PHP listsString2(id 25), which is thestringtype keyword, not a string literal. So
bca find stringreports a hit onevery PHP file carrying a string type annotation.
Evidence
The same distinction is already drawn correctly one predicate over:
php_bool_terminal_kinds!(big-code-analysis-ast/src/macros/kind_sets.rs)deliberately excludes
Float2(id 52) with a comment saying it is thefloattype keyword rather than a literal.String2is the same shape andis included in
is_string.Why it is its own issue
This is
Checker::is_string, not a metric terminal set — a differentpredicate with different consumers (
bca find,bca count). Nothing in theABC/Halstead path is affected, which is why the 2026-09-14 batch left it
alone rather than widening a metric fix into a classifier change.
It is nonetheless the
.claude/rules/grammar-dispatch.md§7 case: siblingpredicates classifying the same node differently drift silently, and each
reads as internally consistent from its own side.
Before fixing
bca dumpwhich id astringtype annotation versus a stringliteral actually carries at the pinned grammar, and enumerate every
numeric-suffix alias of both (§1).
is_string↔get_op_typestring classification, and check whether Halstead currently agrees or
disagrees with
is_stringhere.all have type keywords that could be spelled as a literal-looking kind.
Related
Float2exclusion rationale is recorded.Resolution
Status: Fixed (pending merge)
Commit:
c755fafaon branchfix/issue-1474Root cause:
PhpCode::is_stringlistedPhp::String2(kind_id 25),the
stringtype keyword — a node the grammar emits only as the solechild of a
primitive_typewrapper.bca find -t string/bca count stringreach that predicate throughis_string_with_code, so every PHPtype annotation was reported as a string literal. #288's two
justifications for the arm had both been retired already: #1293 moved
String2intoget_op_type'sprimitive_type-suppression arm, and#1261 removed the identical keyword aliases from TypeScript and TSX.
PHP was the only language affected — Java, C#, Kotlin and Groovy spell
their string types as
type_identifier/predefined_typeand listnone of them, and the JS-family
String2aliases are literals. Measuredcorpus impact:
php/strings.php24 → 12 hits,php/classes.php27 → 8 (earlier triage in this thread estimated 24 → 8, which was
wrong).