Fixes #33231: [DQ Threshold W2.4] Build row-level violation counts for columnValuesToBeBetween / LengthsToBeBetween - #33911
Conversation
…two between tests `columnValuesToBeBetween` and `columnValueLengthsToBeBetween` decided pass/fail from MIN/MAX aggregates, which cannot answer "how many rows are out of range" -- the one number a row tolerance is checked against. Both test definitions already declare the threshold as "number of failures tolerated ... or a share of the evaluated rows", so the verdict now comes from counting those rows. `BetweenBoundsChecker` already had both halves of the counting, used by the dimensional queries: `build_row_level_violations_sqa()` and `get_violations_mask()`. They are now wired into the overall result too, through a new `_run_violation_count()` on each engine -- one aggregate query for SQA, one vectorized pass per dataframe for pandas -- so the two count the same rows: a NULL is not a violation and an unset bound excludes nothing. The counting only runs when a tolerance is actually configured. With none, one value outside the window and a MIN/MAX outside it are the same verdict, so the result is bit for bit what it was and no extra query is paid for. Since the tolerance is now spent on rows, these two no longer widen their bounds with it: the window is evaluated exactly as configured, and a threshold applied to both the window and the rows would be applied twice. Bounds are still resolved through `get_min_bound`/`get_max_bound`, so dynamic assertion keeps working, and `run_validation()` is untouched. MIN/MAX stay in `testResultValue` -- users read them. When a tolerance decided the verdict the result message leads with the count it was checked against and keeps the window and the extremes as context, and the counts are reported as passed/failed rows since they are already computed. Two fixes the counting needed: an infinite-bound check that only asks `math.isinf` of a float, so a datetime window does not raise, and a COALESCE around the SUM, so an empty table counts zero violations rather than NULL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…unded The between validators counted their violations and then, with computePassedFailedRowCount set, counted again through compute_row_count to fill passedRows/failedRows. The second scan reads the table again -- or, on a percentage sample, a different set of rows -- so the reported rows could contradict the status the first count decided. Both now report the counts the verdict was taken on and only fall back to compute_row_count when no violation count was taken at all. BetweenBoundsChecker also read only ∓inf as an unset bound, so a validator that resolves its bounds dynamically and finds none on one side would compare against None: junk SQL on the SQL half, a TypeError on the pandas one. Both halves now build a condition only for the sides the window actually sets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
✅ Playwright Results — workflow succeededValidated commit ✅ 614 passed · ❌ 0 failed · 🟡 1 flaky · ⏭️ 0 skipped · 🧰 0 lifecycle flaky PerformanceBlocking targets: ✅ met · Optimization targets: 🟡 in progress Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting. 🕒 Full workflow signal wall (to summary) 55m 14s ⏱️ Max setup 5m 3s · max shard execution 15m 37s · max shard-job elapsed before upload 21m 24s · reporting 5s 🌐 239.36 requests/attempt · 2.22 app boots/UI scenario · 12.66% common-shard skew Optimization targets still in progress:
🟡 1 flaky test(s) (passed on retry)
How to debug locally# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip # view trace |
Keep the base signature on the _run_violation_count overrides, narrow the runner to QueryRunner, type the checker's count as a ColumnElement so it can be labelled, and fail loudly on an empty result row. Pin that an explicit zero threshold does not pay for the count query.
#34056 moved Login.spec.ts and LoginConfiguration.spec.ts from e2e/Pages to e2e/Auth without updating impact-map.json. Every targeted plan picks the smoke entry up, so the planner fails on a selector whose spec no longer exists. Auth/** is delegated to the SSO lane, so the moved paths are dropped from the main lanes instead of failing the plan.
Code Review ✅ Approved🟡 Medium risk · Adds row-count-based tolerance verdicts to two data quality validators. Adds row-level violation counting for OptionsDisplay: compact → Counting what did not apply, without listing it. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
|



What olivaw checked (machine-observed, §8.2/A.1)
4399f56ef732ca7e92381a50626fe319165292142fcf6e26324cc4f09e52073cffb79b0c2f5cb9ffNo build or test command is configured for this workspace, so only the diff's existence was checked. Set
run_config.build_cmd/test_cmdto have olivaw verify its own work.What the agent says it did (unverified)
The PR appears safe to merge, with no outstanding correctness or repository-rule violations identified.
Summary
This PR adds row-level violation counting for the value and value-length “between” validators when a failure threshold is configured.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR Input[Column values] --> Metrics[Compute MIN/MAX] Input --> Count{Threshold configured?} Count -->|No| Extremes[Evaluate MIN/MAX against bounds] Count -->|Yes| Violations[Count total and out-of-range rows] Violations --> Threshold[Apply absolute or percentage threshold] Extremes --> Result[Test result] Threshold --> Result Violations --> Reporting[Populate passed and failed rows]Reviews (2) · Last reviewed commit: "Review: report the counted violations, a..."