An inline oneOf/anyOf branch whose pointer an outside $ref also names takes its
Naming.Hint from whichever lowering interns the node first. The union lowering derives
variant_<index>; hoistSubSchema, reached through the outside $ref, derives the pointer's
last segment. Both are valid hints and nothing compares them, so the same components compiled in
two declaration orders produce two different documents — silently.
openapi: 3.1.0
info: {title: t, version: "1"}
paths: {}
components:
schemas:
Host:
oneOf:
- {type: integer, description: d}
- type: string
Outside: {$ref: '#/components/schemas/Host/oneOf/0'}
Compiled with Host declared first, t/anon/components/schemas/Host/oneOf/0 is hinted
variant_0; with Outside first, 0. cmp.Diff over the two registries shows only that field.
Why this is filed on its own
The $ref-branch half of the same mechanism is closed: a branch that is a $ref carrying
siblings now derives its hint from the $ref target on both paths, so both agree whichever
arrives first, and TestComposition_BranchAliasIsOrderIndependent pins it for allOf, oneOf
and anyOf.
An inline branch has no target to name, so the two lowerings genuinely hold different
information: the union knows the branch's ordinal within the union, and hoistSubSchema knows
only the pointer it was handed. Closing this means deciding which spelling names the node and
teaching the other path to produce it — a naming decision, not an agreement fix.
Method
Compiled both orders through openapi.New().Compile(...) and diffed Document.Types.
An inline
oneOf/anyOfbranch whose pointer an outside$refalso names takes itsNaming.Hintfrom whichever lowering interns the node first. The union lowering derivesvariant_<index>;hoistSubSchema, reached through the outside$ref, derives the pointer'slast segment. Both are valid hints and nothing compares them, so the same components compiled in
two declaration orders produce two different documents — silently.
Compiled with
Hostdeclared first,t/anon/components/schemas/Host/oneOf/0is hintedvariant_0; withOutsidefirst,0.cmp.Diffover the two registries shows only that field.Why this is filed on its own
The
$ref-branch half of the same mechanism is closed: a branch that is a$refcarryingsiblings now derives its hint from the
$reftarget on both paths, so both agree whicheverarrives first, and
TestComposition_BranchAliasIsOrderIndependentpins it forallOf,oneOfand
anyOf.An inline branch has no target to name, so the two lowerings genuinely hold different
information: the union knows the branch's ordinal within the union, and
hoistSubSchemaknowsonly the pointer it was handed. Closing this means deciding which spelling names the node and
teaching the other path to produce it — a naming decision, not an agreement fix.
Method
Compiled both orders through
openapi.New().Compile(...)and diffedDocument.Types.