Repository navigation
Description
The goal and context come first, then the ordered plan. Each step is a sub-issue, and the blocked-by relations are set on the issues themselves.
End goal
The first milestone's emitters (Go, Kotlin/JVM and Kotlin KMP, #901) can be built on the golden spec, the Cloudflare API schema (cloudflare/api-schemas openapi.json), without guessing. Done means all of the following:
- every fact the plan layer and the refiners read is either carried by the IR or derived by one stated rule;
- every value they read has a rule in
docs/emitters/for each case the golden spec contains; - the engine owns what the design gives it: fatality, rendering and writing.
Context
The measurements in #919 walked every compiled document of the golden spec and a corpus of 1,838 OpenAPI specs the way milestones M3a to M3c would, at c387e25c. They counted where a consumer has to guess.
- Design gaps. The design gives no rule for return shapes beyond models and lists, base URLs, nameless enum members, discriminated unions as the compiler emits them,
anyOf, streams, non-model error bodies, or mostUnmodeledentries. - Facts the IR doesn't carry. Usage, which the design reads for every type, is never computed.
- What the IR does carry. A reflection walk found 46% of its declared fields never set by any compiler, which bounds what M3 should implement.
#919's report carries the evidence and the commands behind every number.
Plan
1. Settle the contract before plan code is written
- docs/emitter-design: the first targets are Go, Kotlin/JVM and Kotlin KMP #901: the targets, and the plan-versus-refine procedure of
docs/emitters/plan/plan-or-refine.md - engine: decide whether emitters run on a document with error diagnostics, and give the engine the fatality rule #957: whether emitters run on a document with error diagnostics
- ir: decide whether derived facts (usage, subtypes, flattened properties) live in one per-document index #950: one per-document index for derived facts (usage, subtypes, flattened properties)
- docs/emitter-design: scope the first emitter to the IR a compiler produces, and degrade the rest with a diagnostic #961: scope M3 to the IR a compiler produces
- docs/emitter-design: say what an SDK emitter does with each kind of Unmodeled entry #951: what an SDK emitter does with each kind of
Unmodeledentry - ir: discriminated unions lower with WireTagged=false, a combination the normative tag modes don't define #954: discriminated unions' tag mode
- docs/emitter-design: ParamShape varies by target, which §2.2 rules out of the plan #698, docs/emitter-design: target options are free-form, with no validation, versioning or lifecycle #706, docs/emitter-design: naming policy should be allowed to consult the source spelling for acronyms #717: decisions shared by three targets
- engine: move diagnostic rendering and artifact writing out of the CLI, where emitter-design §2.1 puts them in the engine #958: rendering and writing move from the CLI to the engine
2. First models, enums and one client (M3a)
- docs/emitter-design: four gaps the first target will hit #255: four gaps the first target hits
- docs/emitter-design: give ReturnShape a value for scalar, binary, union and map responses #952: return shapes
- docs/emitter-design: say where a generated client's base URL comes from #953: base URL
- docs/emitter-design: give an enum member whose value has no letters or digits a naming rule #956: nameless enum members
- docs/emitter-design: positional path parameters need URL order, and patch shapes must not carry defaults #697, docs/emitter-design: reserved words cover keywords, not the identifiers generated code binds #701, docs/emitter-design: rules the emit layer must hold to #709, docs/emitter-design: recursive types and very large model sets need plan-level facts #718: path-parameter order, reserved identifiers, emit-layer rules, recursive types
- ir: provide FlattenedProperties with defined order and override rules #812, ir: an inherited property that a composing schema makes required has no home #663: flattened properties and inherited requiredness
- openapi: an operation whose only response is
defaulthas no success response #608, ir: decide whether four no_ir_home operation constructs get real fields #285:default-only responses, operation-level constructs - docs/emitters: a verify stage that compiles and lints generated output #704: a verify stage, three toolchains
- pass: pin Validate's diagnostic order wherever it ranges a map #821: pin
Validate's diagnostic order at its four unpinned sites before emitter goldens record it - ir: a non-streaming operation lowers with an empty Streaming value, though the IR declares "none" for it #978: a non-streaming operation's
Streamingvalue outside the declared set - test: add conformance cases for common formats, client streaming and null values #1017: conformance cases for the common formats, client streams and
nullvalues the golden spec sets, which the first emitters lower only once a case witnesses them (blocked by docs/emitter-design: scope the first emitter to the IR a compiler produces, and degrade the rest with a diagnostic #961)
3. The hard axes and operations (M3b, M3c)
- docs/emitters: give a union that admits more than one variant (anyOf) a lowering of its own #959:
anyOf - docs/emitter-design: an unknown union variant is always a decode error #700: unknown variants
- docs/emitter-design: lower error payloads that are not error-flagged models #960: error payloads (blocked by ir: decide whether derived facts (usage, subtypes, flattened properties) live in one per-document index #950)
- PlannedError has no Headers and no media-type election now that ErrorCase is a response #447: error headers and media types
- docs/emitters: EnvelopePolicy is named but never defined #695: response envelopes
- docs/emitters: derive safety and idempotency from the HTTP method in the plan #696: idempotency
- docs/emitter-design: describe streams the way the IR carries them, not as an event union with framing on the binding #955: streams
- ir: pagination can't address a request-body input, a page count, or a stop condition #665: pagination
- docs/emitters: detect client-level parameters by structure #719: client-level parameters
- docs/emitters: no refine step reads TypeCommon.Sensitive #895: redaction
- docs/emitters: runtime policy has no per-operation override #710, docs/emitters: runtime policy lacks several behaviors every SDK has to choose #711, docs/emitters: read runtime policy and SDK hints that documents embed as vendor extensions #712: runtime policy, including policy a document embeds as extensions
- pass: report names that collide once canonicalized #647: canonical-name collisions
Out of scope: the OpenAPI front end's own plan (#920), and the architecture and contributor-path work (#976).
Priority: P0, the tier of its highest open step (#255).
Activity
13 remaining items
OmarAlJarrah commentedon Nov 2, 2026
The emitter-design steps of this plan now each have a PR. The design docs work goes in eight stacked PRs, which merge in order, plus one on #1229:
anyOf), the plan proving which unions are disjointdst), and docs: several design documents say IDs survive renames, which pointer-derived IDs don't #677Still open among this tracker's steps once those land, none of them design work: #821 (
Validate's diagnostic order), #665 (pagination's IR gaps) and #647 (canonical-name collisions), which belong to the IR and passes. The tracker stays open for them.