test(vetting): a golden reference table is const, and read with .at() - #424
Merged
Conversation
darkclad
force-pushed
the
main-ref-vals-const
branch
2 times, most recently
from
August 14, 2026 16:01
e217330 to
bdf80aa
Compare
added 2 commits
August 30, 2026 09:45
…th .at()
A reference table is read-only data, but 34 of the 102 the 6.3.1 rules inspect were
declared mutable, and 25 read sites reached them through operator[]:
static ref_vals_map<double> firstorder_2d_ibsi_ref_vals { ... };
ASSERT_TRUE(agrees_gt(total, firstorder_2d_ibsi_ref_vals[feature_name], 100.));
On a key the table does not hold, operator[] default-inserts 0 rather than failing, so
the assertion compares against a golden that was never written down -- and agrees_gt
derives its band from the golden, so a golden of 0 passes exactly when the computed
value is also 0. That is not an unreachable corner: "the feature was not computed and
returned 0" is one of the specific failures a golden table exists to catch, and in that
combination the test goes green against a reference that is not there. The inserted key
also persists for the rest of the run, so a later .count() guard on it succeeds too.
operator[] does not exist on a const map, so every site needing attention arrived as a
compile error rather than as a silent change in behaviour, which is what makes a sweep
this wide safe to do mechanically. A missing key now throws naming the key instead of
inventing a zero.
No existing assertion was wrong: every test passes and nothing threw out of .at(), so no
test in the tree was relying on a default-inserted key today. This closes the hole
prospectively.
ref_vals_list is a std::vector, whose operator[] reads rather than inserts, so the two
index sites in test_3d_morphology_mechanics.h are left as they are.
The const rule is only worth as much as its enforcement, so check_test_names.py now rejects a reference table declared mutable, alongside the raw-container, _common.h and cross-family-include rules. The self-test plants a table whose name, location and type all conform, leaving mutability as its only defect, and asserts the rule does not fire on a const table -- a rule that flags everything is as useless as one that flags nothing. SPEC 6.3.1 and test_ref_vals.h record the rule, why operator[] on a reference table is a correctness problem rather than a style one, and why a ref_vals_list index is outside it.
darkclad
force-pushed
the
main-ref-vals-const
branch
from
August 30, 2026 16:45
bdf80aa to
252752b
Compare
const, and read with .at()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
30 files, all under
tests/. Nosrc/nyxchange.Rebased onto current
mainand reworked against it: the branch was 158 commits behind, andtwo of its three commits had been overtaken in the meantime (see What the rebase absorbed
below). What is left is the part
mainstill does not have.Follow-up to #422, which gave every golden table one name, one location and one declaration
type. This adds the property those three could not express: the table is read-only data,
and saying so in the type closes a way for an assertion to pass against a golden that does
not exist.
The defect
Of the 102 tables the §6.3.1 rules inspect, 34 were declared without
const, and 25 readsites reached them through
operator[]:On a key the table does not hold,
operator[]default-inserts 0 rather than failing. Theassertion then compares against a golden that was never written down — and
agrees_gtderivesits band from the golden:
So a golden of 0 passes exactly when the computed value is also 0. That is not an unreachable
corner: "the feature was not computed and returned 0" is one of the specific failures a
golden table exists to catch, and in that combination the test goes green against a reference
that isn't there. The inserted key also persists for the rest of the run, so a later
.count()guard on the same key succeeds too.Same class the #422 review kept surfacing — an assertion that cannot fail on the thing it
claims to check — reached through the container's API instead of through naming or file
layout.
The change
conston the 34 remaining tables,.at()at the 25 read sites.operator[]does notexist on a
constmap, so every site needing attention arrived as a compile error, not asa silent change in behaviour — which is what makes a sweep this wide safe to do mechanically.
A missing key now throws naming the key instead of inventing a zero. The clean build is itself
the proof that the set is closed: had a read site been missed, it would not have compiled.
ref_vals_listis astd::vector, and a const vector'soperator[]reads rather thaninserts, so the two index sites in
test_3d_morphology_mechanics.hare left alone. SPEC andtest_ref_vals.hsay so rather than leaving the exception to be re-derived.Enforced.
check_test_names.pyrejects a reference table declared withoutconst, besidethe existing raw-container,
_common.hand cross-family-include rules. The self-test plants atable whose name, location and type all conform so that mutability is its only defect, and
asserts the rule does not fire on a
consttable — a rule that flags everything is asuseless as one that flags nothing. SPEC §6.3.1 and
test_ref_vals.hrecord the rule and whythis is a correctness problem rather than a style one.
What the rebase absorbed
Two of the three original commits are no longer needed, and are dropped rather than replayed:
test_2d_remaining_common.hcleanup.mainhas since folded that header into themorphology one (
baf6a6b6), so the file it cleaned up does not exist any more.test_2d_neighbor_analytic.handtest_2d_neighbor_cellprofiler.hnow guard the labelbefore reaching it, as
test_2d_neighbor_regression.halready did.Also worth noting: tables added to
mainin those 158 commits were writtenconstfrom thestart, which is why 34 rather than 53 were left to convert. This PR closes the remainder and
makes reopening it a build failure.
What this did and did not find
No existing assertion was wrong. Every test passes, and nothing threw from
.at(), so notest in the tree was relying on a default-inserted key today. The change closes the hole
prospectively; it did not uncover a live bad assertion.
Verification
TEST_2D_GABOR_GPU_RUNS_MECHANICSon a CPU-only build)-fsanitize=address,undefined -fno-sanitize-recover=undefined, Linux):gtest 878 passed / 1 skipped of 879 with 0 diagnostics, wrapper exit 0. The four-test
delta from Windows is the DICOM HU-loader mechanics tests, absent from a
NOEXTRAS=ONbuild.The instrumented
pytest tests/python/leg aborts attest_nyxus.py::TestNyxus::test_nonimq_wsi_scalabilityon a pre-existing UBSan finding onmain—src/nyx/features/glszm.cpp:426: signed integer overflow: 46341 * 46341 cannot be represented in type 'int', reached through the 2D whole-slide path. It cannot be attributableto this PR: the diff contains no
src/nyxfile and does not touchtest_nyxus.py, so theinstrumented module is built from bytes identical to
upstream/main. With that one testdeselected the leg runs clean: 87 passed / 1 skipped / 7 Arrow, 0 diagnostics.
pytest tests/python/: 88 passed / 1 skipped (7 pre-existing Arrow failures of a tiff-onlybuild)
check_test_names.py --checkandcheck_coverage.py --checkclean; 102 tables inspected,0 raw, 0 non-const, 0 in a
_common.h; vetting self-tests 10/10 with the new casetests/— nosrc/nyxchangegit diff --shortstatand--ignore-all-space --shortstatagree, so nowhitespace-only churn
Commits
test(vetting): make every golden reference table const and read it with .at()test(vetting): reject a golden reference table declared without constNot in this PR
The
constexprform asked for in #422 review.std::unordered_mapwithstd::stringkeysallocates, so the compile-time shape is
constexpr std::array<std::pair<std::string_view, double>, N>with aconstexpraccessor. The payoff usually claimed for it — a mistyped keycaught at build time — is not available while keys arrive as runtime
std::stringparametersinto the shared
assert_*helpers, and after this PR it changes no behaviour. Recorded asoptional follow-up rather than dropped.