Skip to content

fix(ack): synthesize union-owned discriminator on encode for codec branches#113

Merged
leoafarias merged 1 commit into
mainfrom
fix/discriminated-codec-encode
May 28, 2026
Merged

fix(ack): synthesize union-owned discriminator on encode for codec branches#113
leoafarias merged 1 commit into
mainfrom
fix/discriminated-codec-encode

Conversation

@leoafarias

Copy link
Copy Markdown
Collaborator

Problem

A discriminated-union codec branch whose encoder omits the union-owned discriminator could be decoded but not re-encoded — a broken round-trip:

Ack.discriminated<Map<String, Object?>>(
  discriminatorKey: 'type',
  schemas: {
    'cat': Ack.object({'name': Ack.string()}).codec<Map<String, Object?>>(
      decode: (d) => {'name': d['name']!},
      encode: (c) => {'name': c['name']},   // omits 'type' — union owns it
    ),
  },
).safeEncode({'name': 'Mittens'});   // FAILED; expected {'type':'cat','name':'Mittens'}

The effective branch injects the discriminator as a bare required literal; for a codec branch the intermediate map omits it, so ObjectSchema encode-validation fails. (This is the flutter_codec use case; the generated map-backed extension-type path is unaffected because it carries the discriminator in the map.)

Fix

Synthesize the discriminator on encode for codec branches only:

  • New internal ObjectSchema.encodeOnlyDefaults map supplies a property value when the key is absent on encode.
  • Set only on codec-backed branches, gated by an underCodec flag threaded through effectiveDiscriminatedBranch — flipped true only when a CodecSchema sits on the wrapper spine.
  • Plain branches keep the bare required literal, so encoding a payload missing the discriminator still fails — no automatic branch selection.
  • The field is excluded from ==/hashCode/toMap, so effective branches stay equal to authored twins and JSON Schema export is unchanged (discriminator stays required, no default) with zero schema-model changes.

Tests

Added: codec-omits-discriminator encode + round-trip, passthrough()+codec, multi typed-codec branch selection, nested Default/Codec gating, and a plain-branch regression lock.

Verified locally:

  • dart analyze packages/ack/lib — no issues
  • full ack suite — 921 passed
  • ack_json_schema_builder — 49 passed
  • ack_generator discriminated integration — 19 passed

…anches

Codec branches whose encoder omits the union-owned discriminator could be decoded but not re-encoded: the effective branch injected the discriminator as a bare required literal that the codec's intermediate map lacked, so ObjectSchema encode-validation failed.

Carry the synthesized value in an internal ObjectSchema.encodeOnlyDefaults map, set only on codec-backed branches (gated by a CodecSchema on the wrapper spine via the threaded underCodec flag). Plain branches keep the bare required literal, so encoding a payload missing the discriminator still fails — no automatic branch selection.

The field is excluded from ==/hashCode/toMap, so effective branches stay equal to authored twins and JSON Schema export is unchanged (discriminator stays required, no default).
@docs-page

docs-page Bot commented May 28, 2026

Copy link
Copy Markdown

To view this pull requests documentation preview, visit the following URL:

docs.page/btwld/ack~113

Documentation is deployed and generated using docs.page.

@leoafarias leoafarias merged commit 20398c8 into main May 28, 2026
1 check passed
@leoafarias leoafarias deleted the fix/discriminated-codec-encode branch May 28, 2026 21:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant