test/lib.sh and test/pytest/pgc_cluster.py each carry an implementation of "what was this binary built from". On 2026-09-09 they produced four defects between them, two in each copy, and not one was found by whoever wrote that copy. All four are fixed; this issue is about the arrangement that produced them.
The four
| # |
defect |
in |
found by |
| 1 |
the digest missed objstore/*.c entirely — a separately built module the top-level Makefile reaches by recursion |
python |
@linuxhikerpm (#897) |
| 2 |
the digest mixed in each file's bare name, so src/module.c and objstore/module.c were interchangeable |
python |
me, while fixing 1 |
| 3 |
xargs -0 cat | md5sum — no paths, no boundaries, so moving bytes between files left the hash unchanged |
shell |
@linuxhikerpm (#898) |
| 4 |
the digest missed each build directory's Makefile |
python |
me, while writing the twin |
Defect 3 meant source that cannot compile reported matches the binary under test:
before_hash=bfce474cc159 after_hash=bfce474cc159
initial_compile=0 repartitioned_compile=1 error: redefinition of 'x'
Defect 4 meant editing objstore/Makefile — which changes how that module builds — moved one hash and not the other:
baseline shell=45be41a5c47b python=bea88c7d79ca
objstore/Makefile edited shell=cfb8f4553041 python=bea88c7d79ca
What makes this an arrangement problem rather than four bugs
The Python docstring said "the same input set as pgc_source_fingerprint in test/lib.sh" throughout all four. It was false when written and stayed false through two rounds of fixing. A prose assertion of agreement is not a mechanism, and it is worse than saying nothing, because it is exactly what stops the next person checking.
Nobody caught their own copy. Four defects, four found by the other party. That is not a comment on either of us; it is what two implementations of one idea do. You cannot review a divergence you are looking at from only one side.
And the failure is silent by construction. When the two disagree the stamp is written to one path and read from another, the reader finds nothing, the verdict is unknown — and unknown is deliberately not a failure, because someone who ran make install by hand has no stamp. So the whole mechanism goes quiet and every suite prints freshness UNVERIFIED while looking healthy. That design decision is right, and it is what makes drift between the two copies undetectable rather than loud.
What is already in place
test/selftest/340 now has an arm asserting the property the docstring only claimed: not that the two hashes are equal — they are different digests over the same files, used independently, and requiring equality would couple two things that have no reason to be coupled — but that the same edit moves both. It walks five edits: a source, a module source, a module Makefile, the top-level Makefile, and the control file.
That arm is a smoke alarm, not a fix. It catches the next divergence; it does not remove the ability to diverge.
The options, and what I would pick
A. Drive the shell from Python, as build_and_install already does. pgc_cluster.build_and_install runs bash -c '. test/lib.sh; pgc_build_and_install …' rather than reimplementing the build, and it does so for exactly this reason, stated in its own docstring. source_fingerprint could do the same and become four lines. This is what I would do. One implementation, one place to be wrong, and the Python side keeps a typed return.
The cost is a bash subprocess per fingerprint. build_once calls it twice per session, so that is measurable in microseconds against a build.
B. Keep both and keep the agreement arm. Cheaper today, and it is where we are. It leaves the ability to diverge in place and relies on a guard nobody has to run.
C. Move the fingerprint out of both into a small script both call. More work than A for the same result, unless something outside test/ needs it.
Why now rather than later
test/pytest/ is on main and jd's rule of 2026-09-09 means every new test ships in both harnesses. Every twin written from here is a chance for a second implementation of something to appear. This is the first one, it produced four defects in a day, and the pattern generalises: the same issue exists in miniature for the 17 fixture constants duplicated across #902's twin, which is a separate discussion but the same shape.
Happy to do A. Wanted the decision recorded rather than made inside a PR.
test/lib.shandtest/pytest/pgc_cluster.pyeach carry an implementation of "what was this binary built from". On 2026-09-09 they produced four defects between them, two in each copy, and not one was found by whoever wrote that copy. All four are fixed; this issue is about the arrangement that produced them.The four
objstore/*.centirely — a separately built module the top-level Makefile reaches by recursionsrc/module.candobjstore/module.cwere interchangeablexargs -0 cat | md5sum— no paths, no boundaries, so moving bytes between files left the hash unchangedMakefileDefect 3 meant source that cannot compile reported
matches the binary under test:Defect 4 meant editing
objstore/Makefile— which changes how that module builds — moved one hash and not the other:What makes this an arrangement problem rather than four bugs
The Python docstring said "the same input set as
pgc_source_fingerprintintest/lib.sh" throughout all four. It was false when written and stayed false through two rounds of fixing. A prose assertion of agreement is not a mechanism, and it is worse than saying nothing, because it is exactly what stops the next person checking.Nobody caught their own copy. Four defects, four found by the other party. That is not a comment on either of us; it is what two implementations of one idea do. You cannot review a divergence you are looking at from only one side.
And the failure is silent by construction. When the two disagree the stamp is written to one path and read from another, the reader finds nothing, the verdict is
unknown— andunknownis deliberately not a failure, because someone who ranmake installby hand has no stamp. So the whole mechanism goes quiet and every suite printsfreshness UNVERIFIEDwhile looking healthy. That design decision is right, and it is what makes drift between the two copies undetectable rather than loud.What is already in place
test/selftest/340now has an arm asserting the property the docstring only claimed: not that the two hashes are equal — they are different digests over the same files, used independently, and requiring equality would couple two things that have no reason to be coupled — but that the same edit moves both. It walks five edits: a source, a module source, a module Makefile, the top-level Makefile, and the control file.That arm is a smoke alarm, not a fix. It catches the next divergence; it does not remove the ability to diverge.
The options, and what I would pick
A. Drive the shell from Python, as
build_and_installalready does.pgc_cluster.build_and_installrunsbash -c '. test/lib.sh; pgc_build_and_install …'rather than reimplementing the build, and it does so for exactly this reason, stated in its own docstring.source_fingerprintcould do the same and become four lines. This is what I would do. One implementation, one place to be wrong, and the Python side keeps a typed return.The cost is a
bashsubprocess per fingerprint.build_oncecalls it twice per session, so that is measurable in microseconds against a build.B. Keep both and keep the agreement arm. Cheaper today, and it is where we are. It leaves the ability to diverge in place and relies on a guard nobody has to run.
C. Move the fingerprint out of both into a small script both call. More work than A for the same result, unless something outside
test/needs it.Why now rather than later
test/pytest/is onmainand jd's rule of 2026-09-09 means every new test ships in both harnesses. Every twin written from here is a chance for a second implementation of something to appear. This is the first one, it produced four defects in a day, and the pattern generalises: the same issue exists in miniature for the 17 fixture constants duplicated across #902's twin, which is a separate discussion but the same shape.Happy to do A. Wanted the decision recorded rather than made inside a PR.