ci: make both workflows able to run at all #1

Merged
dtourolle merged 6 commits from ci/green-the-runner into master 2026-09-03 18:19:42 +00:00
6 Commits
Author SHA1 Message Date
dtourolle 9bcc765408 fix(ci): the builder image has no unzip, so the replay tier had no input
Traceability Validation / Check requirement traces (pull_request) Successful in 19s
Unit tests / Build and run the GPU-free suite (pull_request) Successful in 3m25s
Found by CI itself, on run 1437 -- the first run that ever got far enough
to try. Everything ahead of it worked: checkout brought both submodules,
v2 pulled and passed its own version assert, and the fixtures resolved at
the pinned version. Then:

    scripts/artifacts/pull_artifacts.sh: line 54: unzip: command not found

The replay fixtures ship as a zip in the generic package registry and
pull_artifacts.sh unpacks them with unzip. Without it the step exits 127
and the T2 tier has no input -- reported as a missing fixture by the
verify step below, which is a missing tool wearing the wrong label.

Worth naming why the local rehearsal missed this and CI did not: the
rehearsal had the dumps staged in the working tree by hand, so it built
and ran the tier without ever executing the script that fetches them. The
image was checked against the build, not against the job.

Tag v2 -> v3, in all three places, in one commit.

TRACES: DP-007 | PR-004
2026-08-31 08:04:43 +02:00
dtourolle 3966e19a83 test: two tests still describe the registry as it was before 1477c53
Both failed the first time CI was able to run this suite, and neither is
a new break. They assert semantics that two deliberate changes replaced,
and nothing noticed because nothing had ever executed them.

1477c53 (2026-08-09) made a dormant track associable only if it had been
identified: an unowned dormant track has no actor to re-attach to, so it
only enlarges the matcher's comparison set and invites a new face landing
on an anonymous stub. Its message records the trade -- "a small recall
cost (~1-3pp on some films, e.g. Lord of War -2.5) for a cleaner, bounded
pool. Kept deliberately." Both tests build tracks that are never
identified, so since that commit they are dropped from the pool one line
before the extinction horizon they were written to exercise. The tests
date from 2026-07-31 and 2026-08-08 -- they are older than the gate.
Fixed by owning the track while it is still on screen, which is what a
real run does and what makes the horizon reachable at all.

The second test needed more than that, and the rename says why. It was
built on association and reaping answering on DIFFERENT clocks -- the
tracker's for "may this associate?", the watermark for "is this
finished?" -- which is exactly the arrangement track_registry.hpp:184-203
now rules out: one clock, one threshold, "nothing is offered past its
reap horizon, nothing is reaped while still offerable". So there is no
longer an interval in which a track is retired from association but still
alive, and a test named for that interval cannot pass. Rewritten to
assert what the unified clock actually promises: a tracker racing 50 s
past the horizon retires nothing while the matcher lags, the votes in
flight still land, and the watermark passing the horizon retires, reaps
and emits in one step.

Kept: the AR-008 tag, the late-vote check and dropped_votes() == 0, which
were the point of the test and still hold.

Full suite now 151/151 in sae-builder-cpu.

TRACES: AR-008, AR-013 | SR-002
2026-08-31 08:04:17 +02:00
dtourolle 5ce6394416 chore: update KPN — diagnostics.hpp includes the <vector> it uses
Traceability Validation / Check requirement traces (pull_request) Successful in 10s
Unit tests / Build and run the GPU-free suite (pull_request) Failing after 40s
af9da7d on top of 5375ab4, and the reason it exists is this repository.

kpn/diagnostics.hpp declares NetworkSnapshot with two std::vector members
and has never included <vector>. It compiled everywhere we build because
something earlier in each translation unit dragged the definition in
first. src/benchmark.hpp includes <kpn/diagnostics.hpp> before its own
<vector>, and under Debian 12 / GCC 12 -- the CI image, and nothing we
develop on -- nothing supplies it, so the two members fail to declare and
every later use of .nodes or .channels fails after them. The errors all
name benchmark.hpp, so it reads as our bug until you look at the first
line of compiler output rather than the last.

This bump also crosses the four perf/phase0-harness commits between
5375ab4 and the pin, which is a larger move than a header fix and worth
being explicit about. Checked rather than assumed: the two tests failing
in CI fail identically with the pin at 771b9f8 plus the include fix
alone, so they are not this bump's doing. The perf work changes the
scheduler and pool; the failures are tracker extinction-window logic and
are reachable with no pool at all.

Also found while checking KPN's public headers standalone under GCC 12,
and NOT fixed there: network.hpp names IChannelProbe (channel.hpp:557)
without including channel.hpp -- the same latent bug, waiting for the
same kind of consumer. web_debug.hpp needs httplib.h, which is an
optional external dependency and not a defect.
2026-08-30 22:42:26 +02:00
dtourolle 80c23d39d1 fix(ci): sae-builder-cpu could not configure this repository at all
v1 has no libfftw3. SAE_SCENE_XGB is on by default and pulls the learned
scene-boundary detector into result_sink, whose find_library(FFTW3_LIB
fftw3 REQUIRED) at CMakeLists.txt:377 runs at CONFIGURE time -- so cmake
fails before any target is chosen, and building only `sae_tests` does not
get you past it. The image predates the detector; nothing rebuilt it when
the detector landed, which is precisely the gap DP-007's own register row
records.

-DSAE_SCENE_XGB=OFF would also have made the configure pass. It is the
wrong fix and worth saying why: CI is the only place these tests run, so
a flag that silences a subsystem there silences it everywhere, and the
job would have gone green over a detector nobody was compiling.

The image's self-check gains a line, because an image that ships a
library CMake cannot find the way CMake looks for it is the failure this
block exists to catch. FFTW is checked as a bare .so rather than through
pkg-config, since find_library is what CMakeLists.txt actually calls --
checking fftw3.pc would pass on an image whose libfftw3.so was absent.

Tag bumped v1 -> v2 here, in build_builder_image.sh and in the workflow's
run-time assert, in one commit, as this image's contract requires. v2 is
built and published. Rehearsed in the image before pinning it: configure,
build and 151 tests now run.

TRACES: DP-007 | PR-004
2026-08-30 22:42:15 +02:00
dtourolle c5a8502bbb ci(tests): publish what the job was told to pull, and pin it
Traceability Validation / Check requirement traces (pull_request) Successful in 40s
Unit tests / Build and run the GPU-free suite (pull_request) Failing after 36s
DP-007's row says the builder image is "pinned by tag in the Gitea
container registry". The tag was pinned; the image was never pushed.
Every run since the workflow landed died at
"Error response from daemon: manifest unknown" before a single step ran,
so the tier this workflow exists to execute has still never executed.

sae-builder-cpu:v1 is now in the registry, built from ff3b8eb by
scripts/ci/build_builder_image.sh and reporting SAE_BUILDER_VERSION=v1,
which is what the job's own assert-the-image step demands. The
v1-ff3b8eb audit tag went with it.

Behind that, the same absence one layer down: no replay-fixtures package
existed either, so "Verify the fixtures actually arrived" would have
failed next. tests/fixtures/dumps is now published at version ff3b8eb.

Which makes the `latest` here worth removing rather than keeping. Two
reasons, either sufficient. It is the same argument DP-007 already
makes about the image tag -- a dump is an input to the tests, so a
re-upload under a moving `latest` retroactively changes what an earlier
green build proved. And `latest` was the only thing in this job that
wanted a credential: package downloads are anonymous while the repo is
public, and only resolving `latest` needs a token for the list endpoint.
No GITEA_TOKEN secret is configured on this repo, so that step could
never have resolved `latest` even once the image existed. Pinning
deletes the dependency instead of documenting it.

The failure message below it said the step "needs GITEA_TOKEN to resolve
'latest'"; it now says to check the pinned version still exists, which
is the thing that can actually go wrong -- pull_artifacts.sh warns and
continues on a missing version rather than failing, which is why that
verify step is there at all.

TRACES: DP-007 | PR-004
2026-08-30 22:09:02 +02:00
dtourolle fb4e4d4abc ci(traceability): the job container is where act_runner looks for node
The traceability job has been failing since it was written, and never on
anything it checks. It declared no `container:`, so it ran in the
runner's default image, which has no node; act_runner executes JS
actions with the node it finds inside the job container, and both
actions/checkout and upload-artifact are JS. The job died at
"Cannot find: node in PATH" before the repository was checked out, and
every later step then failed on an empty working tree -- the summary
step's "head: cannot open 'docs/traceability.md'" is that, not a missing
report.

node:20-bookworm, and the choice is not arbitrary: node is the part with
no workaround, while Debian 12 already carries python3.11 (tomllib, so
the stdlib-only extractor reads traceability.toml) and git (for the
pull_request diff step). Nothing in it names this repo, so the file
stays copyable into the other two components unedited, which its header
claims and this commit keeps true.

The kpnpp-builder and jellytau-builder images bake node in for exactly
this reason, and Dockerfile.builder-cpu says so in a comment. That
knowledge just had not reached the one job with no image of its own.

Second failure behind the first: the jray-project submodule was pinned
by SSH URL. The runner has no key, so `submodules: recursive` could not
have fetched the extractor even with node present. https, like the KPN
submodule beside it.

Gate and static check both pass locally on this tree -- 42/72 traced,
73.7% in CI scope, 0 orphans, 0 bare-cosine violations -- so what CI
reports next is a fact about CI, not about the tree.
2026-08-30 22:08:51 +02:00