Carved out of objectui#7546 by the domain:ui PM seat, on the contract review of PR #7684. #7684 carries Fixes #7546; without this card the finding below survives only as a comment on a closed card and a pin-test comment. That is measured-and-lost, and it is the seat's miss — objectui#7690 rescued the axis-config half of #7546 and this half was not.
The fact, as PR #7684 measured it
normalizeSeries reads str(raw.chartType) ?? str(raw.type). The first limb is undeclared on ChartDataSeriesSchema, which is a non-strict z.object, so an authored chartType on a series is silently stripped by the parse and never reaches that limb.
chartType measured not live on the authoring face, with lit controls, twice:
| population |
chartType |
control |
| docs |
0 |
dataKey / name / type / color lit |
| fixtures |
0 |
lit |
designer inputs |
0 |
the chart registration's series is one code input |
| src literals |
0 |
— |
| tests |
9 |
all internal dataKey-shaped, taking ChartRenderer's raw fast path — they never reach the normalizer's first limb |
Limb ablation, re-run by the reviewer on 197 files / 2380 tests (5× the author's population): deleting str(raw.chartType) ?? left 2380 passed; the sibling-limb control (deleting ?? str(raw.type)) went 2 failed. The instrument is lit and the zero is a reading.
And the contract of record refuses the name itself: @objectstack/spec@17.2.0 answers Unrecognized key(s) on this chart series: chartType. Did you mean chartType → type? — its alias map already declares chartType a spelling of type. Core's own chart-presentation.ts:122-123 translates authored type → internal chartType, confirming it is the internal spelling.
The ruled shape — option A
The PM ruling on #7546 and the contract review of #7684 both land on A: a named alias refusal pointing at type, the posture the spec itself takes. Not B (fold chartType onto type at parse — the renderer takes chartType FIRST, so the fold would let the alias overwrite the canonical key when both are written, inverting the objectui#7113 precedence rule) and not C (declare it as a second writable name — contradicts the spec's alias map and the three in-repo docblocks calling it the internal spelling; the N-dialects hazard of AGENTS.md #0.1).
⚠️ This is a NARROWING, and that is why it is its own card. { name: 'x', chartType: 'line' } draws a line today through the first limb; a named refusal takes that away. It needs its own changeset grade and its own liveness re-read at the time of implementation — ⛔ do not inherit the readings above as still-true, re-measure them.
Not in scope
⛔ Do not touch the ?? str(raw.type) sibling limb — it is lit (2 red on ablation). ⛔ Do not fold this into #7684; that PR's fence is deliberate. Sibling cards from the same measurement: objectui#7681 (a declared per-series type is dropped on the dataKey fast path), objectui#7682 (variant carries three different unions across four sites), objectui#7690 (the axis-config object dialect).
Generated by Claude Code
Carved out of objectui#7546 by the
domain:uiPM seat, on the contract review of PR #7684. #7684 carriesFixes #7546; without this card the finding below survives only as a comment on a closed card and a pin-test comment. That is measured-and-lost, and it is the seat's miss — objectui#7690 rescued the axis-config half of #7546 and this half was not.The fact, as PR #7684 measured it
normalizeSeriesreadsstr(raw.chartType) ?? str(raw.type). The first limb is undeclared onChartDataSeriesSchema, which is a non-strictz.object, so an authoredchartTypeon a series is silently stripped by the parse and never reaches that limb.chartTypemeasured not live on the authoring face, with lit controls, twice:chartTypedataKey/name/type/colorlitinputschartregistration'sseriesis onecodeinputdataKey-shaped, takingChartRenderer's raw fast path — they never reach the normalizer's first limbLimb ablation, re-run by the reviewer on 197 files / 2380 tests (5× the author's population): deleting
str(raw.chartType) ??left 2380 passed; the sibling-limb control (deleting?? str(raw.type)) went 2 failed. The instrument is lit and the zero is a reading.And the contract of record refuses the name itself:
@objectstack/spec@17.2.0answersUnrecognized key(s) on this chart series: chartType. Did you mean chartType → type?— its alias map already declareschartTypea spelling oftype. Core's ownchart-presentation.ts:122-123translates authoredtype→ internalchartType, confirming it is the internal spelling.The ruled shape — option A
The PM ruling on #7546 and the contract review of #7684 both land on A: a named alias refusal pointing at
type, the posture the spec itself takes. Not B (foldchartTypeontotypeat parse — the renderer takeschartTypeFIRST, so the fold would let the alias overwrite the canonical key when both are written, inverting the objectui#7113 precedence rule) and not C (declare it as a second writable name — contradicts the spec's alias map and the three in-repo docblocks calling it the internal spelling; the N-dialects hazard ofAGENTS.md#0.1).{ name: 'x', chartType: 'line' }draws a line today through the first limb; a named refusal takes that away. It needs its own changeset grade and its own liveness re-read at the time of implementation — ⛔ do not inherit the readings above as still-true, re-measure them.Not in scope
⛔ Do not touch the
?? str(raw.type)sibling limb — it is lit (2 red on ablation). ⛔ Do not fold this into #7684; that PR's fence is deliberate. Sibling cards from the same measurement: objectui#7681 (a declared per-seriestypeis dropped on thedataKeyfast path), objectui#7682 (variantcarries three different unions across four sites), objectui#7690 (the axis-config object dialect).Generated by Claude Code