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

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions