发现于 #3375(给 viewEnvelope 补 ViewItem spec 一致性 pin 时),不在该 PR 的 fence 内(属运行时行为改动),故单独记录。
现象
packages/app-shell/src/views/ObjectDataPage.tsx 的 handleSaveAsView(约 250-254 行)把当前 URL 上的下钻条件原样塞进要持久化的 view spec:
const spec: Record< string, any > = {
...config,
columns: ...,
...(urlFilters.length ? { filter: urlFilters } : {}),
};
const env = viewEnvelope(objectName ?? '', spec, { ... });
await createRuntimeMetadata('view', env.name, env, { metadataClient });
而 urlFilters 是 FilterTriple[](drillUrlFilters.ts:23:[string, string, unknown] —— 三元组数组),@objectstack/spec 的 ViewItem list config 里 filter 要求的是 ViewFilterRuleSchema 对象数组({ field, operator, value },且 operator 取规范枚举 equals 等,不是 =)。
复现(spec@17.0.0-rc.2,即当前 lockfile 解析版本)
把 viewEnvelope 在该调用点的实际产出喂给记录门:
config.filter = [['stage','=','open']]
ViewItemSchema.safeParse(env) -> false
[{"expected":"object","code":"invalid_type","path":["config","filter",0],
"message":"Invalid input: expected object, received array"}]
对照:builder 那条路径是对的 —— viewFilterFold.foldFilterGroupToSpecRules(viewFilterFold.ts:122)产出 { field, operator, value },并且用 normalizeFilterOperator 把 operator 规范化过,产出可以过门。也就是说同一个 filter 键在本仓存在两种写法,只有 fold 那条符合 spec。
影响
带下钻条件时点「Save as view」,写出去的是一条 off-spec 的 ViewItem。ADR-0017 记录门若在发布/校验侧收紧,这条 view 会被拒;在此之前它以第二种事实方言的形式沉淀下来。
建议方向(交由 triage 定夺)
契约优先:在 producer 侧把三元组折成 spec 的 rule 对象再进 viewEnvelope(复用 normalizeFilterOperator,与 viewFilterFold 同一出口),而不是在消费侧容忍三元组。
备注
#3375 的 pin 只覆盖 viewEnvelope 自身的产出契约,对这条走的是「按 spec 形状的 filter rules」用例;三元组这条留给本 issue,以免把运行时改动混进纯 pin PR。
发现于 #3375(给
viewEnvelope补 ViewItem spec 一致性 pin 时),不在该 PR 的 fence 内(属运行时行为改动),故单独记录。现象
packages/app-shell/src/views/ObjectDataPage.tsx的handleSaveAsView(约 250-254 行)把当前 URL 上的下钻条件原样塞进要持久化的 view spec:而
urlFilters是FilterTriple[](drillUrlFilters.ts:23:[string, string, unknown]—— 三元组数组),@objectstack/spec的 ViewItem list config 里filter要求的是ViewFilterRuleSchema对象数组({ field, operator, value },且 operator 取规范枚举equals等,不是=)。复现(spec@17.0.0-rc.2,即当前 lockfile 解析版本)
把
viewEnvelope在该调用点的实际产出喂给记录门:对照:builder 那条路径是对的 ——
viewFilterFold.foldFilterGroupToSpecRules(viewFilterFold.ts:122)产出{ field, operator, value },并且用normalizeFilterOperator把 operator 规范化过,产出可以过门。也就是说同一个filter键在本仓存在两种写法,只有 fold 那条符合 spec。影响
带下钻条件时点「Save as view」,写出去的是一条 off-spec 的 ViewItem。ADR-0017 记录门若在发布/校验侧收紧,这条 view 会被拒;在此之前它以第二种事实方言的形式沉淀下来。
建议方向(交由 triage 定夺)
契约优先:在 producer 侧把三元组折成 spec 的 rule 对象再进
viewEnvelope(复用normalizeFilterOperator,与viewFilterFold同一出口),而不是在消费侧容忍三元组。备注
#3375 的 pin 只覆盖
viewEnvelope自身的产出契约,对这条走的是「按 spec 形状的 filter rules」用例;三元组这条留给本 issue,以免把运行时改动混进纯 pin PR。