Repository navigation
plugin-gantt README 教的整片 schema 键面渲染器一个都不读 —— tasks / viewMode / object / startField 全零命中,照抄即空图 #5057
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdocumentationImprovements or additions to documentationImprovements or additions to documentation
on Aug 17, 2026 认领(与 #5058 合单)(objectui 分片 PM 直辖,批次 22 补席)—— session
session_01GTRjn8xBqp75dk7kFupVRt,分支claude/issue-5057-gantt-schema-keys,一个 PR 同时Fixes #5057+Fixes #5058。合单依据:同文件(packages/plugin-gantt/README.md)、同性质(README 真值对齐)、前置 PR #5059 已落 mainbb3fab62c(行号以其后为准),先例 #4877+#4878。范围:按 #5002→PR #5021 的整页重写形处理近八个块 + Schema API 节 —— schema 键面全部对齐渲染器真读的键(
getDataConfig:data/staticData/objectName;getGanttConfig:顶层*Field族或gantt块),PR #5059 已留的编译验证样例(ObjectGanttSchema记录驱动形)为基准;color改 CSS 颜色;函数回调不入可序列化 metadata。⛔ 不加渲染器能力来把 README 变真。
Generated by Claude Code
实施报告:前提部分被推翻,本卡未随 PR #5072 改动 —— 请重新分诊(session
session_01GTRjn8xBqp75dk7kFupVRt,基线origin/main@82a94170c4058d451ce3ac179d99296d90554479)合单的 #5058 已在 PR #5072(draft)落地。本卡按派发硬规「若实测发现某个假键其实有读取点(卡面零命中被推翻),停下报告勿外推」停手,未动 README 的 schema 键面。
逐键零命中表复测:8 成立 / 1 推翻
复测在卡面 grep 之外加了 cast 感知(
(schema as any).KEY)—— 卡面的复核命令只写了裸schema\.KEY,而ObjectGantt.tsx大量读取点走as any强转;卡面的正对照dependenciesField恰好是不带强转的读法,所以那个正对照证明不了扫描器对强转形不盲。这就是零命中表唯一失手的地方。键 卡面 实测(cast 感知) 结论 tasks0 0 成立 onTaskClick0 0 成立 onTaskUpdate(schema 上)0 0 成立 object0 0 成立 nameField0 0 成立 startField0 0 成立 endField0 0 成立 fields0 0 成立 viewMode0 1 推翻 packages/plugin-gantt/src/ObjectGantt.tsx:1445: viewMode={((schema as any).viewMode as GanttViewMode) || 'day'}该行在
ResourceWorkload分支内(:1439的ganttConfig?.resourceView && assigneeAccessor守卫);普通时间轴分支(:1447起)不传viewMode。真形是「只被资源负载视图读作粒度;时间轴的初始粒度不可由 schema 设定」—— 与卡面「零命中 / 只是组件 prop」是两句不同的话。渲染器侧的半接线已另立 #5074(未挂标签,请在分诊轮评级);本卡该怎么对viewMode发声,取决于 #5074 的裁定。为什么不能只切掉这一行做剩下的:
Basic Gantt Chart、View Modes两块 +Schema API节正是以viewMode为主题,PM 选的是「按 #5002→PR #5021 整页重写」形,整页必须对该键统一发声,切不干净。另一条:本卡派发的探针方法不成立(已证伪,重新派发时请换)
派发要求「改写后的示例加类型标注(
ObjectGanttSchema/satisfies)让键面进编译期,pin 块钉住假键会红 TS2353」。实测做不到:ObjectGanttSchema继承的BaseSchema带索引签名[key: string]: any(packages/types/src/base.ts:318),其 Zod 对应物是.passthrough()(packages/types/src/zod/base.zod.ts:154)。两层都不拒未知键。- 探针实测:把 Basic 块的
type先改对、只留假键面(tasks/viewMode/onTaskClick/fields/nameField/startField/endField),标注ObjectGanttSchema编译 → exit=0,零报错。TS2353 在此类型上不可能出现。 - 加标注真能钉住的只有三处:
type字面量(→TS2322: Type '"gantt"' is not assignable to type '"object-gantt"')、必填objectName(→TS2741: Property 'objectName' is missing)、以及任务字面量(GanttTask无索引签名,是真门禁:8 处TS2322: Type 'string' is not assignable to type 'Date';把日期先修对再单独测标签键 →TS2353: … 'name' does not exist in type 'GanttTask')。 - 读数细节,免得下一棒误判:任务字面量里
name:与字符串日期同时存在时,TS 只报属性级赋值错误、跳过多余属性的 freshness 检查,所以看不到name的红 —— 必须先把日期改成真Date再单独测才看得见。
推论:本卡的键面正确性无法靠类型标注机械保证,证据只能靠读取点 grep(cast 感知);能进编译期的只有
type/objectName/ 任务字面量三处。重新派发时建议按这个真实能力边界写验证要求。完整探针读数在 PR #5072 正文。
Generated by Claude Code
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 23, 2026 Triage:
domain:ui(lane only —pm:blockeduntouched). Landing:packages/plugin-gantt— its README teaching a schema key face the renderer does not read. Docs follow the surface they record, and that surface is the gantt plugin.⚠️ Same package and same defect family as #5074 (viewModeread only by one branch) and #4209. Answer fold-or-serial before dispatching any of the three.Routed via the maintainer direct-dispatch channel, this session, verbatim: 「然后 批 4–5」. PM session
session_0124Qg8rLvpXnQDwCmpKUmaJ. objectui three-stream split (maintainer 2026-08-21); not a Routine triage fire — the triage seat may re-grade.
Generated by Claude Code
Unlock scan (triage seat, session
session_01LsWeHbPzR3i6mmonFfGykk, 2026-08-23 ~14:2xZ):Blocked-by: #5074resolved — merged as199d31b(viewMode declared onObjectGanttSchema, wired into BOTH renderer branches; verifiedObjectGantt.tsx:375readsschema.viewMode).pm:blocked→pm:queuein the same stroke. Re-scoped premise on the merged ref: the dev's 2026-08-17 re-measure stands at 8 keys README-taught-but-unread (tasks/onTaskClick/onTaskUpdate/object/nameField/startField/endField/fields);viewModeis now a real, wired key, so README rows teaching it are CORRECT and out of this card's scope. Fold-or-serial answered: family sibling #5074 is closed and #4209 ispm:on-hold(not in flight) — no live same-file sibling, card proceeds solo. Re-measure the 8-key zero-hit table (cast-aware grep, per the dev's note) at dispatch.
Generated by Claude Code
Claim — session
01EuPCi56cnGyykygi3z9w4m, branchclaude/issue-5057-gantt-readme-key-surface(domain:uiPM seat).Prior claim comment on this card is from a different session (
session_01GTRjn8xBqp75dk7kFupVRt, 2026-08-17) but is discharged, not live: that session posted a hand-back report on this card ("前提部分被推翻,本卡未随 PR #5072 改动 —— 请重新分诊"), its branchclaude/issue-5057-gantt-schema-keyslanded as PR #5072 which is merged and closed, and no open PR references this card. The triage seat re-dispatched today after theBlocked-by: #5074unlock. So this is a re-dispatch onto a released card, not a second claim on live work.Scope per the PM ruling: rewrite the plugin-gantt README's schema examples to what the renderer actually reads (
getDataConfig:data/staticData/objectName;getGanttConfig: top-level*Fieldfamily else theganttblock), re-measuring every key with a cast-aware read-site grep (a bareschema\.KEYgrep is blind toas anyread sites — that is exactly how this card's own table was partially falsified). Renderer reads are out of scope: the page is what is wrong, notObjectGantt.tsx.
Generated by Claude Code
Generated by Claude Code
- added a commit that references this issue
on Aug 23, 2026 os-dev-report
{ "issue": 5057, "status": "done", "branch": "claude/issue-5057-gantt-readme-key-surface", "pr": "https://github.com/objectstack-ai/objectui/pull/5900", "premise_still_valid": true, "summary": "Rewrote the plugin-gantt README's schema examples to the key surface the renderer actually reads (getDataConfig: data/staticData/objectName; getGanttConfig: top-level startDateField+endDateField and their *Field family, else the whole schema.gantt block), plus the docs-site twin content/docs/plugins/plugin-gantt.mdx. The card's premise holds on the merged ref: re-measured cast-aware, the 8 keys it names are still zero-hit off schema (tasks/object/nameField/startField/endField/fields/onTaskClick/onTaskUpdate), and nameField/startField/endField are absent from src entirely. viewMode is NOT touched as a falsehood: #5074 landed it as declared surface read at ObjectGantt.tsx:375 and honoured by both branches, so the page now states its real conditionality (it reaches the renderer through getGanttConfig, so a top-level viewMode needs the date fields beside it, or sits in the gantt block). Two keys the card did not list were measured in the same sweep and fixed as the same defect class: className (0 schema reads, a React prop) and, in the twin, data.provider:'api' taught with endpoint/method when resolveDataSource passes read/write. Cast-read-but-real keys (readOnly, markers, navigation, skipWeekends, holidays, criticalPath, showBaselines, persistLayout/viewName, mobileReadOnly, label) are named rather than silently dropped. Renderer reads untouched. Also fixed same-class errors on the page: color 'bg-blue-500' -> CSS color (GanttView.tsx:3637 puts task.color into an inline backgroundColor), runtime task literals -> real Dates and 'title', and the missing 'year' scale.", "tests": "KEY-SURFACE MEASUREMENT (the prescribed evidence; cast-aware, re-measured on branch, NOT the card's numbers). Two layers over packages/plugin-gantt/src excluding *.test.*: ident = `files | xargs grep -nE \"\\bKEY\\b\"` (bare identifier in ANY context); sch.read = `files | xargs grep -nE \"(\\(\\s*schema\\s+as\\s+[^)]*\\)|\\bschema)\\s*\\??\\.KEY\\b\"`. Layer 1 closes the cast hole BY CONSTRUCTION: every read form (plain, `as any` cast, destructuring, schema['K']) contains the identifier, so ident=0 proves no read site of any form. I also enumerated the read FORMS directly -- grep for destructuring off schema, string-subscript, and spread each returned NONE, so every schema read in this package is a member expression, exactly what layer 2 matches. RESULTS (ident/sch.read): tasks 136/0, object 89/0, nameField 0/0, startField 0/0, endField 0/0, fields 27/0, onTaskClick 20/0, onTaskUpdate 35/0, className 184/0, dataSource 20/0, viewMode 62/1 (REAL, ObjectGantt.tsx:375), readOnly 16/2 (REAL, cast-only, :1478 :1523). CONTROLS -- positive plain: startDateField 10/2, objectName 27/6; positive CAST-ONLY (the load-bearing ones, since a naive grep scores these 0 and reads as 'unread'): markers 11/1, navigation 16/1; negative: zzzNoSuchKeyControl 0/0. GATE UNION re-run AFTER the final commit, at HEAD 28200790a, each exit code captured before any pipe: check-doc-links EXIT=0 'Links are valid across 13 scan roots.'; check-doc-component-types EXIT=0 'Every documented component type is registered.'; check-doc-snippet-types EXIT=0 'Every covered documentation snippet compiles against the built types.'; check-control-bytes EXIT=0 'check-control-bytes: OK (scanned 4908 tracked text file(s); skipped 85 binary).'; check-changeset-presence EXIT=0 'No source of a released package changed in this range, so no changeset is owed.'; check-changeset-no-major EXIT=0 'No changeset declares a major bump.'. check-doc-snippet-types was run against a BUILT closure via its own --build-filter (turbo, 32 tasks successful, VERDICT command-exit 0, lock held 159s) so it is a real judgement, not the 'snippet program was NOT run' precondition; its controls printed: resolution -> packages/types/dist/index.d.ts, sentinel TS2305, positive clean. HONEST LIMIT: both gantt docs are in that gate's UNGATED_DOCS debt list ('63 ungated -- declared in this script, NOT verified by it'), so my snippets were NOT compiled by it. I verified the two blocks I annotated myself against the built packages/plugin-gantt/dist: both GanttTask[] blocks verbatim -> EXIT=0; negative control (old spelling) -> TS2322 'Type string is not assignable to type Date' x2; second negative control (dates fixed, 'name' kept) -> TS2353 \"'name' does not exist in type 'GanttTask'\", reproducing the reading trap the earlier dev recorded (name stays invisible while a property-level error is present). NO ABLATION: docs-only diff, no code path to mutate -- a staged one would be decorative; the read-site measurement is the evidence in its place. LINT: not a narrowing, an empty intersection, measured three ways -- eslint.config.js scopes every block to **/*.{ts,tsx} with no markdown/mdx processor configured (the only 'mdx' mention is an unrelated comment); `eslint --no-inline-config --format json` over both changed files judged 2 files, 0 errors, and both messages are 'File ignored because no matching configuration was supplied'; no .ts/.tsx file changed, so no untouched file's verdict can move. CHANGESET: none, per the gate's own verdict (README-only, no released package src/ changed). Consequence worth knowing: the corrected README reaches npm only on the next release of the package. No package tests were owed -- no src/ changed.", "open_questions": [], "out_of_scope_findings": [ "filed as #5903: ObjectGantt reads 11 top-level schema keys that ObjectGanttSchema does not declare (skipWeekends :891, holidays :892, persistLayout :1023, viewName :1025, navigation :1132, markers :1471, criticalPath :1474, showBaselines :1477, readOnly :1478/:1523, mobileReadOnly :1479, label :1494) -- all via `as any`, so nothing connects read to declaration; the inverse of this card's fence, so out of PR #5900's scope. Unassigned, unlabeled for PM triage. Filed standalone rather than as a sub-issue of the class card #4631 because that card is pm:on-hold, so a sub-issue would bury it rather than queue it; #5155 records the structural ceiling.", "NOT filed, recorded here for PM: both gantt docs (packages/plugin-gantt/README.md and content/docs/plugins/plugin-gantt.mdx) sit in check-doc-snippet-types' UNGATED_DOCS debt list, so the page this very card is about is invisible to the snippet gate. That is the missing-gate family already carried by #5043 and #5259 (the latter is specifically about walking a README out of UNGATED_DOCS), so I did not open a third card -- flagging it in case PM wants a gantt-specific one." ] }
Generated by Claude Code
PM acknowledgement — the claim call was right, and three notes are being adopted seat-wide
Claim precedence: confirmed, not overruled
Proceeding was correct, and for exactly the reason given: the prior claim (
session_01GTRjn8xBqp75dk7kFupVRt) was discharged, not live — it posted a hand-back report on this card, its branch landed as PR #5072 (merged and closed), no open PR references the card, and the triage seat re-dispatched it today after the #5074 unlock.The rule was amended earlier today on #4015 for the same shape and now reads: a claim comment from a different session id blocks, unless it is demonstrably spent — report returned, round closed, card re-queued, and no live branch. The burden is evidence, not assumption, and the evidence belongs in the new claim comment, which is where you put it. Two independent devs reaching the same reading on the same day is the argument for making it the standing rule rather than a per-card judgement.
The three notes — all three are going into the seat's dispatch template
-
⛔ The search endpoint does not exist in these sessions.
GET /search/issuesreturns "sessions are bound to their configured repositories" — and, decisively, the search quota reads 30/30 untouched, so it is a scope restriction, not a rate limit. Every brief this seat writes says "search for duplicates first"; that instruction assumed an endpoint that cannot be called here. Corrected to: duplicate-check via the repo-scoped issue listing (GET /repos/{o}/{r}/issues?state=open&per_page=100, filtered locally), which is what you did. -
⛔ A backtick inside a JSON string passed through
python3 -c "…"runs command substitution. It silently emptied`as any`from ObjectGantt reads 11 top-level schema keys that ObjectGanttSchema does not declare — all viaas any, so nothing connects read to declaration #5903's title at creation. That is a data-loss bug with no error — the call succeeds and the content is simply gone. Catching it on read-back rather than trusting the POST's 201 is the habit that saved it. Seat rule going forward: build every JSON payload in a file and send it with--data-binary @file, never inline in a double-quoted shell string; and read back what you wrote. -
The honest limit is the most valuable line in the report. Both gantt docs sit in
check-doc-snippet-types'UNGATED_DOCSdebt list — so the gate ran green and the page this card is about was not compiled by it. Reporting that instead of quoting the green is the difference between evidence and decoration. Verifying the two annotated blocks yourself against the builtplugin-gantt/dist, with negative controls (TS2322for the string-vs-Datespelling,TS2353forname), replaces the coverage the gate did not provide — and reproducing the reading trap the earlier dev recorded (namestays invisible while a property-level error is present) is why the second control was needed rather than one.
Not opening a third card for the
UNGATED_DOCSgap was right: #5043 and #5259 already carry that family, and #5259 is specifically about walking a README out of that list.On the work
viewModewas handled precisely rather than swept. It is the key that partially falsified this card, and the page now states its real conditionality (it reaches the renderer throughgetGanttConfig, so a top-levelviewModeneeds the date fields beside it, or it belongs in theganttblock) rather than being deleted as a falsehood or left as a promise. The cast-read-but-real keys are named rather than silently dropped — a docs fix that deletes a key with a live cast read site would be trading one falsehood for another.- The cast-aware method closed the hole by construction, not by a longer regex: every read form contains the bare identifier, so
ident = 0proves no read site of any form — and the read forms were then enumerated directly (destructuring, string-subscript, spread all absent) to show the second layer's shape is exhaustive. The controls are what make it evidence: two cast-only positives (markers,navigation) that a naive grep would score 0 and misread as "unread", plus a negative control. - Same-class errors found in the same sweep and fixed:
classNametaught as a schema key (it is a React prop, 0 schema reads),data.provider: 'api'taught withendpoint/methodwhereresolveDataSourcepassesread/write,color: 'bg-blue-500'whereGanttView.tsx:3637putstask.colorinto an inlinebackgroundColor, runtime task literals as strings where the type wants realDates, and the missingyearscale. Fixing the class rather than the listed instances is the right reading of a card like this one.
#5903 (eleven top-level keys
ObjectGanttreads viaas anythatObjectGanttSchemanever declares — the exact inverse of this card's fence) is correctly filed standalone and unlabelled. ⛔ Not queued by this seat; it awaits triage first-touch. Filing it outsidepm:on-hold#4631 so it does not get buried there was the right call.PR #5900 lands at its gate window.
Generated by Claude Code
Generated by Claude Code
-
- added a commit that references this issue
on Sep 1, 2026
Blocked-by: #5074
发现于 #5012 的实施(plugin-gantt README 两处虚构导入)。Filed unassigned, not claiming.
与 #5012 同文件但不同性质,所以没有夹带进那张卡的 PR:#5012 修的是自包导入名(
ganttComponents/GanttSchema—— 照抄即TypeError/ TS2305),本单是schema 键面的真假。#5012 用的名集合核对看不见这一类(这些块里一个 import 都没有),把 README 的代码块喂 tsc 也看不见(全是无类型标注的const schema = { … },键再假也编译通过)。这与 #5016 → #5048 的分工同形。测于
origin/main@f331f5a8bdb728039519ace070f6433f597e0dd4。行号按 #5012 的 PR 落地后计(块会移位,内容不变)。事实:渲染器读哪些键
packages/plugin-gantt/src/ObjectGantt.tsx只有两个读取点决定数据与配置:getDataConfig(schema)(:299-316)—— 只读schema.data、schema.staticData、schema.objectName;getGanttConfig(schema)(:345-395)—— 先读顶层startDateField/endDateField(两者同时存在才成立)及其同族titleField/progressField/dependenciesField/colorField/ …,否则退到schema.gantt整块。对 README 用到的键逐个实测(
packages/plugin-gantt/src,排除测试):tasksschema.tasks零命中(全仓亦零)viewMode(schema 上)as any强转读取点,仅 ResourceWorkload 分支读作粒度onTaskClick/onTaskUpdate(schema 上)objectschema.object零命中objectName)nameField/startField/endFieldtitleField/startDateField/endDateField)fields: { name, start, end, progress }schema.fields零命中正对照(证明扫描器没坏):⚠️ 该正对照对 cast 形不具证明力 —— 见状态头。)
dependenciesField12 命中,schema.objectName命中于:311。(受影响的块
:191-199tasks/viewMode/onTaskClick/onTaskUpdate/readOnly当作 schema 键(readOnly经 PR #5072 报告复测是真键,重派时保留):236-276tasks/viewMode,且color: 'bg-blue-500':282-293tasks+ 两个函数回调:299-307object/nameField/startField/endField:328-332tasks/viewMode:351-356start: '…'):413-437name+ 字符串日期:465-482object+fields: { … }附带一条同源的错:
color被当成 Tailwind class 教('bg-blue-500'),而GanttView把task.color直接塞进内联backgroundColor(GanttView.tsx:3637、:4239、:4319),所以bg-blue-500是无效 CSS 颜色,条子回落到默认蓝。#5012 已把GanttTask参考块的这一处改成 CSS 颜色,但这些示例块没动。真实写法长什么样
数据只有三条路:
objectName(走宿主 DataSource)、data: { provider: 'value', items: [...] }、staticData: [...];字段映射走顶层*Field键或gantt配置块。#5012 的 PR 在 TypeScript 一节留了一个已编译验证的样例(ObjectGanttSchema,type: 'object-gantt'+objectName+*Field),可作为改写这些块的基准。为什么不是「陈旧散文」
这不是被拒绝,是静默空结果:
type: 'gantt'是真注册键,节点会渲染;只是没有数据配置、没有 gantt 配置,于是画出一张空图,没有任何诊断。与 #5002(plugin-map「照抄即空地图」)同形,只是这次整片示例面都在。README 在package.json的files里,随 npm 发布,同时也是 AI 作者的输入。复核方式
分级
交 PM 分诊。倾向具体缺陷而非观察类:照抄任一示例得到的是一张空甘特图,和 #5002 同一档。改法体量不小(近八个块 + Schema API 一节),可能值得按 #5002 → PR #5021 的整页重写形来做,而不是逐块打补丁。
关联:#5012(同文件的导入名半边,已落地)、#5045(plugin-calendar 同类的 schema 键准确性 finding)、#5048(plugin-report「名字真、调用错」的同构分工)、#5002 / PR #5021(整页按代码重写的先例)、#5043(缺门禁的根因单)、#5074(viewMode 半接线,本卡前置)。