Skip to content

feat: implement multi fetch to the same subgraph - #1594

Merged
ysmolski merged 53 commits into
masterfrom
feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph
Aug 13, 2026
Merged

feat: implement multi fetch to the same subgraph#1594
ysmolski merged 53 commits into
masterfrom
feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph

Conversation

@devsergiy

@devsergiy devsergiy commented Jul 16, 2026

Copy link
Copy Markdown
Member

Adds an opt-in MultiFetch optimization: entity fetches that
target the same subgraph and execute in the same parallel wave
are merged into a single upstream request,
cutting the number of subgraph round-trips.

How it works

  • Planner: entity fetches record their normalized upstream operation,
    variables, and request envelope as merge material.

  • Postprocess: the new createMultiFetch stage groups same-datasource entity fetches
    within each parallel wave and merges them into one MultiEntityFetch.
    Member operations are combined via AST merging with collision-safe variable renaming;
    each member becomes an aliased _entities field (f1, f2, …) guarded by @include(if: $includeFN).

  • Loader: a merged fetch renders per-entry representations, sends one request,
    then demuxes the response by alias; per-entry data merging, error partitioning and path rewriting.
    Entries excluded at prepare time (denied, no items) ship includeFN:false and
    an empty representations array, so variable coercion still passes upstream.

Defaults

Off by default at both gates: the postprocess stage is the pipeline's only opt-in stage,
and without the planner flag no merge material is recorded.


Co-authored-by: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Alberto Garcia Hierro alberto@wundergraph.com
Co-authored-by: Yury Smolski 140245+ysmolski@users.noreply.github.com

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ca3e91a0-e99c-4474-88d7-0f86feac722d

📥 Commits

Reviewing files that changed from the base of the PR and between e1be792 and 5a62140.

📒 Files selected for processing (2)
  • v2/pkg/engine/resolve/loader.go
  • v2/pkg/engine/resolve/loader_multi_entity.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • v2/pkg/engine/resolve/loader_multi_entity.go
  • v2/pkg/engine/resolve/loader.go

📝 Walkthrough

Walkthrough

MultiFetch adds planner configuration and postprocessing for merging same-wave federation entity fetches. It records structured operations, builds aliased requests, executes shared requests, and maps results and errors back to individual response paths.

Changes

Federation MultiFetch

Layer / File(s) Summary
Configuration and operation merging
execution/engine/*, v2/pkg/engine/plan/*, v2/pkg/astimport/*, v2/pkg/asttransform/*
Adds MultiFetch configuration, recursive variable renaming, and aliased GraphQL operation merging with include guards.
Datasource recording and request assembly
v2/pkg/engine/datasource/graphql_datasource/*, v2/pkg/engine/datasource/httpclient/*
Records structured subgraph operations, avoids representation-variable collisions, and assembles deterministic request envelopes.
Fetch-tree postprocessing
v2/pkg/engine/postprocess/*
Merges compatible entity fetches within execution waves, rewires dependencies, and renders deferred inputs.
Resolve model and response loading
v2/pkg/engine/resolve/*
Adds multi-entity fetch types, per-entry metadata, shared response loading, result fan-out, and alias-specific error handling.
Integration coverage
execution/engine/execution_engine_multi_fetch_test.go, v2/pkg/engine/**/*_test.go
Covers merged and separate execution, subscriptions, request rendering, dependency waves, variable collisions, empty representations, errors, and response equivalence.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ExecutionEngine
  participant GraphQLPlanner
  participant Postprocessor
  participant Subgraph
  participant MultiEntityLoader

  ExecutionEngine->>GraphQLPlanner: EnableMultiFetch configuration
  GraphQLPlanner->>Postprocessor: Record entity-fetch artifacts
  Postprocessor->>Postprocessor: Merge compatible same-wave fetches
  Postprocessor->>Subgraph: Send aliased merged request
  Subgraph-->>MultiEntityLoader: Return aliased entities and errors
  MultiEntityLoader-->>ExecutionEngine: Fan out results to response paths
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the PR's main change: implementing multi-fetch support for the same subgraph.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph

Comment @coderabbitai help to get the list of available commands.

@ysmolski
ysmolski self-requested a review August 4, 2026 09:47
Comment thread v2/pkg/engine/plan/configuration.go
Comment thread docs/multi-fetch/plan.md Outdated

@ysmolski ysmolski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partial review

Comment thread docs/multi-fetch/review-plan.md Outdated
Comment thread docs/multi-fetch/design-v2.md Outdated
Comment thread v2/pkg/astimport/astimport_test.go Outdated
Comment thread v2/pkg/engine/postprocess/create_multi_fetch.go Outdated
Comment thread v2/pkg/engine/resolve/fetch.go

@ysmolski ysmolski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2nd batch

Comment thread v2/pkg/asttransform/merge_operations.go
Comment thread v2/pkg/engine/datasource/httpclient/input_assembly.go Outdated
Comment thread v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go Outdated
Comment thread v2/pkg/engine/postprocess/postprocess.go Outdated
Comment thread v2/pkg/engine/postprocess/create_multi_fetch.go

@ysmolski ysmolski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another batch

Comment thread execution/engine/execution_engine_multi_fetch_test.go Outdated
Comment thread v2/pkg/engine/postprocess/render_subgraph_inputs.go Outdated
Comment thread v2/pkg/engine/postprocess/create_multi_fetch.go Outdated
Comment thread v2/pkg/engine/resolve/loader.go Outdated
Comment thread v2/pkg/engine/postprocess/create_multi_fetch.go Outdated
Comment thread v2/pkg/engine/resolve/fetch_multi.go Outdated
Comment thread v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go Outdated
Comment thread v2/pkg/astimport/astimport.go Outdated
Comment thread v2/pkg/asttransform/merge_operations.go Outdated
Comment thread v2/pkg/engine/postprocess/create_multi_fetch.go Outdated
@fiam
fiam force-pushed the feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph branch from 9dbfbdd to a5f4e7a Compare August 6, 2026 22:24
@ysmolski
ysmolski marked this pull request as ready for review August 11, 2026 08:48
@ysmolski
ysmolski requested a review from a team as a code owner August 11, 2026 08:48

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_multi_fetch_test.go (1)

895-915: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unused path parameter from employeeProducts.

The closure ignores path. The value always resolves []string{"products"}. The call sites at Line 936 and Line 956 pass different values, which suggests a difference that does not exist.

♻️ Proposed cleanup
-	employeeProducts := func(path string) *resolve.Field {
+	employeeProducts := func() *resolve.Field {
 		return &resolve.Field{
 			Name: []byte("products"),

Then update both call sites to employeeProducts().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_multi_fetch_test.go`
around lines 895 - 915, Remove the unused path parameter from the
employeeProducts closure in multiFetchEmployeeProductsData, then update both
call sites to invoke employeeProducts() without arguments. Preserve the existing
fixed products path and field configuration.
v2/pkg/engine/postprocess/render_subgraph_inputs_test.go (1)

76-84: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a case for disableRewriteOpNames.

Every subtest constructs &renderSubgraphInputs{}, so disableRewriteOpNames is always false and the suffix branch always runs. No test pins the behaviour when the flag is true, where the operation name must stay unsuffixed in both the input and the query plan.

💚 Proposed test case
+	t.Run("suffix is skipped when rewriting operation names is disabled", func(t *testing.T) {
+		const namedSource = `query MyOp($representations: [_Any!]!){_entities(representations: $representations){__typename}}`
+		node := renderInputFetch(t, 3, "MyOp", namedSource, resolve.SubgraphRequestEnvelope{Method: "POST", URL: "http://x"}, fragments, nil)
+		(&renderSubgraphInputs{disableRewriteOpNames: true}).ProcessFetchTree(resolve.Sequence(node))
+		require.Contains(t, renderedInput(t, node), `query MyOp(`)
+		require.NotContains(t, renderedInput(t, node), `MyOp__3`)
+	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/engine/postprocess/render_subgraph_inputs_test.go` around lines 76 -
84, Add a subtest in the operation-name suffix coverage that constructs
renderSubgraphInputs with disableRewriteOpNames enabled, then assert the
rendered input and query-plan operation name remain unsuffixed. Preserve the
existing suffixed behavior test for the default false setting.
v2/pkg/asttransform/merge_operations_test.go (1)

22-31: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a case with an incomplete VariableRename map.

mergeMember always builds a total mapping from the document's own variable definitions. No test therefore reaches the miss path in mergeVariableDefinitions, where a missing key produces an empty variable name. Add a case that omits one variable so the chosen behaviour is pinned.

This relates to the defect raised on v2/pkg/asttransform/merge_operations.go line 68.

💚 Proposed test case
+	t.Run("incomplete variable rename is rejected", func(t *testing.T) {
+		member := mergeMember(t, m1, "_f1", "f1", "includeF1")
+		delete(member.VariableRename, "first")
+		_, err := MergeOperationDocuments("", []OperationMergeMember{member})
+		require.Error(t, err)
+	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/asttransform/merge_operations_test.go` around lines 22 - 31, Add a
merge-operation test case that constructs an OperationMergeMember with a
deliberately incomplete VariableRename map, omitting one variable defined in the
document, so mergeVariableDefinitions exercises its missing-key path and pins
the expected empty-name behavior. Keep the existing mergeMember helper unchanged
for total mappings and target the new case at the merge operation test flow.
v2/pkg/asttransform/merge_operations.go (1)

35-59: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Validate that member aliases, include variables and renamed variable names are unique.

MergeOperationDocuments is exported and trusts the caller for uniqueness. Two members with the same Alias produce two identically aliased root fields. A consumer that demultiplexes the response by alias then collapses both entries and loses one member's data. Two members whose VariableRename maps yield the same target name produce a duplicate variable definition, which the upstream subgraph rejects.

The current caller derives "f"+strconv.Itoa(i+1) and "includeF"+strconv.Itoa(i+1), so it is safe today. A cheap check keeps the invariant enforced at the API boundary.

🛡️ Proposed uniqueness check
 	importer := &astimport.Importer{}
 	nonNullBool := merged.AddNonNullNamedType([]byte("Boolean"))
+	seenAliases := make(map[string]struct{}, len(members))
+	seenVariables := make(map[string]struct{}, len(members))
 	for i, member := range members {
 		if member.Document == nil {
 			return nil, fmt.Errorf("asttransform: member %d has no document", i+1)
 		}
+		if _, ok := seenAliases[member.Alias]; ok {
+			return nil, fmt.Errorf("asttransform: duplicate member alias %q", member.Alias)
+		}
+		seenAliases[member.Alias] = struct{}{}
+		if _, ok := seenVariables[member.IncludeVariable]; ok {
+			return nil, fmt.Errorf("asttransform: duplicate include variable %q", member.IncludeVariable)
+		}
+		seenVariables[member.IncludeVariable] = struct{}{}
+		for _, renamed := range member.VariableRename {
+			if _, ok := seenVariables[renamed]; ok {
+				return nil, fmt.Errorf("asttransform: duplicate merged variable %q", renamed)
+			}
+			seenVariables[renamed] = struct{}{}
+		}
 		mergeVariableDefinitions(merged, opRef, importer, member, nonNullBool)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/asttransform/merge_operations.go` around lines 35 - 59, Update
MergeOperationDocuments to validate member uniqueness before merging: reject
duplicate member Alias values, duplicate include-variable names, and duplicate
target names produced by VariableRename mappings. Track each category
independently, return a descriptive error identifying the conflicting name, and
only proceed to mergeVariableDefinitions and mergeMemberSelection after
validation succeeds.
v2/pkg/engine/postprocess/create_multi_fetch_test.go (1)

478-495: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case for a member document with no operation definition.

TestBuildMergedOperation covers a wrong root field. It does not cover a document that parses to zero operation definitions. That input currently panics in validateEntitiesRootField (see the comment on create_multi_fetch_document.go Lines 75-84). Add the case together with the bounds guard so the abort path is locked.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@v2/pkg/engine/postprocess/create_multi_fetch_test.go` around lines 478 - 495,
The TestBuildMergedOperation cases should include a member whose
SubgraphOperation document has no operation definition, and assert
buildMergedOperation returns an error without panicking. Add the corresponding
bounds guard in validateEntitiesRootField before accessing an operation
definition, preserving the existing invalid-root-field error behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@execution/engine/execution_engine_multi_fetch_test.go`:
- Around line 48-63: The testRoundTripper callback must not call require.NotNil
or require.NoError because it runs on resolver fetch goroutines. Replace those
fatal assertions with non-fatal validation and return an HTTP error response
when the request body is missing or cannot be read, keeping failures reportable
on the test goroutine.

In `@v2/pkg/astimport/astimport.go`:
- Around line 243-266: Update ImportVariableDefinitionWithVariableNameRename to
import and preserve the source variable definition’s Directives, applying the
variable-rename map to each directive before attaching them to
variableDefinition. Ensure MergeOperationDocuments retains VARIABLE_DEFINITION
directives in the merged operation.

In `@v2/pkg/asttransform/merge_operations.go`:
- Around line 64-73: In v2/pkg/asttransform/merge_operations.go lines 64-73,
update mergeVariableDefinitions to use a two-value lookup for
member.VariableRename[origName], return an error when the entry is missing or
empty, and propagate that error through MergeOperationDocuments. In
v2/pkg/asttransform/merge_operations_test.go lines 22-31, add a test that
removes one entry from the map produced by mergeMember and verifies
MergeOperationDocuments returns an error.

In `@v2/pkg/engine/postprocess/create_multi_fetch_document.go`:
- Around line 75-84: The validateEntitiesRootField function must reject
documents with no operation definition or an invalid root SelectionSet reference
before indexing, returning descriptive errors for each case; update
v2/pkg/engine/postprocess/create_multi_fetch_document.go lines 75-84
accordingly. Add a TestBuildMergedOperation case in
v2/pkg/engine/postprocess/create_multi_fetch_test.go lines 478-495 using a
member document without an operation definition and assert that
buildMergedOperation returns an error.

In `@v2/pkg/engine/postprocess/render_subgraph_inputs.go`:
- Around line 76-89: Make both `sjson.SetRawBytes` and `op.PrintedQuery()`
failures observable in the render flow instead of returning with an empty
request. Check and record each error on the plan, or attach a non-empty error
marker that `processSingleFetch` preserves, so `fetch.SubgraphOperation` is not
silently replaced by an unrecoverable empty `Input`. Keep successful variable
assembly and query rendering unchanged.

---

Nitpick comments:
In `@v2/pkg/asttransform/merge_operations_test.go`:
- Around line 22-31: Add a merge-operation test case that constructs an
OperationMergeMember with a deliberately incomplete VariableRename map, omitting
one variable defined in the document, so mergeVariableDefinitions exercises its
missing-key path and pins the expected empty-name behavior. Keep the existing
mergeMember helper unchanged for total mappings and target the new case at the
merge operation test flow.

In `@v2/pkg/asttransform/merge_operations.go`:
- Around line 35-59: Update MergeOperationDocuments to validate member
uniqueness before merging: reject duplicate member Alias values, duplicate
include-variable names, and duplicate target names produced by VariableRename
mappings. Track each category independently, return a descriptive error
identifying the conflicting name, and only proceed to mergeVariableDefinitions
and mergeMemberSelection after validation succeeds.

In
`@v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_multi_fetch_test.go`:
- Around line 895-915: Remove the unused path parameter from the
employeeProducts closure in multiFetchEmployeeProductsData, then update both
call sites to invoke employeeProducts() without arguments. Preserve the existing
fixed products path and field configuration.

In `@v2/pkg/engine/postprocess/create_multi_fetch_test.go`:
- Around line 478-495: The TestBuildMergedOperation cases should include a
member whose SubgraphOperation document has no operation definition, and assert
buildMergedOperation returns an error without panicking. Add the corresponding
bounds guard in validateEntitiesRootField before accessing an operation
definition, preserving the existing invalid-root-field error behavior.

In `@v2/pkg/engine/postprocess/render_subgraph_inputs_test.go`:
- Around line 76-84: Add a subtest in the operation-name suffix coverage that
constructs renderSubgraphInputs with disableRewriteOpNames enabled, then assert
the rendered input and query-plan operation name remain unsuffixed. Preserve the
existing suffixed behavior test for the default false setting.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 86bf69d8-64f4-47ae-b44d-07da8c1b3ae2

📥 Commits

Reviewing files that changed from the base of the PR and between 165b1f5 and 1c3854e.

📒 Files selected for processing (36)
  • execution/engine/engine_config.go
  • execution/engine/execution_engine.go
  • execution/engine/execution_engine_multi_fetch_test.go
  • v2/pkg/astimport/astimport.go
  • v2/pkg/astimport/astimport_test.go
  • v2/pkg/asttransform/merge_operations.go
  • v2/pkg/asttransform/merge_operations_test.go
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_multi_fetch_test.go
  • v2/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go
  • v2/pkg/engine/datasource/httpclient/httpclient_test.go
  • v2/pkg/engine/datasource/httpclient/input_assembly.go
  • v2/pkg/engine/plan/configuration.go
  • v2/pkg/engine/plan/datasource_configuration.go
  • v2/pkg/engine/plan/multihop_compound_key_test.go
  • v2/pkg/engine/plan/planner_configuration.go
  • v2/pkg/engine/postprocess/create_multi_fetch.go
  • v2/pkg/engine/postprocess/create_multi_fetch_document.go
  • v2/pkg/engine/postprocess/create_multi_fetch_test.go
  • v2/pkg/engine/postprocess/deduplicate_single_fetches.go
  • v2/pkg/engine/postprocess/postprocess.go
  • v2/pkg/engine/postprocess/postprocess_test.go
  • v2/pkg/engine/postprocess/render_subgraph_inputs.go
  • v2/pkg/engine/postprocess/render_subgraph_inputs_test.go
  • v2/pkg/engine/postprocess/resolve_input_templates.go
  • v2/pkg/engine/resolve/fetch.go
  • v2/pkg/engine/resolve/fetch_multi.go
  • v2/pkg/engine/resolve/fetch_test.go
  • v2/pkg/engine/resolve/fetchtree.go
  • v2/pkg/engine/resolve/fetchtree_test.go
  • v2/pkg/engine/resolve/loader.go
  • v2/pkg/engine/resolve/loader_multi_entity.go
  • v2/pkg/engine/resolve/loader_multi_entity_test.go
  • v2/pkg/engine/resolve/loader_test.go
  • v2/pkg/engine/resolve/tainted_objects.go
  • v2/pkg/engine/resolve/tainted_objects_test.go

Comment thread execution/engine/execution_engine_multi_fetch_test.go
Comment thread v2/pkg/astimport/astimport.go
Comment thread v2/pkg/asttransform/merge_operations.go Outdated
Comment thread v2/pkg/engine/postprocess/create_multi_fetch_document.go
Comment thread v2/pkg/engine/postprocess/render_subgraph_inputs.go

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

Claude Code Review is paused for this repository. To reconnect it, an admin of this repository's GitHub organization (or the account owner, for personal repositories) who can also manage your Claude organization's Code Review settings needs to re-link GitHub in Code Review settings. This is a one-time step.

Tip: disable this comment in your organization's Code Review settings.

@ysmolski
ysmolski force-pushed the feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph branch 2 times, most recently from 43284b7 to 227e3b7 Compare August 13, 2026 08:35
devsergiy and others added 9 commits August 13, 2026 12:06
Detailed spec for merging same-subgraph entity fetches into one aliased
_entities request: postprocess createMultiFetch stage, resolve.MultiEntityFetch,
astimport cross-document selection import with variable renaming, loader
prepare/merge, ART tracing and query plans. Includes user Q&A decisions and
the corrections from an adversarial verification pass against the codebase.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Key corrections: dual sjson input shapes (v1.0.4 prepend in-repo vs append
downstream), order-agnostic input scanner, public-API-only document merge,
record-time representations-collision guard, error-preserving variable
recording helper, expanded test coverage per review findings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shape-neutral envelope remainder, survivor-ID rewrite for all member IDs,
satisfiable per-DeferID fixtures, per-entry out copying, all-excluded early
return before rate limiting, hardened scanner rules, verified test-harness
instructions, printer-accurate directive spacing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Unique-match fail-safe for the append-shape query anchor, dedupe-proof test
fixtures, excluded-entry carve-out in error fan-out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…equest (MultiFetch)

Opt-in via plan.Configuration.EnableMultiFetch + postprocess.EnableMultiFetch().
The graphql datasource records the normalized upstream operation document and
its body.variables fragments on the fetch configuration; a new postprocess
stage groups same-wave entity fetches per subgraph and defer scope, merges
their documents through new astimport cross-document selection-set import
with variable renaming, and emits a resolve.MultiEntityFetch whose aliased
_entities fields are guarded by @include(if: $includeFN) booleans. The
loader renders per-entry representations with per-entry dedup and
authorization, fires one request, and demuxes the response per alias through
the existing mergeResult machinery with per-entry error attribution.

Spec: docs/multi-fetch/spec.md. Plan: docs/multi-fetch/plan.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fetch backpointer

Entry items no longer reference the replaced member fetch (kept the merged-away
SingleFetch and its MergeableOperation document alive in the cached plan, and a
multi backpointer would make plans cyclic, breaking structural comparison).
Deduplicate the merged DependsOnFetchIDs union and strip empty static segments
from entry representations templates. Rewrite the datasource multi-fetch tests
onto datasourcetesting.RunTest with full expected-plan equality.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Level-by-level walkthrough (planning, postprocessing, runtime, observability)
with file and test maps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ysmolski
ysmolski force-pushed the feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph branch from 227e3b7 to 0dd960e Compare August 13, 2026 09:06
@ysmolski
ysmolski merged commit 22584e2 into master Aug 13, 2026
10 checks passed
@ysmolski
ysmolski deleted the feat/router-62-engine-batch-entity-resolution-requests-to-the-same-subgraph branch August 13, 2026 10:11
ysmolski pushed a commit that referenced this pull request Aug 13, 2026
🤖 I have created a release *beep* *boop*
---


##
[2.16.0](v2.15.1...v2.16.0)
(2026-08-13)


### Features

* implement multi fetch to the same subgraph
([#1594](#1594))
([22584e2](22584e2))
* schedule fetch trees optimally
([#1612](#1612))
([bd03deb](bd03deb))


### Bug Fixes

* check interface implementation in `potentiallySameObject` for
nullability relaxation
([#1454](#1454))
([5bacb9e](5bacb9e))
* improve handling of nullable lists for required fields
([#1631](#1631))
([0af4dd3](0af4dd3))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

Co-authored-by: wundergraph-bot[bot] <285992168+wundergraph-bot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants