Uh oh!
There was an error while loading. Please reload this page.
feat(types,plugin-gantt): declare the ten gantt keys ObjectGantt reads through a cast - #6053
Merged
Merged
Conversation
…s through a cast (#5903) All ten were read as `(schema as any).K` in ObjectGantt.tsx — real, working, README-documented features that nothing connected to a declaration: not tsc, not the zod mirror, not the designer registry inputs. - `ObjectGanttSchema` (TS) and its zod mirror gain the same ten keys at the same requiredness (all optional), so `zod-mirror-parity` stays at zero drift for the pair and no `KnownDrift` entry is added. `navigation` derives from the spec's `NavigationConfigSchema` by reference. - `ObjectGanttProps.schema` is retyped `ObjectGridSchema` -> `ObjectGanttSchema`. Without that, dropping the casts would leave the reads on `BaseSchema`'s index signature — the same invisibility in different syntax. - `label`, the eleventh reported key, was already declared on `BaseSchema`; only its cast is dropped. - New declaration pin `gantt-declared-keys.test.ts` compiles under `tsconfig.test.json`, so removing a declaration fails the build naming the key. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
…-describing Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CSoz9uGhaaSgiq3hshtN7L
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Aug 24, 2026
yinlianghui
marked this pull request as ready for review
August 24, 2026 15:09
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Aug 24, 2026
This was referenced Aug 24, 2026
This was referenced Aug 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#5903
Verified at
fb876485d(final commit; every gate result below was re-run on thattree). Merge-base
b0de7a85c.What landed
ObjectGanttSchemadeclares the ten keysObjectGanttreads —skipWeekends,holidays,persistLayout,viewName,navigation,markers,criticalPath,showBaselines,readOnly,mobileReadOnly— on both its TS declarationand its zod mirror, at the same requiredness (all optional). All twelve
(schema as any).Kread sites are gone.navigationis taken from the spec'sNavigationConfigSchemaby reference, thesame way
ObjectGridSchema.navigationis, rather than restated. The other ninehave no spec member (
GanttConfigSchemamodels none of them), so they aredeclared as objectui's own display extension — the standing
timeSegmentsalready has on
GanttConfig.ObjectGanttProps.schemais retypedObjectGridSchema→ObjectGanttSchema.This is the load-bearing part of the change, not a tidy-up. The ten keys are not
grid keys, so under the old prop type dropping the casts would have left every
read landing on
BaseSchema's index signature — the same invisibility indifferent syntax. The grid-style
{ gantt: { … } }block is unaffected:getGanttConfigreads it through that same index signature exactly as before,and the registered renderer (
index.tsx) passesschema: any, so no runtimeshape is turned away. There is no other in-repo caller.
Per-key verdict — declare, delete, or already declared
Two outcomes were admissible per key. No read was deleted: all eleven are
live, and PR #5900's README (landed) documents all eleven as genuine working
features. Read sites are cited at the merge-base line numbers.
skipWeekends:891workingCalendar;GanttView.workaxis.test.tsxdrives itholidays:892workingCalendar; same testpersistLayout:1023persistLayoutKey;ObjectGantt.persistfilters.test.tsx,ObjectGantt.test.tsx:530viewName:1025persistLayoutKeynavigation:1132useNavigationOverlay; drawer-vs-page modemarkers:1471GanttViewmarkersprop →resolvedMarkerscriticalPath:1474React.useState(criticalPathDefault)(GanttView:2864)showBaselines:1477GanttView:2996,:3848readOnly:1478,:1523ObjectGantt.drawerlock.test.tsx:84)mobileReadOnly:1479effectiveReadOnly(GanttView:752)label:1494BaseSchema.label: string | I18nLabelDelta against the card, key by key. The card's count of 11 holds exactly on
merge-base
b0de7a85c— same eleven keys, same line numbers, nothing added orremoved by today's
packages/typestraffic. Neither #6003 (dashboard widgetvocabulary) nor #6012 (
IconSchema's glyph key rename) touches any of them. Onecorrection: the card lists
labelas undeclared, and it is not —BaseSchemahas carried it since #4580. So this card declares ten, not eleven.
labelispinned in the new test anyway, because "already declared" is the claim that would
silently stop being true.
Enumeration method, and its counter-probe
The card's reproduce command is a regex over
(schema as X).KEY. That is blindby construction to
(schema as any)['foo'], to a destructure off anany-typedlocal, and to a cast spanning lines — three spellings of one defect with no
shared pattern. So the read set was re-derived with an AST walk instead: an
expression counts as schema-rooted after stripping parenthesis /
as/satisfies/ non-null wrappers, with local aliases chased to a fixed point;property access, string-literal element access, and object-binding patterns are
all collected.
Result on merge-base: 47 distinct top-level keys read off
schema, of which11 are cast reads — precisely the card's eleven.
Counter-probe (the method must find keys that are legitimately declared, or it
is blind): it finds
objectName,viewMode,startDateField,endDateField,titleField,dependencyField,progressField— the seven already onObjectGanttSchema— andlabel, already onBaseSchema. After the change thesame walk reports zero cast reads and the same 47 keys.
The other 36 keys are read bare through the index signature rather than through a
cast; that is a different mechanism and out of this card's fence, filed as #6051.
Reverse verification — the signal this card exists to create
Directions were predicted before running. Both mutations were proved on disk in
both directions (removed text → 0, surviving anchor → 1), run under
trap … EXIT INT TERM, andgit diff HEAD --statis empty afterwards.Ablation A — restore
ObjectGanttSchema's TS declaration to its pre-card state.packages/typestests import source-relative, butplugin-ganttresolves@object-ui/typesthroughexports→dist, so the types package was rebuiltbetween mutation and reading, and the mutation was confirmed to have reached
dist/objectql.d.ts(skipWeekendscount 1 → 0).@object-ui/types type-check. Measured: exit2,ten
error TS2578: Unused '@ts-expect-error' directive.— one per declaredkey, at the ten pinned lines. Mechanism: with the declaration gone each member
resolves to
anythrough the index signature, the wrong-typed assignmentstarts succeeding, and the directive becomes unused. Each directive names its
key, so the failure is self-describing.
@object-ui/plugin-gantt type-check, and stated as anon-signal up front. Measured: exit
0. Under the index signature a readsite can never be the detector —
schema.readOnlytype-checks asanyeitherway. This is why the pin lives in
packages/types, compiled bytsconfig.test.json, and not at the read site.Ablation B — restore only the zod mirror, TS declaration intact. This tests
the dispatch's mechanism assumption 3 ("declaring on the TS side alone will turn
zod-mirror-parityred").5 passed, exit0. Its compile-time half (theLedgerMismatchassignment,which runs under
tsc -p tsconfig.test.json, not vitest): exit0. Both greenwith the mirror missing all ten keys.
NarrowerThanDeclaredmaps over the intersection of the mirror's mirrored keyswith
keyofthe declaration, so a key present in the declaration but absentfrom the mirror's
.shapedrops out of the comparison entirely. The ratchetdetects a mirror that is narrower on a shared key; it cannot detect a mirror
that is missing one. The reverse direction is blind too, and for a second
reason:
ObjectGanttSchema's declaration carriesBaseSchema's indexsignature, so
keyofit isstring | numberand every indexed lookup resolvesto
any, which is assignable to anything the mirror could say.KnownDriftentry was ever on the table — the ledger isunchanged, still 17 entries on this merge-base (the "13" figure describes the
post-fix(types): widen seven zod mirrors the renderer already implements (#5927 group A) #6032 state, which has not landed). The new pin caught the missing mirror
instead:
2 failed | 7 passed, exit1.Counter-probe on enforcement — measured, not assumed, exactly as the dispatch
asked.
BaseSchemais.passthrough()with an index signature (#5155'sstructural ceiling), so the two halves differ and the test pins both:
readOnly: 'yes'is refused, where itparsed green before. That is the accept-set narrowing this card lands, the same
one plugin-gantt: schema 上的 viewMode 只被 ResourceWorkload 分支读,时间轴静默忽略 —— 且该键在 ObjectGanttSchema 与 spec 的 GanttConfigSchema 都未声明 #5074 landed for
viewMode;{ readonly: true, skipWeekend: true }parses green. Declaring these ten did not buy rejection of a misspelling.
Anyone reading this card as "misspellings now fail" is reading it wrong, and
the test says so in the one place that cannot rot.
Both halves also have positive counter-probes so neither can pass vacuously: a
well-typed value is accepted on every key (runtime), and the correctly-typed
literal assigns on every key (compile time) — without which a declaration
narrowed to
neverwould satisfy all ten directives.Gates — by name, with exit codes
Exit codes captured before any pipe. Every reading below is from
fb876485d.pnpm --filter @object-ui/types type-check(runstsc --noEmit, then the examples and test projects)0pnpm --filter @object-ui/plugin-gantt type-check(runstsc --noEmit, then the test project)0pnpm exec vitest run packages/types/src packages/plugin-gantt/src(root form)0— 101 files, 1006 tests passedpnpm --filter '...@object-ui/types' build(downstream)0— 91 packagespnpm --filter '...@object-ui/types' type-check(downstream)0— 42 packageseslint .inpackages/types0— 0 errors, 244 warnings (all pre-existingno-explicit-any)eslint .inpackages/plugin-gantt0— 0 errors, 251 warningscheck:control-bytes0check:spec-symbols0check:doc-types0check:self-import,check:phantom-deps,lint:coverage0check-changeset-presence,check-changeset-no-major0regenerate-known-schema-types --check0The script name is echoed in each
type-checklog, so a zero-match silent passcannot read as green. The prefix form
'...@object-ui/types'is thedownstream consumer direction — the correct one for a contract tightening.
@object-ui/react-runtimewas built separately first; it is not in the prefixclosure but
packages/componentsneeds itsdist. Per the dispatch that is aknown local gotcha, not a finding.
Serial constraints
packages/typeswas taken after #5927's PR #6032 was confirmed not mergedinto
origin/main(checked by commit-log scan at branch time). The predictedconflict on
zod-mirror-parity.test.tsdoes not arise: that file is not inthis diff at all — declaring on both sides at constant requiredness leaves the
ratchet at zero drift for this pair, so there was nothing to edit there. No
sibling-claimed file was touched:
packages/test-supportand the parity testfiles (#5872),
RecordDetailView.tsx(#5835),form.tsx(#6010) andplugin-detail/src/renderers/__tests__/(#5808) are all untouched.Out-of-scope findings (filed, not fixed here)
navigationexample showsbasePath, which no read site consumes and the spec's NavigationConfigSchema refuses #6050 — the plugin-gantt README'snavigationexample showsbasePath,which nothing in the repo reads and which the spec's
NavigationConfigSchemaactively rejects. Found because the new pin test used that README snippet
verbatim as its well-typed fixture and it failed with
unrecognized_keys. Theone place this PR touches is its own new doc comment, which had been drafted
from that README line — the phantom is removed there and the absence recorded.
getGanttConfigreads 24 more top-level keys ObjectGanttSchema does not declare — same defect as #5903, hidden by the index signature instead of a cast #6051 (finding) —getGanttConfigreads 24 further top-level keys thatneither schema declares, invisible through the index signature rather than a
cast. Same defect class, different mechanism; whether the flat spelling is a
sanctioned second authoring form for
GanttConfigis a ruling.labellocale map to "[object Object]" —BaseSchema.labelisstring | I18nLabel#6052 —String(schema.label)stringifies anI18nLabellocale map to[object Object]in the export filename. Pre-existing; this PR is deliberatelybehaviour-preserving there, but dropping the cast makes the union visible at
the call site for the first time.
⛔ Class card #4631 is not reopened — triage said doing this per-package
specimen does not reopen the class, and nothing here widens past
ObjectGantt.⛔ Draft on purpose: the PM lands this. Not marked ready, not enqueued, no
auto-merge.
Generated by Claude Code