Tolerate missing @gl_introduced fields within the introduction milestone
What does this MR do and why?
The @gl_introduced(version:) directive lets out-of-tree clients
(Duo Workflow Service, Language Server) tag query fields with the
GitLab milestone that introduced them. The backend strips tagged
nodes before validation and restores them for execution, so
missing fields resolve to null instead of failing the query.
The old check stripped a field only when its tagged milestone was
strictly greater than the backend milestone. A field tagged with
the backend's own milestone stayed in the query. If the schema
didn't have that field yet, for example on a -pre build or a
stale CI branch on the same milestone, validation failed with an
undefinedField error.
This caused incident gitlab-org/quality/analytics/ci-health-incidents#1195 (closed), which blocked 9 MR pipelines on 2026-08-25. CI jobs booted a Duo Workflow Service that selected a query containing a field the stale branch didn't have yet.
A version string can't prove a mid-milestone field exists, so the introduction milestone now gets a tolerance window (milestone compared as major.minor, patch ignored):
| Tagged milestone vs backend milestone | Behavior |
|---|---|
| Older than the backend | Field must exist; undefinedField error otherwise (unchanged) |
| Backend milestone or later | Resolves normally if present; null if absent (new for the equal case) |
Strictness returns one milestone later, so a typo'd or removed field doesn't null silently forever.
The null fallback is also narrower now. It used to apply to any unknown field once a query contained any stripped node. It now applies only to the field names collected from the stripped nodes, so a typo in an untagged field still raises an error.
Stripping a node used to have validation side effects: a variable or fragment used only inside the stripped subtree looked unused, and a fully stripped selection set looked empty. The tracer now suppresses exactly those errors, so those query shapes work and the old documented limitations for them are removed.
How to verify
- Run
spec/requests/api/graphql/future_fields_spec.rbfor the end-to-end behavior of the three milestone cases. - Run the filter and fallback specs under
spec/lib/gitlab/graphql/version_filter/for the milestone comparison and the field-name-scoped fallback.
References
- Issue: #622471
- Incident: gitlab-org/quality/analytics/ci-health-incidents#1195 (closed)