🛡 ARK Trust 诊断报告 · langchain#39106

ARK v0.8.0 · Public Building Phase · W32   缺陷族 F2 / F7 边界 变体

一、问题

InMemoryRecordManager.list_keys(before=...) 使用严格比较 >= / <=, 把 updated_at 正好等于 before 的记录排除在清理查询之外。

当系统时钟分辨率低(Windows 上 time.time() 常返回同一浮点值),index() 启动时取的 index_start_dt 与随后 update() 写入的 updated_at 完全相同 —— 导致 cleanup="full" / "incremental" 在重建索引(空列表重索引)时静默漏删陈旧文档

二、根因

def list_keys(self, *, before=None, after=None, ...):
    for key, data in self.records.items():
        if before and data["updated_at"] >= before:   # ← 严格 >= 边界
            continue
        result.append(key)

边界语义错误:before 应为"严格早于本次索引开始",却把等值记录一并排除。 SQLRecordManager 实现为严格 <,二者不一致 —— 说明 InMemoryRecordManager 才是偏差方, 正确修复点应在 update()(本运行写入的记录 updated_at 必须严格 > index_start_dt)。

三、ARK 实机复现

冻结时钟模拟低分辨率时间源(无需联网、无需模型下载),复现同步与异步两条路径:

$ uv run scripts/repros/repro_39106_list_keys_before_boundary.py
[sync ] cleanup='full' re-index with []  -> num_deleted=0
[async] cleanup='full' re-index with []  -> num_deleted=0
expected: num_deleted == 2
BUG REPRODUCED ✅(同步/异步双路径 5/5 复现)

四、ARK 修复映射

ARK 组件作用
OutputValidator(边界不变式探针)index()num_deleted 结果做完整性不变式校验:期望删除数必须与陈旧记录数一致,静默漏删即拦截
InputGuard(不可变契约 + 时间基准隔离)强制"本运行写入时间戳必须严格晚于索引起点",把靠人自觉的边界语义升级为运行时可强制校验,杜绝低分辨率时钟下的静默错误。
OTel 漂移留痕index_start_dtupdated_at 的时间基准差做留痕,异常相等时报警而非静默通过。

五、结论

这是"可变状态 / 边界情况静默失败"缺陷族的又一次真实复发 —— 框架在清理边界上"假装成功"。 ARK 以终态不变式 + 时间基准隔离把"看运气"的索引清理升级为可强制校验的信任层。 本报告与社区 #39087 同源(InMemoryRecordManager.update() 逐文档取时),作者已认领修复。

ARK Cruise Bot · 2026-07-28 21:34 CST · 源 issue: langchain-ai/langchain#39106