Skip to content

fix: do not charge actual cost for denied fields - #1582

Merged
ysmolski merged 5 commits into
masterfrom
yury/eng-9855-do-not-charge-actual-cost-for-denied-fields
Jul 9, 2026
Merged

fix: do not charge actual cost for denied fields#1582
ysmolski merged 5 commits into
masterfrom
yury/eng-9855-do-not-charge-actual-cost-for-denied-fields

Conversation

@ysmolski

@ysmolski ysmolski commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Do not charge actual costs when some feld is denied or
nulled because some of its non-nullable children was null.

We collect stats on render pass in Resolvable too.
This gives easy way to handle stats for nulled items of arrays.

@ysmolski
ysmolski requested a review from a team as a code owner July 8, 2026 13:42
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds authorization-aware actual cost accounting: cost paths move to rendered fieldPath, resolution records cost stats after render-time authorization/null propagation, ComputeActualCost uses resolve context stats, execution gains authorizer options, and tests cover denied-field cost behavior.

Changes

Auth-aware cost accounting

Layer / File(s) Summary
CostTreeNode fieldPath rename and lookups
v2/pkg/engine/plan/cost.go, v2/pkg/engine/plan/cost_visitor.go
CostTreeNode stores fieldPath instead of jsonPath; cost lookup logic uses fieldPath for runtime type stats, abstract-type weighting, list multipliers, unreached-subtree pruning, AST path construction, and debug output.
Render-time rendered-field-path cost tracking
v2/pkg/engine/resolve/resolvable.go
Resolvable records cost-control stats during render using renderFieldPath(); adds reachedFields memoization, centralizes authorization-coordinate derivation, and updates array/object stat collection and reset/init behavior.
ComputeActualCost signature and execution options
execution/graphql/request.go, execution/engine/execution_engine.go
Request.ComputeActualCost now accepts *resolve.Context; the execution engine passes the resolve context and adds authorizer options for post-fetch and pre-fetch field authorization.
Denied-field cost tests
execution/engine/execution_engine_cost_auth_test.go
Adds authorizers and TestExecutionEngine_Cost_DeniedFields subtests covering control cases, pre-fetch and post-fetch denials, non-nullability propagation, and list behavior.

Estimated code review effort: 4 (Complex) | ~60 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 clearly matches the main change: preventing actual cost charges for denied fields.
Description check ✅ Passed The description is directly related to the changeset and describes the new actual-cost and render-pass stats behavior.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yury/eng-9855-do-not-charge-actual-cost-for-denied-fields

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

🤖 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/graphql/request.go`:
- Around line 211-218: Guard resolveCtx before using it in
Request.ComputeActualCost so nil callers don’t panic; keep the existing fallback
behavior of setting actualCost to 0 when cost cannot be computed. Update the
initial nil check in ComputeActualCost to include resolveCtx alongside calc and
resolveCtx.TypeNameStats, and only call calc.ActualCostWithDenials when
resolveCtx is non-nil and has the required stats.

In `@v2/pkg/engine/plan/cost.go`:
- Around line 968-972: The comment on ActualCostWithDenials currently describes
typeNameDenials as JSON paths, but the matching logic in isFieldDenied uses
exact resolver field paths including the leading operation type. Update the
documentation in ActualCostWithDenials and any nearby references to say these
are resolver field paths, not JSON paths, and clarify the required format with
the operation type prefix so callers use the same keys that isFieldDenied
expects.
🪄 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: dfa4049f-399c-4327-b4a3-a842df9dc21f

📥 Commits

Reviewing files that changed from the base of the PR and between 66ef719 and ac3e2ee.

📒 Files selected for processing (8)
  • execution/engine/execution_engine.go
  • execution/engine/execution_engine_cost_auth_test.go
  • execution/graphql/request.go
  • v2/pkg/engine/plan/cost.go
  • v2/pkg/engine/plan/cost_visitor.go
  • v2/pkg/engine/resolve/context.go
  • v2/pkg/engine/resolve/resolvable.go
  • v2/pkg/engine/resolve/resolve.go

Comment thread execution/graphql/request.go Outdated
Comment thread v2/pkg/engine/plan/cost.go Outdated

@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)
execution/engine/execution_engine_cost_auth_test.go (1)

263-284: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Rename the stale test titles
expectedActualCost is 5 in both cases, so only Query.user is charged. Update the titles to match that behavior:

  • denied non-nullable field nulls the parent: earlier sibling is charged... earlier sibling is also not charged
  • subgraph null for non-nullable field nulls the parent: earlier sibling and the field are charged... neither sibling nor the field is charged
🤖 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 `@execution/engine/execution_engine_cost_auth_test.go` around lines 263 - 284,
The affected subtests in execution_engine_cost_auth_test.go have stale names
that no longer match the asserted cost behavior. Update the `t.Run(...)` titles
around the `expectedActualCost` assertions so they describe that only
`Query.user` is charged, using the same test cases and identifiers (`denied
non-nullable field nulls the parent` and `subgraph null for non-nullable field
nulls the parent`) to rename them to the corrected “earlier sibling is also not
charged” and “neither sibling nor the field is charged” wording.
🤖 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 `@execution/engine/execution_engine_cost_auth_test.go`:
- Around line 263-284: The affected subtests in
execution_engine_cost_auth_test.go have stale names that no longer match the
asserted cost behavior. Update the `t.Run(...)` titles around the
`expectedActualCost` assertions so they describe that only `Query.user` is
charged, using the same test cases and identifiers (`denied non-nullable field
nulls the parent` and `subgraph null for non-nullable field nulls the parent`)
to rename them to the corrected “earlier sibling is also not charged” and
“neither sibling nor the field is charged” wording.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c844cd03-fbab-4cef-8e47-96d65598ed53

📥 Commits

Reviewing files that changed from the base of the PR and between 39454aa and 8b2e1b5.

📒 Files selected for processing (5)
  • execution/engine/execution_engine_cost_auth_test.go
  • execution/graphql/request.go
  • v2/pkg/engine/plan/cost.go
  • v2/pkg/engine/plan/cost_visitor.go
  • v2/pkg/engine/resolve/resolvable.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • v2/pkg/engine/plan/cost_visitor.go

Base automatically changed from ENG-9828-router-add-pre-fetch-scope-authorization to master July 9, 2026 15:35
@ysmolski
ysmolski force-pushed the yury/eng-9855-do-not-charge-actual-cost-for-denied-fields branch from 423b398 to dc832f5 Compare July 9, 2026 15:40
@ysmolski
ysmolski merged commit 00d9f66 into master Jul 9, 2026
9 checks passed
@ysmolski
ysmolski deleted the yury/eng-9855-do-not-charge-actual-cost-for-denied-fields branch July 9, 2026 15:44
ysmolski pushed a commit that referenced this pull request Jul 9, 2026
🤖 I have created a release *beep* *boop*
---


##
[2.10.0](v2.9.2...v2.10.0)
(2026-07-09)


### Features

* **resolve:** add opt-in pre-fetch field authorization mode
([#1561](#1561))
([eb3b142](eb3b142))


### Bug Fixes

* do not charge actual cost for denied fields
([#1582](#1582))
([00d9f66](00d9f66))

---
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>
ysmolski pushed a commit that referenced this pull request Jul 10, 2026
🤖 I have created a release *beep* *boop*
---


##
[1.17.1](execution/v1.17.0...execution/v1.17.1)
(2026-07-09)


### Bug Fixes

* do not charge actual cost for denied fields
([#1582](#1582))
([00d9f66](00d9f66))

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

2 participants