[libgraphql-core-v1] Task 16.6c: Deprecation validations (2.6 + @deprecated-on-required)#107
Merged
Conversation
…n-required) Implements Task 16.6c from the v1 plan: - DeprecationState::from_directives() computes deprecation on demand from a type element's directive annotations; new deprecation_state() accessors on FieldDefinition, ParameterDefinition, and InputField. Computed (not stored) so the 16.6b extension-merge construction paths are automatically covered with no builder plumbing. An omitted reason yields the spec's default "No longer supported" (now also used by the builtin @deprecated seed); an explicit null reason yields None. - IsValidImplementation step 2.6 (verified verbatim from the Sep2025 spec text: "If {field} is deprecated then {implementedField} must also be deprecated"): an implementing field may be @deprecated only if the interface field it implements is also deprecated. New DeprecatedFieldImplementingNonDeprecatedInterfaceField error with the span on the offending @deprecated annotation and a note pointing at the non-deprecated interface field. Replaces the long-standing TODO in object_or_interface_type_validator. The converse (deprecated interface field, non-deprecated implementer) is legal and tested. - @deprecated must not appear on required (non-null, defaultless) arguments or input fields: DeprecatedRequiredParameter, DeprecatedRequiredInputField, and DeprecatedRequiredDirectiveParameter enforced at build() time over merged types, so extension-contributed params/fields are covered. Help notes explain the make-it-optional escape hatch. 28 tests added (accessor semantics incl. reason defaults, validator matrices incl. transitive-interface and converse-OK cases, extension- path regressions, end-to-end build_from_str cases). 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
…ns doc
- Standardize the IsValidImplementation step label to the spec's own
numeric "2.6" everywhere (code comments, tests, plan doc) -- the
September2025 source text numbers the steps 2.1-2.6; "2.f" was the
audit's paraphrase. Rule existence and direction re-verified verbatim
against the September2025 tag: "If {field} is deprecated then
{implementedField} must also be deprecated."
- Document find_deprecated_annotation's first-wins behavior for
(spec-invalid) duplicate @deprecated annotations, with a pointer to
Task 16.6f's 5.7.3 validation that will reject duplicates outright.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TipQtpvuLuHjHmRsVEgwJw
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens libgraphql-core-v1 schema validation around deprecations by (1) making deprecation state queryable on-demand from directive annotations, (2) enforcing IsValidImplementation step 2.6 deprecation consistency for implementing fields, and (3) prohibiting @deprecated on required (non-null, defaultless) arguments and input fields (including directive definition parameters).
Changes:
- Add
DeprecationState::from_directives()(+DEFAULT_REASON) anddeprecation_state()accessors onFieldDefinition,ParameterDefinition, andInputField. - Enforce IsValidImplementation step 2.6: an implementing field marked
@deprecatedmust not implement a non-deprecated interface field, with spans targeted to the@deprecatedannotation. - Enforce
@deprecatedprohibition on required arguments/input fields at build/validation time across objects/interfaces, input objects, and custom directive definitions, plus extensive new tests (including extension-merge regressions).
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| libgraphql-core-v1-plan.md | Updates plan checklist/notes to reflect 16.6c completion and the standardized “2.6” label. |
| crates/libgraphql-core-v1/src/validators/object_or_interface_type_validator.rs | Implements IsValidImplementation 2.6 enforcement and required-parameter @deprecated prohibition with targeted spans + notes. |
| crates/libgraphql-core-v1/src/validators/input_object_type_validator.rs | Adds required input-field @deprecated prohibition with targeted spans + notes. |
| crates/libgraphql-core-v1/src/validators/directive_definition_validator.rs | Adds required directive-parameter @deprecated prohibition for custom directives. |
| crates/libgraphql-core-v1/src/types/deprecation_state.rs | Adds directive-driven deprecation computation and a helper to locate @deprecated annotations. |
| crates/libgraphql-core-v1/src/types/field_definition.rs | Adds FieldDefinition::deprecation_state() accessor. |
| crates/libgraphql-core-v1/src/types/parameter_definition.rs | Adds ParameterDefinition::deprecation_state() accessor. |
| crates/libgraphql-core-v1/src/types/input_field.rs | Adds InputField::deprecation_state() accessor. |
| crates/libgraphql-core-v1/src/types/mod.rs | Re-exports find_deprecated_annotation for validator span targeting. |
| crates/libgraphql-core-v1/src/schema/type_validation_error.rs | Adds new TypeValidationErrorKind variants for the new deprecation validations. |
| crates/libgraphql-core-v1/src/schema/schema_builder.rs | Centralizes the builtin @deprecated default reason via DeprecationState::DEFAULT_REASON. |
| crates/libgraphql-core-v1/src/types/tests/deprecation_state_tests.rs | Adds unit tests for accessor semantics and default/null reason handling. |
| crates/libgraphql-core-v1/src/validators/tests/object_or_interface_type_validator_tests.rs | Adds validator-level tests for 2.6 enforcement and required/optional parameter rules. |
| crates/libgraphql-core-v1/src/validators/tests/input_object_type_validator_tests.rs | Adds validator-level tests for required/optional input-field rules. |
| crates/libgraphql-core-v1/src/validators/tests/directive_definition_validator_tests.rs | Adds validator-level tests for required/optional directive-parameter rules. |
| crates/libgraphql-core-v1/src/schema/tests/schema_builder_tests.rs | Adds end-to-end build-from-str tests covering the new validations and deprecation-state extraction. |
| crates/libgraphql-core-v1/src/schema/tests/schema_builder_extension_tests.rs | Adds extension-merge regression tests to ensure merged validation covers extension-contributed deprecated items. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Task 16.6c (third of the six schema-hardening PRs): deprecation validations — the
IsValidImplementationdeprecation-consistency rule and the@deprecated-on-required prohibition, both entirely unenforced until now.What & why
Plumbing —
deprecation_state()everywhere it matters. NewDeprecationState::from_directives()computes deprecation on demand forFieldDefinition,ParameterDefinition, andInputField(computed, not stored — so the 16.6b extension-merge construction paths are automatically covered with zero builder plumbing). Reason extraction follows spec: omitted → the default"No longer supported"(DeprecationState::DEFAULT_REASON, now the single source of truth shared with the builtin@deprecatedseed); explicitnull→ deprecated with no reason.IsValidImplementation step 2.6. Verified verbatim from the September2025 spec source: "If {field} is deprecated then {implementedField} must also be deprecated." An implementing field may be
@deprecatedonly if the interface field it implements is too; the converse (deprecated interface field, non-deprecated implementer) is legal and explicitly tested. Implemented inside the same per-interface-contract loop as the sibling checks (so it flows through the transitive-interface machinery identically), replacing the long-standing TODO. Error span targets the offending@deprecatedannotation, with a "defined here without @deprecated" note on the interface field.§3.13.3 —
@deprecatedmust not appear on required (non-null, defaultless) arguments or input fields. Enforced atbuild()time over merged types (extension-contributed params/fields covered, regression-tested):DeprecatedRequiredParameter(field args),DeprecatedRequiredInputField, andDeprecatedRequiredDirectiveParameter(directive definitions' own args, matching graphql-js's reading of the blanket "arguments" wording). Each error includes a help note about the make-it-optional escape hatch. Requiredness is exactlynon-null AND no defaultat all three sites — a non-null arg with a default is optional and passes.Tests (28 new; v1 crate 256 → 284)
Accessor semantics (6, incl. reason default/null), object/interface validator matrix (7: 2.6 error w/ span+notes, both-deprecated OK, converse OK, interface-implements-interface, per-contract transitive case, required-param error, optional-param OKs), input-object (2), directive-def (2), end-to-end
build_from_str(8), and 16.6b extension-path regressions (3).Verification
cargo test --workspace— 1389 green;cargo clippy --workspace --tests -- -Dwarnings— clean[x]boxes + Completion Notes per the Execution Protocol🤖 Generated with Claude Code
https://claude.ai/code/session_01TipQtpvuLuHjHmRsVEgwJw
Generated by Claude Code