build_once() in test/pytest/pgc_cluster.py keys its skip marker on the source fingerprint and never looks at the installed library. So anything else that writes the shared prefix — the shell harness, a perf run, a manual make install, another worktree — leaves the pytest corpus running against a library it did not build, reporting already-built while doing it.
This is not hypothetical. It cost two sessions today and the evidence was printed in both.
Measured: two independent incidents
Mine, reviewing #955. The corpus showed 10 failures, all in test_join_runtime_filter.py, on the PR's tree and on plain main. Neither was red. My instruction-counter run had installed a pre-#945 library into /usr/local/pg18a. Rebuilding from main took that file from 10 failed to 11 passed.
@jdatcmd's, on their own box, after I flagged it. /usr/local/pg17 was holding a pre-#945 library and they ran #945's suite through the skip-build path:
stale .so 9edef563e34d 44 checks, 25 passed + 19 FAILED
restored 2c9559d087b0 44 checks, 44 passed + 0 failed
Nineteen failures in one file with the code entirely innocent.
Reproduced deliberately
baseline
marker: /usr/local/pg18a/bin/pg_config|18|a0e6afc3e13e
.so: f0b770d93a2a (built from /root/wmp = main)
result: 11 passed
install a pre-#945 .so, VALID for this prefix, marker untouched
.so: d312a10c0cfb
marker: /usr/local/pg18a/bin/pg_config|18|a0e6afc3e13e <- unchanged
run the same tests from main again
-- build: already-built from /root/wmp
-- cluster: worker=master port=29768 PostgreSQL 18.4 .so=d312a10c0cfb
FAILED test_serial_join_runtime_filter
FAILED test_scattered_join_runtime_bloom
FAILED test_cross_type_int4_int8_bloom
FAILED test_collation_mismatch_bloom_only
restore main's .so
result: 11 passed
The mechanism, and why the existing guard misses it
pgc_cluster.py:438 keys the marker on pg_config, major and source_fingerprint(srcdir). Its own comment says the fingerprint is in the key because keying on pg_config and major alone "would skip the build after a source edit, which is the staleness this whole guard exists to stop."
That is right as far as it goes. The guard detects staleness caused by editing the source. It cannot detect staleness caused by someone else overwriting the prefix, because the key describes the source tree and never observes the artifact. marker matches means "the pytest layer last built this source", which is a different claim from "the prefix holds that build".
The two lines that disagree, in one output
-- build: already-built from /root/wmp
-- cluster: ... .so=d312a10c0cfb
The first names a tree and reads as provenance. The second carries the actual identity. d312a10c0cfb is not a build of /root/wmp. Both of us walked past it, and conftest.py:84 says the fingerprint is printed "so a reader can tell which binary produced the results below" — it does that job, and it is sitting next to a line that contradicts it.
Failure distribution is the diagnostic
Worth recording because it is what should have tipped us off sooner: a stale library's blast radius is exactly the feature that library lacks, so it presents as one whole file failing while the rest of the corpus passes. Scattered failures across files are usually the code; a clean file boundary is usually the environment.
Proposed
Record the installed library's fingerprint in the marker alongside the source fingerprint, and compare the file on disk against it before returning already-built. A mismatch means a third party wrote the prefix, so rebuild.
One trap for whoever implements it: the .so md5 is not a function of the source alone — the build path is compiled in. Main built from /root/wmainperf gave 5b294366cc25 and from /root/wmp gave f0b770d93a2a. So the fix cannot compare against a stored per-source constant. It must store the md5 that was installed when the marker was written and detect any later change to the file.
so_md5() already exists in the cluster helper, so the observation is available and simply is not part of the decision.
Out of scope
Stopping other harnesses from writing the prefix. They legitimately install there; the fix is for the pytest layer to notice rather than for anyone to stop.
Not a defect, for contrast, and worth keeping
Cross-major contamination already fails closed. Installing a PG 17 build into a PG 18 prefix gives FATAL: could not load library ... undefined symbol: smgrtruncate2 and the cluster refuses to start. It is cross-tree contamination within one major that fails open. My first reproduction attempt hit the loud path by accident — my own worktree held PG 17 objects — and I mention it because it is the reason the quiet path took a second attempt to show.
build_once()intest/pytest/pgc_cluster.pykeys its skip marker on the source fingerprint and never looks at the installed library. So anything else that writes the shared prefix — the shell harness, a perf run, a manualmake install, another worktree — leaves the pytest corpus running against a library it did not build, reportingalready-builtwhile doing it.This is not hypothetical. It cost two sessions today and the evidence was printed in both.
Measured: two independent incidents
Mine, reviewing #955. The corpus showed 10 failures, all in
test_join_runtime_filter.py, on the PR's tree and on plainmain. Neither was red. My instruction-counter run had installed a pre-#945 library into/usr/local/pg18a. Rebuilding from main took that file from 10 failed to 11 passed.@jdatcmd's, on their own box, after I flagged it.
/usr/local/pg17was holding a pre-#945 library and they ran #945's suite through the skip-build path:Nineteen failures in one file with the code entirely innocent.
Reproduced deliberately
The mechanism, and why the existing guard misses it
pgc_cluster.py:438keys the marker onpg_config,majorandsource_fingerprint(srcdir). Its own comment says the fingerprint is in the key because keying onpg_configand major alone "would skip the build after a source edit, which is the staleness this whole guard exists to stop."That is right as far as it goes. The guard detects staleness caused by editing the source. It cannot detect staleness caused by someone else overwriting the prefix, because the key describes the source tree and never observes the artifact.
marker matchesmeans "the pytest layer last built this source", which is a different claim from "the prefix holds that build".The two lines that disagree, in one output
The first names a tree and reads as provenance. The second carries the actual identity.
d312a10c0cfbis not a build of/root/wmp. Both of us walked past it, andconftest.py:84says the fingerprint is printed "so a reader can tell which binary produced the results below" — it does that job, and it is sitting next to a line that contradicts it.Failure distribution is the diagnostic
Worth recording because it is what should have tipped us off sooner: a stale library's blast radius is exactly the feature that library lacks, so it presents as one whole file failing while the rest of the corpus passes. Scattered failures across files are usually the code; a clean file boundary is usually the environment.
Proposed
Record the installed library's fingerprint in the marker alongside the source fingerprint, and compare the file on disk against it before returning
already-built. A mismatch means a third party wrote the prefix, so rebuild.One trap for whoever implements it: the
.somd5 is not a function of the source alone — the build path is compiled in. Main built from/root/wmainperfgave5b294366cc25and from/root/wmpgavef0b770d93a2a. So the fix cannot compare against a stored per-source constant. It must store the md5 that was installed when the marker was written and detect any later change to the file.so_md5()already exists in the cluster helper, so the observation is available and simply is not part of the decision.Out of scope
Stopping other harnesses from writing the prefix. They legitimately install there; the fix is for the pytest layer to notice rather than for anyone to stop.
Not a defect, for contrast, and worth keeping
Cross-major contamination already fails closed. Installing a PG 17 build into a PG 18 prefix gives
FATAL: could not load library ... undefined symbol: smgrtruncate2and the cluster refuses to start. It is cross-tree contamination within one major that fails open. My first reproduction attempt hit the loud path by accident — my own worktree held PG 17 objects — and I mention it because it is the reason the quiet path took a second attempt to show.