From 6e744d371775cd1eec577f8e80060f12101d2df8 Mon Sep 17 00:00:00 2001 From: weichen Date: Tue, 15 Sep 2026 04:11:40 +0000 Subject: [PATCH] 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 --- ...-09-13-chat-history-refresh-remediation.md | 7 +- .../ops/2026-09-15-chatlog-contextasm-u10.md | 59 ++++ ...-09-13-chat-history-refresh-remediation.md | 12 +- ...6-09-13-chat-history-refresh-disappears.md | 2 +- .doc/ops/CURRENT.md | 12 +- ...4-module-decoupling-refactor-acceptance.md | 10 +- ...-09-13-chat-history-refresh-remediation.md | 2 +- .doc/remediation/gap-matrix.md | 4 +- .doc/status/FEATURE-MATRIX.md | 4 +- ...-09-13-chat-history-refresh-test-report.md | 15 +- ...9-15-chatlog-contextasm-u10-test-report.md | 102 ++++++ .../chat-refresh-live.py | 305 ++++++++++++++++++ .../live.json | 118 +++++++ .../go-test-chatflow-related.txt | 2 + .../go-test-short.txt | 50 +++ 15 files changed, 672 insertions(+), 32 deletions(-) create mode 100644 .doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md create mode 100644 .doc/test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md create mode 100644 .doc/test-reports/assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py create mode 100644 .doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json create mode 100644 .doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-chatflow-related.txt create mode 100644 .doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-short.txt diff --git a/.doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md b/.doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md index 5991bcf9..d2df8ca9 100644 --- a/.doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md +++ b/.doc/archive/ops/2026-09-13-chat-history-refresh-remediation.md @@ -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) diff --git a/.doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md b/.doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md new file mode 100644 index 00000000..0f44a563 --- /dev/null +++ b/.doc/archive/ops/2026-09-15-chatlog-contextasm-u10.md @@ -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。 diff --git a/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md b/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md index 30f2f470..8eec8422 100644 --- a/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md +++ b/.doc/archive/ops/checklists/2026-09-13-chat-history-refresh-remediation.md @@ -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 diff --git a/.doc/audit/2026-09-13-chat-history-refresh-disappears.md b/.doc/audit/2026-09-13-chat-history-refresh-disappears.md index daf2a4d8..caa94c28 100644 --- a/.doc/audit/2026-09-13-chat-history-refresh-disappears.md +++ b/.doc/audit/2026-09-13-chat-history-refresh-disappears.md @@ -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) ## 证据 diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index ae33f5dc..4a6c74e3 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -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/` 或 `fix/`,**禁止** `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) | diff --git a/.doc/ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md b/.doc/ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md index b5fa182a..f267b95f 100644 --- a/.doc/ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.md +++ b/.doc/ops/checklists/2026-09-14-module-decoupling-refactor-acceptance.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,不用局部测试冒充全计划完成。 diff --git a/.doc/remediation/2026-09-13-chat-history-refresh-remediation.md b/.doc/remediation/2026-09-13-chat-history-refresh-remediation.md index 9dcfebd8..51ec9188 100644 --- a/.doc/remediation/2026-09-13-chat-history-refresh-remediation.md +++ b/.doc/remediation/2026-09-13-chat-history-refresh-remediation.md @@ -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` diff --git a/.doc/remediation/gap-matrix.md b/.doc/remediation/gap-matrix.md index 25d251dc..8e5cc64d 100644 --- a/.doc/remediation/gap-matrix.md +++ b/.doc/remediation/gap-matrix.md @@ -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` | --- diff --git a/.doc/status/FEATURE-MATRIX.md b/.doc/status/FEATURE-MATRIX.md index 67ebf46e..d224afe3 100644 --- a/.doc/status/FEATURE-MATRIX.md +++ b/.doc/status/FEATURE-MATRIX.md @@ -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` | --- diff --git a/.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md b/.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md index 6858bc49..22f5c1d2 100644 --- a/.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md +++ b/.doc/test-reports/2026-09-13-chat-history-refresh-test-report.md @@ -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 只读,未用作活验样本。 diff --git a/.doc/test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md b/.doc/test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md new file mode 100644 index 00000000..8686e2d2 --- /dev/null +++ b/.doc/test-reports/2026-09-15-chatlog-contextasm-u10-test-report.md @@ -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 与发布门禁「激活后文档任务 + 重登/重启」仍开放,不构成本切片搬包理由。 + +停止扩面 diff --git a/.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py b/.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py new file mode 100644 index 00000000..0e897468 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py @@ -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()) diff --git a/.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json b/.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json new file mode 100644 index 00000000..3fd0942b --- /dev/null +++ b/.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/live.json @@ -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" +} \ No newline at end of file diff --git a/.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-chatflow-related.txt b/.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-chatflow-related.txt new file mode 100644 index 00000000..3c63a875 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-chatflow-related.txt @@ -0,0 +1,2 @@ +ok chat-agent-system/internal/app/chatflow 0.004s +ok chat-agent-system/internal/server 0.006s diff --git a/.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-short.txt b/.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-short.txt new file mode 100644 index 00000000..550b4f63 --- /dev/null +++ b/.doc/test-reports/assets/2026-09-15-chatlog-contextasm-u10/go-test-short.txt @@ -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