Measure whether the copies that should be identical still are — and never say which one is right.
2026-08-27. Two measurements on the same day, in the same estate:
One configuration file existed in 29 copies, in 4 distinct versions, under 3 different naming conventions. Nobody knew that until it was counted.
Separately, one of our own components — a plugin running on dozens of client sites we operate — was found in 6 distinct contents and declared only 3 version numbers — including one install that claimed the same version as the majority while differing from it, and one that carried the highest version number while having lost five files the others had.
Both findings share a shape: the declared version number does not identify the content. It is a declared value, not a measured one. Anything that trusts it is counting wrong, and no completeness check will notice, because the field is full.
For every copy it builds a manifest — sha256 per file, relative path — and
reduces it to one fingerprint: sha256 over the sorted digest-and-path lines.
Sorting is not cosmetic. os.walk does not guarantee an order, and without a stable
one two identical copies produce two different fingerprints; the tool would report
divergence everywhere and mean nothing by it.
Then it:
- groups by content, never by name and never by declared version;
- compares the declared version against the measured content, and names the contradiction when the same claimed version covers different contents. A tool that only groups by content sees those as two ordinary variants rather than as a lie;
- shows the three-set difference between groups: only in A, only in B, and in both but different. The third set is the one that distinguishes a superset from a divergent branch. Without it, a copy with two extra files looks like a newer version even when it has lost five others.
It will not tell you which copy is the correct one, and it will not align anything.
Choosing is a decision. A tool that decides quietly will one day overwrite the copy that had the thing nobody else had — the translation, the local fix, the field that was only ever set in one place.
Every run states how many copies were measured out of how many declared, which ones were missing, how many files could not be read, and what was excluded.
If an include filter was used, the run says so — divergence outside the filter was
not measured. Measured divergence is a lower bound, never an upper one. A partial
coverage can call two things identical when they are not, and it always errs in the
same direction.
A run that measured nothing prints NOTHING WAS MEASURED. This is not a pass. and
exits 2.
None. Python 3.8+, standard library only.
curl -O https://raw.githubusercontent.com/langacorp/samecheck/main/samecheck.py
python3 samecheck.py --selftest
python3 samecheck.py --selftest
Five directions, all asserted, any one failing fails the test:
- must fire on copies that differ — one by a changed file, one by an added file
- must stay silent on identical copies, including when one has a
node_modulesthe other lacks - must name the contradiction — same declared version, different content
- must not look like a pass when nothing was measured
- the fingerprint must not depend on file order — the same manifest fed in reverse must produce the same fingerprint
python3 samecheck.py /srv/site-a/plugin /srv/site-b/plugin /srv/site-c/plugin
python3 samecheck.py -c copies.json --json
copies.example.json:
{
"copies": [
"/srv/site-a/wp-content/plugins/example",
"/srv/site-b/wp-content/plugins/example"
],
"exclude": ["node_modules", ".git", "cache"],
"include": "\\.php$",
"declared_version": {
"file": "example.php",
"pattern": "Version:\\s*([0-9.]+)"
}
}declared_version is optional; without it the tool groups by content only and
cannot name contradictions.
Exit codes: 0 one content · 1 divergence found · 2 nothing was measured.
- It compares files on disk. Database rows, registered cron jobs and licence state are not files, are not measured, and can make two copies with the same fingerprint behave differently.
- Two files can be functionally equivalent and byte-different — a timestamp in a header, different line endings. Those are reported as divergence, because they are, and deciding they do not matter is a decision.
--includemakes a run faster and the answer smaller. It never makes it safer.
Each came out of a defect measured on our own estate. Each one is standalone and depends on none of the others.
- realroute — checks that a route really exists, by content and not by status code.
- leakform — finds secrets in a git repository by shape, across every ref.
- provenreal — compares what a system claims with what can be measured, from independent sources.
- countdrift — finds numbers written by hand that no longer match their source.
- kemproof — attests that an ML-KEM-768 key exchange really happened. It does not encrypt anything.
The set is kept on the organisation profile. It is not written here as a count, because a number typed by hand is the thing countdrift exists to find.
LANGA runs an ecosystem of digital services on its own infrastructure. This tool came out of a defect we hit while running them: the same component installed in many places, quietly no longer the same. Those places are:
- LANGA — the ecosystem
- Drive In — marketing packages for local business
- LANGA Tools — WordPress toolkit for developers
- eFruit — food marketplace for local producers
See How we work.
MIT. See LICENSE.
Built and maintained by LANGA.