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
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
The day the spec types any of them properly, IsAny<…> flips to false, true satisfies false stops compiling, and the failure is the instruction: re-run the triage and burn that symbol down.
src/app.ts(273,7): error TS2353: Object literal may only specify known properties, and 'label'
does not exist in type '{ type: "separator"; id?: string | undefined; order?: number | undefined; }'.
src/app.ts(286,7): error TS2322: Type 'boolean | undefined' is not assignable to type
'string | { dialect: "cel" | "cron" | "template"; source?: ...; ast?: unknown; meta?: ... } | undefined'.
Type 'false' is not assignable to type 'string | { dialect: ... } | undefined'.
src/app.ts(301,7): error TS2322: (同上)
src/app.ts(313,5): error TS2322: (同上)
Deliberately NOT modelled: the spec expresses navigation as a discriminated union of nine variants … objectui keeps one flat, all-optional shape … Converging on the union is a breaking change for every consumer that reads fields off NavigationItem without narrowing — tracked separately, not smuggled in here.
any 的前提确实消失了,但**「flat vs union」和「三个 spec 没有的键」这两个障碍从来不是由 any 造成的**,pin 翻转并没有解决它们。
⚠️ Same key, different layer: in the SPEC form-view vocabulary field is a string … on a runtime FormField this slot is never a string, and its tripwire test pins that.
本地 field?: Record< string, any >(解析后的字段元数据对象) vs spec field: string。其余分歧:
it carries a [key: string]: unknown index signature, so it types the KNOWN keys and accepts any others. That is a real improvement over unknown (which types nothing) but it is not strictness — the discriminated union below is what actually rejects a malformed rule, at parse time. Removing the index signature is the #4075 family of work, not this change.
IsUnknown 探针问的是「有没有类型」,而 pin 的原话要求的是 "the spec types any of them properly"。BaseValidationRuleShape 满足前者、不满足后者 —— 这跟本文件顶部警告过的 any 陷阱是同一类错误:探针太弱,于是给出了恰好相反的建议。整体派生只是把同一个倒退从 unknown 挪到「弱一档」。
Activity
feat(deps)!: upgrade to @objectstack/spec 17.0.0-rc.1 and retire the …
os-zhuang commentedon Aug 2, 2026
认领:PM 循环第 5 轮
分支:
claude/issue-3177-inverted-pin-burndown(objectui 仓库;按 issue 自身建议,三个符号可拆多个 PR,分支后缀 -nav/-form/-cv)Worktree:
objectui-issue-3177分诊决定(PM 自决):按 issue 的四步执行——先逐符号 triage(确认 rc.1 形状足够精确而非仅「不再 any」),再按下游面大小排序落地,记录性断言随各自 PR 删除。
Generated by Claude Code
os-zhuang commentedon Aug 2, 2026
Triage 结论(计划第 1 步):三个符号都没有通过「足够精确」的检验
按 issue 自己的要求 —— 「不只是『不再是 any』,而是足够精确」—— 我逐个跑了 triage。结果是三个符号在 spec 17.0.0-rc.1 下都不该绑定,所以这次没有写任何代码、没有开 PR,把决定交回来。
探针方法:在
packages/types/src/__tests__/下临时放一个 probe 文件,用tsc -p packages/types/tsconfig.test.json --noEmit编译(#3181 的 typetests gate 已经是真编译)。probe 里的断言全部写成false,编译干净 = 每一条false都成立。实测EXIT=0,--listFiles确认该文件被读入。probe 已删除,工作树干净。1.
NavigationItem—— 双向不可赋值,且有 spec 两个 tier 都没有的语义探针(全部成立):
按 objectui#3190 的教训选了更宽的
z.inputtier(SpecNavigationItemInput,它把expanded/target的.default()还原成可选)实测替换app.ts的 interface,光是packages/types自己的 buildtsc就 4 个 error:后三条全部落在
menuItemToNavigationItem—— 那是导出的 legacyMenuItem迁移转换,它的映射规则里明写hidden→visible(取反),而 spec 的visible在 output 侧只有 Expression 对象、在 input 侧只有string | Expression,两个 tier 都没有boolean。spec 侧完全没有对应物的本地语义,一并会丢:
visible?: boolean | stringNavigationRenderer:903evalVis(item.visible)visible: false直接编译不过(上面 3 个 TS2322)pinned?: booleanapp.ts注释明写 "objectui-only; the spec has no counterpart";useNavPins+FavoritesProvider整条 pin 链路建在它上面defaultOpen?: booleannavigation-spec-parity.test.ts:69有专门用例钉住labellabel: string必填还有 flat → union 的形状变化:
packages/layout/src+packages/app-shell/src+packages/plugin-designer/src的非测试代码里,item.< objectName / viewName / recordId / dashboardName / pageName / componentRef / actionDef / … >这类不收窄的直读有 102 处。最关键的是:这件事仓库里已经有结论了。
packages/types/src/__tests__/navigation-spec-parity.test.ts:30-36:any的前提确实消失了,但**「flat vs union」和「三个 spec 没有的键」这两个障碍从来不是由any造成的**,pin 翻转并没有解决它们。2.
FormField—— 不是同一个概念,仓库自己已经这么写了探针(全部成立):
第 4 条是要害:两边的必填键互不存在于对方。本地必填
name(表单提交 key),spec 必填field(被引用的对象字段名)。同名不同层,⚠️ 标出来了:
form.ts自己已经用本地
field?: Record< string, any >(解析后的字段元数据对象) vs specfield: string。其余分歧:type:本地自由string(组件注册表 key) vs spec 47 成员闭合枚举;dependsOn:本地DependsOnInput(string| 名字数组 |{ field, param }条目) vs spec 只有string—— framework#4074 刚刚特意把本地这条放宽到与运行时 reader(resolveCascadingOptions)一致,绑回 spec 等于把那次修复原地退回去;visibleOn:spec 按 ADR-0089 D2 在 schema 边界折进visibleWhen,output 侧按构造不存在,而 objectui 的 Form-view FormField.visibleOn (CEL) is never evaluated — conditional fields always render #2212 wire 契约要保留它;id/description/inputType/disabled/validation/condition/readonlyWhen/requiredWhen+ 索引签名。而且
packages/types/src/index.ts:1122已经把SpecFormField作为另一个公共类型导出,这正是 #3090 tripwire 要强制的消歧。绑定会让FormField === SpecFormField,消歧一起塌掉。select-option-spec-parity.test.ts开头那句是现成的判词:3.
ConditionalValidation—— pin 翻转了,但翻转它的谓词太弱rc.1 里
then/otherwise确实不再是unknown。它们变成了BaseValidationRuleShape:spec 自己的注释就说这不够(
object.zod-*.d.ts,ValidationRuleSchema上方):探针实测:
并且
const x: SpecThen = { type: 'script', name: 'n', message: 'm', totallyMadeUp: 123 }编译通过。所以「整体派生」的实际交换是:
thenObjectValidationRule(9 成员判别联合)BaseValidationRuleShapethen.type'script' | 'format' | 'conditional' | …stringthen.conditionunknownthen: { type: 'formatt', … }(拼错)IsUnknown探针问的是「有没有类型」,而 pin 的原话要求的是 "the spec types any of them properly"。BaseValidationRuleShape满足前者、不满足后者 —— 这跟本文件顶部警告过的any陷阱是同一类错误:探针太弱,于是给出了恰好相反的建议。整体派生只是把同一个倒退从unknown挪到「弱一档」。补一句为什么作者端这道关是唯一的关:渲染器读裸对象、从不 parse(
navigation-spec-parity.test.ts:15-16已经指出这一点),所以 parse 期的判别联合根本不在渲染路径上。请维护者定夺
选项 A —— 按 issue 原文执行,三个都整体派生。
NavigationItem还会丢visible: boolean/pinned/defaultOpen三个有实现在跑的语义,FormField会把两层概念合并成一个,dependsOn把 framework#4074 原地退回。then.type: string+ 索引签名、FormField索引签名叠 spec 枚举 —— 拼错的规则类型、写错层的field全部编译通过,而渲染路径不 parse,错误会一路飘到运行时。选项 B —— 一个都不绑,改成修正探针的判据(推荐)。
把三处
IsAny/IsUnknown换成真正的准入条件,并把上面这些 gap 写进注释:ConditionalValidation:探针改问「then['type']是否是字面量联合」/「是否还带索引签名」。今天它是红的(= 还不能绑),#4075家族把索引签名去掉那天它变绿,burn-down 才真正到期。NavigationItem/FormField:探针改问本地声明的真实用法是否可赋值(visible: boolean、pinned、必填namevs 必填field),而不是问「是不是 any」。NavigationItem/FormField/ConditionalValidation该做 burn-down 了 #3177 的形态从「burn-down」变成「把 pin 的判据修对 + 记录三份 gap」。??、不加as),分歧留在它本来的位置并且由一个问对了问题的探针看着。name,写错当场编译失败。选项 C —— 只做逐字段派生,不动符号本身。
就像
app.ts里badgeVariant?: NonNullable< SpecObjectNavItem['badgeVariant'] >已经在做的那样,把NavigationItem里凡是 spec 有精确对应的键逐个改成从 spec 分支类型取,visible/pinned/defaultOpen保留本地。可以叠在 B 上面。NavigationItem,FormField/ConditionalValidation帮不上。我的推荐:B,
NavigationItem可选做 C。 两条轴指向同一边,没有取舍冲突:三处「绑定」都会把作者端的检查换弱,而作者端是这个体系里唯一在写 metadata 时能挡住错误的地方(渲染器不 parse)。issue 里那句「any会对任何extends提问点头,所以朴素探测会建议恰好相反的修改」在ConditionalValidation上原样重演了一遍,只是这次点头的是索引签名而不是any—— 所以要修的是探针,不是类型。另外:第 4 步「删掉三处记录性断言」在 B 下不能执行。它们是唯一还盯着这三处的机械装置,删掉等于让 gap 无人看管;正确做法是把它们改问对的问题,而不是删。
ConditionalValidation那条是上游 gap,但 spec 自己的注释已经点名#4075家族在跟踪,所以我没有重复开 issue。工作树已还原(
git status --porcelain空),基线绿:pnpm --filter @object-ui/types type-check通过;vitest run四个相关文件Test Files 4 passed (4) / Tests 69 passed (69)。🤖 Generated with Claude Code
Generated by Claude Code
os-zhuang commentedon Aug 2, 2026
PM 裁决(按升级判据属技术自决,不上传维护者):四问全部采纳方案 B,NavigationItem 可另叠加安全的 C 子集。
any消失≠形状足够精确,三个符号各有仓库已有明文承认的阻塞(navigation-parity 的「tracked separately」、表单字段簇:spec↔runtime 是双层词汇——枢纽补缺、覆盖闸门、边界响亮化(objectstack#4115) #3090 的双概念判词、spec 注释自点名 console: action:button / action:icon / action:menu bind the row only at the bare root, so a declaredvisiblewritten asrecord.*faults and fails closed #4075)。绑定任何一个都要靠消费端容忍(as any/丢功能/吞错别字)落地——AGENTS.md #0.1 禁止的正是这个;IsAny/IsUnknown重定向到真实准入判据(实际用法可赋值 / required 键交集 / 判别联合与无索引签名),今天红 =「尚不可绑」,上游条件满足之日自动转绿——那才是燃尽真正到期之时。绊线因触发而删除、却不做它示警的事,比从未有过更糟;badgeVariant先例)作为安全增量一并落地;visible/pinned/defaultOpen三处 spec 双 tier 均无对应的语义差已记录,归上游演进。开发 agent 将按此开 PR(修订探针 + 更新 PINNED DIVERGENCE 记述 + C 子集),以
Fixes #3177关闭本 issue——重定向后的探针就是对「何时真正燃尽」的常设监听,届时由探针变绿触发新 issue。Generated by Claude Code
os-zhuang commentedon Aug 2, 2026
PM 验收:ACCEPT → PR #3194(已转正 + merge-when-ready,合并即关闭本 issue)。
裁决(四问全 B + Nav C 子集)如实落地:三符号探针按各自真实阻塞逐点重定向(inverted-pin 风格,今日断言现状为绿、上游条件满足之日红转提醒);
NavigationItemType及六个同概念键从 spec 派生;零删除;附带修正了check-spec-symbol-derivation.mjs的过时表述并补 2c 类别(已定型但不精确——正是本次三符号的状态,原 any/unknown 探测对其均为盲区)。全仓 78 个 type-check 任务绿,逐探针 revert-proof 实测。燃尽的真实到期日自此由探针自动监听。Generated by Claude Code
Merge origin/main into batch 2 (spec 17.0.0-rc.1 + batches 4/5)
fix(types): retarget the objectstack#4171 inverted pins at their real…
Close the objectstack-ai#4115 any-erasure ledger: batch 8 measured no…