The script that produced #726’s first look at test A existed in one place: another session’s scratchpad, which gets cleaned up. Richard asked me to commit it before that happened.

Saving it

I copied it before reading anything else, to two places, and checked that all three copies had the same checksum. It was also byte-identical to the copy embedded in #726’s comment, so the comment and the file agreed about what had produced the cited numbers.

The committed version, backend/scripts/twin_relation_graph.py, keeps the method and the SQL. What changed is around them:

  • The grouping is pure functions, so it can be tested without a database.
  • The engine is read-only, and the script checks transaction_read_only before its first query.
  • It refuses a target with no rows, or one stored under two predicates. The first would make the comparison examine nothing, and the second would merge two relation types the bridged export keeps apart.

The tests build a small graph from entity sets and check its links against ones worked out by hand. Two of them need Postgres: they ran on a throwaway database, which I dropped afterwards. Then I broke the code three ways: flipped the link names, swapped the SQL’s subject and object, and dropped the read-only option. Each time the test meant to catch that change failed, and nothing else did.

The numbers had moved

Next, the original script, unchanged, on prod, read-only. #726 cites 11, 14 and 12 of 124 other meanings. Today it printed 10, 11 and 11 of 126.

The four CIViC targets were the same, row for row. What had changed was the graph around them:

  • OncoKB’s re-key and re-annotation (#744) ran at 19:38 that evening, twelve hours after the first measurement. It brought OncoKB’s first resistance edges, as two new meanings (LEVEL_R1, LEVEL_R2), and a third new meaning, px_LEVEL_Px2. Its LEVEL_1 rows went from 237 to 1,919.
  • ClinVar lost one meaning.
  • Her patient edges had changed: MAPLE:current_medication went from 15 rows to 21, for one.

kg_bridge_report.py --check showed the meaning changes against the 2026-10-04 snapshot, and main’s refreshed snapshot agreed: 130 meanings in her six sources. The committed version then reproduced the original’s output meaning for meaning on the same data.

So the cited figures were right for the day they were measured, and are a snapshot. The conclusion stands: the twins differ only through a dozen sparse classes. But a figure measured on a live graph needs its date where it is cited. I dated it in the pdr2 rule, which now points at the script, and left #726 today’s numbers.

What the script still is not

It is not test A. It reads stored rows, not an exported train split, and it compares one round of neighbours by name, not six rounds of colour refinement from a marked query relation. The full test A can build on its grouping. It needs an export reader and the colour refinement, and it should compare the twins’ links to each other, which this version leaves out.