pipeline 4.5.0 Two threads. The `validate-*` self-validation harness had never run — every component was included at `@$CI_COMMIT_SHA`, `$[[ component.version ]]` resolves empty for a SHA ref, so each job pulled `ci-rust:` and died at container attach, masked by `when: manual` + `allow_failure: true`. It runs now, and immediately caught a stale Claude model id, a `container-image` publishing path bug, and an unbound-variable class in `pipeline.just`. It is deliberately still not gating: the repo has no language fixtures, so every go/rust/node validate job would fail on that alone, and a permanently-red gate on the L1 catalog is worse than none. The second thread is supply-chain hygiene: Fedora and UBI10 repoints, and an end to the recurring class where GitLab garbage-collects its own published analyzer digest and reddens a pipeline we never touched. A **minor**: no template input added, removed, or renamed. - **Renovate: UBI9 to UBI10 replacement rules.** `replacement` is its own updateType, separate from `major` — the human-review lane never saw these. - **`validate-*` harness is playable.** Image-tag interpolation fixed and wiring corrected. Stays `manual` + `allow_failure` by deliberate decision until language fixtures exist. - **`ci-runtime-node` on UBI10** (`ubi10/nodejs-22-minimal`), removing ten unfixable HIGH curl/libcurl CVEs — 0 of 107 measured findings had a Red Hat fix, so the base moved rather than the finding being waived. - **Fedora containers repoint** `quay.io` to `registry.fedoraproject.org`. - **hadolint checksum** reads the combined `checksums.sha256` (upstream 2.15.0+). - **Rust jobs build, test and clippy `--locked`.** - **`secret-verdict` no longer pins a digest.** GitLab GC'd its own published `security-products/secrets` digest, which reddened this pipeline twice on an image we never changed; it now tracks the immutable version tag. - **`claude-drift-triage`** default model id corrected. - **`lint-includes`** tolerates an `image:` override on suppressed jobs. - **Eleven `pipeline.just` recipes guarded against unbound `CI_COMMIT_TAG`** under `set -u`. Release paths hard-fail with a clear message; artifact paths skip cleanly. A silent `exit 0` in a release path would report green while publishing nothing. - **`signal-digest.py`** discovers group runners dynamically instead of checking a hardcoded id pair, and its wedged-MR predicate now catches conflict-plus-armed. The old check reported a permanent false WARN on a dead runner while covering neither runner that mattered. - **`platformAutomerge: false` scoped to `dunn.dev/cairn/**`** (was estate-wide), moving the decision into Renovate's own retry loop so it self-heals. - **Stop digest-pinning `registry.gitlab.com/security-products/**`.** Pinning a digest we do not control against a registry that GCs it converts vendor housekeeping into a hard red pipeline.