pipeline v5.8.0 -- L0 gate branch-push coverage + catalog Renovate policy

Gate-coverage repair and catalog-side Renovate policy. The L0 gate now
instantiates on a bare branch push -- roughly a quarter of consumer repos
were reporting green having evaluated zero gate logic -- and
`automerge-gate` gained a second independent cargo-verdict slot. The
estate preset picked up an internal-trust exemption from
`minimumReleaseAge` and wasmtime-family grouping. Separately, this
catalog's own Renovate bot gained a signal digest, a token-expiry alarm,
CI validation of the preset, and stage decoupling (catalog-internal --
nothing a consumer pins or extends moves with those).

- **`automerge-gate`: `cargo_job_2` -- gate on a second independent
  cargo-verdict job.** A repo with 2+ Cargo manifests and no root
  manifest (nomograph/extension: `host/` + `crates/extension-host/`)
  could not vouch itself through the L0 gate -- `cargo_job` had exactly
  one needs: slot, so extension shipped hand-rolled CI instead (see its
  `.gitlab-ci.yml` header). `cargo-verdict` gained a `check_name` input
  (default `"cargo"`, unchanged) so a second instance can emit
  `CHECK_CARGO_HOST`/`CHECK_CARGO_EXTENSION_HOST` instead of colliding on
  `CHECK_CARGO`; `automerge-gate` gained `cargo_job_2` pointing at that
  instance's `job_name`, plus a hyphen-to-underscore fold when resolving
  `required-checks` names to `CHECK_<NAME>` variables (needed for
  hyphenated multi-cargo check names; a no-op for the existing bare
  `osv`/`cargo` names). `cargo_job_2` defaults to a sentinel job name no
  consumer defines, so every existing single-cargo-job consumer is
  unaffected (verified: `needs: job: <undefined-name> optional: true`
  lints valid with no such job in the pipeline). A third manifest would
  follow the identical pattern (`cargo_job_3`); not shipped preemptively.
- **Renovate: internal-trust exemption from `minimumReleaseAge`, all update
  types including major.** `minimumReleaseAge: "7 days"` exists to give a
  compromised third-party release time to be caught before we consume it --
  there is no third party in the loop for artifacts we author, build, and
  tag ourselves. Two new `packageRules` set `minimumReleaseAge: null` for
  the nomograph/pipeline catalog itself (both the `component:` includes and
  the `${NOMOGRAPH_REGISTRY}`-prefixed images collapse to
  depName/packageName `nomograph/pipeline` on the `gitlab-tags` datasource
  -- verified against Renovate's `gitlab-ci` manager source), our own
  crates (`nomograph-claim`, `nomograph-workflow`, confirmed live on
  crates.io), and the `gitlab-releases`-datasource mise tools
  (`andunn/dkg`, `gapvec`, `glean`). Majors deliberately keep
  `automerge: false` via the existing major-updates rule -- a major can
  still break consumers and the releaser owns consumer green, so the age
  gate is gone but human review is not. Mirrors the equivalent (narrower)
  rule in `dunn.dev/pipeline`'s preset.
- **Renovate: group the wasmtime crate family into one MR.** `wasmtime` and
  every `/^wasmtime-/` crate are pinned in lockstep by a shared
  `wasmtime-environ` exact-pin, so Renovate splitting them into separate MRs
  produced MRs that were each red in isolation -- including a security pair
  that could not be landed incrementally (observed on `extension`: !14,
  a security fix bumping `wasmtime` to 46.0.2, broke Cargo resolution
  against `wasmtime-wasi` =46.0.1; !13 bumping `wasmtime-wasi` to v47 left
  two `wasmtime` versions in one graph with cross-version type mismatches;
  both sat red until landed together as `extension!15`). New `packageRules`
  entry sets `groupName: "wasmtime family"` only -- majors keep
  `automerge: false` from the existing major-updates rule, minor/patch keep
  automerge from the minor+patch rule, and a mixed-type group will not
  automerge because its updates disagree, which is the correct conservative
  outcome.
- **Renovate bot: signal digest + token-expiry alarm** (catalog-internal;
  no template or preset behavior moves). Parity port from
  `dunn.dev/pipeline` so both estates run the same alerting logic. New
  `scripts/signal-digest.py` and a scoped `justfile` (this repo had none;
  other jobs call scripts directly) drive a `signal-digest` job that runs
  after the scheduled scan with `when: always` and folds five cheap health
  signals -- the scan's own trace and `artifactErrors`, every configured
  group's Dependency Dashboard "Errored" section, every repo's
  default-branch pipeline status, runner liveness, and wedged MRs -- into
  one pinned GitLab issue, plus an optional webhook. `renovate-token-check`
  reds within 30 days of `RENOVATE_TOKEN_EXPIRES` (a PAT cannot introspect
  its own expiry, so the date is carried in that variable and updated on
  rotation). No new secret: `GITLAB_TOKEN` maps from the `RENOVATE_TOKEN`
  the scan already holds. Adapted rather than copied blind -- both jobs use
  this repo's digest-pinned alpine and default `storr` tag, and
  `signal-digest`'s rules carry the sibling `renovate` job's `$RENOVATE ==
  "true"` guard so the weekly container-rebuild schedule (where `renovate`
  does not run) does not fail pipeline creation on `needs: [renovate]`.
- **CI: `validate-renovate` gate on this repo's own preset**
  (catalog-internal). Edits to `renovate.json` / `renovate-config.json` now
  run `renovate-config-validator --strict` inside the same digest-pinned
  `renovate/renovate` image the bot pulls, on MR and on main push -- so a
  green pipeline means that exact bot build accepts the config, not that it
  parsed on a laptop. Every preset edit before this landed unchecked.

- **`automerge-gate`, `osv-verdict`, `cargo-verdict`: gate never
  instantiates on a bare branch push.** All three `rules:` blocks matched
  only `$CI_PIPELINE_SOURCE == "merge_request_event"` or
  `$CI_COMMIT_BRANCH == "main"` -- a Renovate bot branch pushed but not
  yet carrying an open MR pipeline is neither, so the gate and its verdict
  producers simply did not run: `needs: optional: true` swallowed the
  absent job, and the pipeline reported green having evaluated zero gate
  logic. Added a third clause, `if: $CI_COMMIT_BRANCH &&
  $CI_OPEN_MERGE_REQUESTS == null`, scoped so it fires only when the
  branch carries no open MR yet: once an MR opens, its
  `merge_request_event` pipeline (clause above) independently covers the
  same push, so the branch-pipeline copy stays out of the way instead of
  duplicating a full OSV scan / `cargo build --all-features` + test run
  on every push thereafter. The first push after MR creation still races
  GitLab populating `$CI_OPEN_MERGE_REQUESTS`, so one duplicated run per
  MR remains -- accepted, not engineered away. Verified via `ci/lint`
  against a synthetic consumer carrying the refined 3-clause shape
  (`valid: true`, no errors). Measured across the estate: roughly 25 of
  97 consumer repos were losing gate coverage in branch context before
  this fix.
- **Renovate bot: `needs: []` decouples the scan from every prior stage**
  (catalog-internal). The `renovate` job sits in the last stage with no
  `needs:`, so GitLab's stage-sequential default made it wait on all of
  `lint` -- confirmed on scheduled pipeline 2724786185, where all seven
  lint-stage jobs ran to completion before the scan started. A failing or
  stuck earlier-stage job (a container build on a rotated base-image
  digest, say) would then block or skip the one job positioned to fix it.
  `needs: []` lets it run on schedule regardless, matching
  `dunn.dev/pipeline` (05ce0f7c) and `yotoshelf/pipeline`'s existing
  convention.