Skip to content

feat: add new visitor for inline arguments validation - #1577

Merged
SkArchon merged 23 commits into
masterfrom
milinda/eng-9586-routerengine-force-use-of-variables
Jul 15, 2026
Merged

feat: add new visitor for inline arguments validation#1577
SkArchon merged 23 commits into
masterfrom
milinda/eng-9586-routerengine-force-use-of-variables

Conversation

@SkArchon

@SkArchon SkArchon commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

This PR adds a visitor which can be registered by the router, and is used to validate inline arguments. And on top of that allow setting of inline argument values for printing with extensions (this is in case of non-enforced).

@coderabbitai summary

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.

Open Source AI Manifesto

This project follows the principles of the Open Source AI Manifesto. Please ensure your contribution aligns with its principles.

@SkArchon
SkArchon requested a review from a team as a code owner July 6, 2026 17:53
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds inline-argument detection and response extension output, and refactors cost-control collection plus actual cost computation across resolve and execution. It also updates cost-related tests, changelog entries, and release version metadata.

Changes

Inline Arguments Rule

Layer / File(s) Summary
Validator and rule wiring
v2/pkg/astnormalization/inline_arguments.go
Defines inline argument findings and validator options, registers the prevalidation rule, and implements argument traversal that skips variables, records findings, or raises an external error in enforce mode.
Detection and enforcement tests
v2/pkg/astnormalization/inline_arguments_test.go
Adds shared test setup and coverage for literal, variable, directive, skip/include, position, and enforce-mode behavior of inline argument detection.
Resolver response extensions
v2/pkg/engine/resolve/const.go, v2/pkg/engine/resolve/context.go, v2/pkg/engine/resolve/resolvable.go, v2/pkg/engine/resolve/extensions_test.go
Adds resolver context storage for inline arguments, clears it during cleanup, defines response extension literals, serializes extensions.inlineArguments when present, and validates the emitted response shape in resolver tests.

Cost Control and Actual Costing

Layer / File(s) Summary
Resolve cost-control plumbing
v2/pkg/engine/resolve/resolvable.go, v2/pkg/engine/resolve/request.go, execution/engine/execution_engine_test.go
Gates type-name stats collection on cost control, initializes stats lazily, changes request cost handling for missing calculators or stats, and wires the execution test harness to enable cost control when costs are computed.
Actual cost weighting
v2/pkg/engine/plan/cost.go
Separates field and child multipliers, adds runtime implementing-type weighting, and changes debug output formatting.
Execution cost tests and release metadata
execution/engine/execution_engine_cost_test.go, execution/CHANGELOG.md, release-please-manifest.json, v2/CHANGELOG.md
Updates actual-cost expectations, adds null-parent and abstract-field cost coverage, and bumps changelog/version metadata for the release.

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

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.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding inline-arguments validation via a new visitor.
Description check ✅ Passed The description is related to the changeset and explains the new visitor, validation, and extension printing behavior.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch milinda/eng-9586-routerengine-force-use-of-variables

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

@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: 2

🧹 Nitpick comments (1)
v2/pkg/astnormalization/inline_arguments_test.go (1)

46-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a test for validator reuse across multiple operations.

All current tests construct a fresh InlineArgumentsValidator per case, so the accumulation-across-runs behavior flagged in inline_arguments.go (findings/state not cleared automatically between NormalizeOperation calls) isn't exercised here. A test reusing the same validator for two sequential operations would surface whether Findings correctly resets or leaks.

🤖 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/astnormalization/inline_arguments_test.go` around lines 46 - 155, Add
a test in TestInlineArgumentsRule_Detection that reuses the same
InlineArgumentsValidator across two sequential NormalizeOperation calls to
verify Findings/state do not accumulate between runs. Use the existing
runInlineArgumentsRule helper or InlineArgumentsValidator directly, and assert
the second operation’s findings only reflect that operation. Reference
InlineArgumentsValidator, NormalizeOperation, and Findings to locate the
behavior in inline_arguments.go.
🤖 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 `@v2/pkg/astnormalization/inline_arguments.go`:
- Around line 71-75: The inlineArgumentsVisitor struct has embedded-field
spacing that violates the linter rule. Update the inlineArgumentsVisitor
declaration by adding a blank line after the embedded *astvisitor.Walker field
and before the regular fields operation, definition, and validator so the struct
layout matches the expected grouping.
- Around line 38-50: The InlineArgumentsValidator is retaining stale Findings
across reused document walks, so NormalizeOperation can report results from
previous operations; update the validation flow around InlineArgumentsValidator
and OperationNormalizer to clear Findings at the start of each walk instead of
relying on callers to invoke ClearFindings manually. Ensure the reset happens in
the same path that triggers EnterArgument/HadInlineArguments so each document
gets isolated results, and avoid sharing a single validator instance across
concurrent walks unless access is synchronized.

---

Nitpick comments:
In `@v2/pkg/astnormalization/inline_arguments_test.go`:
- Around line 46-155: Add a test in TestInlineArgumentsRule_Detection that
reuses the same InlineArgumentsValidator across two sequential
NormalizeOperation calls to verify Findings/state do not accumulate between
runs. Use the existing runInlineArgumentsRule helper or InlineArgumentsValidator
directly, and assert the second operation’s findings only reflect that
operation. Reference InlineArgumentsValidator, NormalizeOperation, and Findings
to locate the behavior in inline_arguments.go.
🪄 Autofix (Beta)

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: 6bcdea2d-3f98-4624-9c99-09cf3a422029

📥 Commits

Reviewing files that changed from the base of the PR and between 2cc5a87 and c166d91.

📒 Files selected for processing (2)
  • v2/pkg/astnormalization/inline_arguments.go
  • v2/pkg/astnormalization/inline_arguments_test.go

Comment thread v2/pkg/astnormalization/inline_arguments.go Outdated
Comment thread v2/pkg/astnormalization/inline_arguments.go

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
v2/pkg/engine/resolve/context.go (1)

285-307: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

clone() doesn't deep-copy InlineArguments — shared backing array risk.

Files, RenameTypeNames, RemapVariables, and subgraphErrors are all deep-copied in clone(), but the new InlineArguments slice is left as a shallow copy from cpy := *c. Cloned contexts (e.g., per-subgraph fetch contexts) will share the same backing array as the parent, so appends on one side can race with or unexpectedly mutate the other.

🔧 Proposed fix
 	cpy.Files = append([]*httpclient.FileUpload(nil), c.Files...)
 	cpy.Request.Header = c.Request.Header.Clone()
 	cpy.RenameTypeNames = append([]RenameTypeName(nil), c.RenameTypeNames...)
+	cpy.InlineArguments = append([]string(nil), c.InlineArguments...)
🤖 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/resolve/context.go` around lines 285 - 307, The clone() method
in Context is still shallow-copying InlineArguments via cpy := *c, which can
leave cloned contexts sharing the same backing array. Update clone() to
explicitly deep-copy InlineArguments the same way Files and RenameTypeNames are
copied, so per-clone mutations in Context do not affect the original or sibling
clones.
♻️ Duplicate comments (1)
v2/pkg/astnormalization/inline_arguments.go (1)

38-51: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Stale Findings across reused validator — still unresolved.

OperationNormalizer/InlineArgumentsValidator is intended for reuse across NormalizeOperation calls in hot paths, but Findings is only cleared via the manual ClearFindings() method. If InlineArgumentsRule(validator) is registered once and the normalizer reused, findings from prior operations leak into subsequent log-only reports unless every caller remembers to clear them explicitly. Concurrent use of the same validator instance also races on the append in EnterArgument.

This was flagged previously and does not appear to have been addressed — the struct and its ClearFindings/HadInlineArguments API are unchanged from the earlier review round.

Consider clearing Findings at the start of each walk (e.g., in EnterDocument) rather than relying on external callers, and document/enforce non-concurrent use of a shared validator.

🤖 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/astnormalization/inline_arguments.go` around lines 38 - 51, The shared
InlineArgumentsValidator still retains stale Findings between NormalizeOperation
runs and is unsafe when reused concurrently. Update InlineArgumentsValidator so
Findings is reset automatically at the start of each traversal, ideally in
EnterDocument, rather than relying on external ClearFindings calls, and keep
HadInlineArguments reporting only the current walk’s state. Also make the
intended non-concurrent use of a reused validator explicit in the
InlineArgumentsRule/OperationNormalizer usage or comments so callers do not
share one instance across simultaneous walks.
🤖 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.

Outside diff comments:
In `@v2/pkg/engine/resolve/context.go`:
- Around line 285-307: The clone() method in Context is still shallow-copying
InlineArguments via cpy := *c, which can leave cloned contexts sharing the same
backing array. Update clone() to explicitly deep-copy InlineArguments the same
way Files and RenameTypeNames are copied, so per-clone mutations in Context do
not affect the original or sibling clones.

---

Duplicate comments:
In `@v2/pkg/astnormalization/inline_arguments.go`:
- Around line 38-51: The shared InlineArgumentsValidator still retains stale
Findings between NormalizeOperation runs and is unsafe when reused concurrently.
Update InlineArgumentsValidator so Findings is reset automatically at the start
of each traversal, ideally in EnterDocument, rather than relying on external
ClearFindings calls, and keep HadInlineArguments reporting only the current
walk’s state. Also make the intended non-concurrent use of a reused validator
explicit in the InlineArgumentsRule/OperationNormalizer usage or comments so
callers do not share one instance across simultaneous walks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 11a84895-49c5-407e-a97f-5c44fb489527

📥 Commits

Reviewing files that changed from the base of the PR and between c166d91 and 3e3675d.

📒 Files selected for processing (5)
  • v2/pkg/astnormalization/inline_arguments.go
  • v2/pkg/astnormalization/inline_arguments_test.go
  • v2/pkg/engine/resolve/const.go
  • v2/pkg/engine/resolve/context.go
  • v2/pkg/engine/resolve/resolvable.go
✅ Files skipped from review due to trivial changes (1)
  • v2/pkg/engine/resolve/const.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • v2/pkg/astnormalization/inline_arguments_test.go

@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.

🧹 Nitpick comments (1)
v2/pkg/engine/resolve/extensions_test.go (1)

154-180: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Unused no-op authorizer adds noise.

The authorizer at Lines 156-160 always returns nil, nil (never denies) and isn't reflected in the expected output's extensions. It doesn't appear necessary to exercise the rate-limit-deny + inline-arguments interaction.

♻️ Simplify by dropping the no-op authorizer
 	t.Run("rate limit deny & inline arguments", testFnWithPostEvaluation(func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx *Context, expectedOutput string, postEvaluation func(t *testing.T)) {
 
-		authorizer := createTestAuthorizer(func(ctx *Context, dataSourceID string, input json.RawMessage, coordinate GraphCoordinate) (result *AuthorizationDeny, err error) {
-			return nil, nil
-		}, func(ctx *Context, dataSourceID string, object json.RawMessage, coordinate GraphCoordinate) (result *AuthorizationDeny, err error) {
-			return nil, nil
-		})
-
 		limiter := &testRateLimiter{
 			policy:  "policy",
 			allowed: 0,
 			allowFn: func(ctx *Context, info *FetchInfo, input json.RawMessage) (*RateLimitDeny, error) {
 				return &RateLimitDeny{Reason: "rate limit exceeded"}, nil
 			},
 		}
 
 		res := generateTestFederationGraphQLResponse(t, ctrl)
 
 		resolveCtx := NewContext(context.Background())
-		resolveCtx.authorizer = authorizer
 		resolveCtx.rateLimiter = limiter

Separately, consider adding coverage for InlineArguments combined with an authorization deny, and for the resolver context cleanup path (clearing InlineArguments between requests) mentioned in the PR summary — not present in this file.

🤖 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/resolve/extensions_test.go` around lines 154 - 180, The test
case in testFnWithPostEvaluation is carrying an unused no-op authorizer that
never denies and does not affect the expected response, so remove the authorizer
setup and the resolveCtx.authorizer assignment from the “rate limit deny &
inline arguments” scenario. Keep the focus on NewContext, rate limiter,
RateLimitOptions, and InlineArguments so the test only covers the intended
behavior, and consider adding separate coverage elsewhere for InlineArguments
plus an authorization deny and for context cleanup between requests.
🤖 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.

Nitpick comments:
In `@v2/pkg/engine/resolve/extensions_test.go`:
- Around line 154-180: The test case in testFnWithPostEvaluation is carrying an
unused no-op authorizer that never denies and does not affect the expected
response, so remove the authorizer setup and the resolveCtx.authorizer
assignment from the “rate limit deny & inline arguments” scenario. Keep the
focus on NewContext, rate limiter, RateLimitOptions, and InlineArguments so the
test only covers the intended behavior, and consider adding separate coverage
elsewhere for InlineArguments plus an authorization deny and for context cleanup
between requests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 676a45ef-436f-4344-b53d-cb9d373dc13b

📥 Commits

Reviewing files that changed from the base of the PR and between 201ed9a and 7c1f178.

📒 Files selected for processing (1)
  • v2/pkg/engine/resolve/extensions_test.go

ysmolski and others added 4 commits July 7, 2026 17:45
This fix includes basic and often used cases, but it does not include 
some combinations of abstract fields and fragments. 
For those I have included the test cases (disabled right now).

I have simplified how parents are used in calculations. 
I have added children multiplier to distiungish them from the field cost
which is always multiplied even when null was returned on that field.

This solution can be sophisticated further if there is a need for it.
Potentially, I could take different approach of walking the response
from subgraphs and match them with Cost Tree. That would remove
many heuristics and exceptions and make things much more simple.
But that would happen in a separate PR.

`typeNameStats` is populated only when CC is enabled.
🤖 I have created a release *beep* *boop*
---


##
[2.9.1](v2.9.0...v2.9.1)
(2026-07-07)


### Bug Fixes

* do not charge children of null-parents
([#1574](#1574))
([cf436ec](cf436ec))

---
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>
🤖 I have created a release *beep* *boop*
---


##
[1.17.0](execution/v1.16.0...execution/v1.17.0)
(2026-07-07)


### Features

* add defer support part 4
([#1547](#1547))
([8891a0e](8891a0e))


### Bug Fixes

* do not charge children of null-parents
([#1574](#1574))
([cf436ec](cf436ec))

---
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>

@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.

🧹 Nitpick comments (1)
v2/pkg/engine/plan/cost.go (1)

794-847: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider extracting the ACTUAL-mode multiplier adjustment into a helper.

This block (list-size averaging, non-list child discounting, fragment exclusion, and abstract type-share narrowing) is dense and was flagged as high complexity. Splitting it into a small helper (e.g., node.adjustActualMultiplier(input, parentStats)) would make each branch easier to follow and test in isolation, without changing behavior.

🤖 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/plan/cost.go` around lines 794 - 847, The ACTUAL-mode
multiplier adjustment in the cost calculation is too dense and should be split
into a helper for readability and testability. Extract the branching logic from
the multiplier block in the cost adjustment flow into a focused helper such as a
method on the node or a small function near cost.go that handles list-size
averaging, non-list child discounting, fragment-field exclusion, and
abstract-type share narrowing. Keep the existing behavior unchanged by
preserving the current use of node.parent, node.returnsListType,
node.returnsSimpleType, node.returnsAbstractType, node.isEnclosingTypeAbstract,
and input.typeStats while moving the logic into the helper.
🤖 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.

Nitpick comments:
In `@v2/pkg/engine/plan/cost.go`:
- Around line 794-847: The ACTUAL-mode multiplier adjustment in the cost
calculation is too dense and should be split into a helper for readability and
testability. Extract the branching logic from the multiplier block in the cost
adjustment flow into a focused helper such as a method on the node or a small
function near cost.go that handles list-size averaging, non-list child
discounting, fragment-field exclusion, and abstract-type share narrowing. Keep
the existing behavior unchanged by preserving the current use of node.parent,
node.returnsListType, node.returnsSimpleType, node.returnsAbstractType,
node.isEnclosingTypeAbstract, and input.typeStats while moving the logic into
the helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cadd52f9-eef7-4dc9-8e57-d10b7c44b572

📥 Commits

Reviewing files that changed from the base of the PR and between 7c1f178 and c28eb40.

📒 Files selected for processing (8)
  • execution/CHANGELOG.md
  • execution/engine/execution_engine_cost_test.go
  • execution/engine/execution_engine_test.go
  • execution/graphql/request.go
  • release-please-manifest.json
  • v2/CHANGELOG.md
  • v2/pkg/engine/plan/cost.go
  • v2/pkg/engine/resolve/resolvable.go
✅ Files skipped from review due to trivial changes (2)
  • release-please-manifest.json
  • v2/CHANGELOG.md

@SkArchon
SkArchon marked this pull request as ready for review July 7, 2026 12:43
@endigma
endigma requested review from endigma and removed request for endigma July 7, 2026 13:57
Comment thread v2/pkg/astnormalization/inline_arguments.go Outdated
Comment thread v2/pkg/astnormalization/inline_arguments.go Outdated
Comment thread v2/pkg/engine/datasource/graphql_datasource/graphql_datasource.go Outdated

@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.

Comment thread v2/pkg/engine/datasource/grpc_datasource/grpc_datasource.go
Comment thread v2/pkg/astnormalization/inline_arguments.go Outdated
Comment thread v2/pkg/astnormalization/inline_arguments.go Outdated
Comment thread v2/pkg/astnormalization/astnormalization.go
Comment thread v2/pkg/astnormalization/inline_arguments.go Outdated
Comment thread v2/pkg/engine/resolve/resolvable.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.

@SkArchon
SkArchon merged commit fce54b2 into master Jul 15, 2026
10 checks passed
@SkArchon
SkArchon deleted the milinda/eng-9586-routerengine-force-use-of-variables branch July 15, 2026 10:23
SkArchon pushed a commit that referenced this pull request Jul 15, 2026
🤖 I have created a release *beep* *boop*
---


##
[2.12.0](v2.11.0...v2.12.0)
(2026-07-15)


### Features

* add new visitor for inline arguments validation
([#1577](#1577))
([fce54b2](fce54b2))

---
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.

4 participants