Mandatory native V4 relationship validation
原生 V4 关系的强制校验
Tool-role results cannot be checked through the released V3 user-role representation without projecting away current fields. Replacing that validation view requires a native reader to retain the earlier lifecycle, retired-syntax, and system-message checks. The representation change and its mandatory admission therefore belong together. An event can satisfy its TypeScript declaration and message rules while contradict
English
Problem
Tool-role results cannot be checked through the released V3 user-role representation without projecting away current fields. Replacing that validation view requires a native reader to retain the earlier lifecycle, retired-syntax, and system-message checks. The representation change and its mandatory admission therefore belong together.
An event can satisfy its TypeScript declaration and message rules while contradicting earlier durable events. A tool result without an advertised call and a checkpoint naming another compaction both contain locally valid fields. Accepting either as a current Session makes later readers depend on damaged relationships, and tightening admission after release can strand already-written histories.
Decision
The V4 format restorer and current JSONL scanner share one mandatory cross-event relationship pass before exposing a restored artifact or storage handle. It checks turn and step order, advertised tool calls and settlements, PTC parentage and settlement identity, retry chains and request providers, human-message title citations, command completion references, compaction ownership and current spans, and the protected system head. The installed event set controls semantic interpretation, including compaction prepasses and title references. Unknown ignorable records retain their payloads and original positions; known records remain validated even when marked ignorable. The check reads native event fields without altering artifacts or projecting them into a historical format. JSON argument comparisons inspect own properties in both Node and the worker; inherited prototype members cannot satisfy recorded fields. The tool-role decision owns result representation.
An unfinished tail may retain an open turn, step, tool call, or compaction. A closing event must settle the relationships it closes. An inherited unfinished compaction ends at its session/end-seed marker; it does not constrain the child's lifecycle. Repair message identities retain their historical numeric suffix after earlier migrations change sequence coordinates. Fork repairs retain their separately validated native identities.
Installed Session adoption continues to own event envelopes, message roles and metadata, canonical request headers, and surface replacement reference coverage. Native system-message admission also validates coordinates, identity, content blocks, and known image/tool-call fields before physical recovery can discard rows. Additional JSON fields and unknown nonempty content tags remain intact; retired tool-result wrappers are refused. Retired request/header.header.system and required tool/code-dispatch* tags remain hard refusals before recovery; obsolete ignorable PTC records remain opaque. Physical framing alone does not establish semantic validity.
A retired tool-result wrapper outside its owning tool/result row would require changing the event, role, or source to represent it in V4. The adjacent migration lifts only the canonical owned wrapper; target restoration refuses wrappers remaining in interpreted content. Native row admission applies the same refusal before recoverable tail suppression. The check follows declared message, content, and Assistant-stream slots instead of recursively inspecting JSON, so tool arguments, replay state, schema parameters, nested extensions, and unknown ignorable payloads retain their recorded values.
EpochHeader.system explicitly reserves the retired key as system?: never with @persistenceReserved. The catalog retains its empty value set so permitting a value is a change to a forbidden field, rather than an ordinary optional-field addition. The native reader and Session adoption continue to reject that key; system prompts remain system/message events.
Alternatives considered
Project V4 back into a frozen V3 validation view. This couples current acceptance to retired representations and invites new fields to disappear in the projection. Frozen generations remain independently readable, while the current restorer interprets its own fields.
Consequences
The native restorer maintains one bounded state machine per read and rejects contradictions before successor publication. Frozen V0–V3 validators and committed Session generations remain unchanged. Public catalog regressions cover invalid relationships alongside partial tails, inherited cuts, immutable unknown attribution, and complete tool exchanges; these checks enforce the declared V4 representation without changing its schemas. Breaking changes require a successor; compatible additions use new acknowledgements, and implementation fixes preserve the declared meaning.
中文
Problem
tool 角色结果不能通过已发布的 V3 user 角色表示进行校验,否则投影会丢弃当前字段。替代该校验视图后,原生读取方必须保留原有的生命周期、退役语法和 system 消息检查。因此,表示变更与必需的接纳校验需要一同完成。
事件即使符合 TypeScript 声明和消息规则,也可能与较早的持久化事件矛盾。没有声明调用的工具结果、指向另一压缩事务的检查点,都可以拥有局部有效字段。将它们接纳为当前 Session 会让后续读取器依赖损坏的关系;发布后再收紧准入则可能让已写入的历史无法读取。
Decision
V4 格式恢复器与当前 JSONL 扫描器共用同一强制跨事件关系校验,在公开恢复产物或存储句柄之前执行。它检查 turn 与 step 顺序、声明的工具调用及其结算、PTC 父子关系与结算身份、重试链与请求 provider、标题的人类消息引用、命令完成引用、压缩归属与当前区间,以及受保护的 system 首节点。已安装事件集合控制语义解释,包括压缩预扫描和标题引用。未知的可忽略记录保留其载荷与原始位置;已知记录即使标记为可忽略仍会接受校验。校验直接读取原生事件字段,不修改产物,也不将其投影为历史格式。Node 和 Worker 中的 JSON 参数比较都检查自有属性,继承的原型成员不能代替记录字段。工具角色决策负责结果表示。
未完成的尾部可以保留打开的 turn、step、工具调用或压缩事务。关闭事件必须结清它关闭的关系。继承的未完成压缩事务在其 session/end-seed 标记处结束,不约束子 Session 的生命周期。较早迁移改变序号坐标后,修复消息身份仍保留历史数字后缀。fork 修复保留经过独立校验的原生身份。
已安装的 Session 接纳器继续负责事件封装、消息角色与元数据、规范请求头,以及 surface 替换的引用覆盖。原生 system 消息准入还会在物理恢复可能丢弃行之前,校验坐标、身份、内容块及已知 image/tool-call 字段。额外 JSON 字段和非空的未知内容标签保持不变,退役的 tool-result 包装会被拒绝。退役的 request/header.header.system 和必需的 tool/code-dispatch* 标签仍在恢复前强制拒绝;标记为可忽略的过时 PTC 记录保持不透明。仅通过物理分帧不能证明语义有效。
退役的 tool-result 包装若不属于对应的 tool/result 行,就需要改变事件、角色或来源才能在 V4 中表示。相邻迁移只提升规范的自有包装;目标恢复器拒绝解释内容中剩余的包装。原生行准入在可恢复尾部被忽略之前执行同样的拒绝。检查沿声明的消息、内容和 Assistant stream 字段进行,不递归扫描 JSON,因此工具参数、replay state、schema 参数、嵌套扩展和未知可忽略载荷保留其记录值。
EpochHeader.system 通过带有 @persistenceReserved 的 system?: never 显式保留退役键。目录保留其空值集合,使允许某个值被识别为对禁止字段的修改,而非普通可选字段添加。原生读取方和 Session 接纳继续拒绝该键;系统提示词仍由 system/message 事件承载。
Alternatives considered
将 V4 投影回冻结的 V3 校验视图。 这会将当前准入与退役表示绑定,并容易让新增字段在投影中消失。冻结代际仍可独立读取,当前恢复器解释自己的字段。
Consequences
原生恢复器为每次读取维护独立状态机,在发布后继文件之前拒绝矛盾。冻结的 V0–V3 校验器及已提交的 Session 代际保持不变。公开目录回归覆盖无效关系、部分尾部、继承切分点、未知归属的不可变保存,以及完整工具交互;这些检查落实已声明的 V4 表示,不改变其 schema。破坏性变更要求后继版本;兼容新增使用新的确认记录,实现修复须保留声明的含义。