feat(types): regenerate schemas + inject Literal-discriminator defaults#254
Merged
feat(types): regenerate schemas + inject Literal-discriminator defaults#254
Conversation
Upstream spec added a cluster of breaking changes — most Asset classes
went from 'discriminator is implicit' to 'asset_type is required'.
Pydantic honors 'required' literally, breaking ergonomic construction:
# Before upstream change: TextContent(content='hello')
# After upstream change, pre-fix:
TextContent(asset_type='text', content='hello') # must repeat tag
Fix: inject_literal_discriminator_defaults() in post_generate_fixes.py.
Pattern-matches AnnAssign nodes whose annotation is Literal['x'] (bare
or Annotated-wrapped) with no default, appends ` = 'x'` on the same
line. Touched 687 fields across 615 classes in 105 files — Asset
types, pricing options, webhook types, catalog types, all spec
discriminator fields.
Wire consumption unchanged. Literal type still rejects other values,
so validation strength preserved. Wire dicts with the tag present
validate as before; dicts without the tag now also work (fall through
to default) — useful for minimal clients.
Pattern-based, not value-specific: robust to spec-value churn as long
as the single-value-Literal discriminator shape holds.
Also pulls upstream PRs #250 (design doc) and #251 (A2A contextId,
+22 integration tests). All green.
+16 new tests in tests/test_literal_discriminator_defaults.py. Covers
Asset defaults, VAST/DAAST dual-discriminator defaults, validation-
strength preservation, wire-format compatibility, injector meta-tests
(skips multi-value literals, extracts single-value, skips non-Literal).
2102 passing (was 2086), mypy clean.
Co-Authored-By: Claude Opus 4.7 (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.
Summary
Upstream spec added a cluster of breaking changes — most Asset classes went from "discriminator is implicit" to "required tag field with single-valued
Literal[...]type". Pydantic honors required literally, breaking ergonomic construction:Our v3→v4 migration already handles the
<Type>Asset → <Type>Contentrename; this new breaker is separate (required tag on the renamed class) and hits 15 test failures acrosstest_client,test_preview_html, andtest_discriminated_unions.The fix: pattern-based default injection
inject_literal_discriminator_defaults()inscripts/post_generate_fixes.py. Walks the AST of each generated Pydantic model; for anyAnnAssignwhose annotation isLiteral['x'](bare orAnnotated-wrapped) and whose value isNone(no default), appends= 'x'on the same line via a line-based edit.Touched 687 fields across 615 classes in 105 files — not just Asset types. Pricing options, webhook types, catalog types, and every other spec discriminator with a single-value Literal all get defaults.
Why this is safe
Literaltype still rejects any other explicit value — defaulting doesn't weaken the tag check.asset_typevalues) as long as the single-value-Literal shape holds.What's NOT fixed
The 3 WebhookAsset / CatalogAsset / VAST residual failures I flagged in the assessment turned out to also be Literal discriminators — all 15 failures are resolved by this one change. Future genuine-non-discriminator breakers (where a field became required with no canonical default) would need a separate mitigation (BeforeValidator coercion, better error messages) — this PR doesn't add that infrastructure because we don't need it yet.
Tested
tests/test_literal_discriminator_defaults.py:asset_typecheck)ValidationError)2102 passed, 22 skipped(was 2086 on previous green; 15 new cleared + 16 test additions - 15 removals).ruff,mypyclean across 678 source files.Also in this PR (upstream pulls)
contextId+taskIdauto-retain across multi-turn calls (+22 integration tests)Test plan
scripts/post_generate_fixes.py:inject_literal_discriminator_defaults— the AST walk + line edit is the risky part. Edit order is sorted descending so earlier edits don't shift later line indices.= 'text'suffix is well-formatted and syntactically valid (easy to spot-check onsrc/adcp/types/generated_poc/core/assets/text_asset.py).🤖 Generated with Claude Code