Skip to content

ADR-0053 D-E3:mongo 的遗留形态是永久态,但它既无 backfill 也无读修复——#4191 storage-form 轴最尖的一格无法闭合 #4220

Description

@os-zhuang

#4191 的 storage-form 轴工作中分出。SQL 系四格与 driver-memory 的 D-E3 收敛格已落地(#4205、本轮 PR),mongo 这一格无法在当前形态下闭合,原因是设计缺口而不是测试缺口。

缺口本身

ADR-0053 给 SQLite 的遗留数据配了两条保险:

  1. backfillCanonicalDatetimes / backfillCanonicalTimes 在 schema sync 时收敛(D-B3、D-C2);
  2. 永久保留的读修复表达式(sqliteCanonicalDatetimeSql / sqliteCanonicalTimeSql),因为「query correctness must never be contingent on [a migration] having run」,且它同时覆盖永远不会被 backfill 的外部表(ADR-0015)。

mongo 两条都没有。D-E3 明确不做 boot-step backfill:

MongoDB gets no automatic backfill — rewriting a real collection is a migration, not a boot step — so a pre-existing collection keeps whatever it holds until migrated

但「until migrated」指向的迁移并不存在supports.migrations: false,代码里没有任何 $expr / $convert / repair 路径——已逐一 grep 确认)。于是一个 #4047 之前建立的 collection 是永久错的,而 D-E1 说明它的失败模式是所有后端里最安静的:

a string comparand never matches a Date value, in either direction, for every operator —— $gte included

预期机理(推理,非实测——见下)

canon 是 datetime → BSON Datedate/time → 文本。遗留 collection 的两个写者群按 writerForm 分裂:native 写入落成 BSON Date(datetime 恰好合规、time/date 不合规),wire 写入落成 ISO 文本(datetime 不合规)。comparand 被 coerceTemporalValue 强制成 canon 形态后,跨类型的那一半整体不匹配。以共享夹具估算,TEMPORAL_CASES 第一格(#3777 默认仪表盘窗口)期望 [b_prev, c_open, d_mid, e_late],实际只会得到 native 那一半 [b_prev, c_open]

为什么本轮没有直接做

当前开发环境跑不了真实 MongoDB:出站代理对 fastdl.mongodb.org 返回 403(policy denial,mongodb-memory-server 把它误报成「version-platform combination doesn't exist」),本机也没有 docker 守护进程。因此:

  • 无法实测行结果,上面的机理只能是推理;
  • 修复(无论走哪条)全程无法在本地执行一次,属于盲写安全相关的驱动改动;
  • 直接把 sweep 写进去只会得到一个必然红的测试。

按「不做未验证的架构改动 / 不为未交付的能力做假覆盖」的纪律,本轮不动,立项在此。

两条候选修法(需要裁决)

方案 形状 代价
A. 读修复(与 SQLite 对称) translateFilter 对未收敛列包 $expr + $convert/$toDateonError 保留原值 正确性不依赖迁移、覆盖外部 collection;但走不了索引,宽查询代价大;$convert 对 zone-naive 空格分隔文本的解析行为需实测
B. 显式迁移命令 一条 os migrate 子命令重写 collection(D-E3 说的正是「a migration」) 符合 D-E3 原文;但迁移跑之前查询仍然是错的,违反 D-B3「correctness must never be contingent」

倾向 A + B 并存,与 SQLite 完全对称:A 保证任何时刻的正确性,B 把代价降回可索引。但这需要在能跑真实 mongo 的环境里逐格验证。

验收

在真实 MongoDB 上,mongodb-temporal-conformance.test.ts 增加两条遗留 sweep(getDb().collection(x).insertMany(...) 直塞混合形态、绕过 toStorageForms),跑 TEMPORAL_CASES / TEMPORAL_TIME_CASES,行 id 集合与 canonical sweep 逐格相同——即 #4191 的轴规则。

关联

#4191(本体)、#4205#4047 / #3777 / #3912 / #3994;ADR-0053 D-B3 / D-C2 / D-E1 / D-E3。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions