Skip to content

控制台「筛选」把整个 FilterGroup 对象存进 view 的 filter(spec 声明的是 ViewFilterRule[])—— 真浏览器实测 422,#5114 热修修不到 #5159

Description

@xuyushun441-sys

发现于 #5114 热修的 dogfood 浏览器端到端复核(真实 /_console bundle,objectui 固定 pin f5bc4c78,Playwright 驱动)。

与 #5114 是同一个「保存筛选条件」动作上的两个独立缺陷,叠在同一份 body 上。#5114 的重开修掉里层那个,修不到这一条。 写下来免得下一个人以为热修合并后控制台就通了 —— 它不通。

实测:真浏览器里点一次「Filter → Add filter」

showcase 起在自有端口,真实登录,/_console/apps/showcase_app/showcase_task,点工具栏 Filter → Add filter:

PUT /api/v1/meta/view/showcase_task.default  ->  422
{"error":"[invalid_metadata] view/showcase_task.default failed spec validation: root: Invalid input",
 "code":"INVALID_METADATA","issues":[{"path":"","message":"Invalid input","code":"invalid_union"}]}

抓下来的 body 里,filter 是这个:

"filter": {
  "id": "root",
  "logic": "and",
  "conditions": [
    { "id": "712135fb-58c5-4be4-a611-1925181509b0", "field": "title", "operator": "equals", "value": "" }
  ]
}

是 FilterGroup 对象,不是 ViewFilterRule[]。 而 ListViewSchema.filter 声明的是 z.array(ViewFilterRuleSchema)。

两个缺陷是叠着的 —— 把抓下来的真 body 三变体回放

同一份 body,只改 filter,分别打到 修前(origin/main)/ 修后(#5114 热修)两个真实运行的 server:

变体 修前 修后(#5114)
① 原样(FilterGroup 对象) 422 invalid_union 422 invalid_union
② 拆掉分组 → rule[],保留 UI 的 id 422 ACCEPTED
③ 拆掉分组 → rule[],去掉 id ACCEPTED ACCEPTED

读法:外层类型错(本 issue)挡在前面;把它拆开之后,下一道就是 #5114 那个 id。 #5114 的重开让 ② 从 422 翻成通过 —— 必要,但不充分。外层不修,控制台保存筛选条件仍然 422。

产出端链路(objectui,固定 pin 上逐跳可查)

  1. components/src/custom/filter-builder.tsx —— handleChange(newGroup: FilterGroup) → onChange?.(newGroup),交出的是分组对象;addCondition 给每行盖 id: crypto.randomUUID()(:228)
  2. plugin-list/src/ListView.tsx:2155-2161 —— onChange={(newFilters) => { setCurrentFilters(newFilters); onFilterChange?.(newFilters) }},原样上抛
  3. app-shell/src/views/ObjectView.tsx:1592-1595 —— onFilterChange={(filter) => { persistViewPatch(viewDef.id, viewDef, { filter }); … }}(同源另一处::1337)
  4. persistViewPatch(ObjectView.tsx:242)→ dataSource.updateViewConfig(objectName, viewId, { ...baseViewDef, ...merged })
  5. data-objectstack/src/index.ts:2608 → client.meta.saveItem('view', viewId, merged) → PUT /api/v1/meta/view/:name

对照:Studio 侧那条路今天是好的 —— app-shell/src/views/metadata-admin/widgets.tsx:1727-1732 的 handle 在写回前把每行压成 {field, operator, value}(顺带剥了 id),所以走 Studio 视图编辑器配筛选不会 422。缺的是运行时工具栏这条路的同一半转换。

处方倾向(不代劳裁定)

按 Prime Directive #12 契约优先,修产出端,⛔ 不要把 ListViewSchema.filter 放宽成 union([rule[], FilterGroup]):

  • A(推荐):运行时工具栏在 persistViewPatch 之前把 FilterGroup 折成 ViewFilterRule[] —— 这个转换 Studio 侧已经写好了(widgets.tsx 的 handle),反方向也有(plugin-view/src/config/view-config-utils.ts 的 parseSpecFilter/toFilterGroup);缺的就是写方向的这一半。代价小,且把「一个视图的 filter 在库里只有一种形状」这条守住。
  • B:如果分组语义(logic: 'or'、嵌套组)确实要进协议,那是一次有意的 spec 扩展(带 ADR + 迁移 + 读端全线更新),不是靠消费端容忍。

选 B 之外的任何「放宽 schema」都会让 filter 在库里同时有两种形状,所有读端都得两边都认 —— 正是本仓一直在还的那类债。

⚠️ 一并注意:logic: 'or' 今天没有任何落盘表示。修 A 之后 and 能正确折平,or 会被静默降级成 and —— 那是「声明 ≠ 生效」的另一面,建议在修 A 时一并判定(要么折平时对 or 显式报错,要么走 B)。

关联

Activity

  1. xuyushun441-sys commented on Aug 4, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    维护者裁决(2026-08-04):A1

    CLAIM

    • 会话:session_01Ehu85kbvMcrNTUJjwxvLJ9(spec 车道 PM,派发给 os-dev 实施)
    • 分支:objectui 仓 claude/issue-5159-filter-fold

    Generated by Claude Code

  2. xuyushun441-sys commented on Aug 4, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    重派记录(2026-08-04)

    前次派发的 dev 在配额窗口期被维护者手动停止;维护者现指示重派。裁决不变(A1,见上方 2026-08-04 裁决评论),分支沿用 claude/issue-5159-filter-fold;若远端存在截断前的 checkpoint 提交,按「中断运行不留证据」纪律全量重验后再复用。依赖已就位:PR #5154(内层 id 接纳)已合入 main。

    • 会话:session_01Ehu85kbvMcrNTUJjwxvLJ9(spec 车道 PM)

    Generated by Claude Code

  3. xuyushun441-sys commented on Aug 4, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    结案(2026-08-04)

    由 objectui PR #3360(已合并)按 A1 裁决修复:写方向折叠抽为共享 viewFilterFold.ts(两个调用点走同一函数,顺带删除落后 4 个运算符的手抄映射表);or/嵌套组响亮拒绝(10 语言包);id 剥离 —— 本单回放矩阵中变体 ②「rule[] 带 id 被接受」只在 framework main 的服务端成立,objectui 自己钉的 spec(17.0.0-rc.2)会以 unrecognized_keys 拒绝,故剥离是必须而非偏好,该 premise 修正已钉为测试;三变体全部在 payload 边界对真实 ListViewSchema 闭合。跨仓引用不自动关单,手动关闭。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions