Files
agentic-pd-hybrid/docs/ONBOARDING_NEXT_AGENT_ZH.md
kzlin 7590e55189 docs: archive deprecated docs to docs/archive/, drop E1 from onboarding
Two cleanups:

1. Drop "E1: naive 1P3D default" experiment from the onboarding manual.
   GPU hours are precious; naive 1P3D + policy=default has near-certain
   loss on multi-turn cache hit (it's round-robin without prefix awareness),
   so the comparison doesn't add information vs E1=naive 1P3D kv-aware.
   The new manifest has only 2 runs: E1 (naive 1P3D kv-aware) + E2 (KVC
   v2 + RDMA). Run-time budget drops from 16.5h serial to 11h serial /
   5.5h parallel. Updated:
   - §0 TL;DR ("3 组" -> "2 组")
   - §2 H1 hypothesis (drop "default and kv-aware each one" -> just kv-aware)
   - §3.1 experiment matrix (3 rows -> 2 rows + rationale for the drop)
   - §3.2 startup config (drop E1 default section, renumber E2/E3 -> E1/E2)
   - §6 decision table + expected-range table
   - §7 FAQ ("3 个 E1-E3" -> "2 个 E1-E2")
   - §9 deliverables

2. Move 8 deprecated docs to docs/archive/:
     AGENTIC_FIT_ANALYSIS_ZH.md         (ts=10 era analysis; superseded)
     STRUCTURAL_VALIDATION_REPORT_ZH.md (ts=10 era validation; superseded)
     KVC_DEBUG_JOURNEY_V1_TO_V5.md      (v1-v5 sweep process notes)
     V5_PROFILE_INVESTIGATION_ZH.md     (v5 1Hz polling investigation)
     REFACTOR_PLAN_ZH.md                (v0 plan; superseded by V1)
     KVCACHE_CENTRIC_PROGRESS_ZH.md     (earliest 2026-04-27 progress)
     SWEBENCH_EXPERIMENT_PROGRESS.md    (early SWE trace setup)
     SWEBENCH_EXPERIMENT_RESULTS.md     (early SWE result snapshot)

   All cross-references in active docs (V2_DEEP_ANALYSIS / V2_RESULTS /
   REFACTOR_PLAN_V1 / TEAM_REPORT / ONBOARDING) rewritten from
   `docs/FOO.md` to `docs/archive/FOO.md` via sed pass.

   Added `docs/archive/README.md` explaining what each archived doc is
   and when (if ever) to reopen it. Designed so a new reader hitting
   the archive dir immediately knows it's not required reading.

After this commit the active docs in docs/ are 9 files (down from 17),
which should make the onboarding doc's "Level 1 / Level 2 / Level 3"
classification self-evident.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 22:40:35 +08:00

20 KiB
Raw Blame History

接班 Agent 上手手册

对象:接手本项目的下一个 SWE/research agent 目标30 分钟读完后达到当前主 agent 的认知水平,能独立跑对照实验、看懂数据、避开历史坑 作者状态:本手册定稿于 kvc-debug-journey-v1-to-v4 @ 506d360,下一个工作分支是 feat/d-to-p-sync


0. 你是谁你将要做什么5 行 TL;DR

  1. 你接手的是 agentic-pd-hybrid——SGLang xPyD 基础上加 session-aware KVCache 层的 LLM serving 框架,目标是在多轮长 context coding agent workload 上比 vanilla DP 快
  2. v2迁移机制 + threshold tuning已经在 SWE-Bench 50sess trace ts=1 上击败 4DP CA 6/8 个 latency/TTFT 指标,但 TTFT p99 输 3×1.28s vs 0.43s
  3. 上一个 agent 已诊断出 TTFT p99 长尾的根因——8.3% 请求走 reseed 慢路径,每次需要 P 重算 prefill + mooncake transfer = 3-7s
  4. 你的任务:在有 GPU + IB RDMA 的环境上跑 2 组对照实验,验证 (a) naive 1P3D + kv-aware 相对 KVC 的边际贡献、(b) 启用真 RDMA 后 KVC v2 的 TTFT p99 是否能压到 ~0.7s 量级
  5. 跑完结果 push 到 outputs/,主 agent 会拉下来更新 paper draft 和 future-work 文档

1. 必读文档(按这个顺序读,不要乱跳

Level 1核心 30 分钟(必读,读完就能开始干活)

# 文档 时长 为什么读它
1 docs/PROJECT_OVERVIEW.md 5min 项目目标 + 三种 mechanismpd-disagg / pd-colo / kvcache-centric的术语区分
2 docs/V2_DEEP_ANALYSIS_ZH.md §0 (TL;DR) + §6 (生产决策) 10min 当前状态最准确的 snapshot——v2 赢什么、输什么、为什么
3 docs/KVC_ROUTER_ALGORITHM.md §1-§3 + §9 10min 形式化的算法Algorithm 1/2/3+ 4 个 open questions。§9 OQ#4 就是你正在解决的问题
4 docs/RESEED_SLOW_PATH_AND_D_TO_P_GAP_ZH.md §0-§2 5min reseed 路径完整时间线t=0 → t=4550ms知道每段耗时分别来自哪里

读完上面 4 篇就能跑实验了。如果你时间紧张,就只读这 4 篇 + 本手册

Level 2进阶遇到具体问题时再读

文档 何时读
docs/REFACTOR_PLAN_V1_ZH.md 想理解为什么从 ts=10 切到 ts=1
docs/MIGRATION_V1_FINDINGS_ZH.md 想理解 v1→v2 演化v1 为何 thrashingv2 reset-on-success 怎么修的)
docs/V2_RESULTS_ZH.md v2 原始战报注意headline 表略乐观,请优先看 V2_DEEP_ANALYSIS_ZH.md 的修订版)
docs/V2_DEEP_ANALYSIS_ZH.md §4 全文 论文 reviewer 的对等性挑战 + 我们的辩驳;写 paper 时必读
docs/TEAM_REPORT_AGENTIC_PD_HYBRID_ZH.md 想理解 ts=10 时代的 §1-§9 结构性问题清单(很多问题在 ts=1 下消失,但底层机制仍在)

Level 3归档别读,是历史包袱)

  • docs/archive/AGENTIC_FIT_ANALYSIS_ZH.mdts=10 时代的早期分析,结论已被 ts=1 数据 supersede
  • docs/archive/STRUCTURAL_VALIDATION_REPORT_ZH.mdts=10 数据下的结构性验证,同上
  • docs/archive/KVC_DEBUG_JOURNEY_V1_TO_V5.mdv1-v5 调优 sweep 的过程笔记,知道有这个文件就行
  • docs/archive/V5_PROFILE_INVESTIGATION_ZH.mdprofile 调查,已 supersede
  • docs/archive/REFACTOR_PLAN_ZH.mdv0 重构计划,已被 V1 supersede
  • docs/archive/SWEBENCH_EXPERIMENT_*.md:早期实验日志

Level 0本手册的"姐妹"文档(读这个之前你应该已经在看本文了

  • docs/ONBOARDING_NEXT_AGENT_ZH.md(就是本文)

2. 项目当前状态快照(用一张表说清)

Trace:        outputs/qwen35-swebench-50sess.jsonl  (4449 reqs / 52 sessions, time-scale=1.0)
Hardware:     4× H100 80GB + Mellanox mlx5_0/_1 @ 200 Gb/s IB (active, but **未启用** in current sweep)
Model:        Qwen3-30B-A3B-Instruct-2507 (TP1)
Branch:       kvc-debug-journey-v1-to-v4 = 主分支v2 已合入)
              feat/d-to-p-sync           = 预留给 D→P 增量同步的开发,**当前空**
              main                       = 旧 baseline比主分支落后 18 commit

已得出的结论(高置信度)

  1. v2 (reset-on-success + threshold 8192) 击败 4DP CAlat mean -1.4%、p50 -13%、TTFT mean -25%、TTFT p50 -55%、TTFT p90 -67%
  2. TTFT p99 KVC 输 3×1.28s vs 0.43s。来自 8.3% reseed/fallback 慢路径
  3. 慢路径耗时五五开P 端 re-prefill ~1.5-3s + mooncake P→D transfer ~1.5-4s当前是 TCP loopback,未启用真 RDMA
  4. capacity-backup 救不了 slow path:直接 audit 过P 端 backup 不会随 direct-to-D append 更新,是 seed-time 静态快照
  5. D→P 增量同步代码不存在:经 Opus agent forensic 审查 + 全分支 git 检索确认

待验证的核心假设(这是你的实验任务

# 假设 验证方法 预期结果
H1 KVC v2 相对 4DP 的胜利不只是来自 1P3D 拓扑——KVC 层admission / migration / direct-to-D也有显著贡献 跑 naive 1P3D + policy=kv-aware ts=1 N=1vanilla SGLang pd-disagg无 KVC 层)作为中间对照 naive 1P3D 应该处于 KVC v2 和 4DP 之间。如果它 ≈ KVC v2 → 胜利来自拓扑而非 KVC 层;如果 ≈ 4DP → 胜利来自 KVC 层
H2 启用真 RDMA 把 mooncake P→D transfer 从 1.5-4s 压到 200-400msTTFT p99 从 1.28s 降到 ~0.7s 在 v2 sweep 加 --force-rdma --ib-device mlx5_0,跑同 trace 同 ts=1 TTFT p99 应该 ~0.5-0.8s 区间。如果没改变 → mooncake 实际没用 RDMA / 配置错误;如果降到 ~0.3s → 我们对 transfer 段贡献的估计偏低
H3 即使启用 RDMATTFT p99 仍然输 DP因为 re-prefill 段不动) 同 H2 实验结果 应该看到 TTFT p99 ~0.7s > DP 0.43s。如果 ≤ DP → 我们对 re-prefill 段成本的估计错了,可能整个 slow path 理论需要重审

3. 你要跑的实验the main task

3.1 实验矩阵(按 ROI 排序)

GPU hour 珍贵,砍掉了原计划的 naive 1P3D + policy=default baselinelow-ROI——naive 1P3D 用 default policy 在多轮 cache 命中上几乎必败,没必要拿这个对比当 H1 的对照点)。最终保留 2 个 run

# 配置 GPU mechanism policy RDMA 预期时长 目的
E1 naive 1P3D kv-aware 4 pd-disaggregation kv-aware on ~5.5h H1分离"1P3D + kv-aware policy"贡献 vs "KVC 层admission/migration/direct-to-D"贡献
E2 KVC v2 + RDMA 4 kvcache-centric kv-aware on ~5.5h H2/H3验证 RDMA 能把 TTFT p99 从 1.28s 压到 ~0.7s

两个 run 串行约 11h并行用两组 GPU 可压到 ~5.5h。

3.2 启动配置:详细 flag 清单

参考 scripts/sweep_ts1_migration_v2.sh 作为底版。两个新 sweep 脚本的关键 flag

E1: naive 1P3D kv-aware

python -m agentic_pd_hybrid \
  --mechanism pd-disaggregation \
  --policy kv-aware \
  --topology-pd 1P3D \
  --transfer-backend mooncake \
  --force-rdma --ib-device mlx5_0 \   # ← 单独测拓扑+policy 而非 transport必须开 RDMA 才能跟 E2 公平
  --trace outputs/qwen35-swebench-50sess.jsonl \
  --time-scale 1.0 \
  --concurrency 32 \
  --request-timeout-s 300 \
  --max-input-len 87811 \              # ← 拉齐到 DP 限,消除 abort 数量不对等
  --output-root outputs/qwen3-30b-tp1-ts1-naive-1p3d-kvaware

E2: KVC v2 + RDMA

参考 scripts/sweep_ts1_migration_v2.sh只加两个 flag

  --transfer-backend mooncake \
+ --force-rdma --ib-device mlx5_0 \
+ --max-input-len 87811 \
  --kvcache-direct-max-uncached-tokens 8192 \
  --kvcache-migration-reject-threshold 3 \
  --kvcache-prefill-backup-policy release-after-transfer \

保留 v2 的其它所有配置——这是 v2 + RDMA 的 ablation不要顺手改其它东西

3.3 实验前的环境验证(别跳

# 1. GPU
nvidia-smi -L                # 应该看到 4 张 H100 80GB

# 2. RDMA
ibstat | grep -E "State|Rate|Port"
# 期望mlx5_0 / mlx5_1 都是 State=Active, Rate=200 Gb/s

# 3. Mooncake 能识别 RDMA 设备
python -c "from mooncake_transfer_engine import TransferEngine; e=TransferEngine(); print(e.get_local_topology())"
# 期望:输出包含 mlx5_0 / mlx5_1

# 4. 现有 v2 数据可读
python3 scripts/analysis/recompute_summary.py outputs/qwen3-30b-tp1-ts1-migration-v2/kvc_1p3d_migration_v2_run1_metrics.jsonl
# 期望:打印出 failure_count=45, abort_count=40 等

# 5. 算法实现 syntax check
python3 -m py_compile src/agentic_pd_hybrid/{policies,replay,metrics,benchmark,cli}.py
# 期望:全过

任何一步失败立刻停下来排查,不要硬上。


4. 已踩过的坑(避免重复)

# 症状 教训
1 abort 被计入 latency stats DP/KVC 都有 0.08s 的快速失败被算成"快请求",拉低 mean/p50 已在 metrics.py 修复commit 5eac9b4)。新 run 出 summary 时会自动包含 abort_count / failure_count 字段
2 max-input-len 双方不一致KVC=92098 vs DP=87811 SGLang 按 mem_fraction_static 自动算 max_total_num_tokensKVC decode-only worker GPU 内存多 2 GB 跑新 run 时显式传 --max-input-len 87811 强制对齐
3 mooncake 默认 TCP loopback sweep 脚本只传 --transfer-backend mooncake 不够,会落到 TCP跑出来比 RDMA 慢 10× 必须加 --force-rdma --ib-device mlx5_0
4 capacity-backup 不是 D→P 同步 flag 名字误导,看代码就会发现它只是"reseed 完不关 P session"KV 是 seed-time 静态快照 不要在 capacity-backup 上浪费时间;要真正消灭 reseed 长尾必须实现 D→Pfeat/d-to-p-sync
5 N=1 在 ts=1 下"够用"是有条件的 baseline N=3 确认 categorical 完全确定,但 v2 引入的 reset-on-success 等新代码路径未独立验证 v2 + RDMA 的对照建议 N=2对 RDMA-on/off 各一次
6 ts=10 数据别参考 当年的 372/912/396 errors 是 benchmark artifact不代表真实生产 所有比较锁定 ts=1不要尝试 ts=10 "复现"或验证
7 critic agent 的 "MAJOR" 别盲信 上一轮 critic 把 cache fragmentation / prefill 闲置标为 MAJOR其实是 KVC 的设计意图 详见 V2_DEEP_ANALYSIS_ZH §4.4 / §4.5。Audit 视角和生产视角要分清
8 GPU utilization 图布局有残留小问题 组标签 (KVC 1P3D / DP 4-way CA) 与 subplot title 视觉上仍有轻微挤压 已被用户接受为可发表状态。不要再花时间调这张图

5. CLI 速查表

跑实验

# 完整 sweep参考 v2
bash scripts/sweep_ts1_migration_v2.sh

# 写自己的 sweep复制 sweep_ts1_migration_v2.sh改 mechanism/policy/output-root

看数据

# 修复版 summary推荐用这个旧的 summary.json 含 abort 污染)
python3 scripts/analysis/recompute_summary.py outputs/<run>/*_metrics.jsonl

# 跨配置对照
python3 scripts/analysis/analyze_ts1_validation.py    # 比较 KVC vs DP ts=1 4-run

出图(参考 v2 流程)

# 4 张已有的图,对应不同 viz 问题
python3 scripts/analysis/plot_v2_path_breakdown.py    # execution_mode 分布 + path-level latency
python3 scripts/analysis/plot_ttft_pdf.py             # TTFT PDF (KVC vs DP)
python3 scripts/analysis/plot_gpu_utilization.py      # GPU 利用率(请求计数 vs 工作量)
python3 scripts/analysis/plot_cache_efficiency.py     # cache 效率hit rate vs turn + uncached ECDF

# 数据更新后重新出图:直接 rerun每个脚本都参数化了输入路径

Git

# 主分支(实验)
git checkout kvc-debug-journey-v1-to-v4

# 新功能分支D→P 同步,空)
git checkout feat/d-to-p-sync

# 远程
origin = git@ipads.se.sjtu.edu.cn:wangjh/agentic-pd-hybrid.git

# Push 用 (SSH known_hosts 第一次需要 accept)
GIT_SSH_COMMAND='ssh -o StrictHostKeyChecking=accept-new -o UserKnownHostsFile=~/.ssh/known_hosts' git push

# user.email 没设全局,建议 per-commit 传:
git -c user.email=YOUR_EMAIL -c user.name=YOUR_NAME commit -m "..."

6. 跑完结果后看什么数字checklist

每个 run 跑完,至少收集以下几个数字(用 recompute_summary.py

☐ request_count                            (期望 4449)
☐ error_count + abort_count + failure_count
☐ latency_stats_s.{mean, p50, p90, p99}
☐ ttft_stats_s.{mean, p50, p90, p99}      ← 别忘 p99这是 KVC 的真实代价点
☐ execution_modes 分布
☐ per_decode_load 分布(看负载均衡)
☐ per_prefill_load 注意dispatcher 计数 ≠ GPU 工作量)
☐ cache_hit_request_count + total_cached_tokens (推 cache hit rate)

两组对照实验跑完后看以下"决定性数字"

比较 关键看点 决策
E1 (naive 1P3D kv-aware) vs E2 (KVC v2 + RDMA) TTFT p50/p99、direct-to-D 占比 量化"KVC 层admission/migration/direct-to-D在 kv-aware 之上的额外收益"H1
KVC v2 (TCP, 历史 v2 run) vs E2 (KVC v2 + RDMA) TTFT p99、reseed mode 的耗时execution_mode == reseed 的 ttft_s p50 验证 H2/H3RDMA 救多少 transfer 段
E1 (naive 1P3D kv-aware) vs DP 4w历史 ts=1 baseline 全部 latency / TTFT 指标 间接锚定"拓扑差异 + kv-aware policy"的天花板

期待的数字范围(如果实验顺利)

配置 lat p50 lat p99 TTFT p50 TTFT p99 direct-to-D %
E1 naive 1P3D kv-aware ~0.75s ~8-10s ~0.20s ~0.8-1.2s N/A
E2 KVC v2 + RDMA ~0.58s ~7-8s ~0.04s ~0.5-0.8s ~91%
(参考) KVC v2 + TCP历史 0.58s 8.7s 0.04s 1.29s 91.6%
(参考) DP 4w历史 ts=1 0.67s 8.4s 0.09s 0.43s N/A

如果你看到的数字偏离这个范围 ≥ 2×,先停下来检查配置(环境验证 §3.3 那些项目),不是写报告。


7. 遇到 X 怎么办FAQ

Q: 跑出来 KVC v2 + RDMA 的 TTFT p99 比预期高很多(> 1s

A: 大概率 RDMA 没真用上。检查:

  1. outputs/<run>/<subdir>/benchmark-config.jsonforce_rdma 是不是 Trueib_device 是不是 "mlx5_0"
  2. 服务器 startup logoutputs/<run>/<subdir>/logs/prefill-0.log)有没有 "MOONCAKE_DEVICE=mlx5_0" / "using RDMA" 类信息
  3. ibstat mlx5_0 看 active 状态没掉

Q: KVC v2 + RDMA 跑出来 TTFT p99 ≤ DP违反 H3

A: 这是个好消息。可能性:

  1. 我们对 re-prefill 段耗时估计偏高(实际 SGLang 的 prefix cache 把 P 端 re-prefill 救了一半)
  2. RDMA 直接快到把 transfer 段压到 ~50ms 量级,整个 reseed < 1.5s
  3. v2 的 reseed 触发频率被 RDMA 间接降低(某种 race condition 改善了 LRU 行为)

任一情况都值得深挖,建议把 reseed mode 的 ttft_s 分布单独拉出来看应该有清晰的双峰fast reseed + 极少数 outlier

Q: naive 1P3D 跑不起来 / SGLang 报错。

A: 仓库里 outputs/qwen3-30b-exps/pd-disaggregation-default-20260427T062616Z/ 有过历史的 1P1D 跑通配置可以参考。常见坑:

  1. --mechanism pd-disaggregation--topology 必须配合topology 不能用 KVC 的 1P3D 名字
  2. SGLang vendored 在 third_party/sglang/不要pip install sglang 用外部版本——可能 API 不对齐
  3. --policy default 时不要传 --kvcache-* 系列 flag会被 ignore 但会污染 config 输出

Q: 我想跑别的对照(更大 trace / 更多 GPU / 真实 RDMA 跨节点)。

A: 先把上面 2 个 E1-E2 跑完。这 2 个是论文核心 contribution 的 ablation不能跳。其它对照更长 trace、8 GPU 2P6D、真跨节点 RDMA、补 naive 1P3D + policy=defaultV2_DEEP_ANALYSIS_ZH §7.3,作为 follow-up。

Q: 跑完后想自动出对比图。

A: 4 个现有 plot_*.py 脚本都是参数化的,把输入路径改成你的新 run 就能复用。如果对比维度变多(如三方对比 naive vs KVC vs DP可以扩展现有脚本而不是新写——见 plot_ttft_pdf.py 的模板。

Q: 发现 metrics.jsonl 字段不一致 / 缺字段。

A: 看 src/agentic_pd_hybrid/metrics.pyRequestMetrics dataclass。所有新增字段必须在那里加否则 recompute_summary.py 会报 KeyError。注意dataclass 的 field_names 是按 RequestMetrics.__dataclass_fields__ 取的,不是 jsonl 里所有 key。


8. 如果你完全卡住

读这一段:

  1. 不要尝试在没看本手册 §1 必读文档的情况下硬上代码
  2. 不要在 main 分支或 feat/d-to-p-sync 上跑实验——用 kvc-debug-journey-v1-to-v4
  3. 不要修 metrics.py 的统计字段,除非你能解释清楚为什么它当前的 abort 排除是对的
  4. 不要信任 critic agent 的"MAJOR"标签,要看代码层证据
  5. 不要跳过环境验证§3.3)直接跑长 sweep——5h 跑出垃圾数据浪费的成本更高

如果你卡住超过 30 分钟,把卡点写成一句话,去主 agent 留言git commit message / branch 注释)。


9. 主 agent 留给你的两个具体期待

  1. 两组对照实验跑完后,在新 commit message 里给我以下数字(用 recompute_summary.py 输出格式):

    E1 naive 1P3D kv-aware:  lat={mean,p50,p90,p99}  ttft={mean,p50,p90,p99}  fail_count
    E2 KVC v2 + RDMA:        同上 + reseed-mode 的 ttft p50/p99 分开
    
  2. 跑 E2 时收集 reseed 路径的实测耗时分布

    pd-router-d-session-reseed 这个 execution_mode 的 ttft_s 分布
    并把 P→D mooncake transfer 时长 vs P 端 re-prefill 时长 单独拉出
    (需要在 structural/admission-events.jsonl 里找 timestamp diff
    

    这两组数字直接决定 paper future-work 章节怎么写 D→P sync 的必要性。


附录 A关键文件位置速查

你在找什么 在哪
算法实现 src/agentic_pd_hybrid/policies.py (KvAwarePolicy + RoutingState)
整个 replay orchestration src/agentic_pd_hybrid/replay.py (~3000 行,慢慢读)
指标统计 src/agentic_pd_hybrid/metrics.py
CLI 入口 src/agentic_pd_hybrid/cli.py
Server 启动配置 src/agentic_pd_hybrid/stack.py
SGLang 改动 third_party/sglang/python/sglang/srt/{managers/scheduler.py, managers/io_struct.py, disaggregation/mooncake/...}
历史 sweep 脚本 scripts/sweep_ts1_*.sh
分析脚本 scripts/analysis/*.py
实验输出 outputs/qwen3-30b-tp1-ts1-*/

附录 B关键 commit 速查(按"想理解什么改动看什么 commit"组织)

想理解 看 commit
v2 的核心改动 2ec0deb feat(kvc): session migration with reset-on-success + direct-append threshold tuning
metrics.py 修复 5eac9b4 fix(metrics): exclude aborted requests from latency/ttft/tpot stats
完整 analysis 文档(多版本叠加修订) c01d610 (latest) / 9ccd853 / b5af195 / c551906 / 517677d
算法形式化定义 37e9caa docs(kvc): production-decision reframe + formal router algorithm spec
各种 figure 脚本 c551906 (TTFT PDF) / b5af195 (path breakdown) / 517677d (GPU + cache)
backpressure 代码 c47adaf feat(kvc): honor admission backpressure hintsca4b64c feat(sglang): expose backpressure pause hint

核心句:先读 §1 Level 1 的 4 篇文档30 min+ 本手册30 min然后按 §3 跑 E1/E2/E3 三组实验,按 §6 收集决定性数字,遇到坑查 §4结果 push 到 outputs/ 下。别瞎改不属于本任务的代码——你的工作是验证 v2 的胜利在 ablation 中是否站得住,不是开发新机制(那是 feat/d-to-p-sync 分支的事,下一阶段才做)。

跑完之后期待你的 commit