Skip to content

Conversation

@Aenimus
Copy link
Member

@Aenimus Aenimus commented Nov 20, 2025

Summary by CodeRabbit

  • New Features

    • Support for using __typename as a key in field sets and a new notice when __typename is already provided.
  • Bug Fixes

    • Skip __typename where appropriate to prevent invalid selections/provides; clearer errors that include subgraph context and typename-specific warnings.
  • Refactor

    • Standardized error/message parameter shapes and updated constant names for consistent messaging.
  • Tests

    • Expanded tests for __typename key scenarios, provides/requires edge cases, and related error messages.

✏️ Tip: You can customize this high-level summary in your review settings.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/cosmo-docs.
  • I have read the Contributors Guide.

@coderabbitai
Copy link

coderabbitai bot commented Nov 20, 2025

Walkthrough

Refactors error helpers to accept typed object parameters, adds LITERAL_PERIOD and TYPENAME constants (replacing PERIOD), introduces typeNameAlreadyProvidedErrorMessage and HandleNonExternalConditionalFieldParams, centralizes non-external conditional-field handling, updates path parsing to use LITERAL_PERIOD, and expands tests for __typename scenarios.

Changes

Cohort / File(s) Summary
Errors & types
composition/src/errors/errors.ts, composition/src/errors/types.ts
Error helpers changed to accept destructured param objects (IncompatibleTypeWithProvidesErrorMessageParams, NonExternalConditionalFieldErrorParams), added typeNameAlreadyProvidedErrorMessage, exported new param types, and updated public declarations/signatures.
String constants
composition/src/utils/string-constants.ts
Replaced PERIOD with LITERAL_PERIOD and added TYPENAME ('__typename') constant; updated public exports.
Federation layer
composition/src/v1/federation/federation-factory.ts, composition/src/v1/federation/utils.ts
Switched path/coordinate splitting/joining from PERIOD to LITERAL_PERIOD; added TYPENAME guards to skip/adjust processing for __typename during validation and tag generation.
Normalization core
composition/src/v1/normalization/normalization-factory.ts, composition/src/v1/normalization/params.ts, composition/src/v1/normalization/utils.ts
Added HandleNonExternalConditionalFieldParams type and private #handleNonExternalConditionalField method; replaced inline logic with centralized handler; updated error constructions to structured param objects; used LITERAL_PERIOD and TYPENAME; adjusted some internal array typings to Array<...>.
Normalization utils (detailed)
composition/src/v1/normalization/utils.ts
Added early-exit and validation guards for __typename in selection/key-field processing, emitted specific invalid-selection messages for __typename cases, and replaced PERIOD usage with LITERAL_PERIOD.
Tests — fieldset & provides
composition/tests/v1/directives/fieldset-directives.test.ts, composition/tests/v1/directives/provides.test.ts
Expanded fixtures and tests around __typename as a key and provides scenarios; updated test imports/expectations to use new error helpers, constants, and structured error params; minor test description fixes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Heterogeneous changes: error API signatures, new constants used across federation and normalization layers, added private handler, and expanded tests.
  • Review attention recommended for:
    • composition/src/v1/normalization/normalization-factory.ts (new private handler, usages, and structured error conversions).
    • composition/src/errors/errors.ts and composition/src/errors/types.ts (public signature and export changes).
    • All places converting PERIODLITERAL_PERIOD and introducing TYPENAME guards to ensure consistent path handling and no regressions in coordinate parsing.
    • Updated tests to confirm error-message shapes and __typename behaviors.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: support __typename in field sets' directly describes the main change throughout the PR: adding support for __typename fields within federation field sets.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5940dc3 and 271b590.

📒 Files selected for processing (1)
  • composition/src/errors/types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • composition/src/errors/types.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: build_test
  • GitHub Check: build_push_image (nonroot)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: build_push_image
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: image_scan
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: build_test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
  • GitHub Check: build_push_image
  • GitHub Check: build_test

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Nov 20, 2025

Router image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-916c2a82373891b6246e2cde044ddaf13d4e4a6f

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
composition/tests/v1/directives/provides.test.ts (1)

440-479: Fix the isTypeName condition to explicitly check for __typename

The bug in composition/src/errors/errors.ts at line 1490 is confirmed. The line const isTypeName = segments[segments.length - 1]; assigns the last segment string (always truthy) rather than checking if it equals __typename. This causes both __typename and regular fields like NestedObject.age to incorrectly trigger the __typename-specific error message.

Change line 1490 to explicitly compare against the TYPENAME constant:

const isTypeName = segments[segments.length - 1] === TYPENAME;

You'll need to import TYPENAME from ../utils/string-constants if not already imported.

🧹 Nitpick comments (3)
composition/src/v1/normalization/utils.ts (1)

76-77: __typename handling and period constant usage in key-field validation

  • Importing and using LITERAL_PERIOD for currentPath.join(...) and related joins is consistent with other modules and keeps the delimiter centralized.
  • In validateKeyFieldSets:
    • Skipping fields where fieldName === TYPENAME avoids looking up synthetic __typename in fieldDataByName and allows mixed keys like id __typename to validate purely on real fields.
    • The new SelectionSet branch for lastFieldName === TYPENAME correctly reports a non-composite String scalar using invalidSelectionSetDefinitionErrorMessage, without relying on schema metadata.
  • One behavioral change worth double-checking: a key field set that consists only of __typename will now:
    • Be traversed without any errors (the field is ignored in Field.enter), and
    • Still result in a RequiredFieldConfiguration being pushed for that fieldSet.

If the intention is to allow __typename to appear in key field sets but still require at least one non-__typename field to form an actual key, you may want to enforce that keyFieldSetPaths (or some non-typename counter) is non-empty before adding a configuration.

Also applies to: 87-91, 145-145, 208-210, 244-245, 272-273, 288-297

composition/src/v1/normalization/normalization-factory.ts (2)

1680-1710: Centralized non-external conditional-field handling is sound

The new private #handleNonExternalConditionalField cleanly centralizes the V1 vs V2 behavior for non-external conditional fields:

  • In V2 (isSubgraphVersionTwo === true), it appends a nonExternalConditionalFieldError with directiveCoords, directiveName, fieldSet, subgraphName, and targetCoords: currentFieldCoords.
  • In V1, it appends a nonExternalConditionalFieldWarning with the same coordinates and field set, matching the behavior already asserted in the tests.

Both scalar/enum leaf nodes without external ancestors and bare __typename in a field set now delegate to this helper, which makes the behavior consistent across provides/requires and reduces duplication in validateConditionalFieldSet. The call sites also correctly avoid invoking this when there is at least one external ancestor, which is important for nested __typename under external parents.

Also applies to: 1813-1820


2052-2109: Typed accumulators in validateProvidesOrRequires improve clarity without changing behavior

Changing allErrorMessages and configurations to explicitly typed Array<string> and Array<RequiredFieldConfiguration> is a small but useful clarity improvement. The method still:

  • Aggregates per-field error message strings and, when any are present, pushes a single invalidProvidesOrRequiresDirectivesError(...) onto this.errors.
  • Returns undefined when there are no configurations and no errors, preserving the “redundant directive” behavior relied on by tests where all fields are effectively unconditionally provided.

No functional issues here.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df8a0e3 and 151fb45.

📒 Files selected for processing (10)
  • composition/src/errors/errors.ts (5 hunks)
  • composition/src/errors/types.ts (2 hunks)
  • composition/src/utils/string-constants.ts (2 hunks)
  • composition/src/v1/federation/federation-factory.ts (6 hunks)
  • composition/src/v1/federation/utils.ts (2 hunks)
  • composition/src/v1/normalization/normalization-factory.ts (8 hunks)
  • composition/src/v1/normalization/params.ts (1 hunks)
  • composition/src/v1/normalization/utils.ts (7 hunks)
  • composition/tests/v1/directives/fieldset-directives.test.ts (9 hunks)
  • composition/tests/v1/directives/provides.test.ts (6 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-09-08T20:57:07.946Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: controlplane/src/core/repositories/SubgraphRepository.ts:1746-1763
Timestamp: 2025-09-08T20:57:07.946Z
Learning: The checkSubgraphSchema.ts file already correctly implements linked subgraph functionality, using byName(linkedSubgraph.name, linkedSubgraph.namespace) to fetch target subgraphs and properly handles parse(newSchemaSDL) for schema building. The implementation doesn't need fixes for byId usage or schema parsing as it's already correct.

Applied to files:

  • composition/tests/v1/directives/provides.test.ts
  • composition/src/v1/federation/federation-factory.ts
  • composition/tests/v1/directives/fieldset-directives.test.ts
  • composition/src/v1/normalization/normalization-factory.ts
📚 Learning: 2025-08-28T09:17:49.477Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2141
File: router-tests/http_subscriptions_test.go:17-55
Timestamp: 2025-08-28T09:17:49.477Z
Learning: The Cosmo router uses a custom, intentionally rigid multipart implementation for GraphQL subscriptions. The multipart parsing in test files should remain strict and not be made more tolerant, as this rigidity is by design.

Applied to files:

  • composition/tests/v1/directives/provides.test.ts
📚 Learning: 2025-10-17T16:35:24.723Z
Learnt from: Aenimus
Repo: wundergraph/cosmo PR: 2287
File: composition/tests/v1/federation-factory.test.ts:569-583
Timestamp: 2025-10-17T16:35:24.723Z
Learning: In the wundergraph/cosmo repository's Vitest test suite, `toHaveLength()` works with Map objects and `expect(map.has(key))` without an explicit matcher correctly asserts the boolean result in the test assertions for `composition/tests/v1/federation-factory.test.ts`.

Applied to files:

  • composition/tests/v1/directives/provides.test.ts
  • composition/tests/v1/directives/fieldset-directives.test.ts
📚 Learning: 2025-09-03T21:12:18.149Z
Learnt from: JivusAyrus
Repo: wundergraph/cosmo PR: 2156
File: cli/src/commands/subgraph/commands/link.ts:21-28
Timestamp: 2025-09-03T21:12:18.149Z
Learning: Subgraph names in the Cosmo platform can contain slashes, so when parsing formats like `<namespace>/<subgraph-name>`, only the first slash should be treated as the delimiter between namespace and subgraph name. The subgraph name portion can contain additional slashes.

Applied to files:

  • composition/tests/v1/directives/provides.test.ts
📚 Learning: 2025-08-20T10:08:17.857Z
Learnt from: endigma
Repo: wundergraph/cosmo PR: 2155
File: router/core/router.go:1857-1866
Timestamp: 2025-08-20T10:08:17.857Z
Learning: router/pkg/config/config.schema.json forbids null values for traffic_shaping.subgraphs: additionalProperties references $defs.traffic_shaping_subgraph_request_rule with type "object". Therefore, in core.NewSubgraphTransportOptions, dereferencing each subgraph rule pointer is safe under schema-validated configs, and a nil-check is unnecessary.

Applied to files:

  • composition/tests/v1/directives/fieldset-directives.test.ts
  • composition/src/v1/normalization/normalization-factory.ts
🧬 Code graph analysis (9)
composition/src/v1/federation/utils.ts (1)
composition/src/utils/string-constants.ts (1)
  • TYPENAME (156-156)
composition/src/errors/types.ts (1)
composition/src/types/types.ts (2)
  • TypeName (11-11)
  • SubgraphName (9-9)
composition/src/v1/normalization/params.ts (2)
composition/src/v1/normalization/normalization-factory.ts (1)
  • HandleNonExternalConditionalFieldParams (1680-1710)
composition/src/types/types.ts (1)
  • DirectiveName (3-3)
composition/tests/v1/directives/provides.test.ts (6)
composition/src/errors/errors.ts (4)
  • nonExternalConditionalFieldError (1482-1500)
  • invalidProvidesOrRequiresDirectivesError (667-674)
  • incompatibleTypeWithProvidesErrorMessage (690-699)
  • typeNameAlreadyProvidedErrorMessage (1600-1605)
composition/src/utils/string-constants.ts (2)
  • PROVIDES (115-115)
  • ID_SCALAR (64-64)
composition/tests/utils/utils.ts (1)
  • normalizeSubgraphFailure (27-34)
composition/src/router-compatibility-version/router-compatibility-version.ts (1)
  • ROUTER_COMPATIBILITY_VERSION_ONE (3-3)
composition/src/subgraph/types.ts (1)
  • Subgraph (18-22)
composition/src/ast/utils.ts (1)
  • parse (272-274)
composition/src/v1/federation/federation-factory.ts (2)
composition/src/utils/string-constants.ts (1)
  • LITERAL_PERIOD (89-89)
composition/src/resolvability-graph/constants/string-constants.ts (1)
  • LITERAL_PERIOD (5-5)
composition/src/v1/normalization/utils.ts (4)
composition/src/router-configuration/types.ts (1)
  • RequiredFieldConfiguration (76-81)
composition/src/utils/string-constants.ts (3)
  • TYPENAME (156-156)
  • LITERAL_PERIOD (89-89)
  • STRING_SCALAR (142-142)
composition/src/errors/errors.ts (1)
  • invalidSelectionSetDefinitionErrorMessage (607-619)
composition/src/utils/utils.ts (1)
  • kindToNodeType (82-151)
composition/tests/v1/directives/fieldset-directives.test.ts (8)
composition/tests/utils/utils.ts (4)
  • normalizeSubgraphSuccess (36-46)
  • normalizeString (19-21)
  • normalizeSubgraphFailure (27-34)
  • federateSubgraphsSuccess (58-71)
composition/tests/v1/utils/utils.ts (5)
  • KEY_DIRECTIVE (67-69)
  • OPENFED_FIELD_SET (71-71)
  • SCHEMA_QUERY_DEFINITION (158-162)
  • REQUIRES_DIRECTIVE (99-101)
  • EXTERNAL_DIRECTIVE (46-48)
composition/src/errors/errors.ts (4)
  • invalidDirectiveError (239-250)
  • invalidSelectionSetDefinitionErrorMessage (607-619)
  • nonExternalConditionalFieldError (1482-1500)
  • invalidProvidesOrRequiresDirectivesError (667-674)
composition/src/utils/utils.ts (2)
  • numberToOrdinal (44-57)
  • kindToNodeType (82-151)
composition/src/v1/warnings/warnings.ts (1)
  • nonExternalConditionalFieldWarning (57-76)
composition/src/types/types.ts (2)
  • TypeName (11-11)
  • FieldName (5-5)
composition/src/router-configuration/types.ts (1)
  • ConfigurationData (83-95)
composition/src/subgraph/types.ts (1)
  • Subgraph (18-22)
composition/src/errors/errors.ts (2)
composition/src/errors/types.ts (2)
  • IncompatibleTypeWithProvidesErrorMessageParams (45-49)
  • NonExternalConditionalFieldErrorParams (51-57)
composition/src/utils/string-constants.ts (1)
  • LITERAL_PERIOD (89-89)
composition/src/v1/normalization/normalization-factory.ts (7)
composition/src/v1/constants/constants.ts (1)
  • BASE_SCALARS (111-121)
composition/src/errors/errors.ts (5)
  • incompatibleTypeWithProvidesErrorMessage (690-699)
  • unknownNamedTypeErrorMessage (1525-1527)
  • nonExternalConditionalFieldError (1482-1500)
  • typeNameAlreadyProvidedErrorMessage (1600-1605)
  • invalidSelectionSetDefinitionErrorMessage (607-619)
composition/src/v1/normalization/params.ts (1)
  • HandleNonExternalConditionalFieldParams (17-22)
composition/src/v1/warnings/warnings.ts (1)
  • nonExternalConditionalFieldWarning (57-76)
composition/src/utils/string-constants.ts (2)
  • TYPENAME (156-156)
  • STRING_SCALAR (142-142)
composition/src/utils/utils.ts (1)
  • kindToNodeType (82-151)
composition/src/router-configuration/types.ts (1)
  • RequiredFieldConfiguration (76-81)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: integration_test (./events)
  • GitHub Check: integration_test (./telemetry)
  • GitHub Check: image_scan (nonroot)
  • GitHub Check: integration_test (./. ./fuzzquery ./lifecycle ./modules)
  • GitHub Check: image_scan
  • GitHub Check: build_test
  • GitHub Check: build_push_image
  • GitHub Check: build_test
  • GitHub Check: build_test
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Analyze (go)
🔇 Additional comments (16)
composition/src/errors/types.ts (1)

45-57: New error parameter types look consistent with callers

IncompatibleTypeWithProvidesErrorMessageParams and NonExternalConditionalFieldErrorParams correctly model the payloads used in errors.ts and normalization code (coords, fieldSet, directiveName, subgraphName, etc.). No issues from a typing or cohesion perspective.

composition/src/errors/errors.ts (2)

690-699: Object-parameter refactor for provides error is sound

Switching incompatibleTypeWithProvidesErrorMessage to accept IncompatibleTypeWithProvidesErrorMessageParams and including subgraphName in the message improves clarity and call-site readability. No functional issues spotted.


1600-1605: typeNameAlreadyProvidedErrorMessage helper is consistent with existing wording

The new helper mirrors fieldAlreadyProvidedErrorMessage but specializes on @provides and omits the legacy @external caveat. This keeps error construction centralized and aligns with the new structured error flows.

composition/src/v1/federation/utils.ts (1)

26-27: Skipping __typename in implicit key inference looks correct

Guarding on fieldName === TYPENAME in validateImplicitFieldSets prevents __typename from contributing to implicit key field sets or unconditionally-provided checks, which matches the goal of “supporting __typename in field sets” without treating it as a real key field. Traversal state (currentDepth, definedFields) remains consistent.

Just be aware that a key field set consisting only of __typename will now be considered implicitly valid here (no errors raised); confirm this aligns with your expectations for implicit key generation.

Also applies to: 141-143

composition/src/v1/normalization/params.ts (1)

17-22: Parameter object for non-external conditional field handling is well-scoped

HandleNonExternalConditionalFieldParams cleanly groups the coords, directive name, and field set used by #handleNonExternalConditionalField, matching the usage in normalization-factory.ts. No issues.

composition/src/v1/federation/federation-factory.ts (1)

208-209: Centralizing period handling via LITERAL_PERIOD is consistent

All updated split(LITERAL_PERIOD) calls operate on coordinates/paths that are constructed with .${...} elsewhere, so this is a mechanical refactor that keeps the delimiter definition centralized in string-constants.ts without changing behavior. No issues spotted.

Also applies to: 600-602, 1485-1486, 2352-2352, 2403-2403

composition/src/utils/string-constants.ts (1)

89-90: New LITERAL_PERIOD and TYPENAME constants fit existing patterns

Adding LITERAL_PERIOD and TYPENAME aligns with other literal constants (LITERAL_NEW_LINE, LITERAL_SPACE) and supports shared usage in federation/normalization utilities. Names and values look correct.

Also applies to: 156-156

composition/tests/v1/directives/provides.test.ts (2)

440-479: Object-form nonExternalConditionalFieldError expectations look consistent

Switching the expectations to use the object-parameter form of nonExternalConditionalFieldError with explicit directiveCoords, directiveName, fieldSet, subgraphName, and targetCoords matches the new helper signature and keeps the tests resilient to message formatting changes. No issues spotted with coordinates or field-set strings for the four error cases on subgraph n and the V2 case on p.

Also applies to: 516-527


792-816: Leaf-node @provides and __typename @provides tests correctly pin error behavior

The new fixtures nakaa and nalaa plus their tests align well with the normalization logic:

  • For a leaf-node @provides on Query.a: ID, the expectation that getFieldSetParent(true, ...) yields an incompatibleTypeWithProvidesErrorMessage using fieldCoords: "Query.a" and responseType: ID_SCALAR is correct and guards future regressions in base-scalar detection.
  • For @provides(fields: "__typename") on Query.a: Object, expecting a single invalidProvidesOrRequiresDirectivesError(PROVIDES, [ " On field \"Query.a\":\n -" + typeNameAlreadyProvidedErrorMessage("Object.__typename", nalaa.name) ]) matches the new validateConditionalFieldSet branch that special-cases TYPENAME for provides.

These tests accurately capture the intended semantics and are a good addition to the coverage for error helpers.

Also applies to: 2029-2052

composition/tests/v1/directives/fieldset-directives.test.ts (5)

253-275: Empty-selection-set parse test matches field-set parsing behavior

The updated test for "id { }" now clearly asserts a single invalidDirectiveError wrapping unparsableFieldSetErrorMessage('id { }', SyntaxError(...)). That lines up with how extractKeyFieldSets feeds raw field sets into safeParse('{'+fieldSet+'}'). The message and raw field-set string in the expectation look correct and should guard against regressions in the parser error reporting.


433-487: __typename key semantics and entity-link tests are well specified

The new KEY-focused tests and fixtures cover important edge-cases:

  • naaad asserts that @key(fields: "__typename") is accepted and normalized into the expected schema with KEY_DIRECTIVE + OPENFED_FIELD_SET.
  • naaae checks that adding a selection set to __typename in a key produces an invalidSelectionSetDefinitionErrorMessage with STRING_SCALAR and kindToNodeType(Kind.SCALAR_TYPE_DEFINITION), which matches the intended “non-composite type” messaging.
  • sbaaa/sbaab and sbaac/sbaad verify that explicit and implicit __typename keys create the right federated entity link and resulting schema.

These expectations align with the new TYPENAME handling and should provide solid regression coverage for typename-as-key behavior.

Also applies to: 2171-2222, 2276-2322


449-463: Selection set on __typename tests align with new scalar-typename guardrails

Both tests that assert errors when a selection set is added to __typename (for KEY and REQUIRES) correctly:

  • Use invalidSelectionSetDefinitionErrorMessage with:
    • the raw field-set string (including trailing space where present),
    • fieldCoordinatesPath pointing at Entity.__typename,
    • selectionSetTypeName=STRING_SCALAR,
    • fieldTypeString=kindToNodeType(Kind.SCALAR_TYPE_DEFINITION).
  • Couple this with a nonExternalConditionalFieldWarning in the V1 REQUIRES case (naaac), reflecting the separate “non-external conditional field” concern.

This matches the new validateConditionalFieldSet logic that special-cases TYPENAME for selection sets while still reusing the generic invalid-selection-set machinery.

Also applies to: 1515-1538


1047-1512: REQUIRES + __typename V1/V2 matrix is comprehensive and consistent

The new block of REQUIRES tests around fixtures naaaanaaac and saaaasaaae exercises a nuanced matrix:

  • Direct __typename in a V1 field set yields a nonExternalConditionalFieldWarning and no requires configuration (naaaa), whereas the same in a V2 subgraph yields a nonExternalConditionalFieldError (naaab).
  • Nested __typename under external vs non-external parents is covered:
    • Valid and conditional when the parent field is external (saaaa/saaaae, with requires configuration and no warnings).
    • Producing only warnings and no requires configuration when the parent chain is non-external (saaab/saaac/saaad variants).
  • The federated test with saaaa/saaae confirms that nested __typename in a requires field set composes correctly across subgraphs.

The configuration expectations (presence/absence of requires, externalFieldNames, and field-name sets) match what NormalizationFactory’s #handleNonExternalConditionalField and validateConditionalFieldSet are designed to produce. Coverage here looks strong and should catch regressions in future refactors.

Also applies to: 2128-2274


1543-1564: Router configuration implicit-key test refactor is behavior-preserving

Switching this router-configuration test to destructure subgraphConfigBySubgraphName from federateSubgraphsSuccess while leaving the configuration expectations unchanged keeps the semantics identical and improves consistency with other tests that already use the same helper. No behavioral risk here.

composition/src/v1/normalization/normalization-factory.ts (2)

1637-1678: getFieldSetParent refactor correctly wires object-form provides error messages

The updated getFieldSetParent logic for isProvides === true now:

  • Derives fieldCoords once (${parentTypeName}.${fieldName}) and uses it consistently.
  • Returns an incompatibleTypeWithProvidesErrorMessage constructed from { fieldCoords, responseType: fieldNamedTypeName, subgraphName: this.subgraphName } when the field’s named type is a base scalar or a non-object/interface named type.
  • Uses unknownNamedTypeErrorMessage(fieldCoords, fieldNamedTypeName) when the named type is missing from parentDefinitionDataByTypeName.

This matches the new leaf-node @provides test for ID and keeps the error context precise at the directive field, not the parent type. The change is localized and backward-compatible for the object/interface success path.


1769-1783: __typename-specific handling in conditional field-set validation matches new tests

The additions around TYPENAME in validateConditionalFieldSet look correct and align with the new test cases:

  • In the Field visitor:
    • When fieldName === TYPENAME and isProvides is true, you push typeNameAlreadyProvidedErrorMessage(currentFieldCoords, nf.subgraphName) into errorMessages and BREAK the traversal, which is exactly what the “__typename can be provided” test asserts via invalidProvidesOrRequiresDirectivesError(PROVIDES, [...]).
    • When fieldName === TYPENAME, isProvides is false, and there are no external ancestors, you delegate to #handleNonExternalConditionalField, which produces either a warning (V1) or an error (V2), matching the REQUIRES tests for direct __typename field sets.
  • In the SelectionSet visitor:
    • When a selection set is entered with lastFieldName === TYPENAME, you emit invalidSelectionSetDefinitionErrorMessage(fieldSet, fieldCoordsPath, STRING_SCALAR, kindToNodeType(Kind.SCALAR_TYPE_DEFINITION)) and BREAK, which matches the KEY/REQUIRES tests that attach selection sets to __typename.

The early TYPENAME checks also ensure __typename never falls through to the regular fieldDataByName/unknown-type path, so it won’t be misreported as an undefined field. Overall, the behavior for __typename in provides/requires field sets is now explicit and well-covered by the tests.

Also applies to: 1972-1989

@Aenimus Aenimus enabled auto-merge (squash) November 20, 2025 11:58
@Aenimus Aenimus merged commit c25f3f3 into main Nov 20, 2025
34 checks passed
@Aenimus Aenimus deleted the david/eng-8510-support-__typename-in-field-sets branch November 20, 2025 12:06
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