Class ViewShadowRelation

All Implemented Interfaces:
NamedWriteable, Writeable, Resolvable, Unresolvable

public class ViewShadowRelation extends LeafPlan implements Unresolvable
Marker leaf node that represents a view-name being looked up on linked projects (CPS) as a potential remote index with the same name as a local view. It is emitted by ViewResolver (only when CPS is enabled) as a sibling of each resolved view's recursive substitution, inside the per-resolution-level ViewUnionAll.

Lifecycle, with the parts each PR is responsible for:

  1. Emitted during view resolution alongside the strict (recursive) resolution. The shadow and its strict sibling form the strict/lenient pair for that level. (landed in the ViewResolver refactor)
  2. ViewCompaction.preIndexResolution reshapes user-written Subquery/ UnionAll structures into ViewUnionAll but leaves shadows in place so PreAnalyzer can still pair each shadow with its sibling at index-resolution time. (landed)
  3. PreAnalyzer collects ViewShadowRelation patterns into a separate set, and EsqlSession issues a lenient field-caps request per batch (ALLOW_UNAVAILABLE_TARGETS + project routing scoped to linked projects only — IndexResolver.FLAT_WORLD_OPTIONS). Results land in AnalyzerContext.optionalLinkedResolution, keyed by the shadow's full linkedIndexPattern() (view name + applicable exclusions). (deferred to the lenient field-caps PR)
  4. The ResolveViewShadow analyzer rule (sibling of ResolveTable, in the Initialize batch) consults AnalyzerContext.optionalLinkedResolution for this shadow's linkedIndexPattern(). If a remote index is found the shadow is replaced with a corresponding EsRelation; otherwise the shadow is left unresolved. (this PR — backed by a mocked optionalLinkedResolution map until the lenient field-caps PR provides real data)
  5. ViewCompactionPostIndexResolution runs after ResolveViewShadow: any still-unresolved shadow is stripped, then nested ViewUnionAlls are flattened and remaining NamedSubquery wrappers unwrapped. Per Strategy A in esql-planning#543, sibling EsRelations stay separate (a UnionAll/ViewUnionAll of EsRelations) rather than being merged via a third combined field-caps call. (landed)
The strict, default-options field-caps path on the local cluster keeps resolveViews(true) unchanged, so a remote project that has a view with the same name still fails the query with RemoteViewNotSupportedException. This node only enables lookup of remote indices with the same name as a local view.