fix(elixir): decode discriminated inline unions without a mapping - #111
Merged
Merged
Conversation
An inline oneOf with `discriminator: {propertyName: ...}` and no mapping
got an empty `%{}` mapping: prepareElixirSpec infers tags only from $ref
variants, and `{}` is truthy, so descriptor() never fell back. Codec then
rejected every value ("response does not match required fields").
ExternalObject.object hit this, failing the ExternalObjects list contract
test in archastro-elixir; agents, ai, and api_chat carried the same
broken descriptor.
Emit a plain `{:union, variants}` when no tag maps to a module. Codec
tries each variant, and each variant's own discriminator enum keeps the
match exact.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Review on ArchCode
Problem
Regenerate SDKin archastro-elixir (#24) fails theExternalObjectslist contract test:The same empty-mapping descriptor was also generated in
agents.ex,ai.ex, andapi_chat_channel.ex. Other languages don't use a tag→module mapping, so only Elixir is affected.What changed
backends/elixir/index.tsdescriptor(): if the explicit or inferred mapping has no entries, emit{:union, variants}instead of a discriminated union with%{}.Codec.decode/2then tries each variant. Each hoisted variant struct requires its owntypeenum value, so exactly one matches.$refs) are unchanged. Existing testpreserves original implicit discriminator tags while normalizing modulesstill passes.Scope / risk
Generator only (Elixir). Unchanged: every union that currently decodes. Changed: unions that currently fail on every input. Low risk.
Testing
elixir.test.ts›decodes discriminated inline union variants without a mapping by trying each variant: failed before the fix (output contained{"type", %{}}), passes after.npm test: 426/426.tsc --noEmitandnpm run lintclean.auto/regenerate-sdk) with this build viaARCHASTRO_SDK_GENERATOR_BIN=… ./scripts/regenerate_sdk.sh --local <this checkout>, then ran CI's steps locally:mix format --check-formatted✅,mix compile --warnings-as-errors✅,mix dialyzer→ 0 errors.ExternalObjectscontract suite against Prism: 27/27 (previously 26/27).mix test test/contract --only channel_contractwith the harness from this repo: 16/16.CIruns the vitest case. archastro-elixirCIruns the generated contract tests on each regen PR.Follow-up
Release sdk-generator v0.11.11, rerun
Regenerate SDKin archastro-elixir, then update that PR's hand-written fixtures and itschannel-harnesslockfile entry (0.5.0 → 0.7.1). That lives in the Elixir repo, not here.🤖 Generated with Claude Code