Skip to content

Complete October 2021 GraphQL spec compliance#1930

Open
spawnia wants to merge 13 commits into
masterfrom
fix-single-field-subscription-spec-compliance
Open

Complete October 2021 GraphQL spec compliance#1930
spawnia wants to merge 13 commits into
masterfrom
fix-single-field-subscription-spec-compliance

Conversation

@spawnia

@spawnia spawnia commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Full October 2021 Spec Compliance 🎉

This PR completes webonyx/graphql-php's compliance with the October 2021 GraphQL specification.
After auditing the spec against the implementation, SingleFieldSubscription (section 5.2.3.1) was the last remaining gap.

Changes

Rewrite SingleFieldSubscription validation to match the reference graphql-js implementation:

  • Expand fragments (inline and named) before counting root fields — previously only top-level selections were counted, missing fields contributed via fragments
  • Reject introspection fields (__schema, __type, __typename) at the subscription root
  • Reject @skip/@include directives on top-level selections
  • Handle fragment cycle detection and type condition matching

Test plan

  • 21 new/updated tests mirroring graphql-js's SingleFieldSubscriptionsRule-test.ts (40 assertions)
  • Full test suite passes across PHP 7.4–8.5: make test
  • Static analysis passes across PHP 7.4–8.5: make stan
  • Benchmarks show no regression

🤖 Generated with Claude Code

spawnia added 4 commits June 14, 2026 15:51
🤖 Generated with Claude Code
🤖 Generated with Claude Code

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

Pull request overview

Updates the subscription validation rule to align SingleFieldSubscription with the October 2021 GraphQL spec, particularly around fragment expansion at the subscription root and additional root-level restrictions.

Changes:

  • Rework SingleFieldSubscription validation to expand inline/named fragments before counting top-level subscription fields.
  • Add new validation failures for introspection fields and @skip/@include directives at the subscription root.
  • Add/extend PHPUnit coverage for fragment expansion, recursion handling, introspection fields, directive rejection, and the “no subscription type” skip behavior; document the change in the changelog.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/Validator/Rules/SingleFieldSubscription.php Rewrites validation logic to expand fragments, reject introspection fields, and reject @skip/@include at the subscription root.
tests/Validator/SingleFieldSubscriptionsTest.php Adds extensive tests mirroring graphql-js coverage for the updated subscription rule behavior.
CHANGELOG.md Records the spec-compliance fix under Unreleased.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Validator/Rules/SingleFieldSubscription.php
Comment thread src/Validator/Rules/SingleFieldSubscription.php
spawnia added 2 commits June 14, 2026 16:29
Matches graphql-js behavior: only expand inline fragments and fragment
spreads whose type condition matches the subscription root type.

🤖 Generated with Claude Code
Covers the no-type-condition and non-matching type condition paths
to improve patch coverage.

🤖 Generated with Claude Code
🤖 Generated with Claude Code

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/Validator/Rules/SingleFieldSubscription.php
spawnia and others added 5 commits June 14, 2026 16:45
🤖 Generated with Claude Code
The commonmark.org URL in the @deprecated directive description must
match graphql-js exactly since it's part of the introspection schema.

🤖 Generated with Claude Code

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Comment thread src/Validator/Rules/SingleFieldSubscription.php
Comment thread src/Validator/Rules/SingleFieldSubscription.php
Comment thread CHANGELOG.md
@spawnia spawnia changed the title Fix SingleFieldSubscription to comply with October 2021 spec Complete October 2021 GraphQL spec compliance Jun 14, 2026
October 2021 is fully compliant, September 2025 tracked in #1931.

🤖 Generated with Claude Code
@spawnia spawnia requested review from ruudk and simPod June 14, 2026 15:29

@simPod simPod left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI review note: the @skip/@include rejection appears to be current-draft / graphql-js 17 behavior, not October 2021 behavior. If the intent is to match current graphql-js, the code direction makes sense, but the README/changelog wording around “October 2021 compliance” is misleading.

// Check for @skip/@include on top-level selections
/** @var array<int, DirectiveNode> $forbiddenDirectiveNodes */
$forbiddenDirectiveNodes = [];
foreach ($node->selectionSet->selections as $selection) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

AI review:

@skip/@include are only checked on the operation’s immediate top-level selections here, but subscription root fields can also be contributed by expanded fragments. That means this currently accepts a root field with a forbidden directive when it comes from a fragment:

subscription sub {
  ...frag
}

fragment frag on SubscriptionRoot {
  catSubscribe @include(if: true) {
    meows
  }
}

The draft/reference CollectSubscriptionFields logic applies the directive check during recursive collection, so fragment-contributed root selections should be checked as they are collected too.

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