Skip to content

finding(types): ChartDataSeriesSchema SILENTLY STRIPS six series keys the renderer reads — label, variant, opacity, dashArray, stack, yAxis #7546

Description

@claude

Found while implementing #7113 (PR #7545); out of that card's scope — its ruling fences the change to chart-level data, xAxisKey, and the two series binding dialects. Filed unassigned for triage. Not fixed in that PR.

The finding

ChartDataSeriesSchema is a non-strict z.object — not .passthrough() like BaseSchema. A non-strict z.object strips an undeclared key in silence. Six keys that normalizeSeries demonstrably reads are undeclared, so a parsed series loses them and safeParse reports success.

Measured against the built mirror on origin/main 98d4108a2:

input : { name, label, stack, yAxis, opacity, dashArray, variant }
parse : success = true
output: { name }

Every one of the six is read at packages/plugin-charts/src/normalizeChartSchema.ts in normalizeSeries (lines 242-256):

key read
label const lbl = label(raw.label)
variant str(raw.variant), narrowed to comparison / current / primary
opacity num(raw.opacity)
dashArray str(raw.dashArray)
stack str(raw.stack)
yAxis str(raw.yAxis), narrowed to left / right

Why this is worse than the chart-level case #7113 fixed

They are different failure shapes, and this is the sharper one:

This is the same silent no-op the #6896 retirement tombstone comment names in this very file, applied to keys that are live rather than retired.

Also undeclared, though merely passed through rather than stripped, on ChartSchema itself: xAxis (the axis config object dialect — field, format, title, showGridLines, min, max, position, logarithmic) and yAxis, both read by normalizeAxis / normalizeChartSchema at lines 204-220 and 287-298. #7113 deliberately folded only the bare-string xAxis and left the object dialect untouched, because folding it would discard its presentation keys — declaring it is the follow-up this finding covers.

Suggested shape

Declare the six series keys on ChartDataSeriesSchema and its TS twin ChartDataSeries with the narrowings the reads already enforce (variant and yAxis are closed unions in the normalizer, so the declaration should be the union, not string), and declare the axis-config dialect on ChartSchema. Both faces move together or zod-mirror-parity.test.ts records the drift.

⚠️ Whether the axis-config object should be declared at all — versus retired under ADR-0049 if no authored document uses it — is a triage question, not a foregone conclusion. variant in particular is worth a liveness read before declaring: it is narrowed to three values whose consumers should be confirmed.

Related: #7113 (the chart-level half, PR #7545), #6896 (the retirement whose tombstone prose names this class), #7112 (the teaching sites).


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions