DSH / Atlas
2026-09-19implementedarchitecturearchived 2026-09-30

Lossless projection checkpoint JSON

无损投影检查点 JSON

Projection checkpoints can contain opaque extension data and message metadata. A JSON key named `__proto__` is ordinary recorded data. The Zod JSON parser drops that own key while rebuilding objects, so reopening a valid checkpoint can yield different projection state from replaying the Session log.

English

Problem

Projection checkpoints can contain opaque extension data and message metadata. A JSON key named __proto__ is ordinary recorded data. The Zod JSON parser drops that own key while rebuilding objects, so reopening a valid checkpoint can yield different projection state from replaying the Session log.

Decision

The checkpoint value schema uses the existing isJsonValue predicate from dsh-util-values. It enforces the same lossless JSON rules as the checkpoint writer's snapshotJsonValue without rebuilding valid objects. Validation still rejects non-JSON and lossy values. Storage-domain table values are immutable borrowed records; the validator does not supply a defensive-copy guarantee.

Alternatives considered

  • Keep z.json(). Its object reconstruction removes valid own keys, so a successful validation can still change the checkpoint value.
  • Validate and clone with snapshotJsonValue. This preserves keys but copies already immutable stored values. The read-only predicate matches the storage-domain borrowed-value contract.

Consequences

Domain reads preserve every valid own key in checkpoint values, including nested __proto__ and constructor properties. A projection's stateSchema still owns its hydration value; opaque fields must use validation that preserves their keys. The borrowed-value validator does not create an independent copy or project to JSON Schema.

The domain version remains unchanged because the stored JSON representation is unchanged; this corrects its reader. Regression coverage opens a synthetic fixture produced by the real writer, then writes, closes, and reopens it through StorageDomain. Session format versions and historical generations do not change. Predecessor recovery and Session-format binding continue to own cache-version and identity compatibility.

中文

问题

投影检查点可以包含不透明扩展数据和消息元数据。名为 __proto__ 的 JSON 键是普通记录数据。Zod JSON 解析器在重建对象时丢弃该自有键,因此重新打开有效检查点可能得到与回放 Session 日志不同的投影状态。

决策

检查点值 schema 使用 dsh-util-values 中既有的 isJsonValue 谓词。它执行与检查点写入器 snapshotJsonValue 相同的无损 JSON 规则,不重建有效对象。校验仍拒绝非 JSON 和有损值。Storage-domain 表值是不可变的借用记录;校验器不提供防御性复制保证。

备选方案

  • 保留 z.json()。 其对象重建会移除有效自有键,因此校验成功仍可能改变检查点值。
  • 用 snapshotJsonValue 校验并复制。 这能保留键,但会复制已经不可变的存储值。只读谓词符合 storage-domain 的借用值约定。

影响

Domain 读取保留检查点值中的每个有效自有键,包括嵌套的 __proto__ 和 constructor 属性。Projection 的 stateSchema 仍拥有其 hydration 值;不透明字段必须使用保留其键的校验器。借用值校验器不生成独立副本,也不投影为 JSON Schema。

存储 JSON 表示未变,因此 domain 版本不变;本修改修正其读取器。回归测试打开真实写入器生成的合成 fixture,再通过 StorageDomain 写入、关闭并重新打开。Session 格式版本与历史代际不变。前代恢复与 Session 格式绑定 继续负责缓存版本与身份兼容性。