Skip to content

feat(bench): add the Attaform (Zod 4) adapter and order the comparison by performance#406

Merged
ozzyfromspace merged 2 commits into
mainfrom
feat/bench-attaform-zod4
Jun 14, 2026
Merged

feat(bench): add the Attaform (Zod 4) adapter and order the comparison by performance#406
ozzyfromspace merged 2 commits into
mainfrom
feat/bench-attaform-zod4

Conversation

@ozzyfromspace

Copy link
Copy Markdown
Contributor

What

Adds a second Attaform row to the cross-library benchmark, Attaform (Zod 4), so the arena measures
both adapters Attaform ships, and reorders the documentation comparison so the fastest library sits at
the top.

Two commits:

  1. feat(bench-arena): the Attaform (Zod 4) adapter plus the dual-zod isolation that lets one bench
    host both zod majors safely.
  2. feat(site): the comparison tables now rank by performance (best first), with a field-count
    selector that re-ranks at each scale.

Why

Attaform treats its zod-v3 and zod-v4 adapters as first-class peers, so the benchmark should hold both
to the same cohort. Separately, the comparison page rendered libraries in fixed registry order, so a
reader could not see at a glance who leads a given dimension.

The dual-zod isolation (the load-bearing piece)

Attaform's published zod-v4 adapter imports bare zod (on a zod 4.x install, bare zod resolves to
v4). The bench pins zod 3.x for the rest of the cohort, where bare zod is v3, so without isolation
the v4 adapter would resolve v3 and a v4-built schema would fail to parse.

The fix is a small vite resolver (enforce: 'pre') that redirects only the Attaform dist's bare
zod import to an aliased zod-v4 package (npm:zod@^4), leaving every other library's zod
untouched. The v3 cohort is provably unaffected (see the validation run below). This is the general
pattern for hosting two zod majors in one app, and it carries directly to any future adapter that needs
a different zod major than its neighbours.

One new bench-only devDependency: zod-v4 (an alias of zod@^4).

Local parity check (throwaway, not committed)

A local head-to-head smoke run (attaform vs attaform-zod4 across all 68 comparable cells) puts the
median ratio at exactly 1.00:

  • Hot paths at parity or faster on v4: keystroke at scale (massive L2000 5.1 = 5.1ms, grid N100M8
    +3%), validate often faster on v4, rerender identical, array ops within noise.
  • Retained memory converges at runtime scale: arrays N100 +1.6%, grid N100M8 +1.6%.
  • The only real gaps are a one-time schema-build cost at structural scale: the massive scenario
    (hundreds of distinct keys plus deep nesting) shows mount +43% and retained heap +83% on v4. This is
    zod v4's heavier in-memory schema representation, faithfully reflected by the adapter. It does not
    appear in arrays/grid at scale (where one small row shape is reused N times), and it is a one-time
    mount/heap cost, not a steady-state hot-path cost.

Absolute numbers are host-specific; CI will re-measure. No DNFs, no failures.

Docs comparison ordering

The runtime (timed plus memory) tables now sort by the selected scale's measurement, best first, with a
field-count selector that re-ranks at other scales (hidden for single-param dimensions). The bundle
table sorts smallest-first. Capability and supply-chain tables keep registry order (they are not
performance axes). The sort works on the current committed cohort immediately.

Sequencing

This PR's sort UI works on the current results.json now. After merge, a CI bench refresh (the monthly
sharded workflow) repopulates results.json with the ninth row so the published tables include
Attaform (Zod 4).

Test plan

  • Bench typecheck (vue-tsc), root lint plus format, site typecheck: green.
  • Arena spec validation (--grep 'attaform-zod4|DU'): 116 passed, 0 failed; attaform-zod4 DU green,
    every v3-cohort DU cell unchanged.
  • Full head-to-head smoke (--grep attaform): 136 passed, 4 skipped (the L5000 budget skips), 0 failed.

🤖 Generated with Claude Code

ozzyfromspace and others added 2 commits June 13, 2026 19:27
…lation

Add a second Attaform row to the cohort, built on `attaform/zod-v4`, so the bench
measures both first-class zod adapters side by side. It mirrors the existing
Attaform adapter exactly (same shared Field / ArrayRow bindings, same handle),
differing only in the validator it feeds: `useForm` / `useWizard` from
`attaform/zod-v4` over zod v4 schemas. New `*Zod4` scenario builders (dispatched
by `zodV4SchemaFor`) mirror the v3 shapes, and `schemaLib` gains a `zod4` value.

Dual-zod isolation is the load-bearing piece. Attaform's published zod-v4 adapter
imports bare `zod`, expecting zod@^4 (its zod-v3 adapter imports the `zod-v3`
alias instead). The arena pins zod@3 for the whole v3 cohort, so without isolation
the v4 adapter resolves zod v3 and runs v3's discriminatedUnion over a v4 schema,
which throws "discriminator could not be extracted" and breaks the DU scenario.

A small `enforce: 'pre'` vite resolver redirects ONLY the Attaform dist's bare
`zod` import to an aliased `zod-v4` package (npm:zod@^4); every other bare `zod`
import (the v3 validators, the v3 schema builders) is left untouched, so the v3
cohort's numbers cannot move. This is the general shape for hosting mixed zod
majors in one bundle, and the same approach will host a future vee-validate v4.

Validated locally: the zod-v4 row is green across all seven scenarios including
discriminated-union, and every v3-cohort DU cell passes unchanged (116 passed, 0
failed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le selector

The runtime tables rendered fixed registry order, so a reader could not see who
was fastest at a glance. Order the rows by performance instead, best at the top,
ranked by the value at the largest (at-scale) param where the cost gaps read
truest. A did-not-finish or unsupported cell sorts last, never ahead of a real
measurement.

Add a "Sort by" selector that re-ranks the rows at any other field count, so a
reader can watch the order shift as a form grows from a handful of fields to
thousands. It shows only when a dimension has more than one param; single-param
scenarios (discriminated-union, wizard) still sort, with no selector. The bundle
table already orders smallest-first, and the capability / scorecard tables stay
in registry order since they are not performance axes.

Also label the new `zod4` schema value as "Zod 4" in the capability matrix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
attaform Ready Ready Preview, Comment Jun 13, 2026 11:50pm

@ozzyfromspace ozzyfromspace merged commit 67e576b into main Jun 14, 2026
15 checks passed
@ozzyfromspace ozzyfromspace deleted the feat/bench-attaform-zod4 branch June 14, 2026 01:07
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