# 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`)目前渲染出的每个 `
  • ` 只包含两个 `` 文本节点,**没有任何 `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 的真实内容,对应 `
  • ` 呈现 `.active` 高亮。 4. 代码列表(`code_diff`/`test_report`)重复验证。 5. 两个"查看全部"仍跳到未过滤 `#/artifacts`。 6. 直接在地址栏输入 `#/artifacts/` 能独立正确加载(不依赖前置点击状态)。 ### 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 | | "查看全部"行为不变 | 不改动现有 `` 标签 | 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 本身不预锁实现细节。