Repository navigation
api: tolerate unknown enum values on both clients (T106, #54, D-2026-10-13-09) - #79
Merged
Merged
Conversation
zzThis RM-075, D-2026-10-13-09: a value a response enum does not list yet no longer fails the whole response. Android: the generator option enumUnknownDefaultCase=true decodes it to the generated unknown_default_open_api case. Every when over a generated enum handles that case. Discovery's contract property is name-mapped to contractVersion, because the 7.25.0 enum serializer template does not compile for its escaped name. An unknown error code stays unavailable. iOS: swift-openapi-generator 1.13.1 has no fallback option, so EnumToleranceMiddleware rewrites an unknown value to a fallback case before the generated client decodes it, with the known values read from each generated enum's allCases. Generated types stay untouched. DecodingTest.anEnumValueOutsideContract1IsRefused asserted the behavior D-2026-10-13-09 reverses; it now asserts that the value decodes to the unknown case and the rest of the body is kept. Ticks T106 and T095. Closes #54 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6 of 7 tasks
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.
zzThis RM-075, D-2026-10-13-09 (accepted by Danny on zzthis #170): a value a response enum does not list yet no longer fails the whole response. Generator versions are unchanged: OpenAPI Generator 7.25.0, swift-openapi-generator 1.13.1.
Mechanism
Android. The generator option
enumUnknownDefaultCase=trueis added to:core-api:openApiGenerate. An unknown value decodes to the generatedunknown_default_open_apicase. Everywhenover a generated enum in core-api and the app handles that case.The option exposed a 7.25.0 template bug. The generator escapes Discovery's
contractproperty as a reserved word, and the new enum serializer then writes that name HTML-encoded (`Contract`Serializer), which does not compile.--name-mappings contract=contractVersionrenames it in Kotlin only. The wire name stayscontract. This is generator configuration (runtime.md, API client step 6), and onlyDemoApichanged to match.iOS. swift-openapi-generator 1.13.1 has no fallback option. Its feature flags are empty, and its unknown-case support is internal only. Its documented "open enum" pattern (
anyOfwithtype: string) needs a contract change, which the contract 1 freeze rules out. So a newEnumToleranceMiddlewarein ZZAPI, first in both clients' middleware lists, rewrites an unknown value before the generated client decodes the body:allCases, so a value the contract adds is known as soon as the pin moves.ZZServicecalls.Cache-Controlresponse header is an enum on iOS too. An unknown value becomesno-store, which means only that FR-041 does not keep that resolve. Android never decoded that header.Fallback per enum
unknown_default_open_api)viewview, so it reads likepublic.publicstatuscodes.status_expiredcaption. Not active, so no Revoke. There is no copy for an unknown status, and copy comes only from zzThis.expired(same screens)scopefree_publicauth_providersAppModel.authProviders, so no button.scopescontractX-ZZ-Contractheader stays the strict version check (FR-032).1providersnoteAccountskips it.token_type,expires_inBearer,900statusrevokederror(404, 429, other)unavailable, as before this changeunavailable, as before this changeTokenRequest.Provider,ReportRequest.Reason)whenstays exhaustive.One existing assertion changes
DecodingTest.anEnumValueOutsideContract1IsRefused(Android, from #43) asserted that an Account with"providers":["github"]is refused. D-2026-10-13-09 and T095 require the opposite. It is nowanEnumValueOutsideContract1DecodesToTheUnknownCase, which asserts that the account decodes,providers == [unknown_default_open_api], and the id is kept. Please confirm this reading of the decision.Tests
Android
TolerantReaderTest:"view":"auditor"decodes and the record shows (the body from Generated clients fail a whole response on an unknown enum value (RM-075) #54)unavailableiOS
TolerantReaderTests:"view":"auditor"shows the recordCache-Controlis not cacheabletoken_typeandexpires_inunavailableWith the middleware removed, the 8 tolerance tests fail with
.unavailable.Commands run, all green:
swift testin ZZAPI: 45 tests./gradlew :core-api:openApiGenerate :core-api:test :app:testDemoDebugUnitTest :app:testLocalDebugUnitTest :core-auth:test :core-storage:test: 83 / 170 / 10 / 16 testspython3 scripts/lint-specs.pyandpython3 scripts/check-strings.pySpecs
Closes #54
🤖 Generated with Claude Code