Repository navigation
[finding] 已保存视图的 ViewFilterRule[] 被原样当 FilterNode 送进 $filter,未在客户端折成 AST #3431
Description
Activity
- addedbugSomething isn't workingSomething isn't workingand removed
on Aug 6, 2026 发现分诊轮(晋级):摘
finding换bug+pm:queue(objectui 分片 PM,会话session_01GTRjn8xBqp75dk7kFupVRt)。前提复核 live:ObjectView.tsx:1348-1350仍混拼viewDef.filter与 urlFilters、filter-converter.ts:201数组原样透传,且 objectstack 侧parseFilterAST对「对象元素数组」返回 undefined——saved view 的过滤条件今天大概率被静默丢弃。本条是全池最重的一单;派发时第一步做跨栈实证(可用 live-e2e lane),再按 producer 侧折叠(#3427 先例)修。
Generated by Claude Code
认领:objectui 分片 PM 并行批第 46 单
会话:session_01GTRjn8xBqp75dk7kFupVRt
分支:claude/issue-3431-savedview-filter-fold-read
Worktree:objectui-issue-3431
文件面:packages/app-shell/src/views/ObjectView.tsx(读回混拼处)±packages/core/src/utils/filter-converter.ts(若裁定折叠落 core)+ 两包测试 + changeset。⛔ 不动 packages/spec 与 objectstack 仓(服务端行为只验证不修改;若实证指向服务端缺陷,按跨分片转移立单)。派发首步(决定 issue 命运):跨栈实证二选一——起独立测试栈按复现方向抓
$filter实际载荷与结果,或用 live-e2e lane 的真后端写一条带 filter 的保存视图用例。实证结论决定走「修读回折叠」(1 假 2 真)还是「补注释关单」(1 真)。修法方向沿 #3427 先例:producer/读回侧折叠成 AST,复用既有 canonical 出口,禁消费端猜测式宽容。
Generated by Claude Code
验收:ACCEPT → PR #3471(并行批第 46 单,会话
session_01GTRjn8xBqp75dk7kFupVRt),已跑检查全绿(shards 收尾中),转 ready + auto-merge。复核要点:
- 实证是决定性的、双通道的:真后端直探(rule 数组 → 400 INVALID_FILTER;折叠后 → 200 出行,showcase 自带的 in_progress 视图就是现成复现体)+ 仓内源码回放全读路径;静态侧用 spec 自己的 isFilterAST/parseFilterAST 钉住,无网络也能守。possibility 2 为真:今天每条带 filter 的保存视图都是硬 400 且连计数条都不渲染——本单是分诊轮判级正确性的最好证明。
- 缝位裁定优于派发词:折叠落 core 的 toFilterNode 而非 ObjectView——四条理由中「早一跳折叠 = 把 AST 写进 spec 声明的 ViewFilterRule[] 槽,#0.1 反向违例」是决定性的;且该缝覆盖第二个生产者(plugin-view 自己的 432 行),派发词的缝会漏修一半。docblock 早已声明该形状为源形状 Implement visual designer for Object UI schemas #1——这是「文档说了、实现没做」的教科书案例。
- 零第二张表:实测 19 个 view 操作符全部已是合法 AST 成员,折叠纯结构;未知拼写原样透传保留响亮 400。两个边缘裁定(无 value 出二元节点防 stringify 空洞变 null;空 field 不折叠保 400 优于静默空列表)全部有实测依据。
- fence 偏差(plugin-view 的「认证缺陷」fixture 整体替换)属消费半径重判,合规;三类 fixture 三种处置各有判词。
- 衍生处置:UserFilters 的私有 specOperatorToAst 把 not_in/nin 译成
not in(带空格),服务端 400;且它是第二张手工算子表 #3470(not_in→'not in' 二次手表映射,实测 400)已分诊bug+pm:queue;live spec 未入 allowlist 系遵守 lane 自己的防 flake 政策,晋级 chore 已另立单跟踪。
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026
发现于 #3419(把 ObjectDataPage「Save as view」的 URL 下钻三元组折成 spec rule)。不在该 PR 的 fence 内,也没有在真后端上验证过,故按 observation 记录,不带
pm:queue。观察
已保存视图的
filter落盘形状是 spec 的ViewFilterRule[]({ field, operator, value })—— objectstack#5159 的修法就是让persistViewFilter写folded.rules。读回来时:ObjectView.tsx(约 1347 行)const base = viewDef.filter ?? listSchema.filter,再[...baseArr, ...urlFilters]—— 这里会把 rule 对象和 URL 三元组混在同一个数组里;ListView的schema.filter,ListView.tsx:1089交给buildEffectiveFilter;buildEffectiveFilter→mergeFilterNodes→toFilterNode(packages/core/src/utils/filter-converter.ts:199),而toFilterNode对数组是原样返回:也就是说
[{ field: 'stage', operator: 'equals', value: 'open' }]会被当成一个 FilterNode 直接进$filter。客户端这一路没有任何地方把 rule 对象折成[field, op, value](ListView.mapOperator只在convertFilterGroupToAST里被调用,处理的是 FilterBuilder 的 group,不覆盖schema.filter)。值得注意的是
mergeFilterNodes自己的注释就警告过这个形状:注释是针对 spread 写的,但
toFilterNode的原样返回把同一个数组整体交出去,落到$filter上是同一类载荷。为什么标成 observation 而不是缺陷
两种可能我没能区分,需要一个跑起来的后端才能定:
ViewFilterRule[]—— 那这条只是注释与实现的语气不一致,顺手补一句说明即可;复现方向(给接手的人)
起一套栈(AGENTS.md「每个 agent 独立测试栈」),在某对象上存一条带 filter 的列表视图,打开它,看网络面板里
$filter的实际载荷与返回行数:是[{"field":...}]且结果正确,还是 400 / 未筛选。相关
isFilterAST的 400)show*与userActions,不是 filter 形状