---
name: learn-from-history
description: >
  审计近期对话历史，把重复失败与成功模式转成可证伪的 harness 改进契约，并在后续审计中归因。
  用户要求总结历史对话、回顾近期 agent 表现、从历史中学习或寻找可自动化改进时使用。
---

# Learn From History

把历史学习当成一个**可观测改进环**，而不是经验摘抄：固定输入，分层下钻证据，定位最窄变更面，为每项建议同时声明预测收益与回归风险，再由后续历史验证。

默认审计当前项目最近 7 个自然日期（含今天），不跨项目。默认只报告；用户已明确要求应用建议或提交时，按其授权范围完成，不重复确认。报告和 decision manifest 本身不扩大编辑、回滚或发布权限。

本流程采用 [Agentic Harness Engineering](https://arxiv.org/abs/2604.25850) 的三层可观测思想，并适配为有人确认的项目审计：

1. **组件可观测**：每个失败模式只归属一个首选变更面；
2. **经验可观测**：最终概览可下钻到 unit finding，再到固定 snapshot 的原始 thread；
3. **决策可观测**：每个变更建议都是带收益预测、回归风险和验收条件的可证伪契约。

## 事实源

- 运行编排与 unit prompt：`scripts/run_history.py`
- 提取逻辑：`scripts/extract_daily.py`
- run 与 decision manifest 校验：`scripts/validate_run.py`
- unit 报告格式：`references/analysis-template.md`
- 跨轮决策账本：`spec/reviews/history-learn-YYYY-MM-DD.json`

`extract_range.py` 仅保留手工范围导出的兼容用途，不是主路径。

## 流程

### 0. 核对当前仓库的入口、产物位置与授权

先读根指引和 `docs/standards/documentation.md`。本仓库的维护入口是本文件及相邻 `scripts/`；其他安装目录中的旧副本不能替代受版本控制的实现。显式保留本轮用户要求的日期、项目、更新范围与提交授权，交接后从原始请求核对，不让压缩摘要重新解释权限。

本仓库按 `DOC-HISTORY-001` / `DOC-LINK-001` 禁止重建 `spec/reviews/`，因此使用**临时报告模式**：报告与变更/验收记录写到本次 run 目录，稳定结论更新对应事实源；完整过程不进入仓库。该模式执行步骤 1–4、6 和已授权的编辑，使用 run validator 验证输入覆盖；步骤 5 和步骤 7 的持久 decision ledger 分支不适用，不声称通过 decision ledger 校验或形成跨轮因果归因。完成后按步骤 9 的临时模式清理输入。后文的 `spec/reviews/` 账本协议仅用于明确允许该目录的仓库，不能借技能恢复已废弃目录。

### 1. 创建 snapshot run

从环境中的 Working directory 取得项目根，显式传入 `--cwd`：

```bash
python3 .claude/skills/learn-from-history/scripts/run_history.py \
  --days 7 \
  --cwd <工作目录>
```

只有用户明确要求跨项目时才使用 `--all`：

```bash
python3 .claude/skills/learn-from-history/scripts/run_history.py --days 7 --all
```

脚本创建权限为 `0700` 的唯一目录：

```text
/tmp/learn-from-history/<run_id>/
  manifest.json
  snapshot/threads.db
  extracted/<day>/*.txt
  prompts/unit-NNN.txt
  summaries/
```

它通过 SQLite backup 固定本次审计的数据边界，提取物权限为 `0600`。`manifest.json` 是本次运行的唯一输入清单，记录 snapshot digest、`repository_root`、日期、thread、消息数、输入 digest、降级统计和分析单元。

**完成标准**：命令 exit 0，manifest `status=ready` 或 `status=empty`。任一日期失败时命令必须 exit 非零；不得分析部分成功结果。`empty` 时报告近期无记录并结束。

### 2. 检查 manifest

Read `manifest.json`，核对：

- `project_filter` 或 `all_projects` 与用户范围一致；
- `window.active_days`、`totals.thread_count`、`totals.message_count`；
- `totals.truncations` 与 `totals.parse_failures`；
- 每个 `unit` 的输入、消息数、prompt、summary 和 sidecar 路径。

再试读窗口两端及不同消息格式的 thread：有消息计数却只有空白正文、工具调用消失或系统提醒被当成用户原话时，先检查提取器与持久化协议。`parse_failures=0` 不单独证明内容完整。格式契约以 `peri-acp-types/src/store.rs` 和 `messages/` 为准；修改提取器须用 legacy/V1 的真实 SQLite 往返、工具配对与损坏输入回归验证，不只测 JSON helper。修复后从同一 snapshot 补提取，记录旧/新 manifest 与 extractor digest，重审变化的输入；不得沿用旧 digest 或旧行号宣称完成。

本流程按 thread 的 `updated_at` 日期归档**完整 thread**，不按消息切断因果链。报告中写清该语义。

不要扫描 run 目录猜测输入，也不要读取其他 run 的同名文件。

### 3. 执行分析单元

每个 unit 的完整任务已经写入 `prompts/unit-NNN.txt`。派发 `general-purpose` agent 时，把该 prompt 文件内容作为任务；子 agent 自己直接 Read/Write，不得再次调用 Agent，不得修改仓库。

调度规则：

- 1 个 unit：同步执行；
- 2 个以上独立 unit：可后台并行，无固定并发上限；
- unit 较多时：分批启动，当前批次全部收到终态后再启动下一批；
- agent 失败时优先 resume 原 child thread，不创建重复任务；
- background 的 started/completed 通知不是通过证据，不轮询未完成结果。

单元按 thread 文件大小和数量规划，不机械按天切分；大日期可拆成多个 unit，小日期可合并。每个 agent 必须同时写：

- `summaries/unit-NNN.md`：thread 结果和跨 thread finding；
- `summaries/unit-NNN.json`：`status=analyzed`、输入 digest、覆盖数、finding 契约和降级复核。

优先比较相同或相近意图中的成功/失败轨迹，找出**分歧点**；它比单独阅读失败更能区分能力缺口、随机执行偏差和 harness 缺陷。每条 finding 的证据与反证必须写成：

```text
extracted/<day>/<thread>.txt :: <可定位摘录或事件>
```

原始 thread 是证据层，不是默认阅读入口；先读 unit finding，主张不足时再下钻。输入中有 `[TRUNCATED ...]` 或 `[MESSAGE_PARSE_FAILED]` 时，必须人工评估该 thread 是否仍足够支撑 finding，并在 `degraded_inputs_reviewed` 登记；证据不足则写入 `blocked`，不得外推。

### 4. 机器校验经验层

所有 unit 终态后运行：

```bash
python3 .claude/skills/learn-from-history/scripts/validate_run.py \
  /tmp/learn-from-history/<run_id>
```

validator 检查：

- summary 非空且不是 `null`；
- sidecar unit ID、`status=analyzed`、thread 数和消息数；
- 输入文件集合与 manifest 完全相等，digest 未变化；
- 降级输入已显式复核，没有 blocked 输入或 extraction failure；
- finding 含 classification、failure pattern、root cause、可下钻 evidence/counterevidence、带分母 frequency、impact、confidence、fact source；
- finding 已选择 target surface，解释归属，并声明 predicted fixes、risk regressions 与 acceptance。

**完成标准**：命令 exit 0 且 `validation.json` 为 `passed`；其 `attestation` 记录本次实际读取的 manifest digest 与完整 sidecar `{unit_id, path, sha256}` 集合，供同日 decision ledger 复写并在后续审计中三方核对。失败 unit 优先 resume；校验通过前不得汇总或宣称完成。

### 5. 归因上轮决策

在汇总新建议前，按日期读取当前项目 `spec/reviews/` 中相关的 `history-learn-*.json`。只处理 `status=implemented`、含实施验证，且未被任何更新账本给出经保留的 `validation.json`、manifest digest 和 unit sidecar 共同证明的 `keep | revert` 终局 verdict 的变更；自报或已丢失 run 证据的终局不生效，`improve` 与 `inconclusive` 保持待观察。

对每个 prior change：

1. 将 `predicted_fixes` 与本轮观察到的改善逐项对照；
2. 主动检查 `risk_regressions`，并从旧有成功模式中选择至少一个 preserved-success probe；
3. 区分“改动后发生”与“由改动导致”；没有同类对照、明确分歧点或独立验收时，不声称因果；
4. 给出 `keep | improve | revert | inconclusive | not_implemented` verdict；
5. `revert` 只是建议，仍需用户确认，且必须说明恢复范围与保留哪些有效部分。

历史窗口未覆盖实施前基线、相关场景未再次出现、运行环境或模型改变时，verdict 必须是 `inconclusive`，不能用“未再出现失败”冒充修复成功。

### 6. 聚合、去重与组件归属

只读取当前 manifest 列出的 unit summary/sidecar。每条 finding 先分类：

- `rule_gap`：真实稳定规则缺口；
- `active_issue_covered`：已有 active issue，禁止复制事故叙事；
- `skill_gap`：现有 skill 缺指引或触发失败；
- `execution_deviation`：规则已覆盖但未遵循；
- `external_blocker`：环境、权限、provider 或平台阻塞。

再读取当前项目根路由和 finding 所需的最小事实源：

- 根 `CLAUDE.md`：判断项目哲学与路由，不复制工程细则或事故叙事；
- `docs/standards/` 与测试 canonical standard：稳定规则；
- 对应模块 `CLAUDE.md`：模块入口和专属不变量；
- `spec/issues/`：active change、事故验收和具体产品风险；
- `spec/global/problems.md`：历史索引；
- `DiscoverSkillsTool`：当前 skill catalog。

按**最窄有效层**选择一个首选 target surface：

| 失败根因 | 首选面 |
| --- | --- |
| 稳定工程约束缺失 | standard 或 module guidance |
| 产品行为/架构缺陷 | active issue，再落到 implementation + test |
| 可复用但按需触发的工作流缺失 | skill |
| 工具说明或 schema 让模型误用现有能力 | tool description |
| 工具能力、错误恢复或输出形态不足 | tool implementation |
| 需要跨步骤观察、拦截或完成门 | middleware |
| 需要隔离上下文或专门角色处理独立子任务 | subagent |
| 多轮重复出现且跨任务稳定的边界经验 | memory |
| 参数/注册/权限装配错误 | configuration |
| 已有规则未执行，且无结构性缺口 | none；记录 execution deviation |
| 外部平台或权限阻塞 | external |

不要默认把所有教训塞进 prompt、规则或本 skill。论文消融显示组件收益不相加，重复约束会增加冗余检查；若多个候选面表达同一防线，只保留执行力最强且副作用最小的一层，其他层仅在有独立证据时补充。

只有多次证据、影响明确且存在事实源缺口时才建议新稳定规则；单次事件默认不制度化。若可观测，记录消息数、重复工具调用、错误重试或耗时等效率代理，但不能以“更短”替代任务正确性。

### 7. 生成报告与 decision manifest

**临时报告模式**：写入本次 run 的 `findings.md` 与 `changes.json`，记录范围、证据/反证、已有覆盖、采用或未采用的建议、目标与保留行为的验收及实际结果。引用已通过 run validator 的 unit sidecar；不传 `--decision-manifest`，不把这份临时记录称为已认证的跨轮账本。没有可核对的旧账本时，旧建议的效果为 `inconclusive`。随后按已有授权进入步骤 8。

**持久账本模式（仅允许 `spec/reviews/` 的仓库）**：

写入同日配对产物：

```text
spec/reviews/history-learn-YYYY-MM-DD.md
spec/reviews/history-learn-YYYY-MM-DD.json
```

Markdown 报告至少包含：

1. snapshot 截止时间、项目过滤和“按 thread updated_at 归日”语义；
2. 日期、thread、消息、unit、截断和解析失败统计；
3. prior change attribution 与 verdict；
4. finding 的根因、可下钻证据/反证、频次、影响、置信度与事实源；
5. 稳定规则候选、skill 候选、已有覆盖、成功模式；
6. validation 结果和 blocked 项；
7. 结构化 change plan。

JSON 是决策账本，至少包含：

```json
{
  "version": 1,
  "run_id": "<snapshot run id>",
  "source_run_dir": "/tmp/learn-from-history/<run_id>",
  "source_manifest_sha256": "<manifest.json sha256>",
  "source_sidecars": [
    {
      "unit_id": "unit-NNN",
      "path": "summaries/unit-NNN.json",
      "sha256": "<sidecar sha256>"
    }
  ],
  "project_filter": "<project root or null>",
  "prior_attribution": [
    {
      "source": "spec/reviews/history-learn-YYYY-MM-DD.json",
      "change_id": "CHG-001",
      "verdict": "keep|improve|revert|inconclusive|not_implemented",
      "rationale": "<为何该证据支持此 verdict；区分时序相关与因果>",
      "observed_fixes": [
        {
          "source_finding": "unit-NNN/F-NNN",
          "source_run_id": "<本轮 snapshot run id>",
          "source_manifest_sha256": "<本轮 manifest.json sha256>",
          "finding_contract": {
            "id": "F-NNN",
            "classification": "<本轮 finding classification>",
            "failure_pattern": "<本轮 finding failure_pattern>",
            "root_cause": "<本轮 finding root_cause>",
            "target_surface": "<本轮 finding target_surface>",
            "predicted_fixes": [],
            "risk_regressions": [],
            "acceptance": {"target": [], "preserved_success": []}
          },
          "finding_digest": "<finding_contract 的规范 SHA-256>",
          "prior_contract": "<旧 change.predicted_fixes 中的原文>",
          "outcome": "fixed|improved|unchanged|regressed|not_observed",
          "observed_delta": "<本轮观察到的脱敏变化>"
        }
      ],
      "observed_regressions": [
        {
          "source_finding": "unit-NNN/F-NNN",
          "source_run_id": "<本轮 snapshot run id>",
          "source_manifest_sha256": "<本轮 manifest.json sha256>",
          "finding_contract": {
            "id": "F-NNN",
            "classification": "<本轮 finding classification>",
            "failure_pattern": "<本轮 finding failure_pattern>",
            "root_cause": "<本轮 finding root_cause>",
            "target_surface": "<本轮 finding target_surface>",
            "predicted_fixes": [],
            "risk_regressions": [],
            "acceptance": {"target": [], "preserved_success": []}
          },
          "finding_digest": "<finding_contract 的规范 SHA-256>",
          "prior_contract": "<旧 change.risk_regressions 中的原文>",
          "outcome": "fixed|improved|unchanged|regressed|not_observed",
          "observed_delta": "<本轮观察到的脱敏变化>"
        }
      ]
    }
  ],
  "changes": [
    {
      "id": "CHG-001",
      "status": "proposed|implemented|blocked",
      "source_findings": ["unit-NNN/F-NNN"],
      "classification": "skill_gap",
      "failure_pattern": "<observable pattern>",
      "root_cause": "<causal hypothesis>",
      "baseline": "<当前 snapshot 中脱敏的发生率、成功率或具体现状>",
      "target_surface": "skill",
      "files": ["<repository-relative path>"],
      "why_this_surface": "<component choice>",
      "predicted_fixes": ["<next-run observable outcome>"],
      "risk_regressions": ["<preserved behavior at risk>"],
      "acceptance": {
        "target": ["<target check>"],
        "preserved_success": ["<preserved-success check>"]
      },
      "verification": []
    }
  ]
}
```

一个 logical change 对应一个 entry；不要把跨组件“大改造”打包成不可归因的一项。`baseline` 必须保留当前 snapshot 中脱敏、可比较的发生率或具体现状，因为 `/tmp` 原始输入清理后它是下轮归因的参照。`source_sidecars` 必须逐项复制本轮 `validation.json.attestation.sidecars`，与 `source_manifest_sha256` 一起把 canonical repository ledger 绑定到实际通过校验的 unit sidecar；旧 ledger 缺此字段时历史终局 fail closed，但该 change 仍可在新账本中重新归因。change 的 `classification`、`target_surface` 与 `acceptance` 不能脱离所引用 finding；可以追加检查，但不能省略 finding 已声明的检查。`acceptance.target` 与 `acceptance.preserved_success` 各至少一项，按折叠空白后的文本全局唯一。`proposed` 时 `verification` 为空；实施后每个 acceptance 恰好对应一个 `{check, command, status, result}`，且全部为 `passed`。prior attribution 的 observation 必须同时绑定当前 `source_finding`、本轮 run/manifest、`finding_contract` 及其规范 digest、旧 change 中逐字匹配的 `prior_contract`、受限 `outcome` 和本轮 `observed_delta`；`finding_contract` 取 validator 定义的核心 finding 字段。`keep` 至少需要 `fixed|improved` 且不能有 `regressed`，`revert` 至少需要 regression observation 的 `regressed` 且不能同时声称修复。不能用无关 finding 与自由文本拼出强 verdict。建议必须列出至少一个预测修复、一个回归风险或明确的 no-risk 理由，以及目标验收和 preserved-success 验收。报告和 JSON 都必须脱敏，不复制凭据、认证头、完整用户数据或本机私密配置。

生成后运行：

```bash
python3 .claude/skills/learn-from-history/scripts/validate_run.py \
  /tmp/learn-from-history/<run_id> \
  --decision-manifest spec/reviews/history-learn-YYYY-MM-DD.json
```

如果校验的是旧 v1 `--all` run，manifest 可能没有 `repository_root` 且 `project_filter=null`；此时必须显式绑定账本所属仓库，不能从 decision 路径静默推断：

```bash
python3 .claude/skills/learn-from-history/scripts/validate_run.py \
  /tmp/learn-from-history/<run_id> \
  --decision-manifest spec/reviews/history-learn-YYYY-MM-DD.json \
  --repository-root <工作目录>
```

**完成标准**：run 与 decision manifest 均为 `passed`，每个 change 都能追溯到当前 unit finding。

### 8. 按已有授权编辑

先核对本轮和前文的授权。用户已明确要求更新项目内规则、技能或提交时，直接执行该范围；仅缺失会影响操作范围的授权时提问，不能把模糊的“全部”跨作用域解释：

- **仅报告**：不改文件；
- **项目内稳定规则**：只改项目 standards/模块事实源；
- **项目内全部**：还可改项目级 skill、测试或 active issue；
- **包含用户级 skill**：单独明确授权后才可修改 `~/.claude/skills/`；
- **逐项确认**：按 change ID 选择。

新 skill、用户级文件、提交、push 和高影响 Git 操作永远不由“项目内全部”隐式授权。

编辑时保持一项 change 对应最小 diff。完成后：

1. 运行该项 `acceptance` 中的目标检查与 preserved-success 检查；
2. 在本轮变更记录中填写实际实施状态与逐项验证结果；持久账本模式将 decision manifest 的 `status` 改为 `implemented`，`verification` 为 `acceptance.target` 与 `acceptance.preserved_success` 每个检查写一个 `{check, command, status, result}`，`check` 与原文一致且全部为 `passed`；未实施保持 `proposed`，受阻写 `blocked`；
3. 临时报告模式核对 run validation 和逐项验收；持久账本模式再次运行 decision manifest 校验；
4. 用户已明确要求提交时，按 `docs/standards/git.md` 核对改动归属与 staged diff 后提交；未授权提交则只报告，不把 commit 授权扩展成 push。

若多个 change 同时落地且作用面重叠，下一轮无法可靠单项归因；优先分批实施或在报告中显式标记 confounded。

### 9. 清理敏感输入

临时报告模式在 run 校验通过、报告写完且逐项验收完成后，执行 `python3 .claude/skills/learn-from-history/scripts/validate_run.py <run_dir> --cleanup-inputs`。保留 manifest、validation、unit summary/sidecar 与本轮脱敏报告、变更记录；若曾补提取，还须清理本次生成的旧原始提取物和补充 diff，不删除其他 run。该模式不产生持久账本 attestation。

以下为持久账本模式：

最终报告和 decision manifest 写完、全部校验通过后，默认清理 snapshot、原始提取物和 prompts：

```bash
python3 .claude/skills/learn-from-history/scripts/validate_run.py \
  /tmp/learn-from-history/<run_id> \
  --decision-manifest spec/reviews/history-learn-YYYY-MM-DD.json \
  --cleanup-inputs
```

保留 manifest、`validation.json`、summary sidecar 和脱敏报告/决策账本；它们共同构成后续终局 attribution 的证据链。历史 attestation 必须从限定 run/repository 根下以不跟随 symlink 的普通文件读取，并让解析内容与 digest 来自同一次打开；canonical repository ledger 的 `source_sidecars`、旧 `validation.json.attestation` 与保留 sidecar digest 必须逐项一致。路径异常、换指、产物缺失或 digest 不符时一律 fail closed。此时旧 `keep|revert` 不得关闭变更，下一轮继续归因。该链提供可审计的一致性和 Git 可追踪锚，不宣称能抵抗可同时重写仓库 ledger、Git 历史与 `/tmp` 产物的主体；报告和 ledger 仍需人工确认。若用户明确需要保留原始审计输入，跳过 cleanup 并提示其敏感性和路径。

## 失败处理

| 状态 | 行动 |
| --- | --- |
| 数据库不存在或 snapshot 失败 | 报告阻塞并结束 |
| manifest `empty` | 报告近期无记录，可询问是否 `--all` |
| manifest `failed` 或命令非零 | 不启动 agent；修复或重新创建 run |
| agent 中断 | resume 原 child thread |
| sidecar 缺失、digest 不符、覆盖不全 | validator 失败；不得汇总 |
| finding 无原始路径 locator、根因或反证检查 | validator 失败；补证据，不降格为直觉建议 |
| 输入截断/解析失败且无法复核 | 标为 blocked，不将相关判断写成稳定规则 |
| prior change 缺基线或相关场景未复现 | `inconclusive`，不判 keep/revert |
| 回归风险未搜索 | 不实施；补 preserved-success probe |
| 事实源已有同义规则 | 标记已覆盖或仅强化原 Verify |
| 建议涉及用户级 skill | 单独确认，不继承项目内编辑授权 |
