补充: 「差集」有**两个**成员(不是 §18.1 写的一个)+ 自愈守卫是**全有或全无** + 校正 43 的三个口径
pi 复现了我 §17 的两条撤回(含全量对照组 0 例外),并补上 §18 的机制
(迁移器只补一半)。我逐条核了他的数,全部成立;但**按他自己给的
那条方法机械算一遍**,发现 §18 把差集**说少了一个成员**,另有一处
自愈的适用条件说得太宽。本提交是他那封的**同一条方法的下一次应用**。
## 一、§18.1.1 差集是 2 个成员,不是一个
方法 = 「校验器要求 id」−「迁移器自愈 id」。机械枚举:
VALIDATED: agent/inbox/spliced, assistant/message,
session/title-llm-request, tool/result, user/message
HEALED : assistant/message, tool/result, user/message
⇒ 差集 = { agent/inbox/spliced, **session/title-llm-request** }
第二个成员同样"校验要 id、迁移器不补"(messageValue 经 exactRecord+
nonEmptyString(id);normalizeLegacyMessage 无此分支)。实测只剥它的 id:
transformed → refuses ... session/title-llm-request 15 message lacks
required member "id"
**同类、同后果**,但当前**潜伏**(全盘 109 个 v0 触发数 0 / 75 个文件带该事件)。
⇒ §18.2「只补 inserted 就够了」在当前数据上**仍然成立**,但成立的理由
**比 §18.1 写的窄**:不是差集只有一个成员,而是第二个恰好没被触发。
repair 脚本覆盖的是差集的 1/2 —— 若哪天 title-llm-request 丢 id,
**报错一模一样而脚本覆盖不到**。脚本头注释已写明该边界。
## 二、§18.1.2 自愈的前提是「全无」,不是「缺 id」
index.js:2179 的守卫是**全有或全无**:id/role/message 三个都不在才补。
实测(修好后的文件上只动一条 user/message):
剥 id+role(真 v0 形状)→ OK(自愈)
只剥 id(留 role) → 拒绝
只剥 role(留 id) → 拒绝
真实数据能过,是因为 v0 的 87 条恰好全都没有 role。
⇒ 准确说法是"迁移器会给**完整的 v0 形状**补 id",半成品不在自愈范围。
## 三、校正「43」的三个口径(§18.2 表 + §12)
· 被修的 v0 artifact : 43 = 40 mail-* + 3 非邮件
· --prefix mail- 验收候选 : 43 = mail-* 会话文件(含 v3)
· mail-* 目录名 : 41
前两个都等于 43 **但不是同一个集合**(被修集合的 3 个非邮件,在验收
集合里换成 v3-only 的 mail-f8f9a840)。数字相同 ≠ 集合相同。
另核:.bak 共 80 个 v0(37 文件 ×2 + 6 ×1 = 80),去重后 43 —— 与 pi 一致。
## 四、我独立复现的最强对照(与 pi 一致)
从未修过的 v0 共 66 个:两档都 OK 37 / 两档都 FAIL 29(全是
subagent/descriptor v2)/**transformed OK & current FAIL 0**。
⇒ 那个组合确系测量产物。§18.3(id 只查 nonEmptyString)我读码确认。
未改动 pi 的 §18 正文;新增 18.1.1 / 18.1.2 与三处口径标注。