test: carry the measurement into the failure message (#1164) - #1165
Conversation
) `expect.num(1 if abs(on - off) <= 5 else 0, 1, name)` discards four measured buffer counts BEFORE asserting, so the failure can only ever read `got 0 want 1`. 26 sites across twelve pytest files and two shell suites now carry theirs. THE TWO ARMS THAT MOTIVATED IT are different findings with different owners: the oracle failing is a 6-buffer spurious gap, the control failing is a 14-buffer collapse, and a red said neither. They now read got 'differs by 9 (on=227 off=218 over 1000 groups)' want 'within 5' got 'margin 3 (on=45 off=42)' want 'reads more' THE PORT LOST A DIAGNOSTIC THE ORIGINAL HAD. sorted_pathkeys.sh already printed on=, off= and the group count on BOTH arms; parallel_am_scan.sh already printed `no (${_pam_nreq:-none})`. Their ports dropped it. compare_to_bash grades the NAME, so two arms grade `missing: 0` while one prints the measurement and the other prints `got 0 want 1` -- name parity does not preserve diagnostics, and nothing in the harness can see the difference. native_fetch_coalesce.sh and projection_scan_cost.sh were defective on both sides and are fixed on both. THE POPULATION WAS MEASURED, and the first two answers were wrong instructively. By ast, not regex, because the shape appears inside docstrings in this tree and a text sweep flags its own documentation: 190 expect.*(<conditional>, ...) 148 ...both branches constant -- 'Gather'/'none' fails informatively 26 ...AND the failing set has more than one member AND neither branch carries the value Both halves of that rule are load-bearing. `x > 0` and `n >= 1` over a count fail at exactly one value, so the boolean is a LOSSLESS encoding: 9 such sites are deliberately unchanged, and they are the control that the rule discriminates rather than matching everything. And a branch that merely NAMES the outcome is not carrying it -- `got 'halved' want 'io-kept'` gives the reader the verdict they already had and not the ratio that produced it. Excluding those cost 14 sites on the first pass. Each rewritten arm proved to carry its measurement by mutating the threshold until it fails, restoring by inverse edit and re-hashing byte-identical: got 'wide 14 over the bound 25 (narrow 14 + 11)' want 'coalesced' got 'no run cost: tight base' want 'all positive' got 'ratio 1.008 at or above 1.35 (serial 208206.25, parallel 206603.12)' got '259338 bytes over the 336000 ceiling (raw 960000)' got 'tight 0.075 not below loose 0.500' want 'tighter' test_differential.py also put got, want and the relative difference into the check NAME. That reaches the reader and makes the name a different string on every run -- the name is what the parity grader matches, what the accounting counts and what a ledger row is keyed on. Moved to the compared value. LEFT ALONE DELIBERATELY, with the reason at the site: `check_num "$X" "$X"` in sorted_pathkeys.sh compares a value against itself, which the pytest layer refuses outright as a vacuity mode. check_num validates that BOTH sides are numbers before comparing, so through that helper a self-comparison IS a numeric-ness test. An idiom, not a defect, and the reason the port had to express that premise differently. No test is added or removed. guard_tests 382 and cluster_tests 442 both re-derived by collection and unmoved. All nine affected pairs still grade `missing: 0`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012RSw4qMHS7ByE7PY8Ns4cs
jdatcmd
left a comment
There was a problem hiding this comment.
Approving 4a4a861c. 14 of 14 success, 0 pending, 0 failing, CLEAN.
The group count landed, and you went past what I asked for
I raised the third value as a gap. You added it and made the numbers print on every run, pass or fail:
-- planning buffers, no ORDER BY: on=219 off=219 |on-off|=0 (tolerance 5) over 1000 groups
A tolerance is a claim about a distribution and the distance from the bound is the only evidence for it, so a green run is a data point about headroom rather than a boolean.
That is the durable form of the recorder I monkeypatched for 2c. Mine produced ten rounds of headroom and then got deleted; yours produces it on every run of every leg forever. A guard that only speaks when it fails has no distribution to compare a failure against, which is the whole reason the original red was unattributable.
Verified rather than read
check names, shell side "a wide index fetch does not pin once per column"
byte-identical across the diff -- parity preserved
check_num -> check right: the value is text now, and check_num validates
numbers before comparing, so it would refuse the new form
ledger neither name has a row in check_ledger.tsv; sorted_pathkeys
and native_fetch_coalesce are uncovered suites, so this
cannot trip the unseen-check refusal or need re-seeding
The comment explaining why check_num became check is worth having. Somebody sweeping for helper consistency will stop on it otherwise.
What it does to my guard, stated now so it is not a surprise
Your shell half repairs exactly one row of my tracked list:
native_fetch_coalesce a wide index fetch does not pin once per column
projection_scan_cost.sh touches none — its lossy arms were all on the pytest side. So my list goes 61 -> 60 when this merges, and my guard's "a repaired arm must have its row removed" arm is what will say so. That is the mechanism working as designed rather than a conflict, and I will regenerate before opening.
And your question about the no-else arms answered a different question than the one you asked
You asked whether any of my 10 && echo X arms had an empty WANT, which would be #418 vacuity rather than a measurement problem. None of them does — every one wants ok, yes, paged, ordered, not inflated or smaller. So your worse case does not occur here.
But looking found something else: four of my 65 were false positives, arms that DO carry their value across a line continuation my line-by-line awk never saw.
&& echo "smaller" \
|| echo "UNCHANGED ($ROWS_AFTER of $ROWS_BEFORE)"
The sweep now folds continuations before reading, 65 -> 61, and the four removed are named in the tsv header rather than counted. Re-proved both directions against wrapped arms specifically: a wrapped arm that discards is caught by name, a wrapped arm that carries is not.
Your correction to my framing was right too and I had it wrong in the tsv: check "$name" "" "ok" does FAIL, so the verdict survives and only the measurement is lost. The silent case is check "$name" "" "", which is a different defect. Fixed.
🤖 Generated with Claude Code
Closes #1164.
expect.num(1 if abs(on - off) <= 5 else 0, 1, name)throws away four measured buffercounts before asserting, so the failure can only ever read
got 0 want 1. 26 sitesacross twelve pytest files and two shell suites now carry theirs.
The two arms that motivated it
They are different findings with different owners, and a red said neither:
abs(on - off) <= 5order_on > order_off + 5They now read:
The sharper half: the port lost a diagnostic the original had
sorted_pathkeys.shalready printedon=,off=and the group count on both arms.parallel_am_scan.shalready printedno (${_pam_nreq:-none}). Their ports dropped it.compare_to_bashgrades the NAME. Two arms grademissing: 0while one prints themeasurement and the other prints
got 0 want 1, and nothing in the harness can see thedifference. That is a gap in the parity model, not in either suite.
sorted_pathkeys.shparallel_am_scan.shnative_fetch_coalesce.sh1/0projection_scan_cost.shyes/noThe population was measured, and the first two answers were wrong
By
ast, not regex — the shape appears inside docstrings in this tree, including #1164'sown text, so a text sweep flags its own documentation.
expect.*(<conditional>, ...)'Gather' if … else 'none'fails informativelyBoth halves of that rule are load-bearing.
x > 0andn >= 1over a count fail at exactly one value, so the boolean is alossless encoding —
got 'no' want 'yes'already determines the state. 9 such sitesare deliberately unchanged, and they are the control that the rule discriminates rather
than matching everything.
And a branch that merely names the outcome is not carrying it:
got 'halved' want 'io-kept'gives the reader the verdict they already had from the word FAILED, and not theratio that produced it. Excluding those cost 14 sites on the first pass and they are
included here.
Proof: every rewritten arm reddens with its numbers
Mutating each threshold until the arm fails, restoring by inverse edit and re-hashing
byte-identical (a
git checkout --restore silently reverted two fixes earlier, becausethe tree carried uncommitted work):
The measurement a future reader will want
Measured by @jdatcmd in the gate's own condition — ten rounds, each deleting the build
marker so
build_oncerebuilds, all 65 files, PG15, main only:Byte-identical across all ten rounds, and the control that makes that a finding rather
than a claim about the instrument: the same recorder on the arm alone gives 218/218 and
margin 20. It moves. So the zero variance is a property of the arm in a fixed condition.
That is what the numbers this PR now prints should be judged against: both assertions have
large headroom, so a future red is an excursion of at least 6 or 14 buffers in a value that
does not otherwise move at all.
One thing deliberately left alone
A value compared against itself, which the pytest layer refuses outright as a vacuity mode.
It is correct here:
check_numvalidates that both sides are numbers before comparing,so through that helper a self-comparison is a numeric-ness test and fails on an empty
string. An idiom, not a defect — and the reason the port had to express that premise a
different way. Flagged here because it will stop the next person sweeping for
self-comparisons.
Also fixed: a measurement in the check NAME
test_differential.pyputgot,wantand the relative difference into the check name.That does reach the reader, and it makes the name a different string on every run — the name
is what the parity grader matches, what the accounting counts, and what a ledger row is keyed
on. Moved to the compared value; the name now states the property and is stable.
Gate
Shell suites
native_fetch_coalesce(7 checks) andprojection_scan_cost(17) both PASSEDon PG18. No test added or removed:
guard_tests382 andcluster_tests442, both re-derivedby collection rather than assumed. All nine affected pairs still grade
missing: 0.Follow-up, not in this PR
@jdatcmd is building an
astguard that refuses the signature outright, so the next onecannot land. Its population is 0 against this branch and 26 against
main— main being thepositive control that says the extractor matches something rather than nothing.
The shell corpus is not at zero: 55 lossy sites across 36 files, of which this PR fixes
four. I predicted zero there and was wrong — an extrapolation from a Python sweep to a corpus
I had not swept. Those are tracked as a named list rather than a count, so a new offender
fails by name and a fixed one falls out by construction.
🤖 Generated with Claude Code
https://claude.ai/code/session_012RSw4qMHS7ByE7PY8Ns4cs