fix(snapshot): stabilize refresh volatiles

This commit is contained in:
Dudu-0223
2026-07-27 14:58:38 +08:00
parent 79eb3a9035
commit 82637524a3
8 changed files with 252 additions and 10 deletions

View File

@@ -0,0 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-07-27-stable-snapshot-refresh-volatiles.md
2026-07-27-stable-snapshot-refresh-volatiles.md: e6bff6ef4d20b431cee86d16df863a7c7b138e02
2026-07-27-stable-snapshot-refresh-volatiles.zh.md: 33acbbc0504ca1b61495cbb95a0f6dec28dfa0df

View File

@@ -0,0 +1,29 @@
# Agent Note: Stable snapshot refresh volatiles
Status: implemented
English | [中文](2026-07-27-stable-snapshot-refresh-volatiles.zh.md)
## Problem
ACP snapshot comparison normalizes generated UUIDs, cwd aliases, spill locators, embedded event times, and omitted-byte counts, but refresh write-back persisted the fresh raw values. A behaviorally unchanged refresh therefore rewrote fixtures with new randomness or host-specific path spellings even though the comparison contract considered both logs equal.
## Decision
Refresh write-back uses `normalizeSessionLog` as its sole volatile-value authority. After existing record alignment, it recursively compares fresh and existing leaves through their normalized records: normalized-equivalent leaves retain the existing raw value, while normalized-distinct leaves retain the fresh semantic value.
Object fields align by key. Array elements align only when all corresponding arrays have the same length; otherwise the fresh array wins. Records must retain the same type, and strings remain atomic leaves. Existing packed-chunk timing alignment and inserted-title handling remain separate because they align logical events rather than values inside one record.
## Alternatives considered
**Use deterministic UUIDs and spill filenames in snapshot deployments.** Replacing production randomness would weaken the security shape under test or require test-only behavior in storage and approval implementations.
**Commit normalized fixtures.** Tokenized session logs would stop being raw replay inputs and would cause a broad fixture migration unrelated to the write-back defect.
**Preserve a whole record when its normalized form is unchanged.** This is simpler but churns a random field whenever another field in the same record changes semantically. Leaf-level preservation keeps those decisions independent.
## Consequences
Repeated refreshes no longer rewrite aligned fixture values solely because the normalizer classifies them as volatile, and new volatile categories added to the normalizer automatically inherit the write-back behavior. Structural ambiguity remains conservative: changed record types, resized arrays, and strings containing both semantic and volatile changes use fresh values rather than risk reusing misaligned data.
Focused unit coverage pins recursive object/array behavior, volatile strings, and fresh semantic fields. Keyless refresh coverage proves approval UUIDs, cwd aliases, spill paths, and event-read volatility leave their committed fixtures byte-identical.

View File

@@ -0,0 +1,29 @@
# Agent Note: 稳定快照刷新中的易变值
Status: implemented
[English](2026-07-27-stable-snapshot-refresh-volatiles.md) | 中文
## 问题
ACPAgent Client Protocol快照比较会归一化生成的 UUID、cwd 别名、spill locator、嵌入的事件时间和省略字节数但刷新写回会持久化本次生成的原始值。因此即使比较契约将两份日志视为相等一次行为未发生变化的刷新仍会用新的随机值或宿主特有的路径写法改写 fixture测试前置数据
## 决策
刷新写回以 `normalizeSessionLog` 作为易变值的唯一判定依据。现有记录完成对齐后,系统基于归一化后的记录,递归比较本次生成记录与现有记录的叶节点:归一化后等价的叶节点保留现有原始值,归一化后不同的叶节点则保留本次生成的语义值。
对象字段按键对齐。只有所有对应数组长度相同时,才对齐其元素;否则以本次生成的数组为准。记录必须保持同一类型,字符串始终作为不可拆分的叶节点。现有的打包分片计时对齐与插入标题处理仍保持独立,因为它们对齐的是逻辑事件,而非单条记录内的值。
## 考虑过的替代方案
**在快照部署中使用确定性的 UUID 和 spill 文件名。** 替换生产环境使用的随机性会削弱测试所要验证的安全属性,或者要求存储与审批实现引入仅用于测试的行为。
**提交归一化后的 fixture。** token 化的会话日志将不再是原始回放输入,并会引发与写回缺陷无关的大范围 fixture 迁移。
**当整条记录的归一化形式未变时保留整条记录。** 这种做法更简单,但同一记录中的另一个字段发生语义变化时,也会改写其中的随机字段。按叶节点保留可使这些决策彼此独立。
## 后果
重复刷新不再仅仅因为规范化器将已对齐的 fixture 值归类为易变值,就改写这些值;以后加入规范化器的新易变值类别也会自动继承该写回行为。结构有歧义时仍采取保守策略:记录类型发生变化、数组尺寸发生变化,或字符串同时包含语义变化与易变变化时,均使用本次生成的值,避免冒险复用未对齐的数据。
聚焦的单元测试固定了递归处理对象与数组的行为、易变字符串以及本次生成的语义字段。无密钥刷新测试证明,审批 UUID、cwd 别名、spill 路径和事件读取中的易变值不会改变已提交 fixture 的任何字节。