Skip to content

Skip the qualifying-params lookup for scopes other than given - #2925

Open
ericproulx wants to merge 1 commit into
masterfrom
perf/qualifying-params-given-only
Open

Skip the qualifying-params lookup for scopes other than given#2925
ericproulx wants to merge 1 commit into
masterfrom
perf/qualifying-params-given-only

Conversation

@ericproulx

Copy link
Copy Markdown
Contributor

Summary

A nested scope resolves its params through @parent.qualifying_params.presence, which reads the request's ParamScopeTracker out of fiber storage and looks the parent up in its identity Hash. That runs twice per validator on a nested scope (once in should_validate?, once in the attributes iterator) on every request.

Only #meets_dependency? ever stores qualifying params, and it returns before doing so unless the scope has a dependency, i.e. is a given. Every other scope therefore always answered empty; it now answers nil without the lookups. The sole caller applies .presence, so nil and the previous empty Array behave the same.

Benchmarks

Median of 7 interleaved subprocess rounds against master, Ruby 4.0.6, no JIT:

request delta
JSON POST with a nested requires :user, type: Hash do ... end (3 attributes) +5.4%
flat params GET (control) +0.2% (noise)

Per nested validator: 1.77 → 1.39 µs; per nested scope resolution, about 190 ns saved. The gain grows with nesting depth.

Test plan

  • Full RSpec suite passes locally.
  • RuboCop clean.
  • Mutation-checked through existing specs: inverting the guard, or returning unconditionally, fails 2 given specs each.
  • CI green.

🤖 Generated with Claude Code

A nested scope resolves its params through
`@parent.qualifying_params.presence`, which reads the request's tracker
out of fiber storage and looks the parent up in its identity Hash. That
runs twice per validator on a nested scope, once in `should_validate?`
and once in the attributes iterator, on every request.

Only `#meets_dependency?` ever stores qualifying params, and it returns
before doing so unless the scope has a dependency, i.e. is a `given`.
Every other scope therefore always answered empty, and now does so
without the lookups: about 190 ns per resolution, and a nested validator
went from 1.77 to 1.39 µs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ericproulx
ericproulx force-pushed the perf/qualifying-params-given-only branch from 271a0a6 to 0f02917 Compare September 10, 2026 19:18
@github-actions

github-actions Bot commented Sep 10, 2026

Copy link
Copy Markdown

Danger Report

No issues found.

View run

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.

1 participant