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 fromff3b8ebby 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 versionff3b8eb. 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
153 lines
6.6 KiB
YAML
153 lines
6.6 KiB
YAML
name: Unit tests
|
|
|
|
# TRACES: DP-007 | PR-004
|
|
#
|
|
# The tier the verification strategy is built on, finally executing.
|
|
#
|
|
# docs/requirements.md describes a four-tier plan in which T1 (functor unit)
|
|
# and T2 (replay) are "the only tiers that can exist in CI at all", and the
|
|
# traceability gate reports a CI-scope coverage fraction over exactly those
|
|
# tiers. Until this workflow existed, nothing ran them: "covered" meant a
|
|
# TRACES tag was present in a file, not that any test had been executed. That
|
|
# is the same failure mode as counting a test that cannot run, one level up,
|
|
# and the gate cannot detect it because a tag is all it can see.
|
|
#
|
|
# The runner is an Intel N100 with no discrete GPU. Nothing here calls a model:
|
|
# T1 constructs node functors directly, and T2 replays a precomputed HDF5 dump.
|
|
# T3 (ORT CPU smoke) and T4 (GPU) are deliberately absent -- the embedder is
|
|
# ~930 ms/frame on this hardware, so a 77 s clip at 5 fps would be six minutes
|
|
# of inference alone.
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
- master
|
|
- develop
|
|
pull_request:
|
|
branches:
|
|
- main
|
|
- master
|
|
- develop
|
|
|
|
jobs:
|
|
unit-tests:
|
|
runs-on: linux/amd64
|
|
name: Build and run the GPU-free suite
|
|
|
|
# Pinned by tag, never `latest`, so rebuilding the image cannot silently
|
|
# change what a previous green build meant. Bumping the dependency set means
|
|
# bumping the tag in scripts/ci/build_builder_image.sh AND here, in one
|
|
# commit -- see that script's header.
|
|
container:
|
|
image: gitea.tourolle.paris/dtourolle/sae-builder-cpu:v1
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
# KPN is a submodule and the pipeline does not build without it.
|
|
#
|
|
# NOTE: this checks out the commit this repo PINS, which is the whole
|
|
# point and is also the first thing this job will disagree with a
|
|
# developer about. A local KPN working copy that is ahead of
|
|
# origin/master builds and passes here while CI builds something else
|
|
# entirely; the AR-004 evidence in docs/requirements.md was gathered
|
|
# that way. If this job fails on tests that pass locally, check
|
|
# `git -C external/KPN log origin/master..HEAD` before suspecting the
|
|
# tests.
|
|
# LFS is deliberately NOT fetched: SAE_MODELS_DIR is baked into the
|
|
# binary as a path string and nothing in T1/T2 opens a model file, so
|
|
# pulling ~hundreds of MB of ONNX would cost the job everything and
|
|
# buy it nothing.
|
|
submodules: recursive
|
|
lfs: false
|
|
|
|
- name: Assert the builder image is the pinned one
|
|
run: |
|
|
set -e
|
|
echo "builder=$SAE_BUILDER version=$SAE_BUILDER_VERSION"
|
|
echo "ort=$SAE_ORT_VERSION opencv=$SAE_OPENCV_VERSION"
|
|
# The image reports its own tag. A mismatch means the `container:`
|
|
# line above and the image that actually landed disagree, which is
|
|
# exactly the drift the pinning exists to prevent -- so it fails the
|
|
# job rather than building against an unknown toolchain.
|
|
[ "$SAE_BUILDER_VERSION" = "v1" ] || {
|
|
echo "image reports version '$SAE_BUILDER_VERSION', workflow pins v1" >&2
|
|
exit 1
|
|
}
|
|
|
|
# Pinned to a version, never `latest`, for the same reason the builder
|
|
# image above is: a dump is an input to the tests, so a moving `latest`
|
|
# would let a re-upload retroactively change what an earlier green build
|
|
# proved. It also removes a credential from this job entirely -- package
|
|
# DOWNLOADS are anonymous while the repo is public, and only resolving
|
|
# `latest` needs a token (the list-packages endpoint requires auth on this
|
|
# instance). `latest` was the sole reason this step wanted GITEA_TOKEN,
|
|
# and no such secret is configured, so it could never have resolved.
|
|
#
|
|
# Bumping the fixtures means uploading a new version with
|
|
# scripts/artifacts/push_artifacts.sh replay-fixtures and editing the SHA
|
|
# here, in the same commit -- as with the image tag.
|
|
- name: Fetch replay fixtures
|
|
# bash, not sh: the script declares #!/bin/bash and uses `set -o
|
|
# pipefail` and arrays, which dash does not have.
|
|
run: bash scripts/artifacts/pull_artifacts.sh replay-fixtures ff3b8eb
|
|
|
|
# pull_artifacts.sh warns and continues when a package version is missing,
|
|
# which is right for a developer pulling one artifact of several and wrong
|
|
# here. A T2 test whose fixture never arrived must not look like a pass:
|
|
# the dumps are the entire input to the replay tier, and VR-002's claim is
|
|
# that replay drives the real nodes over real data.
|
|
- name: Verify the fixtures actually arrived
|
|
run: |
|
|
set -e
|
|
missing=0
|
|
for f in tests/fixtures/dumps/superhero.h5; do
|
|
if [ -s "$f" ]; then
|
|
echo " ok: $f ($(wc -c < "$f") bytes)"
|
|
else
|
|
echo " MISSING: $f" >&2
|
|
missing=1
|
|
fi
|
|
done
|
|
if [ "$missing" -ne 0 ]; then
|
|
echo "" >&2
|
|
echo "Replay fixtures are absent, so the T2 tier cannot run." >&2
|
|
echo "They are not in git (tests/fixtures/dumps/.gitignore) -- they" >&2
|
|
echo "live in the Gitea generic package registry and are pulled by" >&2
|
|
echo "the step above, at the version pinned there. Check that the" >&2
|
|
echo "version still exists in the registry: pull_artifacts.sh warns" >&2
|
|
echo "and continues on a missing one rather than failing." >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Configure
|
|
run: |
|
|
set -e
|
|
# SAE_GEMM_BACKEND defaults to ROCM and the auto-detect prefers a GPU
|
|
# backend where it finds one; CPU is stated explicitly so this job
|
|
# cannot start depending on what happens to be installed on the runner.
|
|
# The CPU kernel is OpenBLAS in this image (tests/CMakeLists.txt fails
|
|
# the configure if it is not), so the suite exercises the kernel the
|
|
# CPU release actually ships.
|
|
cmake -S . -B build \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DSAE_BUILD_TESTS=ON \
|
|
-DSAE_GEMM_BACKEND=CPU
|
|
|
|
- name: Build the test suite
|
|
run: cmake --build build --target sae_tests --parallel
|
|
|
|
- name: Run the tests
|
|
run: ctest --test-dir build --output-on-failure
|
|
|
|
- name: Save test output
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: unit-test-results
|
|
path: build/Testing/
|
|
retention-days: 30
|