Skip to content

fix: use API field names in structured output schemas - #390

Merged
jbeckwith-oai merged 3 commits into
mainfrom
codex/structured-output-api-property-names-20260813
Aug 13, 2026
Merged

fix: use API field names in structured output schemas#390
jbeckwith-oai merged 3 commits into
mainfrom
codex/structured-output-api-property-names-20260813

Conversation

@jbeckwith-oai

@jbeckwith-oai jbeckwith-oai commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Generate structured-output JSON Schema properties, required names, and reused-definition paths from each field's canonical api_name.
  • Reject duplicate API aliases explicitly instead of silently collapsing schema properties.
  • Encode each definition path segment separately to prevent direct-alias/nested-path collisions, escape complete $defs names as RFC 6901 JSON Pointer tokens, and percent-encode URI fragments correctly.
  • Support aliases containing /, ~, #, spaces, %, reserved URI characters, and Unicode while preserving valid $defs references.
  • Keep internal api_name metadata out of emitted schemas while preserving descriptions, nullable fields, Ruby readers, API parsing, and request serialization.
  • Remove the redundant converter dispatch branch and reuse the existing canonical JSON Schema converter.
  • Add isolated regression coverage for aliases, duplicate aliases, pointer/URI escaping, deep nested/reused definitions, colliding direct/nested paths, Ruby/API-name collisions, converter round trips, and real WebMock-backed Chat Completions and Responses request/response round trips.

Castiron / generation ownership

No upstream Castiron generator, compiler, renderer, template, OpenAPI schema, or companion regeneration change is required.

Verified against the actual Castiron generation workflow, not just file appearance:

  1. docs/stainless-sdk-json-fixtures/release-primary/generated-file-excludes.yaml explicitly excludes Ruby lib/openai/helpers/ and broad test/, while explicitly re-including only generated resource tests and namespace scaffolding.
  2. Castiron's crates/castiron-verify/src/generated_files.rs implements the exact prefix/include-prefix precedence used by generated-tree verification.
  3. Evaluating that real policy against every changed path and a generated control path gives:
EXCLUDED lib/openai/helpers/structured_output/base_model.rb
EXCLUDED lib/openai/helpers/structured_output/json_schema_converter.rb
EXCLUDED test/openai/helpers/structured_output_api_names_test.rb
GENERATED test/openai/resources/chat/completions_test.rb
  1. Castiron's Ruby renderer (crates/castiron-render-ruby/src/output.rs and src/lib/render_views.rs) emits package/client/model/resource/signature files and resource tests, not structured-output helper code or handwritten helper tests.
  2. The SDK's CONTRIBUTING.md independently states that the generator never modifies lib/openai/helpers/.

The overlapping #385 changes unrelated Tapioca/reader behavior; this PR does not incorporate or modify any of that work.

Regression evidence

The initial suite failed against unmodified origin/main with 5 failures in 6 tests: invalid property names, leaked api_name, lost nested $defs, and incorrect Chat Completions/Responses request schemas. Subsequent reviewer regressions independently failed before their fixes for duplicate aliases, JSON Pointer escaping, URI-fragment escaping, deeply nested definitions, and direct-alias/nested-path collisions.

Verification

  • mise exec ruby@4.0.6 -- env TEST_API_BASE_URL=http://127.0.0.1:4510 ./scripts/test637 runs, 2,577 assertions, 0 failures.
  • mise exec ruby@4.0.6 -- bundle exec rake lint1,390 RuboCop files clean, Sorbet clean, and 1,212 RBS files valid.
  • mise exec ruby@4.0.6 -- bundle exec rake build:gem — gem builds successfully.
  • New alias/pointer/URI/collision regressions pass on Ruby 3.3.12, 3.4.10, and 4.0.6.
  • Existing structured-output suite remains green, with no new Ruby 4 URI deprecation warnings.
  • Explicit thermo-nuclear code-quality review completed before every push; schema dispatch and complete reference encoding stay in their canonical owning layers.

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner August 13, 2026 19:26
@openai-sdks

openai-sdks Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 11.913s for Ruby SDK PR #390.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 286ms
tests/chat-completions-create.test.ts ✅ Passed 327ms
tests/chat-completions-stream.test.ts ✅ Passed 137ms
tests/files-content-binary.test.ts ✅ Passed 408ms
tests/files-create-multipart.test.ts ✅ Passed 266ms
tests/files-list-pagination.test.ts ✅ Passed 181ms
tests/initialize-config.test.ts ✅ Passed 264ms
tests/instance-isolation.test.ts ✅ Passed 315ms
tests/models-list.test.ts ✅ Passed 242ms
tests/responses-background-lifecycle.test.ts ✅ Passed 317ms
tests/responses-body-method-errors.test.ts ✅ Passed 594ms
tests/responses-cancel-timeout.test.ts ✅ Passed 344ms
tests/responses-cancel.test.ts ✅ Passed 323ms
tests/responses-compact-retries.test.ts ✅ Passed 366ms
tests/responses-compact.test.ts ✅ Passed 412ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 196ms
tests/responses-create-advanced.test.ts ✅ Passed 278ms
tests/responses-create-disconnect.test.ts ✅ Passed 1.021s
tests/responses-create-errors.test.ts ✅ Passed 355ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 204ms
tests/responses-create-retries.test.ts ✅ Passed 457ms
tests/responses-create-stream-failures.test.ts ✅ Passed 190ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 222ms
tests/responses-create-stream-wire.test.ts ✅ Passed 2.55s
tests/responses-create-stream.test.ts ✅ Passed 194ms
tests/responses-create-terminal-states.test.ts ✅ Passed 389ms
tests/responses-create-timeout.test.ts ✅ Passed 293ms
tests/responses-create.test.ts ✅ Passed 349ms
tests/responses-delete.test.ts ✅ Passed 425ms
tests/responses-input-items-errors.test.ts ✅ Passed 212ms
tests/responses-input-items-list.test.ts ✅ Passed 195ms
tests/responses-input-items-options.test.ts ✅ Passed 366ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 404ms
tests/responses-input-tokens-count.test.ts ✅ Passed 335ms
tests/responses-malformed-inputs.test.ts ✅ Passed 2.179s
tests/responses-not-found-errors.test.ts ✅ Passed 419ms
tests/responses-parse.test.ts ✅ Passed 227ms
tests/responses-retrieve-retries.test.ts ✅ Passed 477ms
tests/responses-retrieve.test.ts ✅ Passed 317ms
tests/responses-stored-method-errors.test.ts ✅ Passed 833ms
tests/retry-behavior.test.ts ✅ Passed 3.192s
tests/sdk-error-shape.test.ts ✅ Passed 454ms

View OkTest run #31737464433

SDK merge (50baed1ec054) · head (5657031baa80) · base (0531498c5498) · OkTest (a845fa206fa4)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 776ec111f5

ℹ️ 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".

Comment thread lib/openai/helpers/structured_output/base_model.rb

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found one additional alias-collision edge case below. The existing unresolved JSON Pointer escaping thread is also substantive: API aliases containing / or ~ can currently produce broken $refs. I did not duplicate that inline comment.

Comment thread lib/openai/helpers/structured_output/base_model.rb

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc4fce0225

ℹ️ 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".

Comment thread lib/openai/helpers/structured_output/json_schema_converter.rb Outdated
Comment thread lib/openai/helpers/structured_output/json_schema_converter.rb Outdated

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requested duplicate-alias rejection and //~ JSON Pointer behavior are addressed, but this head still has two substantive $ref correctness issues already captured in the current inline threads: URI-fragment reserved characters such as # are not percent-encoded, and escaping only after joining path segments allows direct aliases to collide with structurally nested definition names. I did not duplicate those inline comments.

@HAYDEN-OAI HAYDEN-OAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The follow-up fixes address the remaining $ref correctness issues. Per-segment RFC 6901 escaping now preserves structural path boundaries before the complete $defs key is escaped as a single pointer token, and URI-fragment encoding safely handles reserved, percent, whitespace, and non-ASCII characters while materializing the intended readable definition key. Together with the duplicate-alias validation and Chat/Responses coverage, this looks good.

@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Aug 13, 2026
Merged via the queue into main with commit d1e3cf3 Aug 13, 2026
13 checks passed
@jbeckwith-oai
jbeckwith-oai deleted the codex/structured-output-api-property-names-20260813 branch August 13, 2026 19:49
@openai-sdks openai-sdks Bot mentioned this pull request Aug 13, 2026
@jbeckwith-oai jbeckwith-oai added the generator Touches generated SDK files label Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

generator Touches generated SDK files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants