The gap
ir.Enum carries exactly the field this extension is the OpenAPI spelling of:
// ir/types.go:284-286
Closed bool
But the OpenAPI compiler hardcodes Closed: true (compose.go:1182, :1221), and the extension-promotion vocabulary is a closed set of three deprecation targets (promotion.go:36-43) with no enum-openness target. So x-extensible-enum survives only as a generic vendor_extension entry and the field it maps onto stays true.
Why it matters
Open versus closed is a real semantic difference and the IR already models it — this is a wiring gap, not a modelling one. For a generator it decides whether to emit a fallback member; for a diff consumer it decides whether adding an enum value is a breaking change at all.
Suggested fix
Add an enum-openness promotion target and map x-extensible-enum onto Enum.Closed = false. Under the existing promotion mechanism this looks like a small, well-precedented change.
Found by a study of dexpace/spaceapi adopting morphic IR as its input format (spaceapi#56), 2026-09-05. Related: #418 (non-emitter consumer), #419 (cross-revision identity).
The gap
ir.Enumcarries exactly the field this extension is the OpenAPI spelling of:But the OpenAPI compiler hardcodes
Closed: true(compose.go:1182,:1221), and the extension-promotion vocabulary is a closed set of three deprecation targets (promotion.go:36-43) with no enum-openness target. Sox-extensible-enumsurvives only as a genericvendor_extensionentry and the field it maps onto stays true.Why it matters
Open versus closed is a real semantic difference and the IR already models it — this is a wiring gap, not a modelling one. For a generator it decides whether to emit a fallback member; for a diff consumer it decides whether adding an enum value is a breaking change at all.
Suggested fix
Add an enum-openness promotion target and map
x-extensible-enumontoEnum.Closed = false. Under the existing promotion mechanism this looks like a small, well-precedented change.Found by a study of
dexpace/spaceapiadopting morphic IR as its input format (spaceapi#56), 2026-09-05. Related: #418 (non-emitter consumer), #419 (cross-revision identity).