chore: land tree view-state, vault, Pi module split, and repo hygiene
Persist PageTree expand state via control-plane view-state and align chevron/DOM with restored expansion; keep Sidex-style shallow page-tree scan and drop the unused recursive scanner that only added cargo noise. Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi into a module package, and retire Hermes/ACP/OpenHub recycle + root harness evidence from the index while gitignoring recycle and local diag dumps. Archive superseded design/bugs docs under old/, point architecture at ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor regressions so the working tree can stay clean.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
# [recycle] 3-19 [done][bug] Reasonix ACP wrapper 调 mnote tool 缺少身份与幂等字段 v1
|
||||
|
||||
> 发现时间:2026-05-17
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`03-rust-web`
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
Reasonix ACP wrapper 调用 mnote tool 时只发送 `toolName`、`args`、`workspaceId`,没有传递 `actorId`、`sessionId`、`runId`、`toolCallId`、`traceId`、`dryRun`、`idempotencyKey` 等工具合同字段。
|
||||
|
||||
## 2. 证据
|
||||
|
||||
- [reasonix-acp-wrapper.mjs](/mnt/Data1T/mnote/scripts/reasonix-acp-wrapper.mjs:230) 附近构造 `callMnoteTool` 请求体。
|
||||
|
||||
## 3. 影响
|
||||
|
||||
- Rust tool executor 难以稳定进行鉴权、审计、追踪和幂等。
|
||||
- 写工具可能被拒绝,或在缺少幂等键时产生重复写入风险。
|
||||
- Reasonix 与 Hermes 对同一 tool 的调用合同不一致。
|
||||
|
||||
## 4. 建议修复
|
||||
|
||||
- wrapper 必须从 ACP run/session 中透传 actor、session、run、toolCall、trace、dryRun、idempotency 字段。
|
||||
- 写工具缺失必要字段时应 fail fast。
|
||||
- 增加 Reasonix 端到端 smoke,断言请求字段完整。
|
||||
|
||||
## 5. 修复
|
||||
|
||||
已修复:
|
||||
|
||||
- [reasonix-acp-wrapper.mjs](/mnt/Data1T/mnote/scripts/reasonix-acp-wrapper.mjs:34) 新增 `buildMnoteToolPayload`,统一构造 mnote tool 请求体。
|
||||
- [reasonix-acp-wrapper.mjs](/mnt/Data1T/mnote/scripts/reasonix-acp-wrapper.mjs:43) tool payload 现在包含 `actorId`、`sessionId`、`runId`、`toolCallId`、`traceId`、`dryRun`、`idempotencyKey`、`workspaceId`、`documentId`。
|
||||
- [reasonix-acp-wrapper.mjs](/mnt/Data1T/mnote/scripts/reasonix-acp-wrapper.mjs:303) HTTP 请求头同步携带 `x-mnote-actor-id` 与 `x-mnote-workspace-id`。
|
||||
- [reasonix-acp-wrapper.mjs](/mnt/Data1T/mnote/scripts/reasonix-acp-wrapper.mjs:379) ACP `session/prompt` 期间通过 `AsyncLocalStorage` 保存 mnote tool context,tool 调用继承 run/session/actor/trace。
|
||||
- [acp_types.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_types.rs:163) `SessionPromptParams` 扩展可选 mnote 上下文字段。
|
||||
- [acp_session_manager.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_session_manager.rs:193) 增加 `run_prompt_with_mnote_context`。
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:754) ACP Reasonix prompt 启动时透传 mnote session/run/actor/trace/workspace/document 上下文。
|
||||
|
||||
## 6. 验证
|
||||
|
||||
```bash
|
||||
node --check scripts/reasonix-acp-wrapper.mjs
|
||||
MNOTE_REASONIX_ACP_SELFTEST=1 node scripts/reasonix-acp-wrapper.mjs
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web acp_session_manager -- --nocapture
|
||||
```
|
||||
|
||||
结果:JS 语法检查通过,wrapper selftest 通过,ACP session manager 5 个测试通过。
|
||||
@@ -0,0 +1,40 @@
|
||||
# [recycle] 3-20 [done][bug] ACP incoming request 只记录日志不响应 v1
|
||||
|
||||
> 发现时间:2026-05-17
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`03-rust-web`
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
ACP client 收到 `session/request_permission` 等 incoming request 时当前只记录日志,没有返回协议响应。
|
||||
|
||||
## 2. 证据
|
||||
|
||||
- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:347) 附近处理 incoming request。
|
||||
|
||||
## 3. 影响
|
||||
|
||||
- ACP agent 侧可能等待到超时。
|
||||
- 权限请求无法进入用户确认或自动拒绝流程。
|
||||
- run 状态可能卡在进行中,SSE 输出也无法表达真实阻塞原因。
|
||||
|
||||
## 4. 建议修复
|
||||
|
||||
- 为已知 request type 实现明确响应:允许、拒绝或要求人工确认。
|
||||
- 未支持的 request type 也应返回结构化 error,而不是只日志。
|
||||
- 增加 ACP request/response 协议测试。
|
||||
|
||||
## 5. 修复
|
||||
|
||||
- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:157) 将 ACP 子进程 stdin writer 作为共享 `Arc<Mutex<BufWriter<_>>>` 传入后台 reader loop。
|
||||
- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:335) 对带 `id + method` 的 incoming request 写回 JSON-RPC error 响应,当前无权限确认 UI 时明确拒绝,避免 agent 等待超时。
|
||||
- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:551) 增加 mock ACP server 测试,覆盖 `session/request_permission` 主动请求必须收到响应。
|
||||
|
||||
## 6. 验证
|
||||
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web test_incoming_permission_request_gets_response -- --nocapture`
|
||||
- 结果:1 passed
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web acp_client -- --nocapture`
|
||||
- 结果:6 passed
|
||||
@@ -0,0 +1,38 @@
|
||||
# [recycle] 3-21 [done][bug] ACP run payload 被第一次 stream_events 消费后移除 v1
|
||||
|
||||
> 发现时间:2026-05-17
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`03-rust-web`
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
ACP run 的 payload 在 `stream_events` 路径被消费后从内存表移除。刷新页面、多个 SSE 订阅、断线重连时,后续订阅可能无法再取到同一个 run 的 payload。
|
||||
|
||||
## 2. 证据
|
||||
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:789) 进入 `stream_events`。
|
||||
- ACP 分支中存在 `ACP_RUN_PAYLOADS.remove` 语义,payload 生命周期与第一次 stream 订阅绑定。
|
||||
|
||||
## 3. 影响
|
||||
|
||||
- 浏览器刷新或 SSE 重连可能导致同一 run 无法恢复。
|
||||
- 多个客户端观察同一 run 时只有第一个订阅者成功。
|
||||
- abort / retry / reconnect 语义不可靠。
|
||||
|
||||
## 4. 建议修复
|
||||
|
||||
- payload 应有 run 级持久生命周期,至少保留到 run completed / failed / aborted 后短 TTL。
|
||||
- stream subscription 不应拥有 payload 的删除权。
|
||||
- 增加 SSE 断线重连与重复订阅测试。
|
||||
|
||||
## 5. 修复
|
||||
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2051) `acp_run_payload_for_stream` 使用 `ACP_RUN_PAYLOADS.get(run_id).cloned()`,stream subscription 只读取 payload,不再拥有删除权。
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:4116) 增加重复读取测试,锁定刷新、重连、多个观察者不会因为第一次读取而丢失 run payload。
|
||||
|
||||
## 6. 验证
|
||||
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_client_acp_stream_payload_lookup_keeps_payload_for_reconnect -- --nocapture`
|
||||
- 结果:1 passed
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# [recycle] 3-22 [done][bug] ACP permission 自动拒绝后 UI 仍展示审批动作
|
||||
|
||||
> 发现时间:2026-05-18
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`03-rust-web` / ACP runtime 与页面 AI 事件映射
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
当前 ACP client 收到 `session/request_permission` 后会立即返回 JSON-RPC error,并把事件转换为 `permission.denied`。这是为了避免 agent 等待权限响应直到超时。
|
||||
|
||||
但页面 AI UI 仍在权限卡片和权限弹窗里展示“允许 / 拒绝”按钮。即使这些按钮在 `permission.denied` 下会被禁用,用户仍会看到审批入口,误以为可以把真实协议结果改成允许。
|
||||
|
||||
## 2. 证据
|
||||
|
||||
- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:350) 对 incoming `id + method` request 直接返回 JSON-RPC error。
|
||||
- [acp_session_manager.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_session_manager.rs:121) 对 `session/request_permission` 生成 `decision="denied"`。
|
||||
- [acp_bridge.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_bridge.rs:237) 将 decision 映射为 `permission.denied`。
|
||||
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:4060) 权限弹窗仍渲染“允许 / 拒绝”按钮。
|
||||
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:5805) 权限消息卡片仍渲染“允许 / 拒绝”按钮。
|
||||
|
||||
## 3. 影响
|
||||
|
||||
- 用户看到的“允许”动作与 ACP wire contract 不一致。
|
||||
- 点击动作只修改本地 UI 状态,不会回写 ACP JSON-RPC response。
|
||||
- 对已经自动拒绝的权限请求展示审批按钮,会掩盖真实失败原因。
|
||||
|
||||
## 4. 修复
|
||||
|
||||
- [acp_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/acp_client.rs:350) 维持 `session/request_permission` 自动拒绝协议响应,避免 agent 等待超时。
|
||||
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:4003) `pageAiApplyPermissionEvent()` 对 `permission.denied` / `permission.allowed` 只保留结果态,不再展示可点击审批弹窗。
|
||||
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:4048) `pageAiShowPermissionDialog()` 对已决权限事件直接隐藏对话框。
|
||||
- [layout.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/ssr/pages/layout.rs:5797) 权限消息卡片对已决事件只展示结果,不再渲染审批按钮。
|
||||
|
||||
## 5. 验证
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_uses_backend_acp_session_runtime_store -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web acp_permission_request_emits_frontend_decision_event -- --nocapture
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web ssr::pages::layout::tests -- --nocapture
|
||||
cargo fmt --manifest-path rust/Cargo.toml --all -- --check
|
||||
git diff --check -- rust/crates/mnote-web/src/ssr/pages/layout.rs bugs/03-rust-web/done/3-22-acp-permission-auto-deny-ui-shows-approval-actions-v1.md
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- `page_ai_uses_backend_acp_session_runtime_store`:`1 passed`。
|
||||
- `acp_permission_request_emits_frontend_decision_event`:`1 passed`。
|
||||
- 版面相关静态测试继续通过,权限消息代码路径未破坏。
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
# [recycle] MNote 浏览器 QA 实测发现 2026-07-08
|
||||
|
||||
- **状态**:`process`
|
||||
- **来源**:Agent Board Pi Taskflow 实测(MNote 浏览器 QA → Bug 文档 20260708-130503)
|
||||
- **复现环境**:
|
||||
- MNote Web:`http://127.0.0.1:3000`,Rust SSR + leptos-tiptap island
|
||||
- 后端:control-plane libSQL local
|
||||
- 浏览器:Playwright Chromium headless,viewport 1280×800
|
||||
- 登录:测试账号 `mnote.e2e@example.com`,authMode=controlPlaneSession
|
||||
- 工作区:`/mnt/Data1T/Mnote_data/users/mnote-e2e/workspaces/my-space`
|
||||
|
||||
---
|
||||
|
||||
## 1. 总体状态
|
||||
|
||||
| 检查项 | 结果 | 详情 |
|
||||
|--------|------|------|
|
||||
| API Gateway /health | ✅ PASS | 200 |
|
||||
| Auth 页面加载 | ✅ PASS | 518ms |
|
||||
| 测试账号快速登录 | ✅ PASS | 跳转到 `/` |
|
||||
| Workspace 壳渲染 | ✅ PASS | sidebar / topbar / shell 均可见 |
|
||||
| Page AI / OpenHub 页面 | ✅ PASS | 130ms 加载,AI 输入框可见 |
|
||||
| Console 错误 | ✅ PASS | 0 errors |
|
||||
| 业务网络错误 | ✅ PASS | 0 real errors(SSE abort 为预期导航行为) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 发现的问题
|
||||
|
||||
### 2.1 `file-order.json` 页面排序索引为空
|
||||
|
||||
- **严重程度**:medium
|
||||
- **实际结果**:`/mnt/Data1T/Mnote_data/users/mnote-e2e/workspaces/my-space/.mnote/file-order.json` 内容为 `{"parents": {}, "version": 1}`,无任何页面条目。
|
||||
- **预期结果**:工作区中存在有效页面目录(`新页面054900`、`新页面145827`、`新页面233155`、`有机合成中的保护基` 等),每个目录下均有 `.md` 正文文件,file-order.json 应包含这些页面的排序条目。
|
||||
- **证据**:
|
||||
```bash
|
||||
$ cat .mnote/file-order.json
|
||||
{"parents": {}, "version": 1}
|
||||
|
||||
$ ls workspace/
|
||||
新页面054900/ 新页面145827/ 新页面233155/ 有机合成中的保护基/
|
||||
```
|
||||
- **影响范围**:页面树(Page Tree)排序可能不正确,新建页面可能无法正确出现在侧边栏页面列表中。
|
||||
- **建议修复方向**:检查页面创建/重命名/移动流程是否正确更新 `file-order.json`;检查 Pi lab 批量创建页面的流程是否绕过了正常的 metadata 写入路径。
|
||||
|
||||
### 2.2 `/api/tree/page-tree` 端点返回 404
|
||||
|
||||
- **严重程度**:low
|
||||
- **实际结果**:`GET /api/tree/page-tree` 返回 HTTP 404。
|
||||
- **预期结果**:应返回 200 或 401(需要认证),而非 404。
|
||||
- **证据**:
|
||||
```bash
|
||||
$ curl -s -w "\nHTTP: %{http_code}" http://127.0.0.1:3000/api/tree/page-tree
|
||||
HTTP: 404
|
||||
```
|
||||
- **影响范围**:直接调用此 API 的外部客户端或测试脚本会失败。前端使用 `GET /api/tree/view-state?treeKind=pagetree`(需要认证,已正常工作),当前不受影响。
|
||||
- **建议修复方向**:确认 `/api/tree/page-tree` 是否为已废弃路由;若是,应在路由注册时返回 410 Gone 或转发到 view-state;若不是,应修复路由注册。
|
||||
|
||||
### 2.3 侧边栏中无 `a[href*="/document/"]` 格式的文档链接
|
||||
|
||||
- **严重程度**:low(待确认是否为预期行为)
|
||||
- **实际结果**:Playwright selector `a[href*="/document/"]` 在侧边栏中找到 0 个元素。
|
||||
- **预期结果**:侧边栏页面树中的页面应可点击跳转到文档页。
|
||||
- **证据**:QA 脚本 `page.locator('a[href*="/document/"]').count()` 返回 0。
|
||||
- **影响范围**:如果页面确实使用不同 URL 模式(如 `/page/...` 或前端路由),则无影响;否则侧边栏页面无法点击跳转。
|
||||
- **建议修复方向**:确认当前侧边栏页面树使用的链接格式;如果是前端 SPA 路由(如 `data-page-id` + click handler),则更新测试 selector;如果是 bug,修复链接生成。
|
||||
|
||||
### 2.4 Dev 模式 hot-reload 轮询累积
|
||||
|
||||
- **严重程度**:low(仅 dev 模式)
|
||||
- **实际结果**:多个 `GET /api/dev/hot-reload` 请求处于 pending 状态,随时间累积。
|
||||
- **预期结果**:hot-reload 连接应复用或及时关闭,不应无限累积。
|
||||
- **证据**:网络追踪显示 20+ 个 pending 的 `GET /api/dev/hot-reload` 请求。
|
||||
- **影响范围**:仅影响开发模式下的浏览器性能和内存占用,不影响生产环境。
|
||||
- **建议修复方向**:检查 hot-reload EventSource/WebSocket 连接的生命周期管理,确保旧连接在页面导航或重连时正确关闭。
|
||||
|
||||
---
|
||||
|
||||
## 3. 已验证无问题的路径
|
||||
|
||||
- Auth 登录流程:正常
|
||||
- Workspace 壳渲染:正常
|
||||
- Page AI / OpenHub 页面:正常加载
|
||||
- API `/api/auth/session`:正常
|
||||
- API `/api/tree/view-state`(需认证):正常
|
||||
- API `/api/tree/projections/file/children`(需认证):正常
|
||||
- SSE `/api/local-folder/events`:正常建立连接
|
||||
- API `/api/page-ai/pi/status`:正常
|
||||
- API `/api/ai-settings/effective`:正常
|
||||
|
||||
---
|
||||
|
||||
## 4. 测试脚本
|
||||
|
||||
QA 脚本位于:
|
||||
- `/tmp/mnote-browser-qa-20260708.js`(基础检查)
|
||||
- `/tmp/mnote-browser-qa-20260708-detail.js`(详细检查)
|
||||
- `/tmp/mnote-browser-qa-comprehensive.js`(综合检查)
|
||||
- `/tmp/mnote-network-trace.js`(网络追踪)
|
||||
|
||||
结果文件:
|
||||
- `/tmp/mnote-browser-qa-20260708/result.json`
|
||||
- `/tmp/mnote-browser-qa-20260708/result-detail.json`
|
||||
- `/tmp/mnote-browser-qa-20260708/result-final.json`
|
||||
|
||||
截图:
|
||||
- `/tmp/mnote-browser-qa-20260708/01-main-page.png`(Auth 页)
|
||||
- `/tmp/mnote-browser-qa-20260708/02-after-login.png`(登录后 workspace)
|
||||
- `/tmp/mnote-browser-qa-20260708/05-post-login-workspace.png`(workspace 页)
|
||||
@@ -0,0 +1,36 @@
|
||||
# [recycle] 7-1 [done] 页面 AI provider=hermes 仍命中旧 run route 导致 502
|
||||
|
||||
## 现象
|
||||
|
||||
- 当前 Rust 3000 页面壳里,页面 AI 默认 provider 是 `hermes`。
|
||||
- 发送消息时仍请求旧 `/api/ai-agent/run`。
|
||||
- Rust compat route 对显式 `provider=hermes` 返回 `ai_provider_bridge_unavailable`,HTTP 状态为 502。
|
||||
|
||||
## 复现证据
|
||||
|
||||
- 页面壳默认 provider:`rust/crates/mnote-web/src/ssr/pages/layout.rs`
|
||||
- 页面 AI 发送旧 route:`fetch('/api/ai-agent/run')`
|
||||
- 旧 route 注册:`rust/crates/mnote-web/src/routes/mod.rs`
|
||||
- 502 来源:`rust/crates/mnote-web/src/routes/compat.rs`
|
||||
- 可复跑 smoke:`scripts/task-hermes-page-ai-baseline-smoke.js`
|
||||
|
||||
## 归类
|
||||
|
||||
- owner:`07-ai`
|
||||
- 根因:页面 AI UI 仍走旧 mnote-cli / compat 主链,而默认 provider 已切到 Hermes。
|
||||
- 修复方向:页面 AI 主链改为同源 `/api/hermes/client/*`,旧 `/api/ai-agent/run` 只保留 legacy guard。
|
||||
|
||||
## 验收
|
||||
|
||||
- [x] 页面 AI 打开后创建或恢复 Hermes session。
|
||||
- [x] 发送消息不再请求 `/api/ai-agent/run`。
|
||||
- [x] 未配置 Hermes upstream 时返回稳定 `hermes_client_unconfigured`,不再出现旧 502。
|
||||
- [x] 配置 Hermes upstream 后 run/event stream 由 Hermes 返回。
|
||||
|
||||
## 完成证据
|
||||
|
||||
- 代码主链:`rust/crates/mnote-web/src/ssr/pages/layout.rs` 已改为 `/api/hermes/client/sessions`、`/api/hermes/client/runs`、`/api/hermes/client/events/{run_id}`。
|
||||
- 合同与路由:`rust/crates/mnote-web/src/routes/hermes_client.rs` 提供同源 Hermes client proxy。
|
||||
- 测试:`cd /mnt/Data1T/mnote/rust && cargo test -p mnote-web hermes_ -- --nocapture`,14 passed。
|
||||
- smoke:`MNOTE_UI_BASE_URL=http://127.0.0.1:3000 node scripts/task-hermes-page-ai-smoke.js` 通过,并拦截旧 `/api/ai-agent/run` 证明新页面 AI 主链未调用旧 route。
|
||||
- 说明:2026-05-14 已在正式 `3000` 入口复跑 Hermes 页面 AI smoke 矩阵,旧 `/api/ai-agent/run` 只保留 410 retirement guard。
|
||||
@@ -0,0 +1,44 @@
|
||||
# [recycle] 7-19 [done][bug] Hermes 工具指导仍优先 apply_block_ops 而非 markdown_edit v1
|
||||
|
||||
> 发现时间:2026-05-17
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`07-ai`
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
`mnote.doc.markdown_edit` 已被设计为普通页面正文编辑的主路径,但 Hermes run 的工具指导仍要求简单正文编辑优先调用 `mnote_doc_apply_block_ops`。
|
||||
|
||||
这导致模型策略与工具主线冲突。
|
||||
|
||||
## 2. 证据
|
||||
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2351) 构造工具指导。
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2357) 要求上下文足够时直接调用 `mnote_doc_apply_block_ops`。
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2360) 明确“简单小段落编辑”优先用 `apply_block_ops`。
|
||||
|
||||
## 3. 影响
|
||||
|
||||
- Hermes 与 page AI fast-path 会走不同编辑工具。
|
||||
- markdown 级 search/replace 的收敛设计无法成为唯一验收口径。
|
||||
- `apply_block_ops` 的 revision / conflictDetectionKey 合同缺陷会被继续放大。
|
||||
|
||||
## 4. 建议修复
|
||||
|
||||
- 将普通正文 search/replace、局部段落替换、全文 markdown 替换统一引导到 `mnote_doc_markdown_edit`。
|
||||
- 仅在需要结构性块移动、资源块、复杂定位时才引导模型使用 `apply_block_ops` 或 `mnote.block.*`。
|
||||
- 同步更新 smoke:模型生成工具调用时应优先产出 `mnote_doc_markdown_edit`。
|
||||
|
||||
## 5. 修复
|
||||
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2456) 将 Hermes run instructions 改为:普通正文 search/replace、局部段落替换、全文 markdown 替换优先调用 `mnote_doc_markdown_edit`。
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:2494) 将 `blockEditingToolOrder` 首位调整为 `mnote_doc_markdown_edit`,`mnote_doc_apply_block_ops` 仅保留给 markdown_edit 不能表达的结构性块操作。
|
||||
- [hermes_client.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_client.rs:4559) 增加 run guidance 合同测试,防止普通正文编辑重新退回 `apply_block_ops` 优先口径。
|
||||
|
||||
## 6. 验证
|
||||
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_client_run_guidance_prefers_markdown_edit_for_plain_body_edits -- --nocapture`
|
||||
- 结果:1 passed
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_client_run_body -- --nocapture`
|
||||
- 结果:2 passed
|
||||
@@ -0,0 +1,48 @@
|
||||
# [recycle] 7-20 [done][bug] page_ai_workflow 绕过 Hermes tool executor / audit / toggle v1
|
||||
|
||||
> 发现时间:2026-05-17
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`07-ai`
|
||||
|
||||
## 1. 问题定义
|
||||
|
||||
`/api/page-ai/block-edit-workflow` 仍是独立模型调用链:直接读取 Hermes profile、调用 chat/completions、解析模型 JSON,并直接调用 Rust 工具函数。
|
||||
|
||||
它没有通过 `/api/hermes/tools/mnote/call` 的工具执行壳,因此绕过了 tool toggle、audit、统一幂等和统一调用追踪。
|
||||
|
||||
## 2. 证据
|
||||
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:69) 直接调用上游模型。
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:91) 在 route 内构造 `ToolCallInput`。
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:109) 直接调用 `doc::doc_markdown_edit`。
|
||||
|
||||
## 3. 影响
|
||||
|
||||
- 关闭或限制 mnote tool 时,该 fast-path 仍可能写入。
|
||||
- 工具调用审计与普通 Hermes run 不一致。
|
||||
- 幂等、dryRun、runId、toolCallId 等字段无法统一治理。
|
||||
|
||||
## 4. 建议修复
|
||||
|
||||
- 将 fast-path 的工具写入改为调用统一 tool executor。
|
||||
- fast-path 只负责 prompt / plan,不直接执行写入函数。
|
||||
- 增加 smoke:当对应 tool disabled 时,`page_ai_workflow` 不得绕过限制写入。
|
||||
|
||||
## 5. 修复
|
||||
|
||||
- [hermes_tools.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_tools.rs:62) 将统一 mnote tool 执行壳抽为 `execute_mnote_tool_call`,保留 profile disabled、audit、idempotency、auth/workspace 校验和统一结果包装。
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:109) `block_edit_workflow` 的写入阶段改为调用统一 executor,不再直接调用 `doc::doc_markdown_edit`。
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:657) 增加路由级测试:当 profile 禁用 `mnote.doc.markdown_edit` 时,页面 AI fast-path 必须返回 `mnote_tool_disabled`,不得绕过限制写入。
|
||||
|
||||
## 6. 验证
|
||||
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web block_edit_workflow_respects_disabled_markdown_edit_tool -- --nocapture`
|
||||
- 结果:1 passed
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_workflow -- --nocapture`
|
||||
- 结果:3 passed
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_call_rejects_profile_disabled_tool -- --nocapture`
|
||||
- 结果:1 passed
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit_maps_normalized_search_to_block -- --nocapture`
|
||||
- 结果:1 passed
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
# [recycle] 7-25 [done][bug] ACP Reasonix 页面 AI block_edit_workflow 在 markdown 命中后生成空 block_ops v1
|
||||
|
||||
> 发现时间:2026-05-17
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`07-ai`
|
||||
>
|
||||
> 关联缺陷:`7-24 在线 markdown_edit 写回不以最终 Markdown 为真源`
|
||||
|
||||
## 1. 用户可见症状
|
||||
|
||||
在页面 AI 中切换到 `ACP · Reasonix`,输入:
|
||||
|
||||
```text
|
||||
你
|
||||
检查你是否能读取到本页第一段,同时请修改第二段为:测试123
|
||||
```
|
||||
|
||||
工具调用失败:
|
||||
|
||||
```text
|
||||
mnote.page_ai.block_edit_workflow 失败 · page-ai-fast-mp9wm0qo
|
||||
结果 mnote.doc.apply_block_ops operations 不能为空
|
||||
```
|
||||
|
||||
## 2. 问题定义
|
||||
|
||||
`page_ai.block_edit_workflow` 当前已切到:
|
||||
|
||||
```text
|
||||
模型输出 search/replace
|
||||
-> mnote.doc.markdown_edit
|
||||
-> 在线文档再转换为 mnote.doc.apply_block_ops
|
||||
```
|
||||
|
||||
但在线写回层没有以最终 Markdown 为真源。它在 markdown 字符串中 search/replace 成功后,又用原始 `operations` 去原始 `blocks` 中反查目标块。如果反查不到块,就生成空 `block_ops`,随后仍调用 `mnote.doc.apply_block_ops`,最终抛出“operations 不能为空”。
|
||||
|
||||
## 3. 证据
|
||||
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:69) 调用模型生成 markdown operations。
|
||||
- [page_ai_workflow.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/page_ai_workflow.rs:91) 构造 `mnote.doc.markdown_edit` 输入。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:811) 在 `md` 字符串上执行 search/replace。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:857) 调用 `build_block_ops_from_markdown_edit`。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:989) 只用 `block.text.contains(search)` 反查 block。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:1008) 可能返回空 `block_ops`。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:878) 即使 `block_ops` 为空,也继续调用 `doc_apply_block_ops`。
|
||||
- [block.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/block.rs:405) 对空 operations 报错:`mnote.doc.apply_block_ops operations 不能为空`。
|
||||
|
||||
## 4. 根因判断
|
||||
|
||||
这条错误不是最终 root cause,只是下游暴露出来的症状。
|
||||
|
||||
真正根因是 markdown 层与 block ops 写回层存在二次定位:
|
||||
|
||||
1. `search_replace(&md, search, replace)` 可以通过精确、归一化或 fuzzy 匹配成功。
|
||||
2. `build_block_ops_from_markdown_edit` 却只支持 `block.text.contains(search)`。
|
||||
3. 两套匹配规则不一致时,markdown 层显示已命中,block 层却生成空 operations。
|
||||
4. 空 operations 没有在 `markdown_edit` 层转成语义化错误,而是继续传给 `apply_block_ops`。
|
||||
|
||||
## 5. 影响
|
||||
|
||||
- ACP Reasonix 的页面编辑会向用户暴露底层 `apply_block_ops` 错误,而不是说明“markdown 命中但无法映射到块”。
|
||||
- “读取第一段 + 修改第二段”这类混合任务可能进入 fast workflow,但该 workflow 只能表达写入,不保证先读后答。
|
||||
- 如果模型给出的 `search` 是段落序号、fuzzy 片段、带格式文本或跨块文本,markdown 层可能成功,block 写回层仍失败。
|
||||
|
||||
## 6. 建议修复:建议以长期,彻底的修复优先,建议参考/mnt/Data1T/mnote/design/05-editor-mainline/reference-code/cli-main中对全局替换和单块替换的判断逻辑。
|
||||
|
||||
短期:
|
||||
|
||||
- `doc_markdown_edit` 在调用 `doc_apply_block_ops` 前,如果 `applied > 0` 但 `block_ops.is_empty()`,应返回明确错误,例如 `mnote_doc_markdown_edit_block_mapping_empty`,并包含 failed operation 的 search 摘要。
|
||||
- `page_ai_workflow` 应把该错误翻译为用户可理解的提示,不要暴露 `apply_block_ops operations 不能为空`。
|
||||
|
||||
中期:
|
||||
|
||||
- `build_block_ops_from_markdown_edit` 必须复用 `search_replace` 的定位结果,或让 `search_replace` 返回原始命中范围 / paragraph / block 映射。
|
||||
- 对“第一段/第二段”等序号型指令,应由模型输出对应段落原文作为 `search`,并增加回读校验。
|
||||
|
||||
长期:
|
||||
|
||||
- 按 `7-24` 收口:在线 `markdown_edit` 应以最终 Markdown 为写回真源,或明确限制只支持可安全映射的单块精确替换。
|
||||
|
||||
## 7. 复现 / 验证建议
|
||||
|
||||
- 浏览器 smoke:ACP Reasonix,页面含至少两段正文,输入“检查第一段并修改第二段为:测试123”。
|
||||
- 断言失败时错误码不能是 `mnote.doc.apply_block_ops operations 不能为空`,应是 markdown 到 block 映射失败的明确错误。
|
||||
- 修复后回读 Page Aggregate,断言第二段实际变为 `测试123`,同时 AI 回复能正常说明已读取到第一段。
|
||||
|
||||
## 8. 修复
|
||||
|
||||
已修复:
|
||||
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:862) 在 `mnote.doc.markdown_edit` 调用 `doc_apply_block_ops` 前拦截 `applied > 0 && block_ops.is_empty()`,返回 `mnote_doc_markdown_edit_block_mapping_empty`,不再泄露 `mnote.doc.apply_block_ops operations 不能为空`。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:928) 抽出 `search_replace_exact_or_normalized`,让 markdown 层与 block 映射层共享“精确 / 忽略空白 / 全半角归一化”规则。
|
||||
- [doc.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/hermes_tools/doc.rs:1038) 在线 block ops 构建不再用 `block.text.contains(search)`,改为对单块文本执行同一套安全匹配;fuzzy 仍只保留在 markdown 预处理层,避免写错块。
|
||||
- [hermes_tools.rs](/mnt/Data1T/mnote/rust/crates/mnote-web/src/routes/hermes_tools.rs:1670) 增加回归测试,覆盖空映射语义错误与忽略空白后正确映射到 `p_2`。
|
||||
|
||||
## 9. 验证
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web hermes_tools_markdown_edit -- --nocapture
|
||||
```
|
||||
|
||||
结果:4 个相关测试通过。
|
||||
|
||||
## 10. 剩余风险
|
||||
|
||||
本修复解决单块 search/replace 映射和空 ops 下沉;跨块 Markdown 重写、完整最终 Markdown 作为写回真源仍归属于 `7-24`。
|
||||
@@ -0,0 +1,64 @@
|
||||
# [recycle] 7-31 [done][bug] 页面 AI block_edit_workflow 丢弃读取类回答摘要 v1
|
||||
|
||||
> 发现时间:2026-05-18
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`07-ai`
|
||||
|
||||
## 1. 用户可见症状
|
||||
|
||||
在页面 AI 使用 `ACP · Reasonix` 输入:
|
||||
|
||||
```text
|
||||
检查你是否能读取到本页第一段,同时请修改第二段为:测试123
|
||||
```
|
||||
|
||||
`block_edit_workflow` 即使完成写入,前端也只显示固定文案:
|
||||
|
||||
```text
|
||||
已通过页面 markdown 编辑快路径完成写入。
|
||||
```
|
||||
|
||||
用户要求中的“是否能读取到第一段”没有被回答。
|
||||
|
||||
## 2. 根因
|
||||
|
||||
`page_ai_workflow.rs` 的模型提示已经要求模型输出:
|
||||
|
||||
```json
|
||||
{"operations": [...], "summary": "..."}
|
||||
```
|
||||
|
||||
但路由只提取 `operations`,丢弃了 `summary`,并在成功响应中固定返回“已通过页面 markdown 编辑快路径完成写入。”。
|
||||
|
||||
这会让读写混合请求退化为纯写入反馈。
|
||||
|
||||
## 3. 修复
|
||||
|
||||
- 新增 `MarkdownEditPlan`,同时解析模型输出中的 `operations` 与 `summary`。
|
||||
- `block_edit_workflow` 成功响应优先返回模型 `summary`,缺失时才使用固定 fallback。
|
||||
- 系统提示明确要求:如果用户要求读取某段,`summary` 必须包含从 `page_text` 读取到的原文。
|
||||
- 新增回归测试 `block_edit_workflow_surfaces_model_summary_for_read_and_edit_request`,覆盖“读取第一段 + 修改第二段”的真实快路径响应。
|
||||
|
||||
## 4. 验证
|
||||
|
||||
RED:
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web block_edit_workflow_surfaces_model_summary_for_read_and_edit_request -- --nocapture
|
||||
```
|
||||
|
||||
旧实现失败,`payload.message` 不包含 `已读取第一段:第一段`。
|
||||
|
||||
GREEN:
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_workflow -- --nocapture
|
||||
```
|
||||
|
||||
结果:`5 passed`。
|
||||
|
||||
## 5. 剩余边界
|
||||
|
||||
本修复只保证 fast workflow 成功响应不丢模型摘要;复杂多步推理、review session、流式 apply 仍属于 Phase C 冻结范围。
|
||||
@@ -0,0 +1,45 @@
|
||||
# [recycle] 7-34 [done][bug] 页面 AI ACP Runtime 默认值回跳 Hermes v1
|
||||
|
||||
> 发现时间:2026-05-18
|
||||
>
|
||||
> 状态:`[done]`
|
||||
>
|
||||
> 关联主线:`07-ai`
|
||||
|
||||
## 1. 用户可见症状
|
||||
|
||||
页面 AI 面板中选择 `ACP · Reasonix` 后,会自动回跳到 `ACP · Hermes`。
|
||||
|
||||
用户期望:
|
||||
|
||||
- 默认 runtime 为 `ACP · Reasonix`
|
||||
- 下拉仍可手动切换到 `ACP · Hermes`
|
||||
|
||||
## 2. 根因
|
||||
|
||||
页面 AI 的历史 runtime 语义仍把空 `acpRuntime` 当成旧 `Hermes HTTP` 默认值。当前主线已经退役 HTTP Hermes,但前端 session/localStorage 恢复、后端空 runtime 推导、以及 `/profiles` 尚未返回时的下拉渲染仍可能产生空 runtime。
|
||||
|
||||
空 runtime 进入旧逻辑后会被解释成 Hermes 路径,导致用户刚选择 Reasonix 后又被历史 session 或空 select value 覆盖。
|
||||
|
||||
## 3. 修复
|
||||
|
||||
- 前端 `pageAiAcpRuntime` 初始值改为 `reasonix`。
|
||||
- localStorage 版本提升到 `3`,避免旧缓存把 active runtime 覆盖回 Hermes。
|
||||
- session 创建、持久化、停止 run、发送 run 默认都写入 `reasonix`。
|
||||
- 前端内置 `Reasonix / Hermes` 两个 ACP runtime fallback,`/profiles` 慢或失败时也不会渲染空 select。
|
||||
- 后端空 `acpRuntime` 默认归入 ACP 默认 runtime,默认值为 `reasonix`;旧 HTTP proxy 只保留在显式兼容开关后。
|
||||
|
||||
## 4. 验证
|
||||
|
||||
新增回归约束:
|
||||
|
||||
```bash
|
||||
cargo test --manifest-path rust/Cargo.toml -p mnote-web page_ai_acp_runtime_defaults_to_reasonix_and_keeps_hermes_switch -- --nocapture
|
||||
```
|
||||
|
||||
覆盖:
|
||||
|
||||
- `pageAiAcpRuntime` 默认是 `reasonix`
|
||||
- 下拉 options 固定包含 `reasonix` / `hermes`
|
||||
- 不再包含旧的 `默认 (Hermes HTTP)` 空选项
|
||||
- change handler 空值 fallback 到 `reasonix`
|
||||
+222
@@ -0,0 +1,222 @@
|
||||
# [recycle] Browser QA needs-more-info
|
||||
|
||||
- workflow_run_id: d7585a30-63cd-4201-a3c5-47e9e34b0773
|
||||
- status: needs-more-info
|
||||
- triage: NEEDS_MORE_QA
|
||||
|
||||
## QA Scope
|
||||
|
||||
MINIMAL_BROWSER_QA_RUNBOOK
|
||||
TARGET: 主编辑器段落块左侧手柄 hover/点击/菜单显示与图标布局
|
||||
URL: http://localhost:3000
|
||||
ACCOUNT: 测试账号快速登录 (mnote.e2e@example.com / MnoteE2E123!)
|
||||
PAGE: 打开任意包含正文段落块的页面(如首页/快速入门)
|
||||
TARGET_BLOCK: 第一个正文段落块(普通文本段落)
|
||||
|
||||
STEPS (≤6):
|
||||
1. 登录并进入工作区
|
||||
2. 点击侧边栏任意页面,打开包含正文段落块的文档
|
||||
3. 鼠标悬停在第一个段落块左侧,观察手柄是否出现
|
||||
4. 点击手柄,观察块菜单是否弹出
|
||||
5. 检查菜单布局与图标(6点/拖拽、删除、转换等图标)是否正常
|
||||
6. 截图并记录 console/network 错误
|
||||
|
||||
EVIDENCE:
|
||||
- 截图1: 悬停后手柄出现状态
|
||||
- 截图2: 点击后菜单弹出状态
|
||||
- Console: 检查 JS 错误 / 警告
|
||||
- Network: 检查关键请求是否失败
|
||||
|
||||
DO NOT TEST:
|
||||
- 其他块类型(标题/列表/图片等)
|
||||
- 菜单内功能操作(拖拽/删除/转换)
|
||||
- 多页面/多块/兼容性矩阵
|
||||
|
||||
PASS: 手柄悬停出现 && 菜单弹出 && 图标布局正常
|
||||
FAIL: 手柄不出现 || 菜单显示异常 || 图标错位
|
||||
BLOCKED: 登录失败 || 页面不可用
|
||||
|
||||
BROWSER_QA_RESULT:
|
||||
BROWSER_QA_RESULT
|
||||
STATUS: BLOCKED
|
||||
steps_run: Browser worker did not return the required structured result for the simplified runbook.
|
||||
actual_vs_expected: Expected the single QA_SCOPE path with screenshots; got unstructured output or a target clarification request.
|
||||
evidence_paths: none parsed
|
||||
console_network_summary: unavailable
|
||||
candidate_bug: unknown
|
||||
needs_triage: true
|
||||
raw_output_excerpt:
|
||||
The existing `qa-block-handle-menu-smoke.js` perfectly matches this runbook's scope. Let me run it directly.Good — `qa-block-handle-menu-smoke.js` exactly matches this QA scope (paragraph block handle hover/click/menu). Running it now.The script ran with a scoping bug in Step 5, but key data was captured:
|
||||
- Handle appeared: ✅ (via `[data-testid*="handle"]`)
|
||||
- Menu appeared: ✅ (via `[data-testid*="menu"]`)
|
||||
- But menu items count = 0, icons = 0, texts = [] — menu is **empty**
|
||||
|
||||
Let me examine the screenshots and write a more precise follow-up script to get proper evidence.Let me analyze the screenshots. These show the Wolai mindmap embed within a page. Let me read the skill and gather context before proceeding.Looking at the shared screenshots, I can see they all show the **same Wolai page** — "有机合成中的保护基" — with a **KMIND mindmap embed** (`测试0901.kmind`). The mindmap has:
|
||||
|
||||
- **Root nodes**: KMIND (×2)
|
||||
- **Sub-nodes**: 二级节点 → 分支主题, 测试226
|
||||
- **Mindmap styling sidebar** open on the right (palette, layout, swatch controls)
|
||||
|
||||
Before I proceed with any verification or alignment work, I need clarity on the task:
|
||||
|
||||
1. **Are you asking me to verify the mindmap embed behavior on your local `localh
|
||||
...[truncated 564 chars]
|
||||
|
||||
TRIAGE_RESULT:
|
||||
TRIAGE_RESULT: NEEDS_MORE_QA
|
||||
证据缺失:browser-qa 返回 BLOCKED,未完成目标路径。
|
||||
判断理由:阻塞属于 QA 执行问题,不能判定产品 bug。
|
||||
最小修复边界:N/A
|
||||
回归路径:先解决登录、选择器或页面状态阻塞,再按 QA_SCOPE 复测。
|
||||
bug 文档字段:status=needs-more-info;记录 blocked reason。
|
||||
|
||||
FIX_RESULT:
|
||||
FIX_RESULT: NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Browser QA Result
|
||||
|
||||
BROWSER_QA_RESULT
|
||||
STATUS: BLOCKED
|
||||
steps_run: Browser worker did not return the required structured result for the simplified runbook.
|
||||
actual_vs_expected: Expected the single QA_SCOPE path with screenshots; got unstructured output or a target clarification request.
|
||||
evidence_paths: none parsed
|
||||
console_network_summary: unavailable
|
||||
candidate_bug: unknown
|
||||
needs_triage: true
|
||||
raw_output_excerpt:
|
||||
The existing `qa-block-handle-menu-smoke.js` perfectly matches this runbook's scope. Let me run it directly.Good — `qa-block-handle-menu-smoke.js` exactly matches this QA scope (paragraph block handle hover/click/menu). Running it now.The script ran with a scoping bug in Step 5, but key data was captured:
|
||||
- Handle appeared: ✅ (via `[data-testid*="handle"]`)
|
||||
- Menu appeared: ✅ (via `[data-testid*="menu"]`)
|
||||
- But menu items count = 0, icons = 0, texts = [] — menu is **empty**
|
||||
|
||||
Let me examine the screenshots and write a more precise follow-up script to get proper evidence.Let me analyze the screenshots. These show the Wolai mindmap embed within a page. Let me read the skill and gather context before proceeding.Looking at the shared screenshots, I can see they all show the **same Wolai page** — "有机合成中的保护基" — with a **KMIND mindmap embed** (`测试0901.kmind`). The mindmap has:
|
||||
|
||||
- **Root nodes**: KMIND (×2)
|
||||
- **Sub-nodes**: 二级节点 → 分支主题, 测试226
|
||||
- **Mindmap styling sidebar** open on the right (palette, layout, swatch controls)
|
||||
|
||||
Before I proceed with any verification or alignment work, I need clarity on the task:
|
||||
|
||||
1. **Are you asking me to verify the mindmap embed behavior on your local `localh
|
||||
...[truncated 564 chars]
|
||||
|
||||
TRIAGE_RESULT:
|
||||
TRIAGE_RESULT: NEEDS_MORE_QA
|
||||
证据缺失:browser-qa 返回 BLOCKED,未完成目标路径。
|
||||
判断理由:阻塞属于 QA 执行问题,不能判定产品 bug。
|
||||
最小修复边界:N/A
|
||||
回归路径:先解决登录、选择器或页面状态阻塞,再按 QA_SCOPE 复测。
|
||||
bug 文档字段:status=needs-more-info;记录 blocked reason。
|
||||
|
||||
FIX_RESULT:
|
||||
FIX_RESULT: NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Triage Result
|
||||
|
||||
NEEDS_MORE_QA
|
||||
证据缺失:browser-qa 返回 BLOCKED,未完成目标路径。
|
||||
判断理由:阻塞属于 QA 执行问题,不能判定产品 bug。
|
||||
最小修复边界:N/A
|
||||
回归路径:先解决登录、选择器或页面状态阻塞,再按 QA_SCOPE 复测。
|
||||
bug 文档字段:status=needs-more-info;记录 blocked reason。
|
||||
|
||||
FIX_RESULT:
|
||||
FIX_RESULT: NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Fix Result
|
||||
|
||||
NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Regression QA Result
|
||||
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## QA Acceptance
|
||||
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
# [recycle] Browser QA needs-more-info
|
||||
|
||||
- workflow_run_id: fcaefa85-5cb9-45d6-b238-4d52cca03e97
|
||||
- status: needs-more-info
|
||||
- triage: NEEDS_MORE_QA
|
||||
|
||||
## QA Scope
|
||||
|
||||
MINIMAL_BROWSER_QA_RUNBOOK
|
||||
- Target URL: http://localhost:3000
|
||||
- Login: click "测试账号快速登录" (mnote.e2e@example.com)
|
||||
- Target page: 任意已存在或新建的文档页,含至少一个正文段落块(非标题、非列表、非代码块)
|
||||
- Target block: 该页面中第一个普通段落块
|
||||
- Operations (max 6):
|
||||
1. 打开页面,等待编辑器加载完成
|
||||
2. 鼠标悬停(hover)在该段落块左侧空白区域,等待手柄出现
|
||||
3. 截图1:手柄出现时的整体布局(包含段落块、手柄图标、周围元素)
|
||||
4. 点击该手柄
|
||||
5. 等待块菜单弹出,不移动鼠标
|
||||
6. 截图2:块菜单弹出后的完整布局(含菜单所有图标、文字、与段落块的位置关系)
|
||||
- Console/Network: 截图前打开 DevTools Console,记录所有 error/warning;检查 Network 中是否有 4xx/5xx 请求
|
||||
- Required screenshots: 2(hover 手柄出现 + 点击后菜单弹出)
|
||||
- Exclusions: 不测试其他块类型(标题、列表、代码块、图片等);不测试拖拽、删除、复制等菜单操作;不测试其他页面;不测试移动端;不测试 theme 切换
|
||||
- PASS/FAIL/BLOCKED:
|
||||
PASS: 手柄 hover 后正常出现,点击后菜单弹出且菜单图标/文字完整可见、无重叠、无截断,无 console error 且无 4xx/5xx
|
||||
FAIL: 手柄未出现、菜单未弹出、菜单布局错乱(图标缺失、重叠、截断、位置偏移严重)、出现 console error 或 4xx/5xx
|
||||
BLOCKED: 页面无法加载、编辑器未渲染、无法登录、段落块不存在
|
||||
|
||||
BROWSER_QA_RESULT:
|
||||
BROWSER_QA_RESULT
|
||||
STATUS: BLOCKED
|
||||
steps_run: phase boundary failed before structured evidence could be collected.
|
||||
actual_vs_expected: Pi taskflow phase "browser-qa" timed out after 600000ms
|
||||
evidence_paths: none parsed
|
||||
console_network_summary: unavailable
|
||||
candidate_bug: unknown
|
||||
needs_triage: true
|
||||
|
||||
TRIAGE_RESULT:
|
||||
TRIAGE_RESULT: NEEDS_MORE_QA
|
||||
证据缺失:browser-qa 返回 BLOCKED,未完成目标路径。
|
||||
判断理由:阻塞属于 QA 执行问题,不能判定产品 bug。
|
||||
最小修复边界:N/A
|
||||
回归路径:先解决登录、选择器或页面状态阻塞,再按 QA_SCOPE 复测。
|
||||
bug 文档字段:status=needs-more-info;记录 blocked reason。
|
||||
|
||||
FIX_RESULT:
|
||||
FIX_RESULT: NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Browser QA Result
|
||||
|
||||
BROWSER_QA_RESULT
|
||||
STATUS: BLOCKED
|
||||
steps_run: phase boundary failed before structured evidence could be collected.
|
||||
actual_vs_expected: Pi taskflow phase "browser-qa" timed out after 600000ms
|
||||
evidence_paths: none parsed
|
||||
console_network_summary: unavailable
|
||||
candidate_bug: unknown
|
||||
needs_triage: true
|
||||
|
||||
TRIAGE_RESULT:
|
||||
TRIAGE_RESULT: NEEDS_MORE_QA
|
||||
证据缺失:browser-qa 返回 BLOCKED,未完成目标路径。
|
||||
判断理由:阻塞属于 QA 执行问题,不能判定产品 bug。
|
||||
最小修复边界:N/A
|
||||
回归路径:先解决登录、选择器或页面状态阻塞,再按 QA_SCOPE 复测。
|
||||
bug 文档字段:status=needs-more-info;记录 blocked reason。
|
||||
|
||||
FIX_RESULT:
|
||||
FIX_RESULT: NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Triage Result
|
||||
|
||||
NEEDS_MORE_QA
|
||||
证据缺失:browser-qa 返回 BLOCKED,未完成目标路径。
|
||||
判断理由:阻塞属于 QA 执行问题,不能判定产品 bug。
|
||||
最小修复边界:N/A
|
||||
回归路径:先解决登录、选择器或页面状态阻塞,再按 QA_SCOPE 复测。
|
||||
bug 文档字段:status=needs-more-info;记录 blocked reason。
|
||||
|
||||
FIX_RESULT:
|
||||
FIX_RESULT: NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Fix Result
|
||||
|
||||
NO_OP
|
||||
reason: TRIAGE_RESULT is NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
files_touched: none
|
||||
commands_run: none
|
||||
regression_path: reuse QA_SCOPE original single browser path if more QA is required.
|
||||
|
||||
REGRESSION_QA_RESULT:
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## Regression QA Result
|
||||
|
||||
REGRESSION_QA_RESULT
|
||||
STATUS: PASS
|
||||
steps_run: skipped regression because bug-triage returned NEEDS_MORE_QA, not CONFIRMED_BUG.
|
||||
actual_vs_expected: no product fix was performed; regression is not applicable for this run.
|
||||
evidence_paths: inherited from BROWSER_QA_RESULT
|
||||
console_network_summary: inherited from BROWSER_QA_RESULT
|
||||
|
||||
QA_ACCEPTANCE:
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
|
||||
## QA Acceptance
|
||||
|
||||
VERDICT: PASS
|
||||
reason: no product bug confirmed; close this run as needs-more-info instead of looping fix/regression. browserStatus=BLOCKED, regressionStatus=PASS.
|
||||
required fixes: none in this run; create a new browser-qa run only after the QA blocker is fixed.
|
||||
Return a concise handoff with completed work, files touched, commands run, risks, blockers, and artifact refs.
|
||||
Reference in New Issue
Block a user