Skip to content

ObjectGantt reads 11 top-level schema keys that ObjectGanttSchema does not declare — all via as any, so nothing connects read to declaration #5903

Description

@claude

Measured while rewriting the plugin-gantt README's schema key surface for #5057
(PR #5900). Filed unassigned, not claiming. Duplicate-searched against the open
issue list (the repo-scoped listing — this session cannot use the search API):
no open issue covers the gantt instance. #4631 is the CLASS card for
"three declared surfaces disagree" and is pm:on-hold; #5155 records the
structural ceiling (BaseSchema's index signature). This is the concrete,
per-package specimen, filed standalone so it is not buried under an on-hold
class card.

The fact

ObjectGantt reads eleven top-level schema keys that ObjectGanttSchema
does not declare. All eleven are read through an as any cast, which is what
lets them exist at all — the cast is load-bearing, not incidental.

Declared on ObjectGanttSchema (packages/types/src/objectql.ts:1951), 8 keys:

type objectName startDateField endDateField titleField
dependencyField progressField viewMode

Read off schema but NOT declared, 11 keys (packages/plugin-gantt/src/ObjectGantt.tsx):

KeyRead site
skipWeekends:891
holidays:892
persistLayout:1023
viewName:1025
navigation:1132
markers:1471
criticalPath:1474
showBaselines:1477
readOnly:1478, :1523
mobileReadOnly:1479
label:1494

Reproduce (cast-aware — a bare schema\.KEY grep scores every one of these 0
and reads as "unread", which is how #5057's own table was partially falsified):

find packages/plugin-gantt/src -name '*.ts' -o -name '*.tsx' \
| grep -v '\.test\.' \
| xargs grep -nE '\(\s*schema\s+as\s+[^)]*\)\s*\??\.[A-Za-z_]+'

Why it is worth a card

  1. These are real, working features that an author following the published
    type cannot discover.
    readOnly disables every edit path;
    markers draws reference lines; navigation picks drawer-vs-page;
    skipWeekends/holidays drive the work axis. None appear in
    ObjectGanttSchema, so neither a TS consumer nor the designer's registry
    inputs (which declare only objectName + gantt,
    packages/plugin-gantt/src/index.tsx:106-119) can offer them.

  2. It is the shape plugin-gantt: schema 上的 viewMode 只被 ResourceWorkload 分支读,时间轴静默忽略 —— 且该键在 ObjectGanttSchema 与 spec 的 GanttConfigSchema 都未声明 #5074 already ruled on, times eleven.plugin-gantt: schema 上的 viewMode 只被 ResourceWorkload 分支读,时间轴静默忽略 —— 且该键在 ObjectGanttSchema 与 spec 的 GanttConfigSchema 都未声明 #5074 took exactly
    one such key — viewMode, then read only through a cast in one branch — and
    resolved it by declaring it on ObjectGanttSchema derived from the spec's
    GanttConfigSchema member, then wiring both branches. That ruling gives the
    precedent and the mechanism; these eleven have had neither applied.

  3. The cast is what hides it. Because the read is (schema as any).K,
    nothing — not tsc, not the registry meta, not any gate — connects the read
    to a declaration. Per finding(types): BaseSchema's [key: string]: any leaves every component schema open, so a "declare the surface" fix can never reject a misspelled TOP-LEVEL key #5155 the index signature means declaring them still
    would not reject a misspelling, but declaring them does fix discovery,
    designer inputs, and the published type, which is the half that is
    achievable today.

Not in scope of #5057 / PR #5900

That card is docs-only and explicitly fenced: "If you find a key the renderer
should read, file it, do not implement it." This is the inverse — keys the
renderer does read that the type does not declare — so it is equally out of
that PR's fence. PR #5900 names all eleven in the README prose (as
cast-read-but-real) so readers are not left guessing meanwhile; that is a
documentation mitigation, not a fix.

Suggested resolution (for triage, not a decision)

Per key, the #5074 route or ADR-0049 enforce-or-remove: declare it on
ObjectGanttSchema (deriving from the spec's GanttConfigSchema member where
one exists, so the member list cannot drift) and drop the cast; or retire the
read if the key is not wanted. readOnly and markers are already documented
platform behaviour and look like clear declares.


Generated by Claude Code


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions