AgentEvalTool/.scratch/v0.6/spec-ux.md
sinohqb 8bc5aa6979 feat(campaign): add per-Run timeline seam + endpoint
build_campaign_timeline flattens a campaign's child Runs into offset-sorted
per-Run entries (distinct from the report's 12-bucket aggregation), reusing a
shared _run_window_offset口径 so both views place a run identically. Exposes
GET /campaigns/{id}/timeline and the api.ts type/call. (v0.6 ticket 06)
2026-07-31 16:49:04 +08:00

87 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# v0.6 SpecUX 升级)— 评估活动页 UX 升级
**状态**: ready-for-agent
**领域词汇**: 见 CONTEXT.md「周期评估」章节评估活动 / 服务周期窗口 / 活动计划 / 可用性)
**关键决策**: ADR-0002通过率含执行失败、ADR-0003活动分期本批不改判定/调度/报告聚合语义
**批次说明**: 本 spec 是 v0.6 评估活动功能线的 **UX 升级批次**(①倍速反向输入 ②计划时间轴预览 ④展开行时间轴),与 `spec.md`v1 静态地基)并存。线③「活动分析 Agent」属新功能另立 **v0.7** spec。
**工单**: 本 spec 派生 v0.6/issues/0610。
## Problem Statement
评估活动Campaign的能力在 v0.6 静态地基已落地,但**新增/查看活动的页面对用户不友好**
1. **时间倍速是裸数字**:新增活动时「时间倍速」是一个 `InputNumber`(默认 1仅一句 tooltip用户得自己心算「填多大倍速能让 24h 窗口几分钟跑完」。用户真正关心的是「加速后多久跑完」,而不是抽象的倍速值。
2. **活动计划不直观**:计划是一组 `场景 + 偏移小时 + 次数` 的表单行,看不出「在这个窗口的哪些时段、跑哪个场景、跑几次」的时间分布全貌。
3. **看不到活动过程**:活动列表每行不可展开;跑完只能进报告抽屉看聚合曲线,无法直观回看「整个活动过程中,各个子 Run 在时间上如何依次发生、各自成败」。
## Solution
对活动页做三项 UX 升级,**不触碰**判定、调度、报告聚合的任何语义:
- **① 倍速反向输入**:新增活动时用户填「窗口长度」+「希望加速后多久跑完」系统自动派生并只读展示时间倍速正式线用「实时」开关×1。用户从此按「耗时」思考而非「倍速」。
- **② 计划时间轴预览**:保留(优化后的)行编辑器做精确录入,其上方增加一条**只读时间轴预览**,把计划条目按偏移画在代表窗口的水平轴上、颜色区分场景、标注次数,随表单实时刷新。
- **④ 展开行时间轴**:活动列表每行可展开为一条**横向窗口时间轴**,把该活动的子 Run 按「加速后窗口偏移」定位成节点、颜色表状态、hover 显详情、点击跳该 Run 报告;进行中活动随现有轮询实时长出新节点。②与④共用同一套时间轴视觉语言。
## User Stories
1. 作为质量负责人,我想在新增活动时直接填「希望这个 24 小时窗口在多久内跑完」(如 1 小时),系统替我算好倍速,以便我不必心算倍速。
2. 作为质量负责人,我想在填写时实时看到「加速后约 X 跑完」,以便确认压缩节奏符合预期。
3. 作为质量负责人,我想在正式线一键选「实时」(真实墙钟、倍速 ×1以便采到真实的凌晨/高峰表现。
4. 作为质量负责人,当我把目标耗时填得比窗口还长(意味着倍速 <1比真实还慢我想被拦下或纠正以便不产生无意义的减速活动
5. 作为质量负责人我想在编辑活动计划时看到一条时间轴预览把每个计划条目按其窗口偏移画出来以便一眼看清哪些时段跑哪个场景跑几次的分布
6. 作为质量负责人我想计划预览用颜色区分不同场景并标注每个条目的次数以便区分密集与稀疏时段
7. 作为质量负责人我想计划预览随我编辑表单实时更新以便边填边看
8. 作为质量负责人我想在活动列表里展开任意一行看到这个活动的完整过程时间轴以便回看整个服务周期里发生了什么
9. 作为质量负责人我想过程时间轴把每个子 Run 按其加速后窗口偏移定位成节点以便看清子 Run 在窗口内的时间分布
10. 作为质量负责人我想每个节点用颜色表示状态完成/失败/运行中/取消以便一眼识别问题时段
11. 作为质量负责人我想 hover 节点看到场景通过率时延以便无需展开报告即可速览
12. 作为质量负责人我想点击节点直接跳到该子 Run 的报告以便下钻排查
13. 作为质量负责人当我展开一个进行中的活动时我想时间轴随轮询长出新派生的子 Run以便实时观察活动推进
14. 作为质量负责人我想活动列表/详情处也用加速后约 X 完成而非裸倍速展示以便和新增表单的心智一致
## Implementation Decisions
### ① 倍速反向输入前端为主API 契约不变)
- 新增活动表单把时间倍速输入替换为两项**窗口长度**沿用预设下拉 6/12/24/48/72h+ **目标加速耗时**数值 + 单位默认分钟)。
- 前端派生 `time_scale = window_seconds / target_real_seconds`作为**只读**展示倍速 ×24 · 加速后约 1 小时跑完」),提交时仍在 payload 里发 `time_scale`。**后端 `POST /campaigns` 契约与 `Campaign.time_scale` 语义完全不变**。
- 实时开关选中即 `target_real_seconds = window_seconds` `time_scale = 1.0`并禁用目标耗时输入
- 约束目标耗时必须 窗口长度 `time_scale ≥ 1`违反时表单校验拦截对应 US-4)。
- 派生与反算 scale+window 反推加速后耗时用于列表/详情展示抽成**纯前端 util** `campaignTime.ts` `deriveTimeScale` / `acceleratedDuration`集中口径便于复用
### ② 计划时间轴预览(纯前端)
- 新增一个**只读时间轴预览组件**输入 = 表单当前的 `window_seconds` + `plan` 条目 + 场景名映射输出 = 一条水平窗口轴,条目按 `offset_seconds` 定位颜色按 `scenario_id` 稳定分配标注 `count`
- 不涉及任何后端改动数据完全来自表单本地状态随编辑实时重渲染
- 的过程时间轴共享底层展示见下共享组件」)。
### ④ 展开行时间轴(新后端纯接缝 + 前端展开行)
- **新后端纯函数接缝** `build_campaign_timeline(campaign, runs) -> list[CampaignTimelineEntry]` `evaluation/report.py` 或紧邻的模块每条含`run_id / scenario_id / scenario_name / offset_seconds加速后窗口偏移clamp [0, window]/ status / pass_rate / avg_latency_ms / started_at`。
- 偏移计算复用现有报告口径`offset = (run.started_at - campaign.started_at).total_seconds() * time_scale`clamp `[0, window_seconds]`未开始的子 Run started_at与取消 Run 的处理在此接缝内明确定义
- `pass_rate` 直接取子 Run `summary.pass_rate`权威只读不重算沿 v0.5/v0.6 约定)。
- **新端点** `GET /campaigns/{id}/timeline` `{entries: CampaignTimelineEntry[]}`返回逐 Run 扁平数组区别于报告的 12 桶聚合曲线)。
- **前端**活动列表行改为 `expandable`展开区渲染横向窗口时间轴 Run 节点按 `offset_seconds` 定位颜色=状态、hover 显场景/通过率/时延点击跳 `/reports?run={run_id}`展开进行中活动时随现有 5s 轮询刷新时间轴数据
### 共享组件
- 的计划预览与的过程时间轴共用一个**底层横向时间轴展示组件**窗口轴 + 定位标记 + 颜色 + hover两处用不同数据适配:②计划条目」,④ Run」。保证视觉语言一致避免两套实现
### API 契约(新增项)
- `GET /campaigns/{id}/timeline` `{ "entries": [ { "run_id", "scenario_id", "scenario_name", "offset_seconds", "status", "pass_rate", "avg_latency_ms", "started_at" } ] }`
- 其余活动端点、`Campaign` 模型、`time_scale` 语义均不变
## Testing Decisions
- **好测试只测外部行为**接缝喂构造好的输入断言输出不测内部实现细节
- **主接缝`build_campaign_timeline`纯函数** —— 唯一新增的可测后端接缝单测覆盖正常子 Run 的偏移计算 `time_scale` 压缩)、clamp 到窗口边界未开始/取消/失败子 Run 的处理字段映射pass_rate 取自 summary场景名映射)、空活动。**Prior art**`tests/unit/test_report.py` / `test_campaign_report.py`同样喂 campaign+runs 断言聚合 dict 的模式)。
- **端点集成测试**`GET /campaigns/{id}/timeline` 200/404字段形状。**Prior art**`tests/integration/test_runs_api.py`、现有 campaigns router 测试
- **前端无测试框架**:①倍速反向输入派生/反算/实时开关/≤窗口校验)、②计划预览、④展开时间轴均以 `npx tsc --noEmit` + `npm run build` + 浏览器实操验证含进行中活动的轮询刷新)。`deriveTimeScale`/`acceleratedDuration` 写成纯函数便于将来接入前端测试
## Out of Scope
- **线 活动分析 Agent + 服务质量改善建议**新功能另立 **v0.7** spec含新增分析模型岗位全局默认分析模型 + 活动可覆盖多步分析 Agent结构化分析报告按需生成+缓存)。
- **计划的拖拽编辑**本批时间轴预览为**只读**拖拽调偏移/点击空白新增等交互不做
- **跨活动对比**、活动列表分页/筛选增强均不在本批
## Further Notes
- 预览与过程时间轴的共享底层组件是本批的关键复用点也是唯一较有设计含量的前端接缝——先把它的输入接口设计干净带窗口偏移的标记数组」),两处适配即可
- 列表/详情的加速后约 X 完成展示与新增表单的派生口径必须走同一个纯 util避免两处算法漂移呼应 v0.6 口径收敛到一处的做法)。