Add MFE version overrides table and resolver

What does this MR do and why?

Part 3 of the registry-direct MFE series: the runtime data layer — a single mfe_version_overrides table and the resolver that decides which version of each MFE an instance serves.

  • One row per app: name, version, manifest_sha256 (the sha256 of the app's registry version-manifest bytes, as published in the registry app index), activated_gitlab_version (GitLab MAJOR.MINOR recorded at activation), updated_by_id (loose FK, async-nullify).
  • Gitlab::Mfe::Resolver.resolve(name) serves the override only while (a) the instance has not been downgraded below the activation version and (b) the override is still newer than the baked version — otherwise baked, with a reason code for admin-UI tooltips. A GitLab upgrade whose baked version overtakes the override naturally reclaims serving.
  • Overrides are read once per request (SafeRequestStore); an unreadable database degrades to baked-only with one structured log — MFEs can never take a page down.
  • Nothing in product code writes or reads this table yet; the admin API (next part) and the runtime loader consume it.

How to verify

bin/rspec spec/models/mfe/ spec/lib/gitlab/mfe/resolver_spec.rb

Stack

# Scope MR
1 Config section + instance kill switch !246732 (merged)
2 Vendor pin file + registry manifest schema + verified bake task !246736 (closed)
3 Version overrides table + resolver this MR
4 Admin API + routes + sidebar !246758 (closed)
5 Admin UI (Vue) !246764 (closed)
6a Runtime loader: gon contract, manifest verification + SRI, baked fallback, CSP connect-src !246775 (closed)
6b Duo Chat consumer behind mfe_duo_chat !246778 (closed)
7 Developer mode (local dev server + HMR) !246833 (closed)

Related to #605798.

Edited by Illya Klymov

Merge request reports

Loading