Skip to content

Chore: Fork-free code generation and regenerated Components.swift - #441

Closed
Krivoblotsky wants to merge 6 commits into
chore/phase-0-ci-safety-netfrom
chore/fork-free-generation
Closed

Krivoblotsky wants to merge 6 commits into
chore/phase-0-ci-safety-netfrom
chore/fork-free-generation

Conversation

@Krivoblotsky

Copy link
Copy Markdown
Contributor

What

Makes make generate a one-command, fork-free operation and regenerates Components.swift with it.

  • No generator fork. The Makefile clones and builds the stock Swift OpenAPI Generator at a pinned release (1.13.1) under .build/, and installs the one Python dependency (PyYAML) into a virtualenv there. Prerequisites are a Swift toolchain, python3 with venv, and network access on the first run.
  • Two new pipeline steps replace the three patches that lived in the private fork. Scripts/transform_openapi.py collapses OpenAI's anyOf: [X, {type: 'null'}] nullability into optional properties (481 sites in the vendored spec; the stock generator otherwise drops every such property) and records the wire values of all 45 discriminated unions, whose discriminators have no mapping in the spec. Scripts/postprocess_components.py re-wraps the generator's 1.13 multi-file output under the existing header, appends the wire values to each union's decoder, and adds the try-both fallback for message, which names both InputMessage and OutputMessage. It supersedes Scripts/extract_components.py.
  • Scripts/fix_recursive_reference.py handles any number of $recursiveRef occurrences, each pointed at its enclosing component. The live spec now has two (CompoundFilter, BetaCompoundFilter) and the strict one-occurrence version aborts on it.
  • Generation workflow: runs make generate on every PR and fails when the committed Components.swift differs, so the file can never drift from the pipeline again. The built generator is cached per version and Swift toolchain.
  • Regenerated Components.swift from the unchanged vendored spec. Two regression tests cover behaviour the fork got wrong: ItemResource now decodes input messages, and InputItem decodes item_reference by its wire value.
  • CONTRIBUTING.md describes the new workflow; CHANGELOG has the entries.

Why

Regeneration only worked on one machine: it required a sibling checkout of an unpinned, unpublished fork of the generator. Upstream has not shipped the missing behaviour (nullable anyOf has been open since 2024 and the maintainer considers a proper fix a breaking change), and generator 1.13 changed its output layout in a way the old extraction script could not handle. The upstream maintainer's recommended workaround is exactly this: fix the spec before generation instead of patching the generator. Full analysis: the "Generation Without the Fork" audit.

Affected Areas

Generation tooling (Makefile, Scripts/, openapi-generator-config.yaml unchanged), CI (.github/workflows/generation.yml), the generated Components.swift, two tests, docs. No hand-written source changes.

The regenerated schemas differ from the fork's output in 29 API-gate lines, all recorded in .github/api-breakage-allowlist.txt with the changelog entry:

  • 23 nested typealiases that were artifacts of how the fork kept the single-member anyOf alive (for example OutputMessage.MessagePhase, CreateResponse.Value3Payload.IncludeEnum); the top-level types they aliased are unchanged. Keeping the anyOf instead produces 5,000 lines of wrapper structs, so collapsing is the right call.
  • CreateTranscriptionRequest.ChunkingStrategyPayload.body is no longer optional (a request-side generated type the SDK does not use itself), and CreateTranscriptionRequest gained a stream part.

If exact parity is preferred, the post-processor can re-add the 23 typealiases; say so and I will add it before merge.

More Info

🤖 Generated with Claude Code

Krivoblotsky and others added 4 commits September 14, 2026 17:16
make generate now clones and builds the pinned generator release under .build/ and installs PyYAML into a virtualenv there; no sibling checkout or private fork is needed. Two scripts replace the fork's patches: transform_openapi.py collapses OpenAI's anyOf-with-null nullability into optional properties (the stock generator drops those properties) and records the wire values of every discriminated union, whose discriminators have no mapping in the spec; postprocess_components.py re-wraps the 1.13 multi-file output under the existing header, appends the wire values per union and adds the try-both fallback for the message value shared by InputMessage and OutputMessage. It supersedes extract_components.py. fix_recursive_reference.py now handles any number of recursive references, which the live spec requires.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Same vendored spec, stock generator 1.13.1. The 29 generated-type differences against 0.5.1 are recorded in the API allowlist and explained in the changelog: 23 nested typealias artifacts of the previous nullable handling are gone, CreateTranscriptionRequest.ChunkingStrategyPayload.body is no longer optional, and CreateTranscriptionRequest gained a stream part. Two regression tests cover decoding the previous patches got wrong: ItemResource accepts input messages and InputItem decodes item_reference by wire value.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Runs the generation pipeline on every pull request and push to main and fails if the committed file differs, so generated schemas cannot drift from the pipeline. The built generator is cached per version and Swift toolchain.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rmat

The breakage allowlist must contain messages only: with a comment or blank line present the checker matches none of the entries.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Krivoblotsky
Krivoblotsky force-pushed the chore/fork-free-generation branch from 38ca98b to 684760c Compare September 14, 2026 14:16
Krivoblotsky and others added 2 commits September 14, 2026 17:17
Lets a stacked pull request, whose base is not main, get the platform matrix on demand.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Krivoblotsky
Krivoblotsky changed the base branch from chore/phase-0-ci-safety-net to main September 14, 2026 14:18
@Krivoblotsky Krivoblotsky reopened this Sep 14, 2026
@Krivoblotsky
Krivoblotsky changed the base branch from main to chore/phase-0-ci-safety-net September 14, 2026 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants