Skip to content

[libgraphql-core-v1] Task 16.6a: Validate @oneOf input object constraints#105

Merged
jeffmo merged 1 commit into
mainfrom
lgcore_v1_task16.6a
Jul 7, 2026
Merged

[libgraphql-core-v1] Task 16.6a: Validate @oneOf input object constraints#105
jeffmo merged 1 commit into
mainfrom
lgcore_v1_task16.6a

Conversation

@jeffmo

@jeffmo jeffmo commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Task 16.6a (first of the six schema-hardening PRs from the Task 16.5 audit): implement the @oneOf input-object validation the audit found entirely missing — input X @oneOf { a: Int! } previously built without error despite being invalid per the September 2025 spec's Input Objects Type Validation rules.

What & why

Per spec, every field of a @oneOf input object must (a) have a nullable type and (b) declare no default value — a oneOf input represents exactly one caller-supplied choice, so a required field or an always-present default is contradictory.

  • New validate_oneof_constraints() in the existing InputObjectTypeValidator (already orchestrated by SchemaBuilder::build() step 4 — zero new wiring)
  • Two precisely-targeted TypeValidationErrorKind variants rather than one merged kind: InvalidNonNullableOneOfInputField (span → the offending type annotation, where the ! lives) and InvalidOneOfInputFieldWithDefaultValue (span → the field). A field violating both reports both. Each carries an ErrorNote::spec link
  • Nullability is the field's outer type nullability per spec: [Int]! is rejected, [Int!] is accepted
  • Detection matches the annotation name "oneOf" — sound because absorb_directive() rejects user redefinition of builtins, so any annotation with that name is the genuine builtin. Argument-level directive-application validation is out of scope (owned by Task 16.6f)

Tests (9 new)

7 unit: valid oneOf; non-nullable rejected; defaulted rejected; both-violations-on-one-field reports two errors; non-oneOf control (constraints must not leak); [Int]! rejected / [Int!] accepted list-nullability pair.
2 end-to-end via build_from_str: proves the annotation survives the full parse → builder → validator pipeline, plus the valid-oneOf happy path.

Known gap (tracked, blocked on 16.6b)

extend input X @oneOf is invisible today because all type extensions are silently dropped (16.6b's charter). The plan doc now requires a oneOf-via-extension regression test as part of 16.6b.

Verification

  • cargo test --workspace — 1322 tests green (217 in v1, up from 208)
  • cargo clippy --workspace --tests -- -Dwarnings — clean
  • Opus sub-agent review completed pre-PR: no blockers; both should-fixes applied (list-nullability tests, extension-gap tracking); import-style nit fixed
  • Plan doc updated with [x] boxes + Completion Notes per the Execution Protocol (same commit)

🤖 Generated with Claude Code

https://claude.ai/code/session_01TipQtpvuLuHjHmRsVEgwJw


Generated by Claude Code

Implements Task 16.6a from the v1 plan. The @OneOf directive was
registered as a builtin since Task 14, but nothing enforced its
type-validation constraints -- a schema like `input X @OneOf { a: Int! }`
built silently despite being invalid per the September 2025 spec.

Per the spec's Input Objects Type Validation rules, every field of a
@OneOf input object must have a nullable type and must not declare a
default value (each input represents exactly one choice, so a required
field or an always-present default would be contradictory).

The check lives in the existing InputObjectTypeValidator (already
orchestrated by SchemaBuilder::build() step 4, so no new wiring), with
two new precisely-targeted TypeValidationErrorKind variants rather than
one merged kind -- a field violating both rules reports both errors,
and each error's span points at the offending construct (the type
annotation for nullability; the field for defaults). Both carry
ErrorNote::spec links per the plan's error-note convention.

Detection matches the directive annotation by name; argument-level
validation of directive applications is out of scope here (owned by
Task 16.6f).

Tests: 5 unit tests (valid oneOf, non-nullable rejected, defaulted
rejected, both-violations reports two errors, non-oneOf control) plus
2 end-to-end build_from_str tests proving the annotation survives the
full parse -> build -> validate pipeline. Plan doc updated with
completion notes per the Execution Protocol.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TipQtpvuLuHjHmRsVEgwJw

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

Implements GraphQL September 2025 spec validation for @oneOf input objects in libgraphql-core-v1, ensuring schema builds fail when @oneOf fields violate the required constraints (outer type must be nullable; no default values).

Changes:

  • Added InputObjectTypeValidator::validate_oneof_constraints() and wired it into the existing input-object validation flow.
  • Introduced two new TypeValidationErrorKind variants for precise, separately-reportable oneOf violations (non-nullable field; default value).
  • Added unit + end-to-end tests covering valid/invalid @oneOf cases, including list outer-nullability behavior, and updated the v1 plan doc completion notes.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
libgraphql-core-v1-plan.md Marks Task 16.6a complete and documents implementation notes + the known extension-gap follow-up.
crates/libgraphql-core-v1/src/validators/input_object_type_validator.rs Adds @oneOf constraint validation and runs it as part of input-object type validation.
crates/libgraphql-core-v1/src/schema/type_validation_error.rs Adds dedicated error kinds/messages for @oneOf field constraint violations.
crates/libgraphql-core-v1/src/validators/tests/input_object_type_validator_tests.rs Adds unit tests for @oneOf constraint enforcement (including list outer nullability).
crates/libgraphql-core-v1/src/schema/tests/schema_builder_tests.rs Adds end-to-end build tests verifying @oneOf violations are surfaced through build_from_str.

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

@jeffmo jeffmo merged commit 58ba666 into main Jul 7, 2026
8 checks passed
@jeffmo jeffmo deleted the lgcore_v1_task16.6a branch July 7, 2026 23:35
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