# 06 — 后端时间轴接缝 + `GET /campaigns/{id}/timeline` **What to build:** 一个纯函数把某活动的全部子 Run 映射成「逐 Run 时间轴条目」——每条含 run_id、场景 id/名、加速后窗口偏移(`(started_at − campaign.started_at) × time_scale`,clamp 到 `[0, window_seconds]`)、状态、通过率(取子 Run summary,只读不重算)、平均时延、started_at;未开始/取消的子 Run 在函数内有明确定义的处理。再暴露一个只读端点 `GET /campaigns/{id}/timeline` 返回 `{entries: [...]}`(逐 Run 扁平数组,区别于报告的 12 桶聚合),并在前端 `api.ts` 加对应类型与调用。curl / 测试即可验证。 **Blocked by:** 无 —— 可立即开始。 **Status:** ready-for-agent - [ ] 新增纯函数 `build_campaign_timeline(campaign, runs)`(放 `evaluation/report.py` 或紧邻模块),偏移口径复用现有报告的 `× time_scale` + clamp。 - [ ] 单测覆盖:正常偏移(含 time_scale 压缩)、clamp 到窗口边界、未开始子 Run、取消/失败子 Run、字段映射(pass_rate 取自 summary、场景名映射)、空活动。仿 `test_campaign_report.py`。 - [ ] 新增 `GET /campaigns/{id}/timeline` → `{entries}`;404 当活动不存在。 - [ ] 端点集成测试(200 字段形状 + 404),仿现有 campaigns router 测试。 - [ ] `api.ts` 增加 `CampaignTimelineEntry` 类型与 `campaignsApi.timeline(id)`。 - [ ] `pytest` 全绿、`ruff check backend/` 通过。