fix: use API field names in structured output schemas - #390
Conversation
There was a problem hiding this comment.
💡 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".
HAYDEN-OAI
left a comment
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
💡 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".
HAYDEN-OAI
left a comment
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this comment.
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.
Summary
api_name.$defsnames as RFC 6901 JSON Pointer tokens, and percent-encode URI fragments correctly./,~,#, spaces,%, reserved URI characters, and Unicode while preserving valid$defsreferences.api_namemetadata out of emitted schemas while preserving descriptions, nullable fields, Ruby readers, API parsing, and request serialization.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:
docs/stainless-sdk-json-fixtures/release-primary/generated-file-excludes.yamlexplicitly excludes Rubylib/openai/helpers/and broadtest/, while explicitly re-including only generated resource tests and namespace scaffolding.crates/castiron-verify/src/generated_files.rsimplements the exact prefix/include-prefix precedence used by generated-tree verification.crates/castiron-render-ruby/src/output.rsandsrc/lib/render_views.rs) emits package/client/model/resource/signature files and resource tests, not structured-output helper code or handwritten helper tests.CONTRIBUTING.mdindependently states that the generator never modifieslib/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/mainwith 5 failures in 6 tests: invalid property names, leakedapi_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/test— 637 runs, 2,577 assertions, 0 failures.mise exec ruby@4.0.6 -- bundle exec rake lint— 1,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.