Summary
Found sweeping siblings for #1359 (grammar-dispatch §7). The
terminal-bool operand sets that ABC's unary-conditional walker consults
(src/macros/kind_sets.rs, Fitzpatrick Rule 9, #557) name Integer for
Ruby and Elixir but not the other numeric literal kinds those grammars
emit. A float or a suffixed numeric used as a bare && / || operand
scores one condition instead of two.
Python's set already names both Float and Integer, so the three
truthy-value languages disagree with each other for no reason anyone
recorded.
Reproduction
$ cat a.rb
def f
a && 1
end
$ bca metrics --no-config -p a.rb # abc.conditions: 2 (correct)
$ cat b.rb
def f
a && 1.0
end
$ bca metrics --no-config -p b.rb # abc.conditions: 1 (wrong)
a && 1r and a && 2i report 1 for the same reason. Elixir:
$ printf 'def f(a) do\n a && 1\nend\n' # abc.conditions: 2
$ printf 'def f(a) do\n a && 1.0\nend\n' # abc.conditions: 1
Python is the control and is already right:
$ printf 'def f(a):\n return a and 1.0\n' # abc.conditions: 2
Why the count drops rather than errors
src/metrics/abc/ruby.rs:111,134 requires the operand's kind to be in
ruby_bool_terminal_kinds!() and its parent list kind to be a
Binary*. A float / rational / complex operand is not in the set,
so the walker recurses one level, and the recursion then fails the
list-kind gate. Nothing warns; the condition is simply not counted.
Fix shape
src/macros/kind_sets.rs:
Then re-derive the comment above each macro, which currently enumerates
the operand kinds as a closed list and so is part of the contract.
Sweep
The remaining seventeen sets were checked. Lua, Tcl, iRules and the four
JS-family sets name a single Number kind that covers both integers and
floats, so they have no gap. C#, Java, Groovy, Rust, Go, C++, PHP,
Kotlin and Perl name no numeric literal at all — plausibly deliberate,
since a bare numeric is not a boolean operand in most of them, but no
comment says so and Perl at least is a truthy-value language. Worth
confirming Perl separately rather than assuming.
Tests
Per-language abc.conditions assertions for a float operand, plus the
Ruby suffixed forms. abc.conditions == cyclomatic() - 1 per space is
the cross-check .claude/rules/grammar-dispatch.md §8 asks for.
Summary
Found sweeping siblings for #1359 (grammar-dispatch §7). The
terminal-bool operand sets that ABC's unary-conditional walker consults
(
src/macros/kind_sets.rs, Fitzpatrick Rule 9, #557) nameIntegerforRuby and Elixir but not the other numeric literal kinds those grammars
emit. A float or a suffixed numeric used as a bare
&&/||operandscores one condition instead of two.
Python's set already names both
FloatandInteger, so the threetruthy-value languages disagree with each other for no reason anyone
recorded.
Reproduction
a && 1randa && 2ireport 1 for the same reason. Elixir:Python is the control and is already right:
$ printf 'def f(a):\n return a and 1.0\n' # abc.conditions: 2Why the count drops rather than errors
src/metrics/abc/ruby.rs:111,134requires the operand's kind to be inruby_bool_terminal_kinds!()and its parent list kind to be aBinary*. Afloat/rational/complexoperand is not in the set,so the walker recurses one level, and the recursion then fails the
list-kind gate. Nothing warns; the condition is simply not counted.
Fix shape
src/macros/kind_sets.rs:ruby_bool_terminal_kinds!— addFloat,Complex,Rational.All three are valid truthy operands and all three parse to their own
named kind (
complexandrationalare wrappers over the numeral;see fix(getter/ruby): complex and rational literals double-count their inner numeral #1359). Only the outermost node should be listed, or the operand
is reached twice.
elixir_bool_terminal_kinds!— addFloat.Then re-derive the comment above each macro, which currently enumerates
the operand kinds as a closed list and so is part of the contract.
Sweep
The remaining seventeen sets were checked. Lua, Tcl, iRules and the four
JS-family sets name a single
Numberkind that covers both integers andfloats, so they have no gap. C#, Java, Groovy, Rust, Go, C++, PHP,
Kotlin and Perl name no numeric literal at all — plausibly deliberate,
since a bare numeric is not a boolean operand in most of them, but no
comment says so and Perl at least is a truthy-value language. Worth
confirming Perl separately rather than assuming.
Tests
Per-language
abc.conditionsassertions for a float operand, plus theRuby suffixed forms.
abc.conditions == cyclomatic() - 1per space isthe cross-check
.claude/rules/grammar-dispatch.md§8 asks for.