Skip to content

[#5298 第二批] filter-normalizer(Cube 面)NULL-safe 对齐:先实测既有 NULL 行为,分叉则改写;N1 入表按后落地者规则 #5977

Closed

Description

@os-zhuang

裁决依据:#5298「四项确认落档」评论(维护者 2026-08-06)——实施面①裁定全扩分批,本单是第二批;方向④:非否定路径 $ne/$nin/$notContains 包含 NULL 行。第一批(PR #5962:driver-sql 五出口 + read-scope-sql + formula $exists)已 MERGED。

任务

  1. 先实测:packages/services/service-analytics/src/strategies/filter-normalizer.ts 的 notEquals/notIn/notContains 降级路径(约 :267-275,极性表副本约 :710-719)对 NULL 行的既有行为——非否定路径上的 $ne / $nin / $notContains:driver-sql 排除 NULL 行,driver-memory / formula 返回它们(#5146 只裁定了 $not) #5298 成本清单明记此面未测(容器无 Cube 实例);用其真实消费端(native-sql 一致性 harness / MemoryAnalyticsService 路径)驱动实测,别静态读码下结论。
  2. 与裁决方向分叉的,改写对齐(参照 PR fix(drivers,analytics,formula): $ne / $nin / $notContains 在 $not 之外也 NULL-safe (#5298) #5962 中 read-scope-sql 的形态:OR 展开、复用极性判定);已一致则记录证据、一行不改。
  3. N1 入表判定:FILTER_LOGIC_CASES 的 N1($ne 含 NULL 行)按「后落地者入表」规则(非否定路径上的 $ne / $nin / $notContains:driver-sql 排除 NULL 行,driver-memory / formula 返回它们(#5146 只裁定了 $not) #5298 PM 裁定评论)——若 drivers(turso): remote 模式没有继承 #5146 的 $not NULL-safe —— 同一个 TursoDriver,local 返回 NULL 行、remote 不返回(实测,origin/main) #5903(turso remote)届时已 MERGED,本 PR 补 N1 入表(spec 表文档 RULED-but-not-yet-enrolled 小节有现成行,复制即可);未落地则如实留给 drivers(turso): remote 模式没有继承 #5146 的 $not NULL-safe —— 同一个 TursoDriver,local 返回 NULL 行、remote 不返回(实测,origin/main) #5903,报告说明。
  4. 反向验证方向预判:若第 2 步有改写,native-sql harness 的 N1 格(现红,见 PR fix(drivers,analytics,formula): $ne / $nin / $notContains 在 $not 之外也 NULL-safe (#5298) #5962 表文档小节)应转绿。

边界(⛔)

验收

  • filter-normalizer 对三算子的 NULL 行为与裁决一致(实测证据,非推断);service-analytics 全绿 + 相关 conformance harness 全绿;若有行为改写 → changeset。

Activity

  1. self-assigned this
    on Aug 6, 2026
  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 9 轮(drivers 车道,#5962 落地后的第二批棒)
    会话:session_01WyvqvKMG6asi9aXjKE6xtx
    分支:claude/issue-5977-filter-normalizer-null-safe
    Worktree:objectstack-issue-5977
    域:domain:drivers 程序锚点(#5298 裁决①),落点 service-analytics 属 services 领地——跨域执行申报,定向在飞检查:#5234 在飞同包不同文件(like-pattern.ts / objectql-strategy.ts vs 本单 filter-normalizer.ts),零文本重叠可并行,后落地者 rebase;#5770 在飞面为 driver-turso,不相交。
    文件面:strategies/filter-normalizer.ts(视实测结果,可能零改动)+ 实测/一致性测试 + 视情 spec 表 N1 行 + changeset(仅当有行为改写)。

    同批串行注记:#5903 因与 #5770 同文件(remote-transport.ts)改排 #5770 落地后派发——原「#5962 落地即放 #5903」的计划因 #5770 先行在飞而顺延,防同文件双改。


    Generated by Claude Code

  3. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

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

    CI 清零后转 ready 入队;#5903 的派发词将并入「N1+N4 两行入表」职责(其为两行共同的最后 blocker)。


    Generated by Claude Code

  4. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    交付:PR #6004(draft,CI 24 检查 22 success / 2 skipped,零 failure)。 会话 session_01WyvqvKMG6asi9aXjKE6xtx。

    实测结论:分叉成立(不是「已一致」的小单),但落点与正文指认不同

    真实消费端驱动(NativeSQLStrategy 端到端跑 sql.js;ObjectQL 路径在 executeAggregate 缝上捕获引擎 filter 并真实执行)。{stage: {$ne: 'won'}},行 3/4 的 stage 为 NULL:

    编译器 改前 改后
    NativeSQLStrategy 原生 SQL 2 2,3,4
    ObjectQLStrategy 回显 SQL 2 2,3,4
    ObjectQLStrategy → 引擎 condition 2,3,4 2,3,4

    改前 WHERE 逐字:stage != $1 / stage NOT IN ($1) / stage NOT LIKE $1 ESCAPE $2。

    ⚠️ 正文与成本清单 §1.C 把 Cube 面记成一个发射点(filter-normalizer.ts:267-275),实际是两个:那处是 MONGO_TO_CUBE_OP 算子改名表,不决定 NULL 行为;真发射器是 native-sql-strategy.ts 的 buildFilterClause 与 objectql-strategy.ts 的 buildFilterClauseSql。已把该清点订正评论挂到 #5930(谓词编译收敛调查)。

    引擎那列改前就对,但不是 analytics 层做对了,而是 #5962 让 driver-sql 自己加了守卫 —— 即「画哪些行取决于下游哪个编译器先接住叶子」。

    改法与边界

    守卫下沉成树结构(fieldLeaves 发 or(notSet, 比较)),三个编译器零改动同时对齐,因此没有触碰 ⛔ 的 objectql-strategy.ts。守卫范围复用既有极性对 nullValueSatisfiesOperator / operatorIsNullTotal 的 allowNull 判定,不新增算子名单($ne: null 仍 total、空 $nin 仍 TRUE 常量、正向比较逐字节不变、$not 极性未拓宽)。

    N1 入表:留给 #5903

    收尾实测 git log origin/main --grep=5903 为空、issue 仍 open ⇒ 本 PR 是先落地者,FILTER_LOGIC_CASES 一行未加。但 spec 表文档那张实测 blocker 矩阵已订正(否则「Cube 面答 ['2']」成为假话):Cube 行摘掉,driver-turso remote 成为 $ne 与 $not 两行共同的最后一个 blocker,两行随 #5903 一并入表 —— 对 #5903 的派发词是简化,不是加担子。

    反向验证

    方向如预判为 RED(直白谓词变更,非 #5046 那类计数门反转):短路守卫后 15 条转红(含新增 7 条 #5298 钉子全红),恢复后全绿。派发词第 4 条预判的「harness N1 格转绿」不适用——N1 尚未入表,harness 里没有该格,已如实记录而非套模板。

    范围外发现另立 #6005($not 的 allowNull 支在本次之后成为冗余第二层,谓词等价、finding 不入队)。


    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

pm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions