What is a pin, and what is allowed to block one?
CORRECTED 2026-09-01 — the code was never the problem
The first version of this ticket said would_pin/pin_is_green had become a
precondition. That is false and it would have sent someone to "fix" correct
code. Verified by grep:
| symbol | every non-test use |
|---|---|
would_pin |
twatch.py:2718 assignment, twatch.py:2654 comment. Nothing reads it. |
pin_is_green |
defined trackt.py:1525; used once at :1581 inside cmd_pinstatus, to print "last pin T found fully green" — a rollback target. |
pin_shadow() |
docstring, twatch.py:2628: "Deliberately never touches pinned, make pin, or stable_linux_amd64/**." |
pin_is_green does not gate the pin; it is the recovery half of
"recovered, not prevented". Credit frank-T-on-seven for catching this, including
that it was the first to misread its own signal.
So the inversion is in READING, not in code. make pin is a ~34s human
action needing only the self-host fixedpoint, and it was available every hour of
those 49. What happened is that agents — this one included — read "would NOT
pin" as "cannot pin".
The general finding, which is worth more than any code change:
A shadow gate that publishes a verdict nobody is authorised to act on will be read as authority anyway.
That is a fact about advisory signals, not about pinning.
The design, in the repo's own words
devdocs/dev/track-t.md states the design plainly:
A pin is fast and unverified on purpose:
make stabilize-fast && make pinis ~34s and proves the self-host fixedpoint, on the explicit trade that a bad pin is recovered, not prevented. Track A pays 34s instead of 25 minutes, and T supplies the verdict afterwards.
A shadow gate that answers "would NOT pin" is preventing, not recovering. That is the whole issue. Nothing was designed wrong and nobody made a bad call; a post-hoc verdict grew into a precondition, and each step looked like an improvement.
What it cost, measured 2026-09-01
| last pin | v398, 2026-08-30 19:34 — 49h before this was written |
| pin cadence immediately before | 9 pins in 26h, gaps of 0.7h to 7.9h |
| last pin T found FULLY GREEN | v354, 2026-08-19 — 12 days |
| tree past the pin | 1724 commits, 256 touching compiler/ |
would_pin outcomes today |
every shadowed candidate: would NOT pin |
The number that actually matters is the RECOVERY leg, not the pin count.
"49h with no pin" is a human not running a 34s command. The real degradation is
that pin_is_green requires a full run with no RED tier, nothing has
qualified since v354 on 2026-08-19, so if v398 turns out bad the only
fully-verified target to recover to is twelve days stale. The fast-pin trade is
explicitly "a bad pin is recovered, not prevented" — and the recovery leg is the
half that quietly went missing.
The user-visible consequence: the pin cannot build any C program for i386 or
arm32, because the fix (fc9c8ade2) landed one day after v398. The tree
compiles C for all five targets; the pin compiles three. Tracks B/E build with
$(PXX_STABLE), so for them the compiler is simply broken on two targets.
The evidence that the blocking rule is not even self-consistent
tools-devtest#00 has been red for 208 consecutive full runs — and it is in
v398's pin_baseline, so it is waived: red_set - unexpected resolves to
exactly {tools-devtest#00}. There were 81 WOULD PIN decisions with that
job red. So the gate already tolerates an inherited red by design.
The streak did not decay, it broke on one job: 2026-08-31T05:36:03Z, sha
aac20e75ed1f, "1 red(s) the current pin does not have:
test-pascal-conformance#shard0/6". Sole blocker. job_last_pass for it is
17fd5566a65e — the last sha that would have pinned.
One Track P parse regression has held the entire fleet's ground still for two days. That is the argument in one sentence.
Owner's view, 2026-09-01
"a pin is a successful self compile. so, we added in all regression testing before we would do a full pin, but that is why we ran into this issue - no pin at all. which is a worse outcome."
Recommendation
- Say out loud that the pin gate is the self-host fixedpoint — because the code already does this and the confusion was entirely in how the shadow's output reads. No tooling change is needed to cut a pin today.
- Make the shadow's output say what it is.
would_pin: falsereads as a refusal. If it said "advisory — 12 reds this pin does not have; pinning is not blocked", none of tonight happens. That is the one cheap code change and it is Track T's. KeepSUPERSEDED BY THE OWNER, 2026-09-06 — see the note below.pinstatusand the green-fallback, because "last pin T found fully green" is genuinely useful — it just must not be the thing that stops a pin being cut.
2026-09-06 — RECOMMENDATION 1 WAS FOLLOWED AND IT NEARLY CAUSED THE OPPOSITE FAILURE
This ticket is entirely about UNDER-pinning: agents reading an advisory verdict as a refusal and not cutting a pin for 49 hours. Today produced the other edge of the same sentence, and recommendation 1 as written does not prevent it.
Pin v405, owner-authorised, seat gating first as required. gate.sh quick came
back RED on two rows:
FAIL pinned builds live lib/rtl (19s) <- the red this pin CLEARS. A grade.
FAIL self-host fixedpoint (86s) <- NOT a grade. This IS the pin.
"the fixedpoint reached from PINNED differs from compiler/pascal26"
The seat held, and said afterwards that they had been carrying only half the rule. "A valid pin is the self-host fixedpoint. Nothing else may block one" — the half everyone quotes is nothing else may block one, which is this ticket's finding and is correct. The half that has no sentence of its own is that the fixedpoint row is therefore the one row that DOES block, because it is not a test result about the pin, it is the pin's definition.
Read at speed — "a red is a reason to pin SOONER", "graded, never gated" —
the paragraph reads as covering every red on the gate. Had it been followed
that way, test-smoke would have chained from the seat's LOCAL binary and
blessed a fixedpoint that these sources do not define, then handed it to every
lane as ground. Both binaries self-reproduce and both print green, so nothing
downstream could have seen it — the Thompson shape selfhost_fixedpoint.sh's
header is written to catch.
So recommendation 1 needs its second clause, and this is the proposed wording, stated as a REASON rather than as a count because a count goes stale the moment a row is added:
A row that restates the pin's own DEFINITION is not a grade. Every row that reports a property of the TREE is.
The first draft of that said "of the gate's rows, exactly one is not a grade",
and the seat that hit the incident objected before it hardened: that is a fact
about a row LIST, and a new definitional row tomorrow makes it false with nothing
reporting the change — a stale Makefile:<n> in prose form.
And note the symmetry with this ticket's existing finding, because it is the same defect and not a second one. "A shadow gate that publishes a verdict nobody is authorised to act on will be read as authority anyway" is a rule about a reading that is too STRONG. This is the same sentence being read too WEAK. Both directions cost a pin — 49 hours in one direction, a poisoned ground in the other — and both are fixed by the same thing: saying which rows decide and why, in the place the reader is standing.
Two residuals from the incident, neither blocking:
- The fixedpoint row went red once and never reproduced — three hand-run
hermetic chains agreed afterwards, the rebuilt binary was byte-identical to the
one the gate had called a mismatch, the race guard did not fire, and
byte 98sits inside the first program header'sp_filesz, a real content difference rather than a timestamp. Recorded as unexplained, not resolved; stage_1a hashed3daed564c60cand that is the first question if it recurs. - A SECOND fixedpoint red on the confirming gate was operator error and is
closed:
sync.shpulls before it pushes, so banking the pin movedcompiler/**and the gate ran without a rebuild — two valid fixedpoints. Noted here only so the residual is read as one occurrence and not two, because two reads as a pattern and a pattern gets chased.
The counter-argument, stated fairly
pinned is the ground B/C/D/E build every artifact on, and the reason pin
verification was built at all was that 18 of 25 pins never received a full
run and 13 were never judged in any tier. Cutting fast pins again re-opens
that. The answer is that it was already the accepted trade — make revert
demotes a bad pin — and that 12 days of no movement is a larger, quieter cost
than an occasional bad pin that gets demoted. But it is a real trade and the
decision should name it rather than pretend the fast pin is free.
2026-09-06 — THE OWNER RULED ON HALF OF THIS TICKET WHILE IT SAT HERE, AND RECOMMENDATION 3 IS NOW WRONG
b93dc4098 (09:34, "PINS ARE NOT RELEASES — the owner settles pin cadence and
RTL coherence") and e89f6da8f (09:35, "we avoid rollbacks — forward is the
recovery path") put the ruling into CLAUDE.md, which takes precedence over this
ticket. Verbatim:
"yes staying in sync with the rtl is a primary purpose of pinning. this is also why we have to pin on regular intervals, even if there are reds. pins are not releases."
"yes we avoid rollbacks. useful work done is work done, even if (other) things break."
Recommendation 3 is directly contradicted. CLAUDE.md now says
pin_is_green/pinstatus "name a target for an operation this fleet does not
perform", and instructs nobody to rank a ticket on rollback depth or spend work
making make revert produce a coherent pair. The green-fallback is the rollback
path; there is no rollback. Keeping it "because it is genuinely useful" is the
release instinct this ticket was opened to name, wearing the ticket's own
clothes.
Recommendations 1 and 2 stand and are strengthened, because the cadence
ruling makes the shadow's wording matter more, not less: a fleet that pins on a
regular interval with reds reads would_pin: false more often, not less.
HOW THIS WAS MISSED, which is the part worth keeping. I appended the fixedpoint incident to this ticket at 10:07 — 33 minutes after the owner's ruling landed on the same subject — having pulled, and did not notice. I was reading the ticket, and the thing that had changed was the file the ticket is about. A ticket does not announce that its premise moved, and CLAUDE.md does not announce which tickets it just invalidated. The check is cheap and I did not run it:
git log origin/master --since=<when this ticket was last touched> -- CLAUDE.mdbefore appending to any Track U decision ticket. A decision ticket is the one artefact whose whole content is a claim about what the rules currently say.
2026-09-06 — DECIDED BY THE OWNER. Both live recommendations taken.
"i take your advise and i think i already sayd such before like 3 times last week. we need regular pinning, green or not."
Recommendation 1 — LANDED in CLAUDE.md, with the half it was missing. The
original sentence was followed literally this morning and nearly produced the
opposite failure: a seat authorised to pin, gating first as required, got RED on
self-host fixedpoint and had to reason its way to stopping. The clause now
says which rows gate and why, phrased as a reason rather than a row count:
A row that restates the pin's own DEFINITION gates; every row that reports a property of the TREE grades.
Recommendation 2 — accepted, routed to Track T. would_pin: false gets
wording that cannot be read as permission.
Recommendation 3 — struck earlier the same day, by the rollback ruling.
The thing worth more than the ruling
The owner has now stated this at least four separate times — 09-01, 09-06, and twice in the preceding week, by his own count. A rule whose author has had to repeat it four times is not being misunderstood; it is being re-litigated. Each session that re-argued it did so honestly, from a fresh reading, with good reasons — which is exactly why restating it a fifth time would not have worked either. That fact is now IN the rule, so the next fresh reading meets the repetition count before it meets the argument.