# Migration: schema_version 1.3 → 1.4 > **Type**: MINOR **but BREAKING for blind channel integrity**——state 字段不变,但 `rubric_notes.md` 必须拆开。**老用户跑 migrate 之前 blind sub-agent 仍泄漏实绩**。 --- ## WHAT changed ### 文件层(**核心**) | 之前 | 之后 | |---|---| | `rubric_notes.md` 顶部累积所有 bump Memo(含视频名 + 实绩 + 派生证据) | `rubric_notes.md` 只含通用语言(公式 / 维度定义 / bucket 边界 / 指针),**绝不**含实绩 | | —— | `rubric-memo.md`(**新**)累积所有 bump Memo 全文(含视频名 + 实绩 + 派生证据) | ### state 字段 无新增 / 删除 / 改名。仅 `schema_version` bump 标识本次"文件层迁移"必跑。 ### channel B hard refusal list `cheat-score-blind/SKILL.md` 加 `rubric-memo.md` 路径 + refusal_code `blocked_rubric_memo`。 --- ## WHY PR #11 引入 blind-scoring sub-agent(channel B)时承诺它只能读 `scripts/.md` + `rubric_notes.md`。但 cheat-bump Phase 5 落地时把升级 Memo(含证据数据表 + 派生证据 + 真实视频名 + 实绩)写进 rubric_notes.md ——sub-agent 通过白名单读到了本不该看的实绩数据,盲打分变成"看过实绩的事后合理化"。 实测复现(PR #11 测试): ``` contamination_note: rubric_notes.md v0→v1 bump memo 含本 script 同名条目「它让我发的 38w」实绩 contamination_note: rubric_notes.md 派生证据段含本 script 名+实绩 13.7w,CC 锚点被预先校准 → refusal: "non_blind_warning" → all dimensions confidence: medium ``` 修复:拆 file。`rubric_notes.md` 严格只放通用规则(blind 白名单),bump 历史档案沉淀到 `rubric-memo.md`(blind 硬禁读)。详见 [shared-references/observation-lifecycle.md](../shared-references/observation-lifecycle.md) "Blind channel leak guard" 段。 --- ## HOW (Claude steps for /cheat-migrate) 按顺序执行。**不可幂等的步骤要先检查是否已跑过**——本迁移涉及内容文件改写,重跑可能产生重复内容。 ### Step 1:前置检查 1. 读 `.cheat-state.json` → 校验 `schema_version == "1.3"`,否则报错"当前 state 不是 1.3,无需此迁移" 2. 检查 `rubric_notes.md` 存在;不存在 → 报错"找不到 rubric_notes.md。是不是项目还没 init?" 3. 检查 `rubric-memo.md` **是否已存在**: - 已存在 → 询问用户"rubric-memo.md 已有内容,跳过 split 直接 bump schema 到 1.4?回 yes 跳过,回 no 中止迁移" - 不存在 → 进 Step 2 ### Step 2:备份 ```bash cp rubric_notes.md rubric_notes.md.backup-$(date +%s) ``` 提示用户:"已备份 `rubric_notes.md` —— 拆分若出错可恢复"。 ### Step 3:扫描 + 抽离 `rubric_notes.md` 的违禁段 读 `rubric_notes.md` 全文。识别下列 pattern: | Pattern | 处理 | |---|---| | 整段 `## v.X → v.Y 升级 Memo` 含子段(触发观察 / 证据数据 / 诊断 / 跨模型审核 / 已知局限) | **整段抽离**到 rubric-memo.md,原位**删除** | | 派生证据段中带视频名 + 数字(如「停止期待」实绩 13.7w) | **整条抽离**到 rubric-memo.md 的"派生证据"子段;原位用通用语言替代("高抽象密度样本 → CC=1 → 低 reach") | | 校准池重打表 / 排序对照表 | **整表抽离**到 rubric-memo.md 对应 Memo 的"证据数据"子段;原位删除(公式速查表保留——公式速查不含视频名) | | 跨模型审核引用含具体视频名 + 实绩 | 抽离 | | 散落的 `\d+w` / `\d+万` 数字(**例外:bucket 边界** 5-30w / 30-100w 等保留) | 用 Claude 判断:是 bucket 边界 → 保留;是实绩引用 → 抽离 | ### Step 4:写 `rubric-memo.md` 如果文件不存在 → 从 `cheat-on-content/templates/rubric-memo.template.md` 复制空骨架。 然后把 Step 3 抽离出来的 Memo 段**按时间顺序**(旧的在上 / 新的在下)append 到文件末尾。每段 Memo 用 [templates/rubric-memo.template.md](../templates/rubric-memo.template.md) 的 6 组件格式包装;缺组件的标 `(unknown from legacy migration)`。 ### Step 5:清理 `rubric_notes.md` - 顶部 metadata 段加: ```markdown **Upgrade memos**: 见 [rubric-memo.md](rubric-memo.md) ``` - Memo 段被 Step 3 抽走的部分留**短指针**:"v0→v1 升级 Memo 已迁移到 rubric-memo.md,跑 `cat rubric-memo.md` 查看" - 派生证据段替换为通用语言 ### Step 6:自检 leak guard 对清理后的 `rubric_notes.md` 跑: ```bash grep -E '\d+\s*[wWmMkK万]|播放|实绩|实际' rubric_notes.md \ | grep -v -E '^\s*\|[^|]*\|[^|]*\|.*[0-9]+\s*[wkM][^a-zA-Z]' \ | grep -v -E '5-30w|30-100w|100-150w|>150w' ``` (grep 排除明显的 bucket 边界数字) - 无命中 → 通过 - 命中 → 报告剩余的"实绩引用" + 让用户手工 review / 进一步抽离 → 继续 Step 7 或中止 ### Step 7:bump schema + 写回 state 1. 设 `.cheat-state.json` 的 `schema_version = "1.4"` 2. **原子写** 3. 报告:"✅ 迁移到 1.4 完成。`rubric_notes.md` 现仅含通用语言({N} 行),`rubric-memo.md` 含 {M} 段历史 Memo。备份保留:rubric_notes.md.backup-{ts}。" --- ## Manual fallback 不想跑 `/cheat-migrate` 的用户可以**手动拆**: 1. 备份:`cp rubric_notes.md rubric_notes.md.backup` 2. 把所有 `## v.X → v.Y 升级 Memo` 段从 `rubric_notes.md` 整体剪切到**新建**的 `rubric-memo.md`(按时间顺序保留) 3. 把派生证据段的视频名 + 实绩剪到 rubric-memo.md,原位用通用语言替代 4. 在 `rubric_notes.md` 顶部加 `**Upgrade memos**: 见 [rubric-memo.md](rubric-memo.md)` 指针 5. 手改 `.cheat-state.json` 的 `schema_version` 为 `"1.4"` 或者**最懒**:删 `rubric_notes.md` 重 init(损失:所有历史观察 + bump memo),跑 `bash install.sh` 后说"初始化"——cheat-init 会重新创建两份空文件。仅适合校准池还很小(< 5 条)的早期用户。 --- ## 验收 迁移完成后: ```bash # state 升到 1.4 jq '.schema_version' .cheat-state.json # → "1.4" # rubric_notes.md 无实绩泄漏 grep -E '播放|实绩|实际|\d+w[^a-zA-Z0-9]' rubric_notes.md \ | grep -v -E '5-30w|30-100w|100-150w|>150w' \ | head # → 应输出空(除 bucket 边界) # rubric-memo.md 含历史 Memo ls -la rubric-memo.md wc -l rubric-memo.md # → 行数 > 50(取决于历史 bump 次数) # blind sub-agent 不再标 non_blind_warning # 跑 /cheat-score scripts/<已发样本>.md # → JSON.refusal == null, JSON.self_check.any_contamination_signal == false ```