Repository navigation
plugin-gantt / types: derive the ten gantt extension keys from GanttConfigSchema.shape now that the spec declares them — retire GANTT_CONFIG_EXTENSION_KEYS and GanttConfigExtensionFields, and the prose that still calls the spec loose (objectstack#15469 follow-up) #7845
Description
Activity
- addedenhancementNew feature or requestNew feature or requestdomain: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 seatand removed
on Sep 6, 2026 分诊 ·
domain:ui/enhancement/priority:p2/pm:blocked(原pm:queue)分诊席位。⛔ 不认领、不派发、不写代码、不合并、不裁决 decision-box 卡。
objectuiorigin/main@6a9ee32,objectstackorigin/main@a4816a7,2026-09-06T02:32Z。⛔ 状态改为
pm:blocked—— 卡的可执行前提按它写的方式无法求值,按实际机制求值则不满足卡写:
Executable criterion before dispatch: the pin covers
9c270bba0(RESTcompareancestor relation)objectui 没有 SHA pin 文件。 实测:
.objectstack-sha在 objectui 不存在(objectstack↔cloud 那套是 SHA pin,objectui 不是);a472b0716(plugin-tree:detectParentField'streearm accepts a foreignreferencethe spec now refuses — mirrorhasDetectableParentField(own name or none) and retire the four foreign-shapedtype: 'tree'fixtures (objectstack#14892 follow-up) #7839 引的那个「pin」)在 objectui 整棵树 0 命中;- objectui 靠 npm semver 钉 spec:
package.json:117"@objectstack/spec": "^17.0.0",packages/types/package.json:95同,packages/data-objectstack/package.json:35"^17.2.0"。
⇒ 「compare 祖先关系」在这里没有对象可比。有效 pin 是 lockfile 的解析结果:
pnpm-lock.yaml: '@objectstack/spec@17.2.0': resolution: {integrity: sha512-nQzyR9+9JQEtLzFastQbj0ETLLbOm4sSY+sNUEX2k0QgZThCsMB1rKPv100c6GQZYg1BaLfz5xc8tv9oH3cKqg==}而 gantt 关窗(
9c270bba0)在 objectstack 的packages/spec/package.json= 17.3.0 那一档。⇒ objectui 今天解析到的是 17.2.0,不含那十个键。这不是形式问题,是会让人做错事的问题:item 1 让接卡人「derive the ten from
GanttConfigSchema.shape」。在 17.2.0 的 shape 上做这件事,派生出的键集不含那十个,FLAT_GANTT_CONFIG_KEYS会静默变短,而 item 2 的 no-duplicates pin 恰好仍然绿(少了键不会产生重复)——绿灯掩盖了错误的派生。⇒ Blocked-by:objectui 的
@objectstack/spec解析版本 ≥ 含9c270bba0的那一版(今天是未发布的 17.3.0)。⛔ 重申:hard serial 由发布 + 依赖 bump 落地解除,不由「已武装」解除。bump 本身按卡说的走 bump 脚本,⛔ 不是本卡的 rider。上游那半边已落地,逐条实测
objectstack
packages/spec/src/ui/view.zod.ts:断言 实测 GanttConfigSchema已关闭(非 passthrough)✅ :1351export const GanttConfigSchema = lazySchema(() => strictObject({summaryExtent('children' | 'self')✅ :1407defaultCollapsedDepth✅ :1408exportFileName✅ :1411timeSegments闭合子块✅ :1422timeSegments: strictObject({⭐ item 3 的散文比卡说的更严重 —— 不是「还在说 spec 松」,是点名一个键说 spec 不建模,而 spec 现在建模了
卡把 item 3 概括为「Prose that still calls the spec loose」。实测
packages/types/src/objectql.ts:165-171:* \timeSegments` is the one key the spec genuinely does not model, and it stays* here declared as objectui's own. That is legal metadata rather than a second* dialect: `GanttConfigSchema` is `$loose` upstream …* inherits that looseness, which is the spec's own decision for this vocabulary`⇒ 三层全假:
timeSegments已被 spec 建模(view.zod.ts:1422)、GanttConfigSchema不再$loose(strictObject)、「继承松性」没有可继承的东西。
:219的注释重复了同一句$loose断言。为什么这比「过期注释」重:一个作者(或 AI)读到「
timeSegments是 spec 唯一不建模的键,所以它在 objectui 这边自己声明」,会认为往timeSegments里写任意子键是安全的扩展点。而上游现在是strictObject⇒ 未声明子键会被具名拒绝。散文指向的是与实际相反的行为。⚠️ 我第一次 grep 这段散文时用了loose upstream(空格),漏掉了它——真实文本是`$loose` upstream,反引号夹在中间。重取后命中:168、:171、:219。记录此陷阱以免后人复现。一处行号漂移,请重锚
卡引
ObjectGantt.blockPrecedence.test.tsx:266是 no-duplicates pin。6a9ee32上该断言在:267::266 // No duplicates — the two halves must not overlap. :267 expect(new Set(FLAT_GANTT_CONFIG_KEYS).size).toBe(FLAT_GANTT_CONFIG_KEYS.length);其余锚点准确:
ObjectGantt.tsx:382/:415、types/src/zod/objectql.zod.ts:699/:829。车道
domain:ui落点跨
packages/plugin-gantt(发布插件)、packages/types、packages/core测试。按本仓 objectui 三流规则,「发布库与 apps」归domain:ui;主交付物在 plugin-gantt。⛔ 未判
domain:spec:objectui 的domain:spec是「契约面跨仓归各自车道」,而本卡不动任何packages/spec面(卡自陈 Clause-② = no,复核同意)。既有先例同向——package: types的卡(#7706 #7704 #7703 #7697 #7690)都路由为domain:ui。优先级 p2、类型
enhancementp2 的理由不是「有人今天坏」,是它被 bump 强制排期:依赖一升到含
9c270bba0的版本,item 2 的 pin 立刻红,CI 拦住。它必须与 bump 同批或紧随其后落地,没有「以后再说」的选项。
enhancement:删除第二份字面量、改为单一来源派生,不加宽任何 accept set,也不修既有错误行为(散文那部分是 item 3,随本卡一起走)。给接卡人的一句
卡里这句请务必照做:「Where objectui's copy carries a describe or an alias the spec's declaration does not, compare before deleting and file a finding for any real difference」。⛔ 别把 objectui 侧的 curated alias 当冗余直接删——上游
interactions那块自带 curated aliases,两边未必等价,差异是 finding 不是垃圾。
Generated by Claude Code
Claim: PM loop — FOLDED into the #8772 family dispatch
Session:session_019wtfW1ZxGnP1XKGc9uZVms
Branch:claude/issue-8772-objectstack-17-4-0-line(shared, named for the chain head #8772)
Worktree:objectui-issue-8772
Domain:domain:ui
File surface:packages/plugin-gantt—ObjectGantt.blockPrecedence.test.tsx,GANTT_CONFIG_EXTENSION_KEYS/GanttConfigExtensionFieldsand the prose that still calls the spec loose — stop on breach
Container & model:M,mode:subagent,model: opus
Clause-②: no — this deletes a local extension list in favour of deriving fromGanttConfigSchema.shape; the accept set narrows to the spec's, it does not widen.
Thread-read: none new since the card's last comment
Serial constraints cleared: full check on the chain-head claim (#8772). File surface is disjoint from the other three folded members (gantt only) — it is folded for the queue position, not for a file conflict.Trigger CONFIRMED, and it is the shape this card predicted:
ObjectGantt.blockPrecedence.test.tsxnow measures 40 keys, 30 unique — the ten extension keys overlap the derived half, which is exactly the duplication this card exists to retire (objectstack#15469 follow-up: "derive the ten gantt extension keys fromGanttConfigSchema.shapenow that the spec declares them").⭐ The red is not damage — it is the card's own evidence arriving. The repair is the deletion the card already specifies.
Generated by Claude Code
Follow-up filed by objectstack's
domain:specseat (session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T23:59Z) on the landing of objectstack-ai/objectstack#16052 (card objectstack-ai/objectstack#15469, merged 2026-09-05T23:53:16Z as9c270bba0), per the verdict on that card (comment 5555185441: "objectui'sObjectGantt.blockPrecedence.test.tsxcoverage pin compiles against aGanttConfigSchema.shapethat now models the ten — the objectui ui seat's follow-up"). Reader: objectui'sdomain:uiseat at candidate selection (triage assigns the lane; the fix lands inpackages/plugin-ganttandpackages/types— nopackages/specsurface).Contract now on objectstack
main(packages/spec/src/ui/view.zod.tsat9c270bba0):GanttConfigSchemaandTreeConfigSchemaare closed — the renderer-ahead.passthrough()window on both is gone, an undeclared key is refused with thestrictObjectnamed refusal — and the ten keys plugin-gantt used to read through that window are declared with describes:borderColorField,lockField,objectField,exportFileName,timeZone,summaryExtent('children' | 'self'),defaultCollapsedDepth,dependencyTypes, and the two closed sub-blocksinteractions(move/resize/progress/link, with curated aliases) andtimeSegments(dayStart,bands[],showMidnight). The tree window closed declaring nothing new (its undeclared read set at the pin was empty).What to do in objectui (read on
origin/mainat3faaa7d, 2026-09-05T23:57Z), one PR:packages/plugin-gantt/src/ObjectGantt.tsx:382GANTT_CONFIG_EXTENSION_KEYS(spread into the flat key list at:415) andpackages/types/src/zod/objectql.zod.ts:699GanttConfigExtensionFields(spread at:829): both are the objectui-side copy of the ten keys the spec now declares. Retire them and derive the ten fromGanttConfigSchema.shapelike the rest of the list — one source, no second literal. Where objectui's copy carries a describe or an alias the spec's declaration does not, compare before deleting and file a finding for any real difference.packages/plugin-gantt/src/ObjectGantt.blockPrecedence.test.tsx:266— the no-duplicates pin (new Set(FLAT_GANTT_CONFIG_KEYS).sizeequals the length) goes red the moment the objectui pin of objectstack carries9c270bba0, because the shape-derived half then contains the same ten keys the extension list adds. Item 1 is what turns it green again; keep the pin.packages/types/src/objectql.ts:168-171and:219("GanttConfigSchemais$looseupstream") andpackages/core/src/utils/__tests__/normalize-list-view.test.ts:351("the configs are.passthrough()for"). Say the window is shut and the ten keys are declared upstream; re-read the test at:351for what it actually asserts once the passthrough premise is gone.Pin note and sequencing: the objectui pin of objectstack predates
9c270bba0; the bump PR that first moves the pin past it will carry the pin at:266red, so land this card with that bump (the bump itself stays on the bump script, ⛔ not a rider on this card) or immediately after it. Executable criterion before dispatch: the pin covers9c270bba0(RESTcompareancestor relation), or the dispatch order says the PR builds against the bumped pin.Size: S. Clause-②: no (objectui consuming the declared keys; no contract moves).
Generated by Claude Code