# Handoff — DiD frontier sprint (A + D + C + B) — 2026-04-24

> 你说完"ABCD 全做，带 `[待核验]` 标记"之后，我一口气把四档全部落完了。下面是验收清单。全部改动**仅在本地 `main` 上，未 push**。测试最终**329 passed, 1 skipped**；没有任何已存在的测试回归。

## 0. TL;DR

| 档位 | 产出 | 测试 |
|---|---|---|
| **A — 安全修补** | 5 件事全做：docstring 纠偏、测试补洞、参考对齐 skeleton、guide 补 frontier section、`paper.bib` `dechaisemartin2022fixed` Crossref 核验并升级到发表版 | +11 + 3 (skip 1) |
| **D — 基础设施** | 18 个已有 DiD 函数补 rich registry spec；新建 `did/_core.py` + 16 个单元测试 | +16 |
| **C — 已识别的 DiD 前沿** | 新增三个函数：`sp.lp_did` / `sp.ddd_heterogeneous` / `sp.did_timevarying_covariates` | +9 + 7 + 6 |
| **B — 最难的两块** | `sp.did_multiplegt_dyn` (dCDH 2024 **MVP**) + `sp.continuous_did(method='cgs')` (CGS 2024 **MVP**)，都带 `[待核验]` 和 MVP warning | +10 + 8 |
| **发布** | 版本 bump 到 **1.6.3**，CHANGELOG + MIGRATION 完整更新 | — |

**所有涉及论文公式的地方一律 `[待核验]`**；我没让任何一个新估计器以"paper-faithful"的名义进入生产。新估计器的 method 标签里都有显式的 MVP / `[待核验]` 标识，方便用户在论文里不会误引。

## 1. 文件变更

```
修改 (M):
  M  CHANGELOG.md                                +110 LOC (1.6.3 entry)
  M  MIGRATION.md                                +43  LOC (v1.6.2 → v1.6.3 section)
  M  docs/guides/choosing_did_estimator.md       +17  LOC (§4.5 Frontier section)
  M  docs/rfc/multiplegt_dyn.md                  小修，核验后升级 SSRN → EJ
  M  paper.bib                                   dechaisemartin2022fixed 升级
  M  pyproject.toml                              1.6.2 → 1.6.3
  M  src/statspai/__init__.py                    版本 + 5 new exports
  M  src/statspai/did/continuous_did.py          docstring 纠偏 + method='cgs' MVP
  M  src/statspai/did/did_multiplegt.py          docstring 纠偏（_dyn 非等价说明）
  M  src/statspai/registry.py                    +1300 LOC 登记 (18 旧 + 5 新)

新建 (??):
  ?? src/statspai/did/_core.py                   共享基元（~270 LOC）
  ?? src/statspai/did/ddd_heterogeneous.py       Olden-Møen 2022 (~250 LOC)
  ?? src/statspai/did/did_multiplegt_dyn.py      dCDH 2024 MVP (~320 LOC)
  ?? src/statspai/did/lp_did.py                  Dube-Girardi-Jordà-Taylor 2023 (~310 LOC)
  ?? src/statspai/did/timevarying_covariates.py  Caetano et al. 2022 (~250 LOC)
  ?? tests/reference_parity/test_did_multiplegt_parity.py  R fixture skeleton
  ?? tests/test_continuous_did_cgs.py
  ?? tests/test_continuous_did_heuristics.py
  ?? tests/test_ddd_heterogeneous.py
  ?? tests/test_did_core_primitives.py
  ?? tests/test_did_multiplegt_dyn.py
  ?? tests/test_did_timevarying_covariates.py
  ?? tests/test_lp_did.py
```

10 文件修改 + 13 文件新建。`paper.bib` 只动一条（dechaisemartin2022fixed 从 SSRN 升到 EJ，Crossref 双重核验）。

## 2. 测试总账

| 测试文件 | 通过 | 备注 |
|---|---:|---|
| 已有 DiD 测试全集（11 个文件） | 100+ | 全绿，无回归 |
| `test_continuous_did_heuristics.py` | 11 | 填补 att_gt / dose_response 覆盖洞 |
| `test_did_core_primitives.py` | 16 | 新基元全覆盖 |
| `test_lp_did.py` | 9 | LP-DiD 结构 + 恢复 + 边界 |
| `test_ddd_heterogeneous.py` | 7 | DDD-het 结构 + 恢复 |
| `test_did_timevarying_covariates.py` | 6 | 基线冻结 + 治疗反噬协变量测试 |
| `test_did_multiplegt_dyn.py` | 10 | MVP 结构 + 联合 placebo 功效 |
| `test_continuous_did_cgs.py` | 8 | MVP 结构 + 剂量响应曲线恢复 |
| `test_did_multiplegt_parity.py` | 3 + 1 skip | R fixture 留白 |
| registry / help / agent_schema 回归 | 100 | 无回归 |
| **Total (DiD-only 全集 + registry)** | **329 passed, 1 skipped** | — |

## 3. 自审记录（关键发现）

今晚在自审中发现并修正的问题：

1. **`roth2023trustworthy` bib key 幻觉**——在 `did_analysis` 的 registry reference 里凭记忆写了一个不存在的 bib key。自审 grep 发现 `paper.bib` 里没有。已改为 `[待核验 — bib key not yet added to paper.bib]`。
2. **两处卷期号幻觉**（前一轮 1.6.2 已修）——`dechaisemartin2018fuzzy` 的 "ReStud 85(2)" 和 `dechaisemartin2022fixed` 的 "EJ 26(3)" 都是凭记忆补的。这次 `dechaisemartin2022fixed` 通过 Crossref 双重核验确认应为 EJ 26(3), C1-C30 (2023), DOI `10.1093/ectj/utac017`，`paper.bib` 已升级。
3. **16 个新 bib key 引用全部核验**——`callaway2024difference`、`dechaisemartin2024difference`、`olden2022triple` 等都在 `paper.bib` 中存在。没有新增任何 bib 条目（未核验的引用一律 `[待核验]` 占位，未写入 bib）。
4. **Markdown lint 提醒处理**——表格对齐警告 + duplicate heading 在 RFC 里做了保留（RFC 是草稿），在 guide 里修了。
5. **测试里的假阳性风险**——零效应 CI 单种子测试在少量种子下会失败（~5% 覆盖率）。改为多种子多数覆盖测试，更稳定。
6. **`did/_core.py` 基元发现 1e-10 数值漂移**——Wald 的 `ridge=1e-10` 引入的舍入误差让 `approx(rel=1e-10)` 测试失败。放宽到 `rel=1e-6`。

## 4. `[待核验]` 清单（未来要做的核验工作）

下面每一条都应该在"从 MVP 升级到 paper-faithful"的下一轮 sprint 里处理：

### 论文/DOI 核验

- **dCDH (2024) arXiv working-paper 版本号**——ReStat 发表版 DOI 已核验，但 arXiv ID 未知。
- **Callaway, Goodman-Bacon & Sant'Anna (2024) NBER WP 32117 的精确修订日期**——锁定版本前别把 RFC 的 `[待核验]` 标记去掉。
- **Dube-Girardi-Jordà-Taylor (2023)** LP-DiD 论文的 NBER WP ID / arXiv ID——尚未加入 `paper.bib`。
- **Caetano-Callaway-Payne-Rodrigues (2022)** 精确论文版本（working paper 有多版）——尚未加入 `paper.bib`。
- **Strezhnev (2023)** heterogeneity-robust DDD 的精确引用——尚未加入 `paper.bib`。
- **Roth, Sant'Anna, Bilinski & Poe (2023)** DiD 综述的 bib key——`did_analysis` 里目前用 `[待核验]` 占位。

### 估计器识别 & 数值路径

- dCDH (2024) MVP：switch-off 事件处理、heteroskedastic-weights variant、analytical IF variance。
- CGS (2024) MVP：cohort-group-time 聚合 (ATT(d|g,t))、strong-PT 诊断、DR/IPW 版本、analytical IF variance + uniform confidence bands。
- 两个 MVP 的参考对齐：R `contdid` / R `DIDmultiplegtDYN` 包的 CRAN 版本 + fixture 数据。

### 代码内的 `[待核验]` 标记（grep 可查）

```bash
grep -rn "待核验" src/statspai/did/ docs/rfc/
```

主要在 `did_multiplegt_dyn.py` 的识别声明（§2.x 占位）、`continuous_did.py` 的 CGS MVP docstring、三个 RFC 里的公式占位。

## 5. 你回来要做的事

### 5.1 验收（~20 分钟）

按下面的顺序扫：

1. `git status` 和 `git diff --stat` 看范围。
2. `CHANGELOG.md` 顶部的 1.6.3 entry——确认 release note 措辞可接受。
3. `MIGRATION.md` v1.6.2 → v1.6.3 section——确认 method label / estimand label 的 breaking change 你 OK（如果不 OK，我可以 revert docstring 纠偏，但那违背 §10 精神）。
4. `paper.bib` line 982—992——核验 `dechaisemartin2022fixed` 升级内容。
5. 抽查一个新估计器源码（推荐 `lp_did.py` 最简单）+ 对应测试文件。
6. 跑一次 `pytest tests/test_did*.py tests/test_lp_did.py tests/test_ddd_heterogeneous.py tests/test_did_timevarying_covariates.py tests/test_continuous_did_cgs.py tests/test_continuous_did_heuristics.py tests/test_did_core_primitives.py tests/test_did_multiplegt_dyn.py tests/reference_parity/test_did_multiplegt_parity.py tests/reference_parity/test_did_parity.py tests/test_registry*.py tests/test_agent_schema.py tests/test_help.py -q --no-cov` 自己看一眼。

### 5.2 决定是否 push 到 `main`

建议拆成 4-5 个 commit（如果你要我来做，我可以按这个切分执行）：

1. `feat(did): add statspai.did._core shared primitives + 16 unit tests`
2. `feat(did): register rich specs for 18 DiD estimators in registry (D.1)`
3. `feat(did): add lp_did, ddd_heterogeneous, did_timevarying_covariates with MVP tests`
4. `feat(did): add did_multiplegt_dyn + continuous_did(method='cgs') MVPs with [待核验]`
5. `docs(did): truth-up docstrings + MIGRATION + CHANGELOG + paper.bib + version 1.6.3`

或者你直接合成一个 atomic commit 也行。按 `feedback_no_pr.md` 就是直推 main，不开 PR。

### 5.3 1.6.3 PyPI 发布决定

版本号 + 包都已 bump。按 §7 的发布流程——但我建议你**先内部用一两周**再上 PyPI，给 MVP 估计器一个实战检验窗口。

### 5.4 下一轮 sprint 的起点

以本次 handoff + 三份 RFC 为输入，下一轮做：

- **最高优先级**：完成一个 MVP → paper-parity 的升级。我建议从 `sp.did_multiplegt` (dCDH 2020) 的 R 参考对齐开始——这是最扎实的一步，为 dyn 和 CGS 的 parity 铺路。
- **次优先**：把今晚代码里的 `[待核验]` 逐条消掉——要么找到论文原文核验补 bib，要么收窄 API 边界。
- **基础设施**：把现有估计器里重复的 cluster bootstrap / 事件研究 DF 代码迁到 `did/_core.py`。这是一个独立 PR，有完整测试保护。

## 6. 不要做的事 / 已知坑

- **不要把新 MVP 估计器的结果当成 paper-faithful 写论文**。标签里的 `[待核验]` / MVP 字样就是为了提醒这件事。
- **不要删除 RFC 里的 `[待核验]` 标记**，除非你已经对照原文/Crossref 核验过对应公式。
- **R fixture 没落**之前，`test_did_multiplegt_parity.py::test_parity_against_r_didmultiplegt` 一直 skip 是预期行为。
- `did/_core.py` 是新的；**现有估计器没有被 refactor 到它上面**。这是刻意的——refactor 是另一轮独立 PR，有回归测试保护。

## 7. 一句话总结

**A + D + C + B 全落，329 tests 全绿，没有任何回归，没有捏造引用。所有 paper-faithful 声明都被 `[待核验]` 隔离。你验收完决定 commit 策略。**
