You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
spec: GanttConfigSchema is strictObject(...).passthrough(), so a mistyped gantt key is silently accepted — the only one of the three view config schemas that does not refuse it #15469
Found while doing #14471 (prose on colorField for timeline / calendar / gantt). Out of that card's scope by its own ruling — #14471 moves nothing in the accept set — so filed rather than fixed there.
The measurement
packages/spec/src/ui/view.zod.ts builds all three view config schemas with the same strictObject(...) helper. Two of them refuse an undeclared key. The gantt does not:
Run against the built packages/spec/dist/ui/index.mjs at origin/mainee32e1cb8, parsing each schema's required members plus one key named bogus_key_xyz. Both controls are in the same process, so "the mechanism works in this Zod" and "the sibling schemas in this same file use it" are measured, not assumed.
The cause is declared in the source, not accidental
GanttConfigSchema ends with an explicit, commented .passthrough():
// Forward-compatible: the gantt renderer (objectui plugin-gantt) keeps adding// config knobs (e.g. lockField / defaultCollapsedDepth) ahead of this schema.// Passthrough lets those extra fields reach the renderer instead of being// stripped here, so a renderer release no longer has to wait on a spec release.}).passthrough());
It is the only .passthrough() in view.zod.ts. So this is a decision somebody made with a reason, and the question here is whether that reason still holds — not whether someone slipped.
Why it is worth a triage decision
strictObject is applied and then undone at that one site. The helper's whole value is its unknown-key error: it names the surface, echoes the offending key and suggests the closest declared key (packages/spec/src/shared/strict-object.ts). .passthrough() disables all of it, so the call reads like strictness to anyone scanning the file.
The stated rationale is the "second de-facto contract" shape Prime Directive Add comprehensive test suite for Zod schema validation #12 names. "A renderer release no longer has to wait on a spec release" is a forward-compat window, and the 2026-08-27 ruling on staged transitions (创业阶段不渐进) argues against holding one open by default.
It may be invisible to the strictness campaign. The ledger (docs/audits/2026-07-unknown-key-strictness-ledger.md) classifies view.zod.ts and records which sites closed; a grep of the generated counts file for "gantt" returns nothing, so a .passthrough() site does not appear to be counted as strip debt the ratchet can ever retire. Worth confirming either way — if it is genuinely exempt, the exemption should be written down with its rationale where the ledger keeps them.
The keys the window exists for
objectui declares ten GanttConfig members the spec does not model — borderColorField, lockField, objectField, summaryExtent, defaultCollapsedDepth, dependencyTypes, timeZone, exportFileName, interactions, timeSegments (GANTT_CONFIG_EXTENSION_KEYS in packages/plugin-gantt/src/ObjectGantt.tsx at pin 00d3f09c). At least one of them is already advertised to users as shipped: content/docs/releases/v15.mdx:151 names borderColorField. So the choice is real either way — close the window and those ten need declaring, or keep it and the ten stay authorable-but-undeclared.
Decision, not a patch
Both directions are accept-set changes, so this needs triage rather than an implementer:
A — declare the ten and drop .passthrough(). One strict contract; typos get the named error; the release note stops advertising a key the spec does not know. Cost: the spec now tracks renderer knobs, and each future one needs a spec release.
B — keep the window, write it down. Cheapest today. Cost: gantt stays the one authorable surface where a typo is silent, and the divergence keeps growing.
C — declare the ten, keep .passthrough() for the next ones. Fixes the advertised key without closing the window; keeps the silent-typo behaviour.
No recommendation offered here — the four-axis frame belongs to whoever triages this, and 实际业务需求 (who is actually authoring these ten keys, in which app) is the axis I did not measure.
Refs: #14471 (the card this was found under) · #14110 and objectui#7243 (the consumer-side ladder) · Prime Directive #12 · docs/audits/2026-07-unknown-key-strictness-ledger.md
Found while doing #14471 (prose on
colorFieldfor timeline / calendar / gantt). Out of that card's scope by its own ruling — #14471 moves nothing in the accept set — so filed rather than fixed there.The measurement
packages/spec/src/ui/view.zod.tsbuilds all three view config schemas with the samestrictObject(...)helper. Two of them refuse an undeclared key. The gantt does not:Run against the built
packages/spec/dist/ui/index.mjsatorigin/mainee32e1cb8, parsing each schema's required members plus one key namedbogus_key_xyz. Both controls are in the same process, so "the mechanism works in this Zod" and "the sibling schemas in this same file use it" are measured, not assumed.The cause is declared in the source, not accidental
GanttConfigSchemaends with an explicit, commented.passthrough():It is the only
.passthrough()inview.zod.ts. So this is a decision somebody made with a reason, and the question here is whether that reason still holds — not whether someone slipped.Why it is worth a triage decision
strictObjectis applied and then undone at that one site. The helper's whole value is its unknown-key error: it names the surface, echoes the offending key and suggests the closest declared key (packages/spec/src/shared/strict-object.ts)..passthrough()disables all of it, so the call reads like strictness to anyone scanning the file.colorFieldis declared on all three. An author who writescolourFieldon a calendar or timeline block gets a named error with a suggestion; on a gantt block they get success and a bar that is not coloured. That is the exact failure shapegantt.colorFieldis passed raw intobackgroundColor, so pointing it at a select field un-colours every bar — while OMITTING the key colours them correctly #14110 / objectui#7243 just closed one layer down — declaring the key was worse than omitting it — reappearing as a typo the contract will not catch.docs/audits/2026-07-unknown-key-strictness-ledger.md) classifiesview.zod.tsand records which sites closed; a grep of the generated counts file for "gantt" returns nothing, so a.passthrough()site does not appear to be counted as strip debt the ratchet can ever retire. Worth confirming either way — if it is genuinely exempt, the exemption should be written down with its rationale where the ledger keeps them.The keys the window exists for
objectui declares ten
GanttConfigmembers the spec does not model —borderColorField,lockField,objectField,summaryExtent,defaultCollapsedDepth,dependencyTypes,timeZone,exportFileName,interactions,timeSegments(GANTT_CONFIG_EXTENSION_KEYSinpackages/plugin-gantt/src/ObjectGantt.tsxat pin00d3f09c). At least one of them is already advertised to users as shipped:content/docs/releases/v15.mdx:151namesborderColorField. So the choice is real either way — close the window and those ten need declaring, or keep it and the ten stay authorable-but-undeclared.Decision, not a patch
Both directions are accept-set changes, so this needs triage rather than an implementer:
.passthrough(). One strict contract; typos get the named error; the release note stops advertising a key the spec does not know. Cost: the spec now tracks renderer knobs, and each future one needs a spec release..passthrough()for the next ones. Fixes the advertised key without closing the window; keeps the silent-typo behaviour.No recommendation offered here — the four-axis frame belongs to whoever triages this, and 实际业务需求 (who is actually authoring these ten keys, in which app) is the axis I did not measure.
Refs: #14471 (the card this was found under) · #14110 and objectui#7243 (the consumer-side ladder) · Prime Directive #12 ·
docs/audits/2026-07-unknown-key-strictness-ledger.md