← board

pin_verify records positional job numbers and a stale version label

The record

"pin_verify": {
  "date": "2026-08-17T21:28:40Z",
  "red": ["lib-test#36", "lib-test#117", "test-nilpy#12"],
  "sha": "08bdf27290b79f9f40711b2051922e300df52208",
  "tier": "full", "ver": "v347", "verdict": "RED"
}

Defect 1 — the version label is wrong

sha 08bdf2729 is a docs commit at 22:26:29 local. The v347 pin commit f5da30bc9 landed at 22:27:54, 85 seconds later, and 08bdf2729 is its ancestor. The pin version in that tree is therefore 346:

$ git show 08bdf2729:stable_linux_amd64/default/VERSION
346

So a record labelled "ver": "v347" verified a tree pinned at v346. The label appears to be taken from the pin state at report time rather than from the tree at the verified sha. Anyone reasoning "v347 is red, the pin I just took is bad" — the natural reading, and the one that actually happened — is reasoning about the wrong pin.

Defect 2 — red stores positional names, so it is unattributable

Job.name is positional (tools/testmgr.py:1163):

self.name = "%s#%02d" % (target, index)

index is the job's position in the target's make -n recipe, so every #NN shifts when a test is added or removed. Measured, resolving the same three names two ways:

name resolved at the verified sha resolved at HEAD
lib-test#36 test/crtl_exp2.c test/crtl_exp2.c (+ merged group)
lib-test#117 test/lib_tls13_keys.pas test/lib_tls.pas
test-nilpy#12 examples/tk/field_class_identity.npy examples/tk/uses_tkinter_and_configparser.pas

Two of three name a different file depending on which sha you resolve against — and nothing in the record says which to use. Between those two shas a test-nilpy job was inserted at Makefile line ~302, shifting everything after it.

testmgr already has the fix in hand and uses it elsewhere: Job.sel ("stable selector", tools/testmgr.py:1173), and open_regressions stores exactly that alongside the display name:

{"name": "lib-test#36", "job": "lib-test#src:test/crtl_exp2.c", ...}

pin_verify.red stores only the positional half. That is precisely why lib-test#36 was the one red anybody could attribute — not because it was better understood, but because it independently appears in open_regressions where the stable selector is recorded.

Fix: store the src: selector in pin_verify.red (either instead of, or alongside, the display name), and take ver from the verified tree.

What the three reds actually were

Reproduced by hand, with binaries extracted from git so each is a named sha:

job file v346 v347
lib-test#36 test/crtl_exp2.c known open regression, timeout, opened 15:39, pin_built: true
lib-test#117 test/lib_tls13_keys.pas pass (5 ok / 0 FAIL) pass (5 ok / 0 FAIL)
test-nilpy#12 examples/tk/field_class_identity.npy compiles compiles

field_class_identity.npy also compiles with a HEAD-built compiler, producing byte-identical output sizes under all three.

The pin-lag hypothesis is disconfirmed. A lib/** job that needs a post-pin compiler behaviour would fail under the old pin and pass under the new one; lib-test#117 passes under both. And test-nilpy#12 is pin_built: false — it builds with the HEAD compiler, so the pin cannot be its cause either.

And the stable per-job map in the same file already says so:

lib-test#src:test/lib_tls13_keys.pas                pass
test-nilpy#src:examples/tk/field_class_identity.npy pass

Only three jobs are non-pass in the whole map: crtl_exp2.c (timeout, the known regression) and two lib_synapse jobs (skipexternal/ is absent in the watcher's clone, which is the guard in Makefile/install_externals.sh behaving as designed).

So the two unattributed reds are most likely transient — timeout or resource contention during a 186-job parallel lib-test, the same class as crtl_exp2's recorded timeout. Not proven; but they do not reproduce, and the per-job map disagrees with the pin_verify list.

Why this is worth 55

A RED verdict nobody can attribute is worse than a red nobody has looked at: it is read, it dispatches work, and here it dispatched a hunt for a bad pin that was not bad. The failure is not that the run found reds — it is that the record does not carry enough information to identify what went red, so the reds cannot be confirmed, dismissed, or tracked across runs. Positional identity also means two runs' red lists cannot be compared at all if the job list changed between them, which quietly undermines new_red / fixed diffing whenever a test is added.

Gate

pin_verify.red entries resolve to a file without knowing the sha, and ver matches the pin version in the verified tree. A regression test can construct two job lists differing by one inserted job and assert the recorded identity is unchanged.

Resolved 2026-08-19 by Track T (plexus-T) — one defect fixed, one WITHDRAWN

Defect 2 (positional names) — real, and fixed

verify_pin built its red list from j["name"]. It now uses job_key(j), the helper that already exists for exactly this and is used by every other across-commit comparison in twatchj.get("sel") or j["name"], so a report from an older testmgr still falls back rather than crashing.

Confirmed live before the fix, in this morning's record:

"pin_verify": {"red": ["lib-test#36", "lib-test#117"], "ver": "v352", ...}

lib-test#117 could not be resolved from the per-job map at all, exactly as filed.

Gate: tools/devtest_pin_verify.py gains a renumbering check — the same job before and after a test is inserted above it, asserting the recorded identity is unchanged, that it names a source, and that a pre-sel report falls back. That is the regression test this ticket's Gate section asked for. Verified it FAILS on the unfixed code (['lib-test#117'] vs ['lib-test#118']).

Defect 1 (the "stale version label") — WITHDRAWN, and the proposed fix would

have introduced a real bug

The record was correct and the reading of it was wrong. ver is not taken at report time: pin_verify_due gets (ver, sha) from pinned_ref, which reads one line of pin.log, so the two are paired at the source.

The ticket's evidence — git show 08bdf2729:.../VERSION returning 346 for a record labelled v347 — is a true statement about the wrong subject. Two different quantities are being compared:

They differ by exactly one for every pin ever taken, because make pin records the pin against the sha it was built FROM, and the VERSION bump lands in the pin commit that follows. Measured over the last twelve pins:

v343 tree=342   v345 tree=344   v346 tree=345   v347 tree=346   v348 tree=347
v349 tree=348   v350 tree=349   v351 tree=350   v352 tree=351   v353 tree=352
v354 tree=353                        (v344's sha predates the current format)

Eleven of eleven resolvable pins, lag exactly 1. Not drift — the invariant.

So the proposed fix ("take ver from the verified tree") would have relabelled every pin verification with its predecessor's version — attributing each verdict to the wrong binary, in the one record whose entire job is to say which binary was judged. It would have looked like a fix, and it would have been strictly worse than the thing it corrected.

Recorded at length rather than silently dropped because the ticket is otherwise careful and its author verified the number they quote. The error is not sloppiness; it is the shape track-t.md names — a checkable, correct statement standing in for the deciding one, where re-reading the evidence only confirms it.

The slug keeps the old name so existing links resolve; the summary is left intact above for the same reason, with this section as the correction.

Log