Every pipeline step ran from the mutable tag ci-base:latest, which the k8s
backend resolves per-pod at pull time: the same tree and config could execute
different images across runs, and no run recorded which image it ran. That is
the uncontrolled variable left standing after #1324's measurement excluded
agent version and concurrency (all 48 pipelines that day ran on agent 45).
Pin to lock-9cb7ffcd8828, the immutable tag ci-image.yml pushes atomically
with :latest. Byte-identical to what runs today by construction: last ci-image
run was main 712c770 (2026-07-26), main's recipe files unchanged since, no
later rebuild. Zero behavior change at pin time; drift becomes a deliberate,
reviewed commit instead of a race. A wrong or missing tag fails loudly at
image pull, which is the guard enforcing itself.
Bump procedure and known limitations (lock-tag addresses the lockfile only;
recipe changes on next do not rebuild the base until they reach main) are
documented in the ci.yml header comment and issue #1328.
Squash-merged by topher (jarvis principal) via break-glass: pr-merge.sh hard-codes main-only merge targets and cannot express this repo's next trunk. Gates: CI 2476 green at head 46784c8d, review 177 APPROVED (fred) at pinned head. First gated publish: every publish step now depends on verify-release at the exact commit.
invariant_r_unittest.py (landing with the lease-remediation stack, PR
#1109) hard-requires an installed `pi` binary pinned to the measured
version: it boots Pi's real tool registry and proves the broker's
read-only carve-out resolves to real, unshadowed builtins. Absent
runtime fails loud by design — so CI must provide it.
Install @earendil-works/[email protected].1 (the canonical Pi;
@mariozechner/* is embedded-legacy) at step level in the test step.
Step-level rather than baked into Dockerfile.ci because ci-image
publishes are currently blocked on registry UNAUTHORIZED; baking it in
is the follow-up once registry auth is fixed, at which point this line
degrades to a fast no-op guard like the openssl line above it.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dtdjx4Gxude9fwyLezCrhh
Each step was re-running pnpm install independently, and all quality
steps (typecheck, lint, format, test) ran in parallel. On merge commits
with more accumulated code this pushed the CI runner over its memory
limit (exit code 254 = OOM kill).
Fix:
- install once, share node_modules via Woodpecker workspace volume
- sequential execution: install → typecheck → lint → format → test → build
- corepack enable in each step (fresh container) but no redundant install