brd.md 9.54 KB

BRD:修复"Planner 产出总览"面板文件/代码列表点击无反应的 Bug

依据 SOUL.md §16,本 Agent 不直接改写 task.status,仅产出本 BRD Artifact 供 c_org_node_trigger/c_org_loop_route 判定流转。以下事实均来自对当前代码(非文档)的直接读取:frontend/app.js、frontend/style.css、frontend/test_graph_console_smoke.js、src/artifact_query.py、src/artifact_write.py、src/backend_server.py、docs/sdd/02-V-界面与交互.md。

0. 文档信息

  • 触发来源:用户报告的可复现 UI Bug + 用户已给出的确认根因(本 BRD 对根因做了独立交叉验证,见 1.2)。
  • 覆盖实体/接口:V=v_graph_console(#/graph,"Planner 产出总览"面板,2026-08-03 加入,无独立 SDD 文档条目,docs/sdd/02-V-界面与交互.md未记录此面板——见 1.3 的文档缺口说明)复用 V=v_artifact_browser(docs/sdd/02-V-界面与交互.md §2.8);C=c_artifact_get(GET /api/artifacts/:artifact_id,src/artifact_query.py:49-71,本次不修改。
  • 类型:Bug 修复(交互缺陷,根因单一),非新特性、非重新设计。
  • 风险等级:低(纯前端 frontend/app.js 改动,无权限/支付/数据不可逆变更;无需触碰后端 API 或数据库 schema)。
  • 状态机备注:本文档为 task 生命周期中 planning_brd_prd_sdd 阶段产出的 BRD Artifact,不代表任务已完成;状态流转由 c_org_node_trigger/c_org_loop_route 依据 BRD/PRD/SDD/Benchmark 判定。

1. 背景与问题陈述

1.1 用户可观察的症状

控制台 Graph 页面(#/graph)"Planner 产出总览"面板中,"文档列表(brd/prd/sdd/benchmark)"和"代码列表(code_diff/test_report)"两个子列表里的每一项,点击后没有任何反应——用户预期点击后能跳转到该 artifact 的详情/内容页面,实际什么都不发生。

1.2 根因(已通过直接读取生产代码交叉验证,非仅采信用户描述)

  • renderArtifactSummaryList()(frontend/app.js:1344-1351)目前渲染出的每个 <li> 只包含两个 <span> 文本节点,没有任何 data-* 属性,也没有绑定任何点击行为。已确认用户给出的根因描述准确无误。
  • 对照组:同一挂载函数 mountArtifactsOverviewPanel()(1359-1400 行)里的"Graph 运行历史"列表(gc_runs_list)已正确实现"数据带 id + 点击跳转"模式(data-run-task-id + querySelectorAll/addEventListener 绑定),证明面板内已有可复用实现模式,问题范围严格限定在 renderArtifactSummaryList() 及其调用方。
  • 数据侧确认:list_artifacts()(src/artifact_query.py:22-46)返回对象已带 artifact_id(不含 /,可安全嵌入 URL hash)。
  • 已有可复用跳转机制:v_artifact_browser(#/artifacts,frontend/app.js:1560-1654)已完整实现"选中 artifact → 拉取 GET /api/artifacts/:artifact_id → 展示血缘链 + 内容预览",工作正常,不应重建并行逻辑。
  • 路由层现状:render()(77-132 行)只支持精确匹配表和两个正则动态路由(TASK_DETAIL_RE/SKILL_AUDIT_RE),#/artifacts 目前没有携带具体 id 的动态子路由。

1.3 相关文档缺口(供 Validator 知悉,非本次修复范围)

"Planner 产出总览"面板未被 docs/sdd/02-V-界面与交互.md/docs/development-plan.md 记录(与 CLAUDE.md "Status" 一节所述现象一致)。本 BRD 以代码本身为事实来源,不在本次范围内补写缺失文档。

2. 目标与非目标

2.1 目标

  • G1:文档/代码列表每项带真实 artifact_id,点击可跳转,视觉提示与"Graph 运行历史"一致。
  • G2:跳转后精确展示被点击 artifact 的真实内容(复用 v_artifact_browser 预览面板),不是空白/默认最新一条。
  • G3:两个"查看全部"链接继续跳到未过滤 #/artifacts,行为不变。
  • G4:不重新实现内容展示逻辑,只接入既有机制。

2.2 非目标

不修改 src/artifact_query.py/后端 API;不修改 showPreview() 内部逻辑;不改变"查看全部"行为或补充过滤参数;不处理"任务列表"子块点击(范围外,记录为后续跟进项);不改动"Graph 运行历史"现有实现;不引入新依赖/构建步骤。

3. 事实 / 设计决策 / 假设 / 未知

3.1 已知事实

  • renderArtifactSummaryList() 无 data-*/事件绑定;artifacts 已含 artifact_id(UUID,src/artifact_write.py:68)。
  • render() 无查询字符串解析能力;#/tasks/:id、#/skills/:id/audit 是"列表+id 动态子路由"的两个成熟先例。
  • mountArtifactBrowser() 的 refreshList()(1638-1642 行)已有"若 selectedArtifactId 存在则 showPreview(),否则默认第一条"逻辑,可直接复用于"外部带初始 id 进入"场景。
  • .artifact-list li 已有 cursor:pointer/:hover/.active 样式;.simple-list li 没有。
  • frontend/test_graph_console_smoke.js 现有 fixture(116-120 行)不含 artifact_id,若不同步更新会造成"测试通过但未测到关键改动"的假阳性。

3.2 设计决策

  • D1:新增动态路由 #/artifacts/:artifact_id(沿用既有正则动态路由模式),不引入查询字符串解析。
  • D2:mountArtifactBrowser() 新增可选形参 artifactId,有值时预置 selectedArtifactId,复用既有"保持选中项"逻辑触发 showPreview()。
  • D3:renderArtifactSummaryList() 输出 data-artifact-id + 可点击视觉提示;事件绑定放在 mountArtifactsOverviewPanel() 里 innerHTML 赋值之后,与 gc_runs_list 现有模式一致(不用内联 onclick)。
  • D4:跳转 URL 对 artifact_id 做 encodeURIComponent(),与 showPreview() 现有写法一致。

3.3 待验证假设

无实质性待验证假设,根因/数据/可复用机制/路由边界均已通过读代码确认。

3.4 阻塞性未知

无。可直接进入开发。

4. 范围

4.1 范围内文件

  • frontend/app.js:renderArtifactSummaryList()、mountArtifactsOverviewPanel()、routes/动态路由区(新增 ARTIFACT_DETAIL_RE)、mountArtifactBrowser()(新增可选形参)。
  • frontend/test_graph_console_smoke.js:更新 fixture + 断言。
  • frontend/style.css(视实现选择,非必须)。

4.2 明确排除

src/artifact_query.py、src/backend_server.py、src/artifact_write.py;showPreview() 内部逻辑;"查看全部"行为;"任务列表"点击;"Graph 运行历史"现有实现;后端测试套件(应保持全绿但无需新增用例)。

5. 验收标准

5.1 自动化测试证据

  • node frontend/test_graph_console_smoke.js:fixture 含 artifact_id,断言输出含精确匹配的 data-artifact-id;"查看全部"仍渲染为无 id/无查询参数的普通链接;现有断言全部继续通过。
  • python3 -m unittest discover -s src 全量通过(回归基线,未改后端代码)。

5.2 真实浏览器验证证据(人工,本仓库前端既有约定)

  1. #/graph 面板列表项呈现可点击视觉提示。
  2. 点击文档列表项,hash 变为 #/artifacts/<真实 artifact_id>,切换到 Artifact 浏览器。
  3. 预览面板精确展示被点击 artifact 的真实内容,对应 <li> 呈现 .active 高亮。
  4. 代码列表(code_diff/test_report)重复验证。
  5. 两个"查看全部"仍跳到未过滤 #/artifacts。
  6. 直接在地址栏输入 #/artifacts/<id> 能独立正确加载(不依赖前置点击状态)。

5.3 边界场景证据

磁盘文件缺失时预览面板展示"(文件不可用)"文案(既有逻辑),不崩溃。

6. 风险与依赖

  • R1(低):mountArtifactBrowser 新增可选形参需保证 artifactId 为 undefined 时默认行为逐字节不变。
  • R2(低):fixture 更新遗漏 artifact_id 会造成假阳性测试,需人工确认断言做了精确值匹配。
  • R3(可忽略):D4 已给出防御性 encode 写法。
  • 依赖:无外部依赖,无环;复用组件均已验证可工作。

7. 可追溯性矩阵

原始要求 责任范围 验收锚点
每项加真实 artifact_id + 点击跳转 renderArtifactSummaryList() + mountArtifactsOverviewPanel() 绑定 5.1 + 5.2.1/5.2.2
跳转需定位到具体 artifact 详情视图 新增 #/artifacts/:artifact_id 路由(D1)+ 预置 selectedArtifactId(D2) 5.2.2/5.2.6
跳转后展示真实内容,非空白/默认全量 复用既有 showPreview/selectedArtifactId 逻辑 5.2.3/5.2.4 + 5.3
"查看全部"行为不变 不改动现有 <a> 标签 5.1 + 5.2.5
复用现有内容预览机制,不重建 D1-D4 均基于复用 4.2 + 2.1 G4
不修改 c_artifact_get/v_artifact_browser 本身 4.2 排除后端与预览内部实现 4.2

8. PL 自审

  • [x] 根因有明确代码来源(1.2)
  • [x] 事实/决策/假设/未知已分列(第 3 节)
  • [x] 范围清晰,显式排除相邻蔓延项(2.2、4.2)
  • [x] 验收标准可测试、描述可观察结果(5.1/5.2)
  • [x] 已识别"测试通不到真改动"的假阳性风险(3.1、R2)
  • [x] 依赖无环(第 6 节)
  • [x] 原始要求均在追溯矩阵中有责任方与验收锚点(第 7 节)
  • [x] 无需更深调查,风险等级低,可直接进入开发

判定:可以流转到开发(Code Agent),无阻塞性未知,范围与验收标准明确。后续 SDD 应给出 ARTIFACT_DETAIL_RE 具体正则、函数签名与 CSS class 命名,BRD 本身不预锁实现细节。