Skip to content

spec: union-branch selection policy now has two sibling implementations INSIDE one package (error-map renderer vs the D3 structural mapper) #8318

Description

@hotlong

Observation-class finding from #8124 (no defect today — the two agree, and tests on both sides pin the shared verdict).

What

packages/spec/src/shared/error-map.zod.ts (the string renderer: formatZodIssue / selectUnionBranches / CONTAINER_ISSUE_CODES / the depth and branch limits) and packages/spec/src/api/zod-issues-to-fields.ts (the ADR-0114 D3 structural mapper, moved into spec by #8124) carry the SAME union-branch selection policy — kind-mismatch drop, fewest-issues ranking, unrecognized_keys tie-break, declaration-order determinism, depth limit 3, branch cap 3, container descent per #5389 — as two separate implementations.

Why it was tolerable before, and what changed

While the structural mapper was module-local to @objectstack/rest, the duplication was forced: spec exported only the string renderer, and the comment on the rest side documented the pairing ("the verdict must match all the same", #5014). #8124 moved the mapper into spec, so the historical reason is gone: both implementations now live one directory apart in the same package. The module headers bind them to move together in the same PR, but nothing mechanical enforces it.

Possible shape (not ruled)

Extract the selection policy (isKindMismatchOnly, carriesUnknownKey, selectUnionBranches, CONTAINER_ISSUE_CODES, the two limits) into one package-internal module both walks import — internal only, NOT a public export (the #4001 pitfall: do not export internals only these modules need). The walks themselves stay separate (prose lines vs {field, code, message} entries; the renderer also emits the "… and N more branches" line the wire deliberately omits). The one signature wrinkle: the renderer's selectUnionBranches returns {selected, omitted}; the mapper ignores omitted.

Deliberately NOT done in #8124: the card's scope was ending the wire's code leak with a behavior-identical move, and rewriting error-map.zod.ts in the same PR would have widened the test surface the move's proof rests on.


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions