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.