fix(translate): satisfy OpenAI strict-mode object/array requirements on makeNullable's typeless-branch fallback - #832
Conversation
…on the makeNullable typeless-branch fallback #829 fixed makeNullable's fallback for a typeless optional property (no "type"/"anyOf"/"enum") by stamping an explicit value-type union (["string","number","boolean","object","array","null"]) on the synthetic anyOf branch so OpenAI strict mode would accept a typeless node. That fix was necessary but not sufficient: OpenAI's strict-mode validator has two more requirements that apply to any node whose type CAN be "object" or "array", with no exception for a type union that merely includes those alongside other primitives: - additionalProperties:false (+ empty properties/required) on every node whose type can be "object" — 400: "'additionalProperties' is required to be supplied and to be false" - an "items" sub-schema on every node whose type can be "array" — 400: "array schema missing items" Both gaps were found live, back to back, on the same real-OpenAI smoke run (#828): the first request to gpt-5.4-nano with a Workflow-tool-shaped typeless `args` param 400'd on additionalProperties; after fixing that, the very next request 400'd on the array/items gap. Fix: the synthetic branch now also carries additionalProperties:false, an empty properties map, an empty required list, and an items sub-schema. items bottoms out at primitives only (string/number/boolean/null) rather than recursing into the same object/array requirements one level down — deliberate and bounded, since this whole branch already means "no type information at all" and a precise recursive value contract isn't the point. Strengthened TestStrictify_TypelessOptionalGetsExplicitValueType with assertions on all four fields (additionalProperties, properties, required, items) — their absence is exactly what let both gaps ship, since the existing test only checked the type union itself. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @steventohme's task —— View job
Posted 3 advisory nits (won't block merge):
|
workweave-bot
left a comment
There was a problem hiding this comment.
Advisory only — comment-length nits. Won't block merge.
What T-Rex did
Reviews (1): Last reviewed commit: "fix(translate): satisfy OpenAI strict-mo..." | Re-trigger Greptile |
Co-authored-by: workweave-bot <bot@workweave.ai>
Co-authored-by: workweave-bot <bot@workweave.ai>
|
Claude finished @steventohme's task —— View job Claude finished @steventohme's task —— View job
Posted 1 advisory nit (won't block merge):
|
workweave-bot
left a comment
There was a problem hiding this comment.
Advisory only — comment-length nits. Won't block merge.
| // | ||
| // OpenAI strict mode requires, on every node whose type can be "object": additionalProperties:false | ||
| // + empty properties/required (400: "'additionalProperties' is required to be supplied and to be false"). | ||
| // On every node whose type can be "array": an "items" sub-schema (400: "array schema missing items"). | ||
| // items bottoms out at primitives — this branch means "no type info at all", so a shallow | ||
| // terminating schema is deliberate. |
There was a problem hiding this comment.
| // | |
| // OpenAI strict mode requires, on every node whose type can be "object": additionalProperties:false | |
| // + empty properties/required (400: "'additionalProperties' is required to be supplied and to be false"). | |
| // On every node whose type can be "array": an "items" sub-schema (400: "array schema missing items"). | |
| // items bottoms out at primitives — this branch means "no type info at all", so a shallow | |
| // terminating schema is deliberate. | |
| // | |
| // OpenAI strict mode: object-capable nodes need additionalProperties:false + empty | |
| // properties/required; array-capable nodes need an items sub-schema. items bottoms out | |
| // at primitives — deliberate, this branch means "no type info at all". |
Was 6 lines; parenthetical 400-message quotes restate what the code already shows. The WHY fits in 4.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 53bfe70. Configure here.
| "properties": map[string]any{}, | ||
| "required": []any{}, | ||
| "items": map[string]any{"type": []any{"string", "number", "boolean", "null"}}, | ||
| } |
There was a problem hiding this comment.
Strict defaults clobbered by merge
Low Severity
The synthetic branch sets OpenAI-required additionalProperties, properties, required, and items, then copies every key from the original node on top. A typeless node that already carries additionalProperties (or a conflicting required/items) overwrites those defaults and can reintroduce the same strict-mode 400s this change is meant to close.
Reviewed by Cursor Bugbot for commit 53bfe70. Configure here.


What
#829 fixed
makeNullable's fallback for a typeless optional property (no"type"/"anyOf"/"enum") by stamping an explicit value-type union (["string","number","boolean","object","array","null"]) on the syntheticanyOfbranch. Necessary, but not sufficient — OpenAI's strict-mode validator has two more requirements for any node whose type can be"object"or"array", with no exception for a union that merely includes those types alongside primitives:additionalProperties:false(+ emptyproperties/required) on every object-capable node — 400:"'additionalProperties' is required to be supplied and to be false""items"sub-schema on every array-capable node — 400:"array schema missing items"Fix: the synthetic branch now carries both.
itemsbottoms out at primitives only (no recursion) — deliberate, since this branch already means "no type information at all."Why
Both gaps were found live, back to back, on the same real-OpenAI smoke run (#828): a request to
gpt-5.4-nanowith a Workflow-tool-shaped typelessargsparam 400'd onadditionalProperties; after fixing that, the very next request 400'd on the array/itemsgap. Split out of #828 per review — that PR is the test harness; this is the standalone production fix it caught.Testing
go test ./internal/translate/...— strengthenedTestStrictify_TypelessOptionalGetsExplicitValueTypewith assertions on all four fields (additionalProperties,properties,required,items); their absence is exactly what let both gaps ship.go build ./...,go vet ./...,gofmt -l .all clean.