When a named shared fragment is the whole selection on a union field
({ ...FeedItemFields }), hoist that type once into a GraphQLUnions module
and alias it per query — so the same union across queries is one Ruby
type family (one exhaustive case ... T.absurd) instead of a fresh
dispatch module per query. Mirrors the shared-inputs machinery:
per-query codegen records hoisted fragments (used_union_names), a
UnionRefNode references the shared type, generate_unions builds it once,
query modules require_relative "unions" and alias what they use.
No flag — the shared fragment is the opt-in. Triggers only for an exact
lone bare spread; mixing other fields, a directive on the spread, or a
query-local fragment of the same name keeps the union inlined. Dynamic
parse still inlines (no cross-query set to share).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>