revert: nested BaseModel coercion (#295) - #375
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e8650e140
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Automated review identified six pre-#295 converter behaviors that this literal rollback intentionally restores. They are now tracked together in #376 with explicit regression-coverage requirements: union error isolation, nullable fields, strictness preservation, existing-model identity, collection error retention, and nullable collection matchers. I replied to and resolved each inline thread as separately tracked follow-up work. No code was added to this PR because doing so would make #375 a partial model-conversion redesign rather than the standalone rollback requested here. |
Automated Release PR --- ## [0.79.0](openai/openai-ruby@v0.78.0...v0.79.0) (2026-08-14) ### Features * add HTTP response observability ([openai#365](openai#365)) ([48d36b7](openai@48d36b7)) * add Tapioca typing for structured outputs ([openai#364](openai#364)) ([738e2b4](openai@738e2b4)) * **api:** Add new model identifiers and remove audit log source ([e0a4bc5](openai@e0a4bc5)) * **api:** add WebSocket stream IDs ([openai#387](openai#387)) ([5880287](openai@5880287)) * **api:** add workload identity access token issued event ([openai#372](openai#372)) ([9199779](openai@9199779)) * **api:** deprecate Sora video APIs ([openai#386](openai#386)) ([0664456](openai@0664456)) * **client:** add default headers ([openai#369](openai#369)) ([d516874](openai@d516874)) * expose request IDs ([openai#352](openai#352)) ([c15fb7b](openai@c15fb7b)) * support Azure OpenAI v1 ([openai#355](openai#355)) ([c1d223e](openai@c1d223e)) ### Bug Fixes * **api:** Add new model identifiers and remove audit log source ([openai#360](openai#360)) ([e0a4bc5](openai@e0a4bc5)) * **api:** allow nil timeout in client signatures ([openai#363](openai#363)) ([e52ca61](openai@e52ca61)) * **api:** document file upload metadata defaults ([openai#361](openai#361)) ([b4bc1ea](openai@b4bc1ea)) * coerce nested BaseModel fields ([openai#295](openai#295)) ([e5152a9](openai@e5152a9)) * enable streaming when retrieving responses ([openai#413](openai#413)) ([fd85182](openai@fd85182)) * encode multipart array and nested fields ([openai#348](openai#348)) ([1c71a1e](openai@1c71a1e)) * honor workload identity environment defaults ([openai#398](openai#398)) ([f4afea1](openai@f4afea1)) * keep required path parameters out of resource query strings ([openai#402](openai#402)) ([6768a7c](openai@6768a7c)) * loading after ActiveSupport 6 subclass extensions ([openai#346](openai#346)) ([20fbb09](openai@20fbb09)) * make SDK debug body logging fail closed ([openai#411](openai#411)) ([c4f7284](openai@c4f7284)) * package every README-linked guide and example ([openai#382](openai#382)) ([ddecd0f](openai@ddecd0f)) * preserve binary multipart stream reads ([openai#354](openai#354)) ([b3a1ba7](openai@b3a1ba7)) * preserve existing BaseModel instances during coercion ([openai#400](openai#400)) ([fbd8560](openai@fbd8560)) * preserve prefixed idempotency headers on redirects ([openai#404](openai#404)) ([c380e13](openai@c380e13)) * preserve stream identity with HTTP logging ([openai#384](openai#384)) ([640a1fe](openai@640a1fe)) * prevent symbol-keyed headers from bypassing security filters ([openai#383](openai#383)) ([b8165af](openai@b8165af)) * redact sensitive query and form logging ([openai#389](openai#389)) ([7aa54e4](openai@7aa54e4)) * reject invalid webhook signing secrets ([openai#403](openai#403)) ([ad12458](openai@ad12458)) * remove unsound structured-output Tapioca compiler ([openai#405](openai#405)) ([826769a](openai@826769a)) * restore RuboCop coverage for RBI files ([openai#388](openai#388)) ([d2d4b5d](openai@d2d4b5d)) * return values from interruptible enumerator ([openai#350](openai#350)) ([327dad7](openai@327dad7)) * strip credential headers on cross-origin redirects ([openai#391](openai#391)) ([f50f08c](openai@f50f08c)) * tighten JSON, JSONL, and SSE content type matching ([openai#277](openai#277)) ([66359a0](openai@66359a0)) * use API field names in structured output schemas ([openai#390](openai#390)) ([d1e3cf3](openai@d1e3cf3)) * validate and bound retry delays ([openai#392](openai#392)) ([fff94e7](openai@fff94e7)) * **webhooks:** support Rack and case-insensitive HTTP headers ([openai#401](openai#401)) ([37de980](openai@37de980)) ### Reverts * nested BaseModel coercion ([openai#295](openai#295)) ([openai#375](openai#375)) ([65fa76e](openai@65fa76e)) ### Chores * Cover Ruby files at the SDK root ([openai#362](openai#362)) ([d11f25b](openai@d11f25b)) * enforce boolean symbol lint ([openai#395](openai#395)) ([fafdf2e](openai@fafdf2e)) * enforce deprecated constant lint ([openai#379](openai#379)) ([0def912](openai@0def912)) * enforce duplicate match pattern lint ([openai#380](openai#380)) ([7a8f2fb](openai@7a8f2fb)) * enforce empty else lint ([openai#396](openai#396)) ([1e073c1](openai@1e073c1)) * enforce line length lint ([openai#406](openai#406)) ([4592061](openai@4592061)) * enforce line length on base models ([openai#416](openai#416)) ([aef1e33](openai@aef1e33)) * enforce line length on requires ([openai#415](openai#415)) ([c24e045](openai@c24e045)) * enforce missing RuboCop enable directives ([openai#368](openai#368)) ([50046bf](openai@50046bf)) * enforce missing super lint ([openai#393](openai#393)) ([2a42bd0](openai@2a42bd0)) * enforce nonempty pattern branches ([openai#409](openai#409)) ([9d22d5c](openai@9d22d5c)) * enforce redundant directive lint ([openai#366](openai#366)) ([8448a4c](openai@8448a4c)) * enforce redundant exception lint ([openai#397](openai#397)) ([cbda8bc](openai@cbda8bc)) * enforce symbol conversion lint ([openai#381](openai#381)) ([0531498](openai@0531498)) * enforce useless assignment lint ([openai#394](openai#394)) ([9688836](openai@9688836)) * guard RuboCop suppression directives ([openai#408](openai#408)) ([5b6e0dc](openai@5b6e0dc)) * lint Ruby files repository-wide ([openai#377](openai#377)) ([8ca8426](openai@8ca8426)) * remove Stainless attribution and infrastructure ([openai#371](openai#371)) ([33d2c86](openai@33d2c86)) * require MFA for gem releases ([openai#378](openai#378)) ([71798ec](openai@71798ec)) ### Documentation * **api:** describe response stream event unions ([openai#412](openai#412)) ([87d18ef](openai@87d18ef)) * clarify file upload metadata ([openai#358](openai#358)) ([698ac65](openai@698ac65)), closes [openai#243](openai#243) * document fiber scheduler concurrency ([openai#357](openai#357)) ([25a7bbc](openai@25a7bbc)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: openai-sdks[bot] <284451331+openai-sdks[bot]@users.noreply.github.com>
Summary
BaseModelcontract.Commit structure
b269a43eis the literal Git revert of merge commite5152a92962251ce76ceb3d89ec0b6b37fa4efdb.6e8650e1adds only the compatibility test suite.Keeping those changes separate makes the rollback itself directly auditable and the additional contract coverage independently reviewable.
Why
#295 globally coerced nested request-model values, changing the documented contract that
BaseModel#[]and#to_hexpose the raw values callers supplied. The broader conversion changes also interact unsafely with optional discriminators and schemas where multiple variants share the same discriminator.The previous forward-fix PR #373 was closed rather than repurposed. Draft #370 was also closed; issue #287 remains open for a narrower streaming-scoped solution after the model system is redesigned from first principles.
Compatibility coverage
#[],#to_h, and#deep_to_hparams.to_h.fetch(:input).fetch(0).fetch(:type)Generator scope
No Castiron change is required. Castiron intentionally excludes the SDK-owned
lib/openai/internal/runtime, its signatures, and the handwritten test tree, so generated output is unchanged.Validation
scripts/testentry point on Ruby 3.3.12, 3.4.10, and 4.0.6: 613 runs, 2,256 assertions on eachbundle exec rake lint: RuboCop, Sorbet, and 1,212 RBS files greenbundle exec rake build:gem