Decision record
AD-0016 Generated code exempt from the empty-interface rule
Status: accepted. Date: 2026-08-27.
Context
The coding rules forbid the empty interface in any value position: not
interface{} and not any, in parameters, results, struct fields, variables,
map, slice, array, channel and pointer element types, type arguments, named
types, aliases or constraint type sets, with any permitted only as a
type-parameter constraint. The rule governs what this code
declares and not what a dependency accepts, which is why go-cmp is allowed
despite its own signatures.
The three subgraphs are federated GraphQL services, two of them with
subscriptions (AD-0001, AD-0014). gqlgen is the only credible Go library for
that combination, and its generated code is full of interface{}. Left as it
stands, the rule would flag every generated file.
Generated files carry a header comment that starts // Code generated and
ends ` DO NOT EDIT., which is the marker gqlgen writes. One hand-written
exception is foreseeable: gqlgen's explicit_requires populate function,
whose signature carries an empty-interface map and which the capacity
service needs for @requires` over nested fields.
What the coding rules left open was whether generated files fall under the rule at all.
Decision
We will exempt generated files from the empty-interface rule and keep every
hand-written file under it. A file carrying the
// Code generated ... DO NOT EDIT. header is not checked, and a forced
empty interface in a hand-written signature carries an explicit allowance on
the line with a justification in the pull request. SC-02 states the rule
in that form.
Alternatives considered
No code generation at all. Without gqlgen the subgraphs would take the gRPC or extension-module route, and neither supports subscriptions, so live push would be lost.
Per-line allowances inside generated files. An allowance written into a file
that go generate rewrites does not survive the next regeneration.
Consequences
The rule keeps its force where it was meant to apply. Every hand-written file
under adapter/, examples/ and cmd/ is checked as before, and the one
foreseeable exception is named in advance, so its
appearance in a pull request is expected rather than negotiated. gqlgen’s
output carries the standard header, so no file has to be listed by name and
regeneration does not disturb the configuration.
The exemption rests on a one-line header, which proves nothing on its own. A hand-written file that copied it would escape the rule, and only review would notice. That is a weaker guarantee than the rule has anywhere else.
A second cost is the shape of gqlgen’s federation output. With
explicit_requires the populate function’s empty-interface map lands in
hand-written code, and the nested-list @requires that forces it is the first
spike of the implementation phase. If that spike fails and the flat
Part.wiring: String fallback is taken, the exception may not be needed at
all.
Requirements affected
SC-02
Sources
gqlgen’s generated output, its // Code generated ... DO NOT EDIT. header and its explicit_requires populate function. Go’s own convention for the generated-code header. Five spikes before the first line for the one generated file that does not carry the header, and How the design was run for the rule the exemption sits inside.