test: registerRefImMeta is exercised against the function the database has - #53
Merged
Merged
Conversation
…e has
THE GAP. `rapid_db.register_refimmeta` sends twenty-four values
positionally into a stored function declared by rapid_systems migration
128. The stub tier asserts the argument order against the METHOD'S OWN
SIGNATURE — which proves the call is self-consistent, not that it matches
the function the database has. Nothing in this repository contains that
function, so nothing outside the contract tier could.
That distinction is not hypothetical. `products.py` records the same
class of defect reaching production: `refimcatalogs.cattype` is a
smallint, the registrar sent the strings "sextractor"/"photutils",
PostgreSQL refused every reference-image registration at its first
catalogue, and the unit suite stayed green because its fake database
accepts whatever it is handed. A twenty-four argument positional call is
that shape with more places to be wrong.
Five tests: every argument lands in the column it was meant for, a second
registration updates rather than inserting, metadata for an unregistered
reference image is refused, a NULL measurement is refused by the column,
and a refused call leaves the transaction aborted.
EVERY VALUE IS DISTINCT, and that is load-bearing rather than cosmetic:
two columns sharing a value would make a swap between them invisible,
which is exactly what an argument-order test exists to catch. The `real`
columns take binary32-exact values (.25/.5/.75) so the round-trip
comparison is exact and this suite never fails on float formatting.
THE FIFTH TEST IS A FINDING, not a restatement. Writing these surfaced
that `register_refimmeta` reports failure through `exit_code` but leaves
the transaction ABORTED — the next statement on that connection raises
InFailedSqlTransaction whatever it is. The registration path is safe from
this only because `products._check` raises immediately after each call;
a caller that "handled" exit_code 67 by carrying on would meet a wall of
unrelated-looking errors. Asserted so the constraint is stated rather
than rediscovered. The tests that expect a refusal take a SAVEPOINT for
the same reason.
`fixture.make_refimage` is new and deliberately lighter than
`_diffimage_parents`: `refimages` has no FK to `exposures` or `l2files`,
so a caller needing only a reference image should not mint both to get
one. `fid` is read from the seeded `filters`, and `version` is max+1
because `refimagespk` is UNIQUE on (field, fid, ppid, version).
PROVEN TO BE ABLE TO FAIL, not merely observed passing. Two mutations of
the wrapper, each reverted:
- swapping `nsxcatsources`/`npucatsources` (same type, so only the
value check can catch it) -> "nsxcatsources expected 1234 got 1100;
npucatsources expected 1100 got 1234"
- casting eight real parameters as integer -> "clmean expected 1.25 got
1.0; ... cov5percent expected 87.25 got 87.0"
Contract tier: 744 passed, 15 skipped, against a PostgreSQL 18 + Q3C
built from rapid_systems main (e1896658). Stub tier: 2677 PASS.
RussLaher
added a commit
that referenced
this pull request
Sep 15, 2026
…egistration against the real functions The residual gap named on #53. #53 proved the register_refimmeta WRAPPER matches the function migration 128 declares; the stub tier proved the registrar assembles its arguments from the provenance keys REFIMMETA_MEASUREMENTS names. Neither covered the join — that a value a reference-image stage recorded arrives in the column it was meant for, through four stored functions, on one transaction. addRefImage, updateRefImage, registerRefImCatalog and registerRefImMeta all run here, so this covers the family rather than only the newest member: it is the test that would have caught the cattype defect products.py records. Two things the file found about itself, both recorded rather than quietly fixed: * attempt_id is a BIGINT. The first version passed a readable string and PostgreSQL refused it — addRefImage casts that argument to bigint. The stub tier's fake takes whatever it is given, so this would have surfaced on the first live registration. * The first mapping test COULD NOT FAIL: it read the expected values and the mapping from the same table in products.py, so swapping gmin/gmax there passed green. Found by mutation-testing the file, not by review. EXPECTED_MEASUREMENTS is now stated independently, with a separate test keeping the two honest in the other direction. Four mutations, each caught by name and each reverted: swapped mapping, collapsed cattypes, no refimmeta write, a pair dropped from the table. Contract tier 750 passed / 15 skipped against rapid_systems e1896658 -- 744 before this file, so the six demonstrably ran. Stub tier 2677 PASS. One new file; no production code changed.
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.
The gap this closes
rapid_db.register_refimmetasends twenty-four values positionally into astored function declared by rapid_systems migration 128. The stub tier asserts
the argument order against the method's own signature — which proves the call
is self-consistent, not that it matches the function the database actually
has. Nothing in this repository contains that function, so nothing outside the
contract tier could.
That distinction is not hypothetical here.
products.pyrecords the same classof defect reaching production:
refimcatalogs.cattypeis asmallint, theregistrar sent the strings
"sextractor"/"photutils", PostgreSQL refusedevery reference-image registration at its first catalogue, and the unit suite
stayed green throughout because its fake database accepts whatever it is
handed. A twenty-four argument positional call is that shape with more places
to be wrong.
This is the follow-up named in
Caltech-IPAC/rapid#51's merge commit as theone thing that change left unverified end-to-end.
What it asserts
Five tests in
pipeline/contract/test_refimmeta_registration.py:exit_code67, which is whatproducts._checkturns intoRegistrationFailed.Every value is distinct, and that is load-bearing. Two columns sharing a
value would make a swap between them invisible, which is exactly what an
argument-order test exists to catch. The
realcolumns take binary32-exactvalues (
.25/.5/.75) so the round-trip comparison is exact and this suitenever fails on float formatting.
Test 5 is a finding, not a restatement
Writing these surfaced that
register_refimmetareports failure throughexit_codebut leaves the transaction aborted — the next statement on thatconnection raises
InFailedSqlTransactionwhatever it is.The registration path is safe from this only because
products._checkraisesimmediately after every call and the consumer's error path rolls back. A future
caller that "handled"
exit_code67 by carrying on would meet a wall oferrors naming nothing to do with reference images. It is asserted here so the
constraint is stated rather than rediscovered, and the tests that expect a
refusal take a
SAVEPOINTfor the same reason.Proven able to fail
A test observed only passing proves nothing, so both were mutation-checked
against the wrapper, each mutation reverted:
nsxcatsources/npucatsources(same type — only the value check can catch it)nsxcatsources expected 1234 got 1100; npucatsources expected 1100 got 1234realparameters asintegerclmean expected 1.25 got 1.0; … cov5percent expected 87.25 got 87.0Fixture
fixture.make_refimageis new and deliberately lighter than_diffimage_parents:refimageshas no FK toexposuresorl2files, so acaller needing only a reference image should not mint both to get one.
fidisread from the seeded
filtersrather than invented, andversionismax+1because
refimagespkis UNIQUE on(field, fid, ppid, version)— a fixedversion would make the second call in a suite collide with the first, and the
failure would look like the defect under test.
Verification
main(e1896658, the commit carrying 128)What this still does not cover
The registrar's own assembly of those twenty-four arguments
(
products._refimmeta_measurementsand itsREFIMMETA_MEASUREMENTStable) isasserted in the stub tier against the mapping it declares. The two tiers
together cover the chain from provenance key to database column; neither covers
it alone. A full end-to-end
register_reference_imageagainst a real databasewould need an attempt, a terminal record and published products, and is a
larger piece of work than this one.