docs(test): record U10 ChatLog ports and live chat refresh evidence
Archive the finished chat mutex tasks, attach PI idle-chat refresh same-set evidence for project 6252, and stop expansion after in-place ports without a package split. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: "修复对话刷新恢复与授权统计不一致"
|
||||
status: in_progress
|
||||
status: done
|
||||
created: 2026-09-13
|
||||
updated: 2026-09-13
|
||||
updated: 2026-09-15
|
||||
owner: Cursor
|
||||
branch: fix/chat-history-refresh
|
||||
worktree: ".worktrees/fix-chat-history-refresh"
|
||||
@@ -37,7 +37,7 @@ mutex: chat
|
||||
3. [x] 实现统一会话/消息授权查询及统计同集
|
||||
4. [x] 实现历史 dry-run/backfill 与对账
|
||||
5. [x] 完善前端恢复状态及用户隔离缓存
|
||||
6. [ ] 执行全量门禁、真实 PI 刷新 E2E 和双用户负例(PG/单测已完成;PI 待 dev 容器)
|
||||
6. [x] 执行全量门禁、真实 PI 闲聊刷新 E2E 和双用户负例(编制任务激活链 save 400 未纳入本轮)
|
||||
|
||||
## 验收标准
|
||||
|
||||
@@ -55,3 +55,4 @@ mutex: chat
|
||||
|
||||
- Audit: [../../audit/2026-09-13-chat-history-refresh-disappears.md](../../audit/2026-09-13-chat-history-refresh-disappears.md)
|
||||
- Remediation: [../../remediation/2026-09-13-chat-history-refresh-remediation.md](../../remediation/2026-09-13-chat-history-refresh-remediation.md)
|
||||
- Live: [../../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json](../../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json)(项目 6252,window=categories=2,guest 403)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: "U10 chatlog/contextasm 原地端口化"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
owner: Cursor
|
||||
branch: feature/chatlog-contextasm-u10
|
||||
worktree: "-"
|
||||
mutex: chat
|
||||
---
|
||||
|
||||
# U10 chatlog/contextasm 原地端口化
|
||||
|
||||
## 目标
|
||||
|
||||
在不物理拆包的前提下,为对话读取与 prompt 装配建立带 Principal 的消费者端口,使正文、分类、计数、导出、摘要和恢复使用同一授权可见集合。
|
||||
|
||||
## 范围
|
||||
|
||||
- `internal/app/chatflow` ChatLog / ContextAssembler 端口
|
||||
- ctxmgr 表所有权不变;adapter 内做可见性过滤
|
||||
- server 历史读取 handler 改走 ChatLog;忽略 query/body 中的 user_id 身份
|
||||
- 会话 restore / 记忆召回只注入允许集合
|
||||
- 不碰 `intent` mutex,不物理搬到 `chatlog`/`contextasm` 包
|
||||
|
||||
## 非目标
|
||||
|
||||
- U11–U12
|
||||
- 整支 merge `feature/final-artifact-vault`
|
||||
- 启用 `FAV_DEGRADED_READ`
|
||||
- 纯搬包
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 核实 `chat` mutex:`fix/chat-history-refresh` 已是 `dev` 祖先;剩余真实 PI 刷新与 U10 同批收口
|
||||
2. [x] 从最新 `dev` 开 `feature/chatlog-contextasm-u10` 并登记 CURRENT
|
||||
3. [x] 定义 chatflow 端口与 ctxmgr adapter
|
||||
4. [x] 迁移 window/day/stats/search/unread/export/digest/history/restore/memory
|
||||
5. [x] 合同测试:同集计数、非 owner 403、restore/digest 不放大不可见消息
|
||||
6. [x] 验收报告;最后一句 **停止扩面**
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 刷新前后同一授权集合的正文与分类计数一致(adapter 合同测试)
|
||||
- [x] 跨用户负例 fail closed(guest 非 owner)
|
||||
- [x] context assembly / digest 只使用允许集合
|
||||
- [x] 真实 PI 闲聊刷新 E2E 证据(与对话刷新活验同批;编制任务链 save 400 未纳入停走)
|
||||
- [x] 未物理拆包;DTO 转换为 0,拆包收益不成立
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Checklist: [../checklists/2026-09-14-module-decoupling-refactor-acceptance.md](../checklists/2026-09-14-module-decoupling-refactor-acceptance.md)
|
||||
- Plan: [../../remediation/2026-09-14-module-decoupling-refactor-plan.md](../../remediation/2026-09-14-module-decoupling-refactor-plan.md)
|
||||
- Chat refresh: [../../test-reports/2026-09-13-chat-history-refresh-test-report.md](../../test-reports/2026-09-13-chat-history-refresh-test-report.md)
|
||||
- Test report: [../../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md](../../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md)
|
||||
|
||||
## 证据 / 备注
|
||||
|
||||
U9 最后一句 **继续 U10** 只批准进入 M4。禁止 U11–U12。`intent` 认领仍 `in_progress`,本单元不改意图分类。活验项目 6252 / `sess-p6252-u10`;产物 `.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`。未占槽 rebuild。
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: "对话刷新恢复整改 Checklist"
|
||||
status: in_progress
|
||||
status: done
|
||||
created: 2026-09-13
|
||||
updated: 2026-09-13
|
||||
related_task: "../short-term/2026-09-13-chat-history-refresh-remediation.md"
|
||||
updated: 2026-09-15
|
||||
related_task: "../2026-09-13-chat-history-refresh-remediation.md"
|
||||
---
|
||||
|
||||
# 对话刷新恢复整改 Checklist
|
||||
@@ -36,10 +36,10 @@ related_task: "../short-term/2026-09-13-chat-history-refresh-remediation.md"
|
||||
## Wave 5 — 验收
|
||||
|
||||
- [x] `go test -short ./...` — 证据:本机执行输出
|
||||
- [ ] 真实 PI 刷新 E2E(需 dev 容器 + pi-agent)— 证据:待 test-report 补录
|
||||
- [x] 真实 PI 刷新 E2E(需 dev 容器 + pi-agent)— 证据:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`(项目 6252 闲聊刷新同集 + guest 403;编制任务链未通过)
|
||||
- [x] 测试报告归档 — 证据:`.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md`
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [ ] 全部勾选且有证据链接
|
||||
- [ ] gap-matrix `CHAT-HISTORY-REFRESH` → PASS
|
||||
- [x] 全部勾选且有证据链接
|
||||
- [x] gap-matrix `CHAT-HISTORY-REFRESH` → PASS
|
||||
|
||||
@@ -76,7 +76,7 @@ severity: high
|
||||
## 关联整改
|
||||
|
||||
- Remediation: [../remediation/2026-09-13-chat-history-refresh-remediation.md](../remediation/2026-09-13-chat-history-refresh-remediation.md)
|
||||
- Short-term: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/2026-09-13-chat-history-refresh-remediation.md)
|
||||
- Short-term: [../archive/ops/2026-09-13-chat-history-refresh-remediation.md](../archive/ops/2026-09-13-chat-history-refresh-remediation.md)
|
||||
- Gap matrix: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
|
||||
|
||||
## 证据
|
||||
|
||||
+7
-5
@@ -5,14 +5,16 @@
|
||||
|
||||
## 焦点
|
||||
|
||||
1. **DOC-RELIABILITY**: [M3 U9 已签,继续 U10](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md)(任务已归档 [2026-09-15-dataset-lifecycle-u9](../archive/ops/2026-09-15-dataset-lifecycle-u9.md);U9 最后一句 **继续 U10**;U10 须等待 `chat` mutex;**未开工 U10 前禁止 U11–U12**)
|
||||
2. **CHAT-INTENT**: [对话意图运行时状态](../audit/2026-09-13-conversation-intent-runtime-state.md)(`fix/conversation-intent-state`;与文档账本运行时无关)
|
||||
3. **CHAT**: [对话历史刷新](../audit/2026-09-13-chat-history-refresh-disappears.md)(认领仍 `in_progress`;gap 行已 PASS,以代码/handoff 为准收敛)
|
||||
1. **CHAT-INTENT**: [对话意图运行时状态](../audit/2026-09-13-conversation-intent-runtime-state.md)(`fix/conversation-intent-state` 已是 `dev` 祖先;浏览器双标签 busy 仍待 Codex 收口)
|
||||
2. **DOC-RELIABILITY**: [U10 停止扩面](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md)(未合入 `dev`;合入须占集成槽 rebuild。**禁止 U11–U12**)
|
||||
3. **CHAT**: [对话历史刷新活验已补](../test-reports/2026-09-13-chat-history-refresh-test-report.md)(项目 6252 闲聊刷新同集 + guest 403;编制任务链仍开放)
|
||||
|
||||
## 并行认领
|
||||
|
||||
| owner | task | branch | worktree | mutex | status |
|
||||
|-------|------|--------|----------|-------|--------|
|
||||
| Cursor | chatlog-contextasm-u10 | feature/chatlog-contextasm-u10 | - | chat | done |
|
||||
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | done |
|
||||
| Cursor | dataset-lifecycle-u9 | feature/dataset-lifecycle-u9 | - | dataset | done |
|
||||
| Cursor | taskrun-runmanifest-u8 | feature/taskrun-runmanifest | - | taskrun | done |
|
||||
| Cursor | document-reliability-m1-live-and-m2 | refactor/document-reliability-pilot | .worktrees/refactor-document-reliability-pilot | workspace | done |
|
||||
@@ -21,7 +23,6 @@
|
||||
| implementer_cursor | controlled-content-canonical-hash | fix/controlled-content-canonical-hash | .worktrees/fix-controlled-content-canonical-hash | docgov | done |
|
||||
| Codex | project143-controlled-content-404-diagnosis | fix/project143-controlled-content-404-diagnosis | - | docgov-content-diagnosis | done |
|
||||
| Codex | software-project-bootstrap-plan | feature/software-project-bootstrap-plan | - | workflow-design | done |
|
||||
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | in_progress |
|
||||
| Codex | conversation-intent-runtime-state | fix/conversation-intent-state | .worktrees/fix-conversation-intent-state | intent | in_progress |
|
||||
| Cursor | document-revision-wave1-6-implementation | feature/document-revision-management | - | docgov | done |
|
||||
| Cursor-Auto | document-revision-runtime-ui03 | fix/document-revision-runtime-ui03 | - | docgov | done |
|
||||
@@ -56,7 +57,7 @@
|
||||
> 新任务开始前登记。`branch` 必须为 `feature/<slug>` 或 `fix/<slug>`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。
|
||||
|
||||
> workflow-plan 409 与治理鉴权 G1–G5 已收口(见 [test-report](../test-reports/2026-09-14-governance-action-level-authz-test-report.md))。禁止终止或改写项目 143。
|
||||
> `document-reliability-pilot` U9 已签(继续 U10)。U10 须等待 `chat` mutex。禁止 worktree 内 `env-service`。项目 143 只读,禁止终止。未开工 U10 前禁止 U11–U12。
|
||||
> `document-reliability-pilot` U10 **停止扩面**(`chat` mutex 已释放)。禁止 U11–U12。禁止 worktree 内 `env-service`。项目 143 只读,禁止终止。不碰 `intent`。
|
||||
|
||||
## 集成槽位
|
||||
|
||||
@@ -97,6 +98,7 @@
|
||||
| 文档可靠性 M2 | [../test-reports/2026-09-14-document-reliability-m2-test-report.md](../test-reports/2026-09-14-document-reliability-m2-test-report.md) |
|
||||
| 文档可靠性 M3 U8 | [../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md) |
|
||||
| 文档可靠性 M3 U9 | [../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md) |
|
||||
| 文档可靠性 M4 U10 | [../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md) |
|
||||
| SSE/幂等审计 | [../audit/2026-09-13-document-revision-sse-idempotency.md](../audit/2026-09-13-document-revision-sse-idempotency.md) |
|
||||
| 质量门禁自污染审计 | [../audit/2026-09-13-document-revision-quality-gate-self-pollution.md](../audit/2026-09-13-document-revision-quality-gate-self-pollution.md) |
|
||||
| 当前文档路由审计 | [../audit/2026-09-13-document-revision-active-doc-routing.md](../audit/2026-09-13-document-revision-active-doc-routing.md) |
|
||||
|
||||
@@ -48,8 +48,8 @@ owner: Cursor
|
||||
|
||||
## M4–M6 选择性扩展
|
||||
|
||||
- [ ] 每个子切片在原包边界先获得行为收益,再决定物理搬包。
|
||||
- [ ] chatlog/contextasm 保持授权可见集合和计数一致。
|
||||
- [x] 每个子切片在原包边界先获得行为收益,再决定物理搬包。
|
||||
- [x] chatlog/contextasm 保持授权可见集合和计数一致。
|
||||
- [ ] app 是唯一组合根,subscriber 重复启动不重复注册。
|
||||
- [ ] UserProjectContext 不再被多个模块字段级直改。
|
||||
- [ ] server 无 SQL、路径拼接和业务闭包。
|
||||
@@ -69,6 +69,6 @@ owner: Cursor
|
||||
|
||||
## 关闭条件
|
||||
|
||||
- [ ] test report 回链具体 U-ID、commit、环境 identity 和 fixture/dataset。
|
||||
- [ ] CURRENT、FEATURE-MATRIX、gap-matrix 与任务状态一致。
|
||||
- [ ] 未实施后续仍为 planned/deferred,不用局部测试冒充全计划完成。
|
||||
- [ ] test report 回链具体 U-ID、commit、环境 identity 和 fixture/dataset。(U10 已回链;U11–U12 未实施,禁止用 U10 冒充全计划完成)
|
||||
- [x] CURRENT、FEATURE-MATRIX、gap-matrix 与任务状态一致。
|
||||
- [x] 未实施后续仍为 planned/deferred,不用局部测试冒充全计划完成。
|
||||
|
||||
@@ -61,5 +61,5 @@ updated: 2026-09-13
|
||||
## 相关链接
|
||||
|
||||
- Audit: [../audit/2026-09-13-chat-history-refresh-disappears.md](../audit/2026-09-13-chat-history-refresh-disappears.md)
|
||||
- Short-term: [../ops/short-term/2026-09-13-chat-history-refresh-remediation.md](../ops/short-term/2026-09-13-chat-history-refresh-remediation.md)
|
||||
- Short-term: [../archive/ops/2026-09-13-chat-history-refresh-remediation.md](../archive/ops/2026-09-13-chat-history-refresh-remediation.md)
|
||||
- gap-matrix 行: `CHAT-HISTORY-REFRESH`
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|---|---|---|---|---|
|
||||
| WORKFLOW-PLAN-FROZEN-OPTIONAL-DUTIES | active 项目仍展示可编辑职责表单,409 提示在长表单视口外;现有规划又不支持非必需文档“三权全空”,且后端缺少职责人在任成员复核 | **PASS(设置页)** | [audit](../audit/2026-09-14-workflow-plan-409-frozen-and-optional-duties.md);[test-report](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md)。项目 143 只读 frozen、A full+none 激活、B partial 不发 PUT、C 零治理拒绝、双标签转 frozen、成员无配置入口、刷新后 143 仍 frozen | 真实 PI 生成 full/none 并走审批/阶段不阻塞未纳入本轮页面矩阵,不作为本 gap 关闭的替代证据,另立项 |
|
||||
| DOC-CONTENT-CANONICAL-HASH-DRIFT | 旧受控文档 bootstrap 裁剪 Markdown 双空格硬换行并将 canonical SHA 写入账本/DocGov,但未同步文件;正文读取把完整性冲突误报 404,lease/list sync 又放大并制造刷新后加载死锁 | **PASS(真实 UI)** | [audit](../audit/2026-09-14-project143-controlled-content-404.md);[UI report](../test-reports/2026-09-14-controlled-content-ui-acceptance.md)。代码已合 dev、schema 32、项目 143 定向 `migration_repair`;项目 143 `clean-run3` 与新项目 `full-chain-final` 主链及 restart 全部纯页面 PASS,目标 404=0 | [remediation](./2026-09-14-controlled-content-canonical-hash-remediation.md)。隔离 `TestReconcile_LegacyRepair_PG` 未执行,按用户“本轮只允许页面测试”的边界保留为工程测试债,不作为本轮 UI PASS 的替代证据 |
|
||||
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 真实 PI 刷新 E2E 待 dev 容器补录(自动化/PG 已 PASS) |
|
||||
| CHAT-HISTORY-REFRESH | 工作流激活后刷新,对话正文被阶段过滤器清空,但分类数量与锚点仍按全量返回 | **PASS** | [test-report](../test-reports/2026-09-13-chat-history-refresh-test-report.md);活验 [live.json](../test-reports/assets/2026-09-15-chat-history-refresh-live/live.json)(项目 6252,window=categories=2,guest 403);代码:`message_scope.go`、`chat_history_auth.go`、goose 00026/00027 | 闲聊刷新已补。发布门禁「激活后文档任务 + 重登/重启」仍开放,不回退本 gap |
|
||||
| CHAT-INTENT-STATE | 真实会话被诊断探针污染;只读查询误启动文档写任务;错误动作与编辑状态刷新后丢失 | **FAIL** | [audit](../audit/2026-09-13-conversation-intent-runtime-state.md);dev `sess-p143-u9` / task run / lease 现场 | [remediation](./2026-09-13-conversation-intent-runtime-state-remediation.md) |
|
||||
| ENV-RESTART-SOURCE | `docker compose restart` 只重启旧镜像,健康检查无法证明合入代码已部署 | **PASS** | `env-service.sh rebuild` + 真实摘要重测 | 集成冒烟统一使用 `dev rebuild` |
|
||||
| DOCREV-RUNTIME-404 | revision-state 404;账本内存丢失;块保存/overlay 无效;agent 假报告 | **PASS** | [Round20 报告](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[audit](../audit/2026-09-13-document-revision-runtime-404.md) | 运行时 UI 已闭环。change report 仍为 fallback,不冒充 PI。历史失败目录不删 |
|
||||
@@ -70,7 +70,7 @@
|
||||
| DOCREV-ACTIVE-DOC-ROUTING | UI-05「当前受控文档」被法规关键词改路由到 `feasibility_reg`,intake 无 pending | **PASS** | [audit](../audit/2026-09-13-document-revision-active-doc-routing.md);Round20 UI-05 pending 停在 intake V2 | **不改弱 E2E**;不删证据 |
|
||||
| DOCREV-QUALITY-STATUS-FP | 行动计划表状态列「待续」被门禁当敷衍,两轮 repair 后 quality_failed 80 | **PASS** | [audit](../audit/2026-09-13-document-revision-quality-status-false-positive.md);Round20 UI-03 | **不删禁词、不放宽正文**;不删证据 |
|
||||
| GOVERNANCE-ACTION-AUTHZ | 文档动作按职责鉴权;未激活 202-blocked;关闭创建直通 | **PASS** | [test-report](../test-reports/2026-09-14-governance-action-level-authz-test-report.md);[audit 异态](../audit/2026-09-14-planning-with-workflow-key-anomaly.md) | 不改 83 条 planning+key 夹具;none 长 PI 审批链另开 |
|
||||
| DOC-RELIABILITY-PILOT | 受控文档写路径跨表非同事务、读路径被 projection 绑架、授权 TOCTOU;刷新/重启后可能 404/409/projection-missing | OPEN | [复核](../audit/2026-09-14-module-decoupling-plan-review.md);[重构计划](./2026-09-14-module-decoupling-refactor-plan.md);[试点任务](../ops/short-term/2026-09-14-document-reliability-pilot.md);[M1 停止扩面](../test-reports/2026-09-14-document-reliability-pilot-test-report.md);[M1 活验](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md);[M2](../test-reports/2026-09-14-document-reliability-m2-test-report.md);[M3 U8](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md);[M3 U9](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md) | M2 **继续 M3**。U8 **继续 U9**。U9 **继续 U10**(须等 `chat` mutex)。禁止在 U10 开工前写 U11–U12 业务代码 |
|
||||
| DOC-RELIABILITY-PILOT | 受控文档写路径跨表非同事务、读路径被 projection 绑架、授权 TOCTOU;刷新/重启后可能 404/409/projection-missing | OPEN | [复核](../audit/2026-09-14-module-decoupling-plan-review.md);[重构计划](./2026-09-14-module-decoupling-refactor-plan.md);[试点任务](../ops/short-term/2026-09-14-document-reliability-pilot.md);[M1 停止扩面](../test-reports/2026-09-14-document-reliability-pilot-test-report.md);[M1 活验](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md);[M2](../test-reports/2026-09-14-document-reliability-m2-test-report.md);[M3 U8](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md);[M3 U9](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md);[U10 停止扩面](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md) | M3 已签。U10 **停止扩面**(未拆包)。禁止 U11–U12 业务代码。U10 分支未合入 `dev` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
| 模块 | 能力 | 状态 | 证据 | 缺口/后续 | mutex |
|
||||
|------|------|------|------|-----------|-------|
|
||||
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/intent-recognition](../system-design/intent-recognition/);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md) | 明确写动作与只读总结已分流;完整 hard-negative/eval 集仍待补齐 | `intent` |
|
||||
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | `CHAT-HISTORY-REFRESH`:作用域写入、同集授权统计、历史回填;语义摘要(D5 backlog) | `chat` |
|
||||
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md);[U10 端口化](../archive/ops/2026-09-15-chatlog-contextasm-u10.md);[U10 报告](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md) | `CHAT-HISTORY-REFRESH` 闲聊刷新活验已补。U10 原地端口 **停止扩面**(未物理拆包)。语义摘要(D5 backlog) | `chat` |
|
||||
| 智能体小队 | 角色-任务-工作区-黑板 | done | [system-design/agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6 backlog) | `squad` |
|
||||
| 工作流治理 | 三正式工作流 + 阶段门禁 | partial | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md);[冻结态/职责可选整改](../remediation/2026-09-14-workflow-plan-409-frozen-and-optional-duties-remediation.md);[Wave 5 页面矩阵](../test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md);[职责-动作鉴权](../test-reports/2026-09-14-governance-action-level-authz-test-report.md) | 设置页/DutyMode + 动作级鉴权/未激活 202-blocked/关闭创建直通已落地。后续:none 文档真实 PI 审批长链路、CI 三工作流 E2E | `workflow` |
|
||||
| 纯软件项目自举 | 软件项目创建、Bootstrap 基线、Delivery 迭代与受控工程交接 | planned | [详细设计](../system-design/2026-09-14-software-project-bootstrap-workflow.md);[现状调研](../ops/research/2026-09-14-software-project-bootstrap-current-state.md);[验收计划](../ops/checklists/2026-09-14-software-project-bootstrap-acceptance.md) | 当前仅完成方案;目录/模板/执行器/创建向导/真实 PI UI 均未实施。受控代码执行单列后续 Epic | `workflow-design` |
|
||||
@@ -27,7 +27,7 @@
|
||||
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md) | — | `pi-agent` |
|
||||
| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` |
|
||||
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | CI `TEST_DATABASE_URL` 隔离库仍缺;文档运行时真实 UI 已按 UI_PHASE 分文件且 post-restart 断言最终 A1 正文。`-race` 全包并行 TempDir flake 为基建残留 | `ci` |
|
||||
| 模块解耦与可靠事件 | 文档可靠性纵向试点、跨属主事务、多副本互斥、FAV 与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[试点任务](../ops/short-term/2026-09-14-document-reliability-pilot.md);[M1 停止扩面](../test-reports/2026-09-14-document-reliability-pilot-test-report.md);[M1 活验](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md);[M2](../test-reports/2026-09-14-document-reliability-m2-test-report.md);[M3 U8](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md);[M3 U9](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md) | U5–U9 PASS。M2 **继续 M3**;U8 **继续 U9**;U9 最后一句 **继续 U10**(须等 `chat` mutex)。未开工 U10–U12 | `dataset` |
|
||||
| 模块解耦与可靠事件 | 文档可靠性纵向试点、跨属主事务、多副本互斥、FAV 与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[重构计划](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[试点任务](../ops/short-term/2026-09-14-document-reliability-pilot.md);[M1 停止扩面](../test-reports/2026-09-14-document-reliability-pilot-test-report.md);[M1 活验](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md);[M2](../test-reports/2026-09-14-document-reliability-m2-test-report.md);[M3 U8](../test-reports/2026-09-15-taskrun-runmanifest-u8-test-report.md);[M3 U9](../test-reports/2026-09-15-dataset-lifecycle-u9-test-report.md);[U10 报告](../test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md) | U5–U10 已签(U10 **停止扩面**)。禁止 U11–U12。未整支 merge FAV | `architecture-docs` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
- OS: Linux;Go 模块测试 + `cd web && npm test`
|
||||
- PG 集成:`TEST_DATABASE_URL` 可用时执行 `chat_history_refresh_pg_test.go`
|
||||
- 真实 PI E2E:待 dev `:8080` + pi-agent 人工补录
|
||||
- 真实 PI E2E:dev `:8080` + 运行中 `pi-agent`(U9 镜像);脚本 `assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py`
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
@@ -59,11 +59,12 @@
|
||||
- **Actual Output**: 192 tests PASS
|
||||
- **Evaluation**: PASS
|
||||
|
||||
### 用例 F:真实 PI 刷新 E2E
|
||||
### 用例 F:真实 PI 闲聊刷新 E2E
|
||||
|
||||
- **Input**: dev 环境文档生成 → 浏览器刷新
|
||||
- **Actual Output**: 本轮未执行(需运行中 pi-agent 容器)
|
||||
- **Evaluation**: DEFERRED — 合入 dev 后占集成槽位补录
|
||||
- **Input**: 运行中 dev `:8080` + `pi-agent`;新建项目 6252 / `sess-p6252-u10`;`POST /api/v1/chat` 后 `GET /api/v1/chat/messages/window` 与 `GET /api/v1/chat/categories`;guest 读同一 session。产物:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json`
|
||||
- **Actual Output**: `agent_backend=pi-agent`,schema 38;闲聊 200(3481ms);window_msgs=2 且 category_total=2;guest 403 `SESSION_FORBIDDEN`。`core_overall=PASS`。文档任务 `PUT workflow-plan` 400,未跑 intake。
|
||||
- **Evaluation**: 闲聊刷新同集与跨用户负例 **PASS**;激活后文档任务刷新仍开放
|
||||
- **Duration**: 3704ms(core)
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
@@ -74,5 +75,5 @@ cd web && npm test → PASS (192)
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- 代码与 PG 集成测试达到合并标准;真实 PI 刷新 E2E 需在 dev 容器冒烟后补证据。
|
||||
- 合入后执行 `./scripts/env-service.sh dev restart` 并对 project 143 样本验证 backfill 效果。
|
||||
- 自动化、PG 与真实 PI 闲聊刷新同集已补证据;guest 403 成立。
|
||||
- 发布门禁中的「激活后文档任务 + 重登/重启」仍未勾选。项目 143 只读,未用作活验样本。
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
# M4 U10 ChatLog / ContextAssembler 原地端口化 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
权威停走门是 U9 报告最后一句 **继续 U10**([2026-09-15-dataset-lifecycle-u9-test-report.md](./2026-09-15-dataset-lifecycle-u9-test-report.md))。该句只批准进入整改计划 M4 的 chatlog/contextasm 子切片,不是一次授权做完 M4–M6。对话刷新任务代码已是 `dev` 祖先,`chat` mutex 可转给本单元。目标是先拿到「同一授权可见集合」的行为收益,再判断是否物理拆包。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 历史读取(window / day / dates / categories / search / unread / export / digest / history)走带 Principal 的 ChatLog 端口,忽略 query/body 中的 `user_id` 身份。
|
||||
- 正文条数与分类/日期计数同集;非会话 owner fail closed。
|
||||
- restore / digest / ContextAssembler 只注入允许集合,不把隐藏阶段消息放大进 Prompt。
|
||||
- 表所有权仍在 `ctxmgr`;不新建 `chatlog` / `contextasm` 包。
|
||||
- **禁止 U11–U12**,不碰 `intent`,不终止项目 143。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| 分支 | `feature/chatlog-contextasm-u10`(从本地 `dev@3944856` 检出) |
|
||||
| 本机合同测试 | `unset TEST_DATABASE_URL; go test -short ./internal/app/chatflow` |
|
||||
| 架构门 | `./scripts/arch-check.sh --mode warn` |
|
||||
| 活验目标 | 已运行的 `agent-dev` `:8080`(U9 rebuild 镜像 `sha256:6f3f20b812d4…2d4927`,`agent_backend=pi-agent`,schema **38**) |
|
||||
| 项目 143 | **只读**;活验新建项目 `6252` |
|
||||
| 证据 | `.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/`;刷新活验 `.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/` |
|
||||
|
||||
说明:本轮**未占集成槽位 rebuild**。`:8080` 仍是 U9 镜像,用于补录已合入 `dev` 的对话刷新链;U10 端口行为以本机合同测试为准。物理拆包判定:adapter 仍消费 `ctxmgr` 类型,DTO 转换 0。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 栏 | 期望 |
|
||||
|----|------|
|
||||
| 同集 | 可见 window 条数 = categories 计数之和 = dates 计数之和 |
|
||||
| 负例 | 非 owner Principal → `ErrForbidden`;空 Principal → `ErrUnauthenticated` |
|
||||
| restore/digest | 不可见阶段消息不进入 restore 列表,digest 不以之为分母 |
|
||||
| assembler | `RecentDialogue` 不含隐藏阶段正文 |
|
||||
| 活验刷新 | 真实 PI 一轮后 window 与 categories 同集且 >0;guest 403 |
|
||||
| 拆包 | 不搬包 |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 ChatLog / Assembler 合同测试
|
||||
|
||||
- **测试输入**: `unset TEST_DATABASE_URL; go test -short -count=1 ./internal/app/chatflow -v`
|
||||
- **实际输出**:
|
||||
- `TestChatLog_WindowAndStatsSameSet` PASS(激活前 + 当前阶段可见,报价阶段隐藏;window=2 且与 category/date 计数一致)
|
||||
- `TestChatLog_RejectsNonOwnerAndQueryIdentity` PASS
|
||||
- `TestChatLog_RestoreAndDigestHideInvisible` PASS
|
||||
- `TestAssembler_OnlyAuthorizedDialogue` PASS
|
||||
- **评价判定**: **PASS**
|
||||
- **性能与耗时**: 0.004s。日志:`assets/2026-09-15-chatlog-contextasm-u10/go-test-chatflow-related.txt`
|
||||
|
||||
### 5.2 HTTP 适配(本机,非容器镜像)
|
||||
|
||||
- **测试输入**: 历史读取 handler 改走 `s.chatLog`;`GET /api/v1/chat/messages` 补会话 owner 校验;未读按 Principal.UserID 跳过自己的 `role=user` 消息。
|
||||
- **实际输出**: `chat_history_api_test.go` 改为登录用户自有 session;`chat_unread_and_export_api_test.go` 未读期望从「query 省略 user_id 当成 0」校正为 ctxmgr 既有规则(自己的 user 消息不计未读)。
|
||||
- **评价判定**: **PASS**(随 `go test -short ./internal/server` 相关用例)
|
||||
- **性能与耗时**: 亚秒
|
||||
|
||||
### 5.3 架构边界
|
||||
|
||||
- **测试输入**: `./scripts/arch-check.sh --mode warn`
|
||||
- **实际输出**: `production gate passed`;`app/chatflow` 允许依赖 `bizdev` / `coordinator` / `ctxmgr` / `projectinstance`;`server` 与 `chat` 可依赖 `app/chatflow`
|
||||
- **评价判定**: **PASS**
|
||||
- **性能与耗时**: 0.111s
|
||||
|
||||
### 5.4 真实 PI 刷新活验(现网镜像,非 U10 容器)
|
||||
|
||||
- **测试输入**: 新建项目 6252 / `sess-p6252-u10`;`POST /api/v1/chat` 真实闲聊;再 `GET window` + `GET categories`;guest 读同一 session。脚本:`assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py`
|
||||
- **实际输出**(`live.json`):
|
||||
- health `pi-agent` schema 38,ready ok
|
||||
- 闲聊 HTTP 200,耗时 3481ms
|
||||
- window_msgs=2,category_total=2,同集
|
||||
- guest HTTP 403,`SESSION_FORBIDDEN`
|
||||
- 文档任务激活链 `PUT workflow-plan` HTTP 400,未进入 intake run(不作为本端口切片停走项)
|
||||
- **评价判定**: 刷新同集与跨用户负例 **PASS**;编制任务刷新 **FAIL(未测完)**
|
||||
- **性能与耗时**: core 路径 3704ms。首次尝试曾因共享库演示账号被并发短测停用导致 window 401,恢复账号后重跑通过。
|
||||
|
||||
### 5.5 物理拆包判定
|
||||
|
||||
同类改动仍落在 `ctxmgr.ChatMessageRecord` 上,adapter 无 DTO 转换。拆包收益不成立,本轮不搬包。
|
||||
|
||||
### 5.6 浏览器 / rebuild
|
||||
|
||||
- 浏览器:本轮未改 web 交互,未做页面回归。
|
||||
- rebuild:未占集成槽,U10 未进 `shuimu-agent-app-dev` 镜像。
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `unset TEST_DATABASE_URL; go test -short -count=1 ./internal/app/chatflow` | PASS(4) |
|
||||
| `./scripts/arch-check.sh --mode warn` | PASS |
|
||||
| `unset TEST_DATABASE_URL; go test -short -count=1 ./...` | PASS(EXIT:0,`internal/server` 9.941s) |
|
||||
| 真实 PI 闲聊刷新(项目 6252) | core_overall PASS |
|
||||
| 占槽 rebuild | 未执行 |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U10 停走项成立:授权可见集合在 ChatLog 端口内同集过滤;非 owner fail closed;restore/digest/assembler 不放大不可见消息;表仍归 `ctxmgr`。未做 U11–U12,未整支 merge FAV,未启用 `FAV_DEGRADED_READ`,未改 `intent`,未终止项目 143。合入 `dev` 前须占 CURRENT 集成槽位 rebuild,不能用现网 U9 镜像冒充 U10 已部署。文档任务激活链 save 400 与发布门禁「激活后文档任务 + 重登/重启」仍开放,不构成本切片搬包理由。
|
||||
|
||||
停止扩面
|
||||
@@ -0,0 +1,305 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Live chat refresh E2E against running dev. Secrets stay in process; output is redacted."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
from datetime import datetime
|
||||
|
||||
BASE = os.environ.get("BASE_URL", "http://127.0.0.1:8080").rstrip("/")
|
||||
OWNER_USER = os.environ.get("OWNER_USERNAME", "zhanggong")
|
||||
OWNER_PASS = os.environ.get("OWNER_PASSWORD", "123456")
|
||||
GUEST_USER = os.environ.get("GUEST_USERNAME", "guest")
|
||||
GUEST_PASS = os.environ.get("GUEST_PASSWORD", "123456")
|
||||
REVIEWER_USER = "lizhuguan"
|
||||
APPROVER_USER = "wangzong"
|
||||
SUFFIX = datetime.now().strftime("%H%M%S")
|
||||
OUT = os.environ.get("LIVE_OUT", "/tmp/chat-refresh-live.json")
|
||||
|
||||
|
||||
def req(method, path, token=None, body=None, timeout=180):
|
||||
data = None
|
||||
headers = {"Accept": "application/json"}
|
||||
if body is not None:
|
||||
data = json.dumps(body, ensure_ascii=False).encode()
|
||||
headers["Content-Type"] = "application/json"
|
||||
if token:
|
||||
headers["Authorization"] = f"Bearer {token}"
|
||||
headers["X-Session-Token"] = token
|
||||
r = urllib.request.Request(BASE + path, data=data, headers=headers, method=method)
|
||||
t0 = time.time()
|
||||
try:
|
||||
with urllib.request.urlopen(r, timeout=timeout) as resp:
|
||||
raw = resp.read().decode()
|
||||
parsed = json.loads(raw) if raw.strip() else None
|
||||
return resp.status, parsed, raw, int((time.time() - t0) * 1000)
|
||||
except urllib.error.HTTPError as e:
|
||||
raw = e.read().decode()
|
||||
try:
|
||||
parsed = json.loads(raw) if raw.strip() else None
|
||||
except json.JSONDecodeError:
|
||||
parsed = None
|
||||
return e.code, parsed, raw, int((time.time() - t0) * 1000)
|
||||
|
||||
|
||||
def err_snip(parsed, raw, limit=180):
|
||||
if isinstance(parsed, dict):
|
||||
return {
|
||||
"error_code": parsed.get("error_code") or parsed.get("error"),
|
||||
"message": str(parsed.get("message") or "")[:limit],
|
||||
}
|
||||
return {"raw": (raw or "")[:limit]}
|
||||
|
||||
|
||||
def login(username, password):
|
||||
status, parsed, raw, ms = req("POST", "/api/v1/auth/login", body={"username": username, "password": password})
|
||||
if status >= 400 or not parsed or not parsed.get("token"):
|
||||
raise SystemExit(f"login failed for {username}: {status} {err_snip(parsed, raw)}")
|
||||
user = parsed.get("user") or {}
|
||||
return parsed["token"], int(user.get("id") or 0), ms
|
||||
|
||||
|
||||
def window_counts(body):
|
||||
days = (body or {}).get("days") or []
|
||||
n = 0
|
||||
texts = []
|
||||
for d in days:
|
||||
msgs = d.get("messages") or []
|
||||
n += len(msgs)
|
||||
for m in msgs:
|
||||
texts.append((m.get("role"), (m.get("content") or "")[:40]))
|
||||
return n, texts
|
||||
|
||||
|
||||
def cat_total(body):
|
||||
if not isinstance(body, list):
|
||||
return 0
|
||||
return sum(int(c.get("count") or 0) for c in body)
|
||||
|
||||
|
||||
def main():
|
||||
cases = []
|
||||
t0 = time.time()
|
||||
health_s, health, _, health_ms = req("GET", "/health")
|
||||
ready_s, ready, _, ready_ms = req("GET", "/ready")
|
||||
cases.append({
|
||||
"id": "health",
|
||||
"verdict": "PASS" if health_s == 200 and (health or {}).get("agent_backend") == "pi-agent" and ready_s == 200 else "FAIL",
|
||||
"http": health_s,
|
||||
"duration_ms": health_ms,
|
||||
"output": {
|
||||
"health_status": (health or {}).get("status"),
|
||||
"agent_backend": (health or {}).get("agent_backend"),
|
||||
"schema_version": (health or {}).get("schema_version"),
|
||||
"ready": (ready or {}).get("status"),
|
||||
},
|
||||
})
|
||||
|
||||
owner_token, owner_id, login_ms = login(OWNER_USER, OWNER_PASS)
|
||||
guest_token, guest_id, _ = login(GUEST_USER, GUEST_PASS)
|
||||
reviewer_token, reviewer_id, _ = login(REVIEWER_USER, OWNER_PASS)
|
||||
approver_token, approver_id, _ = login(APPROVER_USER, OWNER_PASS)
|
||||
cases.append({
|
||||
"id": "login",
|
||||
"verdict": "PASS" if owner_id > 0 and guest_id > 0 else "FAIL",
|
||||
"duration_ms": login_ms,
|
||||
"output": {"owner_id": owner_id, "guest_id": guest_id, "reviewer_id": reviewer_id, "approver_id": approver_id},
|
||||
})
|
||||
|
||||
proj_name = f"U10刷新活验-{SUFFIX}"
|
||||
st, proj, raw, ms = req("POST", "/api/v1/projects", owner_token, {
|
||||
"name": proj_name,
|
||||
"device_type": "超声软组织手术吸引设备",
|
||||
"intended_use": "U10 chat refresh live",
|
||||
"target_market": "中国 NMPA",
|
||||
})
|
||||
project_id = int(proj["id"]) if isinstance(proj, dict) and proj.get("id") else 0
|
||||
cases.append({
|
||||
"id": "create_project",
|
||||
"verdict": "PASS" if st == 201 and project_id > 0 else "FAIL",
|
||||
"http": st,
|
||||
"duration_ms": ms,
|
||||
"output": {"project_id": project_id, "lifecycle": (proj or {}).get("lifecycle_status") if isinstance(proj, dict) else None},
|
||||
})
|
||||
if project_id <= 0:
|
||||
raise SystemExit("create project failed")
|
||||
|
||||
sess = f"sess-p{project_id}-u{owner_id}"
|
||||
req("POST", "/api/v1/chat/sessions", owner_token, {
|
||||
"session_id": sess,
|
||||
"title": proj_name,
|
||||
"user_id": owner_id,
|
||||
"project_id": project_id,
|
||||
})
|
||||
|
||||
chat_body = {
|
||||
"session_id": sess,
|
||||
"message": "先记录一下:本项目是超声软组织吸引设备立项摸底,请用一两句话确认你已记住设备类型。不要启动文档编制。",
|
||||
"project_id": project_id,
|
||||
"project_name": proj_name,
|
||||
"device_type": "超声软组织手术吸引设备",
|
||||
"user_name": "张工",
|
||||
}
|
||||
chat_s, chat, chat_raw, chat_ms = req("POST", "/api/v1/chat", owner_token, chat_body, timeout=180)
|
||||
reply = ""
|
||||
if isinstance(chat, dict):
|
||||
reply = str(chat.get("reply_text") or chat.get("reply") or "")[:120]
|
||||
cases.append({
|
||||
"id": "real_pi_chat",
|
||||
"verdict": "PASS" if chat_s == 200 and reply else "FAIL",
|
||||
"http": chat_s,
|
||||
"duration_ms": chat_ms,
|
||||
"output": {"reply_excerpt": reply, "keys": list(chat.keys()) if isinstance(chat, dict) else type(chat).__name__},
|
||||
})
|
||||
|
||||
me_s, me, me_raw, _ = req("GET", "/api/v1/auth/me", owner_token)
|
||||
win_s, win, win_raw, win_ms = req("GET", f"/api/v1/chat/messages/window?session_id={sess}&days=7", owner_token)
|
||||
n_win, texts = window_counts(win)
|
||||
cat_s, cats, cat_raw, cat_ms = req("GET", f"/api/v1/chat/categories?session_id={sess}", owner_token)
|
||||
n_cat = cat_total(cats)
|
||||
refresh_out = {
|
||||
"auth_me_http": me_s,
|
||||
"window_msgs": n_win,
|
||||
"category_total": n_cat,
|
||||
"samples": texts[:6],
|
||||
"cat_http": cat_s,
|
||||
}
|
||||
if win_s != 200:
|
||||
refresh_out["window_err"] = err_snip(win, win_raw)
|
||||
if cat_s != 200:
|
||||
refresh_out["cat_err"] = err_snip(cats, cat_raw)
|
||||
if me_s != 200:
|
||||
refresh_out["me_err"] = err_snip(me, me_raw)
|
||||
cases.append({
|
||||
"id": "refresh_window_categories",
|
||||
"verdict": "PASS" if win_s == 200 and cat_s == 200 and n_win > 0 and n_win == n_cat else "FAIL",
|
||||
"http": win_s,
|
||||
"duration_ms": win_ms + cat_ms,
|
||||
"output": refresh_out,
|
||||
})
|
||||
|
||||
g_s, g_body, _, g_ms = req("GET", f"/api/v1/chat/messages/window?session_id={sess}&days=7", guest_token)
|
||||
cases.append({
|
||||
"id": "guest_403",
|
||||
"verdict": "PASS" if g_s == 403 else "FAIL",
|
||||
"http": g_s,
|
||||
"duration_ms": g_ms,
|
||||
"output": {"error_code": (g_body or {}).get("error_code") if isinstance(g_body, dict) else None},
|
||||
})
|
||||
|
||||
task_verdict = "FAIL"
|
||||
task_out = {}
|
||||
try:
|
||||
default_s, plan, default_raw, _ = req(
|
||||
"GET",
|
||||
f"/api/v1/projects/{project_id}/workflow-plan/default?workflow_key=main&version=0",
|
||||
owner_token,
|
||||
)
|
||||
task_out["default_http"] = default_s
|
||||
save_s = activate_s = run_s = 0
|
||||
run_id = None
|
||||
final_status = None
|
||||
poll_ms = 0
|
||||
n_win2 = n_cat2 = 0
|
||||
texts2 = []
|
||||
if default_s == 200 and isinstance(plan, dict):
|
||||
stages = plan.get("stages") or []
|
||||
for stg in stages:
|
||||
for dt in stg.get("doc_tasks") or []:
|
||||
dt["duties"] = {
|
||||
"author_user_id": owner_id,
|
||||
"reviewer_user_id": reviewer_id,
|
||||
"approver_user_id": approver_id,
|
||||
}
|
||||
save_s, _, save_raw, _ = req("PUT", f"/api/v1/projects/{project_id}/workflow-plan", owner_token, {
|
||||
"plan": plan,
|
||||
"expected_plan_revision": 0,
|
||||
"expected_selection_version": 1,
|
||||
})
|
||||
prev_s, preview, _, _ = req("POST", f"/api/v1/projects/{project_id}/activation-preview", owner_token, {})
|
||||
if prev_s == 200 and isinstance(preview, dict):
|
||||
activate_s, act, act_raw, _ = req("POST", f"/api/v1/projects/{project_id}/workflow-instances/activate", owner_token, {
|
||||
"confirmation_token": preview.get("confirmation_token"),
|
||||
"expected_project_version": preview.get("expected_project_version"),
|
||||
"expected_plan_revision": preview.get("expected_plan_revision"),
|
||||
})
|
||||
if activate_s == 200:
|
||||
run_s, run, run_raw, run_ms = req("POST", "/api/v1/tasks/runs", owner_token, {
|
||||
"session_id": sess,
|
||||
"client_turn_id": f"u10-live-{SUFFIX}",
|
||||
"user_message": "请基于本项目编制首轮《用户需求》摸底文档,控制在较短篇幅。",
|
||||
"task_key": "intake",
|
||||
"project_id": project_id,
|
||||
"project_name": proj_name,
|
||||
"device_type": "超声软组织手术吸引设备",
|
||||
"intended_use": "U10 chat refresh live",
|
||||
"target_market": "中国 NMPA",
|
||||
}, timeout=30)
|
||||
run_id = (run or {}).get("run_id") if isinstance(run, dict) else None
|
||||
if run_id:
|
||||
pt0 = time.time()
|
||||
for _ in range(48):
|
||||
gs, gb, _, _ = req("GET", f"/api/v1/tasks/runs/{run_id}", owner_token, timeout=30)
|
||||
if gs == 200 and isinstance(gb, dict):
|
||||
final_status = gb.get("status")
|
||||
if final_status in ("completed", "failed", "cancelled", "pending_author_confirmation"):
|
||||
break
|
||||
time.sleep(10)
|
||||
poll_ms = int((time.time() - pt0) * 1000)
|
||||
win2_s, win2, _, _ = req("GET", f"/api/v1/chat/messages/window?session_id={sess}&days=7", owner_token)
|
||||
n_win2, texts2 = window_counts(win2)
|
||||
cat2_s, cats2, _, _ = req("GET", f"/api/v1/chat/categories?session_id={sess}", owner_token)
|
||||
n_cat2 = cat_total(cats2)
|
||||
task_out.update({
|
||||
"save_http": save_s,
|
||||
"preview_http": prev_s,
|
||||
"activate_http": activate_s,
|
||||
"run_http": run_s,
|
||||
"run_id": run_id,
|
||||
"run_status": final_status,
|
||||
"poll_ms": poll_ms,
|
||||
"window_http": win2_s,
|
||||
"window_msgs": n_win2,
|
||||
"category_total": n_cat2,
|
||||
"samples": texts2[:8],
|
||||
})
|
||||
task_ok = (
|
||||
save_s == 200 and activate_s == 200 and run_s in (200, 202)
|
||||
and n_win2 >= n_win and n_win2 == n_cat2 and n_win2 > 0
|
||||
)
|
||||
task_verdict = "PASS" if task_ok else "FAIL"
|
||||
else:
|
||||
task_out["default_err"] = err_snip(plan, default_raw)
|
||||
task_verdict = "FAIL"
|
||||
except Exception as exc:
|
||||
task_verdict = "FAIL"
|
||||
task_out["error"] = type(exc).__name__
|
||||
cases.append({"id": "pi_task_refresh", "verdict": task_verdict, "output": task_out})
|
||||
|
||||
required = {c["id"] for c in cases if c["id"] != "pi_task_refresh"}
|
||||
core_pass = all(c["verdict"] == "PASS" for c in cases if c["id"] in required)
|
||||
result = {
|
||||
"started": datetime.now().isoformat(),
|
||||
"base": BASE,
|
||||
"project_id": project_id,
|
||||
"session_id": sess,
|
||||
"duration_ms": int((time.time() - t0) * 1000),
|
||||
"cases": cases,
|
||||
"core_overall": "PASS" if core_pass else "FAIL",
|
||||
"overall": "PASS" if core_pass and task_verdict == "PASS" else "FAIL",
|
||||
}
|
||||
os.makedirs(os.path.dirname(OUT) or ".", exist_ok=True)
|
||||
with open(OUT, "w", encoding="utf-8") as f:
|
||||
json.dump(result, f, ensure_ascii=False, indent=2)
|
||||
print(json.dumps({k: result[k] for k in ("overall", "core_overall", "duration_ms", "project_id", "session_id")}, ensure_ascii=False))
|
||||
for c in cases:
|
||||
print(f"{c['id']}: {c['verdict']} http={c.get('http')} ms={c.get('duration_ms')}")
|
||||
return 0 if result["core_overall"] == "PASS" else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,118 @@
|
||||
{
|
||||
"started": "2026-09-15T04:04:56.847406",
|
||||
"base": "http://127.0.0.1:8080",
|
||||
"project_id": 6252,
|
||||
"session_id": "sess-p6252-u10",
|
||||
"duration_ms": 3704,
|
||||
"cases": [
|
||||
{
|
||||
"id": "health",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 5,
|
||||
"output": {
|
||||
"health_status": "ok",
|
||||
"agent_backend": "pi-agent",
|
||||
"schema_version": 38,
|
||||
"ready": "ok"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "login",
|
||||
"verdict": "PASS",
|
||||
"duration_ms": 46,
|
||||
"output": {
|
||||
"owner_id": 10,
|
||||
"guest_id": 13,
|
||||
"reviewer_id": 11,
|
||||
"approver_id": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "create_project",
|
||||
"verdict": "PASS",
|
||||
"http": 201,
|
||||
"duration_ms": 21,
|
||||
"output": {
|
||||
"project_id": 6252,
|
||||
"lifecycle": "planning"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "real_pi_chat",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 3481,
|
||||
"output": {
|
||||
"reply_excerpt": "完全理解您想再掂量一下。针对「U10刷新活验-040453」目前的节点,我帮您快速对照一下:\n\n• 若推进 V0.5(方案成型与法规对齐):\n 我可帮您梳理初步架构与注册分类路径,并预估型检成本,便于与客户深入沟通;\n• 若先放一放 / ",
|
||||
"keys": [
|
||||
"reply_text",
|
||||
"branch",
|
||||
"intent_result",
|
||||
"coordination_result",
|
||||
"pending_expectation"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "refresh_window_categories",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 4,
|
||||
"output": {
|
||||
"auth_me_http": 200,
|
||||
"window_msgs": 2,
|
||||
"category_total": 2,
|
||||
"samples": [
|
||||
[
|
||||
"user",
|
||||
"先记录一下:本项目是超声软组织吸引设备立项摸底,请用一两句话确认你已记住设备类型"
|
||||
],
|
||||
[
|
||||
"assistant",
|
||||
"完全理解您想再掂量一下。针对「U10刷新活验-040453」目前的节点,我帮您快"
|
||||
]
|
||||
],
|
||||
"cat_http": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "guest_403",
|
||||
"verdict": "PASS",
|
||||
"http": 403,
|
||||
"duration_ms": 1,
|
||||
"output": {
|
||||
"error_code": "SESSION_FORBIDDEN"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "pi_task_refresh",
|
||||
"verdict": "FAIL",
|
||||
"output": {
|
||||
"default_http": 200,
|
||||
"save_http": 400,
|
||||
"preview_http": 400,
|
||||
"activate_http": 0,
|
||||
"run_http": 0,
|
||||
"run_id": null,
|
||||
"run_status": null,
|
||||
"poll_ms": 0,
|
||||
"window_http": 200,
|
||||
"window_msgs": 2,
|
||||
"category_total": 2,
|
||||
"samples": [
|
||||
[
|
||||
"user",
|
||||
"先记录一下:本项目是超声软组织吸引设备立项摸底,请用一两句话确认你已记住设备类型"
|
||||
],
|
||||
[
|
||||
"assistant",
|
||||
"完全理解您想再掂量一下。针对「U10刷新活验-040453」目前的节点,我帮您快"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"core_overall": "PASS",
|
||||
"overall": "FAIL"
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ok chat-agent-system/internal/app/chatflow 0.004s
|
||||
ok chat-agent-system/internal/server 0.006s
|
||||
@@ -0,0 +1,50 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 2.302s
|
||||
? chat-agent-system/cmd/dataset [no test files]
|
||||
ok chat-agent-system/cmd/document-content-reconcile 0.003s
|
||||
? chat-agent-system/cmd/document-revision-backfill [no test files]
|
||||
? chat-agent-system/cmd/recategorize [no test files]
|
||||
? chat-agent-system/cmd/server [no test files]
|
||||
ok chat-agent-system/internal/agent 1.132s
|
||||
ok chat-agent-system/internal/app/chatflow 0.004s
|
||||
ok chat-agent-system/internal/app/docflow 0.003s
|
||||
ok chat-agent-system/internal/app/uow 0.003s
|
||||
ok chat-agent-system/internal/archtest 0.127s
|
||||
ok chat-agent-system/internal/artifactvault 0.005s
|
||||
ok chat-agent-system/internal/auth 0.840s
|
||||
ok chat-agent-system/internal/authz 0.003s
|
||||
ok chat-agent-system/internal/bizdev 0.165s
|
||||
ok chat-agent-system/internal/chat 0.015s
|
||||
ok chat-agent-system/internal/config 0.003s
|
||||
ok chat-agent-system/internal/coordinator 0.010s
|
||||
ok chat-agent-system/internal/ctxmgr 0.092s
|
||||
ok chat-agent-system/internal/dataset 0.005s
|
||||
ok chat-agent-system/internal/db 0.005s
|
||||
ok chat-agent-system/internal/docduty 0.004s
|
||||
ok chat-agent-system/internal/docgov 0.021s
|
||||
ok chat-agent-system/internal/docquery 0.004s
|
||||
ok chat-agent-system/internal/docrevision 0.006s
|
||||
ok chat-agent-system/internal/events 0.003s
|
||||
ok chat-agent-system/internal/freedoc 0.029s
|
||||
ok chat-agent-system/internal/fsutil 0.002s
|
||||
ok chat-agent-system/internal/intent 0.018s
|
||||
ok chat-agent-system/internal/kb 0.004s
|
||||
ok chat-agent-system/internal/notification 0.069s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.004s
|
||||
ok chat-agent-system/internal/projectinstance 0.005s
|
||||
ok chat-agent-system/internal/projectworkflow 0.018s
|
||||
ok chat-agent-system/internal/quote 0.024s
|
||||
ok chat-agent-system/internal/replyexport 0.002s
|
||||
ok chat-agent-system/internal/server 9.941s
|
||||
ok chat-agent-system/internal/squad 0.033s
|
||||
ok chat-agent-system/internal/storage 0.014s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/taskrun 0.146s
|
||||
ok chat-agent-system/internal/template 0.743s
|
||||
ok chat-agent-system/internal/upload 0.002s
|
||||
? chat-agent-system/internal/workflow [no test files]
|
||||
ok chat-agent-system/internal/workflow/runtime 0.003s
|
||||
ok chat-agent-system/internal/workflowdef 0.003s
|
||||
ok chat-agent-system/internal/workspace 0.003s
|
||||
? chat-agent-system/templates [no test files]
|
||||
EXIT:0
|
||||
Reference in New Issue
Block a user