Skip to content

Conversation

@Aenimus
Copy link
Member

@Aenimus Aenimus commented Oct 28, 2025

Summary by CodeRabbit

  • New Features

    • Exposed consolidated SDL fragments and directive/type constants for tests and consumers.
    • New normalization/federation helpers that return structured success/failure objects (named fields like schema, errors, federatedGraphSchema).
  • Improvements

    • Streamlined directive handling and dependency emission; stronger typing for configuration maps using a dedicated TypeName key.
    • Centralized constants and reusable type-node fragments for consistent schema composition.
  • Bug Fixes

    • Updated emitted SDL surface to align validation and test expectations with the new directive/type set.

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 Oct 28, 2025

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Walkthrough

Reorganized v1 constants into dedicated modules, consolidated directive-definition shapes to DirectiveDefinitionNode, widened several type signatures to use TypeName/FieldName, introduced centralized persisted-directive extraction, adjusted normalization/federation flows, and updated many tests to use new helpers and exported SDL fragments.

Changes

Cohort / File(s) Summary
Constants & public re-exports
composition/src/index.ts, composition/src/v1/constants/*
New v1 constants modules added (constants.ts, directive-definitions.ts, non-directive-definitions.ts, strings.ts, type-nodes.ts); index.ts re-exports new constant groups; old utils/string-constants removed.
Directive & non-directive AST defs
composition/src/v1/constants/directive-definitions.ts, composition/src/v1/constants/non-directive-definitions.ts, composition/src/v1/constants/type-nodes.ts
Introduced many DirectiveDefinitionNode exports and non-directive AST nodes (scalars, enums, input types, field-set scalar, openfed__Scope, etc.) and type-node constants (REQUIRED_*).
Constants wiring
composition/src/v1/constants/strings.ts, composition/src/v1/constants/constants.ts
Built mappings/sets (TYPE_SYSTEM_DIRECTIVE_LOCATIONS, DEPENDENCIES_BY_DIRECTIVE_NAME, DIRECTIVE_DEFINITION_BY_NAME, BASE_SCALARS, MAX_OR_SCOPES, etc.) and exported them for use across normalization/federation.
Schema-building AST/types
composition/src/schema-building/ast.ts, composition/src/schema-building/utils.ts
Renamed MutableTypeDefinitionNodeMutableDefinitionNode; exported upsertDeprecatedDirective, upsertTagDirectives, isInputObjectDefinitionData; adjusted addValidPersistedDirectiveDefinitionNodeByData types to accept `(MutableDefinitionNode
General utils
composition/src/utils/utils.ts
Added addOptionalIterableValuesToSet(target, source?) helper.
Federation: types & factory
composition/src/v1/federation/federation-factory.ts, composition/src/v1/federation/params.ts, composition/src/v1/federation/utils.ts
Rekeyed many maps to use TypeName; widened clientDefinitions/routerDefinitions to `(MutableDefinitionNode
Normalization: factory, walkers, utils, types
composition/src/v1/normalization/normalization-factory.ts, composition/src/v1/normalization/walkers.ts, composition/src/v1/normalization/utils.ts, composition/src/v1/normalization/types.ts, composition/src/v1/normalization/directive-definition-data.ts
Replaced ByDirectiveName maps with ByName maps (directiveDefinitionByName, directiveDefinitionDataByName, customDirectiveDefinitionByName); constructor and method signatures adjusted (subgraphName → SubgraphName, upsertInputObjectByNode → returns UpsertInputObjectResult); added ExecutionFailure/UpsertInputObjectResult types; walker imports and internal maps switched to TypeName/FieldName; import paths updated to new constants.
Removed/relocated utils module
composition/src/v1/utils/string-constants.ts
File content removed; constants migrated to v1/constants/strings.ts.
Normalization/federation helpers & public API in tests
composition/tests/utils/utils.ts, composition/tests/v1/**/*.test.ts
Tests refactored to use new helpers (normalizeSubgraphSuccess, normalizeSubgraphFailure) and destructured federation returns (e.g., federatedGraphSchema); many test imports switched to new exported SDL fragments and directives (SCHEMA_QUERY_DEFINITION, AUTHENTICATED_DIRECTIVE, TAG_DIRECTIVE, INACCESSIBLE_DIRECTIVE, OPENFED_SCOPE, OPENFED_FIELD_SET, KEY_DIRECTIVE, etc.); expectations updated.
Public type keying
composition/src/normalization/types.ts, composition/src/subgraph/types.ts
Changed maps from Map<string, ConfigurationData>Map<TypeName, ConfigurationData> and aligned related types to TypeName.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

  • Scope: broad changes across constants, directive definitions, normalization and federation factories, types, and extensive test updates.
  • Complexity: mix of type-level refactors (TypeName/DirectiveName), new centralized directive extraction, and many import/emit surface changes.

Areas needing extra attention:

  • federation-factory.ts: correctness of TypeName-keyed maps, migration of persisted-directive extraction, and directive propagation to client/router schemas.
  • normalization-factory.ts / walkers: ensure ByName maps and UpsertInputObjectResult return paths cover all callers and emission of custom directives is correct.
  • constants modules: verify no import cycles and that directive locations/arguments match prior semantics.
  • Test helpers: confirm new normalizeSubgraphSuccess/Failure and federateSubgraphsSuccess/Failure return shapes align with all updated tests.

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% 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 PR title "chore: selectively inject directive defs/deps" refers to a real and important aspect of the changeset—the selective injection of directive definitions and their dependencies—which aligns with the PR's apparent intention based on the branch name. However, the actual implementation encompasses substantial changes beyond this single behavioral feature, including reorganization of constants modules from v1/utils/ to new v1/constants/ modules with specific structural separation, refactoring of FederationFactory and NormalizationFactory to use type-safe keys (TypeName, DirectiveName), and extensive updates to how directive definitions are exposed and managed throughout the codebase. While the selective injection is the intended outcome, the more prominent changes visible in the changeset are the module reorganization and factory refactoring required to enable that behavior. The title captures the goal but not the full scope of structural changes.

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

@github-actions
Copy link

github-actions bot commented Oct 28, 2025

Router-nonroot image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-589ba097d1ba20270380bbccc6df82d2d3a0359a-nonroot

@github-actions
Copy link

Router-nonroot image scan passed

✅ No security vulnerabilities found in image:

ghcr.io/wundergraph/cosmo/router:sha-5d55cfffc32d1fb07aa3ab3ce71cbfec51f9331e-nonroot

@github-actions github-actions bot removed the studio label Oct 28, 2025
@Aenimus
Copy link
Member Author

Aenimus commented Oct 28, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Oct 28, 2025

✅ Actions performed

Full review triggered.

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: 9

Caution

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

⚠️ Outside diff range comments (6)
composition/tests/v1/directives/semantic-non-null.test.ts (1)

409-419: Fix client-schema expectation to use semanticNonNullDefinition (consistent with earlier tests).

Earlier cases use semanticNonNullDefinition for client schema; this block uses SEMANTIC_NON_NULL_DIRECTIVE. Align to prevent assertion failures.

Apply:

-          SCHEMA_QUERY_DEFINITION +
-            SEMANTIC_NON_NULL_DIRECTIVE +
+          SCHEMA_QUERY_DEFINITION +
+            semanticNonNullDefinition +
             `
             type Query {
                a: [[[ID]]] @semanticNonNull(levels: [0, 2])
             }
           `,
composition/tests/v1/types/arguments.test.ts (1)

122-126: Fix stray backticks in test titles

Remove the trailing backtick from these test names.

-  test('that if arguments of the same name are not the same type, an error is returned`', () => {
+  test('that if arguments of the same name are not the same type, an error is returned', () => {
@@
-  test('that if arguments have different boolean default values, an error is returned`', () => {
+  test('that if arguments have different boolean default values, an error is returned', () => {

Also applies to: 154-161

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

184-191: Bug: duplicateOperationTypeDefinitionError is dropped

The error is created but never pushed, so duplicates won’t be reported.

-        if (definitionNode) {
-          duplicateOperationTypeDefinitionError(
-            operationType,
-            namedTypeName,
-            getTypeNodeNamedTypeName(definitionNode.type),
-          );
-          return false;
-        }
+        if (definitionNode) {
+          nf.errors.push(
+            duplicateOperationTypeDefinitionError(
+              operationType,
+              namedTypeName,
+              getTypeNodeNamedTypeName(definitionNode.type),
+            ),
+          );
+          return false;
+        }
composition/tests/v1/directives/directives.test.ts (1)

99-125: Fix invalid GraphQL value in @z(list: …) input object.

{ name: String } is a type name used as a value; GraphQL input values require a string literal like "test".

Apply:

@@
-            type Query {
-              dummy: String! @z(list: {name: String})
-            }
+            type Query {
+              dummy: String! @z(list: { name: "test" })
+            }
@@
 const ne: Subgraph = {
   name: 'ne',
   url: '',
   definitions: parse(`
     directive @z(list: [[Input!]!]!) on FIELD_DEFINITION
     
     type Query {
-      dummy: String! @z(list: { name: String })
+      dummy: String! @z(list: { name: "test" })
     }
     
     input Input {
       name: String!
     }
   `),
 };

Also applies to: 458-471

composition/tests/v1/types/inputs.test.ts (1)

395-406: Fix expected error field name in skipped test.

The fixture defines “field: String! …”, but the assertion references “Input field "name"”. Correct the expectation to “field” to avoid future flakes when the test is enabled.

-  incompatibleInputValueDefaultValueTypeError('Input field "name"', 'Input.name', 'String!', 'null'),
+  incompatibleInputValueDefaultValueTypeError('Input field "field"', 'Input.field', 'String!', 'null'),
composition/tests/v1/types/objects.test.ts (1)

445-463: Duplicate scenario — both tests pass the same subgraph order.

#1.2” repeats the exact inputs as “#1.1”. If the intent is permutation coverage, swap the order in one test.

-const { federatedGraphSchema } = federateSubgraphsSuccess(
-  [subgraphI, subgraphL, subgraphM],
-  ROUTER_COMPATIBILITY_VERSION_ONE,
-);
+const { federatedGraphSchema } = federateSubgraphsSuccess(
+  [subgraphI, subgraphM, subgraphL],
+  ROUTER_COMPATIBILITY_VERSION_ONE,
+);
🧹 Nitpick comments (31)
composition/src/v1/normalization/types.ts (1)

80-89: Include error details in ExecutionFailure for diagnosability.

Expose minimal context (messages or code) on failures.

Apply:

-export type ExecutionFailure = {
-  success: false;
-};
+export type ExecutionFailure = {
+  success: false;
+  errorMessages?: string[];
+};

If you prefer stricter shape, make errorMessages: string[] required.

composition/src/schema-building/utils.ts (1)

301-310: Good: export upsertTagDirectives.

Centralizes tag merging; keeps last-wins by name.

Consider a brief TSDoc noting last-write-wins semantics.

composition/tests/v1/types/interfaces.test.ts (1)

459-459: Duplicate test title (“#1.1”) — rename one for clarity.

Both tests use the same name; prefer “#1.2” for the latter to keep titles unique.

-    test('that an Interface type and extension definition federate successfully #1.1', () => {
+    test('that an Interface type and extension definition federate successfully #1.2', () => {

Also applies to: 481-481

composition/tests/utils/utils.ts (2)

20-20: Simplify normalizeString; avoid redundant alternation and replaceAll.

Use one whitespace pass; works for all whitespace including newlines.

-export function normalizeString(input: string): string {
-  return input.replaceAll(/\s+|\\n\s*/g, ' ').trim();
-}
+export function normalizeString(input: string): string {
+  return input.replace(/\s+/g, ' ').trim();
+}

45-47: Gate debug logging to reduce noisy CI output.

Only log when explicitly enabled.

-  if (!result.success) {
-    console.dir(result.errors);
-  }
+  if (!result.success && process.env.DEBUG_COSMO_TESTS === '1') {
+    console.dir(result.errors, { depth: null });
+  }
composition/tests/v1/directives/one-of.test.ts (1)

105-118: Deduplicate repeated SDL prefixes

Multiple expectations prepend the same SCHEMA_QUERY_DEFINITION + Query block. Extract a small helper (e.g., buildSDL(fragment: string)) to reduce duplication and future drift.

Also applies to: 119-132

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

554-560: Consistent traversal short‑circuit for ENTITY_UNION

Definition returns (continues traversal) while Extension returns false (stops). Prefer returning false in both places for consistency.

     UnionTypeDefinition: {
       enter(node) {
         if (node.name.value === ENTITY_UNION) {
-          return;
+          return false;
         }
         nf.upsertUnionByNode(node);
       },
     },
composition/tests/v1/directives/shareable.test.ts (1)

75-86: Use OPENFED_FIELD_SET constant for consistency

You import OPENFED_FIELD_SET; leverage it instead of hardcoding the scalar.

-           scalar openfed__FieldSet
-          `,
+          ` +
+            OPENFED_FIELD_SET,
composition/tests/v1/directives/provides.test.ts (2)

21-21: Align parse import with other tests

Use parse from '../../../src' for consistency with the rest of the test suite (and any custom parsing options).

-import { parse } from 'graphql';
+import { parse } from '../../../src';

942-943: Prefer toHaveLength for array assertions

Unify on expect(warnings).toHaveLength(0) for readability and consistency.

-      expect(warnings.length).toBe(0);
+      expect(warnings).toHaveLength(0);

Also applies to: 1132-1133

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

37-43: Use OPENFED_FIELD_SET constant instead of hard-coding 'scalar openfed__FieldSet'.

Keeps assertions aligned with shared constants and reduces drift.

Apply:

 import {
   EXTERNAL_DIRECTIVE,
   INACCESSIBLE_DIRECTIVE,
   KEY_DIRECTIVE,
   REQUIRES_DIRECTIVE,
   SCHEMA_QUERY_DEFINITION,
+  OPENFED_FIELD_SET,
 } from '../utils/utils';
…
-            scalar openfed__FieldSet
+          ` + OPENFED_FIELD_SET

Also applies to: 845-905


907-968: Unify Map key generic across the file (TypeName vs string).

This block uses Map<TypeName, ConfigurationData> while earlier assertions use Map<string, ConfigurationData>. Pick one (prefer TypeName if it’s the new public alias) and standardize for consistency.

composition/tests/v1/contracts.test.ts (1)

3-8: Prefer explicit constants over versionOneRouterDefinitions.

To align with “selective injection,” build expectations with SCHEMA_QUERY_DEFINITION plus only the directive constants actually needed (e.g., TAG_DIRECTIVE, INACCESSIBLE_DIRECTIVE). This reduces coupling and keeps tests resilient to directive set changes.

If you want, I can generate a follow-up diff to replace the aggregator in these spots with explicit constants matching each test’s needs.

Also applies to: 1078-1090, 1114-1126, 1149-1162

composition/tests/v1/normalization.test.ts (1)

929-935: Use KEY constant instead of string literal 'key'.

Unifies directive-name references and avoids accidental case mismatches.

Apply:

-    expect(errors[0]).toStrictEqual(
-      invalidDirectiveError('key', 'User', FIRST_ORDINAL, [
+    expect(errors[0]).toStrictEqual(
+      invalidDirectiveError(KEY, 'User', FIRST_ORDINAL, [
         invalidDirectiveLocationErrorMessage(KEY, INPUT_OBJECT_UPPER),
       ]),
     );
composition/tests/v1/types/enums.test.ts (1)

92-118: Optional: reduce repetition in TAG_DIRECTIVE expectations.

Many blocks concatenate TAG_DIRECTIVE + repeated enum SDL. Consider a small helper like expectNormalizedSDLWithTag(nodeSDL) to cut duplication and ease future changes.

Also applies to: 120-146, 148-160

composition/src/v1/constants/constants.ts (3)

160-168: Unify map key typing to DirectiveName.

EVENT_DRIVEN_DIRECTIVE_DEFINITIONS_BY_DIRECTIVE_NAME uses Map<string,...> while other maps use Map<DirectiveName,...>. Align to DirectiveName for type-safety and consistency.

Apply:

-export const EVENT_DRIVEN_DIRECTIVE_DEFINITIONS_BY_DIRECTIVE_NAME = new Map<string, DirectiveDefinitionNode>([
+export const EVENT_DRIVEN_DIRECTIVE_DEFINITIONS_BY_DIRECTIVE_NAME = new Map<DirectiveName, DirectiveDefinitionNode>([

120-136: Clarify “BASE” directive membership; avoid drift between Map vs Array.

BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME includes EDFS_* directives, but BASE_DIRECTIVE_DEFINITIONS[] excludes them. If “BASE” means core federation v1 directives, exclude EDFS_* from the map or rename the map to reflect scope. Alternatively, derive both from a single source to keep them in sync.

Example to derive arrays from the map:

-export const BASE_DIRECTIVE_DEFINITIONS: DirectiveDefinitionNode[] = [
-  DEPRECATED_DEFINITION,
-  EXTENDS_DEFINITION,
-  EXTERNAL_DEFINITION,
-  KEY_DEFINITION,
-  PROVIDES_DEFINITION,
-  REQUIRES_DEFINITION,
-  SPECIFIED_BY_DEFINITION,
-  TAG_DEFINITION,
-];
+export const BASE_DIRECTIVE_DEFINITIONS: DirectiveDefinitionNode[] = Array.from(
+  BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME.values()
+);

Also applies to: 149-158


73-106: Guard against accidental mutation and future divergence.

  • Export maps/sets as ReadonlyMap/ReadonlySet consistently and avoid exposing mutable instances.
  • Consider freezing arrays: Object.freeze([...]) to harden immutability.
  • Prefer constructing subset maps/arrays from a single canonical DIRECTIVE_DEFINITION_BY_NAME to avoid copy‑paste divergence.

Also applies to: 120-148, 149-158, 170-178

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

650-663: Duplicate test titles “#1.3” — rename or parametrize.

Multiple tests share the exact name “that an @inaccessible only needs to be declared on a single field #1.3”. Rename distinctly or use it.each to parametrize order permutations.

Also applies to: 655-663, 660-663


122-139: Avoid non‑null assertion on federatedGraphClientSchema.

The success helper should always return both schemas; drop the “!” to keep tests strict and type‑safe.

-    expect(schemaToSortedNormalizedString(federatedGraphClientSchema!)).toBe(
+    expect(schemaToSortedNormalizedString(federatedGraphClientSchema)).toBe(
composition/tests/v1/types/inputs.test.ts (1)

99-116: Standardize on normalizeSubgraphSuccess helper.

These blocks still use normalizeSubgraph + NormalizationSuccess casting. For consistency with the rest of the suite, switch to normalizeSubgraphSuccess and destructure { schema }.

-const result = normalizeSubgraph(
-  subgraphR.definitions,
-  subgraphR.name,
-  undefined,
-  ROUTER_COMPATIBILITY_VERSION_ONE,
-) as NormalizationSuccess;
-expect(result.success).toBe(true);
-expect(schemaToSortedNormalizedString(result.schema)).toBe(
+const { schema } = normalizeSubgraphSuccess(subgraphR, ROUTER_COMPATIBILITY_VERSION_ONE);
+expect(schemaToSortedNormalizedString(schema)).toBe(

Also applies to: 118-136, 138-156, 158-176, 178-196, 198-216, 218-236

composition/tests/v1/types/objects.test.ts (1)

112-114: Remove unnecessary cast.

normalizeSubgraphSuccess already returns the needed shape; the “as NormalizationSuccess” cast is redundant.

-const { schema } = normalizeSubgraphSuccess(subgraphS, ROUTER_COMPATIBILITY_VERSION_ONE) as NormalizationSuccess;
+const { schema } = normalizeSubgraphSuccess(subgraphS, ROUTER_COMPATIBILITY_VERSION_ONE);
composition/src/v1/constants/strings.ts (1)

62-74: Make exported sets/map truly read‑only at the type level (and arrays immutable).

  • Prefer ReadonlySet for all exported sets to prevent accidental mutation by consumers.
  • Use ReadonlyMap<DirectiveName, ReadonlyArray> so dependency lists can’t be mutated.
  • Minor: the comment above DEPENDENCIES_BY_DIRECTIVE_NAME contradicts the entry for EDFS_NATS_SUBSCRIBE; clarify it.

Apply:

-export const TYPE_SYSTEM_DIRECTIVE_LOCATIONS = new Set<string>([
+export const TYPE_SYSTEM_DIRECTIVE_LOCATIONS: ReadonlySet<string> = new Set<string>([
@@
-export const EVENT_DIRECTIVE_NAMES = new Set<string>([
+export const EVENT_DIRECTIVE_NAMES: ReadonlySet<string> = new Set<string>([
@@
-export const STREAM_CONFIGURATION_FIELD_NAMES = new Set<string>([
+export const STREAM_CONFIGURATION_FIELD_NAMES: ReadonlySet<string> = new Set<string>([
@@
-export const SUBSCRIPTION_FILTER_INPUT_NAMES = new Set<string>([AND_UPPER, IN_UPPER, NOT_UPPER, OR_UPPER]);
-export const SUBSCRIPTION_FILTER_LIST_INPUT_NAMES = new Set<string>([AND_UPPER, OR_UPPER]);
+export const SUBSCRIPTION_FILTER_INPUT_NAMES: ReadonlySet<string> = new Set<string>([AND_UPPER, IN_UPPER, NOT_UPPER, OR_UPPER]);
+export const SUBSCRIPTION_FILTER_LIST_INPUT_NAMES: ReadonlySet<string> = new Set<string>([AND_UPPER, OR_UPPER]);
@@
-export const COMPOSITE_OUTPUT_NODE_KINDS: ReadonlySet<Kind> = new Set<Kind>([
+export const COMPOSITE_OUTPUT_NODE_KINDS: ReadonlySet<Kind> = new Set<Kind>([
@@
-export const DEPENDENCIES_BY_DIRECTIVE_NAME: ReadonlyMap<DirectiveName, Array<DefinitionNode>> = new Map<
-  DirectiveName,
-  Array<DefinitionNode>
->([
+// Dependencies injected when a directive is present in a subgraph
+export const DEPENDENCIES_BY_DIRECTIVE_NAME: ReadonlyMap<DirectiveName, ReadonlyArray<DefinitionNode>> = new Map<
+  DirectiveName,
+  ReadonlyArray<DefinitionNode>
+>([
@@
-export const IGNORED_FEDERATED_TYPE_NAMES: ReadonlySet<TypeName> = new Set<TypeName>([
+export const IGNORED_FEDERATED_TYPE_NAMES: ReadonlySet<TypeName> = new Set<TypeName>([
@@
-export const CLIENT_PERSISTED_DIRECTIVE_NAMES: ReadonlySet<DirectiveName> = new Set<DirectiveName>([
+export const CLIENT_PERSISTED_DIRECTIVE_NAMES: ReadonlySet<DirectiveName> = new Set<DirectiveName>([

Also consider freezing the value arrays:

-  [KEY, [FIELD_SET_SCALAR_DEFINITION]],
+  [KEY, Object.freeze([FIELD_SET_SCALAR_DEFINITION] as const)],

And update the stale comment:

-// `edfs__natsSubscribe` dependencies are added in `validateEventDrivenSubgraph`
+// Dependencies automatically injected for specific directives (e.g., edfs__natsSubscribe requires edfs__NatsStreamConfiguration).

Also applies to: 76-85, 86-94, 95-101, 123-136, 138-142

composition/src/v1/constants/non-directive-definitions.ts (2)

1-1: Unify GraphQL imports to one module path.

Mixing 'graphql/index' and 'graphql' can cause dual module instances and type incompatibilities. Import from 'graphql' only.

-import { InputObjectTypeDefinitionNode, Kind, ScalarTypeDefinitionNode } from 'graphql/index';
+import { InputObjectTypeDefinitionNode, Kind, ScalarTypeDefinitionNode, EnumTypeDefinitionNode } from 'graphql';
@@
-import { EnumTypeDefinitionNode } from 'graphql';

Also applies to: 27-28


36-69: Optional: reorder fields to match normalized SDL expectations.

Your tests assert edfs__NatsStreamConfiguration with consumerInactiveThreshold first. If the normalizer does not sort input fields, this order difference can fail string comparisons. Reorder defensively.

 export const EDFS_NATS_STREAM_CONFIGURATION_DEFINITION: InputObjectTypeDefinitionNode = {
   kind: Kind.INPUT_OBJECT_TYPE_DEFINITION,
   name: stringToNameNode(EDFS_NATS_STREAM_CONFIGURATION),
   fields: [
-    {
-      kind: Kind.INPUT_VALUE_DEFINITION,
-      name: stringToNameNode(CONSUMER_NAME),
-      type: {
-        kind: Kind.NON_NULL_TYPE,
-        type: stringToNamedTypeNode(STRING_SCALAR),
-      },
-    },
-    {
-      kind: Kind.INPUT_VALUE_DEFINITION,
-      name: stringToNameNode(STREAM_NAME),
-      type: {
-        kind: Kind.NON_NULL_TYPE,
-        type: stringToNamedTypeNode(STRING_SCALAR),
-      },
-    },
     {
       kind: Kind.INPUT_VALUE_DEFINITION,
       name: stringToNameNode(CONSUMER_INACTIVE_THRESHOLD),
       type: {
         kind: Kind.NON_NULL_TYPE,
         type: stringToNamedTypeNode(INT_SCALAR),
       },
       defaultValue: {
         kind: Kind.INT,
         value: DEFAULT_CONSUMER_INACTIVE_THRESHOLD.toString(),
       },
     },
+    {
+      kind: Kind.INPUT_VALUE_DEFINITION,
+      name: stringToNameNode(CONSUMER_NAME),
+      type: {
+        kind: Kind.NON_NULL_TYPE,
+        type: stringToNamedTypeNode(STRING_SCALAR),
+      },
+    },
+    {
+      kind: Kind.INPUT_VALUE_DEFINITION,
+      name: stringToNameNode(STREAM_NAME),
+      type: {
+        kind: Kind.NON_NULL_TYPE,
+        type: stringToNamedTypeNode(STRING_SCALAR),
+      },
+    },
   ],
 };

Confirm whether schemaToSortedNormalizedString sorts input field definitions. If it already sorts, this change is optional.

composition/tests/v1/events.test.ts (1)

603-633: Remove ad‑hoc console output and give the test a descriptive name.

console.log in tests is noisy in CI; the case name 'test' is not descriptive.

-test('test', () => {
+test('prints custom input type unchanged by normalization helpers', () => {
@@
-    console.log(printSchema(s));
+    // No assertions here; keep this purely for local inspection if needed.
+    // Consider adding an assertion or removing this block entirely.

Or delete the console.log line if the block must stay.

composition/src/v1/constants/directive-definitions.ts (2)

565-581: Unify FieldSet type construction in @requires for consistency

REQUIRES_DEFINITION hand-builds NON_NULL(FIELD_SET_SCALAR) while KEY_DEFINITION/PROVIDES_DEFINITION use REQUIRED_FIELDSET_TYPE_NODE. Prefer the shared node for consistency and fewer AST variants.

Apply:

 export const REQUIRES_DEFINITION: DirectiveDefinitionNode = {
   arguments: [
     {
       kind: Kind.INPUT_VALUE_DEFINITION,
       name: stringToNameNode(FIELDS),
-      type: {
-        kind: Kind.NON_NULL_TYPE,
-        type: stringToNamedTypeNode(FIELD_SET_SCALAR),
-      },
+      type: REQUIRED_FIELDSET_TYPE_NODE,
     },
   ],
   kind: Kind.DIRECTIVE_DEFINITION,
   locations: [stringToNameNode(FIELD_DEFINITION_UPPER)],
   name: stringToNameNode(REQUIRES),
   repeatable: false,
 };

307-308: Minor: fix @edfs__natsRequest comment typo

Missing colon after providerId. Should read: providerId: String! = "default".

-// directive @edfs__natsRequest(subject: String!, providerId String! = "default") on FIELD_DEFINITION
+// directive @edfs__natsRequest(subject: String!, providerId: String! = "default") on FIELD_DEFINITION
composition/src/v1/normalization/normalization-factory.ts (2)

2990-3004: Defensive guard for unlikely failed upsert

Comment says “cannot actually be unsuccessful”, but we proceed assuming success. Add a small guard to avoid result.data access if this assumption breaks.

- if (result.success) {
+ if (result.success) {
    for (const fieldNode of EDFS_NATS_STREAM_CONFIGURATION_DEFINITION.fields!) {
      this.addInputValueDataByNode({
        fieldName: fieldNode.name.value,
        isArgument: false,
        inputValueDataByName: result.data.inputValueDataByName,
        node: fieldNode,
        originalParentTypeName: EDFS_NATS_STREAM_CONFIGURATION,
      });
    }
- }
+ } else {
+   // Defensive: should not happen; skip injection to prevent undefined access
+   return;
+ }

2945-3029: Dead variable: nonEntityExtensionTypeNames is never populated

The set is declared and checked but never written to, so the error branch is unreachable. Either wire the producer or remove the variable and its check.

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

317-353: Centralized persisted-directive extraction is solid; add tiny safety

Logic cleanly separates auth, deprecated, tag, and generic persisted directives and records references for later def injection. Add a guard for unexpected empty arrays.

Apply:

-      switch (directiveName) {
+      if (!directiveNodes || directiveNodes.length === 0) {
+        continue;
+      }
+      switch (directiveName) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6a443e and a441e27.

⛔ Files ignored due to path filters (1)
  • shared/test/__snapshots__/router.config.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (50)
  • composition-go/composition_test.go (1 hunks)
  • composition/src/index.ts (1 hunks)
  • composition/src/schema-building/ast.ts (1 hunks)
  • composition/src/schema-building/utils.ts (7 hunks)
  • composition/src/utils/utils.ts (1 hunks)
  • composition/src/v1/constants/constants.ts (1 hunks)
  • composition/src/v1/constants/directive-definitions.ts (8 hunks)
  • composition/src/v1/constants/non-directive-definitions.ts (1 hunks)
  • composition/src/v1/constants/strings.ts (1 hunks)
  • composition/src/v1/constants/type-nodes.ts (1 hunks)
  • composition/src/v1/federation/federation-factory.ts (25 hunks)
  • composition/src/v1/federation/params.ts (1 hunks)
  • composition/src/v1/federation/utils.ts (1 hunks)
  • composition/src/v1/normalization/directive-definition-data.ts (1 hunks)
  • composition/src/v1/normalization/normalization-factory.ts (22 hunks)
  • composition/src/v1/normalization/types.ts (2 hunks)
  • composition/src/v1/normalization/utils.ts (1 hunks)
  • composition/src/v1/normalization/walkers.ts (6 hunks)
  • composition/src/v1/utils/string-constants.ts (0 hunks)
  • composition/src/v1/utils/utils.ts (1 hunks)
  • composition/tests/utils/utils.ts (2 hunks)
  • composition/tests/v1/contracts.test.ts (134 hunks)
  • composition/tests/v1/directives/authorization-directives.test.ts (36 hunks)
  • composition/tests/v1/directives/configure-description.test.ts (16 hunks)
  • composition/tests/v1/directives/directives.test.ts (12 hunks)
  • composition/tests/v1/directives/external.test.ts (32 hunks)
  • composition/tests/v1/directives/fieldset-directives.test.ts (4 hunks)
  • composition/tests/v1/directives/inaccessible.test.ts (29 hunks)
  • composition/tests/v1/directives/interface-object.test.ts (10 hunks)
  • composition/tests/v1/directives/one-of.test.ts (13 hunks)
  • composition/tests/v1/directives/override.test.ts (29 hunks)
  • composition/tests/v1/directives/provides.test.ts (31 hunks)
  • composition/tests/v1/directives/require-fetch-reasons.test.ts (11 hunks)
  • composition/tests/v1/directives/semantic-non-null.test.ts (22 hunks)
  • composition/tests/v1/directives/shareable.test.ts (12 hunks)
  • composition/tests/v1/directives/subscription-filter.test.ts (4 hunks)
  • composition/tests/v1/directives/v2-directives.test.ts (3 hunks)
  • composition/tests/v1/entities.test.ts (25 hunks)
  • composition/tests/v1/entity-interface.test.ts (7 hunks)
  • composition/tests/v1/events.test.ts (27 hunks)
  • composition/tests/v1/federation-factory.test.ts (20 hunks)
  • composition/tests/v1/normalization.test.ts (73 hunks)
  • composition/tests/v1/resolvability.test.ts (38 hunks)
  • composition/tests/v1/router-configuration.test.ts (8 hunks)
  • composition/tests/v1/types/arguments.test.ts (8 hunks)
  • composition/tests/v1/types/enums.test.ts (11 hunks)
  • composition/tests/v1/types/inputs.test.ts (13 hunks)
  • composition/tests/v1/types/interfaces.test.ts (29 hunks)
  • composition/tests/v1/types/objects.test.ts (12 hunks)
  • composition/tests/v1/types/scalars.test.ts (4 hunks)
💤 Files with no reviewable changes (1)
  • composition/src/v1/utils/string-constants.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-08T20:57:07.946Z
Learnt from: JivusAyrus
PR: wundergraph/cosmo#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/subscription-filter.test.ts
  • composition/tests/v1/normalization.test.ts
  • composition/tests/v1/directives/shareable.test.ts
🔇 Additional comments (61)
composition/src/v1/utils/utils.ts (2)

33-33: AI summary mentions non-existent function.

The AI-generated summary for this file claims a new exported function addOptionalIterableValuesToSet was added, but this function is not present in the provided code. The actual change is just an import path update for MAX_OR_SCOPES.


33-37: LGTM! Import paths updated correctly.

The import path updates align with the constants reorganization into dedicated v1/constants/ modules. Both MAX_OR_SCOPES and COMPOSITE_OUTPUT_NODE_KINDS are actively used in this file (lines 314, 335-336, 399 and line 444 respectively).

composition/tests/v1/directives/v2-directives.test.ts (4)

10-10: LGTM: Clean constant extraction.

The import of SCHEMA_QUERY_DEFINITION centralizes the base schema definition, reducing duplication and improving maintainability across test files.


20-26: LGTM: Improved readability through destructuring.

The destructuring pattern for federatedGraphSchema and the use of SCHEMA_QUERY_DEFINITION as a schema prefix make the test more readable and maintainable. The test logic remains intact while adapting cleanly to the updated API surface.


43-49: LGTM: Consistent refactoring pattern.

The second test follows the same clean destructuring and constant usage pattern as the first test, ensuring consistency across the test suite.


65-67: LGTM: Safe error handling with destructuring.

The destructuring pattern for error handling is clean and safe. The length check on line 66 properly validates the errors array before accessing errors[0], preventing potential undefined access issues.

composition/tests/v1/entity-interface.test.ts (3)

185-190: Good addition: validating warnings.

The test now properly validates that no warnings are produced during federation, which improves test coverage and ensures the operation completes cleanly.


18-18: SCHEMA_QUERY_DEFINITION import verified successfully.

The verification confirms that SCHEMA_QUERY_DEFINITION is properly exported from composition/tests/v1/utils/utils.ts at line 169 with the expected schema query definition (schema { query: Query }). The import path ./utils/utils in the test file correctly resolves to this export.


30-31: No issues found – destructuring pattern is fully compatible with return type.

The federateSubgraphsSuccess function returns FederationSuccess, which contains all properties being destructured in the test: federatedGraphSchema (GraphQLSchema), subgraphConfigBySubgraphName (Map<string, SubgraphConfig>), and warnings (Array). The refactored destructuring pattern is correct and properly typed.

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

6-6: LGTM.

composition/src/schema-building/utils.ts (3)

287-299: Good: export upsertDeprecatedDirective for reuse.

Makes persisted deprecation handling composable across modules.


749-751: Nice addition: input object runtime guard.

Matches pattern of other guards; improves narrowing.


523-523: No signature widening issues detected.

The function parameter definitions: (MutableDefinitionNode | DefinitionNode)[] at composition/src/schema-building/utils.ts:523 is already compatible with its callers. The only caller passing this.routerDefinitions in federation-factory.ts (lines 2794, 3107) is already typed as (MutableDefinitionNode | DefinitionNode)[] (federation-factory.ts:290), matching the parameter type exactly. All callers are compatible.

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

16-16: Import path update verified—no stale imports remain.

All BASE_SCALARS imports across the codebase have been consistently updated to the new path ../constants/constants. The new path is valid, and no references to the old path exist. The change is safe and complete.

composition/src/schema-building/ast.ts (1)

266-274: ****

The review comment assumes MutableDefinitionNode was renamed from MutableTypeDefinitionNode, but git history shows MutableTypeDefinitionNode has never existed in this codebase. There is no evidence of a rename occurring, therefore no breaking change to mitigate. The back-compat alias suggestion should be disregarded.

Likely an incorrect or invalid review comment.

composition/tests/v1/types/interfaces.test.ts (2)

20-20: Good move to centralized test helpers/constants.

Imports of INACCESSIBLE_DIRECTIVE, SCHEMA_QUERY_DEFINITION, TAG_DIRECTIVE and normalizeSubgraphSuccess/Failure align tests with the new API surface. No issues.

Also applies to: 25-27


1657-1709: New invalid‑implementation fixtures (naaaa, nbaaa) look solid.

They exercise argument type/arity, accessibility, and unimplemented fields well; assertions above match the shapes.

To guard against accidental future edits, consider pinning a snapshot of the expected error shapes for these two cases.

composition/tests/v1/router-configuration.test.ts (1)

22-24: Destructuring configurationDataByTypeName from normalizeSubgraphSuccess is clean.

Matches the updated test helper contract; assertions remain intact.

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

19-19: Import path update verified—no changes needed.

Both exports exist with correct types: BASE_SCALARS is a Set and EDFS_ARGS_REGEXP is a RegExp. The import path correctly resolves and the change is safe.

composition/src/v1/normalization/directive-definition-data.ts (1)

77-109: Imports verified—code changes are correct.

All imports originate from their expected modules with the correct AST node shapes. REQUIRED_*_TYPE_NODE constants are properly typed NonNull wrappers, and all DEFINITION constants are DirectiveDefinitionNode types as expected. The refactoring to v1/constants modules is consistent and complete.

composition-go/composition_test.go (1)

72-100: LGTM! SDL expectations updated to reflect selective directive injection.

The expected SDL now includes only the directives that are actively used (@requiresScopes and @authenticated), along with the new openfed__Scope scalar. This aligns with the PR objective of selectively injecting directive definitions and dependencies rather than including all possible directives upfront.

composition/tests/v1/directives/interface-object.test.ts (3)

29-29: LGTM! Updated to use new test constants.

The import of SCHEMA_QUERY_DEFINITION from the shared utils aligns with the broader refactor to centralize directive and schema definition constants.


33-37: LGTM! Cleaner error destructuring pattern.

The updated pattern directly destructures errors from the failure result, simplifying access compared to the previous result.errors approach.


47-87: LGTM! Consistent migration to SCHEMA_QUERY_DEFINITION.

All test expectations now use SCHEMA_QUERY_DEFINITION as the canonical SDL prefix, replacing the previous versionTwoRouterDefinitions. This standardization improves test maintainability and aligns with the new constant organization.

Also applies to: 169-209, 291-331, 414-454, 534-562, 636-667, 675-699, 707-731, 774-822

composition/src/v1/constants/type-nodes.ts (1)

1-13: LGTM! Well-structured TypeNode constants.

These reusable TypeNode constants (REQUIRED_STRING_TYPE_NODE and REQUIRED_FIELDSET_TYPE_NODE) follow GraphQL AST patterns correctly and will help ensure consistency across directive definitions that require these common type structures.

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

1-15: LGTM! Clean type definition for directive extraction parameters.

The new ExtractPersistedDirectivesParams type provides well-structured parameters for the directive extraction flow, supporting the selective injection feature described in the PR objectives.

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

64-71: LGTM! Useful optional variant of existing utility.

The addOptionalIterableValuesToSet function is a clean addition that mirrors the existing addIterableValuesToSet pattern while handling optional sources gracefully with an early guard clause.

composition/tests/v1/directives/require-fetch-reasons.test.ts (3)

13-13: LGTM! Updated imports for new test constants.

The imports now include REQUEST_FETCH_REASONS_DIRECTIVE and SCHEMA_QUERY_DEFINITION, replacing the previous consolidated definition imports. This aligns with the selective directive injection approach.


23-33: LGTM! Consistent use of SCHEMA_QUERY_DEFINITION.

All federated graph schema expectations now use SCHEMA_QUERY_DEFINITION as the base, replacing versionOneRouterDefinitions. This standardization improves test clarity and maintainability.

Also applies to: 67-82, 117-132, 167-182, 217-232, 267-282, 317-332, 367-384


392-409: LGTM! Explicit directive inclusion in subgraph schemas.

The subgraph-specific schemas now explicitly concatenate SCHEMA_QUERY_DEFINITION with REQUEST_FETCH_REASONS_DIRECTIVE, reflecting the selective directive injection where directives are only included when actually used.

Also applies to: 438-457

composition/tests/v1/directives/external.test.ts (5)

19-19: LGTM! Updated imports for new directive constants.

The imports now include individual directive constants (EXTERNAL_DIRECTIVE, KEY_DIRECTIVE, OPENFED_FIELD_SET) and SCHEMA_QUERY_DEFINITION, replacing the previous consolidated router definition imports.


32-60: LGTM! Explicit directive fragments in normalized schema expectations.

The test expectations now explicitly include directive fragments (EXTERNAL_DIRECTIVE, KEY_DIRECTIVE) rather than relying on base definition sets. This makes the expected output more explicit and aligns with selective directive injection. Note the subgraph reference changed from na to naaaa (defined at line 1171).

Also applies to: 63-91


94-108: LGTM! Proper directive and scalar fragment composition.

The expected output correctly combines EXTERNAL_DIRECTIVE, KEY_DIRECTIVE, and OPENFED_FIELD_SET to construct the complete schema expectation.


337-370: LGTM! Systematic migration to SCHEMA_QUERY_DEFINITION.

All federation test expectations consistently use SCHEMA_QUERY_DEFINITION as the base SDL prefix. The systematic nature of these changes demonstrates a well-executed refactor across the entire test suite.

Also applies to: 374-407, 411-447, 450-486, 489-525, 528-564, 567-603, 606-642, 645-665, 668-688, 702-720, 723-742, 745-764, 767-819, 824-885, 888-944, 970-1022, 1025-1086, 1089-1145


1171-1197: Subgraph renamed from na to naaaa for consistency.

The subgraph definition was renamed, and all references in the test file have been updated accordingly. This maintains internal consistency within the test suite.

composition/src/index.ts (1)

30-35: LGTM! Improved constants organization with centralized exports.

The new exports consolidate v1 constants into dedicated modules (constants, directive-definitions, integers, non-directive-definitions, strings, type-nodes) rather than scattering them across utility modules. This improves discoverability and maintainability of the public API.

Note: This represents a public API surface change. If there are external consumers importing from the previous v1/utils/constants paths, they will need to update their imports.

composition/tests/v1/types/arguments.test.ts (1)

37-41: Good switch to direct destructuring

Using { federatedGraphSchema } improves clarity and avoids leaking helper internals. LGTM.

Also applies to: 61-66

composition/tests/v1/directives/shareable.test.ts (1)

110-133: Permutation tests read well

Order-invariance across subgraphs is covered comprehensively. LGTM.

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

61-62: Rename ripple check verified: customDirectiveDefinitionByName

No remaining references to the old property name exist. The new property customDirectiveDefinitionByName is properly defined (normalization-factory.ts:389), written to (walkers.ts:61), and read from (normalization-factory.ts:3447). The rename is complete and consistent.

composition/tests/v1/types/scalars.test.ts (1)

22-26: Good migration to new normalization/federation helpers.

Destructured results and constant fragments are used cleanly; assertions look correct.

Also applies to: 33-38, 46-49, 71-80

composition/tests/v1/directives/subscription-filter.test.ts (1)

1-33: The review comment is incorrect. NormalizationSuccess is still publicly exported and the cast is necessary.

NormalizationSuccess is re-exported from the main index via export * from './normalization/types', making it part of the public API. The cast in normalizeSubgraphSuccess is not redundant—it serves a purpose: TypeScript needs it to narrow the return type after the expect() assertion, since normalizeSubgraph() returns a union type (success | failure). Removing the import and cast would break the test utilities and dependent tests.

Likely an incorrect or invalid review comment.

composition/tests/v1/normalization.test.ts (1)

789-861: Nice shift to public constants and selective injection.

Using SCHEMA_QUERY_DEFINITION, KEY_DIRECTIVE, SHAREABLE_DIRECTIVE, TAG_DIRECTIVE, and OPENFED_FIELD_SET/OPENFED_SCOPE keeps tests aligned with the new public surface.

composition/tests/v1/directives/authorization-directives.test.ts (1)

12-17: Selective directive injection looks consistent.

Good move to explicit AUTHENTICATED/REQUIRES_SCOPES constants and appending OPENFED_SCOPE only when needed.

Consider adding one negative test asserting OPENFED_SCOPE is not present when no @requiresScopes is used, to guard over‑injection regressions.

Also applies to: 300-318, 575-592

composition/tests/v1/types/enums.test.ts (1)

13-21: Good migration to helper-based test APIs.

Switch to normalizeSubgraphSuccess/Failure and shared directive constants improves readability and reduces boilerplate. No issues found.

composition/src/v1/constants/constants.ts (1)

170-178: Confirm intentional omission of LINK from VERSION_TWO_DIRECTIVE_DEFINITIONS.

LINK is present in V2 map but not in VERSION_TWO_DIRECTIVE_DEFINITIONS[]. If excluded by design (e.g., injected separately), add a brief comment to prevent re-introduction. If not, include it.

[suggest_minor_issue]

composition/tests/v1/directives/inaccessible.test.ts (1)

33-41: LGTM on helper migration and SDL assembly.

Use of federateSubgraphsSuccess/Failure and concatenated SCHEMA_QUERY_DEFINITION + INACCESSIBLE_DIRECTIVE matches the new public test utilities and reads clean.

Also applies to: 266-275, 308-316, 356-364, 405-414, 477-486, 521-529, 579-587, 755-763, 795-803, 835-843, 855-873

composition/tests/v1/types/inputs.test.ts (1)

32-47: LGTM on helper migration and use of SCHEMA_QUERY_DEFINITION/TAG_DIRECTIVE.

Assertions align with new return shapes and shared constants; expectations look correct.

Also applies to: 238-260, 305-324, 342-359, 361-380

composition/tests/v1/types/objects.test.ts (1)

31-41: Helper migration and SDL assertions look solid.

The normalization/federation tests consistently use the new helpers and constants; expectations match the updated flows.

Also applies to: 43-55, 58-69, 71-82, 84-96, 98-109, 139-151, 153-165, 167-179, 181-193, 243-253, 288-309, 311-331, 333-337, 339-359, 361-381, 401-419, 466-486, 487-506

composition/tests/v1/directives/override.test.ts (1)

35-42: LGTM: normalization error surface.

Using normalizeSubgraphFailure and destructuring { errors } aligns with the new API surface.

composition/tests/v1/federation-factory.test.ts (2)

582-591: LGTM: schema prefix constants and client schema assertions.

Switch to SCHEMA_* and persisted directive constants is consistent across tests; client vs server schema checks look sound.

Also applies to: 610-621, 626-639, 642-699


564-572: Fix Map length assertions (use .size).

directiveDefinitionByDirectiveName appears to be a Map/Set (has method). toHaveLength expects a length property and will fail.

Apply:

-expect(subgraphAConfig!.directiveDefinitionByDirectiveName).toHaveLength(2);
+expect(subgraphAConfig!.directiveDefinitionByDirectiveName.size).toBe(2);
@@
-expect(subgraphBConfig!.directiveDefinitionByDirectiveName).toHaveLength(3);
+expect(subgraphBConfig!.directiveDefinitionByDirectiveName.size).toBe(3);

Also applies to: 568-571

⛔ Skipped due to learnings
Learnt from: Aenimus
PR: wundergraph/cosmo#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`.
composition/src/v1/constants/non-directive-definitions.ts (1)

2-2: Import path confirmed — no change required.

'../../ast/utils' resolves to composition/src/ast/utils.ts (defines stringToNameNode and stringToNamedTypeNode) and the same import is used across composition/src/v1; leave as-is.

composition/src/v1/constants/directive-definitions.ts (1)

480-514: @link(as) nullability: comment vs implementation mismatch

The doc comment says as: String! but the implementation makes as optional. Please confirm the intended spec and align comment/AST accordingly. If as must be required, wrap in NON_NULL. If optional, update the comment.

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

167-172: No issues found—type annotation confirms AST nodes are exported

The export declaration at line 103 of composition/src/v1/constants/strings.ts correctly types the values as Array<DefinitionNode> (AST nodes, not strings), matching the expected usage. No type/runtime mismatch exists.


2669-2755: ****

The review comment is based on a faulty assumption. The edfsDirectiveReferences set IS being populated in walkers.ts line 50 during the Directive visitor traversal.

In the normalize() method, upsertDirectiveSchemaAndEntityDefinitions() is called first at line 3455. This walker uses graphql-js's visit() function to traverse the entire document, including all Directive nodes (both global and field-level). When a directive name matches EVENT_DIRECTIVE_NAMES, it's added to edfsDirectiveReferences at line 50.

By the time extractEventDirectivesToConfiguration() is invoked at line 348 of walkers.ts during field processing, the set is already populated. Adding the suggested insertion would constitute redundant work, as the directives have already been registered by the earlier visitor pass.

The existing code flow is correct. No changes are required.

Likely an incorrect or invalid review comment.

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

256-257: TypeName-centric maps and definition arrays: good upgrade

Switch to Map<TypeName,…> and widening of router/client definition arrays improves type-safety and flexibility. Seeded persistedDirectiveDefinitionByDirectiveName looks correct.

Also applies to: 260-264, 276-287, 291-291


649-653: Consistent wiring of extractPersistedDirectives across copy/upsert paths

Good consistency; persisted directives now flow to enums, args, fields, and parent nodes uniformly.

Also applies to: 680-684, 864-868, 968-972, 990-994, 1019-1023, 1079-1083, 1235-1239


2246-2247: Good placement of directive def/deps injection

Running after tag-data generation and before auth propagation ensures definitions exist before schema assembly.


2283-2297: I'll search for more specific information about the dependencies and how client directives are filtered to verify the concerns.The web search wasn't specific to the codebase. Let me search directly in the code for overlapping dependencies.Based on my analysis of the code search results and the review comment, I now have enough information to generate my final response:

Confirm that deduplication is necessary and the client set alignment is valid

Looking at the code search results:

  • DEPENDENCIES_BY_DIRECTIVE_NAME entries show that multiple directives can share dependencies (e.g., multiple directives depend on scalar types and input object types)
  • CLIENT_PERSISTED_DIRECTIVE_NAMES = {DEPRECATED, ONE_OF, SEMANTIC_NON_NULL}
  • getClientPersistedDirectiveNodes() filters for these same three directive names
  • The current code does not deduplicate, so shared dependencies would be added multiple times

The review concern is valid and accurate. The suggested refactor addresses a real issue. The client directive alignment is also correct - the same directive set that gets added to client definitions is the one filtered by getClientPersistedDirectiveNodes().

Avoid duplicate definition insertion and align client directive surface

The current implementation risks appending shared dependencies multiple times to routerDefinitions and clientDefinitions arrays when multiple directives reference the same scalar or type dependencies. The suggested de-duplication using Sets to track already-added definitions is appropriate and necessary.

The client directive alignment is correct: CLIENT_PERSISTED_DIRECTIVE_NAMES ({DEPRECATED, ONE_OF, SEMANTIC_NON_NULL}) matches what getClientPersistedDirectiveNodes() emits, ensuring consistency between the directive set added to clientDefinitions and what the client schema ultimately receives.

The refactor is sound and addresses legitimate concerns.


1946-1948: IGNORED_FEDERATED_TYPE_NAMES guards are correctly scoped to applicable type cases

Based on code inspection, the current guard placement is correct and intentional. The IGNORED_FEDERATED_TYPE_NAMES set contains only internal federation metadata types: 5 scalars (BOOLEAN_SCALAR, ID_SCALAR, INT_SCALAR, FLOAT_SCALAR, STRING_SCALAR), 1 enum (LINK_PURPOSE), and 7 input objects (e.g., SUBSCRIPTION_FIELD_CONDITION, EDFS_NATS_STREAM_CONFIGURATION).

The guards are positioned only where these types can occur:

  • Line 1946: Inside Kind.ENUM_TYPE_DEFINITION case (enum LINK_PURPOSE is guarded)
  • Line 2015: Inside Kind.INPUT_OBJECT_TYPE_DEFINITION case (input objects like SUBSCRIPTION_FIELD_CONDITION are guarded)
  • Line 2155: Inside Kind.SCALAR_TYPE_DEFINITION case (scalars like BOOLEAN_SCALAR are guarded)

The OBJECT_TYPE_DEFINITION, INTERFACE_TYPE_DEFINITION, and UNION_TYPE_DEFINITION cases correctly have no guards because no composite output types appear in the IGNORED set—these are user-defined types that must always be processed.


279-287: Seeded directive-definition map is correctly synchronized with injection registry

All seven directives in persistedDirectiveDefinitionByDirectiveName (AUTHENTICATED, DEPRECATED, INACCESSIBLE, ONE_OF, REQUIRES_SCOPES, SEMANTIC_NON_NULL, TAG) are present in DIRECTIVE_DEFINITION_BY_NAME and reference the identical definition objects from directive-definitions.ts.

Since both maps use the same object references rather than duplicating definitions, semantic consistency of repeatable and locations properties is guaranteed by design—there is no risk of mismatch. The current implementation correctly prevents the drift concern raised in the review comment.

@Aenimus
Copy link
Member Author

Aenimus commented Oct 29, 2025

@coderabbitai pause

@Aenimus
Copy link
Member Author

Aenimus commented Oct 29, 2025

@coderabbitai full review

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

✅ Actions performed

Reviews paused.

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: 4

Caution

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

⚠️ Outside diff range comments (4)
composition/src/v1/normalization/directive-definition-data.ts (1)

407-447: Include streamConfiguration in optional args

NATS subscribe defines STREAM_CONFIGURATION in argument types but not in optionalArgumentNames. Add it for completeness and clearer validation semantics.

 export const NATS_SUBSCRIBE_DEFINITION_DATA: DirectiveDefinitionData = {
   argumentTypeNodeByName: new Map<string, ArgumentData>([
@@
   ]),
   isRepeatable: false,
   locations: new Set<string>([FIELD_DEFINITION_UPPER]),
   name: EDFS_NATS_SUBSCRIBE,
   node: EDFS_NATS_SUBSCRIBE_DEFINITION,
-  optionalArgumentNames: new Set<string>([PROVIDER_ID]),
+  optionalArgumentNames: new Set<string>([PROVIDER_ID, STREAM_CONFIGURATION]),
   requiredArgumentNames: new Set<string>([SUBJECTS]),
 };
composition/src/v1/normalization/walkers.ts (1)

182-191: Bug: duplicate operation types error is not recorded

duplicateOperationTypeDefinitionError(...) is called but not pushed to nf.errors, so duplicates won’t surface.

-        if (definitionNode) {
-          duplicateOperationTypeDefinitionError(
-            operationType,
-            namedTypeName,
-            getTypeNodeNamedTypeName(definitionNode.type),
-          );
-          return false;
-        }
+        if (definitionNode) {
+          nf.errors.push(
+            duplicateOperationTypeDefinitionError(
+              operationType,
+              namedTypeName,
+              getTypeNodeNamedTypeName(definitionNode.type),
+            ),
+          );
+          return false;
+        }
composition/tests/v1/directives/authorization-directives.test.ts (1)

1655-1660: Fix subgraph name typo (breaks warning/error provenance).

Variable is fda but its name is "ng". Use a consistent name to avoid confusing diagnostics.

-const fda: Subgraph = {
-  name: 'ng',
+const fda: Subgraph = {
+  name: 'fda',
composition/src/v1/normalization/normalization-factory.ts (1)

1085-1125: Custom directive definitions not emitted; populate customDirectiveDefinitionByName

#addDirectiveDefinitionsToDocument emits this.customDirectiveDefinitionByName, but addDirectiveDefinitionDataByNode never sets it for custom directives. Result: custom @Directives defined in SDL won’t appear in the output AST.

Add:

   addDirectiveDefinitionDataByNode(node: DirectiveDefinitionNode): boolean {
     const name = node.name.value;
     if (this.definedDirectiveNames.has(name)) {
       this.errors.push(duplicateDirectiveDefinitionError(name));
       return false;
     }
     this.definedDirectiveNames.add(name);
     // Normalize federation directives by replacing them with predefined definitions
     const definition = V2_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME.get(name);
     // Add the V2 directive definitions regardless of use so the subgraph can be recognised as a V2 subgraph.
     if (definition) {
       this.directiveDefinitionByName.set(name, definition);
       // Uses of the directive also set this boolean in the walker.
       this.isSubgraphVersionTwo = true;
       return false;
     }
     // Other known directives will only be added if they are used.
     if (DIRECTIVE_DEFINITION_BY_NAME.has(name)) {
       return false;
     }
-    this.directiveDefinitionByName.set(name, node);
+    this.directiveDefinitionByName.set(name, node);
+    this.customDirectiveDefinitionByName.set(name as DirectiveName, node);
♻️ Duplicate comments (4)
composition/tests/v1/resolvability.test.ts (1)

1059-1059: The typo has already been corrected.

The past review comment suggested changing "frm" to "from", but the test title already correctly uses "from" in the current code.

composition/src/v1/constants/constants.ts (1)

108-118: Fix BASE_SCALARS: remove non-existent “_Entities” scalar and use shared ANY constant

“_Entities” isn’t a scalar in federation; leave only real scalars. Also, avoid the literal '_Any' and use the shared ANY_SCALAR constant for consistency.

@@
-import { DirectiveDefinitionNode } from 'graphql';
+import { DirectiveDefinitionNode } from 'graphql';
@@
-  BOOLEAN_SCALAR,
+  BOOLEAN_SCALAR,
   COMPOSE_DIRECTIVE,
@@
   STRING_SCALAR,
   SUBSCRIPTION_FILTER,
   TAG,
 } from '../../utils/string-constants';
+// Optional: if available in this module, import ANY_SCALAR for consistency
+// (already used elsewhere, e.g., in walkers.ts)
+import { ANY_SCALAR } from '../../utils/string-constants';
@@
-export const BASE_SCALARS: ReadonlySet<string> = new Set<string>([
-  '_Any',
-  '_Entities',
-  BOOLEAN_SCALAR,
-  FLOAT_SCALAR,
-  ID_SCALAR,
-  INT_SCALAR,
-  FIELD_SET_SCALAR,
-  SCOPE_SCALAR,
-  STRING_SCALAR,
-]);
+export const BASE_SCALARS: ReadonlySet<string> = new Set<string>([
+  ANY_SCALAR,
+  BOOLEAN_SCALAR,
+  FLOAT_SCALAR,
+  ID_SCALAR,
+  INT_SCALAR,
+  FIELD_SET_SCALAR,
+  SCOPE_SCALAR,
+  STRING_SCALAR,
+]);
composition/tests/v1/directives/configure-description.test.ts (1)

670-675: Title corrected (“Scalar” propagation).

Previous misnaming is fixed. Thanks for aligning the title with the assertions.

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

3441-3457: Referenced V2 directives are not flagged/injected; set isSubgraphVersionTwo and load from V2 map

When a V2 directive is referenced (common), we should inject its definition and flip the version flag. Current code only checks DIRECTIVE_DEFINITION_BY_NAME and never sets isSubgraphVersionTwo here, so V2-only references are missed.

Apply:

   #addDirectiveDefinitionsToDocument(definitions: Array<DefinitionNode>): void {
     const dependencies = new Set<DefinitionNode>();
     for (const directiveName of this.referencedDirectiveNames) {
-      const definition = DIRECTIVE_DEFINITION_BY_NAME.get(directiveName);
-      if (!definition) {
-        continue;
-      }
-      this.directiveDefinitionByName.set(directiveName, definition);
+      let definition = DIRECTIVE_DEFINITION_BY_NAME.get(directiveName);
+      if (!definition) {
+        // Handle federation V2 directives referenced (but not defined) in SDL
+        definition = V2_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME.get(directiveName);
+        if (!definition) {
+          continue;
+        }
+        this.isSubgraphVersionTwo = true;
+      }
+      this.directiveDefinitionByName.set(directiveName, definition);
       addOptionalIterableValuesToSet(dependencies, DEPENDENCIES_BY_DIRECTIVE_NAME.get(directiveName));
       definitions.push(definition);
     }
     // Always include custom directive definitions regardless of use.
     for (const definition of this.customDirectiveDefinitionByName.values()) {
       definitions.push(definition);
     }
     definitions.push(...dependencies);
   }
🧹 Nitpick comments (33)
composition/tests/v1/types/interfaces.test.ts (5)

20-28: Unify utils import source to avoid split-brain.

You import constants from '../utils/utils' and functions from '../../utils/utils'. If feasible, re-export the functions in v1/utils and use a single source to reduce drift.

Example (only if v1 utils can re-export the shared helpers):

-import { INACCESSIBLE_DIRECTIVE, SCHEMA_QUERY_DEFINITION, TAG_DIRECTIVE } from '../utils/utils';
-// ...
-import {
-  federateSubgraphsFailure,
-  federateSubgraphsSuccess,
-  normalizeString,
-  normalizeSubgraphFailure,
-  normalizeSubgraphSuccess,
-  schemaToSortedNormalizedString,
-} from '../../utils/utils';
+import {
+  INACCESSIBLE_DIRECTIVE,
+  SCHEMA_QUERY_DEFINITION,
+  TAG_DIRECTIVE,
+  federateSubgraphsFailure,
+  federateSubgraphsSuccess,
+  normalizeString,
+  normalizeSubgraphFailure,
+  normalizeSubgraphSuccess,
+  schemaToSortedNormalizedString,
+} from '../utils/utils';

245-331: Reduce brittleness of deep Map/Set equality in error assertions.

Strict equality over nested Map/Set relies on stable insertion/iteration order. If producers change ordering, tests may flake. Consider canonicalizing before compare (sort keys/convert Sets to sorted arrays) or matching structurally with partials.

Minimal pattern (conceptual):

// helpers (tests utils)
const canon = (v: unknown): unknown =>
  v instanceof Map
    ? Array.from(v.entries()).sort(([a], [b]) => String(a).localeCompare(String(b))).map(([k, val]) => [k, canon(val)])
    : v instanceof Set
    ? Array.from(v.values()).sort()
    : Array.isArray(v)
    ? v.map(canon)
    : typeof v === 'object' && v !== null
    ? Object.fromEntries(Object.entries(v).sort(([a],[b]) => a.localeCompare(b)).map(([k,val])=>[k, canon(val)]))
    : v;

// then:
expect(canon(errors[0])).toStrictEqual(canon(expected0));
expect(canon(errors[1])).toStrictEqual(canon(expected1));

Also applies to: 333-409


459-501: De‑duplicate order-variance tests with test.each.

Both tests assert identical SDL with different subgraph order. Use parameterized cases to reduce duplication and ease future edits.

Apply:

-test('that an Interface type and extension definition federate successfully #1.1', () => {
-  const { federatedGraphSchema } = federateSubgraphsSuccess(
-    [subgraphQ, subgraphR, subgraphU],
-    ROUTER_COMPATIBILITY_VERSION_ONE,
-  );
-  expect(schemaToSortedNormalizedString(federatedGraphSchema)).toBe(
-    normalizeString(
-      SCHEMA_QUERY_DEFINITION +
-        `
-          interface Interface {
-            age: Int!
-            name: String!
-          }
-          
-          type Query {
-            dummy: String!
-          }
-        `,
-    ),
-  );
-});
-
-test('that an Interface type and extension definition federate successfully #1.2', () => {
-  const { federatedGraphSchema } = federateSubgraphsSuccess(
-    [subgraphQ, subgraphU, subgraphR],
-    ROUTER_COMPATIBILITY_VERSION_ONE,
-  );
-  expect(schemaToSortedNormalizedString(federatedGraphSchema)).toBe(
-    normalizeString(
-      SCHEMA_QUERY_DEFINITION +
-        `
-          interface Interface {
-            age: Int!
-            name: String!
-          }
-          
-          type Query {
-            dummy: String!
-          }
-        `,
-    ),
-  );
-});
+test.each([
+  [[subgraphQ, subgraphR, subgraphU], '#1.1'],
+  [[subgraphQ, subgraphU, subgraphR], '#1.2'],
+])('that an Interface type and extension definition federate successfully %s', (order) => {
+  const { federatedGraphSchema } = federateSubgraphsSuccess(order, ROUTER_COMPATIBILITY_VERSION_ONE);
+  expect(schemaToSortedNormalizedString(federatedGraphSchema)).toBe(
+    normalizeString(
+      SCHEMA_QUERY_DEFINITION +
+        `
+          interface Interface {
+            age: Int!
+            name: String!
+          }
+          
+          type Query {
+            dummy: String!
+          }
+        `,
+    ),
+  );
+});

431-437: Track the TODO with an issue or inline link.

Convert the TODO into a tracked task (issue/ADR) so future changes to @inaccessible/entity interfaces don’t leave tests stale.

I can open a follow-up issue with a short checklist if helpful.


1657-1709: Rename new fixtures for clarity (or add brief comments).

Identifiers naaaa/nbaaa are opaque. Prefer descriptive names (e.g., subgraphInvalidImplA/subgraphInvalidImplB) or add a comment above each block summarizing its role.

Apply (plus update references at Lines 245 and 333):

-const naaaa: Subgraph = {
+const subgraphInvalidImplA: Subgraph = {
   name: 'naaaa',
...
-const nbaaa: Subgraph = {
+const subgraphInvalidImplB: Subgraph = {
   name: 'nbaaa',
composition/tests/v1/events.test.ts (2)

157-196: Prefer using shared SDL constants to avoid drift

Inline input edfs__NatsStreamConfiguration is duplicated here. Use the shared fragment to reduce maintenance and ensure consistency.

Apply:

-      expect(schemaToSortedNormalizedString(schema)).toBe(
-        normalizeString(
-          SCHEMA_ALL_ROOTS_DEFINITION +
-            EDFS_NATS_PUBLISH_DIRECTIVE +
-            EDFS_NATS_REQUEST_DIRECTIVE +
-            EDFS_NATS_SUBSCRIBE_DIRECTIVE +
-            EXTERNAL_DIRECTIVE +
-            KEY_DIRECTIVE +
-            `
+      expect(schemaToSortedNormalizedString(schema)).toBe(
+        normalizeString(
+          SCHEMA_ALL_ROOTS_DEFINITION +
+            EDFS_NATS_PUBLISH_DIRECTIVE +
+            EDFS_NATS_REQUEST_DIRECTIVE +
+            EDFS_NATS_SUBSCRIBE_DIRECTIVE +
+            EXTERNAL_DIRECTIVE +
+            KEY_DIRECTIVE +
+            `
         type Entity @key(fields: "id", resolvable: false) {
           id: ID! @external
         }
 
         type Mutation {
           updateEntity(id: ID!, name: String!): edfs__PublishResult! @edfs__natsPublish(subject: "updateEntity.{{ args.id }}")
         }
 
         type Query {
           findEntity(id: ID!): Entity! @edfs__natsRequest(subject: "findEntity.{{ args.id }}")
         }
 
         type Subscription {
           entitySubscription(id: ID!): Entity! @edfs__natsSubscribe(subjects: ["entities.{{ args.id }}"], providerId: "my-provider")
           entitySubscriptionTwo(firstID: ID!, secondID: ID!): Entity! @edfs__natsSubscribe(subjects: ["firstSub.{{ args.firstID }}", "secondSub.{{ args.secondID }}"], providerId: "double", streamConfiguration: {consumerName: "consumer", streamName: "streamName", consumerInactiveThreshold: 300})
         }
 
-        input edfs__NatsStreamConfiguration {
-          consumerInactiveThreshold: Int! = 30
-          consumerName: String!
-          streamName: String!
-        }
-
         type edfs__PublishResult {
          success: Boolean!
         }
 
         scalar openfed__FieldSet
       `,
+          ) + EDFS_NATS_STREAM_CONFIGURATION_INPUT + OPENFED_FIELD_SET
-        ),
+        ,
       );

1705-1718: Normalize subgraph name casing for consistency

The name 'subgraph-aH' mixes cases while others are lowercase. Consider 'subgraph-ah' for consistency across fixtures. Behavior is unaffected but reduces noise in diffs/logs.

-const subgraphAH: Subgraph = {
-  name: 'subgraph-aH',
+const subgraphAH: Subgraph = {
+  name: 'subgraph-ah',
composition/tests/v1/directives/provides.test.ts (2)

341-387: Reduce brittleness in deep Map/Set equality

Asserting full ConditionalFieldData structures is fragile. Prefer partial shape checks with objectContaining/maps to focus on intent.

Example:

- expect(conditionalFieldDataByCoordinates).toStrictEqual(new Map([...full structure...]));
+ expect(conditionalFieldDataByCoordinates.get('NestedObject.age')).toMatchObject({
+   providedBy: expect.arrayContaining([
+     expect.objectContaining({ fieldPath: ['entity','object','nestedObject','age'] }),
+     expect.objectContaining({ fieldPath: ['entities','object','nestedObject','age'] }),
+   ]),
+ });
+ expect(conditionalFieldDataByCoordinates.get('NestedObject.name')).toMatchObject({
+   providedBy: expect.arrayContaining([
+     expect.objectContaining({ fieldPath: ['entity','object','nestedObject','name'] }),
+     expect.objectContaining({ fieldPath: ['entities','object','nestedObject','name'] }),
+   ]),
+ });

479-511: Warning count assertions: be explicit about content, not just length

Verifying warnings length followed by element equality can be simplified to checking for the specific warning presence, which is more robust.

- expect(warnings).toHaveLength(1);
- expect(warnings[0]).toStrictEqual(
+ expect(warnings).toEqual([
   nonExternalConditionalFieldWarning(`Query.entity`, o.name, `Entity.id`, `id`, PROVIDES),
- );
+ ]);
composition/tests/v1/federation-factory.test.ts (2)

565-573: Avoid brittle size checks on directive definitions

Checking exact map size is fragile as new built-ins may appear. Assert presence of required directives instead.

-expect(subgraphAConfig!.directiveDefinitionByDirectiveName).toHaveLength(2);
-expect(subgraphAConfig!.directiveDefinitionByDirectiveName.has(KEY)).toBe(true);
-expect(subgraphAConfig!.directiveDefinitionByDirectiveName.has(SHAREABLE)).toBe(true);
+expect(subgraphAConfig!.directiveDefinitionByDirectiveName.has(KEY)).toBe(true);
+expect(subgraphAConfig!.directiveDefinitionByDirectiveName.has(SHAREABLE)).toBe(true);

And similarly for subgraphB: assert 'a', KEY, SHAREABLE exist without asserting total size.


94-99: Keep SDL fragments centralized

Good use of SCHEMA_ALL_ROOTS_DEFINITION/AUTHENTICATED/REQUIRES_SCOPES. Consider centralizing OPENFED_SCOPE and any new directive defs in the same utils aggregator to prevent future drift.

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

117-125: Make field-set normalization more robust to formatting

slice(2, -2) assumes leading/trailing "{ " / " }". Consider trimming by locating outer braces to be resilient to printer changes.

-export function getNormalizedFieldSet(documentNode: DocumentNode): string {
-  return print(lexicographicallySortDocumentNode(documentNode)).replaceAll(/\s+/g, ' ').slice(2, -2);
-}
+export function getNormalizedFieldSet(documentNode: DocumentNode): string {
+  const s = print(lexicographicallySortDocumentNode(documentNode)).replaceAll(/\s+/g, ' ').trim();
+  const start = s.indexOf('{');
+  const end = s.lastIndexOf('}');
+  return start >= 0 && end > start ? s.slice(start + 1, end).trim() : s;
+}
composition/src/v1/federation/utils.ts (1)

97-113: Minor: early-continue to reduce nesting

You can invert conditions to reduce nesting in validateImplicitFieldSets and keep the happy-path linear; functionality unchanged.

composition/tests/utils/utils.ts (1)

36-46: Improve debug output for failed normalization

Match federation logging by adding depth for better visibility.

-  if (!result.success) {
-    console.dir(result.errors);
-  }
+  if (!result.success) {
+    console.dir(result.errors, { depth: null });
+  }
composition/src/utils/utils.ts (1)

64-71: Consider aligning parameter order with the existing function.

The new addOptionalIterableValuesToSet has parameters ordered as (target, source?), while the existing addIterableValuesToSet (lines 58-62) uses (source, target). This inconsistency may cause confusion when developers switch between the two similar functions.

Apply this diff to align the parameter order:

-export function addOptionalIterableValuesToSet<T>(target: Set<T>, source?: Array<T> | Iterable<T>) {
+export function addOptionalIterableValuesToSet<T>(source: Array<T> | Iterable<T> | undefined, target: Set<T>) {
   if (!source) {
     return;
   }
   for (const value of source) {
     target.add(value);
   }
 }
composition/tests/v1/types/arguments.test.ts (2)

122-136: Minor: stray backticks in test titles

Titles like “that if arguments of the same name are not the same type, an error is returned`” have a trailing backtick. Drop it for consistency.

-  test('that if arguments of the same name are not the same type, an error is returned`', () => {
+  test('that if arguments of the same name are not the same type, an error is returned', () => {

36-53: Consistent result handling style in tests

Most tests now destructure outputs; a few still check result.success/fields directly. Consider standardizing on destructuring for readability.

Also applies to: 57-75, 78-96, 98-120, 185-205

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

430-446: LGTM; consider a small helper for Map/Set-heavy expectations

The repeated new Map<TypeName, ConfigurationData>(...) patterns are verbose. A tiny expectConfig helper could reduce duplication, but current assertions are fine.

composition/tests/v1/entity-interface.test.ts (1)

15-15: Use a type-only import for TypeName.

This is only used as a type. Prefer import type { TypeName } to avoid emitting a runtime import.

-import {
+import type {
   TypeName,
 } from '../../src';
composition/src/schema-building/utils.ts (2)

287-300: Harden upsertDeprecatedDirective for external callers.

Now that it’s exported, guard against missing/non-string reasons to avoid runtime errors if used outside the normalized path.

 export function upsertDeprecatedDirective(
   persistedDirectivesData: PersistedDirectivesData,
   incomingDirectiveNode: ConstDirectiveNode,
 ) {
-  if (!incomingDirectiveNode.arguments?.length) {
-    return;
-  }
-  // The argument was already validated in the normalization factory, so it can be safely cast
-  const incomingReasonString = (incomingDirectiveNode.arguments[0].value as StringValueNode).value;
+  const arg = incomingDirectiveNode.arguments?.find((a) => a.name.value === REASON);
+  if (!arg || arg.value.kind !== Kind.STRING) {
+    return;
+  }
+  const incomingReasonString = (arg.value as StringValueNode).value;
   if (persistedDirectivesData.deprecatedReason.length < incomingReasonString.length) {
     persistedDirectivesData.deprecatedReason = incomingReasonString;
   }
 }

301-310: Harden upsertTagDirectives for missing/invalid @tag(name: …).

Add simple guards so exported usage can’t throw on malformed nodes.

 export function upsertTagDirectives(
   persistedDirectivesData: PersistedDirectivesData,
   incomingDirectiveNodes: ConstDirectiveNode[],
 ) {
   for (const incomingDirectiveNode of incomingDirectiveNodes) {
-    // The argument was already validated in the normalization factory, so it can be safely cast
-    const incomingNameString = (incomingDirectiveNode.arguments![0].value as StringValueNode).value;
-    persistedDirectivesData.tagDirectiveByName.set(incomingNameString, incomingDirectiveNode);
+    const arg = incomingDirectiveNode.arguments?.find((a) => a.name.value === 'name');
+    if (!arg || arg.value.kind !== Kind.STRING) {
+      continue;
+    }
+    const incomingNameString = (arg.value as StringValueNode).value;
+    persistedDirectivesData.tagDirectiveByName.set(incomingNameString, incomingDirectiveNode);
   }
 }
composition/tests/v1/entities.test.ts (2)

14-15: Use a type-only import for TypeName.

It’s only used in generics; prefer import type { TypeName } to keep runtime clean.

-import {
+import type {
   TypeName,
 } from '../../src';

608-671: Reduce duplication with parameterized tests (optional).

The #1.x and #2.x suites repeat the same assertions across order permutations. Consider test.each to table-drive inputs while keeping a single assertion block.

// Example sketch:
test.each([
  { order: ['subgraph-u', 'subgraph-v'] },
  { order: ['subgraph-v', 'subgraph-u'] },
])('that if a target key can be satisfied, it will be included in the router configuration (%#)', ({ order }) => {
  const graphs = order.map((n) => ({ subgraphU, subgraphV } as any)[n]);
  const { federatedGraphSchema, subgraphConfigBySubgraphName } = federateSubgraphsSuccess(graphs, ROUTER_COMPATIBILITY_VERSION_ONE);
  // shared SDL and config assertions...
});

Also applies to: 673-736, 738-874, 876-1012, 1014-1150, 1152-1288, 1290-1426, 1428-1564

composition/tests/v1/directives/authorization-directives.test.ts (2)

61-76: Reduce SDL boilerplate with a tiny helper.

Repeated SCHEMA_QUERY_DEFINITION + [fragments] + body clutters tests. Extract a helper like withBaseSDL(body, ...fragments) to assemble once and reuse across this suite. Keeps assertions terse and consistent.


1897-1911: Remove unused fixture subgraphQ or reference it in a test.

Dead fixtures slow readers and risk drift. If not used, drop it.

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

342-345: Extract a base-SDL builder to cut repetition.

You repeatedly do SCHEMA_QUERY_DEFINITION + \...`. A withBaseSDL(body, ...fragments)` helper used across directive tests will reduce duplication and inconsistent whitespace.


236-275: TypeName is currently just string; suggestion is optional/defensive.

TypeName is defined as export type TypeName = string; in both composition/src/resolvability-graph/types/types.ts and composition/src/types/types.ts. String literals like 'Entity' are valid and will type‑check correctly as-is.

The suggestion to add a helper (e.g., const tn = (s: string) => s as TypeName;) is a defensive pattern to future‑proof against potential TypeName changes (e.g., if it becomes a branded type), but it's not required for the current codebase.

composition/tests/v1/directives/inaccessible.test.ts (1)

650-663: Unify success assertions with the new API.

Elsewhere you destructure federateSubgraphsSuccess results; here you still check result.success. Prefer a consistent pattern (either destructure or explicitly assert .success) for readability.

composition/tests/v1/directives/configure-description.test.ts (1)

85-91: Factor shared fragments into a helper.

Combine SCHEMA_QUERY_DEFINITION and CONFIGURE_DESCRIPTION_DIRECTIVE via a small withBaseSDL helper to keep expectations short and uniform across tests.

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

107-131: Parametrize permutation tests to reduce duplication.

The six “functions with extensions correctly” tests differ only in subgraph order. Wrap the orders in a table and loop to cut repetition and maintenance cost.


115-118: Introduce base-SDL helper for federation expectations.

Repeated SCHEMA_QUERY_DEFINITION + \...`patterns can be centralized (e.g.,withBaseSDL`), improving consistency across directive suites.

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

141-169: Name shadowing: imported vs. method getNodeForRouterSchemaByData

This file imports a function named getNodeForRouterSchemaByData and also defines a method with the same name. Calls without this. resolve to the import, which is easy to misread.

Suggestion: rename the class method to getRouterNodeForData (or alias the import) to avoid ambiguity. Low risk readability win.

Also applies to: 1834-1839

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

3728-3753: Naming consistency: consider aligning result key with internal map

Result still exports directiveDefinitionByDirectiveName while the internal is directiveDefinitionByName. Keeping for BC is fine; consider aliasing/renaming in a future major to avoid confusion.

Confirm external consumers still rely on directiveDefinitionByDirectiveName before any rename.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83e0ed6 and 32cf0df.

⛔ Files ignored due to path filters (1)
  • shared/test/__snapshots__/router.config.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (50)
  • composition-go/composition_test.go (1 hunks)
  • composition/src/index.ts (1 hunks)
  • composition/src/normalization/types.ts (2 hunks)
  • composition/src/schema-building/ast.ts (1 hunks)
  • composition/src/schema-building/utils.ts (7 hunks)
  • composition/src/subgraph/types.ts (1 hunks)
  • composition/src/utils/utils.ts (1 hunks)
  • composition/src/v1/constants/constants.ts (1 hunks)
  • composition/src/v1/constants/directive-definitions.ts (9 hunks)
  • composition/src/v1/constants/non-directive-definitions.ts (1 hunks)
  • composition/src/v1/constants/strings.ts (1 hunks)
  • composition/src/v1/constants/type-nodes.ts (1 hunks)
  • composition/src/v1/federation/federation-factory.ts (25 hunks)
  • composition/src/v1/federation/params.ts (1 hunks)
  • composition/src/v1/federation/utils.ts (1 hunks)
  • composition/src/v1/normalization/directive-definition-data.ts (1 hunks)
  • composition/src/v1/normalization/normalization-factory.ts (22 hunks)
  • composition/src/v1/normalization/types.ts (2 hunks)
  • composition/src/v1/normalization/utils.ts (1 hunks)
  • composition/src/v1/normalization/walkers.ts (7 hunks)
  • composition/src/v1/utils/string-constants.ts (0 hunks)
  • composition/src/v1/utils/utils.ts (1 hunks)
  • composition/tests/utils/utils.ts (2 hunks)
  • composition/tests/v1/contracts.test.ts (134 hunks)
  • composition/tests/v1/directives/authorization-directives.test.ts (36 hunks)
  • composition/tests/v1/directives/configure-description.test.ts (17 hunks)
  • composition/tests/v1/directives/directives.test.ts (12 hunks)
  • composition/tests/v1/directives/external.test.ts (34 hunks)
  • composition/tests/v1/directives/fieldset-directives.test.ts (21 hunks)
  • composition/tests/v1/directives/inaccessible.test.ts (30 hunks)
  • composition/tests/v1/directives/interface-object.test.ts (14 hunks)
  • composition/tests/v1/directives/one-of.test.ts (13 hunks)
  • composition/tests/v1/directives/override.test.ts (32 hunks)
  • composition/tests/v1/directives/provides.test.ts (32 hunks)
  • composition/tests/v1/directives/require-fetch-reasons.test.ts (11 hunks)
  • composition/tests/v1/directives/semantic-non-null.test.ts (22 hunks)
  • composition/tests/v1/directives/shareable.test.ts (12 hunks)
  • composition/tests/v1/directives/subscription-filter.test.ts (2 hunks)
  • composition/tests/v1/directives/v2-directives.test.ts (3 hunks)
  • composition/tests/v1/entities.test.ts (45 hunks)
  • composition/tests/v1/entity-interface.test.ts (8 hunks)
  • composition/tests/v1/events.test.ts (29 hunks)
  • composition/tests/v1/federation-factory.test.ts (22 hunks)
  • composition/tests/v1/normalization.test.ts (73 hunks)
  • composition/tests/v1/resolvability.test.ts (38 hunks)
  • composition/tests/v1/router-configuration.test.ts (12 hunks)
  • composition/tests/v1/types/arguments.test.ts (8 hunks)
  • composition/tests/v1/types/enums.test.ts (11 hunks)
  • composition/tests/v1/types/inputs.test.ts (6 hunks)
  • composition/tests/v1/types/interfaces.test.ts (29 hunks)
💤 Files with no reviewable changes (1)
  • composition/src/v1/utils/string-constants.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-08T20:57:07.946Z
Learnt from: JivusAyrus
PR: wundergraph/cosmo#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/normalization.test.ts
🔇 Additional comments (50)
composition/tests/v1/directives/semantic-non-null.test.ts (1)

24-24: LGTM! Good refactoring to centralize test utilities.

The consolidation of schema definition constants into reusable imports improves maintainability and consistency across tests.

composition/tests/v1/types/interfaces.test.ts (2)

33-35: LGTM: migration to normalizeSubgraphSuccess/Failure.

Adoption of the higher-level helpers improves readability and reduces branching on result.success. Keep it consistent across the file.


773-802: Nice fix: varied subgraph order now truly differs across “#1.1”/“#1.2”.

This resolves the earlier copy/paste oversight. Good.

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

33-33: LGTM! Clean import path updates.

The import paths have been updated to reflect the reorganized constants structure, aligning with the broader refactoring to centralize v1 constants into dedicated modules.

Also applies to: 37-37

composition/src/subgraph/types.ts (1)

27-27: LGTM! Type strengthening with TypeName.

The map key type has been narrowed from string to TypeName, improving type safety and aligning with the broader pattern of using TypeName throughout the codebase.

composition/src/normalization/types.ts (1)

14-14: LGTM! Consistent type strengthening.

The addition of the TypeName import and the narrowing of configurationDataByTypeName's key type from string to TypeName improves type safety and maintains consistency with related interfaces like InternalSubgraph.

Also applies to: 26-26

composition/src/v1/constants/type-nodes.ts (1)

1-13: LGTM! Well-structured reusable type node constants.

These constants centralize commonly used required scalar type nodes (String! and openfed__FieldSet!), promoting code reuse and consistency across the GraphQL type construction logic.

composition/tests/v1/normalization.test.ts (3)

51-59: LGTM! Centralized test constants improve maintainability.

Importing reusable directive and schema definition constants from the test utils reduces duplication and makes tests easier to maintain.


66-71: LGTM! Cleaner test patterns with destructuring.

The refactoring to destructure { errors } or { schema } directly from normalization results makes the tests more concise and readable, while maintaining explicit type assertions.

Also applies to: 88-113


162-171: LGTM! Consistent use of SDL constants in test expectations.

Using centralized constants like KEY_DIRECTIVE and OPENFED_FIELD_SET in expected test outputs improves maintainability and ensures consistency across tests.

Also applies to: 190-199

composition/tests/v1/directives/require-fetch-reasons.test.ts (2)

6-6: LGTM! Consolidated imports align with public API.

The import of parse from the public API and the use of centralized test constants (REQUEST_FETCH_REASONS_DIRECTIVE, SCHEMA_QUERY_DEFINITION) improve consistency and maintainability.

Also applies to: 13-13


23-34: LGTM! Consistent use of schema definition constants.

The consistent application of SCHEMA_QUERY_DEFINITION and REQUEST_FETCH_REASONS_DIRECTIVE throughout test expectations ensures that schema definition changes only need to be made in one place.

Also applies to: 67-83, 392-410

composition/tests/v1/types/enums.test.ts (2)

13-13: LGTM! Improved test utilities and constants.

The imports of test helper functions (normalizeSubgraphSuccess, normalizeSubgraphFailure) and centralized constants (INACCESSIBLE_DIRECTIVE, SCHEMA_QUERY_DEFINITION, TAG_DIRECTIVE) make tests more maintainable and easier to read.

Also applies to: 18-21


26-36: LGTM! Cleaner test patterns with helper functions.

Using normalizeSubgraphSuccess and normalizeSubgraphFailure helpers with destructuring provides a cleaner and more consistent test pattern compared to checking result.success flags.

Also applies to: 191-194

composition/src/v1/constants/non-directive-definitions.ts (3)

35-68: LGTM! Well-structured input object with default value.

The EDFS_NATS_STREAM_CONFIGURATION_DEFINITION is properly constructed with three required fields, including a sensible default value for consumerInactiveThreshold.


71-109: LGTM! Scalar and enum definitions are correct.

The scalar type definitions (FIELD_SET_SCALAR_DEFINITION, LINK_IMPORT_DEFINITION, SCOPE_SCALAR_DEFINITION) and the LINK_PURPOSE_DEFINITION enum are properly structured with appropriate AST node kinds and values.


116-186: LGTM! Properly structured recursive filter definitions.

The subscription filter definitions correctly model a recursive filtering structure:

  • SUBSCRIPTION_FIELD_CONDITION_DEFINITION defines field-level conditions
  • SUBSCRIPTION_FILTER_CONDITION_DEFINITION allows composing conditions with AND/OR/NOT operators and correctly references itself for nested logic

The recursive structure is intentional and appropriate for building complex filter expressions.

composition/src/schema-building/ast.ts (1)

266-274: Verify public API status of old type name before adding backcompat alias

The old type name MutableTypeDefinitionNode has no references anywhere in the codebase, including in generated .d.ts files or barrel exports. The backcompat alias is a defensive measure, but its necessity depends on whether this name was ever part of the public API in a previous release. Confirm the following before implementing:

  1. Was MutableTypeDefinitionNode exported as part of a public release?
  2. Are there known external consumers using the old name?
  3. Is this PR renaming an existing public export, or introducing a new internal type?

If the old name was genuinely public, add the backcompat alias as suggested. If not, the alias may be unnecessary.

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

12-15: LGTM!

The new ExtractPersistedDirectivesParams type is well-defined and follows TypeScript best practices. The fields are appropriately typed and align with the centralized directive extraction flow mentioned in the PR objectives.

composition/tests/v1/directives/interface-object.test.ts (2)

16-30: LGTM!

The import updates align with the PR's objective to use public API exports and centralized schema definitions. The migration from direct GraphQL imports to the public API surface (parse, TypeName, SCHEMA_QUERY_DEFINITION) improves consistency across the test suite.


93-93: LGTM!

The type annotation update from Map<string, ConfigurationData> to Map<TypeName, ConfigurationData> provides stronger typing and aligns with the PR's migration to TypeName-based keys.

composition-go/composition_test.go (1)

73-77: LGTM!

The SDL updates correctly reflect the new schema surface, including the introduction of the openfed__Scope scalar and adjusted directive definitions. The test assertions remain intact and valid.

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

80-89: LGTM!

The discriminated union pattern for UpsertInputObjectResult is a robust approach that enables type-safe error handling. The success flag allows TypeScript to narrow the type and provide compile-time safety when accessing the data field.

composition/tests/v1/router-configuration.test.ts (1)

23-25: LGTM!

The destructuring pattern simplifies test assertions and the TypeName-based typing provides stronger type safety. These changes align well with the PR's migration to a more robust public API surface.

composition/tests/v1/directives/v2-directives.test.ts (1)

10-10: LGTM!

The import and usage of SCHEMA_QUERY_DEFINITION centralizes schema fragment definitions and aligns with the broader test suite refactoring.

composition/tests/v1/resolvability.test.ts (1)

20-20: LGTM!

The import of centralized constants (INACCESSIBLE_DIRECTIVE, SCHEMA_QUERY_DEFINITION) improves consistency across the test suite and aligns with the PR's migration to a unified public API surface.

composition/tests/v1/directives/one-of.test.ts (1)

78-86: Comment/expectation alignment looks good

“directive definition” wording now matches the preserved SDL usage of @OneOf. LGTM.

composition/tests/v1/contracts.test.ts (1)

1068-1076: Centralizing SDL fragments via SCHEMA_QUERY_DEFINITION/TAG/INACCESSIBLE is clean

The refactor improves readability and consistency across tests. LGTM.

composition/tests/v1/directives/subscription-filter.test.ts (2)

60-87: Normalization expectations for injected OPENFED types look correct

Switch to normalizeSubgraphSuccess/Failure + OPENFED_* fragments is consistent and clear. LGTM.


456-465: EDG extension scenario

The federated schema expectation for entity extension in EDG matches the intended shape. LGTM.

composition/src/index.ts (1)

29-35: No re-export collisions detected

Verification confirms that composition/src/utils/string-constants.ts (164 exports) and composition/src/v1/constants/strings.ts (9 exports) have zero overlapping identifiers. The two modules export completely distinct symbol names, so no duplicate export errors or ambiguous surfaces will occur.

Likely an incorrect or invalid review comment.

composition/tests/v1/entity-interface.test.ts (2)

31-32: Good move to the new destructured federation result.

The { federatedGraphSchema } shape aligns with the updated API and keeps assertions clear.


88-110: Typed configuration maps look correct.

Using Map<TypeName, ConfigurationData> with explicit Sets/keys matches the new config surface. No issues spotted.

Also applies to: 112-141

composition/src/schema-building/utils.ts (2)

749-751: Nice export for runtime narrowing.

isInputObjectDefinitionData improves type guards downstream; LGTM.


523-540: Broadened parameter type can break callers; add overloads or verify all call sites.

Changing to (MutableDefinitionNode | DefinitionNode)[] means a MutableDefinitionNode[] can no longer be passed safely (the callee pushes a possibly wider element). Either add overloads or confirm all callers are updated to the union.

Optionally add overloads to maintain source compatibility:

-export function addValidPersistedDirectiveDefinitionNodeByData(
-  definitions: (MutableDefinitionNode | DefinitionNode)[],
+export function addValidPersistedDirectiveDefinitionNodeByData(
+  definitions: MutableDefinitionNode[],
+  data: PersistedDirectiveDefinitionData,
+  persistedDirectiveDefinitionByDirectiveName: Map<DirectiveName, DirectiveDefinitionNode>,
+  errors: Error[],
+): void;
+export function addValidPersistedDirectiveDefinitionNodeByData(
+  definitions: (MutableDefinitionNode | DefinitionNode)[],
   data: PersistedDirectiveDefinitionData,
   persistedDirectiveDefinitionByDirectiveName: Map<DirectiveName, DirectiveDefinitionNode>,
   errors: Error[],
-) {
+): void {
   const argumentNodes: MutableInputValueNode[] = [];
   if (!addValidatedArgumentNodes(argumentNodes, data, persistedDirectiveDefinitionByDirectiveName, errors)) {
     return;
   }
   definitions.push({
     arguments: argumentNodes,
     kind: Kind.DIRECTIVE_DEFINITION,
     locations: setToNameNodeArray(data.executableLocations),
     name: stringToNameNode(data.name),
     repeatable: data.repeatable,
     description: data.description,
   });
 }
composition/tests/v1/types/inputs.test.ts (3)

32-33: Helper-based normalization reads cleaner.

normalizeSubgraphSuccess(...).schema makes intent explicit and reduces casting noise.


102-117: Correct directive definition prefixing.

Using TAG_DIRECTIVE in normalization outputs ensures SDL validity without overexposing router fragments.

Also applies to: 126-137, 140-152


268-270: Right place to include SCHEMA_QUERY_DEFINITION.

Federated SDL expectations should be prefixed; this aligns with other suites.

composition/tests/v1/directives/directives.test.ts (3)

14-15: Public test surface trimmed appropriately.

Importing INACCESSIBLE_DIRECTIVE and SCHEMA_QUERY_DEFINITION keeps the suite decoupled from internal constants.


153-155: Correctly include @inaccessible definition in expectations.

Prepending the directive definition avoids false negatives from undefined directives.


350-351: Router schema fragment inclusion is appropriate here.

Federated output should include SCHEMA_QUERY_DEFINITION; assertion matches.

composition/tests/v1/entities.test.ts (1)

51-56: Destructured results + router schema prefix are consistent.

{ federatedGraphSchema } and SCHEMA_QUERY_DEFINITION usage are aligned with the new API.

Also applies to: 55-81

composition/tests/v1/directives/shareable.test.ts (1)

71-86: Nice: no duplicate @Shareable at field level.

Expectation matches the intended behavior precisely.

composition/tests/v1/directives/authorization-directives.test.ts (1)

480-488: The review comment is incorrect. The test code is correct as written.

The test "that merged scopes remove any superfluous scopes #3" properly validates the normalization function:

  • SDL input (line 500): [["a", "b"], ["a"]] — the unmerged source data
  • Data output (line 488): [["a"]] — the expected result after removing superfluous sets

This is the correct test pattern: input with redundant scopes → output with merged/reduced scopes. Changing the SDL to match the expected output would break the merge validation entirely, reducing the test to a trivial pass-through check.

Likely an incorrect or invalid review comment.

composition/tests/v1/directives/override.test.ts (1)

21-31: Test API shifts look correct

Switch to TypeName keys and new { errors }/destructured federation results reads well and matches the new public surface.

Also applies to: 36-43

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

2888-2931: Node 22+ already enforced in engines.node—review concern is mitigated

The code does use isDisjointFrom (a Stage-3 Set method) at lines 2888, 2917, 2949, 2996, 3013, 3046, and 3086. However, your package.json already specifies engines.node: ">=22.11.0", which means the runtime compatibility risk identified in the review is already addressed. No changes are required.

The review comment appears to have been written without checking the existing engine constraint, or before it was added.

composition/src/v1/constants/directive-definitions.ts (1)

226-249: Remove review comment — GraphQL spec allows default values on Non-Null directive arguments

Directive argument definitions may be Non-Null and still provide a default value. If a Non-Null argument definition has a defaultValue, it is treated as optional (the default is used when the argument is omitted). The current code defining providerId: String! = "default" across all EDFS directives is valid per the GraphQL specification and requires no changes.

Likely an incorrect or invalid review comment.

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

1401-1451: Return-type change for upsertInputObjectByNode is clean and used correctly

The UpsertInputObjectResult with success/data simplifies callers and is handled properly in EDGS injection. LGTM.


747-791: Switch to directiveDefinitionDataByName in validation looks correct

Validation now consults the ByName map; consistent with initializeDirectiveDefinitionDatas(). Good change.


2938-3010: Ensure NATS stream config type is emitted via dependencies (skip in main loop)

Confirmed: DEPENDENCIES_BY_DIRECTIVE_NAME includes EDFS_NATS_SUBSCRIBE -> EDFS_NATS_STREAM_CONFIGURATION_DEFINITION (composition/src/v1/constants/strings.ts), and normalization-factory imports/uses that map to add the input type dependency. No change required.

@Aenimus Aenimus merged commit 8e18593 into main Oct 29, 2025
43 of 44 checks passed
@Aenimus Aenimus deleted the david/eng-8418-modify-directive-def-dep-injection branch October 29, 2025 17:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants