ID |
|
|---|---|
Status |
Backlog |
Bucket |
feature |
Created |
2026-05-27 |
Updated |
2026-05-27 |
Make pipeline<→runtime SDL parity test pass
FederationBuildSmokeTest.emittedSdlMatchesRuntimeSchema is currently
@Disabled (landed alongside R247). The test asserts, through graphql-java’s
SchemaDiffing, that the on-classpath schema.graphqls emitted by
SchemaSdlEmitter describes the same schema a consumer rebuilding via
Graphitron.buildSchema(…) sees ; the strongest invariant the spec for
R247 carried for the artefact, and the one that catches both wrong-printer
dispatch and runtime/codegen drift in a single assertion.
R247 closed the federation-runtime-type half of the gap by running
Federation.transform(assembled).setFederation2(true)…build() inside
SchemaSdlEmitter.printFederationServiceSdl so _Service, _entities,
and _Entity line up on both sides. The remaining structural diff
(verified against the sakila federated fixture) is the non-survivor
directive definitions and applications ; @asConnection, @table,
@node, @reference, @service, @condition, @defaultOrder, etc.
The runtime build strips them through
GraphitronSchemaClassGenerator’s `additionalDirective(survivors(assembled))
loop and the per-type applicationsFor survivor filter on
AppliedDirectiveEmitter; the emitter still prints from assembled,
which carries every consumer-authored directive declaration and
application.
Implementation routes
Both routes stay within graphitron’s existing seams; pick one before moving to Ready.
Route 1 — filter at the print seam
Replace
ServiceSDLPrinter.generateServiceSDLV2(federated) in
SchemaSdlEmitter.printFederationServiceSdl with a direct
SchemaPrinter call whose options mirror `generateServiceSDLV2’s shape
plus the survivor predicate:
var options = SchemaPrinter.Options.defaultOptions()
.includeSchemaDefinition(true)
.includeScalarTypes(true)
.includeDirectiveDefinition(SchemaDirectiveRegistry::isSurvivor)
.includeDirectives(SchemaDirectiveRegistry::isSurvivor)
.includeSchemaElement(elt -> elt instanceof GraphQLDirective d
? !DirectiveInfo.isGraphqlSpecifiedDirective(d)
: true);
return new SchemaPrinter(options).print(federated).trim();
The includeSchemaElement predicate replicates
ServiceSDLPrinter.generateServiceSDLV2’s spec-built-in filter (verified
via the JVM-bytecode disassembly of `lambda$generateServiceSDLV2$3). The
non-federation arm needs the same includeDirectiveDefinition /
includeDirectives survivor filter for symmetry.
-
Pro: entirely at the print seam, no new schema materialisation, no cross-module coupling.
-
Con: the "what’s a survivor" semantics live in two sites ; the runtime build (
additionalDirective(survivors)) and the printer predicate. A future divergence (e.g. a directive that’s a survivor at runtime but the printer predicate doesn’t agree) reopens the gap. The unit-tierSchemaSdlEmitterTest.federationArmRoutesThroughServiceSdlPrintermust switch from asserting againstServiceSDLPrinter.generateServiceSDLV2(…)to the new printer call.
Route 2 — render from a runtime-equivalent schema
Reconstruct the runtime schema in-process at codegen, mirroring what
GraphitronSchema.build() does (clearDirectives(),
additionalDirective(survivors), applied-directive filtering via
AppliedDirectiveEmitter.applicationsFor on every container,
Federation.transform), then print that single schema through
ServiceSDLPrinter.generateServiceSDLV2.
-
Pro: one source of truth for the survivor semantics; the emitter prints exactly what the runtime would publish.
-
Con: either evaluates just-generated Java in-process (heavy, and re-introduces the codegen ↔ runtime coupling we deliberately separated) or duplicates the runtime build logic at codegen (two implementations of the same survivor semantics). Both add surface area in a part of the codebase that’s intentionally narrow.
Route 1 is the more contained change and is the recommended starting point unless Spec discussion surfaces a directive case the printer-level filter cannot represent.
Route 3 — Route 1 with the survivor decision made explicit at one site
Independent-review remark surfaced during R247 self-review: Route 1’s con
("splits survivor semantics across two sites") collapses if the print
predicate consumes the same
SchemaDirectiveRegistry.isSurvivor(String) method the codegen
additionalDirective(survivors) loop and per-type
AppliedDirectiveEmitter.applicationsFor filter already consume. Both
sides then route through one survivor decision, with the printer-level
filter as a thin lookup. The con only resurfaces if a future runtime
filter diverges from isSurvivor (e.g. a runtime-only override).
In practice this is what Route 1’s code sketch above already does. Pull this out as the explicit Spec framing so the Spec → Ready reviewer doesn’t re-discover it: "one survivor predicate, two consumers" is the shape, not "two predicates that happen to agree today".
Re-enabling the test
Either route lets the test go green by removing the @Disabled
annotation and its accompanying explanatory comment on
FederationBuildSmokeTest.emittedSdlMatchesRuntimeSchema. The test body
itself (parse both sides through
UnExecutableSchemaGenerator.makeUnExecutableSchema, diff via
SchemaDiffing) is already correct; only the input to the file side
needs to match.
Files touched at minimum
-
graphitron-rewrite/graphitron/src/main/java/no/sikt/graphitron/rewrite/generators/schema/SchemaSdlEmitter.java; the printer call. -
graphitron-rewrite/graphitron/src/test/java/no/sikt/graphitron/rewrite/generators/schema/SchemaSdlEmitterTest.java; unit-tier assertion follows the new printer call. -
graphitron-rewrite/graphitron-sakila-example/src/test/java/no/sikt/graphitron/rewrite/test/querydb/FederationBuildSmokeTest.java; drop@DisabledfromemittedSdlMatchesRuntimeSchema.
Out of scope
-
Reopening the byte-equality framing of the parity assertion. The current
SchemaDiffingcomparison is the right shape: it catches structural drift while ignoring incidental printer whitespace / sort order that graphql-java point releases drift on. -
Federation runtime types (
_Service,_entities,_Entity). Already aligned by R247’sFederation.transformstep inSchemaSdlEmitter.