Enable status on epics behind a feature flag
What does this MR do and why?
Second of three backend MRs bringing status to Epics. This one enables status on the Epic type behind a feature flag and makes reads correct in every namespace, without touching any admin lifecycle configuration. It builds directly on the lifecycle provider that landed in !245353 (merged).
Part of #606012 (closed), under epic gitlab-org#17709. No issue-closing footer is set on purpose: the issue and epic stay open until the whole thing ships.
The problem
Status ships on Issue and Task today. Epics are group-level and resolve nothing: epic is not in the system-defined lifecycle base types and has no status widget. In a namespace that uses custom lifecycles, an epic would fall back to the system-defined lifecycle while issues use the custom one, which breaks the invariant that a namespace uses either system-defined or custom statuses, never both.
What this MR does (all behind work_item_status_for_epics, default off)
- Adds
:epicto the system-defined lifecycle base types and thestatuswidget to the Epic type definition. - Adds the
work_item_status_for_epicsfeature flag (wip, root-ancestor scoped) and rejects thestatuswidget for Epic when the flag is off, so the type is fully dormant until rollout. - Teaches the lifecycle provider to mask: a status-supporting type with no direct custom-lifecycle connection resolves to the Issue lifecycle (or the first available). Epic mirrors Issue, so there is no system-vs-custom divergence and no backfill is needed. The mask is capability-driven (does the type expose the status widget), so it is not epic-specific.
- Makes
supports_status?widget-aware, so the webhook / hook-data capability sites honor the same gate. - Persists the real type-to-lifecycle connection on the first status write to an epic, so the masked state converges to a real row without a backfill and without writing on reads.
- Closes the validation-layer airtightness gap so that with the flag off, a system-defined status is not considered valid for epic.
What this MR deliberately does NOT do (that is MR 3)
- Nothing that only matters when an admin changes the lifecycle afterward: mapping generation when a status is removed, pinning epics when the Issue type is reassigned to another lifecycle, delete protection, and the admin lifecycles-view projection.
Verification
Model and service specs cover the flag on and off, the mask (custom hit and fallback), persist-on-write, and supports_status?. Manual validation on both a system-defined and a custom-lifecycle group.