merge: feature/task-bubble-bind-2026-09-23 (assistant_msg_id bind + error actions)

This commit is contained in:
WeiCHEN
2026-09-23 11:49:50 +08:00
34 changed files with 442 additions and 43 deletions
@@ -0,0 +1,43 @@
---
title: "任务气泡 serverId 绑定与失败卡按钮修复"
task_id: "task-bubble-bind-2026-09-23"
status: done
created: 2026-09-23
updated: 2026-09-23
owner: Cursor
task_type: implementation
task_tier: small
policy_revision: "agent-governance-2026-09-21-r1 @ 15fdb28aa18af456c33fe06f0dce93813d112cc8"
branch: feature/task-bubble-bind-2026-09-23
worktree: .worktrees/task-bubble-bind-2026-09-23
base_dev_sha: "15fdb28aa18af456c33fe06f0dce93813d112cc8"
head_sha: "b9b192a8430a47aebb1ab064f6c71370e8ef516d"
write_scope: ["web/src", "internal/server", ".doc"]
allowed_environments: ["test"]
mutex: "web-task-bubble+task-run-api"
review_state: pending
integration_state: pending
deployment: test_app_overlay_from_worktree
cleanup: pending
cleanup_owner: "独立维护者"
cleanup_trigger: "合入 local_dev 且 tip 为祖先后"
remote_sync: not_requested
---
# 任务气泡 serverId 绑定与失败卡按钮修复
## 用户目标
test 环境任务卡双气泡/排序错乱/刷新退化;继续任务按钮无反应;同时确认 test Runner 已部署响应体积修复。
## 步骤
1. [x] createTaskRun 响应返回 assistant_msg_id;前端绑定 serverId + clientTurnId
2. [x] 失败卡:不可 resume 时隐藏 continue;restart 新开 turn/气泡
3. [x] test 重建核验 + 场景/LiveDualTrack 证据
4. [x] web 回归 + 浏览器验证;报告落盘
## 相关
- 报告:[2026-09-23-task-bubble-bind-test-report](../../test-reports/2026-09-23-task-bubble-bind-test-report.md)
- Plan: test 环境验证 + 前端任务卡修复
@@ -0,0 +1,46 @@
# 测试报告:任务气泡 serverId 绑定与 test 环境核验
- **日期**: 2026-09-23
- **任务**: [2026-09-23-task-bubble-bind](../ops/short-term/2026-09-23-task-bubble-bind.md)
- **被测 SHA**: `b9b192a8`(`feature/task-bubble-bind-2026-09-23`)
- **环境**: test(`:8081` / Runner `:18866` MiniMax-M3);app 镜像由本 worktree 源码构建并 `--force-recreate`
- **判定**: PASS(范围内)
## 范围
1. test Runner `capPatches` 与 LiveDualTrack(typed reject 体积路径)
2. `POST /api/v1/tasks/runs` 返回 `assistant_msg_id`;前端绑定 serverId / clientTurnId;失败卡不展示不可 resume 的「继续任务」
3. `web` `npm test` / `npm run build`;浏览器登录后发任务话术并刷新
## 命令与结果
| 检查 | 结果 | 证据 |
|---|---|---|
| arch-check --mode block | PASS | [arch-check.txt](./assets/2026-09-23-task-bubble-bind/arch-check.txt) |
| web npm test | PASS(491 + 34) | [node-test.txt](./assets/2026-09-23-task-bubble-bind/node-test.txt) |
| web npm run build | PASS | 本地构建日志 |
| go test -short ./internal/server | PASS(含 TypedReject→fatal) | 本会话执行 |
| test `/health` + Runner health | ok / MiniMax-M3 | [app](./assets/2026-09-23-task-bubble-bind/task-bubble-test-app-health.json) · [runner](./assets/2026-09-23-task-bubble-bind/task-bubble-test-runner-health.json) |
| createTaskRun `assistant_msg_id` | 202 + id=242 | [create-task-run.json](./assets/2026-09-23-task-bubble-bind/create-task-run.json) · [scenario-verdict.json](./assets/2026-09-23-task-bubble-bind/scenario-verdict.json) |
| LiveDualTrack @ test Runner | PASS 4.36s | [live-dualtrack.txt](./assets/2026-09-23-task-bubble-bind/live-dualtrack.txt) |
| 浏览器发任务 + 刷新 | 同 turn 无双「任务执行中」占位 | [browser-verify.json](./assets/2026-09-23-task-bubble-bind/browser-verify.json) · screenshots |
## 预期 vs 实际
| 预期 | 实际 |
|---|---|
| Runner 含 `capPatches` | 容器内 `result-v1.mjs` 可见 |
| 不再以 typed reject 伪装可继续 | LiveDualTrack PASS;classify fatal 文案在 app binary |
| create 响应带 `assistant_msg_id` | 有 |
| 终端 failed 不提供 continue | legacy map + handleErrorAction 守卫;单测覆盖 |
| 刷新后无同 turn 双气泡 | 浏览器刷新后每 turn 一张助手卡 |
## 缺项 / 风险
- 完整「已激活工作流」长 E2E intake 本轮因默认 plan 保存校验未走通,未跑通真实文档生成;typed reject 体积路径以 LiveDualTrack + Runner 制品核验为准。
- test app 镜像由 worktree 构建覆盖,尚未合入 local_dev;合入前勿假定 main 构建上下文含本提交。
- `integration_state=pending`;`cleanup=pending`。
## 结论
工作流 A(test Runner/classify 制品)与工作流 B(气泡绑定 + 按钮守卫)在授权 test 环境内验收通过;待合入 local_dev。
@@ -0,0 +1,3 @@
{
"raw": "Method Not Allowed\n"
}
@@ -0,0 +1,6 @@
{
"code": "VALIDATION",
"message": "请求参数无效",
"request_id": "req_b8cd81eead320278",
"error": "{\"error\":\"ERR_INVALID_PLAN\",\"message\":\"invalid workflow plan: no saved plan\"}"
}
@@ -0,0 +1,5 @@
arch-check mode=block
boundaries=/private/tmp/Agent-System/.worktrees/task-bubble-bind-2026-09-23/.doc/system-design/module-boundaries.yaml
ok chat-agent-system/internal/archtest 0.978s
ok chat-agent-system/internal/archtest 0.486s
arch-check block: production gate passed
Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 KiB

@@ -0,0 +1,15 @@
{
"env": "test",
"base_url": "http://127.0.0.1:8081",
"observations": [
"login as admin succeeded",
"send「根据我上传的文档,编写用户初始需求收集表」showed single live task card (执行中) for the new turn",
"refresh kept one assistant card per turn (blocked_pending_governance / 待激活工作流); no duplicated 任务执行中 placeholder for the same turn",
"deployed web bundle contains assistant_msg_id and 正在重新开始任务 markers"
],
"screenshots": [
"browser-chat.png",
"browser-chat-settled.png",
"browser-after-refresh.png"
]
}
@@ -0,0 +1,9 @@
{
"http_status": 202,
"run_id": "run_1790133483248059802",
"status": "blocked_pending_governance",
"assistant_msg_id": 242,
"workspace_id": null,
"error_code": null,
"message": ""
}
@@ -0,0 +1,15 @@
{
"status": 200,
"keys": [
"workflow_definition_key",
"workflow_version",
"workflow_version_id",
"stages"
],
"plan_keys": [
"workflow_definition_key",
"workflow_version",
"workflow_version_id",
"stages"
]
}
@@ -0,0 +1,3 @@
assistant_msg_id present in /app/server
capPatches present in runner result-v1.mjs
classify fatal copy present
@@ -0,0 +1,12 @@
=== RUN TestPiAgentTypedResult_LiveDualTrack
=== RUN TestPiAgentTypedResult_LiveDualTrack/failure_empty_prompt
=== RUN TestPiAgentTypedResult_LiveDualTrack/timeout
=== RUN TestPiAgentTypedResult_LiveDualTrack/cancel
=== RUN TestPiAgentTypedResult_LiveDualTrack/success
--- PASS: TestPiAgentTypedResult_LiveDualTrack (4.36s)
--- PASS: TestPiAgentTypedResult_LiveDualTrack/failure_empty_prompt (0.02s)
--- PASS: TestPiAgentTypedResult_LiveDualTrack/timeout (0.01s)
--- PASS: TestPiAgentTypedResult_LiveDualTrack/cancel (0.30s)
--- PASS: TestPiAgentTypedResult_LiveDualTrack/success (4.02s)
PASS
ok chat-agent-system/internal/agent 5.431s
@@ -0,0 +1 @@
status=200 user_id=4
@@ -0,0 +1,20 @@
✔ 2. 切回项目时相同正文不应因 temp/server id 差异重复展示 (0.070333ms)
✔ 工作流切换与消息展示时序测试套件 (0.924292ms)
✔ DeliverableItem 必须包含 projectId 与 isTemplateOnly 属性 (0.409333ms)
ℹ tests 491
ℹ suites 38
ℹ pass 491
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 3110.608583
RUN v5.0.0 /private/tmp/Agent-System/.worktrees/task-bubble-bind-2026-09-23/web
Test Files 3 passed (3)
Tests 34 passed (34)
Start at 11:09:56
Duration 292ms (transform 63%, import 29%, tests 6%, worker 2%)
@@ -0,0 +1,19 @@
{
"id": 6011,
"code": "task-bubble--0056305d",
"name": "task-bubble-bind-1790133432",
"customer_name": "",
"device_type": "肌骨超声",
"intended_use": "",
"target_market": "",
"current_stage": "V0.1_triage",
"environment": "dev",
"status": "active",
"creator_user_id": 4,
"lifecycle_status": "planning",
"active_workflow_key": "",
"workflow_selection_version": 1,
"workflow_plan_revision": 0,
"created_at": "2026-09-23T03:17:12.134425334Z",
"updated_at": "2026-09-23T03:17:12.134425334Z"
}
@@ -0,0 +1 @@
status=200 type=list
@@ -0,0 +1,41 @@
{
"error": "VALIDATION_FAILED",
"issues": [
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_intake"
},
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_research"
},
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_feasibility_dev"
},
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_feasibility_reg"
},
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_user_requirements"
},
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_prelim_design"
},
{
"code": "SEPARATION_OF_DUTY_VIOLATION",
"message": "作者、审核人、批准人必须分离",
"field": "bd_cdo_quote"
}
],
"message": "工作流配置校验未通过"
}
@@ -0,0 +1,8 @@
{
"assistant_msg_id_in_create": true,
"final_status": "blocked_pending_governance",
"typed_result_rejected": false,
"has_fatal_validate_copy": false,
"resumable": false,
"error_snippet": ""
}
@@ -0,0 +1,9 @@
{
"session_id": "sess-p6011-u4-bubble",
"title": "bubble bind probe",
"user_id": 4,
"project_id": 6011,
"project_name": "task-bubble-bind-1790133432",
"message_count": 0,
"updated_at": "2026-09-23T03:18:03.233795Z"
}
@@ -0,0 +1 @@
{"status":"ok","env":"test","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"kb_ready":true,"database_ready":true,"schema_version":65,"schema_ready":true,"task_store_ready":true}
@@ -0,0 +1 @@
{"ok":true,"service":"shuimu-pi-agent-runner","endpoint_url":"https://api.minimaxi.com/v1","model_id":"MiniMax-M3","api":"openai-compatible","has_token":true,"tavily":{"active":true,"keys_count":2},"data_dir":"/app/data/workspaces","uptime":18.608525759}
@@ -0,0 +1,9 @@
{
"poll": 1,
"http_status": 200,
"status": "blocked_pending_governance",
"error_message": "",
"workspace_id": null,
"resumable": false,
"assistant_message_id": 242
}
@@ -0,0 +1,3 @@
{
"raw": "404 page not found\n"
}