Skip to content

fix(assertion-eval): count() comparisons evaluate correctly (v0.9.x bug closeout)#218

Open
avrabe wants to merge 1 commit into
mainfrom
fix/v0.9.x-assertion-count-comparison
Open

fix(assertion-eval): count() comparisons evaluate correctly (v0.9.x bug closeout)#218
avrabe wants to merge 1 commit into
mainfrom
fix/v0.9.x-assertion-count-comparison

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented May 13, 2026

Summary

The assertion DSL silently rejected pipelines ending in .count() <op> n (>=, >, <=, <, ==, !=) because the lexer had no tokens for the comparison operators or integer literals, and the parser had no production combining them with a pipeline. Users couldn't express cardinality constraints in [[assertion]] blocks.

MWE

[[assertion]]
id = "ASSERT-MIN-THREADS"
check = "components.where(category == 'thread').count() >= 2"
severity = "error"

Pre-fix: parse error. Post-fix: evaluates to Value::Bool.

What changed

  • Lexer — 6 new tokens: NEQ, GE, GT, LE, LT, INT_LIT.
  • Syntax — 6 comparison-op kinds + COUNT_COMPARE_EXPR node.
  • Parser — lookahead wraps a pipeline followed by <op> <int> in a COUNT_COMPARE_EXPR at the ROOT level.
  • Evaleval_count_compare unwraps Value::{Count, Components, Features, Diagnostics} into a usize and returns Value::Bool.

Test plan

  • 7 new unit tests in crates/spar-cli/src/assertion/mod.rs (eval_count_ge_true / _false, _gt, _le, _lt, _eq, _neq) — all pass
  • cargo clippy -p spar -- -D warnings clean
  • Existing eval_count test still passes (unchanged behavior)

Part of v0.9.x bug closeout series (#214 nested binding, #216 classifier_match, #217 has-features).

Co-Authored-By: Claude Opus 4.7 noreply@anthropic.com

…ug closeout)

The assertion DSL silently rejected pipelines ending in `.count() <op> n`
(`>=`, `>`, `<=`, `<`, `==`, `!=`) because the lexer had no tokens for
the comparison operators or integer literals, and the parser had no
production that combined them with a pipeline.

Extends the assertion grammar with:
- Lexer: NEQ, GE, GT, LE, LT, INT_LIT tokens.
- Syntax: 6 new comparison-op kinds + COUNT_COMPARE_EXPR node.
- Parser: lookahead wraps a pipeline followed by `<op> <int>` in a
  COUNT_COMPARE_EXPR at the ROOT level.
- Eval: eval_count_compare unwraps Value::Count / Components / Features
  / Diagnostics into a usize and returns Value::Bool.

7 new tests cover all 6 comparison operators against a 2-thread fixture.

Closes the v0.9.x bug where \`components.where(...).count() >= n\` was
unusable in [[assertion]] blocks.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant