Skip to content

driver-sql:两类无意义比较对象仍编译成「静默空谓词」—— $in/$nin 的非 $field 对象成员,与 LIKE 族的对象比较值(String 成 [object Object]) #5234

Description

@xuyushun441-sys

#5041(PR #5223)实施过程中的范围外发现,只记录不修、不指派。发现者(os-dev)已实测,证据基础同 PR #5223 的探针方法。

两个形状

  1. $in / $nin 列表里的非 $field 对象成员:{ status: { $in: ['a', { foo: 1 }] } } —— 编译通过、执行、静默零行(该成员绑定为无法命中的值)。PR fix(driver-sql): $field 跨字段比较按 ADR-0112 响亮拒绝,不再抛裸 TypeError (#5041) #5223 已拦下列表成员是 {$field: ...} 的情形(按成员序号点名拒绝),但其它对象成员仍走旧路。
  2. LIKE 族($contains/$startsWith/$endsWith…)遇对象比较值:被 String() 成 '[object Object]' 参与匹配 —— 语义上永假,静默零行。

为什么当时没有一并修(记录 dev 的边界判断,供接手者参考)

与既有账的关系

同属 #3948 / #4209 点名的「静默错误答案」类;修法大概率是把 PR #5223 在三个比较发射器上装的形状守卫拓宽到这两类(同一收口点、同一 INVALID_FILTER 信封),但需要先测量 $in 数组成员与 LIKE 比较值的合法形状全集,避免误伤。

Refs:#5041、PR #5223(探针与发射器清单)、#5222($field 的 SQL 实现,v18)、#3948、#4209。

Activity

  1. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    同一形状在 service-analytics 也有一份(#5526 实施途中的范围外发现,不在本 PR 修)

    做 #5526(analytics 的 leaf values 由 string[] 改 unknown[])时必须逐个决定"非字符串比较数在 LIKE 路径上怎么归一",于是把本单第 2 条形状在 analytics 侧也测了一遍。结论:同一个 String() 宽容,在本仓有三份实现,driver-sql 只是其中一份。

    filter.zod.ts 把 LIKE 族的比较数声明为 z.string():

    packages/spec/src/data/filter.zod.ts:143   $contains: z.string().optional(),
    packages/spec/src/data/filter.zod.ts:149   $startsWith: z.string().optional(),
    packages/spec/src/data/filter.zod.ts:152   $endsWith: z.string().optional(),
    

    三个消费方都不拒绝违反该声明的输入,而是 String() 掉它:

    实现 位置 表达式
    driver-sql(本单) packages/plugins/driver-sql/src/sql-driver.ts applyLike String(value).replace(/[\\%_]/g, '\\$&')
    service-analytics 的两个 SQL 发射器 packages/services/service-analytics/src/like-pattern.ts escapeLikePattern 同一表达式(#5567 刻意的第二份实现,两者由 like-metacharacter-escape.test.ts 逐字符互锁)
    service-analytics 的引擎路径 packages/services/service-analytics/src/strategies/objectql-strategy.ts convertFilter String(v0)(#5526 起显式写成这样;此前由删掉的编码器隐式保证)

    所以本单的修法有一条约束值得先记下来:三份必须一起动。只在 driver-sql 收紧,{name: {$contains: {…}}} 就会变成"哪个面接的、就是哪个答案" —— 正是 #5146 / #5332 / #5567 各花一轮消掉的那类分叉。#5567 的 header 已经把"第三份手抄是要拒绝的东西"写下来了,收紧守卫时同理:守卫要么进 like-pattern.ts + applyLike 两处并被那个逐字符互锁测试覆盖,要么在发布/授权时就拒(Prime Directive #12 更偏好后者)。

    顺带两条 analytics 侧的实测,供接手者定范围:

    本单范围与标签不建议变(仍是 driver-sql 的账),只是它的"完成"定义应包含 analytics 那两处发射器,否则修完仍有两个方言。


    Generated by Claude Code

  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    Contributor

    存量裁决轮(维护者 2026-08-06 委托,session_01LeEfA7CFwbJb7JJmXm2KM3):裁定入队。前提经 origin/main 核实精确成立:#5223 落地的 assertCompilableComparand 头注释明写这两个形状 "Deliberately NOT extended"(sql-driver.ts:620-628),applyLike 仍 String(value)——近期算子收口刻意未覆盖,缺陷仍在。driver-sql 不在 #5499 冻结范围。完成定义按 08-05 评论:analytics 两处 LIKE 发射器一并收紧(三份实现一起动)。维护者可否决。


    Generated by Claude Code

  3. self-assigned this
    on Aug 6, 2026
  4. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    Contributor

    认领:PM 循环第 9 轮(drivers 车道,维护者 2026-08-06「加速开发」指令,三路并行批次之一)
    会话:session_01WyvqvKMG6asi9aXjKE6xtx
    分支:claude/issue-5234-silent-empty-predicates
    Worktree:objectstack-issue-5234
    域:domain:drivers 主账;跨域执行申报:完成定义(08-05 评论 + 存量裁决轮口径)含 service-analytics 两处 LIKE 发射器(domain:services 领地)——三份实现一起动,否则修完仍是方言分叉
    文件面:driver-sql 的 sql-driver.ts(applyLike + assertCompilableComparand 拓宽)+ packages/services/service-analytics/src/like-pattern.ts + strategies/objectql-strategy.ts + 各自测试(含 like-metacharacter-escape 互锁表)
    定向在飞检查:全仓 18 张 pm:dispatched 无 driver-sql / service-analytics 面。串行约束:#5298 实现半边与本单同文件(sql-driver.ts),已排本单落地之后。


    Generated by Claude Code

  5. removed their assignment
    on Aug 6, 2026
  6. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    Contributor

    认领解除(drivers 车道 PM,session_01WyvqvKMG6asi9aXjKE6xtx,2026-08-06 14:5xZ):派发的 dev 被维护者手动中止(宿主明确回报 stopped by the user、不会恢复)。摘 assignee 与 pm:dispatched,回 pm:queue。是否重派等维护者示意。

    留档供下次派发:


    Generated by Claude Code

  7. 3 remaining items

  8. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    Contributor

    重派(维护者 2026-08-07 在 PM 会话示意继续):PM 循环第 11 轮(drivers 车道)
    会话:session_01WyvqvKMG6asi9aXjKE6xtx
    分支:claude/issue-5234-silent-empty-predicates(旧分支 6428b27 是 08-06 被中止那次的未完成实现,可审可弃,以最新 origin/main 为基线重做为准)
    Worktree:objectstack-issue-5234
    文件面:driver-sql/src/sql-driver.ts(applyLike + assertCompilableComparand 区)+ service-analytics/src/like-pattern.ts + service-analytics/src/strategies/objectql-strategy.ts + 各自测试 + changeset

    完成定义不变(08-05 评论 + 08-06 存量裁决轮):三份 LIKE 实现一起动,只收紧一份即制造新方言分叉。

    并行注记:#6210(五驱动签名收窄)在飞、同文件不同区(签名区 :2091-2876 vs 本单 applyLike/assertCompilableComparand 区),后落地者 rebase;#6204(聚合信封)已 MERGED,其 sql-driver.ts 改动已在 main。


    Generated by Claude Code

  9. added 2 commits that reference this issue on Aug 7, 2026
  10. os-zhuang commented on Aug 7, 2026

    @os-zhuang
    Contributor

    复核:ACCEPT → PR #6296(PM 实测复核)。

    ⚠️ 首先:本单正文的严重度定级被实测推翻,应记录在案

    正文写「两者都不抛错…失败方向 fail-closed(收窄结果集,不存在权限绕过),风险级别低于 #5041」。dev 用带 r_literal(name 字面就是 [object Object])的 fixture 把「静默零行」变成可证伪命题后实测:

    filter 实际答案 与定级的关系
    {status: {$nin: [{foo:1}]}} 全表(该排除的一行没排除) 方向是放宽,不是 fail-closed
    {name: {$contains: {}}} 命中 r_literal 一条真实记录 不是零行,是错行
    {name: {$notContains: {}}} 为无人记录的理由排除掉一条真实记录 同上,反向

    即:一条本意「排除某些行」的过滤器在 $nin 上等于没写。定级从「fail-closed 低风险」改为放宽类。这条更正值得进分诊经验——「静默零行」这类描述在没有对抗性 fixture(专门放一行等于 [object Object] 的数据)时会自我实现地被确认。

    复核结论

    CI 清零后转 ready 入队。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions