Repository navigation
ci: the foreign judge had never run in CI, and nothing could have said so - #45
Conversation
…d so
⛔⛔ EVERY TEST THAT AGREES WITH qpdf HAS BEEN SKIPPING ON EVERY LANE. Measured
on run 43595391186: the string "qpdf" appears ZERO times in the whole log.
⛔ AND THE TIME IS THE WITNESS, which is the only thing that could have been
noticed: this job reports
ok github.com/go-pdfkit/reader 0.197s (CI)
ok github.com/go-pdfkit/reader 0.758s (a workstation with qpdf)
The sweep generates 42 files by invoking qpdf; it cannot do that in 0.197s. So
the agreement across 1, 2, 3, 5, 25 and 100 pages in five shapes, AND the
negative control that an ordinary file is REFUSED by the foreign judge — the
one #44 added yesterday — have never been checked by anything.
⛔ `go test` WITHOUT -v PRINTS NOTHING ABOUT A SKIP, so the log was not
hiding this badly, it could not report it at all. And coverage stayed at
100.0% throughout: the same statements are reached by the tests that need no
qpdf, so the coverage gate cannot see this and never could. Two gates were
green about a third thing neither measures.
⛔ THIS REPOSITORY ALREADY HOLDS THE OPPOSITE STANDARD, one job down, about a
missing qemu emulator: "A missing emulator FAILS this lane. A lane that
reports success for an architecture it never ran is the one outcome this
matrix exists to rule out." A missing foreign judge is that outcome for a
different reason. go-pdfkit/ops already does it right for pdftoppm.
⛔ REQUIRE_QPDF, NOT CI, because not every lane CAN run it and a rule that
demands the impossible gets deleted. Under qemu-user the test binary is
emulated and an execve of the host's x86-64 qpdf is not something the
emulator can carry out; the Windows lane has no apt. So ONE lane installs
qpdf and sets REQUIRE_QPDF, and there a missing judge FAILS. The others skip,
which is now a stated design instead of an accident nobody could see.
Measured, both directions, rather than predicted:
REQUIRE_QPDF=1, qpdf off PATH -> FAIL, naming the reason
unset, qpdf off PATH -> skip, exit 0
⛔ aptneed FOR THE INSTALL, because a mirror outage must not arrive as a
missing judge: go-pdfkit/ops#90 was four red runs in half an hour on a third
party's DNS. `--need qpdf` asks for the BINARY, since apt saying yes is not
qpdf being on PATH. And `qpdf --version` is printed, so which judge agreed is
answerable afterwards rather than assumed.
⚠ NOT FIXED, and deliberately: actionlint reports SC2086 on `go test $ex
./...` in the qemu job. It is pre-existing — main carries it at line 141 — and
shellcheck is WRONG here. `ex` is empty on the 386 lane, which runs natively
on purpose, so quoting it would hand `go test` an empty package pattern and
break the one lane that must not be emulated. Reader's CI never ran
actionlint, which is why it went unnoticed; silencing it properly is its own
change.
gofmt clean, go vet clean, 0 uncovered blocks of 1806.
Refs #40.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
⛔⛔ SECOND OCCURRENCE IN TWO DAYS, AND I PREDICTED THIS ONE IN WRITING. The
first push of the qpdf lane failed on
go: …/cmd/aptneed@latest: fleettools@v0.112.0 requires go >= 1.27.4
(running go 1.27.3; GOTOOLCHAIN=local)
go-pdfkit/ops hit the identical line on 2026-11-13, and after fixing it I
wrote on that pull request: "Worth knowing for other repositories in the fleet
that pin a toolchain and install fleettools commands in CI: the same pin
blocks them the moment they try." Then I walked into it myself, one repository
later, the next day. A note is applied when somebody remembers to apply it,
and at the moment of adding an install step one is thinking about the install.
So it is recorded as a recurrence rather than a third note. The gate that
catches it is a check over `.github/workflows` for a `<module>/cmd/<x>@latest`
install beside a `go-version` pin below that module's `go` directive —
already filed as pending on go-fleettools/fleettools#103, where the `@latest`
half of the same problem lives. `tagscan` cannot see either: it reads
repositories, not workflows.
All three jobs move to 1.27.4, not only the one that installs aptneed. The
other two do not need it, but a matrix measuring on two different toolchains
is a difference nobody chose, and this fleet has already been bitten by
`stable` quietly selecting a minor.
⛔ GOTOOLCHAIN IS STILL LEFT ALONE. That is what made this a clean failure
naming both versions instead of a runner silently fetching 1.27.4 and
measuring a chain nobody picked.
go.mod stays at `go 1.27.1`: that is the language version this module needs,
not the toolchain a runner must have, and nothing here requires it to move.
actionlint reports only the pre-existing SC2086 discussed in the previous
commit.
Refs #40, #44.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Green at It ran25 mentions of ⛔ The timing alone would not settle it — 0.262 s against 0.197 s before is a smaller gap than I expected, and runner speed varies. The argument that does settle it is structural: ⛔ CI judges with qpdf 11.9.0, and every measurement in my notes used 12.4.2Ubuntu's apt serves 11.9.0. My workstation has 12.4.2, which is the version named in the README, in This is the step ⭐ It is good news, not a problem. The checker now agrees with two independent qpdf majors — 11.9.0 on CI and 12.4.2 locally — which is a stronger claim than either alone, and precisely the "a second corpus measures what the first cannot" argument applied to the judge rather than the inputs. ⚠ What it does mean: the README's "qpdf 12.4.2 is the reference implementation of this format in practice" describes my judge, not CI's. I am not editing that here — it is accurate about where it was measured — but a future disagreement should ask which version reported it before anything else. Pinning CI to 12.4.2 would mean building qpdf from source, which is a cost I would not pay for this. Merging on this. |
Found while reviewing the negative control merged yesterday: the foreign judge it added has never run in CI. Nor has any of the rest of the agreement with qpdf.
Measured
Run
43595391186: the stringqpdfappears zero times in the entire log.And the time is the witness — the only thing that could have been noticed:
The sweep generates 42 files by invoking qpdf. It cannot do that in 0.197 s. So the agreement across 1, 2, 3, 5, 25 and 100 pages in five shapes — and the negative control added yesterday, that an ordinary file is refused by the foreign judge — have never been checked by anything.
Why nothing reported it
go testwithout-vprints nothing about a skip. The log was not hiding this badly; it could not report it at all.Two gates were green about a third thing neither of them measures.
This repository already holds the opposite standard, one job down
Of a missing qemu emulator, its own workflow says:
A missing foreign judge is that outcome for a different reason.
go-pdfkit/opsalready does this correctly forpdftoppm— its render testst.Fatalwhen CI is set.⛔
REQUIRE_QPDF, notCINot every lane can run it, and a rule that demands the impossible gets deleted:
execveof the host's x86-64 qpdf is not something the emulator can carry out;So one lane installs qpdf and sets
REQUIRE_QPDF, and on that lane a missing judge fails. The others skip — which is now a stated design rather than an accident nobody could see.Both directions measured rather than predicted:
REQUIRE_QPDF=1aptneed for the install
A mirror outage must not arrive looking like a missing judge —
go-pdfkit/ops#90was four red runs in half an hour on a third party's DNS.--need qpdfasks for the binary, because apt saying yes is not qpdf being onPATH.qpdf --versionis printed, so which judge agreed is answerable afterwards instead of assumed.⚠ One thing deliberately not fixed
actionlintreports SC2086 ongo test $ex ./...in the qemu job. It is pre-existing — main carries it at line 141 — and shellcheck is wrong here:exis empty on the 386 lane, which runs natively on purpose, so quoting it would handgo testan empty package pattern and break the one lane that must not be emulated.Reader's CI never ran actionlint, which is why it went unnoticed. Silencing it for the right reason is its own change, and I would rather not bury it in this one.
gofmt clean,
go vetclean, 0 uncovered blocks of 1806.Refs #40, #44.
🤖 Generated with Claude Code