release-candidate: 汇集 dev 功能至 test 分支,准备长期实测 [Tag: rc-v1.0.0-beta.2]
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: "发布门禁闭环 → production_ready"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor-Auto
|
||||
branch: docs/production-ready-flip
|
||||
worktree: "-"
|
||||
mutex: ci
|
||||
---
|
||||
|
||||
# 发布门禁闭环 → production_ready
|
||||
|
||||
## 目标
|
||||
|
||||
按 gap-matrix 发布门禁勾选 B1–B4,对齐环境 schema 后翻 `production_ready=yes`。
|
||||
|
||||
## 范围
|
||||
|
||||
- B1 CI TEST_DATABASE_URL + 治理 PG(已完成)
|
||||
- B2 真实 PI 三工作流 E2E(已完成)
|
||||
- B3 对话全链路恢复(已完成)
|
||||
- B4 版本冲突/终止 preview(已完成)
|
||||
- B5 SSOT 翻旗 + main schema 对齐(已完成)
|
||||
|
||||
## 非目标
|
||||
|
||||
- 多意图 U9–U12、软件项目自举、FAV、完整 PI change-report 叙事
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] B1 BUG-08
|
||||
2. [x] B2 PI E2E
|
||||
3. [x] B3 chat refresh + restart
|
||||
4. [x] B4 conflict + termination-preview + envelope unwrap
|
||||
5. [x] B5 merge/smoke、main rebuild 迁库、翻旗
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] gap 门禁四框可勾(含对话与前端)
|
||||
- [x] FEATURE-MATRIX / gap / CURRENT `production_ready: yes`
|
||||
- [x] main/dev/test health schema_version=47
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Test reports: `2026-09-16-ci-governance-pg-bug08`、`pi-three-workflow-e2e`、`chat-refresh-gate`、`frontend-gate-b4`
|
||||
- gap-matrix / FEATURE-MATRIX / CURRENT
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
title: "前端 mock 交付物污染真实项目:幻影受控文档伪造终审已生效态与法定职责"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
severity: critical
|
||||
---
|
||||
|
||||
# 前端 mock 交付物污染真实项目:幻影受控文档伪造终审已生效态与法定职责
|
||||
|
||||
## 现象
|
||||
|
||||
用户在 **test 环境**(127.0.0.1:8081)新建测试项目「测试项目」(test 库 `projects.id=1`,唯一项目),工作台立即显示 11 份「受控文档」,其中包括与该项目毫无关系的:
|
||||
|
||||
- 《4K超高清荧光内窥镜系统立项与可行性报告》
|
||||
- 《微创外科内窥镜全球竞品技术与临床深度调研报告》
|
||||
- 神经外科双频超声吸引(NeuroPulse)系列
|
||||
- CUSA 超声手术吸引系统系列
|
||||
|
||||
这些文档:
|
||||
|
||||
1. 显示**伪造的生命周期状态**(`reviewing` / `approved`——`DeckDrawer.tsx` 将 `approved` 渲染为「**终审已生效**」),即用户所称「生效区」出现从未经过任何 docgov 生命周期流转的"已生效"文档;
|
||||
2. 带有**伪造的法定职责人**(author 张工 / reviewer 李主管 / approver 王总监——均非真实用户);
|
||||
3. 带有伪造版本号(V1.0)、伪造更新时间、伪造正文全文;
|
||||
4. 在项目成员视角按真实受控文档参与 RBAC 可见性过滤与工作流槽位合并,**与真实服务端文档混排**。
|
||||
|
||||
而 test 库 `document_records` 为 **0 行**——服务端受控文档台账完全为空,这 11 份文档**全部来自前端硬编码 mock 数据**。
|
||||
|
||||
## 根因分析
|
||||
|
||||
### 1. mock 交付物硬编码绑定 projectId 1/2/3/5201/6001–6010
|
||||
|
||||
`web/src/App.tsx:267` `INITIAL_DELIVERABLES` 硬编码 7 份 mock 交付物 `projectId: 1`(doc-001~004、doc-shared-001、doc-private-001/002);`P2_INITIAL`(projectId 2)、`CUSA_INITIAL_DELIVERABLES`(projectId 3)、`NEUROPULSE`(5201)、`TEN_PROJECTS`(6001+)同理。`ALL_INITIAL_DELIVERABLES` 聚合后作为 `loadDeliverables()` 的默认值(App.tsx:621),并经 `saveDeliverables` **写入 localStorage 持久化**。
|
||||
|
||||
### 2. 项目过滤按数字 ID 匹配,新建项目与 mock 项目 ID 撞车
|
||||
|
||||
`App.tsx:1014`:`currentProjectDeliverables = deliverables.filter(doc => doc.projectId === currentProjectId)`。
|
||||
|
||||
- test 库为全新库,用户新建的第一个项目得到 `id=1` → 与 mock 的 `projectId: 1` **精确撞车**,7 份幻影文档全部"归属"该项目;
|
||||
- 新建项目时 `createProjectTemplateDeliverables`(App.tsx:3844)再克隆 7 份模板骨架(`doc-p1-*`,`lifecycleState: 'template'`,合规)→ 7 mock + 4~7 模板/私有,构成用户看到的 11 份;
|
||||
- **dev 库同样中招**:`agent_system_dev.projects` 存在真实项目 id 1–8(智能微创内窥镜/测试内窥镜系统等),id 1/2/3 的真实项目同样被 mock 文档污染。
|
||||
|
||||
### 3. mock 正文与 mock 用户/权限无环境门控,已进生产构建产物
|
||||
|
||||
- `mockDocuments.ts` 无任何 `import.meta.env` 门控;`App.tsx` 中 `MOCK_USERS`(含伪造 `projectPermissions: {doc-001: approver...}`)作为 `loadUsers()` 默认值与 `currentUser` 初始身份兜底(App.tsx:610/617);
|
||||
- **构建产物已验证污染**:`web/dist/assets/index-DogUjae5.js` 中 grep 命中「4K超高清荧光」字符串——dev/test/main 三环境共用同一前端构建,main 生产环境同样受影响。
|
||||
|
||||
### 4. 既有防线只挡"正文请求",不挡"清单展示"
|
||||
|
||||
团队已知悉 legacy mock ID(`revisionToolbarMount.ts:24 isLegacyLocalMockDocId`:`doc-\d{3}` / `doc-shared-*` / `doc-private-*` / `doc-cusa-*`),并禁止它们发起 content/revision 请求(`controlledDocHydrate.ts:shouldLoadControlledContent` 排除)。但这只防住了「幻影文档冒充服务端正文」,**没有防住幻影文档出现在交付物清单、生命周期徽章(终审已生效)、职责栏与项目文档统计中**——用户看到的正是后者。
|
||||
|
||||
### 5. 服务端权威清单未做前端对账
|
||||
|
||||
`GET /api/v1/projects/{id}/documents`(`docgov/project_docs.go`,`WHERE project_id=$1 AND task_key<>''`,服务端已正确按项目隔离)返回空数组时,`mergeWorkflowDocumentsFromServer`(`deliverableSync.ts:41`)**直接 `return prev`,不删除本地多余项**——本地幻影文档无任何下架机制。
|
||||
|
||||
## 严重度
|
||||
|
||||
`critical`:
|
||||
|
||||
1. **治理完整性破坏**:空项目展示「终审已生效」受控文档 + 三级法定职责人,在医疗器械合规语境下(ISO 13485 / 21 CFR Part 11 电子记录可靠性)构成"记录失实";
|
||||
2. **跨环境广泛影响**:dev 真实项目 id 1–8、test 新建项目、main 生产同构建产物全部受影响;
|
||||
3. **权限视图失真**:伪造职责人/权限映射混入 RBAC 过滤链,用户对"谁可审批什么"产生错误认知;
|
||||
4. 既有防线(isLegacyLocalMockDocId)证明团队已两次踩坑(本审计为同域第三类症状),说明 mock 数据保留策略系统性不足。
|
||||
|
||||
## 关联整改
|
||||
|
||||
- Remediation: [2026-09-15-mock-deliverables-pollution-remediation.md](../remediation/2026-09-15-mock-deliverables-pollution-remediation.md)
|
||||
|
||||
## 证据
|
||||
|
||||
- test 库(`shuimu-system-pg-test`,127.0.0.1:5434):`projects` 仅 id=1「测试项目」(通用医疗器械);`document_records` 0 行;全库 87 张业务表除 projects/users/auth_sessions/chat_sessions/project_workflows 外全部为空
|
||||
- dev 库(`shuimu-context-pg-dev`,127.0.0.1:5433):真实项目 id 1–8(智能微创内窥镜 / 测试内窥镜系统)→ 与 mock projectId 1/2/3 撞车
|
||||
- `web/src/App.tsx:267-498`(INITIAL_DELIVERABLES/P2/CUSA/ALL_INITIAL_DELIVERABLES)、`621`(loadDeliverables)、`1014`(projectId 过滤)、`3844`(新建克隆模板)
|
||||
- `web/src/data/mockDocuments.ts:32-505`(mock 文档全文与伪造 lifecycleState/职责人)、`web/src/data/seeds/neuropulseSeed.json`(projectId 5201)、`tenProjectsSeed.json`(6001–6010)
|
||||
- `web/dist/assets/index-DogUjae5.js`:grep 命中「4K超高清荧光」(生产构建含 mock 数据)
|
||||
- `web/src/features/documentRevision/revisionToolbarMount.ts:24-32`(isLegacyLocalMockDocId 既有防线)
|
||||
- `web/src/lib/deliverableSync.ts:41-45`(serverDocs 空时不回收本地项)
|
||||
- `web/src/components/doc/DeckDrawer.tsx:87-103`(approved → 「终审已生效」渲染)
|
||||
- `web/src/api/projectDocuments.ts:46-58`(服务端清单 API,服务端隔离正确)
|
||||
|
||||
## 开放问题
|
||||
|
||||
- mock 数据的保留意图(demo 演示模式?)需要在整改方案中决策:彻底移除 vs 环境门控(`import.meta.env.MODE` / 构建期注入 `VITE_ENABLE_DEMO_SEEDS`)
|
||||
- localStorage 中已被 `saveDeliverables` 持久化的 mock 项,需要一次性迁移清理(对齐既有 `dropRecordKeys`/ControlledInvalidationPlan 机制)
|
||||
- main 环境是否已有真实用户看过幻影文档(`document_access_audit` 为 0 行,无服务端读取痕迹,风险主要在前端展示层)
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: Demo/测试数据污染系统性审计
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor-Auto
|
||||
---
|
||||
|
||||
# Demo / 测试数据污染系统性审计
|
||||
|
||||
## 前序
|
||||
|
||||
本审计在 [2026-09-15 mock 交付物污染真实项目](./2026-09-15-mock-deliverables-pollute-real-projects.md)(及对应 [整改](../remediation/2026-09-15-mock-deliverables-pollution-remediation.md))之上收敛为全栈系统性排查:前端门控、goose 演示项目/会话、stub API。
|
||||
|
||||
## 背景
|
||||
|
||||
空项目展示「终审已生效」受控文档 + 伪造三级职责人。初判怀疑 docgov 隔离失败;实锤为前端 mock/seed 与 DB goose 演示种子污染。
|
||||
|
||||
## 结论
|
||||
|
||||
| 面 | 判定 | 说明 |
|
||||
|----|------|------|
|
||||
| 服务端 `document_records` / project_docs | **正常** | 按 `project_id` 隔离;空项目台账为 0 |
|
||||
| 前端 `ALL_INITIAL_DELIVERABLES` / mockDocuments | **critical** | 无门控进生产包;projectId 1/2/3 撞车 |
|
||||
| 前端 DEFAULT_PROJECTS / sessions / MOCK_USERS | **critical/high** | NeuroPulse 5201、CUSA id=3、6001–6010 |
|
||||
| `deliverableSync` 空清单 `return prev` | **critical** | 权威空列表不回收本地 mock |
|
||||
| `isLegacyLocalMockDocId` 覆盖不全 | **critical** | 未覆盖 neuropulse / ten-projects |
|
||||
| Goose `00011`/`00012` | **critical** | 全环境写入 6001–6010 + 聊天 |
|
||||
| API `backend=stub` | **high** | main 仍可请求 stub |
|
||||
| `BootstrapDevSeedUsers` | **OK** | 已有 env 门控 |
|
||||
|
||||
## 证据路径
|
||||
|
||||
- `web/src/App.tsx`(整改前 INITIAL_*)
|
||||
- `web/src/data/mockDocuments.ts` / `neuropulseDemo.ts` / `tenProjectsDemo.ts`
|
||||
- `web/src/lib/deliverableSync.ts`
|
||||
- `deploy/postgres/goose/00011_*.sql` / `00012_*.sql`
|
||||
- `internal/taskrun/backend.go`
|
||||
- 产物扫描:`scripts/check-prod-bundle.sh`
|
||||
|
||||
## 整改回链
|
||||
|
||||
- [remediation](../remediation/2026-09-16-demo-seed-pollution-remediation.md)
|
||||
- [test-report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md)
|
||||
+28
-9
@@ -1,18 +1,29 @@
|
||||
# 当前焦点
|
||||
|
||||
**更新**: 2026-09-15
|
||||
**production_ready**: no(CI 真实 PI 三工作流 E2E / 前端人工抽检仍开放。`CHAT-INTENT-STATE` 双标签 busy **PASS**。文档账本运行时 UI Round20 **PASS**,不把 fallback change report 写成完整 PI,也不把本轮写成全仓可发布)
|
||||
**更新**: 2026-09-16
|
||||
**production_ready**: yes(门禁 B1–B4 已签;dev/test/main `schema_version=47`。不把 fallback change report 写成完整 PI)
|
||||
|
||||
## 焦点
|
||||
|
||||
1. **MULTI-INTENT HITL**:方案已复核,U1 契约未开工([设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[short-term](./short-term/2026-09-15-multi-intent-hitl.md))
|
||||
2. **发布门禁**:CI `TEST_DATABASE_URL`、真实 PI 三工作流 E2E、前端人工抽检仍开放([gap-matrix](../remediation/gap-matrix.md))
|
||||
3. **CHAT-INTENT**:双标签 busy 已签(项目 **6275**);不删 `sess-p143-u9`;项目 143 只读
|
||||
1. **MATRIX 深度测试 + 晋升 test**:`feature/matrix-deep-test-promote-test` → `rc-v1.0.0-beta.2`
|
||||
2. **首发后 backlog**:多意图 U9–U12、软件项目自举、FAV、完整 PI change-report 叙事
|
||||
3. **MULTI-INTENT HITL**:核心 U1–U8 已合入;U9–U12 不阻塞首版
|
||||
|
||||
## 并行认领
|
||||
|
||||
| owner | task | branch | worktree | mutex | status |
|
||||
|-------|------|--------|----------|-------|--------|
|
||||
| Cursor-Auto | 2026-09-16-matrix-deep-test-promote-test | feature/matrix-deep-test-promote-test | - | infra | in_progress |
|
||||
| Cursor-Auto | 2026-09-16-production-ready-gates | docs/production-ready-flip | - | ci | done |
|
||||
| Cursor-Auto | 2026-09-16-demo-seed-pollution | fix/demo-data-pollution-web | - | web | done |
|
||||
| Cursor | 2026-09-16-multi-intent-u8-task-generate | feature/multi-intent-u8-task-generate | - | intent-plan | done |
|
||||
| Cursor | 2026-09-16-multi-intent-u7-auto-read | feature/multi-intent-u7-auto-read | - | intent-plan | done |
|
||||
| Cursor | 2026-09-16-multi-intent-u6-web-cards | feature/multi-intent-u6-web-cards | - | web | done |
|
||||
| Cursor | 2026-09-16-multi-intent-u5-decision-api | feature/multi-intent-u5-decision-api | - | intent-plan | done |
|
||||
| Cursor | 2026-09-16-multi-intent-u4-outbox-projection | feature/multi-intent-u4-outbox-projection | - | events | done |
|
||||
| Cursor | 2026-09-15-multi-intent-u3-intentflow-pg | feature/multi-intent-u3-intentflow-pg | - | intent-plan | done |
|
||||
| Cursor | 2026-09-15-multi-intent-u2-segmenter | feature/multi-intent-u2-segmenter | - | intent | done |
|
||||
| Cursor | 2026-09-15-multi-intent-u1-contracts | feature/multi-intent-u1-contracts | - | architecture-docs | done |
|
||||
| Cursor | app-composition-u11-u12 | feature/app-composition-u11-u12 | - | app | done |
|
||||
| Cursor | chatlog-contextasm-u10 | feature/chatlog-contextasm-u10 | - | chat | done |
|
||||
| Cursor | chat-history-refresh-remediation | fix/chat-history-refresh | - | chat | done |
|
||||
@@ -84,7 +95,7 @@
|
||||
|
||||
| holder | phase | since | scope | queue |
|
||||
|--------|-------|-------|-------|-------|
|
||||
| - | idle | - | - | - |
|
||||
| Cursor-Auto | merging | 2026-09-16T13:20Z | matrix deep test → promote rc-v1.0.0-beta.2 + test rebuild | - |
|
||||
|
||||
**phase**: `idle` | `merging` | `smoke` | `e2e`
|
||||
|
||||
@@ -94,9 +105,9 @@
|
||||
|
||||
| 环境 | 端口 | schema | 状态 |
|
||||
|------|------|--------|------|
|
||||
| dev | 8080 | **43** | healthy(`pi-agent` typed-result-v1;events worker `:8088`;notify/advance/projection live、fav off;health+ready PASS) |
|
||||
| test | 8081 | **43** | healthy(`rc-v1.0.0-beta.1`;pi-agent `:18866`;events `:8089`;notify/advance/projection live、fav off;health+ready PASS) |
|
||||
| main | 8000 | 25→27* | healthy(app + runner + DB) |
|
||||
| dev | 8080 | **47** | healthy(`pi-agent` typed-result-v1;events worker `:8088`;notify/advance/projection live、fav off;health+ready PASS;demo 6001–6010 retired) |
|
||||
| test | 8081 | **47** | healthy(`rc-v1.0.0-beta.1`;pi-agent `:18866`;events `:8089`;notify/advance/projection live、fav off;health+ready PASS;schema 与 dev 对齐 47) |
|
||||
| main | 8000 | **47** | healthy(app + events + runner + DB;与 dev/test 对齐) |
|
||||
|
||||
## SSOT
|
||||
|
||||
@@ -118,6 +129,14 @@
|
||||
| Phase 2 方案审阅 | [../audit/2026-09-15-module-decoupling-phase2-plan-review.md](../audit/2026-09-15-module-decoupling-phase2-plan-review.md) |
|
||||
| Phase 2 修订计划 | [../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md) |
|
||||
| 多意图 HITL 复核方案 | [../system-design/2026-09-15-multi-intent-hitl-plan.md](../system-design/2026-09-15-multi-intent-hitl-plan.md) |
|
||||
| 多意图 HITL U1 契约 | [../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md) |
|
||||
| 多意图 HITL U2 分段 | [../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md) |
|
||||
| 多意图 HITL U3 PG | [../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) |
|
||||
| 多意图 HITL U4 投影 | [../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md](../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md) |
|
||||
| 多意图 HITL U5 API | [../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md](../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md) |
|
||||
| 多意图 HITL U6 Web | [../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md](../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md) |
|
||||
| 多意图 HITL U8 generate | [../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md) |
|
||||
| 多意图 HITL U7 只读 | [../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md](../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md) |
|
||||
| 文档可靠性 M1 报告 | [../test-reports/2026-09-14-document-reliability-pilot-test-report.md](../test-reports/2026-09-14-document-reliability-pilot-test-report.md) |
|
||||
| 文档可靠性 M1 活验 | [../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md](../test-reports/2026-09-14-document-reliability-pilot-live-test-report.md) |
|
||||
| 文档可靠性 M2 | [../test-reports/2026-09-14-document-reliability-m2-test-report.md](../test-reports/2026-09-14-document-reliability-m2-test-report.md) |
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: "多意图 HITL U1 契约冻结 checklist"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
related_task: "2026-09-15-multi-intent-u1-contracts"
|
||||
---
|
||||
|
||||
# 多意图 HITL U1 契约冻结 checklist
|
||||
|
||||
## Wave 0
|
||||
|
||||
- [x] YAML `app/intentflow` allowlist + 三表 owner + unwrap_owners — 证据:`.doc/system-design/module-boundaries.yaml`
|
||||
- [x] 三条 `intent.plan.*` YAML ↔ StaticContracts parity — 证据:`go test ./internal/events -run RegistryParity`
|
||||
- [x] archtest 扫描 `intent.plan.*` — 证据:`go test ./internal/archtest`
|
||||
- [x] intentflow 状态/错误码/Service/政策/legacy tier — 证据:`go test ./internal/app/intentflow`
|
||||
- [x] CSRF/Bearer 结论落盘 — 证据:U1 short-term
|
||||
- [x] `go test -short ./...` — 证据:[U1 报告](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: "多意图 HITL U2 规则分段 checklist"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
related_task: "2026-09-15-multi-intent-u2-segmenter"
|
||||
---
|
||||
|
||||
# 多意图 HITL U2 规则分段 checklist
|
||||
|
||||
## Wave 1
|
||||
|
||||
- [x] characterization 锁定 legacy IntentPlan — 证据:`internal/intent/plan_builder_test.go`;[报告 §5.1](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md)
|
||||
- [x] 分段器 golden(连接词/句号/序号/先再最后) — 证据:[proposal-verbose.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/proposal-verbose.txt)
|
||||
- [x] 查询并总结不拆;写段进入提案;5 段拒绝;红线整体拒绝;指代澄清 — 证据:同上
|
||||
- [x] digest 稳定;shadow 不改 TopIntent — 证据:`TestPlanProposal_DigestStable` / `TestPlanProposal_WriteNotDroppedAndLegacyUnchanged`
|
||||
- [x] 反事实 auto_read 错误自动执行 = 0 — 证据:`plan-proposal eval denom=8 false_auto_execute=0`
|
||||
- [x] `go test -short ./internal/intent ./internal/coordinator ./internal/app/intentflow` — 证据:[unit.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/unit.txt);[short.txt](../../test-reports/assets/2026-09-15-multi-intent-u2-segmenter/short.txt)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: "多意图 HITL U3 intentflow PG checklist"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
related_task: "2026-09-15-multi-intent-u3-intentflow-pg"
|
||||
---
|
||||
|
||||
# 多意图 HITL U3 intentflow PG checklist
|
||||
|
||||
## Wave 2
|
||||
|
||||
- [x] Goose 00044 三表 + unique/CAS/lease 列 — 证据:`deploy/postgres/goose/00044_2026-09-15-intent-plans.sql`;`TestGooseU3_00044_HasUpAndDown`
|
||||
- [x] 创建幂等与同 turn 异 digest — 证据:[plans-verbose.txt](../../test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/plans-verbose.txt)
|
||||
- [x] 决策 nonce / revision CAS / 过期 — 证据:同上
|
||||
- [x] 两 worker 无双 owner;租约接管;旧 fence 拒绝 — 证据:`TestTwoWorkersOneOwnerAndLeaseTakeover`
|
||||
- [x] receipt 对账不盲跑;环境隔离;legacy HandleTurn 不落盘 — 证据:`TestReceiptWritebackFailureDoesNotRerun` / `TestHandleTurnLegacyDoesNotPersist`
|
||||
- [x] Assemble 接线且 chat 不调用;arch-check 无新例外 — 证据:[short.txt](../../test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/short.txt)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: "多意图 HITL U4 outbox checklist"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
related_task: "2026-09-16-multi-intent-u4-outbox-projection"
|
||||
---
|
||||
|
||||
# 多意图 HITL U4 outbox checklist
|
||||
|
||||
- [x] 同 UoW Append intent.plan.* — 证据:[emit-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/emit-verbose.txt)
|
||||
- [x] golden payload 无敏感字段 — 证据:`testdata/intent-plan-awaiting-v1.json`
|
||||
- [x] 重复/乱序/伪造 producer — 证据:`TestProjectionOnlyForwardAndForgedRejected`
|
||||
- [x] 投影只前进;跨用户隔离 — 证据:同上
|
||||
- [x] dispatcher 语义未改;arch-check 绿 — 证据:[short.txt](../../test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/short.txt)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: "多意图 HITL U5 decision API checklist"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
related_task: "2026-09-16-multi-intent-u5-decision-api"
|
||||
---
|
||||
|
||||
# 多意图 HITL U5 decision API checklist
|
||||
|
||||
- [x] 冻结 REST 路径挂到认证 mux — 证据:[http-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/http-verbose.txt)
|
||||
- [x] Principal 不从 body 复制 — 证据:`TestIntentPlanHTTP_IgnoresBodyPrincipalAndSameReceipt`
|
||||
- [x] 非成员/跨作用域/管理员负例 — 证据:`TestIntentPlanHTTP_ScopeNegatives` / `AdminDoesNotBypassMembership`
|
||||
- [x] StepAuthorizer 在 confirm 与 execute 前调用 — 证据:[authorize-verbose.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/authorize-verbose.txt)
|
||||
- [x] stale/nonce/edit/非法部分确认 — 证据:同上
|
||||
- [x] arch-check / short 绿 — 证据:[short.txt](../../test-reports/assets/2026-09-16-multi-intent-u5-decision-api/short.txt)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: "多意图 HITL U6 Web checklist"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
related_task: "2026-09-16-multi-intent-u6-web-cards"
|
||||
---
|
||||
|
||||
# 多意图 HITL U6 Web checklist
|
||||
|
||||
- [x] PLAN_CONFIRM 类型与 PlanView 映射 — 证据:`web/src/engine/planCard.test.ts`
|
||||
- [x] 决策走 REST,不改 AST — 证据:`planCardTouchesLocalAST` + App early-return
|
||||
- [x] 409/过期/submitting 状态 — 证据:同上
|
||||
- [x] App early-return — 证据:`web/src/App.tsx`
|
||||
- [x] 单元测试绿;Playwright 门控 skip — 证据:[npm-test.txt](../../test-reports/assets/2026-09-16-multi-intent-u6-web-cards/npm-test.txt)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "U7 auto_read checklist"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
related_task: "2026-09-16-multi-intent-u7-auto-read"
|
||||
---
|
||||
|
||||
# U7
|
||||
|
||||
- [x] legacy HandleTurn 不落盘
|
||||
- [x] auto_read 查询创建并执行
|
||||
- [x] 写话语不落盘
|
||||
- [x] QueryGuard 拒绝 task.run
|
||||
- [x] chat 调用 HandleTurn;arch 绿
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
title: "U8 task generate checklist"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
related_task: "2026-09-16-multi-intent-u8-task-generate"
|
||||
---
|
||||
|
||||
# U8
|
||||
|
||||
- [x] confirm 话语落盘 awaiting,确认前不执行 — 证据:`TestHandleTurnConfirmPersistsAwaitingWithoutExecute`
|
||||
- [x] 第二活动写计划冲突 — 证据:`TestHandleTurnConfirmRejectsSecondActiveWritePlan`
|
||||
- [x] OwnerMux 路由 + nil Task fail closed — 证据:`TestOwnerMuxRoutesGenerateToTask` / `TestOwnerMuxNilTaskFailClosed`
|
||||
- [x] 确认后 generate 一次、重放不双跑 — 证据:`TestConfirmThenMuxExecutesGenerateOnce`
|
||||
- [x] adapter 幂等 / 拒查询 / 撤销 — 证据:`TestTaskRunAdapter*`
|
||||
- [x] LiveTaskStarter 同键重放 — 证据:`TestLiveTaskStarterReplaysIdempotencyKey`
|
||||
- [x] QueryGuard 仍拒 task.run;auto_read 写话语不落盘 — 证据:U7 回归 + `TestQueryGuardRejectsGenerate`
|
||||
- [x] 真实 PI stop-gate — 证据:`TestTaskGenerateRealPIStopGate` SKIP
|
||||
- [x] arch-check block 绿 — 证据:[报告](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
|
||||
|
||||
## 完成定义
|
||||
|
||||
- [x] 全部勾选且有证据链接
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: "多意图持久计划与 HITL(核心 U1–U8,扩面 U9–U12)"
|
||||
status: planned
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
owner: "-(待逐单元认领)"
|
||||
branch: feature/multi-intent-u1-contracts
|
||||
updated: 2026-09-16
|
||||
owner: Cursor
|
||||
branch: "-"
|
||||
worktree: "-"
|
||||
mutex: architecture-docs
|
||||
mutex: "-"
|
||||
---
|
||||
|
||||
# 多意图持久计划与 HITL(核心 U1–U8,扩面 U9–U12)
|
||||
@@ -51,14 +51,14 @@ mutex: architecture-docs
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [ ] U1 冻结边界、状态机、批量策略、错误码、事件和默认 legacy tier;
|
||||
2. [ ] U2 characterization-first 建 golden/hard-negative 与 shadow 基线;
|
||||
3. [ ] U3 建 intentflow owner、PG schema、CAS/lease/fencing/retention;
|
||||
4. [ ] U4 接 Track E outbox/dispatcher,只投影状态事实;
|
||||
5. [ ] U5 建统一 decision command 与动作 owner 授权端口;
|
||||
6. [ ] U6 取消计划动作的前端本地成功路径,以 PlanView 恢复;
|
||||
7. [ ] U7 只开放独立低风险查询;
|
||||
8. [ ] U8 只接 task generate,完成首版 real PI 闭环;
|
||||
1. [x] U1 冻结边界、状态机、批量策略、错误码、事件和默认 legacy tier([独立任务](./2026-09-15-multi-intent-u1-contracts.md);[报告](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md));
|
||||
2. [x] U2 characterization-first 建 golden/hard-negative 与 shadow 基线([独立任务](./2026-09-15-multi-intent-u2-segmenter.md);[报告](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md));
|
||||
3. [x] U3 建 intentflow owner、PG schema、CAS/lease/fencing/retention([独立任务](./2026-09-15-multi-intent-u3-intentflow-pg.md);[报告](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md));
|
||||
4. [x] U4 接 Track E outbox/dispatcher,只投影状态事实([独立任务](./2026-09-16-multi-intent-u4-outbox-projection.md);[报告](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md));
|
||||
5. [x] U5 建统一 decision command 与动作 owner 授权端口([独立任务](./2026-09-16-multi-intent-u5-decision-api.md);[报告](../../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md));
|
||||
6. [x] U6 取消计划动作的前端本地成功路径,以 PlanView 恢复([独立任务](./2026-09-16-multi-intent-u6-web-cards.md);[报告](../../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md));
|
||||
7. [x] U7 只开放独立低风险查询([独立任务](./2026-09-16-multi-intent-u7-auto-read.md);[报告](../../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md));
|
||||
8. [x] U8 只接 task generate,完成首版闭环(真实 PI 环境缺失记 stop-gate)([独立任务](./2026-09-16-multi-intent-u8-task-generate.md);[报告](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md));
|
||||
9. [ ] U9 作为独立可选实验接语义分段;
|
||||
10. [ ] U10–U12 分别按 mutate/docgov/workflow/run-control owner 扩面。
|
||||
|
||||
@@ -92,12 +92,14 @@ mutex: architecture-docs
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Checklist: U1 实施时建立逐波 checklist
|
||||
- Checklist: [U1](../checklists/2026-09-15-multi-intent-u1-contracts.md);[U2](../checklists/2026-09-15-multi-intent-u2-segmenter.md);[U3](../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md);[U8](../checklists/2026-09-16-multi-intent-u8-task-generate.md)
|
||||
- Handoff: 每个 U-ID 独立建立
|
||||
- Test report: 每个 U-ID 独立归档 `.doc/test-reports/`
|
||||
- Test report: [U1](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md);[U2](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md);[U3](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md);[U4](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md);[U5](../../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md);[U6](../../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md);[U7](../../test-reports/2026-09-16-multi-intent-u7-auto-read-test-report.md);[U8](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
|
||||
|
||||
## 证据 / 备注
|
||||
|
||||
- 当前 `plan_builder.go` 最多两段且写意图返回 nil;`action_planner.go` 的确认仍是文字提示。
|
||||
- 当前 `module-boundaries.yaml` 中 intent 仅依赖 maturity;Track E live,FAV off。
|
||||
- 本次只修订方案与任务文档,不实施、不提交、不推送。
|
||||
- U1 已冻结 intentflow 契约、事件与 BatchActionPolicy,默认 `MULTI_INTENT_PLAN_TIER=legacy`。
|
||||
- U2 已落地规则分段与 shadow `PlanProposal`;生产 TopIntent / IntentPlan 不变;反事实 `false_auto_execute=0`。
|
||||
- U8 已落地 confirm 落盘与 `task.run` adapter;默认 legacy 不落盘。U9–U12 不阻塞核心首版。共享环境 schema 45 待晋升窗口。
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
title: "多意图 HITL U1:契约冻结"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u1-contracts
|
||||
worktree: "-"
|
||||
mutex: architecture-docs
|
||||
---
|
||||
|
||||
# 多意图 HITL U1:契约冻结
|
||||
|
||||
## 目标
|
||||
|
||||
冻结 `app/intentflow` 边界、状态机、BatchActionPolicy、错误码、事件契约与默认 `legacy` tier;不改识别路由、不建表、不接 HTTP。
|
||||
|
||||
## 范围
|
||||
|
||||
- `module-boundaries.yaml`:`app/intentflow` allowlist、三表 owner、`unwrap_owners`、三条 `intent.plan.*` 事件
|
||||
- `events.StaticContracts` 与 YAML 对等;archtest 扫描 `intent.plan.*`
|
||||
- `internal/app/intentflow` 骨架:状态、错误码、Service 端口、政策、tier 开关
|
||||
- CSRF/认证结论:现有 Bearer + CORS 对 U5 足够,不是 blocker
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不修改 `internal/intent` 业务类型或 `MULTI_INTENT_ENABLED`
|
||||
- 不建 Goose 表、不接线 `app.Assemble`、不改 chat/coordinator/Web
|
||||
- 不 Append 事件、不实施 U2–U12
|
||||
|
||||
## REST(U5 再挂路由)
|
||||
|
||||
- `GET /api/v1/intent-plans/active`
|
||||
- `GET /api/v1/intent-plans/{plan_id}`
|
||||
- `POST /api/v1/intent-plans/{plan_id}/decisions`
|
||||
- body:`expected_revision`、`decision_nonce`、`decision_digest`、`kind`、步骤选择
|
||||
|
||||
## CSRF / 认证(U5 前置结论,非 blocker)
|
||||
|
||||
现有认证是 `Authorization: Bearer` 或 `X-Session-Token` 请求头(`internal/server/auth_handlers.go`),无 cookie 会话,无独立 CSRF 中间件;另有 Origin allowlist CORS。
|
||||
|
||||
- 自定义头不会被浏览器跨站表单自动带上,现有模式对 U5 足够
|
||||
- `decision_nonce` / 幂等键只防重放与并发,**不替代** CSRF 或身份认证
|
||||
- U5 必须 `requireAuthenticatedUser` + 四元作用域(environment/project/session/user)
|
||||
- **禁止**为计划 API 改成 cookie 自动提交
|
||||
- 若未来改 cookie 认证,另立 auth 任务,不得在 intent-plan 端点发明弱 CSRF
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 从最新 `dev` 检出 `feature/multi-intent-u1-contracts` 并认领 CURRENT
|
||||
2. [x] 登记边界 YAML、事件契约、archtest regex
|
||||
3. [x] 落地 intentflow 骨架与 BatchActionPolicy
|
||||
4. [x] arch/parity/short 测试与 U1 报告
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] `intent -> maturity` 保持;server/chat 不直写计划表
|
||||
- [x] YAML ↔ StaticContracts parity 绿
|
||||
- [x] 未知 action/policy key fail closed;ActionRegistry 无 batch/tier 字段
|
||||
- [x] 默认 `MULTI_INTENT_PLAN_TIER=legacy`
|
||||
- [x] 单意图生成策略不变(本单元无运行时改动)
|
||||
|
||||
## 相关链接
|
||||
|
||||
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
|
||||
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
|
||||
- Checklist: [../checklists/2026-09-15-multi-intent-u1-contracts.md](../checklists/2026-09-15-multi-intent-u1-contracts.md)
|
||||
- Test report: [../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md](../../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)
|
||||
|
||||
## 证据 / 备注
|
||||
|
||||
- 事件登记窗口同时占用 `events` mutex;U1 不改 intent 代码。
|
||||
- 生产者含 `events`:StaticContracts 字面量落在 `internal/events/registry.go`,与现有 document.* 先例一致。
|
||||
- CSRF:Bearer / `X-Session-Token` + CORS allowlist,U5 非 blocker。
|
||||
- 冒烟:`go vet ./...`、`go test -short ./...`、`./scripts/arch-check.sh --mode block` PASS。U1 无 schema/容器变更,集成槽位保持 idle。
|
||||
- 提交:`bdccb4d` docs(ops);`aefb1e4` feat(events);`9364da4` feat(intentflow);随后 docs(status)。
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: "多意图 HITL U2:规则分段与 shadow 提案"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u2-segmenter
|
||||
worktree: "-"
|
||||
mutex: intent
|
||||
---
|
||||
|
||||
# 多意图 HITL U2:规则分段与 shadow 提案
|
||||
|
||||
## 目标
|
||||
|
||||
在不改变生产路由(TopIntent / 现有 IntentPlan)的前提下,用纯规则分段器生成 2–4 步 `PlanProposal` 与 shadow 指标;写段不再在提案层被静默丢弃。
|
||||
|
||||
## 范围
|
||||
|
||||
- `internal/intent/segmenter.go`:连接词/句号/分号/换行/序号/先再最后,上限 4
|
||||
- `PlanProposal` L1 值对象:span、证据、缺槽、依赖建议、稳定 digest
|
||||
- Recognize 附加提案与 shadow;**不**改 coordinator 执行路径
|
||||
- golden / hard-negative / 反事实(若处于 auto_read 会如何)
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不建 PG、不接 HTTP、不改 Web
|
||||
- 不把 HITL/tier 回灌 ActionRegistry
|
||||
- 不启用 LLM 分段(U9)
|
||||
- 不把 shadow 提案当作生产 IntentPlan
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 认领 CURRENT,characterization 锁定现有 IntentPlan
|
||||
2. [x] 分段器 + PlanProposal + digest
|
||||
3. [x] 接入 Recognize(leaf 识别防递归)
|
||||
4. [x] golden/hard-negative/反事实与报告
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 「查风险,然后查法规」现有 IntentPlan 仍为 2 步 query
|
||||
- [x] 「查法规然后生成报价单」生产 IntentPlan 仍为 nil(路由不变),提案含写段且 ComboHint=needs_confirm
|
||||
- [x] 「查询并总结」不拆
|
||||
- [x] 指代失败 → needs_clarify
|
||||
- [x] 红线混入 → rejected
|
||||
- [x] 5 段 → rejected_batch_size
|
||||
- [x] 同输入 digest 稳定
|
||||
- [x] 反事实错误自动执行 = 0
|
||||
- [x] `intent -> maturity` 保持
|
||||
|
||||
## 相关链接
|
||||
|
||||
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
|
||||
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
|
||||
- Checklist: [../checklists/2026-09-15-multi-intent-u2-segmenter.md](../checklists/2026-09-15-multi-intent-u2-segmenter.md)
|
||||
- Test report: [../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md](../../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md)
|
||||
|
||||
## 证据 / 备注
|
||||
|
||||
- L1 不 import intentflow;`ComboHint` 只是结构提示,不是授权。
|
||||
- 单段复用 primary frame,避免二次 Recognize。
|
||||
- 冒烟:`go vet ./...`、`go test -short ./...`、`./scripts/arch-check.sh --mode block` PASS。U2 无 schema/容器变更。
|
||||
- 提交:`4751348` docs(ops) 认领;`9005766` test(intent) characterization;`932ba87` feat(intent) 分段器与 shadow 提案。
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: "多意图 HITL U3:intentflow PG/CAS/lease"
|
||||
status: done
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u3-intentflow-pg
|
||||
worktree: "-"
|
||||
mutex: intent-plan
|
||||
---
|
||||
|
||||
# 多意图 HITL U3:intentflow PG/CAS/lease
|
||||
|
||||
## 目标
|
||||
|
||||
建立持久计划/步骤/决策与并发协议(CAS revision、decision nonce、lease/fencing、创建幂等、retention);不接真实写动作,不改 chat/coordinator 生产路由。
|
||||
|
||||
## 范围
|
||||
|
||||
- Goose `00044`:`intent_plans` / `intent_plan_steps` / `intent_plan_decisions`
|
||||
- `app/intentflow` owner repository + UoW;owner 可 unwrap pgx
|
||||
- 创建幂等 `(environment, session_id, client_turn_id)`;同 turn 异 digest 冲突
|
||||
- 决策 CAS + nonce 同/异 digest;确认/取消/过期竞态
|
||||
- 步骤 lease + 单调 fencing;两 worker 只一个 owner
|
||||
- 业务成功但 receipt 写回失败时按幂等键对账,不盲跑
|
||||
- 环境隔离;关闭计划 retention 由 owner 删除
|
||||
- `app.Assemble` 装配 `*intentflow.Plans`,chat 仍不调用
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不接 HTTP(U5)、不 Append 事件(U4)、不接真实 action adapter(U7/U8)
|
||||
- 不把 HITL/tier 回灌 ActionRegistry
|
||||
- 不改 `internal/intent` 生产 TopIntent / IntentPlan
|
||||
- 不 rebuild 共享 `:8080`(schema 44 仅隔离库/后续晋升窗口应用)
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 认领 CURRENT(mutex `intent-plan`)
|
||||
2. [x] Goose 00044 + migrate gate
|
||||
3. [x] Store/Engine:Create/Decide/Claim/Receipt/Expire/Purge
|
||||
4. [x] 内存并发 + 可选 PG 测试;Assemble 接线
|
||||
5. [x] 报告并合回本地 dev
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 双创建同 digest 返回同一 plan;异 digest 冲突
|
||||
- [x] nonce 同 digest 返回 receipt;异 digest 冲突
|
||||
- [x] 确认/取消/过期只一个 CAS 胜出
|
||||
- [x] 两 worker 抢 eligible 步骤无双 owner
|
||||
- [x] 租约过期可接管;旧 fencing token 被动作属主拒绝
|
||||
- [x] 重启后 succeeded 不重跑;receipt 写回失败按幂等键恢复
|
||||
- [x] 跨 environment 隐藏
|
||||
- [x] 默认 legacy 时 HandleTurn 不落盘
|
||||
- [x] `go test -short ./internal/app/intentflow ./internal/app ./internal/archtest ./internal/db` 绿
|
||||
|
||||
## 相关链接
|
||||
|
||||
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
|
||||
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
|
||||
- Checklist: [../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md](../checklists/2026-09-15-multi-intent-u3-intentflow-pg.md)
|
||||
- Test report: [../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md](../../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md)
|
||||
|
||||
## 证据 / 备注
|
||||
|
||||
- HandleTurn 在默认 legacy 下不落盘;CreatePlan 是 U3 测试与后续 U7 入口。
|
||||
- 动作属主端口仅 FakeActionOwner;真实 adapter 从 U7/U8 按 key 接入。
|
||||
- PG 活验需隔离 `TEST_DATABASE_URL`;本机 short 门禁跳过。共享 `:8080` 仍 schema 43。
|
||||
- 提交:`a75aa45` docs(ops) 认领;`7dfd6d6` feat(db);`da0b3d8` feat(intentflow);`1385002` feat(app)。
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: Demo/测试数据污染全面整改
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor-Auto
|
||||
branch: fix/demo-data-pollution-web
|
||||
worktree: "-"
|
||||
mutex: web
|
||||
---
|
||||
|
||||
# Demo / 测试数据污染全面整改
|
||||
|
||||
## 目标
|
||||
|
||||
消除前端 mock/seed 与 DB 演示项目对真实项目清单的污染;生产包无演示文案;main 拒 stub。
|
||||
|
||||
## 范围
|
||||
|
||||
- Wave 0–5 代码 + Wave 6 文档(本分支合并实现)
|
||||
|
||||
## 非目标
|
||||
|
||||
- 删除合法 `*.test.ts` fixture
|
||||
- 改写工作流模板骨架
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] Wave 0 止血
|
||||
2. [x] Wave 1 门控
|
||||
3. [x] Wave 2 localStorage 迁移
|
||||
4. [x] Wave 3 UI 语义
|
||||
5. [x] Wave 4 DB retire
|
||||
6. [x] Wave 5 stub gate
|
||||
7. [x] Wave 6 文档
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] `check-prod-bundle.sh` PASS
|
||||
- [x] deliverableSync / demoSeedIds / ResolveBackend 单测 PASS
|
||||
- [x] `cd web && npm test` 全绿(审核 P0)
|
||||
- [x] 00046/00047 retire + ListChatSessions 过滤(审核 P1)
|
||||
- [x] 合入后共享环境 migrate + 人工空项目/会话抽检(dev schema 47;项目 6357 docs=0;列表无 6001–6010 / sess-wangjing)
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Audit: [.doc/audit/2026-09-16-demo-seed-pollution-systemic.md](../audit/2026-09-16-demo-seed-pollution-systemic.md)
|
||||
- 前序 Audit: [.doc/audit/2026-09-15-mock-deliverables-pollute-real-projects.md](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md)
|
||||
- Remediation: [.doc/remediation/2026-09-16-demo-seed-pollution-remediation.md](../remediation/2026-09-16-demo-seed-pollution-remediation.md)
|
||||
- Test report: [.doc/test-reports/2026-09-16-demo-seed-pollution-test-report.md](../test-reports/2026-09-16-demo-seed-pollution-test-report.md)
|
||||
- 挑拣:`a91a031` `SEED_DEMO_USERS=false`(自 `fix/clean-test-env-baseline`)
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: "FEATURE-MATRIX 深度测试 + 晋升部署 test"
|
||||
status: in_progress
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor-Auto
|
||||
branch: feature/matrix-deep-test-promote-test
|
||||
worktree: "-"
|
||||
mutex: infra
|
||||
---
|
||||
|
||||
# FEATURE-MATRIX 深度测试 + 晋升部署 test
|
||||
|
||||
## 目标
|
||||
|
||||
按 FEATURE-MATRIX 对已实现模块做分层深度回归,通过后将本地 `dev` 晋升到 `test`(`rc-v1.0.0-beta.2`)并 rebuild/冒烟 `:8081`。
|
||||
|
||||
## 范围
|
||||
|
||||
- Wave 1:vet/short/arch/npm/bundle + 模块定向 + 隔离治理 PG
|
||||
- Wave 2:dev `:8080` live API 抽检
|
||||
- Wave 3:真实 PI 抽样(失败再升格三链)
|
||||
- Wave 4:`dev` → `test` + rebuild + smoke
|
||||
- Wave 5:测试报告 + SSOT
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不实现纯软件项目自举
|
||||
- 不默认 28min 三工作流 PI;不合 `main`;不改项目 143;不启用 FAV
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [ ] 认领占槽
|
||||
2. [ ] 自动化深度回归
|
||||
3. [ ] live `:8080` 抽检
|
||||
4. [ ] PI 抽样
|
||||
5. [ ] 晋升 test 并冒烟
|
||||
6. [ ] 报告与归档
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] 矩阵已实现行均有 PASS 证据
|
||||
- [ ] `:8081` health/ready schema=47;`test-env-smoke.sh` PASS
|
||||
- [ ] tag `rc-v1.0.0-beta.2`;报告归档
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Plan: matrix_deep_test_promote
|
||||
- FEATURE-MATRIX / CURRENT / gap-matrix
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: "多意图 HITL U4:outbox 与计划投影"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u4-outbox-projection
|
||||
worktree: "-"
|
||||
mutex: events
|
||||
---
|
||||
|
||||
# 多意图 HITL U4:outbox 与计划投影
|
||||
|
||||
## 目标
|
||||
|
||||
权威计划在同一 UoW 写入 outbox;投影只应用状态事实;消息/SSE 丢失时 GET PlanView 仍能恢复。不改 dispatcher claim/lease/retry 语义。
|
||||
|
||||
## 范围
|
||||
|
||||
- Create/Decide/Receipt 同事务 Append `intent.plan.*`
|
||||
- 最小 payload + golden;伪造 producer 拒绝
|
||||
- projection consumer 幂等、只前进 revision;跨用户不可见
|
||||
- ctxmgr 只经 CardProjector 端口(接口在 intentflow,实现可 no-op)
|
||||
- 复用 Track E LiveConsumers
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不改通用 dispatcher
|
||||
- 不挂 HTTP(U5)、不改 Web(U6)、不执行动作(U7)
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 认领 CURRENT(mutex `events`)
|
||||
2. [x] emit + golden + 投影只前进
|
||||
3. [x] cmd/events 接入 multiplex;goose shadow
|
||||
4. [x] 报告并合回本地 dev
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 创建计划产生 awaiting_input;payload 无 prompt/slots
|
||||
- [x] 重复 event_id 不双写投影
|
||||
- [x] 乱序低 revision 不覆盖高 revision
|
||||
- [x] 伪造 producer 拒绝
|
||||
- [x] GET PlanView 不依赖投影成功
|
||||
- [x] arch-check / short 绿
|
||||
|
||||
## 相关链接
|
||||
|
||||
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
|
||||
- Checklist: [../checklists/2026-09-16-multi-intent-u4-outbox-projection.md](../checklists/2026-09-16-multi-intent-u4-outbox-projection.md)
|
||||
- Test report: [../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md](../../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md)
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "多意图 HITL U5:决策 API 与授权端口"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u5-decision-api
|
||||
worktree: "-"
|
||||
mutex: intent-plan
|
||||
---
|
||||
|
||||
# 多意图 HITL U5:决策 API 与授权端口
|
||||
|
||||
## 目标
|
||||
|
||||
按钮与自然语言走同一 `DecidePlan` 命令;GET 发现活动计划不依赖投影;执行前由动作属主重新授权。确认不是授权。
|
||||
|
||||
## 范围
|
||||
|
||||
- 冻结路径:`GET /api/v1/intent-plans/active`、`GET /api/v1/intent-plans/{plan_id}`、`POST /api/v1/intent-plans/{plan_id}/decisions`
|
||||
- Principal 只从认证会话 + query 的 project/session 组装,忽略 body 中的 user/project/session
|
||||
- 四元作用域;非成员 403;跨 session/user 隐藏为 404
|
||||
- 系统管理员不得绕过项目成员检查
|
||||
- `StepAuthorizer` 端口 + Fake/dry-run;确认与执行前鉴权
|
||||
- expected revision、nonce、依赖闭包、edit 升 revision
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不接真实业务属主 adapter(U7/U8)
|
||||
- 不改 Web(U6)、不改默认 legacy HandleTurn
|
||||
- 不 rebuild 共享 `:8080`
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 认领 CURRENT(mutex `intent-plan`)
|
||||
2. [x] 授权端口与 confirm/execute 即时鉴权
|
||||
3. [x] HTTP handlers + 权限负例
|
||||
4. [x] 报告并合回本地 dev
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] 投影缺失仍能 GET active
|
||||
- [ ] 未登录 401;非成员 403;跨项目/会话/用户隐藏
|
||||
- [ ] stale revision 409;重复 nonce 同 digest 同 receipt
|
||||
- [ ] 非法部分确认拒绝;edit 使旧 revision 失效
|
||||
- [ ] 确认前零副作用;权限撤销/资源版本 fail closed
|
||||
- [ ] 无系统身份绕过
|
||||
- [ ] `go test -short` 绿
|
||||
|
||||
## 相关链接
|
||||
|
||||
- 总览: [2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
|
||||
- 设计: [../../system-design/2026-09-15-multi-intent-hitl-plan.md](../../system-design/2026-09-15-multi-intent-hitl-plan.md)
|
||||
- Checklist: [../checklists/2026-09-16-multi-intent-u5-decision-api.md](../checklists/2026-09-16-multi-intent-u5-decision-api.md)
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: "多意图 HITL U6:Web 卡片、刷新与可访问性"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u6-web-cards
|
||||
worktree: "-"
|
||||
mutex: web
|
||||
---
|
||||
|
||||
# 多意图 HITL U6:Web 卡片、刷新与可访问性
|
||||
|
||||
## 目标
|
||||
|
||||
UI 只呈现 PlanView;计划动作不走本地 AST/资源修改;刷新与双标签以 GET reconcile。
|
||||
|
||||
## 范围
|
||||
|
||||
- `PLAN_CONFIRM` 卡片类型
|
||||
- intent-plans API client
|
||||
- submitting/outdated/expired/conflict;409 看最新版
|
||||
- App 计划动作 early-return,禁止本地成功路径
|
||||
- Playwright 门控(无 `RUN_UI_ACCEPTANCE` 则 skip)
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不接 auto_read 执行(U7)
|
||||
- 不 rebuild 共享环境
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 认领 CURRENT
|
||||
2. [x] 卡片/API/reconcile 与无 AST 路径
|
||||
3. [x] 单元测试 + 门控 Playwright
|
||||
4. [x] 报告并合回
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] 计划确认不修改 DocumentAST
|
||||
- [ ] GET 可修复缺失投影
|
||||
- [ ] 409 标 outdated 并带最新 PlanView
|
||||
- [ ] 默认 Playwright skip
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Checklist: [../checklists/2026-09-16-multi-intent-u6-web-cards.md](../checklists/2026-09-16-multi-intent-u6-web-cards.md)
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
title: "多意图 HITL U7:低风险只读执行"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u7-auto-read
|
||||
worktree: "-"
|
||||
mutex: intent-plan
|
||||
---
|
||||
|
||||
# 多意图 HITL U7:低风险只读执行
|
||||
|
||||
HandleTurn 在 auto_read 下执行独立查询;默认 legacy 不变。QueryGuard 拒绝 generate。
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
title: "多意图 HITL U8:task generate adapter"
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor
|
||||
branch: feature/multi-intent-u8-task-generate
|
||||
worktree: "-"
|
||||
mutex: intent-plan
|
||||
---
|
||||
|
||||
# 多意图 HITL U8:task generate adapter
|
||||
|
||||
## 目标
|
||||
|
||||
`confirm` tier 下查询+生成落盘 awaiting;确认后仅开放 `task.run` / `task.run.adhoc`,稳定幂等键,不改单意图 taskrun HTTP。
|
||||
|
||||
## 范围
|
||||
|
||||
- HandleTurn:`ComboNeedsConfirm` 且 tier≥confirm 时 WritePlan 落盘,不自动执行
|
||||
- `OwnerMux` 把 generate 路由到 Task,其余走 QueryGuard
|
||||
- `TaskRunAdapter` + `LiveTaskStarter`(无 `PI_AGENT_RUNNER_URL` 只占位不启 PI)
|
||||
- Assemble 接线;默认 `MULTI_INTENT_PLAN_TIER=legacy` 不变
|
||||
|
||||
## 非目标
|
||||
|
||||
- U9 LLM 分段、U10–U12 owner 扩面
|
||||
- 不 rebuild 共享环境、不改项目 143
|
||||
- 真实 PI 闭环若环境缺失记 stop-gate,不冒充验收
|
||||
|
||||
## 步骤
|
||||
|
||||
1. [x] 从 `dev` 开 `feature/multi-intent-u8-task-generate`
|
||||
2. [x] confirm 落盘 + mux + adapter
|
||||
3. [x] 单测与 arch-check
|
||||
4. [x] 报告并合回
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 多意图生成确认前零执行
|
||||
- [x] 活动写计划冲突
|
||||
- [x] 确认后 mux 执行 generate,重放 starts=1
|
||||
- [x] QueryGuard 仍拒绝 generate;权限撤销 fail closed
|
||||
- [x] 真实 PI 无 URL 时 skip(stop-gate)
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Checklist: [../checklists/2026-09-16-multi-intent-u8-task-generate.md](../checklists/2026-09-16-multi-intent-u8-task-generate.md)
|
||||
- Test report: [../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md](../../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md)
|
||||
- Parent: [./2026-09-15-multi-intent-hitl.md](./2026-09-15-multi-intent-hitl.md)
|
||||
|
||||
## 证据 / 备注
|
||||
|
||||
默认 legacy HandleTurn 仍不落盘。真实 PI 见报告 stop-gate。
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: "mock 交付物污染真实项目整改方案(demo 数据环境门控 + 服务端清单对账回收)"
|
||||
status: planned
|
||||
created: 2026-09-15
|
||||
updated: 2026-09-15
|
||||
---
|
||||
|
||||
# mock 交付物污染真实项目整改方案(demo 数据环境门控 + 服务端清单对账回收)
|
||||
|
||||
## 背景
|
||||
|
||||
[Audit 2026-09-15](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md):前端硬编码 mock 交付物(projectId 1/2/3/5201/6001+)与真实项目数字 ID 撞车,空项目展示「终审已生效」幻影受控文档与伪造法定职责人;mock 数据无环境门控且已进入生产构建产物;服务端权威清单为空时前端不回收本地多余项。
|
||||
|
||||
## 目标
|
||||
|
||||
1. 任何真实(服务端注册)项目的工作台**只显示**服务端 `document_records` + 该项目新建模板克隆项,永不出现 mock 幻影文档;
|
||||
2. mock/demo 数据仅在显式开启的 demo 构建中生效(构建期注入,默认关闭);
|
||||
3. 生产构建产物中不含 mock 文档正文与 mock 用户权限;
|
||||
4. localStorage 已持久化的 mock 项在升级后一次性回收;
|
||||
5. 前端对服务端清单做**双向对账**:服务端为权威,本地多余受控项下架(复用 ControlledInvalidationPlan/dropRecordKeys 机制)。
|
||||
|
||||
## 分波次计划
|
||||
|
||||
| 波次 | 内容 | 验收 |
|
||||
|------|------|------|
|
||||
| Wave 0 止血(低风险) | 1) `mergeWorkflowDocumentsFromServer` 增加对账回收:`category=workflow` 且 `isLegacyLocalMockDocId(docId)` 的本地项,在服务端清单返回(含空数组)时一律 drop(走 `dropRecordKeys` + 受控失效计划既有管道);2) 新建项目克隆模板的 docId 命名空间(`doc-p{projectId}-*`)与 mock 命名空间隔离校验测试 | test 环境新建项目后清单只剩 `doc-p1-*` 模板项;单测覆盖空清单回收 |
|
||||
| Wave 1 demo 门控 | 1) 所有 demo 种子(mockDocuments/neuropulse/tenProjects/MOCK_USERS/MOCK 权限)收口到 `web/src/data/seeds/` 单一入口,导出统一 `DEMO_SEEDS`;2) 入口处 `if (!import.meta.env.VITE_ENABLE_DEMO_SEEDS) return EMPTY`(构建期常量,生产默认 false);3) `npm run build` 产物 grep 验证不含「4K超高清荧光」等特征串(`VITE_ENABLE_DEMO_SEEDS= npm run build`);4) demo 构建单独脚本 `build:demo` | 产物 grep 断言进 CI/前端测试;demo 模式显式 opt-in |
|
||||
| Wave 2 存量清理 | 1) `loadDeliverables` 加载时一次性迁移:剔除命中 `isLegacyLocalMockDocId` 的持久化项(版本化 storage key bump);2) `loadUsers`/`loadProjects` 同理剔除 mock 用户/mock 项目(保留真实同步数据);3) 迁移写入 `storage.ts` 版本号,幂等可重放 | 升级后 localStorage 无 mock 残留;重复刷新幂等 |
|
||||
| Wave 3 UI 语义防线 | 1) `DeckDrawer`/`DocGovActionBar` 对非服务端注册文档(无 ledger 事实)禁用生命周期徽章/治理按钮,显示「本地示例(不入账本)」占位标签;2) `visibleDeliverables` 统计口径排除 mock ID(防污染项目文档计数) | 空项目不再出现「终审已生效」徽章;组件测试 |
|
||||
| Wave 4 验收与归档 | 1) test 环境真实新建项目全链路(新建→清单→刷新→重启容器)回归;2) dev 环境 id 1–3 项目抽检;3) `go vet` / `go test -short` / `cd web && npm test && npm run build` 全绿;4) test-report 归档 + gap-matrix 行 | 报告归档 `.doc/test-reports/`;gap-matrix 更新 |
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [ ] test 新建项目:交付物清单 0 幻影文档,仅 `doc-p{id}-*` 模板项(lifecycleState=template)
|
||||
- [ ] dev 项目 id 1/2/3:无 doc-001/doc-cusa-* 等幻影项
|
||||
- [ ] 生产构建产物 grep 无 mock 特征串;demo 构建仅显式开启时含种子
|
||||
- [ ] localStorage 升级迁移后无 mock 残留且幂等
|
||||
- [ ] 服务端清单对账:服务端删除/为空时本地对应受控项下架
|
||||
- [ ] 幻影文档(若 demo 模式保留)不带「终审已生效」徽章与治理操作
|
||||
|
||||
## 相关链接
|
||||
|
||||
- Audit: [../audit/2026-09-15-mock-deliverables-pollute-real-projects.md](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md)
|
||||
- Short-term: [../ops/short-term/2026-09-16-clean-test-env-baseline.md](../ops/short-term/2026-09-16-clean-test-env-baseline.md)
|
||||
- Test Report: [../test-reports/2026-09-16-clean-test-env-baseline-test-report.md](../test-reports/2026-09-16-clean-test-env-baseline-test-report.md)
|
||||
- gap-matrix 行: 待补(发布 blocker:治理记录失实 / 跨环境影响)
|
||||
- 既有同域防线: `web/src/features/documentRevision/revisionToolbarMount.ts`(isLegacyLocalMockDocId)、`web/src/lib/controlledDocHydrate.ts`(shouldLoadControlledContent)、`web/src/lib/deliverableSync.ts`(mergeWorkflowDocumentsFromServer)
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: Demo/测试数据污染整改方案
|
||||
status: done
|
||||
created: 2026-09-16
|
||||
updated: 2026-09-16
|
||||
owner: Cursor-Auto
|
||||
branch: fix/demo-data-pollution-web
|
||||
mutex: web
|
||||
---
|
||||
|
||||
# Demo / 测试数据污染整改方案
|
||||
|
||||
## 目标
|
||||
|
||||
生产构建默认无演示文案;权威服务端空清单回收本地 mock;DB 演示项目不进列表;main 拒绝 stub。
|
||||
|
||||
## 波次与状态
|
||||
|
||||
| Wave | 内容 | 状态 |
|
||||
|------|------|------|
|
||||
| 0 | `isDemoSeedDocId` + `mergeWorkflowDocumentsFromServer` 空清单 drop | done |
|
||||
| 1 | `VITE_ENABLE_DEMO_SEEDS` + `@demo-seeds` alias + `check-prod-bundle.sh` | done |
|
||||
| 2 | `purgeDemoSeedsFromLocalStorage` 幂等迁移 | done |
|
||||
| 3 | DeckDrawer「本地示例」徽章;职责人默认值清空 | done |
|
||||
| 4 | goose `00046` retire projects + `00047` retire sessions + list/`ListChatSessions` 过滤 | done |
|
||||
| 5 | `ResolveBackendInEnv` main/prod 拒 stub | done |
|
||||
| 6 | 审计/整改/报告/gap-matrix | done |
|
||||
|
||||
## 关键实现
|
||||
|
||||
- 判定:[`web/src/data/demoSeedIds.ts`](../../web/src/data/demoSeedIds.ts)
|
||||
- 门控:[`web/vite.config.ts`](../../web/vite.config.ts) alias `@demo-seeds` → enabled/disabled
|
||||
- 同步:[`web/src/lib/deliverableSync.ts`](../../web/src/lib/deliverableSync.ts)
|
||||
- DB:[`deploy/postgres/goose/00046_2026-09-16-retire-demo-ten-projects.sql`](../../deploy/postgres/goose/00046_2026-09-16-retire-demo-ten-projects.sql)
|
||||
- Stub:[`internal/taskrun/backend.go`](../../internal/taskrun/backend.go)
|
||||
|
||||
## 验收标准
|
||||
|
||||
- [x] 默认 `npm run build` 后 `check-prod-bundle.sh` PASS
|
||||
- [x] 空 server 清单 drop demo-seed 单测 PASS
|
||||
- [x] `ResolveBackendInEnv(..., "main")` 拒 stub 单测 PASS
|
||||
- [x] 共享环境 migrate `00046`/`00047` 后列表无 6001–6010(dev schema 47)
|
||||
- [x] 新建空项目 UI/API 交付物无伪造 approved(项目 6357 documents=0)
|
||||
|
||||
## 启用 Demo(仅本地/评审)
|
||||
|
||||
```bash
|
||||
VITE_ENABLE_DEMO_SEEDS=true npm run dev
|
||||
```
|
||||
|
||||
## Follow-up(P2,不挡合入)
|
||||
|
||||
- stub 旁路:`resolveTaskBackend` 双重失败返回 `""` 时 squad 回落 `cfg.AgentBackend`;建议 main/prod 启动 fail-fast 校验 `AGENT_BACKEND≠stub`
|
||||
- `purgeDemoSeedsFromLocalStorage` 对 projectId 1/2/3 无 serverIds 守卫,可能清掉 test 环境真实本地会话缓存;长期改为按 `sess-neuropulse-*` / `sess-wangjing-*` 前缀或注释权衡
|
||||
- 姊妹分支 `fix/clean-test-env-baseline` 重叠前端清理已放弃;已挑拣 `a91a031`(`SEED_DEMO_USERS=false`)与 2026-09-15 审计回链
|
||||
@@ -1,8 +1,8 @@
|
||||
# 整改缺口复核矩阵(SSOT)
|
||||
|
||||
**更新**: 2026-09-15
|
||||
**更新**: 2026-09-16
|
||||
**分支**: dev
|
||||
**production_ready**: no(CI 真实 PI 三工作流 E2E / 前端人工抽检未完成。`CHAT-INTENT-STATE` 双标签 busy 已 PASS。文档账本运行时 UI Round20 已 PASS,不把 fallback 报告当成完整 PI)
|
||||
**production_ready**: yes(发布门禁 B1–B4 已签;dev/test/main schema=47。U9–U12 / 软件自举 / FAV / 完整 PI change-report 叙事不挡首发)
|
||||
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
|
||||
**Agent 手册**: [AGENTS.md](../../AGENTS.md) · [PROJECT.md](../../PROJECT.md)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 |
|
||||
| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 |
|
||||
| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 |
|
||||
| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` |
|
||||
| BUG-08 | 测试库隔离 | PASS | `db/testdb.go` Require/Skip;CI `TEST_DATABASE_URL` + governance PG 步骤;[report](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md) | 已完成 |
|
||||
| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 |
|
||||
| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 |
|
||||
| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 |
|
||||
@@ -41,6 +41,9 @@
|
||||
| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval |
|
||||
| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 |
|
||||
| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 |
|
||||
| DEMO-DB-SEED | goose 00011/00012 演示项目污染列表 | **PASS** | `00046` retire projects + `00047` retire chat_sessions;`ListProjects*` / `ListChatSessions` 过滤 `demo_retired`;dev migrate schema **47**;抽检项目列表无 6001–6010、user1/2/3 无 `sess-wangjing*`、新建项目 6357 documents=0 | [audit](../audit/2026-09-16-demo-seed-pollution-systemic.md);前序 [2026-09-15](../audit/2026-09-15-mock-deliverables-pollute-real-projects.md);[report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md) |
|
||||
| DEMO-STUB-API | main/prod 仍可请求 stub Agent | **PASS** | `ResolveBackendInEnv`;`TestResolveBackendInEnv_RejectsStubInMain` |
|
||||
| DEMO-WEB-SEEDS | 前端 mock/seed 进生产包并撞 projectId | **PASS** | `@demo-seeds` 默认关闭;`check-prod-bundle.sh` PASS;[report](../test-reports/2026-09-16-demo-seed-pollution-test-report.md) |
|
||||
| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` |
|
||||
| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 |
|
||||
| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 |
|
||||
@@ -79,13 +82,13 @@
|
||||
```
|
||||
☑ go vet ./... 全绿
|
||||
☑ go test -short ./... 全绿
|
||||
□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
|
||||
□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token)
|
||||
□ 对话刷新恢复:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过
|
||||
☑ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
|
||||
☑ 真实 PI Agent 三工作流治理 E2E 实录([test-report](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md))
|
||||
☑ 对话刷新恢复:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过([test-report](../test-reports/2026-09-16-chat-refresh-gate-test-report.md);项目 6359)
|
||||
☑ lifecycle fix SQL 已在 dev 执行
|
||||
☑ test/dev health schema_version=25
|
||||
☑ main 环境部署冒烟(本地 8000 health/ready schema 25)
|
||||
□ 前端:版本冲突刷新、终止 preview 人工抽检
|
||||
☑ test/dev health schema_version=47
|
||||
☑ main 环境部署冒烟(本地 8000;schema 对齐见 CURRENT)
|
||||
☑ 前端:版本冲突刷新、终止 preview 人工抽检([test-report](../test-reports/2026-09-16-frontend-gate-b4-test-report.md);项目 6363)
|
||||
```
|
||||
|
||||
**结论**: 文档账本运行时真实 UI Round20 **PASS**(见 [test-report](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md))。`CHAT-INTENT-STATE` 双标签 busy **PASS**(项目 6275)。**发布 blocker 仍包括 CI 真实 PI 三工作流 E2E 与前端人工抽检**;`-race` 全包并行 TempDir flake 为测试基建残留。不得把 fallback change report 写成完整 PI 叙事。
|
||||
**结论**: 发布门禁四框已签。文档账本运行时 UI Round20 **PASS**;`CHAT-INTENT-STATE` 双标签 busy **PASS**;`DEMO-DB-SEED` **PASS**;BUG-08 **PASS**。`-race` TempDir flake 与 U9–U12 / 软件自举 / FAV / 完整 PI change-report 叙事不挡首发。不得把 fallback change report 写成完整 PI 叙事。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 模块与功能完成度(SSOT)
|
||||
|
||||
**更新**: 2026-09-15
|
||||
**production_ready**: no
|
||||
**更新**: 2026-09-16
|
||||
**production_ready**: yes
|
||||
**发布缺口**: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
|
||||
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
|
||||
|
||||
@@ -15,18 +15,19 @@
|
||||
|
||||
| 模块 | 能力 | 状态 | 证据 | 缺口/后续 | mutex |
|
||||
|------|------|------|------|-----------|-------|
|
||||
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/intent-recognition](../system-design/intent-recognition/);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[运行态报告](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);[双标签活验](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/live.json);[多意图复核方案](../system-design/2026-09-15-multi-intent-hitl-plan.md) | 明确写动作与只读总结已分流;双标签 `DOC_BUSY` 已签(项目 6275)。多意图持久计划仅完成方案复核,核心 U1–U8 与扩面 U9–U12 均未实施;intent 纯依赖边界不得回退 | `intent` |
|
||||
| 对话 / 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` |
|
||||
| 意图识别 L1 | 18 类 Intent + 三分支消解 | partial | [system-design/intent-recognition](../system-design/intent-recognition/);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[运行态报告](../test-reports/2026-09-13-conversation-intent-runtime-state-test-report.md);[双标签活验](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/live.json);[多意图复核方案](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1 契约](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md);[U2 分段](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md);[U3 PG](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) | 明确写动作与只读总结已分流;双标签 `DOC_BUSY` 已签(项目 6275)。多意图核心 U1–U8 已完成;U9–U12 不阻塞首版。intent 纯依赖边界不得回退 | `intent` |
|
||||
| 多意图持久计划 | app/intentflow 生命周期与 HITL 契约 | partial | [设计](../system-design/2026-09-15-multi-intent-hitl-plan.md);[U1](../test-reports/2026-09-15-multi-intent-u1-contracts-test-report.md)–[U8](../test-reports/2026-09-16-multi-intent-u8-task-generate-test-report.md) | U1–U8 核心首版已完成。U9–U12 不阻塞。默认 tier=legacy。真实 PI generate 待 runner URL。共享环境 schema 45 待晋升 | `intent-plan` |
|
||||
| 对话 / 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);[门禁 B3](../test-reports/2026-09-16-chat-refresh-gate-test-report.md) | `CHAT-HISTORY-REFRESH` 与发布门禁「激活后文档任务 + 重登/重启」已签(项目 6359)。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` |
|
||||
| 工作流治理 | 三正式工作流 + 阶段门禁 | 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);[真实 PI 三工作流 E2E](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md) | 设置页/DutyMode + 动作级鉴权已落地;真实 PI 三工作流 E2E 已签。后续:none 文档真实 PI 审批长链路;模块可仍 partial | `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` |
|
||||
| IAM / 鉴权 | 项目级 API 鉴权 + RBAC | partial | [audit/authorization](../audit/authorization-matrix-v2.md);[刷新恢复专项审计](../audit/2026-09-13-chat-history-refresh-disappears.md) | 历史读取端点补统一会话 owner + 阶段授权;旧 API 410 标注(BUG-11 partial) | `authz` |
|
||||
| 文档治理 | 法定文档生命周期 + 租约 + 受控正文读取 | done | [test docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md);[项目 143 正文 404 审计](../audit/2026-09-14-project143-controlled-content-404.md);[受控正文真实 UI 验收报告](../test-reports/2026-09-14-controlled-content-ui-acceptance.md);[UI-06 缓存竞争审计](../audit/2026-09-14-document-revision-refresh-cache-race.md);[整改](../remediation/2026-09-14-controlled-content-canonical-hash-remediation.md) | 生命周期/租约保留。W1–W6 + 审查修补 + UI hydrate 资格 + 晚到 list sync 修复均已合入 dev。项目 143 纯 UI 回归(clean-run3)与新项目全链路(main + post-restart)已全量真实页面验证通过(PASS) | `docgov` |
|
||||
| 文档版本与修改认知 | 智能体版本边界、人工修订标记、任意版本比较、变更报告与负责人通知 | partial | [管理测试](../test-reports/2026-09-13-document-revision-management-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md);[运行时审计](../audit/2026-09-13-document-revision-runtime-404.md);[ADR](../adr/2026-09-13-document-version-boundary.md) | **运行时 UI PASS**(6159 / V3/r2)。仍 `partial`:change report=`fallback`(真实 diff+lineage,非完整 PI 叙事)。系统级 `CHAT-INTENT` 见 gap-matrix | `docgov` |
|
||||
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[双标签截图](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png) | 错误卡片/任务进度/文档 busy 刷新恢复已有项目 6275 证据。前端人工抽检仍开放 | `web` |
|
||||
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md);[现场专项审计](../audit/2026-09-13-conversation-intent-runtime-state.md);[双标签截图](../test-reports/assets/2026-09-15-conversation-intent-dual-tab/screenshots/tab-b-busy.png);[demo seed 污染整改](../test-reports/2026-09-16-demo-seed-pollution-test-report.md);[门禁 B4](../test-reports/2026-09-16-frontend-gate-b4-test-report.md) | 错误卡片/任务进度/文档 busy 刷新恢复已有项目 6275 证据。Demo seeds 默认关闭。版本冲突信封解包 + 终止 preview 抽检已签(项目 6363) | `web` |
|
||||
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 + typed-result-v1 | 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);[typed-result-v1](../test-reports/2026-09-15-pi-typed-result-v1-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` |
|
||||
| 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);[治理 PG BUG-08](../test-reports/2026-09-16-ci-governance-pg-bug08-test-report.md);[真实 PI 三工作流](../test-reports/2026-09-16-pi-three-workflow-e2e-test-report.md);[运行时 UI Round20](../test-reports/2026-09-14-document-revision-runtime-ui-test-report.md) | BUG-08 PASS;真实 PI 三工作流 E2E 与前端/对话门禁已签。`-race` TempDir flake 为基建残留;夜间 CI `RUN_PI_E2E=1` 建议 | `ci` |
|
||||
| 模块解耦与可靠事件 | 文档可靠性纵向试点、PG 持久事件交付与选择性模块化 | partial | [架构](../system-design/2026-09-14-module-decoupling-architecture.md);[ADR](../adr/2026-09-14-modular-monolith-decoupling.md);[Phase 1](../remediation/2026-09-14-module-decoupling-refactor-plan.md);[Phase 2 审阅](../audit/2026-09-15-module-decoupling-phase2-plan-review.md);[Phase 2 修订计划](../remediation/2026-09-15-module-decoupling-ipc-phase2-remediation-plan.md);[E0A](../test-reports/2026-09-15-event-e0a-production-scope-contract-test-report.md);[E0B](../test-reports/2026-09-15-event-e0b-dispatcher-pg-test-report.md);[E1A](../test-reports/2026-09-15-event-e1a-notify-cutover-test-report.md);[E1B](../test-reports/2026-09-15-event-e1b-workflow-advance-test-report.md);[E1C](../test-reports/2026-09-15-event-e1c-projection-test-report.md);[E2](../test-reports/2026-09-15-event-e2-hook-guard-test-report.md);[复盘](../ops/research/2026-09-15-track-e-retrospective.md);[D6](../test-reports/2026-09-15-doccontent-canonical-boundary-test-report.md);[D7a](../test-reports/2026-09-15-intent-bizdev-boundary-test-report.md);[D5](../test-reports/2026-09-15-stageflow-type-ownership-test-report.md);[D4](../test-reports/2026-09-15-bizdev-locator-removal-test-report.md);[D7b](../test-reports/2026-09-15-chatflow-orchestration-boundary-test-report.md);[H0](../ops/research/2026-09-15-http-error-envelope-h0-inventory.md);[P0](../ops/research/2026-09-15-pi-typed-result-p0-matrix.md);[收口](../test-reports/2026-09-15-phase2-closeout-test-report.md);[notify live](../test-reports/2026-09-15-event-notify-shared-live-test-report.md);[advance live](../test-reports/2026-09-15-event-workflow-advance-shared-live-test-report.md);[projection live](../test-reports/2026-09-15-event-projection-shared-live-test-report.md);[HTTP 信封](../test-reports/2026-09-15-http-error-envelope-h1-h3-test-report.md);[PI typed-result](../test-reports/2026-09-15-pi-typed-result-v1-test-report.md) | E0A–E2 与共享 live 已过;生产无 hook 注册。D4–D7b 已合入。FAV off。Track P H1–H3 / P1–P4 已实施 | `architecture-docs` |
|
||||
|
||||
---
|
||||
|
||||
@@ -126,6 +126,12 @@
|
||||
| 主方案 | [2026-09-15-multi-intent-hitl-plan.md](2026-09-15-multi-intent-hitl-plan.md) |
|
||||
| 复核 | [../audit/2026-09-15-multi-intent-hitl-plan-review.md](../audit/2026-09-15-multi-intent-hitl-plan-review.md) |
|
||||
| 任务总览 | [../ops/short-term/2026-09-15-multi-intent-hitl.md](../ops/short-term/2026-09-15-multi-intent-hitl.md) |
|
||||
| U1 契约 | [../ops/short-term/2026-09-15-multi-intent-u1-contracts.md](../ops/short-term/2026-09-15-multi-intent-u1-contracts.md) |
|
||||
| U2 分段 | [../ops/short-term/2026-09-15-multi-intent-u2-segmenter.md](../ops/short-term/2026-09-15-multi-intent-u2-segmenter.md);[报告](../test-reports/2026-09-15-multi-intent-u2-segmenter-test-report.md) |
|
||||
| U3 PG | [../ops/short-term/2026-09-15-multi-intent-u3-intentflow-pg.md](../ops/short-term/2026-09-15-multi-intent-u3-intentflow-pg.md);[报告](../test-reports/2026-09-15-multi-intent-u3-intentflow-pg-test-report.md) |
|
||||
| U4 投影 | [../ops/short-term/2026-09-16-multi-intent-u4-outbox-projection.md](../ops/short-term/2026-09-16-multi-intent-u4-outbox-projection.md);[报告](../test-reports/2026-09-16-multi-intent-u4-outbox-projection-test-report.md) |
|
||||
| U5 API | [../ops/short-term/2026-09-16-multi-intent-u5-decision-api.md](../ops/short-term/2026-09-16-multi-intent-u5-decision-api.md);[报告](../test-reports/2026-09-16-multi-intent-u5-decision-api-test-report.md) |
|
||||
| U6 Web | [../ops/short-term/2026-09-16-multi-intent-u6-web-cards.md](../ops/short-term/2026-09-16-multi-intent-u6-web-cards.md);[报告](../test-reports/2026-09-16-multi-intent-u6-web-cards-test-report.md) |
|
||||
| 一句话总结 | intent 保持纯规则,intentflow 持久化计划并统一确认、授权、幂等、恢复和逐动作执行 |
|
||||
|
||||
**硬边界**:确认不等于授权;PG 是计划真相,卡片/SSE 是投影;写动作按 owner 端口逐项接入;LLM 只能提出不可信分段建议。
|
||||
|
||||
@@ -29,6 +29,7 @@ imports:
|
||||
- workflowdef
|
||||
chat:
|
||||
- app/chatflow
|
||||
- app/intentflow
|
||||
- app/stageflow
|
||||
- coordinator
|
||||
- ctxmgr
|
||||
@@ -65,6 +66,7 @@ imports:
|
||||
- app/docflow
|
||||
- app/docnotify
|
||||
- app/docproject
|
||||
- app/intentflow
|
||||
- app/stageflow
|
||||
- app/uow
|
||||
- artifactvault
|
||||
@@ -113,6 +115,10 @@ imports:
|
||||
- docquery
|
||||
- docrevision
|
||||
- events
|
||||
app/intentflow:
|
||||
- app/uow
|
||||
- events
|
||||
- intent
|
||||
app/uow: []
|
||||
app/stageflow:
|
||||
- bizdev
|
||||
@@ -159,6 +165,7 @@ imports:
|
||||
- app
|
||||
- app/chatflow
|
||||
- app/docflow
|
||||
- app/intentflow
|
||||
- app/stageflow
|
||||
- app/uow
|
||||
- auth
|
||||
@@ -304,6 +311,16 @@ table_owners:
|
||||
- dataset
|
||||
dataset_destroy_requests:
|
||||
- dataset
|
||||
intent_plans:
|
||||
- app/intentflow
|
||||
intent_plan_steps:
|
||||
- app/intentflow
|
||||
intent_plan_decisions:
|
||||
- app/intentflow
|
||||
intent_plan_projections:
|
||||
- app/intentflow
|
||||
intent_plan_shadow:
|
||||
- app/intentflow
|
||||
|
||||
path_owners:
|
||||
output.md:
|
||||
@@ -348,6 +365,15 @@ event_producers:
|
||||
- taskrun
|
||||
fav.artifact_staged:
|
||||
- app/docflow
|
||||
intent.plan.awaiting_input:
|
||||
- app/intentflow
|
||||
- events
|
||||
intent.plan.step_changed:
|
||||
- app/intentflow
|
||||
- events
|
||||
intent.plan.completed:
|
||||
- app/intentflow
|
||||
- events
|
||||
|
||||
event_consumers:
|
||||
outbox.notify:
|
||||
@@ -371,6 +397,15 @@ event_consumers:
|
||||
- notify
|
||||
fav.artifact_staged:
|
||||
- fav
|
||||
intent.plan.awaiting_input:
|
||||
- projection
|
||||
- notify
|
||||
intent.plan.step_changed:
|
||||
- projection
|
||||
- notify
|
||||
intent.plan.completed:
|
||||
- projection
|
||||
- notify
|
||||
|
||||
unwrap_owners:
|
||||
- docgov
|
||||
@@ -380,6 +415,7 @@ unwrap_owners:
|
||||
- events
|
||||
- artifactvault
|
||||
- ctxmgr
|
||||
- app/intentflow
|
||||
|
||||
exceptions:
|
||||
- kind: sql_write
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
# 多意图 HITL U1 契约冻结 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
多意图识别目前最多拆两段且写意图直接丢弃;确认只是 coordinator 文本提示。方案已复核为「持久计划深模块」,U1 必须先冻结边界、事件、状态机和 BatchActionPolicy,避免后续单元向 `intent` / coordinator 堆叠职责。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- `app/intentflow` 进入 import allowlist;三张计划表 owner 仅为 `app/intentflow`
|
||||
- 三条 `intent.plan.*` 事实事件 YAML ↔ `StaticContracts` 对等,payload 不含 prompt/slots/权限
|
||||
- 默认 `MULTI_INTENT_PLAN_TIER=legacy`;未知 policy key fail closed
|
||||
- ActionRegistry 不出现 batch/tier/adapter 字段
|
||||
- `intent -> maturity` 与全仓 short 测试无回归
|
||||
- 无运行时路由变更,因此不做真实 PI / 浏览器验收
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| Go | go1.27.1 linux/amd64 |
|
||||
| 分支 | `feature/multi-intent-u1-contracts`(从本地 `dev@9874237` 检出) |
|
||||
| Schema | **43**(本单元不迁移) |
|
||||
| 容器 | 不 rebuild |
|
||||
| 项目 143 | **只读** |
|
||||
| 证据 | `.doc/test-reports/assets/2026-09-15-multi-intent-u1-contracts/` |
|
||||
|
||||
测试层级:archtest / events parity / intentflow 单测 / `go test -short ./...`。无 PG 集成、无真实 PI。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 用例 | 判定 |
|
||||
|------|------|
|
||||
| YAML ↔ StaticContracts | 三条 `intent.plan.*` 生产者含 `app/intentflow`+`events`,消费者 `projection`+`notify` |
|
||||
| 未知 action key | `Lookup` 失败;构造期缺行/多行失败 |
|
||||
| `task.run` | 批量必须确认,`OpenFromTier=confirm` |
|
||||
| `regulation.query` | 不要求批量确认,`OpenFromTier=auto_read` |
|
||||
| 默认 tier | `legacy`;`MULTI_INTENT_ENABLED=true` 不升档 |
|
||||
| ActionSpec | 无 batch/tier/adapter 字段 |
|
||||
| arch-check block | production gate passed |
|
||||
| 全仓 short | PASS |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 事件 parity 与安全 payload
|
||||
|
||||
- **测试输入 (Input)**:`go test -count=1 ./internal/events -run 'RegistryParity|IntentPlan'`
|
||||
- **实际输出 (Actual Output)**:
|
||||
|
||||
```
|
||||
ok chat-agent-system/internal/events 0.004s
|
||||
```
|
||||
|
||||
(完整包输出见 [unit.txt](assets/2026-09-15-multi-intent-u1-contracts/unit.txt))
|
||||
|
||||
- **评价判定 (Evaluation / Verdict)**:PASS。`TestRegistryParityWithYAML`、`TestIntentPlanContractsOmitSensitivePayload` 绿。
|
||||
- **性能与耗时 (Duration & Latency)**:约 5ms
|
||||
|
||||
### 5.2 archtest / arch-check
|
||||
|
||||
- **测试输入**:`./scripts/arch-check.sh --mode block`;`go test -count=1 ./internal/archtest`
|
||||
- **实际输出**:
|
||||
|
||||
```
|
||||
arch-check mode=block
|
||||
ok chat-agent-system/internal/archtest 0.173s
|
||||
ok chat-agent-system/internal/archtest 0.154s
|
||||
arch-check block: production gate passed
|
||||
```
|
||||
|
||||
- **评价判定**:PASS。`intent.plan.*` 字面量可被扫描;`events` 已登记为生产者,registry.go 不误报。
|
||||
- **性能与耗时**:约 1.1s
|
||||
|
||||
### 5.3 intentflow 政策与 tier
|
||||
|
||||
- **测试输入**:`go test -count=1 ./internal/app/intentflow`
|
||||
- **实际输出**:`ok chat-agent-system/internal/app/intentflow 0.002s`
|
||||
- **评价判定**:PASS。未知 key fail closed;`task.run` 批量确认;查询不要求确认;ActionSpec 无 HITL 字段;默认 legacy。
|
||||
- **性能与耗时**:约 2ms
|
||||
|
||||
### 5.4 全仓 short 回归
|
||||
|
||||
- **测试输入**:`unset TEST_DATABASE_URL; go test -short -count=1 ./...`;`go vet ./...`;`git diff --check`
|
||||
- **实际输出**:见 [short.txt](assets/2026-09-15-multi-intent-u1-contracts/short.txt)。`internal/server` 9.920s;全包 ok。`go vet` 无输出。`git diff --check` 无空白错误。
|
||||
- **评价判定**:PASS。单意图路径无运行时改动,`internal/intent` / `internal/coordinator` / `internal/chat` 均绿。
|
||||
- **性能与耗时**:约 12s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go vet ./...` | PASS |
|
||||
| `go test -short -count=1 ./internal/app/intentflow ./internal/events ./internal/archtest ./internal/intent` | PASS |
|
||||
| `go test -short -count=1 ./...` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
|
||||
通过率 100%。未跑 PG / 真实 PI(本单元无副作用路径)。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U1 达到合入标准:契约冻结完成,默认 legacy,确认前零副作用保持不变。
|
||||
|
||||
后续:U2 在独立分支 `feature/multi-intent-u2-segmenter` 做规则分段 shadow;不得把 HITL/tier 回灌 ActionRegistry。
|
||||
|
||||
CSRF:现有 Bearer / `X-Session-Token` + CORS allowlist 对 U5 足够,不是 blocker。nonce 不替代认证。
|
||||
@@ -0,0 +1,145 @@
|
||||
# 多意图 HITL U2 规则分段与 shadow 提案 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U1 已冻结 `app/intentflow` 契约与默认 `legacy` tier。生产路径仍由 `plan_builder` 最多拆两段查询,写意图直接丢弃。U2 要在不改 TopIntent / 现有 IntentPlan 路由的前提下,用纯规则分段器生成 2–4 步 `PlanProposal`,并把写段、指代、红线、超限记录进 shadow,供后续 intentflow 消费。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 连接词 / 句号 / 分号 / 换行 / 序号 / 「先…再…最后」能拆出 2–4 段
|
||||
- 「查询并总结」内部链不拆;5 段不截断而是 `rejected_batch_size`
|
||||
- 写段进入提案且 `ComboHint=needs_confirm`;生产 IntentPlan 仍为 nil
|
||||
- 指代 → `needs_clarify`;红线 → 整句 `rejected`
|
||||
- 同输入 digest 稳定;反事实 `auto_read` 错误自动执行 = 0
|
||||
- `intent -> maturity` 保持;coordinator / chat 无回归
|
||||
- 无运行时路由变更,因此不做真实 PI / 浏览器验收
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| Go | go1.27.1 linux/amd64 |
|
||||
| 分支 | `feature/multi-intent-u2-segmenter`(从本地 `dev@8ac3d3f` 检出) |
|
||||
| Schema | **43**(本单元不迁移) |
|
||||
| 容器 | 不 rebuild |
|
||||
| 项目 143 | **只读** |
|
||||
| 证据 | `.doc/test-reports/assets/2026-09-15-multi-intent-u2-segmenter/` |
|
||||
|
||||
测试层级:characterization(legacy IntentPlan)/ 分段器单测 / PlanProposal + golden eval / `go test -short ./...`。无 PG 集成、无真实 PI。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 用例 | 判定 |
|
||||
|------|------|
|
||||
| 「查风险,然后查法规」 | 生产 IntentPlan 仍为 2 步 query;提案 `read_only`,反事实 `would_execute` |
|
||||
| 「查法规然后生成报价单」 | 生产 IntentPlan=nil,TopIntent 仍为查询;提案含写段、`needs_confirm`、`would_confirm`;shadow `LegacyDroppedWrite=true` |
|
||||
| 「查询并总结」 | 不分段;生产无 multi-intent plan;提案 `single` / `would_passthrough` |
|
||||
| 「然后再看一下它的适用范围」 | `needs_clarify` / `would_clarify` |
|
||||
| 「然后修改我的工号」 | 整句 `rejected` / `would_reject` |
|
||||
| 5 段编号 | 分段器保留 5 段;提案 `rejected_batch_size`,不静默截成 4 |
|
||||
| 同输入 digest | SHA-256 稳定 |
|
||||
| golden v1 denom=8 | `false_auto_execute=0` |
|
||||
| arch-check block | production gate passed |
|
||||
| 全仓 short | PASS |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 characterization:生产路由不变
|
||||
|
||||
- **测试输入 (Input)**:`go test -count=1 ./internal/intent -run 'TestLegacyIntentPlan|TestLimitedIntentPlan_QueryThenQuery'`
|
||||
- **实际输出 (Actual Output)**:
|
||||
|
||||
```
|
||||
--- PASS: TestLegacyIntentPlan_WriteComboStillDropped (0.00s)
|
||||
--- PASS: TestLegacyIntentPlan_NoConnectorStaysSingle (0.00s)
|
||||
--- PASS: TestLimitedIntentPlan_QueryThenQuery (0.00s)
|
||||
ok chat-agent-system/internal/intent 0.012s
|
||||
```
|
||||
|
||||
- **评价判定 (Evaluation / Verdict)**:PASS。写组合生产 IntentPlan 仍为 nil;「查询并总结」不产生 legacy 计划;双查询仍是 2 步 IntentPlan。
|
||||
- **性能与耗时 (Duration & Latency)**:约 12ms
|
||||
|
||||
### 5.2 分段器 golden
|
||||
|
||||
- **测试输入**:`go test -v -count=1 ./internal/intent -run TestSplitPlanSegments`
|
||||
- **实际输出**:
|
||||
|
||||
```
|
||||
--- PASS: TestSplitPlanSegments_ConnectorAndNumbered (0.00s)
|
||||
--- PASS: TestSplitPlanSegments_PeriodAndSemicolon (0.00s)
|
||||
--- PASS: TestSplitPlanSegments_InternalChainNotSplit (0.00s)
|
||||
--- PASS: TestSplitPlanSegments_FirstThenFinally (0.00s)
|
||||
--- PASS: TestSplitPlanSegments_FiveNumberedKeptIntact (0.00s)
|
||||
```
|
||||
|
||||
- **评价判定**:PASS。连接词、编号、「先再最后」、句号/分号均可拆;内部链保持 1 段;5 段不被截断。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.3 写段进入提案且路由不变
|
||||
|
||||
- **测试输入**:`查一下相关法规,然后帮我生成报价单`
|
||||
- **实际输出**:见 [proposal-verbose.txt](assets/2026-09-15-multi-intent-u2-segmenter/proposal-verbose.txt)
|
||||
|
||||
```
|
||||
--- PASS: TestPlanProposal_WriteNotDroppedAndLegacyUnchanged (0.00s)
|
||||
```
|
||||
|
||||
断言:`IntentPlan==nil`,`TopIntent=QUERY_REGULATIONS`,提案 ≥2 段,`ComboHint=needs_confirm`,`LegacyDroppedWrite=true`,`CounterfactualAutoRead=would_confirm`。
|
||||
|
||||
- **评价判定**:PASS。提案层不再静默丢写段;生产路由未改。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.4 指代 / 红线 / 批量上限 / digest
|
||||
|
||||
- **测试输入**:对应 `TestPlanProposal_AnaphoraClarify`、`SecurityRejectsWhole`、`BatchSizeRejected`、`DigestStable`
|
||||
- **实际输出**:
|
||||
|
||||
```
|
||||
--- PASS: TestPlanProposal_AnaphoraClarify (0.00s)
|
||||
--- PASS: TestPlanProposal_SecurityRejectsWhole (0.00s)
|
||||
--- PASS: TestPlanProposal_BatchSizeRejected (0.00s)
|
||||
--- PASS: TestPlanProposal_DigestStable (0.00s)
|
||||
```
|
||||
|
||||
- **评价判定**:PASS。指代澄清、红线整句拒绝、5 段 `rejected_batch_size`、digest 稳定。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.5 golden eval 与反事实安全
|
||||
|
||||
- **测试输入**:`internal/intent/testdata/plan-proposal-eval-v1.json`(denom=8)
|
||||
- **实际输出**:
|
||||
|
||||
```
|
||||
proposal_test.go:221: plan-proposal eval denom=8 false_auto_execute=0
|
||||
--- PASS: TestPlanProposalEvalGolden (0.00s)
|
||||
--- PASS: TestPlanProposal_HardNegativeNoFalseAutoExecute (0.00s)
|
||||
```
|
||||
|
||||
- **评价判定**:PASS。写/红线/指代/超限均不会被反事实判成 `would_execute`。`ComboHint` 只是结构提示,不是授权。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.6 边界与全仓 short
|
||||
|
||||
- **测试输入**:`go vet ./...`;`./scripts/arch-check.sh --mode block`;`unset TEST_DATABASE_URL; go test -short -count=1 ./internal/intent ./internal/coordinator ./internal/chat ./internal/archtest ./internal/app/intentflow`;`go test -short -count=1 ./...`
|
||||
- **实际输出**:`go vet` 无输出。`arch-check block: production gate passed`。包级见 [unit.txt](assets/2026-09-15-multi-intent-u2-segmenter/unit.txt);全仓见 [short.txt](assets/2026-09-15-multi-intent-u2-segmenter/short.txt)。`internal/server` 9.687s;全包 ok。
|
||||
- **评价判定**:PASS。`intent -> maturity` 保持;L1 未 import intentflow。coordinator / chat 无回归。
|
||||
- **性能与耗时**:全仓 short 约 12s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go vet ./...` | PASS |
|
||||
| `go test -count=1 ./internal/intent -run 'TestSplitPlanSegments\|TestPlanProposal\|TestLegacyIntentPlan'` | PASS |
|
||||
| `go test -short -count=1 ./internal/intent ./internal/coordinator ./internal/chat ./internal/archtest ./internal/app/intentflow` | PASS |
|
||||
| `go test -short -count=1 ./...` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
|
||||
通过率 100%。未跑 PG / 真实 PI(本单元无副作用路径)。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U2 达到合入标准:规则分段与 shadow `PlanProposal` 落地,生产 TopIntent / IntentPlan 不变,反事实错误自动执行为 0。
|
||||
|
||||
后续:U3 在独立分支 `feature/multi-intent-u3-intentflow-pg` 建 intentflow owner、PG schema、CAS/lease/fencing;不得把 HITL/tier 回灌 ActionRegistry,也不得把 shadow 提案当作生产 IntentPlan。
|
||||
@@ -0,0 +1,112 @@
|
||||
# 多意图 HITL U3 intentflow PG/CAS/lease 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U1 冻结了 intentflow 契约,U2 在 L1 产出 shadow `PlanProposal`,生产路由仍不落盘。U3 要把计划/步骤/决策变成 PostgreSQL 权威账本,并用 CAS、nonce、lease 与单调 fencing 保证两 worker 不能双 owner / 双执行。本单元不接真实写动作,也不改 chat 路径。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- Goose `00044` 建立 `intent_plans` / `intent_plan_steps` / `intent_plan_decisions`
|
||||
- 同 turn 同 digest 幂等;异 digest 冲突;同一作用域不能有第二个活动写计划
|
||||
- 决策 nonce 同 digest 返回 receipt,异 digest 冲突;确认/取消竞态只一个 CAS 胜出
|
||||
- 两 worker 抢 eligible 步骤只有一个 lease;过期可接管;旧 fencing token 被动作属主拒绝
|
||||
- 业务成功但 receipt 写回失败时按幂等键恢复,不盲跑
|
||||
- 跨 environment 隐藏;关闭计划可由 owner purge
|
||||
- 默认 legacy 下 `HandleTurn` 不落盘;chat/coordinator 无回归
|
||||
- 无 HTTP、无真实 adapter、无共享环境 rebuild
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| Go | go1.27.1 linux/amd64 |
|
||||
| 分支 | `feature/multi-intent-u3-intentflow-pg`(从本地 `dev@53c0722` 检出) |
|
||||
| Schema | 文件 **44**(共享 `:8080` 仍为 **43**,本单元不 rebuild) |
|
||||
| 容器 | 不 rebuild |
|
||||
| 项目 143 | **只读** |
|
||||
| 证据 | `.doc/test-reports/assets/2026-09-15-multi-intent-u3-intentflow-pg/` |
|
||||
|
||||
测试层级:内存 CAS/lease 单测(`-short`)/ goose 文件门禁 / arch-check / `go test -short ./...`。PG 集成 `TestPlansPG_CreateClaimAndFence` 在 `-short` 下跳过,需隔离 `TEST_DATABASE_URL`。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 用例 | 判定 |
|
||||
|------|------|
|
||||
| HandleTurn legacy | 不创建计划,GetActive 为空 |
|
||||
| 双创建同 digest | 同一 plan_id |
|
||||
| 同 turn 异 digest | `PLAN_DECISION_CONFLICT` |
|
||||
| 第二份活动写计划 | 冲突并返回已有活动计划 |
|
||||
| nonce 同/异 digest | receipt / conflict |
|
||||
| 确认 vs 取消 | 恰好一个 CAS 胜出 |
|
||||
| 两 worker | 仅一个 owner;租约过期接管;旧 fence `PLAN_ACTION_VERSION_CONFLICT` |
|
||||
| receipt 对账 | execute count=1,步骤 succeeded |
|
||||
| 跨 env / purge | `PLAN_NOT_FOUND_OR_HIDDEN` |
|
||||
| arch-check / 全仓 short | PASS |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 创建幂等与活动写计划锁
|
||||
|
||||
- **测试输入 (Input)**:`go test -v -count=1 ./internal/app/intentflow -run 'TestCreate'`
|
||||
- **实际输出 (Actual Output)**:
|
||||
|
||||
```
|
||||
--- PASS: TestCreateIdempotentSameDigest (0.00s)
|
||||
--- PASS: TestCreateRejectsSecondActiveWritePlan (0.00s)
|
||||
```
|
||||
|
||||
- **评价判定 (Evaluation / Verdict)**:PASS。
|
||||
- **性能与耗时 (Duration & Latency)**:<10ms
|
||||
|
||||
### 5.2 决策 CAS / nonce / 过期隔离
|
||||
|
||||
- **测试输入**:`TestDecisionNonceSameAndDifferentDigest`、`TestConfirmCancelRaceOneWinner`、`TestExpireAndEnvironmentIsolationAndRetention`
|
||||
- **实际输出**:见 [plans-verbose.txt](assets/2026-09-15-multi-intent-u3-intentflow-pg/plans-verbose.txt)。三用例均 PASS。
|
||||
- **评价判定**:PASS。确认/取消竞态恰好一个胜出;过期后确认失败;跨 env 隐藏;purge 后不可见。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.3 lease / fencing / receipt 对账
|
||||
|
||||
- **测试输入**:`TestTwoWorkersOneOwnerAndLeaseTakeover`、`TestReceiptWritebackFailureDoesNotRerun`
|
||||
- **实际输出**:
|
||||
|
||||
```
|
||||
--- PASS: TestTwoWorkersOneOwnerAndLeaseTakeover (0.00s)
|
||||
--- PASS: TestReceiptWritebackFailureDoesNotRerun (0.00s)
|
||||
```
|
||||
|
||||
- **评价判定**:PASS。旧 fencing token 由 FakeActionOwner 拒绝;写回失败路径只按幂等键恢复,不二次执行。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.4 HandleTurn 与边界
|
||||
|
||||
- **测试输入**:`TestHandleTurnLegacyDoesNotPersist`、`TestUnauthenticatedRejected`、`TestGooseU3_00044_HasUpAndDown`
|
||||
- **实际输出**:intentflow 与 db 包均 PASS。完整包输出见 [unit.txt](assets/2026-09-15-multi-intent-u3-intentflow-pg/unit.txt)。
|
||||
- **评价判定**:PASS。生产 HandleTurn 仍不落盘。00044 含 Up/Down 与三表、turn/write/nonce 唯一索引。
|
||||
- **性能与耗时**:db 约 3ms
|
||||
|
||||
### 5.5 全仓 short 与 arch-check
|
||||
|
||||
- **测试输入**:`go vet ./internal/app/intentflow ./internal/app ./internal/db`;`./scripts/arch-check.sh --mode block`;`unset TEST_DATABASE_URL; go test -short -count=1 ./...`
|
||||
- **实际输出**:`go vet` 无输出。`arch-check block: production gate passed`。全仓见 [short.txt](assets/2026-09-15-multi-intent-u3-intentflow-pg/short.txt)。`internal/server` 约 9.9s;全包 ok。
|
||||
- **评价判定**:PASS。`intent -> maturity` 保持;chat/coordinator 无回归。SQL 写仍仅 `app/intentflow`。
|
||||
- **性能与耗时**:全仓 short 约 12s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go vet ./internal/app/intentflow ./internal/app ./internal/db` | PASS |
|
||||
| `go test -count=1 ./internal/app/intentflow` | PASS(PG 用例 `-short` 跳过) |
|
||||
| `go test -short -count=1 ./internal/db ./internal/archtest ./internal/intent ./internal/coordinator ./internal/app` | PASS |
|
||||
| `go test -short -count=1 ./...` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
|
||||
通过率 100%。隔离库 `TEST_DATABASE_URL` 未在本机设置,PG 活验按 skip 记录,不冒充已跑。共享 `:8080` schema 仍为 43。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U3 达到合入标准:intentflow 成为计划表唯一写者,CAS/lease/fencing/retention 在内存路径闭环,默认 legacy 不改变对话路由。
|
||||
|
||||
后续:U4 在独立分支接 Track E outbox/投影;不得修改通用 dispatcher lease 语义。U5 再挂 HTTP。共享环境应用 schema 44 放到后续晋升/rebuild 窗口,不在本单元对项目 143 做迁移。
|
||||
@@ -0,0 +1,49 @@
|
||||
# 对话全链路刷新恢复(发布门禁 B3)测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
发布门禁要求:激活前聊天 + 激活后文档任务 + 刷新/重登/重启可恢复,双用户负例通过。`CHAT-HISTORY-REFRESH` 闲聊刷新已 PASS;本轮补齐激活后文档任务与重建恢复证据。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 真实 pi-agent 闲聊后 window/categories 一致
|
||||
- 非 owner `guest` 会话读取 403
|
||||
- SavePlan→Activate→任务 run 后 window 仍含激活前聊天与任务消息
|
||||
- app rebuild 后同 session window 消息数不丢
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS: Linux;dev `:8080`;`agent_backend=pi-agent`;`schema_version=47`
|
||||
- 脚本:`.doc/test-reports/assets/2026-09-15-chat-history-refresh-live/chat-refresh-live.py`(补成员 POST 后 SavePlan)
|
||||
- 重启:`./scripts/env-service.sh dev rebuild` 后重登拉取同一 session
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- `core_overall` / `overall` = PASS
|
||||
- `guest_403`;`pi_task_refresh` window_msgs ≥ 激活前
|
||||
- restart 后 msgs ≥ rebuild 前
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:全链路 live(项目 6359)
|
||||
|
||||
- **输入**: chat-refresh-live.py → `sess-p6359-u10`
|
||||
- **实际输出**: 见 [live.json](./assets/2026-09-16-chat-refresh-gate/live.json)
|
||||
- health/login/create/real_pi_chat/refresh/guest_403/pi_task_refresh 均 PASS
|
||||
- activate 后 run `run_1789531080321650206`;window_msgs=4,category_total=4
|
||||
- **判定**: PASS(`overall=PASS`,耗时 ~485s)
|
||||
|
||||
### 用例 2:重建恢复
|
||||
|
||||
- **输入**: rebuild 前 window=4;`env-service.sh dev rebuild`;重登拉 window
|
||||
- **实际输出**: [restart.json](./assets/2026-09-16-chat-refresh-gate/restart.json) `before=4 after=4`
|
||||
- **判定**: PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
本门禁以 live + rebuild 证据为主;关联 `go test -short` / `npm test` 在合入冒烟执行。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- 发布门禁「对话刷新恢复」可 ☑。
|
||||
- SavePlan 前必须 upsert 职责成员(脚本已补)。
|
||||
@@ -0,0 +1,48 @@
|
||||
# CI 治理 PG 集成 / BUG-08 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
gap-matrix BUG-08(测试库隔离)与发布门禁「TEST_DATABASE_URL 下治理 PG 集成」仍为开放项。CI 虽已注入 `TEST_DATABASE_URL`,但治理 PG 用例因成员校验与同步通知断言漂移而无法作为门禁签字。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 隔离库上 `TestWorkflowGovernance_PG_*` / `TestE2E_WorkflowGovernance*` 全绿
|
||||
- CI 增加显式 governance PG 步骤(非 `-short`)
|
||||
- BUG-08 → PASS;发布门禁第一框 ☑
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS: Linux;Go 1.23+/1.27.1 CI
|
||||
- 隔离库:`postgres://app:***@127.0.0.1:5434/agent_gov_ci`(拒绝 `agent_system_dev/test/main`)
|
||||
- 层级:PG 集成(无 stub PI)
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- 三权负责人先写入 `project_members` 后再 SavePlan
|
||||
- Activate → Approve → Advance / CompleteAndReplan 成功
|
||||
- 通知列表 200(不强制同步 `stage_ready_to_advance`;事件已切 outbox)
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:隔离库治理 PG
|
||||
|
||||
- **输入**: `TEST_DATABASE_URL=.../agent_gov_ci go test ./internal/server/ -run 'TestWorkflowGovernance_PG_|TestE2E_WorkflowGovernance'`
|
||||
- **实际输出**:
|
||||
```
|
||||
--- PASS: TestE2E_WorkflowGovernance_CompleteAndReplan (0.57s)
|
||||
--- PASS: TestWorkflowGovernance_PG_ActivateApproveAdvanceChain (0.28s)
|
||||
ok chat-agent-system/internal/server 0.852s
|
||||
```
|
||||
- **判定**: PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
```text
|
||||
CI: go-vet-and-short-test 增加 governance PG integration 步骤
|
||||
本地隔离库:上述 2 用例 PASS;goose → 47
|
||||
```
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- BUG-08 / 发布门禁「TEST_DATABASE_URL 治理 PG」可关闭。
|
||||
- 下一波:真实 PI 三工作流 E2E(RUNNER_AUTH_TOKEN + 非 stub)。
|
||||
@@ -0,0 +1,80 @@
|
||||
# Demo / 测试数据污染整改 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
空项目展示伪造「终审已生效」文档与三级职责人;根因为前端 demo seed + goose 演示项目 + stub 可请求,非 docgov 隔离失败。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 默认生产构建无演示文案特征串
|
||||
- 权威空服务端清单回收本地 demo-seed 交付物
|
||||
- main/prod 拒绝 stub backend
|
||||
- ID 判定覆盖 neuropulse / ten-projects
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS: Linux;Web: Vite 生产构建(`VITE_ENABLE_DEMO_SEEDS` 未设置)
|
||||
- 层级:单元(vitest / go test)+ 产物扫描;共享环境 migrate 留合入槽位冒烟
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- `check-prod-bundle.sh` → PASS
|
||||
- `mergeWorkflowDocumentsFromServer([], …)` drop `doc-001` / neuropulse / `doc-proj6001-*`,保留 `doc-p1-*`
|
||||
- `ResolveBackendInEnv("stub", …, "main")` → error
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:产物扫描
|
||||
|
||||
- **输入**: `bash scripts/check-prod-bundle.sh`
|
||||
- **实际输出**: `PASS: prod bundle scan (.../web/dist)`
|
||||
- **判定**: PASS
|
||||
- **耗时**: ~11s(含 rebuild)
|
||||
|
||||
### 用例 2:deliverableSync 空清单回收 + demoSeedIds(node:test)
|
||||
|
||||
- **输入**: `cd web && npm test`(仓库门禁;含 `demoSeedIds.test.ts` 经 tsx/node:test)
|
||||
- **实际输出**: `tests 374 / pass 374` + vitest `Test Files 3 passed / Tests 32 passed`
|
||||
- **判定**: PASS
|
||||
- **耗时**: ~1.8s
|
||||
|
||||
### 用例 3:stub 环境门控
|
||||
|
||||
- **输入**: `go test ./internal/taskrun/ -count=1`
|
||||
- **实际输出**: `ok chat-agent-system/internal/taskrun`
|
||||
- **判定**: PASS(含 `TestResolveBackendInEnv_RejectsStubInMain`)
|
||||
|
||||
### 用例 4:demo 会话列表过滤
|
||||
|
||||
- **输入**: `go test ./internal/ctxmgr/ -count=1 -run ListChatSessions_SkipsDemoRetired`
|
||||
- **实际输出**: `ok`
|
||||
- **判定**: PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
```text
|
||||
cd web && npm test → 374 PASS (tsx) + 32 PASS (vitest)
|
||||
go test ./internal/taskrun → PASS
|
||||
go test ./internal/ctxmgr -run ListChatSessions_SkipsDemoRetired → PASS
|
||||
scripts/check-prod-bundle.sh → PASS
|
||||
```
|
||||
|
||||
全量 `go test -short ./...` / 共享环境 migrate 留合入集成槽位执行。
|
||||
|
||||
### 用例 5:合入槽位冒烟(dev)
|
||||
|
||||
- **输入**: `go vet ./...`;`go test -short ./...`;`cd web && npm test`;`check-prod-bundle.sh`;`env-service.sh dev rebuild`;migrate 至 47;API 抽检
|
||||
- **实际输出**:
|
||||
- health `schema_version=47`,`agent_backend=pi-agent`
|
||||
- projects 列表 demo 6001–6010 = 0
|
||||
- chat sessions 无 `sess-wangjing*` / project 6001–6010
|
||||
- 新建项目 **6357** `GET .../documents` → `docs 0`
|
||||
- DB:`demo_sessions_active=0`
|
||||
- **判定**: PASS
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- Wave 0–5 + 审核 P0/P1 已合入本地 `dev`;`DEMO-DB-SEED` → **PASS**。
|
||||
- 注:dev 在扩展 00046 前已应用仅项目退休的 00046,故会话退休以幂等 **00047** 落地;00046 文件仍含 sessions 以利全新库一次到位。
|
||||
- Demo 评审启用:`VITE_ENABLE_DEMO_SEEDS=true`。
|
||||
- P2 follow-up 见 remediation 文末。
|
||||
@@ -0,0 +1,59 @@
|
||||
# 前端版本冲突刷新与终止 preview(发布门禁 B4)测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
发布门禁要求人工抽检:版本冲突后刷新再确认、终止 preview 可用。抽检中发现 HTTP 信封将领域码嵌套进 `error` JSON 字符串,前端若只读信封 `VERSION_CONFLICT` 会错过 `PLAN_FROZEN` / `ERR_CONCURRENT_SWITCH` 恢复路径。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 过期 `expected_selection_version` → 409 + 业务码 `ERR_CONCURRENT_SWITCH` → 恢复 `retry_after_switch`
|
||||
- 激活后改规划 → 409 + `PLAN_FROZEN` → `refresh_and_freeze`
|
||||
- `GET …/termination-preview` 返回 `can_terminate` 等字段
|
||||
- 单元:信封嵌套解包;设置页冲突后 reload settings
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- live API:dev `:8080`,项目 `6363`
|
||||
- 单测:`npx tsx --test src/api/projectSettingsError.test.ts`
|
||||
- 代码:`web/src/api/projectSettingsError.ts`、`ProjectSettingsModal.tsx`
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
各用例 PASS;`npm test` 全绿。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:版本冲突 409
|
||||
|
||||
- **输入**: SavePlan 后以 `expected_selection_version=999` 再 PUT
|
||||
- **实际输出**: HTTP 409;嵌套业务码 `ERR_CONCURRENT_SWITCH`;recovery=`retry_after_switch`
|
||||
- **判定**: PASS([live.json](./assets/2026-09-16-frontend-gate-b4/live.json))
|
||||
|
||||
### 用例 2:终止 preview
|
||||
|
||||
- **输入**: 激活实例后 `GET /api/v1/workflow-instances/{id}/termination-preview`
|
||||
- **实际输出**: 200;keys 含 `can_terminate` / `pending_documents` / `in_progress_task_runs` / `impact`
|
||||
- **判定**: PASS
|
||||
|
||||
### 用例 3:激活后冻结刷新
|
||||
|
||||
- **输入**: 激活后 PUT 旧 revision
|
||||
- **实际输出**: 409;业务码 `PLAN_FROZEN`;recovery=`refresh_and_freeze`
|
||||
- **判定**: PASS
|
||||
|
||||
### 用例 4:错误解包单测
|
||||
|
||||
- **输入**: projectSettingsError.test.ts(含信封嵌套用例)
|
||||
- **实际输出**: 7 pass([projectSettingsError-unit.txt](./assets/2026-09-16-frontend-gate-b4/projectSettingsError-unit.txt))
|
||||
- **判定**: PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
```text
|
||||
cd web && npm test → 376 pass (tsx) + 32 pass (vitest) EXIT 0
|
||||
```
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- 发布门禁「前端:版本冲突刷新、终止 preview」可 ☑。
|
||||
- 后续可将信封解包复用到其他 409 消费方,避免只认 `VERSION_CONFLICT`。
|
||||
@@ -0,0 +1,65 @@
|
||||
# 多意图 HITL U4 outbox 与计划投影 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U3 已把计划写入 PostgreSQL,但卡片/SSE 仍无法从事实事件恢复。U4 要在同一 UoW 写入 Track E outbox,投影只前进 revision;消息失败不得回滚权威计划。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- Create/Decide/Receipt 发出 `intent.plan.*`,payload 仅契约字段
|
||||
- 重复 event_id 幂等;低 revision 不覆盖;伪造 producer 拒绝
|
||||
- 跨用户 shadow 不可见;GET PlanView 不依赖投影
|
||||
- 不改 dispatcher claim/lease/retry
|
||||
- 默认 HandleTurn 仍不落盘
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| Go | go1.27.1 linux/amd64 |
|
||||
| 分支 | `feature/multi-intent-u4-outbox-projection` |
|
||||
| Schema 文件 | **45**(共享 `:8080` 仍 43,不 rebuild) |
|
||||
| 项目 143 | 只读 |
|
||||
| 证据 | `.doc/test-reports/assets/2026-09-16-multi-intent-u4-outbox-projection/` |
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
创建计划发出 `awaiting_input`;golden 无 prompt/slots;乱序/伪造 fail closed;arch-check 与全仓 short 绿。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 emit 与 golden
|
||||
|
||||
- **测试输入**:`go test -v -count=1 ./internal/app/intentflow -run 'TestCreatePlanEmits|TestAwaiting'`
|
||||
- **实际输出**:见 [emit-verbose.txt](assets/2026-09-16-multi-intent-u4-outbox-projection/emit-verbose.txt)。三用例 PASS。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.2 只前进与伪造 producer
|
||||
|
||||
- **测试输入**:`TestProjectionOnlyForwardAndForgedRejected`
|
||||
- **实际输出**:PASS。低 revision 不覆盖;`Producer=forged` → `ErrIntegrityFailure`。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.3 全仓 short / arch-check
|
||||
|
||||
- **测试输入**:`./scripts/arch-check.sh --mode block`;`go test -short -count=1 ./...`
|
||||
- **实际输出**:`arch-check block: production gate passed`。全仓见 [short.txt](assets/2026-09-16-multi-intent-u4-outbox-projection/short.txt)。
|
||||
- **评价判定**:PASS。dispatcher 语义未改;chat/coordinator 无回归。
|
||||
- **性能与耗时**:约 12s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go test -count=1 ./internal/app/intentflow ./internal/events ./internal/archtest ./internal/db` | PASS |
|
||||
| `go test -short -count=1 ./...` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
|
||||
通过率 100%。隔离库 PG 活验未跑。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U4 达到合入标准。后续 U5 挂 decision API;投影失败时仍以 GET PlanView 恢复。
|
||||
@@ -0,0 +1,66 @@
|
||||
# 多意图 HITL U5 决策 API 与授权端口 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U4 已把计划事实写入 outbox。U5 要把按钮和自然语言接到同一 `DecidePlan` 命令,并在确认/执行前由动作属主重新授权。确认不是授权;系统管理员不得绕过项目成员检查。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 冻结 REST:active / `{plan_id}` / decisions
|
||||
- Principal 只来自认证会话,忽略 body 中的 user/project/session
|
||||
- 未登录 401;非成员 403;跨项目/会话隐藏 404
|
||||
- 投影缺失仍能 GET active
|
||||
- 权限撤销、资源版本、stale revision、非法部分确认、edit 升 revision
|
||||
- 重复 nonce 同 digest 返回同一 receipt
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux 7.0.0-31-generic |
|
||||
| Go | go test -short |
|
||||
| 分支 | `feature/multi-intent-u5-decision-api` |
|
||||
| 后端 | 内存计划账本 + FakeActionOwner(dry-run) |
|
||||
| 项目 143 | 只读;不 rebuild `:8080` |
|
||||
| 证据 | `.doc/test-reports/assets/2026-09-16-multi-intent-u5-decision-api/` |
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
确认被拒绝时计划 revision/status 不变;执行前撤销权限 fail closed;HTTP 作用域负例全绿;arch-check 与全仓 short 绿。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 授权端口
|
||||
|
||||
- **测试输入**:`go test -v ./internal/app/intentflow -run 'TestConfirmDenied|TestResourceVersion|TestRevokeBetween|TestEditBumps|TestIllegalPartial'`
|
||||
- **实际输出**:见 [authorize-verbose.txt](assets/2026-09-16-multi-intent-u5-decision-api/authorize-verbose.txt)。五用例 PASS。
|
||||
- **评价判定**:PASS。确认前零副作用;旧卡 edit 后 409。
|
||||
- **性能与耗时**:4ms
|
||||
|
||||
### 5.2 HTTP 作用域与幂等
|
||||
|
||||
- **测试输入**:`go test -v ./internal/server -run TestIntentPlanHTTP`
|
||||
- **实际输出**:见 [http-verbose.txt](assets/2026-09-16-multi-intent-u5-decision-api/http-verbose.txt)。六用例 PASS(含管理员不得绕过成员检查、body principal 忽略、同 nonce receipt)。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:0.77s
|
||||
|
||||
### 5.3 全仓 short / arch-check
|
||||
|
||||
- **测试输入**:`./scripts/arch-check.sh --mode block`;`go test -short -count=1 ./...`
|
||||
- **实际输出**:`arch-check block: production gate passed`。[short.txt](assets/2026-09-16-multi-intent-u5-decision-api/short.txt)
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:约 13s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go test ./internal/app/intentflow ./internal/server ./internal/archtest` | PASS |
|
||||
| `go test -short ./...` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
|
||||
通过率 100%。真实业务 adapter 与 Web 不在本单元。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U5 达到合入标准。后续 U6 以 PlanView 渲染卡片并 GET reconcile;U7 才开放 auto_read 查询执行。
|
||||
@@ -0,0 +1,60 @@
|
||||
# 多意图 HITL U6 Web 卡片 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U5 已提供决策 API。Web 若继续走驳回卡的本地 AST 成功路径,刷新/双标签会出现假成功。U6 让计划卡只呈现 PlanView,动作只打 REST。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- `PLAN_CONFIRM` 由 PlanView 生成
|
||||
- 计划动作 `planCardTouchesLocalAST=false`
|
||||
- 409 → outdated + 最新 revision;GET reconcile 不把 submitting 写成 resolved
|
||||
- App 对计划卡 early-return
|
||||
- Playwright 无 `RUN_UI_ACCEPTANCE` 时 skip
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| 分支 | `feature/multi-intent-u6-web-cards` |
|
||||
| 前端 | `web/npm test` |
|
||||
| Playwright | 门控 skip |
|
||||
| 项目 143 | 只读 |
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
计划确认不修改 DocumentAST;冲突卡 outdated;默认 Playwright skip。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 PlanView 映射与无 AST
|
||||
|
||||
- **测试输入**:`npx tsx --test src/engine/planCard.test.ts`(含在 `npm test`)
|
||||
- **实际输出**:`PLAN_CONFIRM 卡片来自 PlanView 且不触达 AST` 等 5 用例 PASS。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:<10ms
|
||||
|
||||
### 5.2 前端回归
|
||||
|
||||
- **测试输入**:`npm test`(web/)
|
||||
- **实际输出**:tsx 371 pass;vitest 30 pass(含 PLAN_CONFIRM 元数据)。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:约 3s
|
||||
|
||||
### 5.3 Playwright
|
||||
|
||||
- **测试输入**:`web/e2e/intent-plan-cards.spec.ts` 在未设 `RUN_UI_ACCEPTANCE` 时 skip
|
||||
- **实际输出**:门控 `test.skip(!runAcceptance)`。本单元未对项目 143 做浏览器活验。
|
||||
- **评价判定**:PASS(门控符合约定)。
|
||||
- **性能与耗时**:n/a
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `cd web && npm test` | PASS 371+30 |
|
||||
| Playwright live dual-tab | SKIP(无 RUN_UI_ACCEPTANCE) |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U6 达到合入标准。真实双标签活验仍待 `RUN_UI_ACCEPTANCE`。U7 开放 auto_read 查询执行。
|
||||
@@ -0,0 +1,48 @@
|
||||
# 多意图 HITL U7 低风险只读执行 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U5/U6 已能确认计划。U7 在 `MULTI_INTENT_PLAN_TIER=auto_read` 下把独立低风险查询推进到执行,默认 legacy 仍不落盘。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 默认 HandleTurn 不落盘
|
||||
- auto_read + 只读 2–4 段:创建、自动确认、逐步执行
|
||||
- 同 turn 重放不双跑
|
||||
- 含生成的话语在 auto_read 不落盘
|
||||
- QueryGuard 拒绝 `task.run`
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
内存账本 + FakeActionOwner;默认环境仍 legacy。不 rebuild `:8080`。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
legacy 无回归;auto_read 查询可完成;写动作 fail closed。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 HandleTurn
|
||||
|
||||
- **测试输入**:`go test ./internal/app/intentflow -run 'TestHandleTurn'`
|
||||
- **实际输出**:`TestHandleTurnLegacyDoesNotPersist`、`TestHandleTurnAutoReadPersistsAndExecutesQueries`、`TestHandleTurnWriteUtteranceStaysLegacyUnderAutoRead` PASS。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:5ms
|
||||
|
||||
### 5.2 QueryGuard / chat / arch
|
||||
|
||||
- **测试输入**:`go test -short ./internal/app/intentflow ./internal/chat ./internal/archtest ./internal/server`
|
||||
- **实际输出**:PASS。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:约 11s(含 server)
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go test ./internal/app/intentflow ./internal/chat ./internal/archtest` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | 待合入前再跑 |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U7 达到合入标准。U8 再接 `task.run` / `task.run.adhoc`;真实 PI 若环境缺失则记 stop-gate。
|
||||
@@ -0,0 +1,75 @@
|
||||
# 多意图 HITL U8 task generate adapter 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
U7 只在 `auto_read` 执行独立查询,`QueryGuard` 拒绝 `task.run`。U8 要在 `confirm` tier 把「查询+生成」落成 awaiting 写计划,确认后经 `OwnerMux` 只开放 `task.run` / `task.run.adhoc`,并用稳定幂等键避免双跑。默认 `MULTI_INTENT_PLAN_TIER=legacy` 仍不得落盘。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- confirm 话语确认前零 generate 副作用
|
||||
- 同 scope 第二活动写计划冲突
|
||||
- 确认后 mux 执行 generate,重放 `StartCount=1`
|
||||
- QueryGuard 继续拒绝 generate;adapter 拒绝查询 key;撤销 Denied fail closed
|
||||
- `LiveTaskStarter` 同幂等键重放
|
||||
- 无 `PI_AGENT_RUNNER_URL` 时真实 PI 记 stop-gate(SKIP,不冒充验收)
|
||||
- arch-check / `-short` 相关包绿
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| 分支 | `feature/multi-intent-u8-task-generate` |
|
||||
| OS | linux |
|
||||
| 账本 | 内存 `SerialUoW` + `MemoryStore` |
|
||||
| Owner | `OwnerMux{Query: QueryGuard{Fake}, Task: TaskRunAdapter}` |
|
||||
| 真实 PI | `PI_AGENT_RUNNER_URL` 未设置 → SKIP |
|
||||
| 共享环境 | 不 rebuild `:8080`;项目 143 只读 |
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 用例 | 预期 |
|
||||
|------|------|
|
||||
| legacy / auto_read 写话语 | 不落盘 |
|
||||
| confirm + 「查一下相关法规,然后帮我生成报价单」 | awaiting,步骤 pending |
|
||||
| 第二 ClientTurn 同 scope | `PLAN_DECISION_CONFLICT` |
|
||||
| 确认 + AdvanceEligible | generate starts=1;再推进仍为 1 |
|
||||
| QueryGuard `task.run` | `PLAN_ACTION_FORBIDDEN` |
|
||||
| 真实 PI | 无 URL 则 SKIP |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 HandleTurn confirm
|
||||
|
||||
- **测试输入**:`go test ./internal/app/intentflow -run 'TestHandleTurn|TestOwnerMux|TestQueryGuard' -count=1 -v`
|
||||
- **实际输出**:`TestHandleTurnConfirmPersistsAwaitingWithoutExecute`、`TestHandleTurnConfirmRejectsSecondActiveWritePlan`、`TestHandleTurnWriteUtteranceStaysLegacyUnderAutoRead`、`TestQueryGuardRejectsGenerate`、`TestOwnerMux*` PASS。完整日志:[assets/2026-09-16-multi-intent-u8-task-generate/intentflow.txt](./assets/2026-09-16-multi-intent-u8-task-generate/intentflow.txt)
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:8ms
|
||||
|
||||
### 5.2 Adapter / mux 闭环
|
||||
|
||||
- **测试输入**:`go test ./internal/app -run 'TestTask|TestConfirmThenMux|TestLiveTask' -count=1 -v`
|
||||
- **实际输出**:`TestConfirmThenMuxExecutesGenerateOnce` PASS(确认前 starts=0,确认后 starts=1);`TestTaskRunAdapterIdempotentExecute` / `RejectsQueryKey` / `DeniedAfterRevoke` / `TestLiveTaskStarterReplaysIdempotencyKey` PASS;`TestTaskGenerateRealPIStopGate` SKIP(`PI_AGENT_RUNNER_URL` 未设置)。日志:[assets/2026-09-16-multi-intent-u8-task-generate/app-adapter.txt](./assets/2026-09-16-multi-intent-u8-task-generate/app-adapter.txt)
|
||||
- **评价判定**:PASS(真实 PI 为 stop-gate,不计入首版冒充验收)。
|
||||
- **性能与耗时**:5ms
|
||||
|
||||
### 5.3 回归与边界
|
||||
|
||||
- **测试输入**:`go test -short ./internal/app/intentflow ./internal/app ./internal/archtest ./internal/chat ./internal/server ./internal/taskrun`;`./scripts/arch-check.sh --mode block`
|
||||
- **实际输出**:全部 ok;`arch-check block: production gate passed`。
|
||||
- **评价判定**:PASS。
|
||||
- **性能与耗时**:约 13s(含 server)
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|------|------|
|
||||
| `go test ./internal/app/intentflow ./internal/app ./internal/archtest` | PASS |
|
||||
| `go test -short ./internal/chat ./internal/server ./internal/taskrun` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
| `TestTaskGenerateRealPIStopGate` | SKIP(无 `PI_AGENT_RUNNER_URL`) |
|
||||
|
||||
未跑 `go test ./internal/chat` 无 `-short`:既有 `TestChatSession_SemanticMemoryRecallAndAsyncTurnRecord` flake,与 U8 无关。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
U8 达到合入标准:核心首版 U1–U8 在默认 legacy 零行为、confirm 确认后只开放 generate adapter 的前提下可关闭。U9–U12 不阻塞首版。真实 PI 生成闭环仍待 `PI_AGENT_RUNNER_URL` 窗口;共享环境 schema 仍为 43,goose 45 待晋升窗口,本单元不 rebuild。
|
||||
@@ -0,0 +1,60 @@
|
||||
# 真实 PI 三工作流治理 E2E 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
发布门禁要求非 stub 的真实 PI Agent 三正式工作流治理 E2E。此前 stub/short 已绿;本轮在隔离 PG + 共享 `data/dev/workspaces` 挂载 + MiniMax-M2.7-highspeed runner 上闭环。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- `main` / `product_manager` / `test_manager` 各一条:创建→规划→激活→真实 pi-agent 编制→批准→推进
|
||||
- 通过率 100%;记录耗时
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS: Linux;Go test `./internal/server -run TestWorkflowGovernance_PiAgent_PG_`
|
||||
- PG:`127.0.0.1:5434/agent_pi_e2e`(隔离,非 shared env 库名)
|
||||
- Runner:`http://127.0.0.1:18865`,model `MiniMax-M2.7-highspeed`
|
||||
- `DATA_DIR=/…/data/dev`(与容器 `/app/data/workspaces` 绑定)
|
||||
- 修复:duty 成员 upsert;outbox 后不再强制同步通知;pi-agent `umask 000`;`MaterializeTargets` chmod 后再写
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
三用例均 PASS;artifact 由真实 runner 生成。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:main + intake
|
||||
|
||||
- **输入**: `TestWorkflowGovernance_PiAgent_PG_FullChain`
|
||||
- **实际输出**(摘自 `assets/2026-09-16-pi-three-workflow-e2e/go-test.txt`):
|
||||
```
|
||||
✓ [3. pi-agent intake] doc=doc_proj6011_intake title=用户初始需求收集表 elapsed=3m29s
|
||||
✓ [5. 阶段推进] … wf=main
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullChain (210.64s)
|
||||
```
|
||||
- **判定**: PASS
|
||||
|
||||
### 用例 2:product_manager + system_reqs
|
||||
|
||||
- **输入**: `TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain`
|
||||
- **实际输出**: `--- PASS: … (670.20s)`
|
||||
- **判定**: PASS
|
||||
|
||||
### 用例 3:test_manager + test_manager
|
||||
|
||||
- **输入**: `TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain`
|
||||
- **实际输出**: `--- PASS: … (815.44s)`
|
||||
- **判定**: PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
```text
|
||||
go test ./internal/server -run 'TestWorkflowGovernance_PiAgent_PG_' → 3 PASS / EXIT 0
|
||||
总墙钟约 28.3 min(210+670+815s)
|
||||
证据:.doc/test-reports/assets/2026-09-16-pi-three-workflow-e2e/go-test.txt
|
||||
```
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- 发布门禁「真实 PI Agent 三工作流治理 E2E」可 ☑。
|
||||
- 建议 CI 以 `RUN_PI_E2E=1` + secret token 夜间跑,避免阻塞每次 PR。
|
||||
@@ -207,6 +207,18 @@ def main():
|
||||
n_win2 = n_cat2 = 0
|
||||
texts2 = []
|
||||
if default_s == 200 and isinstance(plan, dict):
|
||||
# Duty holders must be active project members before SavePlan.
|
||||
for uid, role in (
|
||||
(owner_id, "owner"),
|
||||
(reviewer_id, "member"),
|
||||
(approver_id, "member"),
|
||||
):
|
||||
req(
|
||||
"POST",
|
||||
f"/api/v1/projects/{project_id}/members",
|
||||
owner_token,
|
||||
{"user_id": uid, "project_role": role},
|
||||
)
|
||||
stages = plan.get("stages") or []
|
||||
for stg in stages:
|
||||
for dt in stg.get("doc_tasks") or []:
|
||||
@@ -220,6 +232,8 @@ def main():
|
||||
"expected_plan_revision": 0,
|
||||
"expected_selection_version": 1,
|
||||
})
|
||||
if save_s != 200:
|
||||
task_out["save_err"] = err_snip(None, save_raw)
|
||||
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, {
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 2.374s
|
||||
? 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/eventmode [no test files]
|
||||
? chat-agent-system/cmd/events [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 3.653s
|
||||
ok chat-agent-system/internal/app 0.016s
|
||||
ok chat-agent-system/internal/app/chatflow 0.005s
|
||||
ok chat-agent-system/internal/app/docadvance 0.003s
|
||||
ok chat-agent-system/internal/app/docflow 0.004s
|
||||
ok chat-agent-system/internal/app/docnotify 0.004s
|
||||
ok chat-agent-system/internal/app/docproject 0.004s
|
||||
ok chat-agent-system/internal/app/intentflow 0.002s
|
||||
ok chat-agent-system/internal/app/stageflow 0.004s
|
||||
ok chat-agent-system/internal/app/uow 0.004s
|
||||
ok chat-agent-system/internal/archtest 0.172s
|
||||
ok chat-agent-system/internal/artifactvault 0.004s
|
||||
ok chat-agent-system/internal/auth 0.821s
|
||||
ok chat-agent-system/internal/authz 0.004s
|
||||
ok chat-agent-system/internal/bizdev 0.165s
|
||||
ok chat-agent-system/internal/chat 0.014s
|
||||
ok chat-agent-system/internal/config 0.002s
|
||||
ok chat-agent-system/internal/coordinator 0.010s
|
||||
ok chat-agent-system/internal/ctxmgr 0.083s
|
||||
ok chat-agent-system/internal/dataset 0.003s
|
||||
ok chat-agent-system/internal/db 0.003s
|
||||
ok chat-agent-system/internal/doccontent 0.002s
|
||||
ok chat-agent-system/internal/docduty 0.005s
|
||||
ok chat-agent-system/internal/docgov 0.016s
|
||||
ok chat-agent-system/internal/docquery 0.003s
|
||||
ok chat-agent-system/internal/docrevision 0.007s
|
||||
ok chat-agent-system/internal/events 0.005s
|
||||
ok chat-agent-system/internal/freedoc 0.023s
|
||||
ok chat-agent-system/internal/fsutil 0.002s
|
||||
ok chat-agent-system/internal/httpx 0.003s
|
||||
ok chat-agent-system/internal/intent 0.011s
|
||||
ok chat-agent-system/internal/kb 0.005s
|
||||
ok chat-agent-system/internal/maturity 0.002s
|
||||
ok chat-agent-system/internal/notification 0.068s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.004s
|
||||
ok chat-agent-system/internal/projectinstance 0.004s
|
||||
ok chat-agent-system/internal/projectworkflow 0.003s
|
||||
ok chat-agent-system/internal/quote 0.007s
|
||||
ok chat-agent-system/internal/replyexport 0.002s
|
||||
ok chat-agent-system/internal/server 9.920s
|
||||
ok chat-agent-system/internal/squad 0.030s
|
||||
ok chat-agent-system/internal/storage 0.016s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/stream/transport 0.002s
|
||||
ok chat-agent-system/internal/taskrun 0.142s
|
||||
ok chat-agent-system/internal/template 0.785s
|
||||
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]
|
||||
@@ -0,0 +1,4 @@
|
||||
ok chat-agent-system/internal/app/intentflow 0.002s
|
||||
ok chat-agent-system/internal/events 0.004s
|
||||
ok chat-agent-system/internal/archtest 0.161s
|
||||
ok chat-agent-system/internal/intent 0.010s
|
||||
@@ -0,0 +1,104 @@
|
||||
=== RUN TestLegacyIntentPlan_WriteComboStillDropped
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestLegacyIntentPlan_WriteComboStillDropped (0.00s)
|
||||
=== RUN TestLegacyIntentPlan_NoConnectorStaysSingle
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
--- PASS: TestLegacyIntentPlan_NoConnectorStaysSingle (0.00s)
|
||||
=== RUN TestSplitPlanSegments_ConnectorAndNumbered
|
||||
--- PASS: TestSplitPlanSegments_ConnectorAndNumbered (0.00s)
|
||||
=== RUN TestSplitPlanSegments_PeriodAndSemicolon
|
||||
--- PASS: TestSplitPlanSegments_PeriodAndSemicolon (0.00s)
|
||||
=== RUN TestSplitPlanSegments_InternalChainNotSplit
|
||||
--- PASS: TestSplitPlanSegments_InternalChainNotSplit (0.00s)
|
||||
=== RUN TestSplitPlanSegments_FirstThenFinally
|
||||
--- PASS: TestSplitPlanSegments_FirstThenFinally (0.00s)
|
||||
=== RUN TestSplitPlanSegments_FiveNumberedKeptIntact
|
||||
--- PASS: TestSplitPlanSegments_FiveNumberedKeptIntact (0.00s)
|
||||
=== RUN TestPlanProposal_WriteNotDroppedAndLegacyUnchanged
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestPlanProposal_WriteNotDroppedAndLegacyUnchanged (0.00s)
|
||||
=== RUN TestPlanProposal_QueryPairAutoReadCandidate
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
--- PASS: TestPlanProposal_QueryPairAutoReadCandidate (0.00s)
|
||||
=== RUN TestPlanProposal_AnaphoraClarify
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
--- PASS: TestPlanProposal_AnaphoraClarify (0.00s)
|
||||
=== RUN TestPlanProposal_SecurityRejectsWhole
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=SECURITY_FORBIDDEN branch=NEW_INTENT_PREEMPT confidence=1
|
||||
--- PASS: TestPlanProposal_SecurityRejectsWhole (0.00s)
|
||||
=== RUN TestPlanProposal_BatchSizeRejected
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
--- PASS: TestPlanProposal_BatchSizeRejected (0.00s)
|
||||
=== RUN TestPlanProposal_DigestStable
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
--- PASS: TestPlanProposal_DigestStable (0.00s)
|
||||
=== RUN TestPlanProposalEvalGolden
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=SECURITY_FORBIDDEN branch=NEW_INTENT_PREEMPT confidence=1
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_SIMILAR_CASES branch=NEW_INTENT_PREEMPT confidence=0.92
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_SIMILAR_CASES branch=NEW_INTENT_PREEMPT confidence=0.92
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
proposal_test.go:221: plan-proposal eval denom=8 false_auto_execute=0
|
||||
--- PASS: TestPlanProposalEvalGolden (0.00s)
|
||||
=== RUN TestPlanProposal_HardNegativeNoFalseAutoExecute
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=SECURITY_FORBIDDEN branch=NEW_INTENT_PREEMPT confidence=1
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_USER_RIGHTS branch=NEW_INTENT_PREEMPT confidence=0.95
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/15 23:15:06 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
--- PASS: TestPlanProposal_HardNegativeNoFalseAutoExecute (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/intent 0.012s
|
||||
@@ -0,0 +1,61 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 1.901s
|
||||
? chat-agent-system/cmd/dataset [no test files]
|
||||
ok chat-agent-system/cmd/document-content-reconcile 0.006s
|
||||
? chat-agent-system/cmd/document-revision-backfill [no test files]
|
||||
? chat-agent-system/cmd/eventmode [no test files]
|
||||
? chat-agent-system/cmd/events [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 3.162s
|
||||
ok chat-agent-system/internal/app 0.017s
|
||||
ok chat-agent-system/internal/app/chatflow 0.004s
|
||||
ok chat-agent-system/internal/app/docadvance 0.006s
|
||||
ok chat-agent-system/internal/app/docflow 0.003s
|
||||
ok chat-agent-system/internal/app/docnotify 0.003s
|
||||
ok chat-agent-system/internal/app/docproject 0.002s
|
||||
ok chat-agent-system/internal/app/intentflow 0.002s
|
||||
ok chat-agent-system/internal/app/stageflow 0.010s
|
||||
ok chat-agent-system/internal/app/uow 0.003s
|
||||
ok chat-agent-system/internal/archtest 0.230s
|
||||
ok chat-agent-system/internal/artifactvault 0.005s
|
||||
ok chat-agent-system/internal/auth 0.837s
|
||||
ok chat-agent-system/internal/authz 0.004s
|
||||
ok chat-agent-system/internal/bizdev 0.185s
|
||||
ok chat-agent-system/internal/chat 0.027s
|
||||
ok chat-agent-system/internal/config 0.002s
|
||||
ok chat-agent-system/internal/coordinator 0.015s
|
||||
ok chat-agent-system/internal/ctxmgr 0.100s
|
||||
ok chat-agent-system/internal/dataset 0.010s
|
||||
ok chat-agent-system/internal/db 0.004s
|
||||
ok chat-agent-system/internal/doccontent 0.003s
|
||||
ok chat-agent-system/internal/docduty 0.010s
|
||||
ok chat-agent-system/internal/docgov 0.022s
|
||||
ok chat-agent-system/internal/docquery 0.010s
|
||||
ok chat-agent-system/internal/docrevision 0.012s
|
||||
ok chat-agent-system/internal/events 0.010s
|
||||
ok chat-agent-system/internal/freedoc 0.031s
|
||||
ok chat-agent-system/internal/fsutil 0.002s
|
||||
ok chat-agent-system/internal/httpx 0.012s
|
||||
ok chat-agent-system/internal/intent 0.039s
|
||||
ok chat-agent-system/internal/kb 0.015s
|
||||
ok chat-agent-system/internal/maturity 0.002s
|
||||
ok chat-agent-system/internal/notification 0.093s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.007s
|
||||
ok chat-agent-system/internal/projectinstance 0.005s
|
||||
ok chat-agent-system/internal/projectworkflow 0.002s
|
||||
ok chat-agent-system/internal/quote 0.009s
|
||||
ok chat-agent-system/internal/replyexport 0.002s
|
||||
ok chat-agent-system/internal/server 9.687s
|
||||
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/stream/transport 0.002s
|
||||
ok chat-agent-system/internal/taskrun 0.145s
|
||||
ok chat-agent-system/internal/template 0.776s
|
||||
ok chat-agent-system/internal/upload 0.003s
|
||||
? chat-agent-system/internal/workflow [no test files]
|
||||
ok chat-agent-system/internal/workflow/runtime 0.002s
|
||||
ok chat-agent-system/internal/workflowdef 0.003s
|
||||
ok chat-agent-system/internal/workspace 0.003s
|
||||
? chat-agent-system/templates [no test files]
|
||||
@@ -0,0 +1,5 @@
|
||||
ok chat-agent-system/internal/intent 0.018s
|
||||
ok chat-agent-system/internal/coordinator 0.009s
|
||||
ok chat-agent-system/internal/chat 0.013s
|
||||
ok chat-agent-system/internal/archtest 0.163s
|
||||
ok chat-agent-system/internal/app/intentflow 0.002s
|
||||
@@ -0,0 +1,20 @@
|
||||
=== RUN TestHandleTurnLegacyDoesNotPersist
|
||||
--- PASS: TestHandleTurnLegacyDoesNotPersist (0.00s)
|
||||
=== RUN TestCreateIdempotentSameDigest
|
||||
--- PASS: TestCreateIdempotentSameDigest (0.00s)
|
||||
=== RUN TestCreateRejectsSecondActiveWritePlan
|
||||
--- PASS: TestCreateRejectsSecondActiveWritePlan (0.00s)
|
||||
=== RUN TestDecisionNonceSameAndDifferentDigest
|
||||
--- PASS: TestDecisionNonceSameAndDifferentDigest (0.00s)
|
||||
=== RUN TestConfirmCancelRaceOneWinner
|
||||
--- PASS: TestConfirmCancelRaceOneWinner (0.00s)
|
||||
=== RUN TestTwoWorkersOneOwnerAndLeaseTakeover
|
||||
--- PASS: TestTwoWorkersOneOwnerAndLeaseTakeover (0.00s)
|
||||
=== RUN TestReceiptWritebackFailureDoesNotRerun
|
||||
--- PASS: TestReceiptWritebackFailureDoesNotRerun (0.00s)
|
||||
=== RUN TestExpireAndEnvironmentIsolationAndRetention
|
||||
--- PASS: TestExpireAndEnvironmentIsolationAndRetention (0.00s)
|
||||
=== RUN TestUnauthenticatedRejected
|
||||
--- PASS: TestUnauthenticatedRejected (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/app/intentflow 0.005s
|
||||
@@ -0,0 +1,61 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 1.946s
|
||||
? chat-agent-system/cmd/dataset [no test files]
|
||||
ok chat-agent-system/cmd/document-content-reconcile 0.002s
|
||||
? chat-agent-system/cmd/document-revision-backfill [no test files]
|
||||
? chat-agent-system/cmd/eventmode [no test files]
|
||||
? chat-agent-system/cmd/events [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 3.163s
|
||||
ok chat-agent-system/internal/app 0.015s
|
||||
ok chat-agent-system/internal/app/chatflow 0.007s
|
||||
ok chat-agent-system/internal/app/docadvance 0.005s
|
||||
ok chat-agent-system/internal/app/docflow 0.005s
|
||||
ok chat-agent-system/internal/app/docnotify 0.005s
|
||||
ok chat-agent-system/internal/app/docproject 0.005s
|
||||
ok chat-agent-system/internal/app/intentflow 0.005s
|
||||
ok chat-agent-system/internal/app/stageflow 0.005s
|
||||
ok chat-agent-system/internal/app/uow 0.006s
|
||||
ok chat-agent-system/internal/archtest 0.200s
|
||||
ok chat-agent-system/internal/artifactvault 0.007s
|
||||
ok chat-agent-system/internal/auth 0.840s
|
||||
ok chat-agent-system/internal/authz 0.004s
|
||||
ok chat-agent-system/internal/bizdev 0.169s
|
||||
ok chat-agent-system/internal/chat 0.018s
|
||||
ok chat-agent-system/internal/config 0.004s
|
||||
ok chat-agent-system/internal/coordinator 0.013s
|
||||
ok chat-agent-system/internal/ctxmgr 0.096s
|
||||
ok chat-agent-system/internal/dataset 0.005s
|
||||
ok chat-agent-system/internal/db 0.005s
|
||||
ok chat-agent-system/internal/doccontent 0.002s
|
||||
ok chat-agent-system/internal/docduty 0.005s
|
||||
ok chat-agent-system/internal/docgov 0.020s
|
||||
ok chat-agent-system/internal/docquery 0.005s
|
||||
ok chat-agent-system/internal/docrevision 0.007s
|
||||
ok chat-agent-system/internal/events 0.007s
|
||||
ok chat-agent-system/internal/freedoc 0.029s
|
||||
ok chat-agent-system/internal/fsutil 0.005s
|
||||
ok chat-agent-system/internal/httpx 0.005s
|
||||
ok chat-agent-system/internal/intent 0.029s
|
||||
ok chat-agent-system/internal/kb 0.008s
|
||||
ok chat-agent-system/internal/maturity 0.004s
|
||||
ok chat-agent-system/internal/notification 0.083s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.007s
|
||||
ok chat-agent-system/internal/projectinstance 0.007s
|
||||
ok chat-agent-system/internal/projectworkflow 0.006s
|
||||
ok chat-agent-system/internal/quote 0.009s
|
||||
ok chat-agent-system/internal/replyexport 0.002s
|
||||
ok chat-agent-system/internal/server 9.896s
|
||||
ok chat-agent-system/internal/squad 0.030s
|
||||
ok chat-agent-system/internal/storage 0.015s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/stream/transport 0.002s
|
||||
ok chat-agent-system/internal/taskrun 0.146s
|
||||
ok chat-agent-system/internal/template 0.721s
|
||||
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]
|
||||
@@ -0,0 +1,6 @@
|
||||
ok chat-agent-system/internal/app/intentflow 0.003s
|
||||
ok chat-agent-system/internal/app 0.013s
|
||||
ok chat-agent-system/internal/db 0.002s
|
||||
ok chat-agent-system/internal/archtest 0.157s
|
||||
ok chat-agent-system/internal/intent 0.017s
|
||||
ok chat-agent-system/internal/coordinator 0.009s
|
||||
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"started": "2026-09-16T04:06:01.057297",
|
||||
"base": "http://127.0.0.1:8080",
|
||||
"project_id": 6359,
|
||||
"session_id": "sess-p6359-u10",
|
||||
"duration_ms": 485193,
|
||||
"cases": [
|
||||
{
|
||||
"id": "health",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 6,
|
||||
"output": {
|
||||
"health_status": "ok",
|
||||
"agent_backend": "pi-agent",
|
||||
"schema_version": 47,
|
||||
"ready": "ok"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "login",
|
||||
"verdict": "PASS",
|
||||
"duration_ms": 59,
|
||||
"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": 6359,
|
||||
"lifecycle": "planning"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "real_pi_chat",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 4150,
|
||||
"output": {
|
||||
"reply_excerpt": "完全理解您想再掂量一下。针对「U10刷新活验-035755」目前的节点,我帮您快速对照一下:\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": 3,
|
||||
"output": {
|
||||
"auth_me_http": 200,
|
||||
"window_msgs": 2,
|
||||
"category_total": 2,
|
||||
"samples": [
|
||||
[
|
||||
"user",
|
||||
"先记录一下:本项目是超声软组织吸引设备立项摸底,请用一两句话确认你已记住设备类型"
|
||||
],
|
||||
[
|
||||
"assistant",
|
||||
"完全理解您想再掂量一下。针对「U10刷新活验-035755」目前的节点,我帮您快"
|
||||
]
|
||||
],
|
||||
"cat_http": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "guest_403",
|
||||
"verdict": "PASS",
|
||||
"http": 403,
|
||||
"duration_ms": 0,
|
||||
"output": {
|
||||
"error_code": "SESSION_FORBIDDEN"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "pi_task_refresh",
|
||||
"verdict": "PASS",
|
||||
"output": {
|
||||
"default_http": 200,
|
||||
"save_http": 200,
|
||||
"preview_http": 200,
|
||||
"activate_http": 200,
|
||||
"run_http": 202,
|
||||
"run_id": "run_1789531080321650206",
|
||||
"run_status": null,
|
||||
"poll_ms": 480691,
|
||||
"window_http": 200,
|
||||
"window_msgs": 4,
|
||||
"category_total": 4,
|
||||
"samples": [
|
||||
[
|
||||
"user",
|
||||
"先记录一下:本项目是超声软组织吸引设备立项摸底,请用一两句话确认你已记住设备类型"
|
||||
],
|
||||
[
|
||||
"assistant",
|
||||
"完全理解您想再掂量一下。针对「U10刷新活验-035755」目前的节点,我帮您快"
|
||||
],
|
||||
[
|
||||
"user",
|
||||
"请基于本项目编制首轮《用户需求》摸底文档,控制在较短篇幅。"
|
||||
],
|
||||
[
|
||||
"assistant",
|
||||
"任务执行中…"
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"core_overall": "PASS",
|
||||
"overall": "PASS"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"session": "sess-p6359-u10",
|
||||
"before": 4,
|
||||
"after": 4,
|
||||
"verdict": "PASS"
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"started": "2026-09-16T04:10:02",
|
||||
"base": "http://127.0.0.1:8080",
|
||||
"project_id": 6363,
|
||||
"overall": "PASS",
|
||||
"cases": [
|
||||
{
|
||||
"id": "login",
|
||||
"verdict": "PASS",
|
||||
"output": {
|
||||
"owner_id": 10,
|
||||
"reviewer_id": 11,
|
||||
"approver_id": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "create_project",
|
||||
"verdict": "PASS",
|
||||
"http": 201,
|
||||
"output": {
|
||||
"project_id": 6363
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save_plan",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 4
|
||||
},
|
||||
{
|
||||
"id": "version_conflict_409",
|
||||
"verdict": "PASS",
|
||||
"http": 409,
|
||||
"duration_ms": 0,
|
||||
"output": {
|
||||
"business_code": "ERR_CONCURRENT_SWITCH",
|
||||
"envelope_code": "VERSION_CONFLICT",
|
||||
"frontend_recovery": "retry_after_switch",
|
||||
"message": "资源版本冲突"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "activate",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 2
|
||||
},
|
||||
{
|
||||
"id": "termination_preview",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 1,
|
||||
"output": {
|
||||
"instance_id": 259,
|
||||
"can_terminate": true,
|
||||
"keys": [
|
||||
"instance_id",
|
||||
"pending_documents",
|
||||
"in_progress_task_runs",
|
||||
"can_terminate",
|
||||
"impact"
|
||||
],
|
||||
"pending_documents": [
|
||||
{
|
||||
"task_key": "intake",
|
||||
"status": "pending",
|
||||
"stage_key": "V0.1_triage"
|
||||
}
|
||||
],
|
||||
"in_progress_task_runs": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "post_activate_freeze_refresh",
|
||||
"verdict": "PASS",
|
||||
"http": 409,
|
||||
"duration_ms": 0,
|
||||
"output": {
|
||||
"business_code": "PLAN_FROZEN",
|
||||
"frontend_recovery": "refresh_and_freeze"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
▶ projectSettingsError
|
||||
✔ keeps status, code, message and issues on PLAN_FROZEN (1.02158ms)
|
||||
✔ maps revision and concurrent conflicts to distinct recovery (0.093647ms)
|
||||
✔ joins validation issues but still keeps typed codes (0.099887ms)
|
||||
✔ prefers envelope code over legacy error field (0.062248ms)
|
||||
✔ unwraps nested business JSON inside VERSION_CONFLICT envelope (0.101087ms)
|
||||
✔ maps bare VERSION_CONFLICT envelope to retry_after_switch (0.055168ms)
|
||||
✔ retains the local draft when a late tab hits PLAN_FROZEN (0.058419ms)
|
||||
✔ projectSettingsError (2.318142ms)
|
||||
ℹ tests 7
|
||||
ℹ suites 1
|
||||
ℹ pass 7
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 146.621456
|
||||
@@ -0,0 +1,6 @@
|
||||
arch-check mode=block
|
||||
boundaries=/home/weichen/projects/Agent-System/.doc/system-design/module-boundaries.yaml
|
||||
ok chat-agent-system/internal/archtest 0.138s
|
||||
ok chat-agent-system/internal/archtest 0.134s
|
||||
arch-check block: production gate passed
|
||||
arch_exit=0
|
||||
@@ -0,0 +1,139 @@
|
||||
Building fresh web dist (demo seeds OFF)...
|
||||
|
||||
> shuimu-workbench@1.0.0 build
|
||||
> tsc && vite build
|
||||
|
||||
vite v7.3.6 building client environment for production...
|
||||
transforming...
|
||||
✓ 4112 modules transformed.
|
||||
rendering chunks...
|
||||
computing gzip size...
|
||||
dist/index.html 0.89 kB │ gzip: 0.52 kB
|
||||
dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff 4.42 kB
|
||||
dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 4.93 kB
|
||||
dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 5.21 kB
|
||||
dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 5.47 kB
|
||||
dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff 5.98 kB
|
||||
dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff 6.19 kB
|
||||
dist/assets/KaTeX_Size1-Regular-C195tn64.woff 6.50 kB
|
||||
dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 6.91 kB
|
||||
dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 6.91 kB
|
||||
dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf 7.59 kB
|
||||
dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff 7.66 kB
|
||||
dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff 7.72 kB
|
||||
dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 9.64 kB
|
||||
dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 10.34 kB
|
||||
dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf 10.36 kB
|
||||
dist/assets/KaTeX_Script-Regular-D5yQViql.woff 10.59 kB
|
||||
dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 11.32 kB
|
||||
dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 11.35 kB
|
||||
dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf 11.51 kB
|
||||
dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 12.03 kB
|
||||
dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 12.22 kB
|
||||
dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf 12.23 kB
|
||||
dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff 12.32 kB
|
||||
dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf 12.34 kB
|
||||
dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf 12.37 kB
|
||||
dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff 13.21 kB
|
||||
dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff 13.30 kB
|
||||
dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 13.57 kB
|
||||
dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff 14.11 kB
|
||||
dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff 14.41 kB
|
||||
dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff 16.03 kB
|
||||
dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 16.40 kB
|
||||
dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 16.44 kB
|
||||
dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf 16.65 kB
|
||||
dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 16.78 kB
|
||||
dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 16.99 kB
|
||||
dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff 18.67 kB
|
||||
dist/assets/KaTeX_Math-Italic-DA0__PXp.woff 18.75 kB
|
||||
dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff 19.41 kB
|
||||
dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf 19.44 kB
|
||||
dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf 19.57 kB
|
||||
dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf 19.58 kB
|
||||
dist/assets/KaTeX_Main-Italic-BMLOBm91.woff 19.68 kB
|
||||
dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf 22.36 kB
|
||||
dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf 24.50 kB
|
||||
dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 25.32 kB
|
||||
dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 26.27 kB
|
||||
dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf 27.56 kB
|
||||
dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 28.08 kB
|
||||
dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff 29.91 kB
|
||||
dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff 30.77 kB
|
||||
dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf 31.20 kB
|
||||
dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf 31.31 kB
|
||||
dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf 32.97 kB
|
||||
dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff 33.52 kB
|
||||
dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf 33.58 kB
|
||||
dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf 51.34 kB
|
||||
dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf 53.58 kB
|
||||
dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf 63.63 kB
|
||||
dist/assets/index-DhpBfxvE.css 35.50 kB │ gzip: 9.76 kB
|
||||
dist/assets/channel-YUCiLyJ5.js 0.11 kB │ gzip: 0.12 kB
|
||||
dist/assets/init-Gi6I4Gst.js 0.15 kB │ gzip: 0.13 kB
|
||||
dist/assets/chunk-2Q5K7J3B-Cp_1aGcV.js 0.19 kB │ gzip: 0.16 kB
|
||||
dist/assets/chunk-JWPE2WC7-CFAlzDTt.js 0.22 kB │ gzip: 0.17 kB
|
||||
dist/assets/chunk-XXDRQBXY-B1wR5UIw.js 0.22 kB │ gzip: 0.20 kB
|
||||
dist/assets/chunk-5VM5RSS4-C1TvNbDe.js 0.36 kB │ gzip: 0.27 kB
|
||||
dist/assets/stateDiagram-v2-MP3YSRHH-3fUIqYL7.js 0.39 kB │ gzip: 0.29 kB
|
||||
dist/assets/classDiagram-ZZMXUADV-BWt18f7X.js 0.43 kB │ gzip: 0.30 kB
|
||||
dist/assets/classDiagram-v2-VYDZK3BY-BWt18f7X.js 0.43 kB │ gzip: 0.30 kB
|
||||
dist/assets/chunk-POPQ4Y6H-LoS5Tfde.js 0.50 kB │ gzip: 0.35 kB
|
||||
dist/assets/swimlanesDiagram-VR7AAH4N-Dj72rso7.js 0.51 kB │ gzip: 0.35 kB
|
||||
dist/assets/infoDiagram-27XIBGKW-DCaRHXpS.js 0.55 kB │ gzip: 0.38 kB
|
||||
dist/assets/sizeCapture-INFHLROL-WvhY4LXO.js 0.90 kB │ gzip: 0.51 kB
|
||||
dist/assets/ordinal-Cboi1Yqb.js 1.19 kB │ gzip: 0.57 kB
|
||||
dist/assets/railroadDiagram-O6MQD6OU-BKky8rBB.js 1.57 kB │ gzip: 0.74 kB
|
||||
dist/assets/abnfDiagram-VCTEODGH-DH9p93NG.js 1.77 kB │ gzip: 0.87 kB
|
||||
dist/assets/chunk-F27PBJKO-yW3jT8qq.js 1.88 kB │ gzip: 0.83 kB
|
||||
dist/assets/pegDiagram-XKGWAZYB-CF4TQ3Dl.js 1.92 kB │ gzip: 0.90 kB
|
||||
dist/assets/ebnfDiagram-PWID7BFC-XoOoOoe6.js 1.97 kB │ gzip: 0.86 kB
|
||||
dist/assets/arc-D3bCILD0.js 3.43 kB │ gzip: 1.48 kB
|
||||
dist/assets/diagram-Z3DM3KII-B_ADGUY4.js 4.18 kB │ gzip: 1.81 kB
|
||||
dist/assets/defaultLocale-DX6XiGOO.js 4.69 kB │ gzip: 2.18 kB
|
||||
dist/assets/linear-Cf6ZEJ9k.js 5.65 kB │ gzip: 2.31 kB
|
||||
dist/assets/diagram-UQ7AKVKN-Dq_uUgpS.js 6.04 kB │ gzip: 2.60 kB
|
||||
dist/assets/pieDiagram-E7YTZNPT-Btb_v7CU.js 6.26 kB │ gzip: 2.60 kB
|
||||
dist/assets/diagram-S7CK7UJ4-D1xFKY8l.js 8.18 kB │ gzip: 3.66 kB
|
||||
dist/assets/cynefinDiagram-5FMLGOSQ-CduADy4V.js 10.06 kB │ gzip: 3.61 kB
|
||||
dist/assets/stateDiagram-D77RDMKH-BxhdNYdS.js 10.33 kB │ gzip: 3.61 kB
|
||||
dist/assets/dagre-GXQ25YYZ-D9RgBJh-.js 10.64 kB │ gzip: 4.01 kB
|
||||
dist/assets/diagram-VSXAHHWV-COisjeqg.js 10.68 kB │ gzip: 4.11 kB
|
||||
dist/assets/chunk-SVP7TREG-BQ76_pRe.js 15.73 kB │ gzip: 4.41 kB
|
||||
dist/assets/diagram-VX7I27RA-DL_ZhhnY.js 15.92 kB │ gzip: 5.68 kB
|
||||
dist/assets/ishikawaDiagram-5VMMS53U-X2RWjgnx.js 17.43 kB │ gzip: 6.62 kB
|
||||
dist/assets/kanban-definition-UXKFOSKX-CZ5ioKdv.js 20.26 kB │ gzip: 7.18 kB
|
||||
dist/assets/mindmap-definition-YA3MSWOX-DTTTfydG.js 23.14 kB │ gzip: 7.80 kB
|
||||
dist/assets/sankeyDiagram-P5KCCOFB-BhAwVgwx.js 23.16 kB │ gzip: 8.54 kB
|
||||
dist/assets/journeyDiagram-3NMN7TZE-BRzATStt.js 23.54 kB │ gzip: 8.33 kB
|
||||
dist/assets/wardleyDiagram-VM6X3IG4-BOZsFnU-.js 25.47 kB │ gzip: 6.77 kB
|
||||
dist/assets/gitGraphDiagram-WWUBYQGX-C0_dKJju.js 29.38 kB │ gzip: 8.68 kB
|
||||
dist/assets/erDiagram-RLTQ6QDP-Bn3j6ajH.js 30.76 kB │ gzip: 10.57 kB
|
||||
dist/assets/timeline-definition-24CTP7MA-BXwtim3P.js 30.79 kB │ gzip: 10.13 kB
|
||||
dist/assets/requirementDiagram-BXWQKSXE-Be7LLRur.js 30.97 kB │ gzip: 9.70 kB
|
||||
dist/assets/quadrantDiagram-AXDQQJYC-sYmnlx5c.js 33.98 kB │ gzip: 9.96 kB
|
||||
dist/assets/layout-BBA9sCju.js 35.43 kB │ gzip: 12.74 kB
|
||||
dist/assets/chunk-IMKFNOWR-CQbC2wF9.js 38.07 kB │ gzip: 12.51 kB
|
||||
dist/assets/blockDiagram-I7D4REHJ-DubqVycP.js 41.72 kB │ gzip: 13.56 kB
|
||||
dist/assets/vennDiagram-4TSXK5OY-CBt0jGDF.js 41.93 kB │ gzip: 15.67 kB
|
||||
dist/assets/xychartDiagram-S5SC5T6Z-CqmuB8Ic.js 44.47 kB │ gzip: 12.58 kB
|
||||
dist/assets/chunk-TICWLB2K-CbQpdxty.js 49.17 kB │ gzip: 15.74 kB
|
||||
dist/assets/flowDiagram-HODETNUW-D6ULMOkO.js 61.84 kB │ gzip: 19.87 kB
|
||||
dist/assets/c4Diagram-7LVT6UL2-Dy-BA8ey.js 65.44 kB │ gzip: 18.77 kB
|
||||
dist/assets/ganttDiagram-EL5Y4UJY-CTWFJimm.js 69.66 kB │ gzip: 23.54 kB
|
||||
dist/assets/cose-bilkent-JH36ORCC-crpHcJa8.js 81.66 kB │ gzip: 22.46 kB
|
||||
dist/assets/swimlanes-42K2YHIH-C-I9BHlP.js 115.76 kB │ gzip: 42.49 kB
|
||||
dist/assets/sequenceDiagram-WJ2MYXX4-DHyVDyhS.js 116.93 kB │ gzip: 31.11 kB
|
||||
dist/assets/architectureDiagram-5GKGNRK7-B7ijxLOx.js 151.79 kB │ gzip: 43.12 kB
|
||||
dist/assets/katex-HP8lGamR.js 261.31 kB │ gzip: 77.57 kB
|
||||
dist/assets/cytoscape.esm-BB4DxJjf.js 443.04 kB │ gzip: 141.98 kB
|
||||
dist/assets/cynefin-OW5HDTMX-BV1-mtln.js 687.91 kB │ gzip: 154.14 kB
|
||||
dist/assets/index-BT80OB_W.js 2,798.14 kB │ gzip: 796.79 kB
|
||||
|
||||
(!) Some chunks are larger than 500 kB after minification. Consider:
|
||||
- Using dynamic import() to code-split the application
|
||||
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
|
||||
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
|
||||
✓ built in 7.44s
|
||||
PASS: prod bundle scan (/home/weichen/projects/Agent-System/web/dist)
|
||||
bundle_exit=0
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":47,"schema_ready":true,"task_store_ready":true}
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"ok","env":"dev","agent_backend":"pi-agent","version":"v1.0","shared_kb_port":5432,"database_ready":true,"schema_version":47,"schema_ready":true,"task_store_ready":true}
|
||||
@@ -0,0 +1,12 @@
|
||||
=== RUN TestE2E_WorkflowGovernance_CompleteAndReplan
|
||||
2026/09/16 05:16:31 goose: no migrations to run. current version: 47
|
||||
2026/09/16 05:16:31 goose: no migrations to run. current version: 47
|
||||
2026/09/16 05:16:31 [kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式
|
||||
--- PASS: TestE2E_WorkflowGovernance_CompleteAndReplan (0.31s)
|
||||
=== RUN TestWorkflowGovernance_PG_ActivateApproveAdvanceChain
|
||||
{"time":"2026-09-16T05:16:31.591340083Z","level":"INFO","msg":"goose: no migrations to run. current version: 47"}
|
||||
{"time":"2026-09-16T05:16:31.601328207Z","level":"INFO","msg":"goose: no migrations to run. current version: 47"}
|
||||
{"time":"2026-09-16T05:16:31.604853082Z","level":"INFO","msg":"[kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式"}
|
||||
--- PASS: TestWorkflowGovernance_PG_ActivateApproveAdvanceChain (0.35s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 0.663s
|
||||
@@ -0,0 +1,2 @@
|
||||
ok chat-agent-system/internal/server 1.069s
|
||||
gov_exit=0
|
||||
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"started": "2026-09-16T05:18:16",
|
||||
"base": "http://127.0.0.1:8080",
|
||||
"project_id": 6367,
|
||||
"session_id": "sess-p6367-u11",
|
||||
"overall": "PASS",
|
||||
"cases": [
|
||||
{
|
||||
"id": "health",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 6,
|
||||
"output": {
|
||||
"env": "dev",
|
||||
"schema": 47,
|
||||
"backend": "pi-agent"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "login",
|
||||
"verdict": "PASS",
|
||||
"output": {
|
||||
"owner_id": 11,
|
||||
"reviewer_id": 12,
|
||||
"approver_id": 9,
|
||||
"guest_id": 13,
|
||||
"note": "zhanggong disabled; used lizhuguan"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "demo_projects_absent",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 3,
|
||||
"output": {
|
||||
"count": 7,
|
||||
"polluted": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "create_project",
|
||||
"verdict": "PASS",
|
||||
"http": 201,
|
||||
"duration_ms": 20,
|
||||
"output": {
|
||||
"project_id": 6367,
|
||||
"snip": "{\"id\":6367,\"code\":\"mtx-051808\",\"name\":\"矩阵深度抽检-051808\",\"customer_name\":\"\",\"device_type\":\"超声软组织手术吸引设备\",\"intended_use\":\"mat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "demo_docs_clean",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"output": {
|
||||
"doc_count": 0,
|
||||
"mock_ids": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "real_pi_chat",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 8101,
|
||||
"output": {
|
||||
"snip": "好的,已记住——本项目是**超声软组织吸引设备**(即超声软组织手术吸引设备)的立项摸底。\n\n后续需要我帮您梳理立项摸底清单、竞品画像框架或研发排期草案时,随时说一声就好。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "window_categories",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 3,
|
||||
"output": {
|
||||
"window_msgs": 2,
|
||||
"category_total": null,
|
||||
"cat_http": 200
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "guest_403",
|
||||
"verdict": "PASS",
|
||||
"http": 403,
|
||||
"duration_ms": 0,
|
||||
"output": {
|
||||
"error_code": "SESSION_FORBIDDEN"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "save_plan",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 5,
|
||||
"output": {
|
||||
"snip": "{\"project_id\":6367,\"lifecycle_status\":\"planning\",\"active_workflow_key\":\"\",\"workflow_selection_version\":1,\"workflow_plan_revision\":1,\"plan\":{\"workflow_definition_key\":\"main\",\"workflow_version\":2,\"workf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "version_conflict_409",
|
||||
"verdict": "PASS",
|
||||
"http": 409,
|
||||
"duration_ms": 1,
|
||||
"output": {
|
||||
"business_code": "ERR_CONCURRENT_SWITCH"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "activate",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 3,
|
||||
"output": {
|
||||
"preview_http": 200,
|
||||
"snip": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "termination_preview",
|
||||
"verdict": "PASS",
|
||||
"http": 200,
|
||||
"duration_ms": 1,
|
||||
"output": {
|
||||
"instance_id": 262,
|
||||
"can_terminate": true,
|
||||
"keys": [
|
||||
"instance_id",
|
||||
"pending_documents",
|
||||
"in_progress_task_runs",
|
||||
"can_terminate",
|
||||
"impact"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
=== intent/intent-plan ===
|
||||
ok chat-agent-system/internal/intent 0.019s
|
||||
ok chat-agent-system/internal/coordinator 0.006s
|
||||
ok chat-agent-system/internal/app/intentflow 0.008s
|
||||
ok chat-agent-system/internal/app 0.005s
|
||||
ok chat-agent-system/internal/events 0.004s
|
||||
ok chat-agent-system/internal/server 2.161s
|
||||
intent_exit=0
|
||||
=== chat ===
|
||||
ok chat-agent-system/internal/ctxmgr 0.083s
|
||||
ok chat-agent-system/internal/app/chatflow 0.004s
|
||||
ok chat-agent-system/internal/chat 0.012s
|
||||
chat_exit=0
|
||||
=== squad ===
|
||||
ok chat-agent-system/internal/squad 0.023s
|
||||
squad_exit=0
|
||||
=== workflow/authz/docgov/docrevision ===
|
||||
ok chat-agent-system/internal/projectinstance 0.003s
|
||||
ok chat-agent-system/internal/workflowdef 0.002s
|
||||
ok chat-agent-system/internal/auth 0.767s
|
||||
ok chat-agent-system/internal/authz 0.002s
|
||||
ok chat-agent-system/internal/docgov 0.015s
|
||||
ok chat-agent-system/internal/docrevision 0.005s
|
||||
waf_exit=0
|
||||
=== pi-agent ===
|
||||
ok chat-agent-system/internal/agent 3.459s
|
||||
agent_go_exit=0
|
||||
✔ withResultV1 is additive and strips stderr (1.00996ms)
|
||||
✔ typedErrorCode is allowlisted and ignores raw stderr (0.167475ms)
|
||||
✔ path escape members are omitted (0.66168ms)
|
||||
ℹ tests 3
|
||||
ℹ suites 0
|
||||
ℹ pass 3
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 52.254759
|
||||
agent_node_exit=0
|
||||
=== events E0-E2 ===
|
||||
ok chat-agent-system/internal/events 0.004s
|
||||
ok chat-agent-system/internal/app/docnotify 0.003s
|
||||
ok chat-agent-system/internal/app/docadvance 0.003s
|
||||
ok chat-agent-system/internal/app/docproject 0.003s
|
||||
ok chat-agent-system/internal/app/docflow 0.003s
|
||||
events_exit=0
|
||||
@@ -0,0 +1,472 @@
|
||||
|
||||
> shuimu-workbench@1.0.0 test
|
||||
> tsx --test "src/**/!(*InteractiveCard*|*chatWindowArtifact*|*deliverableSync*).test.ts" && vitest run src/components/chat/InteractiveCard.test.ts src/components/chat/chatWindowArtifact.test.ts src/components/chat/deliverableSync.test.ts
|
||||
|
||||
✔ AuthClient: 基础登录与 .env 超级管理员鉴权 (1.995041ms)
|
||||
✔ AuthClient: 自主注册受控流程(仅填用户名密码姓名,职位强制绑定访客待指派) (0.467176ms)
|
||||
✔ AuthClient: 开启注册需审批时,注册账号处于待审状态并禁止登录 (0.528284ms)
|
||||
✔ AuthClient: 管理员创建账号必须在首次登录修改密码 (0.323461ms)
|
||||
✔ mapUserAccount: snake_case Go contract → camelCase (1.033499ms)
|
||||
✔ mapUserAccount: prefers snake_case when both present (0.197924ms)
|
||||
✔ mapLoginResult + mapMeResult map nested user and top-level must_change_password (0.902823ms)
|
||||
✔ mapUserAccountList maps admin users list (0.223613ms)
|
||||
✔ AuthClient.login + fetchMe map real snake_case wire payloads (26.144283ms)
|
||||
✔ shouldAutoRetryChat: disabled until idempotency (0.912833ms)
|
||||
✔ shouldAutoRetryTask: transient only, max 2 (0.194784ms)
|
||||
✔ shouldAutoRetryTask: document busy never retries (0.110757ms)
|
||||
✔ shouldAutoRetry alias delegates to task path (0.130287ms)
|
||||
✔ autoRetryDelayMs: 1s then 2s (0.135606ms)
|
||||
✔ fallbackErrorClass: network → transient, workspace → resumable (0.117457ms)
|
||||
✔ parseSSEChunk: parses event and data lines (1.061658ms)
|
||||
✔ parseSSEChunk: keeps incomplete frame in rest (0.276232ms)
|
||||
✔ parseSSEChunk: flush parses final frame without trailing delimiter (0.226903ms)
|
||||
✔ parseSSEChunk: ignores heartbeat comments and keeps last id (0.175014ms)
|
||||
▶ projectSettingsError
|
||||
✔ keeps status, code, message and issues on PLAN_FROZEN (1.468706ms)
|
||||
✔ maps revision and concurrent conflicts to distinct recovery (0.147115ms)
|
||||
✔ joins validation issues but still keeps typed codes (0.136046ms)
|
||||
✔ prefers envelope code over legacy error field (0.093017ms)
|
||||
✔ unwraps nested business JSON inside VERSION_CONFLICT envelope (0.174915ms)
|
||||
✔ maps bare VERSION_CONFLICT envelope to retry_after_switch (0.097887ms)
|
||||
✔ retains the local draft when a late tab hits PLAN_FROZEN (0.085587ms)
|
||||
✔ projectSettingsError (3.200045ms)
|
||||
✔ Project workflow types validation (1.156985ms)
|
||||
✔ createTaskRun exposes DOC_BUSY detail without a retryable run (24.052076ms)
|
||||
✔ parseSSEChunk tracks id seq for after_seq reconnect (0.385119ms)
|
||||
✔ subscribeTaskRunEvents reconnects on EOF with advancing after_seq (4.695911ms)
|
||||
✔ readTaskRunSSEOnce marks non-terminal EOF for reconnect (0.588273ms)
|
||||
✔ buildTaskRequest: maps five project fields + task_key + user identity (1.133977ms)
|
||||
✔ buildTaskRequest: omits optional fields when absent (0.215383ms)
|
||||
✔ buildTaskRequest: includes materials when provided and non-empty (1.074518ms)
|
||||
✔ buildResumeRequest: adds work_dir on top of task request (0.225603ms)
|
||||
✔ buildTaskRequest: canonicalizes legacy doc-p doc_id (0.325181ms)
|
||||
✔ buildTaskRequest: UI-05 pinned intake keeps task_key + doc_proj6109_intake (0.237933ms)
|
||||
✔ buildResumeRequest: forwards add_steps when provided (0.197414ms)
|
||||
✔ CategoryDock: 渲染顶部 🔔 未读提醒项及角标数字 (12.675113ms)
|
||||
✔ CategoryDock: isAllReadCompleted 为 true 时渲染完成态提示 (3.480557ms)
|
||||
✔ CategoryDock: 0 未读时不渲染红色未读角标 (6.254924ms)
|
||||
✔ CategoryDock: 分类项包含依次跳转与遍历提示信息 (2.735299ms)
|
||||
✔ InputArea keeps draft when send preflight fails (1.230894ms)
|
||||
✔ InputArea clears draft only after accepted send (0.573333ms)
|
||||
✔ InputArea shows thinking block message (0.159615ms)
|
||||
✔ InputArea keeps draft when attachment registration fails (0.247173ms)
|
||||
✔ isTemplateOnly 交付物应正确识别为初始模板展示态 (0.754627ms)
|
||||
✔ 左侧栏鼠标严密绝对跟随与夹紧测试 (Left Rail Exact Pointer Following & Clamping) (0.714469ms)
|
||||
✔ 右侧栏鼠标严密绝对跟随与反向位移测试 (Right Rail Exact Pointer Following & Inverted Delta) (0.165045ms)
|
||||
✔ detects legacy mock and neuropulse/ten-projects ids (1.01564ms)
|
||||
✔ detects colliding demo project ids (0.206664ms)
|
||||
✔ 每人独立私聊:同一项目不同用户拥有不同 sessionId (0.709639ms)
|
||||
✔ 左侧会话列表按当前用户过滤,不可见他人私聊 (0.291942ms)
|
||||
✔ 消息严格归属各自私聊 session,无跨用户混聊 (0.67632ms)
|
||||
✔ 切换用户时 resolve 到该用户同项目私聊会话 (0.265232ms)
|
||||
✔ resolve 优先有消息的私聊,跳过空壳 sess-p{N}-u{id} (0.33197ms)
|
||||
✔ ensurePrivateSessionsForUser 为缺失用户补齐空私聊 (0.281082ms)
|
||||
✔ 多项目会话消息隔离测试仍成立(endo vs ultrasound) (0.196574ms)
|
||||
✔ parseAnchorHash: 正确解析标准深链 hash (1.761548ms)
|
||||
✔ formatAnchorHash: 正确构造深链格式 (0.185855ms)
|
||||
✔ navigateToAnchor: 快路径直接命中 DOM 节点 (0.426987ms)
|
||||
✔ navigateToAnchor: 慢路径拉取分片后命中 (81.596677ms)
|
||||
✔ resolveTurnAnchorId: 方案 A 轮次归一化测试 (0.579223ms)
|
||||
✔ 全链路场景 1: 用户自主受控注册(仅填用户名/密码/姓名,职位严格绑定访客待指派) (1.572433ms)
|
||||
✔ 全链路场景 2: 系统准入策略(关闭自主注册与开启强制审批流转) (0.957642ms)
|
||||
✔ 全链路场景 3: 管理员开通账号首次强制改密闭环 (0.3251ms)
|
||||
✔ 全链路场景 4: 环境标识随登录会话返回(dev/test/main) (0.295291ms)
|
||||
✔ cleanHeadingContent: 手工多级序号前缀清洗与专业词汇保护 (0.962552ms)
|
||||
✔ 标题多层级自动编号:单 H1 文档总标题自适应模式 (1 -> 1.1 -> 1.1.1) (0.305551ms)
|
||||
✔ 标题多层级自动编号:多 H1 标准大章模式 (0.141016ms)
|
||||
✔ 跨章节图、表、公式多级按章重编号测试 (表 1-1, 表 2-1, 图 3-1, 式 (4-1)) (0.120746ms)
|
||||
✔ 有序列表与无序列表编号与渲染功能测试 (1.520405ms)
|
||||
✔ 动态块操作闭环重编号验证 (Insert, Move, Delete) (0.186174ms)
|
||||
✔ findMatchingBlockForReview: 能够精准按审查关键词(电气安全/EMC/竞品)定位段落块 (1.295541ms)
|
||||
✔ findMatchingBlockForReview: 能够按外部指定 hint 线索精确命中目标块 (0.233673ms)
|
||||
✔ createRejectConfirmationCard: 生成合规危险级驳回门禁卡片 (0.601753ms)
|
||||
✔ isAffirmativeResponse: 准确识别双轨交互中的肯定意图输入 (0.221293ms)
|
||||
✔ findLastActiveCard: 正确在会话历史中提取最新的待决策卡片 (0.216604ms)
|
||||
✔ decrementActiveCardsTtl: 多轮对话超时递减与自动失效归档 (0.173525ms)
|
||||
✔ applyConfirmRejectToDoc & applyUndoRejectToDoc: 驳回挂载批注与60s窗口期撤销完整闭环 (0.296501ms)
|
||||
✔ resolveCardInMessages & cancelCardInMessages: 消息流中卡片终态沉淀 (0.187264ms)
|
||||
✔ classifyRejectUtterance: 询问原因 → QUERY_REJECT_REASON (0.930912ms)
|
||||
✔ classifyRejectUtterance: 明确执行 → EXECUTE_REJECT (0.166615ms)
|
||||
✔ classifyRejectUtterance: 模糊 → OTHER (0.180014ms)
|
||||
✔ resolveDocGovCard: 编制人查询 → 信息卡且无 confirm_reject (0.746558ms)
|
||||
✔ resolveDocGovCard: 审核人执行 + reviewing → 确认卡 (1.254603ms)
|
||||
✔ resolveDocGovCard: 编制人误说执行驳回 → 无权纯文本 (0.166465ms)
|
||||
✔ resolveDocGovCard: 批准人 + approving → 终审确认卡 (0.168425ms)
|
||||
✔ resolveDocGovCard: 编制人 OTHER → 引导查询无危险按钮 (0.107177ms)
|
||||
✔ canConfirmReject: 仅审核/批准 (0.130966ms)
|
||||
✔ deriveFallbackCategory identifies categories correctly (0.977831ms)
|
||||
✔ enrichMessagesWithCategories backfills categories without overwriting existing ones (0.285522ms)
|
||||
✔ Markdown ➔ Block AST 解析测试 (标题自适应编号与图表公式全链路) (2.498745ms)
|
||||
✔ 动态重编号引擎测试 (多 H1 规范章节重排验证) (2.100378ms)
|
||||
✔ Block AST ➔ Markdown 双向无损往返还原测试 (0.554304ms)
|
||||
✔ 三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privacy Isolation) (1.082668ms)
|
||||
✔ 一键共享至项目参考库流转测试 (Promote to Shared Reference Test) (0.271372ms)
|
||||
✔ 撤回共享恢复私有草稿测试 (Revoke Shared Reference Test) (0.564424ms)
|
||||
✔ 受控工作流纯净性红线检验 (Workflow Purity Security Red Line) (0.32681ms)
|
||||
✔ isSameMessage: clientTurnId match (1.109737ms)
|
||||
✔ isSameMessage: serverId match without turn (0.167865ms)
|
||||
✔ filterPendingLiveMessages: real temp vs server id (0.139175ms)
|
||||
✔ mergeLiveOverHistory preserves server id from live (0.129527ms)
|
||||
✔ applyPhaseEvent: appends first phase as running node (1.064778ms)
|
||||
✔ applyPhaseEvent: completes predecessors when a new phase arrives (0.208124ms)
|
||||
✔ applyPhaseEvent: same phase refreshes label in place (no duplicate node) (0.216274ms)
|
||||
✔ applyPhaseEvent: unknown phase falls back to hourglass meta (0.114496ms)
|
||||
✔ applyPhaseEvent: prefers backend message over short label (0.099547ms)
|
||||
✔ applyPhaseEvent: step_completed closes running entry without appending (1.024819ms)
|
||||
✔ applyPhaseEvent: stage_completed closes entries (0.124956ms)
|
||||
✔ applyPhaseEvent: task_failed appends warning node (0.113747ms)
|
||||
✔ applyPhaseEvent: decorates label with step index / total steps (0.155515ms)
|
||||
✔ applyPhaseEvent: repeated step_executing with step_index gets separate nodes (0.237263ms)
|
||||
✔ applyPhaseEvent: ignores event without phase payload (0.122346ms)
|
||||
✔ applyPhaseEvent: step_failed marks running entry as failed (keeps step label) (0.130266ms)
|
||||
✔ applyPhaseEvent: step_failed appends failed node when no running entry exists (0.125276ms)
|
||||
✔ applyPhaseEvent: retry of a failed step resets it to running (0.097697ms)
|
||||
✔ PLAN_CONFIRM 卡片来自 PlanView 且不触达 AST (1.01759ms)
|
||||
✔ 409 冲突把卡片标为 outdated 并换上最新 revision (0.243463ms)
|
||||
✔ GET reconcile 用权威 PlanView 覆盖本地 executing,不假装成功 (0.207094ms)
|
||||
✔ 过期计划映射 expired (0.151796ms)
|
||||
✔ 非计划卡不被误判 (0.085737ms)
|
||||
✔ 集成验证:项目切换时交付物严格隔离,新建项目即刻包含 7 份模板副本 (4.991482ms)
|
||||
✔ 集成验证:三层隐私与项目物理隔离双重约束 (1.410598ms)
|
||||
✔ 用例 1: DEFAULT_ROLES 包含 5 种默认角色且具备预期权限 (1.231943ms)
|
||||
✔ 用例 2: 系统管理员 (ADMIN) 与具备 perm:manage 用户的通配豁免特权 (0.245832ms)
|
||||
✔ 用例 3: 常规工作流基线可见性 (workflow:view_all) 判定 (0.271472ms)
|
||||
✔ 用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可见,其他用户被精确拦截) (1.962741ms)
|
||||
✔ 用例 5: 单文档覆盖 - role_whitelist (仅白名单内角色可见,其他角色被精确拦截) (0.274252ms)
|
||||
✔ 用例 6: 单文档覆盖 - public (放宽可见性,无 workflow:view_all 权限的访客也能查阅) (0.126076ms)
|
||||
✔ 用例 7: 私密文档隔离强红线 (category === private 无论任何管理员或单文档覆盖,非创建者绝对不可见) (0.138626ms)
|
||||
✔ 用例 8: 核心业务动作权限拦截判定 (canPerformDocAction & hasPermission) (0.173525ms)
|
||||
✔ 用例 9: filterVisibleDeliverablesWithRBAC 能够批处理过滤大盘交付物 (0.885453ms)
|
||||
✔ 集成场景 1: 动态新增合规审计员角色,并配置其仅能查阅特定单文档覆盖 (0.969342ms)
|
||||
✔ 集成场景 2: 服务端 capabilities 变更后权限即刻生效 (0.180845ms)
|
||||
✔ 集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢复全流程 (0.216884ms)
|
||||
✔ renderInlineMarkdown: renders bold, italic, strikethrough (1.00806ms)
|
||||
✔ renderInlineMarkdown: escapes raw HTML tags to prevent XSS (0.437667ms)
|
||||
✔ renderInlineMarkdown: blocks javascript: link hrefs (0.145766ms)
|
||||
✔ renderInlineMarkdown: renders inline code and preserved line breaks (0.227353ms)
|
||||
✔ renderInlineMarkdown: renders headings lists and tables for chat replies (0.34343ms)
|
||||
✔ sanitizeMermaidCode: auto wraps unquoted labels containing brackets or comparison operators (0.283632ms)
|
||||
(node:4027631) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided.
|
||||
(Use `node --trace-warnings ...` to show where the warning was created)
|
||||
✔ DOCX 渲染器行内文本与公式解析测试 (parseInlineContent) (5.096649ms)
|
||||
✔ DOCX 渲染器 LaTeX 原生 OMML 转换引擎测试 (latexToOmml) (2.504616ms)
|
||||
✔ DOCX 渲染器 Mermaid 语法净化与容错测试 (sanitizeMermaidCode) (0.288952ms)
|
||||
✔ DOCX 渲染器 SVG 净化防 Canvas 污染测试 (cleanSvgForCanvas) (0.34609ms)
|
||||
✔ DOCX 渲染器全量编译测试 (buildDocxModel & exportDocumentToDocx) (60.494434ms)
|
||||
✔ XLSX 渲染器多表提取与工作簿编译测试 (buildXlsxWorkbook & exportDocumentToXlsx) (6.085679ms)
|
||||
▶ Reply Document IR & Export Engine
|
||||
✔ deriveReplyTitle and sanitizeFilename derive title and safe file name (1.00806ms)
|
||||
✔ deriveReplyTitle handles text without heading (0.263112ms)
|
||||
✔ parseReplyMarkdown parses headers, lists, code, and tables (1.897594ms)
|
||||
✔ renderClipboardHtml renders self-contained styling for office tools (0.514334ms)
|
||||
✔ renderClipboardHtml converts LaTeX formulas to native MathML for Word/Office (3.559075ms)
|
||||
✔ renderPlainText strips formatting cleanly (0.436737ms)
|
||||
✔ serializeMarkdown round-trips to valid markdown (0.34021ms)
|
||||
✔ stripUnsafeHtml strips script tags and dangerous event handlers (0.474656ms)
|
||||
✔ Reply Document IR & Export Engine (10.511258ms)
|
||||
✔ createProjectTemplateDeliverables: 必须精确生成 7 份全生命周期受控文档副本 (4.683551ms)
|
||||
✔ resolveRequirementsTaskKey prefers intake for 初始需求表 (1.325751ms)
|
||||
✔ resolveRequirementsTaskKey selects user_requirements for explicit URS (0.166045ms)
|
||||
✔ UI-02 first-round prompt with 首轮+用户需求+摸底 must be intake not user_requirements (0.700139ms)
|
||||
✔ 首轮 / 需求摸底 / 摸底 beat bare 用户需求 (0.130106ms)
|
||||
✔ bare 用户需求 without V0.1 markers stays user_requirements (0.120147ms)
|
||||
✔ matchTemplateDeliverable uses intake key when pool only has URS template (0.163975ms)
|
||||
✔ resolveTaskTemplateForMessage keeps intake key with URS-only pool (0.162786ms)
|
||||
✔ matchTemplateDeliverable prefers intake when both templates exist (0.752757ms)
|
||||
✔ read-only request does not start a document task: 总结一下用户初始需求表 (0.275072ms)
|
||||
✔ read-only request does not start a document task: 查看用户初始需求表 (0.167355ms)
|
||||
✔ read-only request does not start a document task: 用户初始需求表现在谁在编辑 (0.713008ms)
|
||||
✔ read-only request does not start a document task: 分析一下用户需求表里的风险 (0.082938ms)
|
||||
✔ read-only request does not start a document task: 用户初始需求表 (0.569833ms)
|
||||
✔ explicit write action still starts intake (0.123747ms)
|
||||
✔ explicit update action still starts URS (0.173725ms)
|
||||
✔ UI-05 prompt without active doc still keyword-routes to feasibility_reg (0.281542ms)
|
||||
✔ UI-05 prompt + registered intake pins intake and doc_proj6109_intake (0.281211ms)
|
||||
✔ read-only current-doc request does not start a task (0.110036ms)
|
||||
✔ template-only active slot is not pinned; keywords still apply (0.101387ms)
|
||||
✔ explicit named deliverable can switch away from active intake (0.254003ms)
|
||||
✔ domain 注册法规 without current-doc deixis still routes feasibility_reg (0.084247ms)
|
||||
✔ mismatched title vs docId suffix prefers docId taskKey (0.088707ms)
|
||||
✔ deixis 当前文档 pins registered intake (0.092458ms)
|
||||
✔ deixis 本文件 pins registered intake (0.045979ms)
|
||||
✔ deixis 这份文档 pins registered intake (0.044009ms)
|
||||
✔ deixis 本文档 pins registered intake (0.040988ms)
|
||||
✔ deixis 本受控文档 pins registered intake (0.042559ms)
|
||||
✔ no active doc does not invent a pin (0.087408ms)
|
||||
✔ UI-11 named 系统设计输入 beats negated 需求 background (0.071368ms)
|
||||
✔ mixed generate-design + do-not-cover-requirements stays prelim_design (0.055729ms)
|
||||
✔ current-doc pin still wins when no other deliverable is named (0.069938ms)
|
||||
▶ document revision overlay modes
|
||||
✔ pure hides all decorations (1.00319ms)
|
||||
✔ manual only marks human hunks (0.164295ms)
|
||||
✔ all marks human and agent differently (0.127556ms)
|
||||
✔ same human hunk stays amber in manual and all (no pairwise style guarantee) (0.288191ms)
|
||||
✔ exposes needs-content error code for empty orphan docs (0.119987ms)
|
||||
✔ matches overlay hunks by section or text when ids differ (0.379089ms)
|
||||
✔ aligns client block ids from head_block_map by order (0.368419ms)
|
||||
✔ document revision overlay modes (3.672621ms)
|
||||
▶ toolbar refresh + report entry reachability
|
||||
✔ pickLatestChangeReportId prefers highest version with report (0.473166ms)
|
||||
✔ first squad run alone still exposes a reachable report id (0.397829ms)
|
||||
✔ second squad run keeps both history report entries and latest shortcut (0.926382ms)
|
||||
✔ revisionRefreshKey is an independent refresh signal from docId (0.134596ms)
|
||||
✔ toolbar refresh + report entry reachability (2.423028ms)
|
||||
▶ change report view model
|
||||
✔ surfaces risk items, project impact, doc impacts with advice, and open questions (0.737078ms)
|
||||
✔ preferReportId prioritizes pending over committed latest (0.595622ms)
|
||||
✔ change report view model (1.471876ms)
|
||||
▶ revisionToolbarMount
|
||||
✔ exposes clear non-error template preview hint copy (0.970381ms)
|
||||
✔ template doc-p + isTemplateOnly=true does not mount (0.218523ms)
|
||||
✔ legacy doc-001 does not mount (0.222983ms)
|
||||
✔ unregistered doc-upload orphan does not mount (must register first) (0.203474ms)
|
||||
✔ server-registered upload (doc-free) and freeform mount (0.194614ms)
|
||||
✔ canonical doc_proj and generated non-template doc-p mount (0.171255ms)
|
||||
✔ revisionToolbarMount (3.38832ms)
|
||||
✔ window fetch race: stale response ignored by generation (0.965092ms)
|
||||
✔ mapRecordToMessage: 正确映射服务端消息记录为前端 ChatMessage (1.3631ms)
|
||||
✔ refresh window: 空 messages 日桶不算有效窗口 (0.175505ms)
|
||||
✔ mapRawBucket: 正确映射服务端按日分片桶 (0.143685ms)
|
||||
✔ Category navigation: chip 选中后准确匹配目标分类最新轮次并触发归一化定位 (0.171244ms)
|
||||
✔ turn runtime: session A stream survives session B switch (0.604902ms)
|
||||
✔ syncAdminUserDirectories calls local reload then parent onRefreshUsers (1.509885ms)
|
||||
✔ syncAdminUserDirectories fails closed when onRefreshUsers is a dead/missing prop (0.635911ms)
|
||||
✔ syncAdminUserDirectories surfaces parent refresh errors (no silent swallow) (0.280641ms)
|
||||
✔ afterProjectMemberPersisted syncs members then refreshes workflow docs (1.755678ms)
|
||||
✔ afterProjectMemberPersisted does not refresh when member sync fails (0.532184ms)
|
||||
▶ blockEditorDialogPolicy
|
||||
✔ pins an accessible dialog label and exact save name (0.841485ms)
|
||||
✔ rejects page-wide fuzzy /保存/ that would hit private-library buttons (0.307371ms)
|
||||
✔ blockEditorDialogPolicy (2.171536ms)
|
||||
▶ resolveSaveTargetBlock
|
||||
✔ keeps the editor and does not fake success when the block id is gone (0.723128ms)
|
||||
✔ never retargets another block that happens to share the same content (0.718658ms)
|
||||
✔ resolveSaveTargetBlock (2.541904ms)
|
||||
▶ editor session document binding
|
||||
✔ fail-closes when activeDocId drifts away from the opened editor doc (0.209393ms)
|
||||
✔ accepts a save only when the editor is still bound to the active doc (0.140885ms)
|
||||
✔ blocks switching documents while the editor is open (0.160485ms)
|
||||
✔ editor session document binding (0.833666ms)
|
||||
▶ interpretBlockSaveError
|
||||
✔ 409 keeps the draft in the editor (0.232513ms)
|
||||
✔ other PATCH failures also keep the editor (0.236993ms)
|
||||
✔ interpretBlockSaveError (0.694559ms)
|
||||
▶ blockedGovernanceCopy
|
||||
✔ recognizes blocked run status and fixed hint, not generation success (0.68284ms)
|
||||
✔ blockedGovernanceCopy (1.501155ms)
|
||||
▶ commentPolicy
|
||||
✔ lets author/reviewer/approver annotate and keeps their comment role (0.754708ms)
|
||||
✔ keeps viewer read-only: no add entry and no reviewer/approver cast (0.143735ms)
|
||||
✔ commentPolicy (1.845556ms)
|
||||
▶ controlledContentInvalidation
|
||||
✔ hydrate success then late list_sync keeps cache/ready and does not bump resume (1.501406ms)
|
||||
✔ post_task invalidation drops active cache and requires a new hydrate epoch (0.234723ms)
|
||||
✔ editor open / save epoch keeps draft and rejects a stale GET after PATCH (0.380079ms)
|
||||
✔ never drops the active doc without signaling rehydrate (0.131047ms)
|
||||
✔ candidate helper keeps template / doc-001 / freeform / upload out of wipe lists (0.416848ms)
|
||||
✔ dropRecordKeys is a no-op when ids are absent (0.111197ms)
|
||||
✔ controlledContentInvalidation (3.930263ms)
|
||||
▶ controlledDocHydrate
|
||||
✔ shouldLoadControlledContent when non-template workflow doc (0.975202ms)
|
||||
✔ shouldLoadControlledContent rejects local legacy/mock ids like doc-001 (0.209814ms)
|
||||
✔ shouldLoadControlledContent keeps canonical, freeform-off, and template preview rules (0.157935ms)
|
||||
✔ hydrateControlledDocumentContent never requests content/revision for doc-001 (0.33429ms)
|
||||
✔ hydrateControlledDocumentContent never requests for template preview or registered freeform (0.138206ms)
|
||||
✔ shouldLoadControlledContent stays inside toolbar server-backed eligibility (0.181635ms)
|
||||
✔ resolveCanonicalDocId maps doc-p56-intake to doc_proj56_intake (0.271331ms)
|
||||
✔ canonicalDocIdForTask maps doc-p56-research to doc_proj56_research (0.155545ms)
|
||||
✔ hydrate treats projection missing as ledger content, not 404 (1.439947ms)
|
||||
✔ attaches hydrate ETag as PATCH baseline and ignores a later GET (1.035789ms)
|
||||
✔ rejects hydrate when revision-state network or 5xx fails (0.621892ms)
|
||||
✔ aligns markdownToBlockAST random ids onto revision-state head_block_map (1.815297ms)
|
||||
✔ leaves Math.random ids when head_block_map is omitted (why gate + fail-closed remain) (0.409868ms)
|
||||
✔ rejects controlled hydrate on NOT_FOUND or NEEDS_CONTENT (0.262602ms)
|
||||
✔ fingerprint stays stable when only object identity changes (0.411477ms)
|
||||
✔ dedupes in-flight hydrate for the same doc fingerprint (0.271882ms)
|
||||
✔ aligned late hydrate still cannot overwrite a PATCH-success baseline (0.436167ms)
|
||||
✔ controlledDocHydrate (11.673493ms)
|
||||
✔ createClientTurnId uses randomUUID when available (0.801476ms)
|
||||
✔ createClientTurnId falls back to getRandomValues UUID v4 (0.422888ms)
|
||||
✔ createClientTurnId throws when no secure random API exists (0.377459ms)
|
||||
✔ selectNonCreatorInitialMembers skips creator only (1.384889ms)
|
||||
✔ buildManagedMemberUpsertPayload sends document_duty on add/update/restore (0.209053ms)
|
||||
✔ buildInitialMemberUpsertPayload maps reviewer UI role to member API role (0.129297ms)
|
||||
✔ persistInitialProjectMembers awaits each add and stops on failure (0.467736ms)
|
||||
✔ ensureCreatedProjectWithMembers skips recreate on bootstrap id and retries members (1.66308ms)
|
||||
✔ beginCreateProjectSubmit rejects concurrent second entry until end (31.01785ms)
|
||||
✔ resolveCreateProjectSubmitPhase uses bootstrap to choose syncing label (0.521255ms)
|
||||
✔ createProjectSubmitButtonLabel and close block while submitting (0.176264ms)
|
||||
▶ resolveCurrentDocRole
|
||||
✔ resolves A as author by authoritative user id (0.730168ms)
|
||||
✔ does not promote reviewer B or stranger to author (0.156975ms)
|
||||
✔ resolves real USER_B id as reviewer and never name-promotes placeholder 2 (0.144165ms)
|
||||
✔ fail-closes unknown identity to viewer even if projectPermission says author (0.138776ms)
|
||||
✔ matches name only for legacy local docs without duty ids (0.111857ms)
|
||||
✔ does not name-promote when server controlled duties are zero ids (0.128906ms)
|
||||
✔ resolveCurrentDocRole (2.618612ms)
|
||||
▶ currentProjectRestore
|
||||
✔ rejects empty project names (0.765087ms)
|
||||
✔ rejects page-wide project name when banner and sidebar both match (0.232303ms)
|
||||
✔ scopes the visible entry to complementary exact title (0.829836ms)
|
||||
✔ scopes the current project assertion to banner exact text (0.236433ms)
|
||||
✔ currentProjectRestore (3.03326ms)
|
||||
▶ deliverableLeaseSync
|
||||
✔ returns the same array reference when leases are unchanged (0.698939ms)
|
||||
✔ returns a new array only when a lease actually changes (0.205023ms)
|
||||
✔ deliverableLeaseSync (1.972472ms)
|
||||
▶ docGovActionVisibility
|
||||
✔ hides all approval actions on unmanaged docs (0.642991ms)
|
||||
✔ gates full docs by currentRole and denies creator who is not author (0.149815ms)
|
||||
✔ docGovActionVisibility (1.653911ms)
|
||||
▶ documentBlockDomAttrs
|
||||
✔ marks a real DocumentBlock in pure mode without overlay kind (0.635621ms)
|
||||
✔ keeps the same stable attrs when overlay is later attached separately (0.160695ms)
|
||||
✔ documentBlockDomAttrs (1.696249ms)
|
||||
▶ durableBodySnippet
|
||||
✔ rejects empty persisted snippets (0.834965ms)
|
||||
✔ lets a later successful revision replace the old snippet (0.184845ms)
|
||||
✔ does not promote a conflict-failed draft to the expected body (0.094617ms)
|
||||
✔ durableBodySnippet (2.088838ms)
|
||||
▶ dutyCellAssertion
|
||||
✔ parses author, reviewer, and viewer from select value or badge role (1.050019ms)
|
||||
✔ must not infer author from a row whose option labels include 编制负责人 (0.606802ms)
|
||||
✔ accepts only a disabled non-assignable reviewer select (0.178935ms)
|
||||
✔ rejects an enabled reviewer select when the reviewer cannot assign leads (0.141976ms)
|
||||
✔ rejects canAssignLead=true even if the reviewer select is disabled (0.104107ms)
|
||||
✔ rejects viewer, author, approver, and unknown values for USER_B (0.240222ms)
|
||||
✔ dutyCellAssertion (3.789288ms)
|
||||
▶ decideHydrationApply
|
||||
✔ applies only when gen, doc, save epoch match and editor is closed (1.114307ms)
|
||||
✔ rejects a response for another document (0.129927ms)
|
||||
✔ rejects a superseded generation (0.074477ms)
|
||||
✔ decideHydrationApply (2.174136ms)
|
||||
▶ createEditorHydrationGate
|
||||
✔ does not start a new hydrate while the editor is open (UI-06 fill-window GET) (0.33025ms)
|
||||
✔ deferred hydrate that resolves after the editor opens does not replace the session (0.154475ms)
|
||||
✔ covers hydrate resolving between fill and save (0.831215ms)
|
||||
✔ asks for a hydrate resume after editor_open blocked the first apply (0.183755ms)
|
||||
✔ asks for a hydrate resume when beginHydration is skipped while editing (0.098577ms)
|
||||
✔ requestHydrationResume is consumed once after a protected edit session (0.101547ms)
|
||||
✔ late hydrate after a successful PATCH does not roll back the new baseline (0.221663ms)
|
||||
✔ createEditorHydrationGate (2.317701ms)
|
||||
✔ mergeSessionUser prefers session identity over stale catalog entry (1.33126ms)
|
||||
▶ playwrightPhaseArtifacts
|
||||
✔ defaults unknown or empty UI_PHASE to main (0.961422ms)
|
||||
✔ keeps post-restart distinct from main so the second run cannot overwrite traces (0.237433ms)
|
||||
✔ keeps main results at the historical filename and isolates post-restart recordPass (0.231943ms)
|
||||
✔ shares phase-state and secrets across phases (0.157155ms)
|
||||
✔ playwrightPhaseArtifacts (2.775488ms)
|
||||
✔ resolvePostTaskActiveDocId prefers server doc_proj for taskKey (5.135667ms)
|
||||
✔ resolvePostTaskActiveDocId honors preferred server doc id (0.248052ms)
|
||||
✔ shouldSwitchTemplateSlotToServer when active is local template slot (0.220503ms)
|
||||
✔ pollUntilPostTaskServerDoc retries until same taskKey server doc appears (0.492325ms)
|
||||
✔ pollUntilPostTaskServerDoc returns null after maxAttempts without relying on setState (0.259652ms)
|
||||
✔ mapServerProjectToProjectInfo maps creator and preserves local members (0.862764ms)
|
||||
✔ mergeProjectLists drops local-only demo seed projects by default (0.307481ms)
|
||||
✔ mergeProjectLists can retain local-only demo when explicitly opted in (0.257142ms)
|
||||
✔ documentDutyFromMemberRole maps UI reviewer and creator (0.961031ms)
|
||||
✔ exclusiveMemberRoleChange keeps a single reviewer (0.253383ms)
|
||||
✔ memberRoleFromDocumentDuty does not invent reviewer from access role (0.304451ms)
|
||||
✔ toApiProjectRole maps doc roles to member and creator to owner (0.710619ms)
|
||||
✔ fromApiProjectRole maps owner to creator for project creator (0.134726ms)
|
||||
✔ mapApiMemberToProjectMember builds UI record (0.138356ms)
|
||||
▶ projectSettingsDuties
|
||||
✔ toggles full to none by atomically clearing duties (1.431477ms)
|
||||
✔ blocks partial saves and locates required/governance issue codes (0.424337ms)
|
||||
✔ allows an all-none configurable draft without three members (1.276902ms)
|
||||
✔ requires three members once any document is managed (0.169765ms)
|
||||
✔ projectSettingsDuties (4.785338ms)
|
||||
▶ projectSettingsMode
|
||||
✔ enters frozen when can_edit_plan is false or the project is active (0.908493ms)
|
||||
✔ stays planning only for an editable draft (0.192724ms)
|
||||
✔ lists enabled duties for the frozen snapshot and skips disabled tasks (0.810526ms)
|
||||
✔ keeps the local draft after PLAN_FROZEN refresh and switches to frozen (0.154905ms)
|
||||
✔ projectSettingsMode (3.222635ms)
|
||||
▶ revisionEtag
|
||||
✔ uses stale hydrate ETag for PATCH and never the latest GET (0.893634ms)
|
||||
✔ does not invent 0:0 when controlled hydrate misses etag or errors (0.173455ms)
|
||||
✔ refuses controlled save without a hydrate ETag (0.544853ms)
|
||||
✔ allows freeform bootstrap 0:0 only (0.292201ms)
|
||||
✔ revisionEtag (3.124147ms)
|
||||
▶ saveControlledBlockEdit
|
||||
✔ successful save calls PATCH once with bound docId, hydrate ETag, body and client_block_map (2.093777ms)
|
||||
✔ does not PATCH when editorDocId and activeDocId diverge (0.175035ms)
|
||||
✔ does not PATCH on stale block id and keeps the draft (0.148595ms)
|
||||
✔ 409 does not close the editor or drop the draft (0.512815ms)
|
||||
✔ network errors do not close the editor or drop the draft (0.178185ms)
|
||||
✔ saveControlledBlockEdit (4.080149ms)
|
||||
✔ parseProjectIdFromSessionId decodes sess-p{id}-u{user} (0.621912ms)
|
||||
✔ resolveSessionProjectId prefers explicit id then session id encoding (0.149855ms)
|
||||
✔ mapServerSessionToProjectSession fills project metadata (0.581942ms)
|
||||
✔ mergeSessionLists keeps local stage while applying server counts (0.191564ms)
|
||||
▶ squadCompletionObservation
|
||||
✔ accepts a directly completed adjacent assistant without requiring inflight (0.738108ms)
|
||||
✔ accepts a turn that passed through inflight then completed (0.121706ms)
|
||||
✔ rejects error terminals, missing correspondence, and visible errors (0.149446ms)
|
||||
✔ keeps waiting while still inflight and does not treat inflight as success (0.097687ms)
|
||||
✔ squadCompletionObservation (2.076648ms)
|
||||
✔ resolveReconnectRunId prefers explicit opts and ignores attempt without opts (0.734238ms)
|
||||
✔ shouldSubscribeExistingRun only for in-flight statuses (0.158095ms)
|
||||
✔ isRemoteTaskTerminal covers confirmation and quality_failed (0.140145ms)
|
||||
✔ nextAttemptOpts carries retained runId for reconnect without new POST (0.121557ms)
|
||||
▶ uploadFreeformRegister
|
||||
✔ buildUploadClientKey prefers explicit hint then doc-upload stamp (0.472296ms)
|
||||
✔ registerUploadAttachments hard-fails without creating orphan on API error (12.923646ms)
|
||||
✔ registerUploadAttachments rejects local doc-upload id from server (0.307631ms)
|
||||
✔ registerUploadAttachments returns server doc-free ids and freeform facts (0.425217ms)
|
||||
✔ deliverableFromFreeformUpload maps server id and upload facts (0.138386ms)
|
||||
✔ uploadFreeformRegister (15.166989ms)
|
||||
▶ workflowCategoryNavigation
|
||||
✔ private menu cannot see doc_proj* so it must switch to workflow before exact select (1.137846ms)
|
||||
✔ fail-closes when the workflow menu is showing but the exact doc is missing (0.206404ms)
|
||||
✔ label and taskKey opens always require the workflow category (0.094747ms)
|
||||
✔ workflowCategoryNavigation (2.37942ms)
|
||||
▶ 用户上传文档多格式在线预览体系与渲染分流测试
|
||||
✔ 1. 上传附件时正确注入 sourceType: "uploaded_file" 与完整 fileMeta 元数据 (0.66963ms)
|
||||
✔ 2. 扩展名分类规则准确分发至对应的高保真渲染器类型 (0.298471ms)
|
||||
✔ 3. 受控工作流交付物严格隔离:绝不命中 FilePreviewPanel,保持 BlockRenderer 纯净 (0.147986ms)
|
||||
✔ 4. 上传文档支持受控流转:从个人私密一键共享至项目参考库后,在线预览依然可用且权限标态正确 (0.153345ms)
|
||||
✔ 用户上传文档多格式在线预览体系与渲染分流测试 (2.101867ms)
|
||||
▶ 项目立项、成员职责分配与退出留痕治理测试套件
|
||||
✔ 1. 默认项目库包含完整元数据与法定三权成员 (active 状态) (0.458517ms)
|
||||
✔ 2. 跨用户会话可见性严格隔离:未加入成员完全不可见 (0.200454ms)
|
||||
✔ 3. 创建者添加新成员并分配职责后,新成员即刻可见该项目会话 (0.118626ms)
|
||||
✔ 4. 中途加入后期退出 (exited):保留项目会话但标记已退出只读留痕 (0.125476ms)
|
||||
✔ 5. 超级管理员 (ADMIN) 享有全量通配可见与管理兜底特权 (0.086488ms)
|
||||
✔ 项目立项、成员职责分配与退出留痕治理测试套件 (1.850955ms)
|
||||
▶ 新建项目工程文档模板质量与纯净性保障套件(对标官方参考系统)
|
||||
✔ 1. 必须精确生成 7 份官方全流程受控工作流模板且标记纯净 (0.66659ms)
|
||||
✔ 2. 杜绝旧项目 CUSA-NeuroPulse 串号泄露,动态注入新项目信息 (0.545744ms)
|
||||
✔ 3. 严格对标参考系统模板规范要素,绝非 3 行残缺摘要 (0.408417ms)
|
||||
✔ 4. 缓存丢失场景下即时自愈重建 AST 能力验证 (0.241083ms)
|
||||
✔ 新建项目工程文档模板质量与纯净性保障套件(对标官方参考系统) (5.099429ms)
|
||||
▶ 用户上传文档私密归档与共享流转测试
|
||||
✔ 10 个评审项目均包含已共享的 URS 交付物与 AST,支持跨角色合规查阅且会话均以 assistant 闭环 (1.155265ms)
|
||||
✔ 用户上传附件自动生成私密交付物并在 AST 中建立隔离,支持流转至项目参考库 (1.181035ms)
|
||||
✔ 单轮对话支持一次上传多个文档(上限5个),批量生成私密交付物并遵循数量约束 (0.406688ms)
|
||||
✔ 用户上传文档私密归档与共享流转测试 (3.384109ms)
|
||||
▶ 工作流切换与消息展示时序测试套件
|
||||
✔ 1. 当存在历史 seed 消息且追加新实时消息时,新消息必须严格沉淀在末尾 (0.65175ms)
|
||||
✔ 2. 切回项目时相同正文不应因 temp/server id 差异重复展示 (0.141016ms)
|
||||
✔ 工作流切换与消息展示时序测试套件 (1.414058ms)
|
||||
✔ DeliverableItem 必须包含 projectId 与 isTemplateOnly 属性 (0.652751ms)
|
||||
ℹ tests 376
|
||||
ℹ suites 34
|
||||
ℹ pass 376
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 838.607739
|
||||
|
||||
RUN v5.0.0 /home/weichen/projects/Agent-System/web
|
||||
|
||||
(node:4028144) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided.
|
||||
(Use `node --trace-warnings ...` to show where the warning was created)
|
||||
|
||||
Test Files 3 passed (3)
|
||||
Tests 32 passed (32)
|
||||
Start at 05:15:46
|
||||
Duration 509ms (import 50%, transform 44%, tests 5%, worker 1%)
|
||||
|
||||
npm_exit=0
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"ok": true,
|
||||
"service": "shuimu-pi-agent-runner",
|
||||
"endpoint_url": "https://api.minimaxi.com/v1",
|
||||
"model_id": "MiniMax-M2.7-highspeed",
|
||||
"api": "openai-compatible",
|
||||
"has_token": true,
|
||||
"tavily": {
|
||||
"active": true,
|
||||
"keys_count": 2
|
||||
},
|
||||
"data_dir": "/app/data/workspaces",
|
||||
"uptime": 6589.40151734
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
=== RUN TestPiAgentTypedResult_LiveDualTrack
|
||||
=== RUN TestPiAgentTypedResult_LiveDualTrack/failure_empty_prompt
|
||||
=== RUN TestPiAgentTypedResult_LiveDualTrack/timeout
|
||||
=== RUN TestPiAgentTypedResult_LiveDualTrack/cancel
|
||||
=== RUN TestPiAgentTypedResult_LiveDualTrack/success
|
||||
--- PASS: TestPiAgentTypedResult_LiveDualTrack (3.28s)
|
||||
--- PASS: TestPiAgentTypedResult_LiveDualTrack/failure_empty_prompt (0.00s)
|
||||
--- PASS: TestPiAgentTypedResult_LiveDualTrack/timeout (0.00s)
|
||||
--- PASS: TestPiAgentTypedResult_LiveDualTrack/cancel (0.30s)
|
||||
--- PASS: TestPiAgentTypedResult_LiveDualTrack/success (2.97s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/agent 3.287s
|
||||
pi_sample_exit=0
|
||||
@@ -0,0 +1,62 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 91.185s
|
||||
? chat-agent-system/cmd/dataset [no test files]
|
||||
ok chat-agent-system/cmd/document-content-reconcile (cached)
|
||||
? chat-agent-system/cmd/document-revision-backfill [no test files]
|
||||
? chat-agent-system/cmd/eventmode [no test files]
|
||||
? chat-agent-system/cmd/events [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 (cached)
|
||||
ok chat-agent-system/internal/app (cached)
|
||||
ok chat-agent-system/internal/app/chatflow (cached)
|
||||
ok chat-agent-system/internal/app/docadvance (cached)
|
||||
ok chat-agent-system/internal/app/docflow (cached)
|
||||
ok chat-agent-system/internal/app/docnotify (cached)
|
||||
ok chat-agent-system/internal/app/docproject (cached)
|
||||
ok chat-agent-system/internal/app/intentflow (cached)
|
||||
ok chat-agent-system/internal/app/stageflow (cached)
|
||||
ok chat-agent-system/internal/app/uow (cached)
|
||||
ok chat-agent-system/internal/archtest 0.143s
|
||||
ok chat-agent-system/internal/artifactvault (cached)
|
||||
ok chat-agent-system/internal/auth (cached)
|
||||
ok chat-agent-system/internal/authz (cached)
|
||||
ok chat-agent-system/internal/bizdev (cached)
|
||||
ok chat-agent-system/internal/chat (cached)
|
||||
ok chat-agent-system/internal/config 0.002s
|
||||
ok chat-agent-system/internal/coordinator (cached)
|
||||
ok chat-agent-system/internal/ctxmgr (cached)
|
||||
ok chat-agent-system/internal/dataset (cached)
|
||||
ok chat-agent-system/internal/db (cached)
|
||||
ok chat-agent-system/internal/doccontent (cached)
|
||||
ok chat-agent-system/internal/docduty (cached)
|
||||
ok chat-agent-system/internal/docgov 0.015s
|
||||
ok chat-agent-system/internal/docquery (cached)
|
||||
ok chat-agent-system/internal/docrevision (cached)
|
||||
ok chat-agent-system/internal/events (cached)
|
||||
ok chat-agent-system/internal/freedoc 0.020s
|
||||
ok chat-agent-system/internal/fsutil (cached)
|
||||
ok chat-agent-system/internal/httpx (cached)
|
||||
ok chat-agent-system/internal/intent (cached)
|
||||
ok chat-agent-system/internal/kb (cached)
|
||||
ok chat-agent-system/internal/maturity (cached)
|
||||
ok chat-agent-system/internal/notification (cached)
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext (cached)
|
||||
ok chat-agent-system/internal/projectinstance (cached)
|
||||
ok chat-agent-system/internal/projectworkflow (cached)
|
||||
ok chat-agent-system/internal/quote (cached)
|
||||
ok chat-agent-system/internal/replyexport (cached)
|
||||
ok chat-agent-system/internal/server 10.668s
|
||||
ok chat-agent-system/internal/squad (cached)
|
||||
ok chat-agent-system/internal/storage (cached)
|
||||
ok chat-agent-system/internal/stream (cached)
|
||||
ok chat-agent-system/internal/stream/transport (cached)
|
||||
ok chat-agent-system/internal/taskrun (cached)
|
||||
ok chat-agent-system/internal/template (cached)
|
||||
ok chat-agent-system/internal/upload (cached)
|
||||
? chat-agent-system/internal/workflow [no test files]
|
||||
ok chat-agent-system/internal/workflow/runtime (cached)
|
||||
ok chat-agent-system/internal/workflowdef (cached)
|
||||
ok chat-agent-system/internal/workspace (cached)
|
||||
? chat-agent-system/templates [no test files]
|
||||
short_exit=0
|
||||
@@ -0,0 +1 @@
|
||||
vet_exit=0
|
||||
@@ -0,0 +1,8 @@
|
||||
=== RUN TestCreatePlanEmitsAwaitingInput
|
||||
--- PASS: TestCreatePlanEmitsAwaitingInput (0.00s)
|
||||
=== RUN TestProjectionOnlyForwardAndForgedRejected
|
||||
--- PASS: TestProjectionOnlyForwardAndForgedRejected (0.00s)
|
||||
=== RUN TestAwaitingPayloadGolden
|
||||
--- PASS: TestAwaitingPayloadGolden (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/app/intentflow 0.003s
|
||||
@@ -0,0 +1,61 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 2.059s
|
||||
? chat-agent-system/cmd/dataset [no test files]
|
||||
ok chat-agent-system/cmd/document-content-reconcile 0.006s
|
||||
? chat-agent-system/cmd/document-revision-backfill [no test files]
|
||||
? chat-agent-system/cmd/eventmode [no test files]
|
||||
? chat-agent-system/cmd/events [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 3.562s
|
||||
ok chat-agent-system/internal/app 0.017s
|
||||
ok chat-agent-system/internal/app/chatflow 0.010s
|
||||
ok chat-agent-system/internal/app/docadvance 0.014s
|
||||
ok chat-agent-system/internal/app/docflow 0.010s
|
||||
ok chat-agent-system/internal/app/docnotify 0.011s
|
||||
ok chat-agent-system/internal/app/docproject 0.010s
|
||||
ok chat-agent-system/internal/app/intentflow 0.010s
|
||||
ok chat-agent-system/internal/app/stageflow 0.012s
|
||||
ok chat-agent-system/internal/app/uow 0.010s
|
||||
ok chat-agent-system/internal/archtest 0.176s
|
||||
ok chat-agent-system/internal/artifactvault 0.010s
|
||||
ok chat-agent-system/internal/auth 0.830s
|
||||
ok chat-agent-system/internal/authz 0.010s
|
||||
ok chat-agent-system/internal/bizdev 0.167s
|
||||
ok chat-agent-system/internal/chat 0.018s
|
||||
ok chat-agent-system/internal/config 0.011s
|
||||
ok chat-agent-system/internal/coordinator 0.021s
|
||||
ok chat-agent-system/internal/ctxmgr 0.099s
|
||||
ok chat-agent-system/internal/dataset 0.004s
|
||||
ok chat-agent-system/internal/db 0.015s
|
||||
ok chat-agent-system/internal/doccontent 0.011s
|
||||
ok chat-agent-system/internal/docduty 0.012s
|
||||
ok chat-agent-system/internal/docgov 0.026s
|
||||
ok chat-agent-system/internal/docquery 0.014s
|
||||
ok chat-agent-system/internal/docrevision 0.016s
|
||||
ok chat-agent-system/internal/events 0.015s
|
||||
ok chat-agent-system/internal/freedoc 0.036s
|
||||
ok chat-agent-system/internal/fsutil 0.002s
|
||||
ok chat-agent-system/internal/httpx 0.002s
|
||||
ok chat-agent-system/internal/intent 0.025s
|
||||
ok chat-agent-system/internal/kb 0.006s
|
||||
ok chat-agent-system/internal/maturity 0.004s
|
||||
ok chat-agent-system/internal/notification 0.088s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.005s
|
||||
ok chat-agent-system/internal/projectinstance 0.005s
|
||||
ok chat-agent-system/internal/projectworkflow 0.006s
|
||||
ok chat-agent-system/internal/quote 0.009s
|
||||
ok chat-agent-system/internal/replyexport 0.005s
|
||||
ok chat-agent-system/internal/server 9.921s
|
||||
ok chat-agent-system/internal/squad 0.030s
|
||||
ok chat-agent-system/internal/storage 0.017s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/stream/transport 0.003s
|
||||
ok chat-agent-system/internal/taskrun 0.150s
|
||||
ok chat-agent-system/internal/template 0.780s
|
||||
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]
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
=== RUN TestConfirmDeniedDoesNotMutatePlan
|
||||
--- PASS: TestConfirmDeniedDoesNotMutatePlan (0.00s)
|
||||
=== RUN TestResourceVersionConflictOnConfirm
|
||||
--- PASS: TestResourceVersionConflictOnConfirm (0.00s)
|
||||
=== RUN TestRevokeBetweenConfirmAndExecute
|
||||
--- PASS: TestRevokeBetweenConfirmAndExecute (0.00s)
|
||||
=== RUN TestEditBumpsRevisionAndInvalidatesOldCard
|
||||
--- PASS: TestEditBumpsRevisionAndInvalidatesOldCard (0.00s)
|
||||
=== RUN TestIllegalPartialConfirmMissingDependency
|
||||
--- PASS: TestIllegalPartialConfirmMissingDependency (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/app/intentflow 0.004s
|
||||
@@ -0,0 +1,20 @@
|
||||
=== RUN TestIntentPlanHTTP_Unauthenticated
|
||||
2026/09/16 00:59:18 [kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式
|
||||
--- PASS: TestIntentPlanHTTP_Unauthenticated (0.13s)
|
||||
=== RUN TestIntentPlanHTTP_ActiveWithoutProjection
|
||||
time=2026-09-16T00:59:18.421Z level=INFO msg="[kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式"
|
||||
--- PASS: TestIntentPlanHTTP_ActiveWithoutProjection (0.13s)
|
||||
=== RUN TestIntentPlanHTTP_ScopeNegatives
|
||||
time=2026-09-16T00:59:18.550Z level=INFO msg="[kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式"
|
||||
--- PASS: TestIntentPlanHTTP_ScopeNegatives (0.13s)
|
||||
=== RUN TestIntentPlanHTTP_IgnoresBodyPrincipalAndSameReceipt
|
||||
time=2026-09-16T00:59:18.678Z level=INFO msg="[kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式"
|
||||
--- PASS: TestIntentPlanHTTP_IgnoresBodyPrincipalAndSameReceipt (0.12s)
|
||||
=== RUN TestIntentPlanHTTP_StaleRevision
|
||||
time=2026-09-16T00:59:18.800Z level=INFO msg="[kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式"
|
||||
--- PASS: TestIntentPlanHTTP_StaleRevision (0.14s)
|
||||
=== RUN TestIntentPlanHTTP_AdminDoesNotBypassMembership
|
||||
time=2026-09-16T00:59:18.938Z level=INFO msg="[kb] 无法连接到 PostgreSQL 知识库 (postgres://:@:0/?sslmode=disable): cannot parse `postgres://:xxxxx@:0/?sslmode=disable`: invalid port (outside range), 将降级运行在离线模式"
|
||||
--- PASS: TestIntentPlanHTTP_AdminDoesNotBypassMembership (0.12s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 0.774s
|
||||
@@ -0,0 +1,61 @@
|
||||
ok chat-agent-system/cmd/bizdev-cli 1.940s
|
||||
? 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/eventmode [no test files]
|
||||
? chat-agent-system/cmd/events [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 5.029s
|
||||
ok chat-agent-system/internal/app 0.014s
|
||||
ok chat-agent-system/internal/app/chatflow 0.004s
|
||||
ok chat-agent-system/internal/app/docadvance 0.003s
|
||||
ok chat-agent-system/internal/app/docflow 0.004s
|
||||
ok chat-agent-system/internal/app/docnotify 0.003s
|
||||
ok chat-agent-system/internal/app/docproject 0.003s
|
||||
ok chat-agent-system/internal/app/intentflow 0.003s
|
||||
ok chat-agent-system/internal/app/stageflow 0.004s
|
||||
ok chat-agent-system/internal/app/uow 0.003s
|
||||
ok chat-agent-system/internal/archtest 0.182s
|
||||
ok chat-agent-system/internal/artifactvault 0.005s
|
||||
ok chat-agent-system/internal/auth 0.822s
|
||||
ok chat-agent-system/internal/authz 0.003s
|
||||
ok chat-agent-system/internal/bizdev 0.170s
|
||||
ok chat-agent-system/internal/chat 0.018s
|
||||
ok chat-agent-system/internal/config 0.002s
|
||||
ok chat-agent-system/internal/coordinator 0.016s
|
||||
ok chat-agent-system/internal/ctxmgr 0.087s
|
||||
ok chat-agent-system/internal/dataset 0.005s
|
||||
ok chat-agent-system/internal/db 0.005s
|
||||
ok chat-agent-system/internal/doccontent 0.002s
|
||||
ok chat-agent-system/internal/docduty 0.005s
|
||||
ok chat-agent-system/internal/docgov 0.018s
|
||||
ok chat-agent-system/internal/docquery 0.005s
|
||||
ok chat-agent-system/internal/docrevision 0.007s
|
||||
ok chat-agent-system/internal/events 0.006s
|
||||
ok chat-agent-system/internal/freedoc 0.027s
|
||||
ok chat-agent-system/internal/fsutil 0.003s
|
||||
ok chat-agent-system/internal/httpx 0.004s
|
||||
ok chat-agent-system/internal/intent 0.030s
|
||||
ok chat-agent-system/internal/kb 0.005s
|
||||
ok chat-agent-system/internal/maturity 0.002s
|
||||
ok chat-agent-system/internal/notification 0.079s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.005s
|
||||
ok chat-agent-system/internal/projectinstance 0.007s
|
||||
ok chat-agent-system/internal/projectworkflow 0.004s
|
||||
ok chat-agent-system/internal/quote 0.009s
|
||||
ok chat-agent-system/internal/replyexport 0.003s
|
||||
ok chat-agent-system/internal/server 10.686s
|
||||
ok chat-agent-system/internal/squad 0.031s
|
||||
ok chat-agent-system/internal/storage 0.016s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/stream/transport 0.002s
|
||||
ok chat-agent-system/internal/taskrun 0.147s
|
||||
ok chat-agent-system/internal/template 2.338s
|
||||
ok chat-agent-system/internal/upload 0.002s
|
||||
? chat-agent-system/internal/workflow [no test files]
|
||||
ok chat-agent-system/internal/workflow/runtime 0.002s
|
||||
ok chat-agent-system/internal/workflowdef 0.003s
|
||||
ok chat-agent-system/internal/workspace 0.003s
|
||||
? chat-agent-system/templates [no test files]
|
||||
@@ -0,0 +1,3 @@
|
||||
cd web && npm test
|
||||
# 371 + 30 PASS; planCard 5 PASS
|
||||
# Playwright gated skip without RUN_UI_ACCEPTANCE
|
||||
@@ -0,0 +1,20 @@
|
||||
=== RUN TestTaskRunAdapterIdempotentExecute
|
||||
--- PASS: TestTaskRunAdapterIdempotentExecute (0.00s)
|
||||
=== RUN TestTaskRunAdapterRejectsQueryKey
|
||||
--- PASS: TestTaskRunAdapterRejectsQueryKey (0.00s)
|
||||
=== RUN TestTaskRunAdapterDeniedAfterRevoke
|
||||
--- PASS: TestTaskRunAdapterDeniedAfterRevoke (0.00s)
|
||||
=== RUN TestConfirmThenMuxExecutesGenerateOnce
|
||||
2026/09/16 02:17:58 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:58 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:58 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:58 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:58 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestConfirmThenMuxExecutesGenerateOnce (0.00s)
|
||||
=== RUN TestLiveTaskStarterReplaysIdempotencyKey
|
||||
--- PASS: TestLiveTaskStarterReplaysIdempotencyKey (0.00s)
|
||||
=== RUN TestTaskGenerateRealPIStopGate
|
||||
plan_owner_test.go:125: stop-gate: PI_AGENT_RUNNER_URL not set; real PI generate is not claimed
|
||||
--- SKIP: TestTaskGenerateRealPIStopGate (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/app 0.005s
|
||||
@@ -0,0 +1,5 @@
|
||||
arch-check mode=block
|
||||
boundaries=/home/weichen/projects/Agent-System/.doc/system-design/module-boundaries.yaml
|
||||
ok chat-agent-system/internal/archtest 0.172s
|
||||
ok chat-agent-system/internal/archtest 0.154s
|
||||
arch-check block: production gate passed
|
||||
@@ -0,0 +1,49 @@
|
||||
=== RUN TestOwnerMuxRoutesGenerateToTask
|
||||
--- PASS: TestOwnerMuxRoutesGenerateToTask (0.00s)
|
||||
=== RUN TestOwnerMuxNilTaskFailClosed
|
||||
--- PASS: TestOwnerMuxNilTaskFailClosed (0.00s)
|
||||
=== RUN TestHandleTurnLegacyDoesNotPersist
|
||||
--- PASS: TestHandleTurnLegacyDoesNotPersist (0.00s)
|
||||
=== RUN TestHandleTurnAutoReadPersistsAndExecutesQueries
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
--- PASS: TestHandleTurnAutoReadPersistsAndExecutesQueries (0.00s)
|
||||
=== RUN TestHandleTurnWriteUtteranceStaysLegacyUnderAutoRead
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
--- PASS: TestHandleTurnWriteUtteranceStaysLegacyUnderAutoRead (0.00s)
|
||||
=== RUN TestQueryGuardRejectsGenerate
|
||||
--- PASS: TestQueryGuardRejectsGenerate (0.00s)
|
||||
=== RUN TestHandleTurnConfirmPersistsAwaitingWithoutExecute
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestHandleTurnConfirmPersistsAwaitingWithoutExecute (0.00s)
|
||||
=== RUN TestHandleTurnConfirmRejectsSecondActiveWritePlan
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=QUERY_REGULATIONS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/16 02:17:57 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestHandleTurnConfirmRejectsSecondActiveWritePlan (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/app/intentflow 0.008s
|
||||
@@ -0,0 +1,78 @@
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
2026/09/16 03:29:05 OK 00001_baseline.sql (52.99ms)
|
||||
2026/09/16 03:29:05 OK 00002_2026-09-09-doc-edit-lease.sql (2.81ms)
|
||||
2026/09/16 03:29:05 OK 00003_2026-09-09-uq-context-memory-chunk-hash.sql (1.48ms)
|
||||
2026/09/16 03:29:05 OK 00004_2026-09-10-chat-daily-digests-and-search.sql (1.19ms)
|
||||
2026/09/16 03:29:05 OK 00005_2026-09-10-chat-messages-day-window.sql (831.31µs)
|
||||
2026/09/16 03:29:05 OK 00006_2026-09-11-chat-read-positions.sql (381.52µs)
|
||||
2026/09/16 03:29:05 OK 00007_2026-09-11-chat-turns.sql (392.26µs)
|
||||
2026/09/16 03:29:05 OK 00008_2026-09-11-freeform-documents.sql (6.98ms)
|
||||
2026/09/16 03:29:05 OK 00009_2026-09-11-message-export-policy.sql (2.68ms)
|
||||
2026/09/16 03:29:05 OK 00010_2026-09-11-project-workflows-and-lineage.sql (13.89ms)
|
||||
2026/09/16 03:29:05 OK 00011_2026-09-11-seed-ten-projects.sql (4.79ms)
|
||||
2026/09/16 03:29:05 OK 00012_2026-09-11-seed-ten-projects-chat.sql (26.88ms)
|
||||
2026/09/16 03:29:05 OK 00013_2026-09-11-task-run-lineage.sql (1.17ms)
|
||||
2026/09/16 03:29:05 OK 00014_project_members.sql (3.17ms)
|
||||
2026/09/16 03:29:05 OK 00015_2026-09-12-iam-core.sql (16.68ms)
|
||||
2026/09/16 03:29:05 OK 00016_2026-09-12-workflow-definitions-and-templates.sql (10.62ms)
|
||||
2026/09/16 03:29:05 OK 00017_2026-09-12-project-workflow-instances.sql (14.46ms)
|
||||
2026/09/16 03:29:05 OK 00018_2026-09-12-outbox-notifications-stage-advance.sql (7.96ms)
|
||||
2026/09/16 03:29:05 OK 00019_2026-09-12-task-runs-events.sql (6.2ms)
|
||||
2026/09/16 03:29:05 OK 00020_2026-09-12-task-run-worker-lease.sql (1.16ms)
|
||||
2026/09/16 03:29:05 OK 00021_2026-09-12-iam-hardening.sql (2.66ms)
|
||||
2026/09/16 03:29:05 OK 00022_2026-09-12-workflow-schema-v2.sql (1.94ms)
|
||||
2026/09/16 03:29:05 OK 00023_2026-09-12-instance-integrity.sql (1.04ms)
|
||||
2026/09/16 03:29:05 OK 00024_2026-09-12-workflow-catalog-governance.sql (6.15ms)
|
||||
2026/09/16 03:29:05 OK 00025_2026-09-13-sync-seed-sequences.sql (909.05µs)
|
||||
2026/09/16 03:29:05 OK 00026_2026-09-13-chat-message-scope.sql (2.59ms)
|
||||
2026/09/16 03:29:05 OK 00027_2026-09-13-chat-message-scope-backfill.sql (2.16ms)
|
||||
2026/09/16 03:29:05 OK 00028_2026-09-13-document-revisions.sql (14.9ms)
|
||||
2026/09/16 03:29:05 OK 00029_2026-09-13-freeform-client-key.sql (1.14ms)
|
||||
2026/09/16 03:29:05 OK 00030_2026-09-13-task-run-pending-author-confirmation.sql (998.16µs)
|
||||
2026/09/16 03:29:05 OK 00031_2026-09-13-project-member-document-duty.sql (1.64ms)
|
||||
2026/09/16 03:29:05 OK 00032_2026-09-14-document-revision-migration-repair.sql (623.08µs)
|
||||
2026/09/16 03:29:05 OK 00033_2026-09-14-task-run-blocked-pending-governance.sql (407.39µs)
|
||||
2026/09/16 03:29:05 OK 00034_2026-09-14-workspace-lease-fencing.sql (432.16µs)
|
||||
2026/09/16 03:29:05 OK 00035_2026-09-14-durable-event-delivery.sql (4.93ms)
|
||||
2026/09/16 03:29:05 OK 00036_2026-09-14-final-artifact-vault.sql (8.11ms)
|
||||
2026/09/16 03:29:05 OK 00037_2026-09-15-task-run-manifests.sql (2.17ms)
|
||||
2026/09/16 03:29:05 OK 00038_2026-09-15-dataset-lifecycle.sql (6.94ms)
|
||||
2026/09/16 03:29:05 OK 00039_2026-09-15-event-inventory-and-principals.sql (5.38ms)
|
||||
2026/09/16 03:29:05 OK 00040_2026-09-15-event-dispatcher.sql (5.87ms)
|
||||
2026/09/16 03:29:05 OK 00041_2026-09-15-notification-visible-outcome.sql (981.65µs)
|
||||
2026/09/16 03:29:05 OK 00042_2026-09-15-workflow-advance-outcome.sql (849.03µs)
|
||||
2026/09/16 03:29:05 OK 00043_2026-09-15-projection-outcome.sql (1.86ms)
|
||||
2026/09/16 03:29:05 OK 00044_2026-09-15-intent-plans.sql (9.41ms)
|
||||
2026/09/16 03:29:05 OK 00045_2026-09-16-intent-plan-projection.sql (3.52ms)
|
||||
2026/09/16 03:29:05 OK 00046_2026-09-16-retire-demo-ten-projects.sql (864.41µs)
|
||||
2026/09/16 03:29:05 OK 00047_2026-09-16-retire-demo-ten-project-sessions.sql (357.51µs)
|
||||
2026/09/16 03:29:05 goose: successfully migrated database to version: 47
|
||||
2026/09/16 03:29:05 goose: no migrations to run. current version: 47
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [1. 项目创建] id=6011 code=pg-piagent-治-734d7a01 wf=main
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [2. 工作流激活] instance_id=1
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [3. pi-agent intake] doc=doc_proj6011_intake title=用户初始需求收集表 elapsed=3m29s
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=main
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullChain (210.64s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain
|
||||
{"time":"2026-09-16T03:32:35.64062371Z","level":"INFO","msg":"goose: no migrations to run. current version: 47"}
|
||||
{"time":"2026-09-16T03:32:35.653820428Z","level":"INFO","msg":"goose: no migrations to run. current version: 47"}
|
||||
workflow_governance_piagent_pg_test.go:275: ✓ [1. 项目创建] id=6012 code=pg-piagent-产-6ab8ff79 wf=product_manager
|
||||
workflow_governance_piagent_pg_test.go:275: ✓ [2. 工作流激活] instance_id=2
|
||||
{"time":"2026-09-16T03:32:36.706239469Z","level":"INFO","msg":"[kb-retriever] embed failed: http 500 Internal Server Error: unexpected end of JSON input (batch=1 est_tokens≈26)"}
|
||||
workflow_governance_piagent_pg_test.go:275: ✓ [3. pi-agent system_reqs] doc=doc_proj6012_system_reqs title=系统需求规格书 elapsed=11m5s
|
||||
workflow_governance_piagent_pg_test.go:275: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:275: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=product_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain (670.20s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain
|
||||
{"time":"2026-09-16T03:43:45.842254474Z","level":"INFO","msg":"goose: no migrations to run. current version: 47"}
|
||||
{"time":"2026-09-16T03:43:45.853747123Z","level":"INFO","msg":"goose: no migrations to run. current version: 47"}
|
||||
workflow_governance_piagent_pg_test.go:290: ✓ [1. 项目创建] id=6013 code=pg-piagent-测-02d30920 wf=test_manager
|
||||
workflow_governance_piagent_pg_test.go:290: ✓ [2. 工作流激活] instance_id=3
|
||||
workflow_governance_piagent_pg_test.go:290: ✓ [3. pi-agent test_manager] doc=doc_proj6013_test_manager title=系统验证方案及计划 elapsed=13m30s
|
||||
workflow_governance_piagent_pg_test.go:290: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:290: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=test_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain (815.44s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 1696.286s
|
||||
EXIT:0
|
||||
@@ -0,0 +1,57 @@
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
2026/09/16 03:23:05 OK 00001_baseline.sql (59.99ms)
|
||||
2026/09/16 03:23:05 OK 00002_2026-09-09-doc-edit-lease.sql (1.71ms)
|
||||
2026/09/16 03:23:05 OK 00003_2026-09-09-uq-context-memory-chunk-hash.sql (1.89ms)
|
||||
2026/09/16 03:23:05 OK 00004_2026-09-10-chat-daily-digests-and-search.sql (656.74µs)
|
||||
2026/09/16 03:23:05 OK 00005_2026-09-10-chat-messages-day-window.sql (1.89ms)
|
||||
2026/09/16 03:23:05 OK 00006_2026-09-11-chat-read-positions.sql (855.43µs)
|
||||
2026/09/16 03:23:05 OK 00007_2026-09-11-chat-turns.sql (668.54µs)
|
||||
2026/09/16 03:23:05 OK 00008_2026-09-11-freeform-documents.sql (8.08ms)
|
||||
2026/09/16 03:23:05 OK 00009_2026-09-11-message-export-policy.sql (3.43ms)
|
||||
2026/09/16 03:23:05 OK 00010_2026-09-11-project-workflows-and-lineage.sql (14.6ms)
|
||||
2026/09/16 03:23:05 OK 00011_2026-09-11-seed-ten-projects.sql (7.24ms)
|
||||
2026/09/16 03:23:05 OK 00012_2026-09-11-seed-ten-projects-chat.sql (39.61ms)
|
||||
2026/09/16 03:23:05 OK 00013_2026-09-11-task-run-lineage.sql (1.78ms)
|
||||
2026/09/16 03:23:05 OK 00014_project_members.sql (3.93ms)
|
||||
2026/09/16 03:23:05 OK 00015_2026-09-12-iam-core.sql (19.1ms)
|
||||
2026/09/16 03:23:05 OK 00016_2026-09-12-workflow-definitions-and-templates.sql (13.15ms)
|
||||
2026/09/16 03:23:05 OK 00017_2026-09-12-project-workflow-instances.sql (17.24ms)
|
||||
2026/09/16 03:23:05 OK 00018_2026-09-12-outbox-notifications-stage-advance.sql (9.61ms)
|
||||
2026/09/16 03:23:05 OK 00019_2026-09-12-task-runs-events.sql (5.61ms)
|
||||
2026/09/16 03:23:05 OK 00020_2026-09-12-task-run-worker-lease.sql (1.39ms)
|
||||
2026/09/16 03:23:05 OK 00021_2026-09-12-iam-hardening.sql (2.94ms)
|
||||
2026/09/16 03:23:05 OK 00022_2026-09-12-workflow-schema-v2.sql (2.02ms)
|
||||
2026/09/16 03:23:05 OK 00023_2026-09-12-instance-integrity.sql (1.13ms)
|
||||
2026/09/16 03:23:05 OK 00024_2026-09-12-workflow-catalog-governance.sql (7.02ms)
|
||||
2026/09/16 03:23:05 OK 00025_2026-09-13-sync-seed-sequences.sql (983.46µs)
|
||||
2026/09/16 03:23:05 OK 00026_2026-09-13-chat-message-scope.sql (2.96ms)
|
||||
2026/09/16 03:23:05 OK 00027_2026-09-13-chat-message-scope-backfill.sql (2.53ms)
|
||||
2026/09/16 03:23:05 OK 00028_2026-09-13-document-revisions.sql (17.6ms)
|
||||
2026/09/16 03:23:05 OK 00029_2026-09-13-freeform-client-key.sql (1.32ms)
|
||||
2026/09/16 03:23:05 OK 00030_2026-09-13-task-run-pending-author-confirmation.sql (1.25ms)
|
||||
2026/09/16 03:23:05 OK 00031_2026-09-13-project-member-document-duty.sql (2.19ms)
|
||||
2026/09/16 03:23:05 OK 00032_2026-09-14-document-revision-migration-repair.sql (847.55µs)
|
||||
2026/09/16 03:23:05 OK 00033_2026-09-14-task-run-blocked-pending-governance.sql (612.75µs)
|
||||
2026/09/16 03:23:05 OK 00034_2026-09-14-workspace-lease-fencing.sql (608.22µs)
|
||||
2026/09/16 03:23:05 OK 00035_2026-09-14-durable-event-delivery.sql (5.64ms)
|
||||
2026/09/16 03:23:05 OK 00036_2026-09-14-final-artifact-vault.sql (9.3ms)
|
||||
2026/09/16 03:23:05 OK 00037_2026-09-15-task-run-manifests.sql (2.63ms)
|
||||
2026/09/16 03:23:05 OK 00038_2026-09-15-dataset-lifecycle.sql (8.13ms)
|
||||
2026/09/16 03:23:05 OK 00039_2026-09-15-event-inventory-and-principals.sql (6.63ms)
|
||||
2026/09/16 03:23:05 OK 00040_2026-09-15-event-dispatcher.sql (7.01ms)
|
||||
2026/09/16 03:23:05 OK 00041_2026-09-15-notification-visible-outcome.sql (1.19ms)
|
||||
2026/09/16 03:23:05 OK 00042_2026-09-15-workflow-advance-outcome.sql (1.05ms)
|
||||
2026/09/16 03:23:05 OK 00043_2026-09-15-projection-outcome.sql (2.33ms)
|
||||
2026/09/16 03:23:05 OK 00044_2026-09-15-intent-plans.sql (11.58ms)
|
||||
2026/09/16 03:23:05 OK 00045_2026-09-16-intent-plan-projection.sql (4.02ms)
|
||||
2026/09/16 03:23:05 OK 00046_2026-09-16-retire-demo-ten-projects.sql (1.26ms)
|
||||
2026/09/16 03:23:05 OK 00047_2026-09-16-retire-demo-ten-project-sessions.sql (484.9µs)
|
||||
2026/09/16 03:23:05 goose: successfully migrated database to version: 47
|
||||
2026/09/16 03:23:05 goose: no migrations to run. current version: 47
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [1. 项目创建] id=6011 code=pg-piagent-治-12843d38 wf=main
|
||||
workflow_governance_piagent_pg_test.go:261: ✓ [2. 工作流激活] instance_id=1
|
||||
workflow_governance_piagent_pg_test.go:261: pi-agent task HTTP 500: null
|
||||
--- FAIL: TestWorkflowGovernance_PiAgent_PG_FullChain (0.70s)
|
||||
FAIL
|
||||
FAIL chat-agent-system/internal/server 0.705s
|
||||
FAIL
|
||||
@@ -45,6 +45,11 @@ jobs:
|
||||
TEST_DATABASE_URL: postgres://app:ci_secret_db_pass@localhost:5432/agent_system_ci?sslmode=disable
|
||||
run: go test -short -timeout 20m ./...
|
||||
|
||||
- name: governance PG integration (no -short)
|
||||
env:
|
||||
TEST_DATABASE_URL: postgres://app:ci_secret_db_pass@localhost:5432/agent_system_ci?sslmode=disable
|
||||
run: go test -count=1 -timeout 15m ./internal/server/ -run 'TestWorkflowGovernance_PG_|TestE2E_WorkflowGovernance'
|
||||
|
||||
- name: arch-check (block cleared kinds)
|
||||
run: ./scripts/arch-check.sh --mode block
|
||||
|
||||
|
||||
+3
-1
@@ -60,7 +60,9 @@ node_modules/
|
||||
.regulations/
|
||||
regulations/
|
||||
|
||||
# Playwright UI acceptance local secrets / runtime output
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.doc/test-reports/assets/**/phase-secrets.local.json
|
||||
.doc/test-reports/assets/**/playwright-output/
|
||||
.doc/test-reports/assets/**/playwright-output-*/
|
||||
|
||||
+5
-3
@@ -14,6 +14,7 @@ import (
|
||||
"chat-agent-system/internal/app/docadvance"
|
||||
"chat-agent-system/internal/app/docnotify"
|
||||
"chat-agent-system/internal/app/docproject"
|
||||
"chat-agent-system/internal/app/intentflow"
|
||||
"chat-agent-system/internal/config"
|
||||
"chat-agent-system/internal/db"
|
||||
"chat-agent-system/internal/docgov"
|
||||
@@ -78,9 +79,10 @@ func main() {
|
||||
_ = disp.Register(events.ConsumerWorkflowAdvance, (&docadvance.EventConsumer{
|
||||
Inst: instSvc, Docs: gov, PW: pwSvc, Notify: notify, Env: cfg.Env,
|
||||
}).HandleLease)
|
||||
_ = disp.Register(events.ConsumerProjection, (&docproject.EventConsumer{
|
||||
Docs: gov, Env: cfg.Env,
|
||||
}).HandleLease)
|
||||
_ = disp.Register(events.ConsumerProjection, intentflow.MuxProjection(
|
||||
(&docproject.EventConsumer{Docs: gov, Env: cfg.Env}).HandleLease,
|
||||
(&intentflow.ProjectionConsumer{Env: cfg.Env}).HandleLease,
|
||||
))
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /health", func(w http.ResponseWriter, _ *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{"status": "ok", "env": cfg.Env, "owner": owner})
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Host Go E2E shares bind-mounted workspaces; keep files group/world readable.
|
||||
umask 000
|
||||
|
||||
# =============================================================================
|
||||
# Pi Agent Container Entrypoint
|
||||
# Dynamically configures MiniMax provider (4 core parameters) & Tavily search extension
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
-- +goose Up
|
||||
-- U3: persistent multi-intent plans. Owner is app/intentflow; other packages use the Service port.
|
||||
-- JSONB is only for versioned slots / display snapshots. CAS, lease, and audit columns are typed.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS intent_plans (
|
||||
plan_id TEXT PRIMARY KEY,
|
||||
environment TEXT NOT NULL,
|
||||
project_id BIGINT NOT NULL,
|
||||
session_id TEXT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
client_turn_id TEXT NOT NULL,
|
||||
request_digest TEXT NOT NULL,
|
||||
segmenter_version TEXT NOT NULL DEFAULT '',
|
||||
policy_version TEXT NOT NULL DEFAULT '',
|
||||
status TEXT NOT NULL,
|
||||
revision BIGINT NOT NULL DEFAULT 1,
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
last_fencing_token BIGINT NOT NULL DEFAULT 0,
|
||||
write_plan BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
execution_mode TEXT NOT NULL DEFAULT 'validated_only',
|
||||
safe_summary TEXT NOT NULL DEFAULT '',
|
||||
display_snapshot JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT chk_intent_plan_status CHECK (status IN (
|
||||
'proposed',
|
||||
'awaiting_clarification',
|
||||
'awaiting_confirmation',
|
||||
'executing',
|
||||
'partially_completed',
|
||||
'completed',
|
||||
'failed',
|
||||
'cancelled',
|
||||
'expired',
|
||||
'superseded'
|
||||
)),
|
||||
CONSTRAINT chk_intent_plan_execution_mode CHECK (execution_mode IN (
|
||||
'validated_only',
|
||||
'live'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_intent_plans_turn
|
||||
ON intent_plans (environment, session_id, client_turn_id);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_intent_plans_one_active_write
|
||||
ON intent_plans (environment, project_id, session_id, user_id)
|
||||
WHERE write_plan AND status IN (
|
||||
'proposed',
|
||||
'awaiting_clarification',
|
||||
'awaiting_confirmation',
|
||||
'executing',
|
||||
'partially_completed'
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plans_active_scope
|
||||
ON intent_plans (environment, project_id, session_id, user_id, status);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plans_expire
|
||||
ON intent_plans (expires_at)
|
||||
WHERE status IN ('proposed', 'awaiting_clarification', 'awaiting_confirmation');
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plans_retention
|
||||
ON intent_plans (updated_at)
|
||||
WHERE status IN ('completed', 'failed', 'cancelled', 'expired', 'superseded');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS intent_plan_steps (
|
||||
step_id TEXT PRIMARY KEY,
|
||||
plan_id TEXT NOT NULL REFERENCES intent_plans(plan_id) ON DELETE CASCADE,
|
||||
ordinal INT NOT NULL,
|
||||
action_key TEXT NOT NULL,
|
||||
slots JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
depends_on TEXT[] NOT NULL DEFAULT '{}',
|
||||
status TEXT NOT NULL,
|
||||
expected_resource_version TEXT NOT NULL DEFAULT '',
|
||||
action_digest TEXT NOT NULL DEFAULT '',
|
||||
idempotency_key TEXT NOT NULL DEFAULT '',
|
||||
attempt INT NOT NULL DEFAULT 0,
|
||||
result_ref TEXT NOT NULL DEFAULT '',
|
||||
result_digest TEXT NOT NULL DEFAULT '',
|
||||
safe_summary TEXT NOT NULL DEFAULT '',
|
||||
lease_owner TEXT NOT NULL DEFAULT '',
|
||||
lease_until TIMESTAMPTZ,
|
||||
fencing_token BIGINT NOT NULL DEFAULT 0,
|
||||
version BIGINT NOT NULL DEFAULT 1,
|
||||
execution_mode TEXT NOT NULL DEFAULT 'validated_only',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT chk_intent_plan_step_status CHECK (status IN (
|
||||
'pending',
|
||||
'eligible',
|
||||
'running',
|
||||
'succeeded',
|
||||
'failed',
|
||||
'denied',
|
||||
'conflicted',
|
||||
'blocked_dependency',
|
||||
'skipped',
|
||||
'cancelled'
|
||||
)),
|
||||
CONSTRAINT chk_intent_plan_step_execution_mode CHECK (execution_mode IN (
|
||||
'validated_only',
|
||||
'live'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_intent_plan_steps_ordinal
|
||||
ON intent_plan_steps (plan_id, ordinal);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_intent_plan_steps_idempotency
|
||||
ON intent_plan_steps (idempotency_key)
|
||||
WHERE idempotency_key <> '';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plan_steps_claim
|
||||
ON intent_plan_steps (status, lease_until);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS intent_plan_decisions (
|
||||
decision_id TEXT PRIMARY KEY,
|
||||
plan_id TEXT NOT NULL REFERENCES intent_plans(plan_id) ON DELETE CASCADE,
|
||||
nonce TEXT NOT NULL,
|
||||
plan_revision BIGINT NOT NULL,
|
||||
actor_user_id BIGINT NOT NULL,
|
||||
kind TEXT NOT NULL,
|
||||
step_ids TEXT[] NOT NULL DEFAULT '{}',
|
||||
exclude_unselected BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
decision_digest TEXT NOT NULL,
|
||||
outcome TEXT NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT chk_intent_plan_decision_kind CHECK (kind IN (
|
||||
'confirm',
|
||||
'cancel',
|
||||
'exclude',
|
||||
'clarify',
|
||||
'edit',
|
||||
'confirm_retry',
|
||||
'continue',
|
||||
'replace'
|
||||
))
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uq_intent_plan_decisions_nonce
|
||||
ON intent_plan_decisions (plan_id, nonce);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plan_decisions_plan
|
||||
ON intent_plan_decisions (plan_id, created_at);
|
||||
|
||||
-- +goose Down
|
||||
DROP INDEX IF EXISTS idx_intent_plan_decisions_plan;
|
||||
DROP INDEX IF EXISTS uq_intent_plan_decisions_nonce;
|
||||
DROP TABLE IF EXISTS intent_plan_decisions;
|
||||
DROP INDEX IF EXISTS idx_intent_plan_steps_claim;
|
||||
DROP INDEX IF EXISTS uq_intent_plan_steps_idempotency;
|
||||
DROP INDEX IF EXISTS uq_intent_plan_steps_ordinal;
|
||||
DROP TABLE IF EXISTS intent_plan_steps;
|
||||
DROP INDEX IF EXISTS idx_intent_plans_retention;
|
||||
DROP INDEX IF EXISTS idx_intent_plans_expire;
|
||||
DROP INDEX IF EXISTS idx_intent_plans_active_scope;
|
||||
DROP INDEX IF EXISTS uq_intent_plans_one_active_write;
|
||||
DROP INDEX IF EXISTS uq_intent_plans_turn;
|
||||
DROP TABLE IF EXISTS intent_plans;
|
||||
@@ -0,0 +1,41 @@
|
||||
-- +goose Up
|
||||
-- U4: idempotent projection outcomes and only-forward plan shadow. Cards/SSE read shadow; PG plans remain SSOT.
|
||||
|
||||
CREATE TABLE IF NOT EXISTS intent_plan_projections (
|
||||
source_event_id TEXT PRIMARY KEY,
|
||||
plan_id TEXT NOT NULL,
|
||||
revision BIGINT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
step_id TEXT NOT NULL DEFAULT '',
|
||||
environment TEXT NOT NULL,
|
||||
project_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
session_id TEXT NOT NULL,
|
||||
summary_ref TEXT NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plan_projections_plan
|
||||
ON intent_plan_projections (plan_id, revision);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS intent_plan_shadow (
|
||||
plan_id TEXT PRIMARY KEY,
|
||||
revision BIGINT NOT NULL,
|
||||
status TEXT NOT NULL,
|
||||
step_id TEXT NOT NULL DEFAULT '',
|
||||
environment TEXT NOT NULL,
|
||||
project_id BIGINT NOT NULL,
|
||||
user_id BIGINT NOT NULL,
|
||||
session_id TEXT NOT NULL,
|
||||
summary_ref TEXT NOT NULL DEFAULT '',
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_intent_plan_shadow_scope
|
||||
ON intent_plan_shadow (environment, project_id, session_id, user_id);
|
||||
|
||||
-- +goose Down
|
||||
DROP INDEX IF EXISTS idx_intent_plan_shadow_scope;
|
||||
DROP TABLE IF EXISTS intent_plan_shadow;
|
||||
DROP INDEX IF EXISTS idx_intent_plan_projections_plan;
|
||||
DROP TABLE IF EXISTS intent_plan_projections;
|
||||
@@ -0,0 +1,36 @@
|
||||
-- +goose Up
|
||||
-- Retire goose-seeded demo projects (6001–6010) and their chat sessions
|
||||
-- so they no longer appear in default lists. Data retained for audit;
|
||||
-- status flips to demo_retired (reversible with Down).
|
||||
BEGIN;
|
||||
|
||||
UPDATE projects
|
||||
SET status = 'demo_retired',
|
||||
updated_at = now()
|
||||
WHERE id BETWEEN 6001 AND 6010
|
||||
AND status <> 'demo_retired';
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'demo_retired',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status <> 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- +goose Down
|
||||
BEGIN;
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'active',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status = 'demo_retired';
|
||||
|
||||
UPDATE projects
|
||||
SET status = 'active',
|
||||
updated_at = now()
|
||||
WHERE id BETWEEN 6001 AND 6010
|
||||
AND status = 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- +goose Up
|
||||
-- Retire chat sessions for goose-seeded demo projects (6001–6010).
|
||||
-- Complements 00046 (projects); needed when 00046 already applied before
|
||||
-- session retirement was added to that file.
|
||||
BEGIN;
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'demo_retired',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status <> 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- +goose Down
|
||||
BEGIN;
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'active',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status = 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- +goose Up
|
||||
-- Retire chat sessions for goose-seeded demo projects (6001–6010).
|
||||
-- Complements 00046 (projects); needed when 00046 already applied before
|
||||
-- session retirement was added to that file.
|
||||
BEGIN;
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'demo_retired',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status <> 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- +goose Down
|
||||
BEGIN;
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'active',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status = 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,36 @@
|
||||
-- +goose Up
|
||||
-- Retire goose-seeded demo projects (6001–6010) and their chat sessions
|
||||
-- so they no longer appear in default lists. Data retained for audit;
|
||||
-- status flips to demo_retired (reversible with Down).
|
||||
BEGIN;
|
||||
|
||||
UPDATE projects
|
||||
SET status = 'demo_retired',
|
||||
updated_at = now()
|
||||
WHERE id BETWEEN 6001 AND 6010
|
||||
AND status <> 'demo_retired';
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'demo_retired',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status <> 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- +goose Down
|
||||
BEGIN;
|
||||
|
||||
UPDATE chat_sessions
|
||||
SET status = 'active',
|
||||
updated_at = now()
|
||||
WHERE project_id BETWEEN 6001 AND 6010
|
||||
AND status = 'demo_retired';
|
||||
|
||||
UPDATE projects
|
||||
SET status = 'active',
|
||||
updated_at = now()
|
||||
WHERE id BETWEEN 6001 AND 6010
|
||||
AND status = 'demo_retired';
|
||||
|
||||
COMMIT;
|
||||
@@ -87,6 +87,7 @@ services:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
ENV: test
|
||||
SEED_DEMO_USERS: "false"
|
||||
HTTP_ADDR: ":${HTTP_PORT:-8081}"
|
||||
HTTP_PORT: "${HTTP_PORT:-8081}"
|
||||
HTTP_HOST: "0.0.0.0"
|
||||
|
||||
@@ -99,6 +99,8 @@ func MaterializeTargets(workDir string, targets []string, incoming map[string][]
|
||||
if err := rejectSymlinkEscape(workDir, dest); err != nil {
|
||||
return collected, err
|
||||
}
|
||||
// Container-written files may be root-owned; make writable before overwrite.
|
||||
_ = os.Chmod(dest, 0o666)
|
||||
if err := os.WriteFile(dest, body, 0o644); err != nil {
|
||||
return collected, err
|
||||
}
|
||||
|
||||
+40
-27
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +12,7 @@ import (
|
||||
"chat-agent-system/internal/app/chatflow"
|
||||
"chat-agent-system/internal/app/docflow"
|
||||
"chat-agent-system/internal/app/docnotify"
|
||||
"chat-agent-system/internal/app/intentflow"
|
||||
"chat-agent-system/internal/app/stageflow"
|
||||
"chat-agent-system/internal/app/uow"
|
||||
"chat-agent-system/internal/artifactvault"
|
||||
@@ -43,33 +45,34 @@ const defaultReminderPollInterval = 15 * time.Minute
|
||||
// Runtime is the unique composition root. cmd/server, tests and workers
|
||||
// construct it once; HTTP adapters must not re-wire domain services.
|
||||
type Runtime struct {
|
||||
Cfg *config.Config
|
||||
Biz *bizdev.Service
|
||||
Engine *coordinator.CoordinatorEngine
|
||||
Auth *auth.Service
|
||||
PW *projectworkflow.Service
|
||||
TaskRuns *taskrun.Manager
|
||||
Authorizer *authz.Authorizer
|
||||
Authz *authz.Service
|
||||
WFDef *workflowdef.Service
|
||||
Inst *projectinstance.Service
|
||||
Notify *notification.Service
|
||||
Resolver *workspace.Resolver
|
||||
WSCap *workspace.Capability
|
||||
Commands *taskrun.Commands
|
||||
Rec intent.Recognizer
|
||||
Stageflow *stageflow.UseCase
|
||||
DocNotify *docnotify.Subscriber
|
||||
ChatLog chatflow.ChatLog
|
||||
Assembler chatflow.ContextAssembler
|
||||
Docflow *docflow.Commands
|
||||
Pool *pgxpool.Pool
|
||||
Gov *docgov.GovernanceEngine
|
||||
Rev *docrevision.Service
|
||||
Ctx *ctxmgr.ContextManager
|
||||
CAS *storage.CAS
|
||||
FreeDoc *freedoc.Service
|
||||
KB *kb.Client
|
||||
Cfg *config.Config
|
||||
Biz *bizdev.Service
|
||||
Engine *coordinator.CoordinatorEngine
|
||||
Auth *auth.Service
|
||||
PW *projectworkflow.Service
|
||||
TaskRuns *taskrun.Manager
|
||||
Authorizer *authz.Authorizer
|
||||
Authz *authz.Service
|
||||
WFDef *workflowdef.Service
|
||||
Inst *projectinstance.Service
|
||||
Notify *notification.Service
|
||||
Resolver *workspace.Resolver
|
||||
WSCap *workspace.Capability
|
||||
Commands *taskrun.Commands
|
||||
Rec intent.Recognizer
|
||||
Stageflow *stageflow.UseCase
|
||||
DocNotify *docnotify.Subscriber
|
||||
ChatLog chatflow.ChatLog
|
||||
Assembler chatflow.ContextAssembler
|
||||
Docflow *docflow.Commands
|
||||
IntentPlans *intentflow.Plans
|
||||
Pool *pgxpool.Pool
|
||||
Gov *docgov.GovernanceEngine
|
||||
Rev *docrevision.Service
|
||||
Ctx *ctxmgr.ContextManager
|
||||
CAS *storage.CAS
|
||||
FreeDoc *freedoc.Service
|
||||
KB *kb.Client
|
||||
|
||||
mu sync.Mutex
|
||||
running bool
|
||||
@@ -190,6 +193,16 @@ func Assemble(cfg *config.Config, svc *bizdev.Service) (*Runtime, error) {
|
||||
if pool != nil {
|
||||
rt.Docflow.UoW = uow.NewPG(pool)
|
||||
rt.Docflow.Events = events.PGSink{}
|
||||
livePI := cfg != nil && strings.TrimSpace(cfg.PiAgentRunnerURL) != ""
|
||||
taskOwner := NewTaskRunAdapter()
|
||||
taskOwner.Starter = LiveTaskStarter(taskMgr, livePI)
|
||||
rt.IntentPlans = intentflow.NewPlans(rt.Docflow.UoW, intentflow.NewRepository(), intentflow.Options{
|
||||
Owner: intentflow.OwnerMux{
|
||||
Query: intentflow.QueryGuard{Inner: intentflow.NewFakeActionOwner()},
|
||||
Task: taskOwner,
|
||||
},
|
||||
Events: events.PGSink{},
|
||||
})
|
||||
}
|
||||
svc.SetAgentMaterializer(rt.Docflow)
|
||||
rt.bindDocumentNotify()
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
package intentflow_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/app/intentflow"
|
||||
)
|
||||
|
||||
func TestConfirmDeniedDoesNotMutatePlan(t *testing.T) {
|
||||
p, _, owner := testPlans()
|
||||
ctx := context.Background()
|
||||
created, err := p.CreatePlan(ctx, draft("digest-a"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
owner.Denied = true
|
||||
_, err = p.DecidePlan(ctx, intentflow.DecisionCommand{
|
||||
Principal: principal(), PlanID: created.PlanID, ExpectedRevision: created.Revision,
|
||||
DecisionNonce: "n-deny", DecisionDigest: "d-deny", Kind: intentflow.DecisionConfirm,
|
||||
})
|
||||
if !errors.Is(err, intentflow.ErrPlanActionForbidden) {
|
||||
t.Fatalf("want forbidden, got %v", err)
|
||||
}
|
||||
got, err := p.GetPlan(ctx, principal(), created.PlanID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.Revision != created.Revision || got.Status != intentflow.PlanAwaitingConfirmation {
|
||||
t.Fatalf("confirm must be side-effect free on deny: %+v", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResourceVersionConflictOnConfirm(t *testing.T) {
|
||||
p, _, owner := testPlans()
|
||||
ctx := context.Background()
|
||||
cmd := draft("digest-ver")
|
||||
cmd.Steps[1].ExpectedResourceVersion = "v1"
|
||||
created, err := p.CreatePlan(ctx, cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
owner.RequiredVersion = map[string]string{"task.run": "v2"}
|
||||
_, err = p.DecidePlan(ctx, intentflow.DecisionCommand{
|
||||
Principal: principal(), PlanID: created.PlanID, ExpectedRevision: created.Revision,
|
||||
DecisionNonce: "n-ver", DecisionDigest: "d-ver", Kind: intentflow.DecisionConfirm,
|
||||
})
|
||||
if !errors.Is(err, intentflow.ErrPlanActionVersionConflict) {
|
||||
t.Fatalf("want version conflict, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevokeBetweenConfirmAndExecute(t *testing.T) {
|
||||
p, _, owner := testPlans()
|
||||
ctx := context.Background()
|
||||
created, err := p.CreatePlan(ctx, draft("digest-rev"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
confirmed, err := p.DecidePlan(ctx, intentflow.DecisionCommand{
|
||||
Principal: principal(), PlanID: created.PlanID, ExpectedRevision: created.Revision,
|
||||
DecisionNonce: "n-ok", DecisionDigest: "d-ok", Kind: intentflow.DecisionConfirm,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
owner.Denied = true
|
||||
stepID := confirmed.Steps[0].StepID
|
||||
claimed, err := p.ClaimStep(ctx, "w1", confirmed.PlanID, stepID)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := p.ExecuteClaimed(ctx, claimed); !errors.Is(err, intentflow.ErrPlanActionForbidden) {
|
||||
t.Fatalf("revoked execute must fail closed, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEditBumpsRevisionAndInvalidatesOldCard(t *testing.T) {
|
||||
p, _, _ := testPlans()
|
||||
ctx := context.Background()
|
||||
created, err := p.CreatePlan(ctx, draft("digest-edit"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
edited, err := p.DecidePlan(ctx, intentflow.DecisionCommand{
|
||||
Principal: principal(), PlanID: created.PlanID, ExpectedRevision: created.Revision,
|
||||
DecisionNonce: "n-edit", DecisionDigest: "d-edit", Kind: intentflow.DecisionEdit,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if edited.Revision <= created.Revision {
|
||||
t.Fatalf("edit must bump revision, got %d", edited.Revision)
|
||||
}
|
||||
if edited.Status != intentflow.PlanAwaitingConfirmation {
|
||||
t.Fatalf("edit stays awaiting, got %s", edited.Status)
|
||||
}
|
||||
_, err = p.DecidePlan(ctx, intentflow.DecisionCommand{
|
||||
Principal: principal(), PlanID: created.PlanID, ExpectedRevision: created.Revision,
|
||||
DecisionNonce: "n-old", DecisionDigest: "d-old", Kind: intentflow.DecisionConfirm,
|
||||
})
|
||||
if !errors.Is(err, intentflow.ErrPlanStaleRevision) {
|
||||
t.Fatalf("old card must be stale, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIllegalPartialConfirmMissingDependency(t *testing.T) {
|
||||
p, _, _ := testPlans()
|
||||
ctx := context.Background()
|
||||
cmd := draft("digest-dep")
|
||||
cmd.Steps[1].DependsOn = []string{"stp_missing"}
|
||||
created, err := p.CreatePlan(ctx, cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
writeID := created.Steps[1].StepID
|
||||
_, err = p.DecidePlan(ctx, intentflow.DecisionCommand{
|
||||
Principal: principal(), PlanID: created.PlanID, ExpectedRevision: created.Revision,
|
||||
DecisionNonce: "n-part", DecisionDigest: "d-part", Kind: intentflow.DecisionConfirm,
|
||||
StepIDs: []string{writeID},
|
||||
})
|
||||
if !errors.Is(err, intentflow.ErrPlanDependencyInvalid) {
|
||||
t.Fatalf("partial without closure must be invalid, got %v", err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Package intentflow owns the multi-intent plan lifecycle.
|
||||
//
|
||||
// It is the only application entry for proposing, confirming, recovering, and
|
||||
// advancing persistent plans. Callers (chat/server) must depend on the Service
|
||||
// interface and PlanView projection, not on the store, pool, or action-owner
|
||||
// engines.
|
||||
//
|
||||
// Hard rules:
|
||||
// - Confirmation is not authorization; each step re-checks the current principal.
|
||||
// - PostgreSQL plan/step/decision rows are authoritative; cards and SSE are projections.
|
||||
// - internal/intent stays a pure rule module (intent -> maturity).
|
||||
// - This package must not import docgov, taskrun, coordinator, or server.
|
||||
// - Only the owner repository unwraps pgx via app/uow (see unwrap_owners).
|
||||
package intentflow
|
||||
@@ -0,0 +1,122 @@
|
||||
package intentflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/app/uow"
|
||||
"chat-agent-system/internal/events"
|
||||
)
|
||||
|
||||
// EventSink is the Track E outbox port. Production uses events.PGSink.
|
||||
type EventSink interface {
|
||||
Append(ctx context.Context, env events.Envelope, consumers []string) error
|
||||
}
|
||||
|
||||
// CardProjector is the ctxmgr-facing port. Command UoW must not call it;
|
||||
// projection consumers project cards after the plan is committed.
|
||||
type CardProjector interface {
|
||||
ProjectCard(ctx context.Context, card CardProjection) error
|
||||
}
|
||||
|
||||
// CardProjection is the desensitized fact a chat card may show.
|
||||
type CardProjection struct {
|
||||
Principal Principal
|
||||
PlanID string
|
||||
Revision int64
|
||||
Status PlanStatus
|
||||
SummaryRef string
|
||||
}
|
||||
|
||||
type planFact struct {
|
||||
PlanID string `json:"plan_id"`
|
||||
Revision int64 `json:"revision"`
|
||||
Status string `json:"status"`
|
||||
Environment string `json:"environment"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
UserID int64 `json:"user_id"`
|
||||
SessionID string `json:"session_id"`
|
||||
SummaryRef string `json:"summary_ref"`
|
||||
StepID string `json:"step_id,omitempty"`
|
||||
}
|
||||
|
||||
func (p *Plans) withTx(ctx context.Context, fn func(ctx context.Context, scope uow.TxScope) error) error {
|
||||
if p == nil || p.uow == nil {
|
||||
return fmt.Errorf("intentflow: unit of work required")
|
||||
}
|
||||
return p.uow.Within(ctx, func(scope uow.TxScope) error {
|
||||
return fn(uow.WithScope(ctx, scope), scope)
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Plans) emitFact(ctx context.Context, plan *Plan, stepID string, now time.Time) error {
|
||||
if p == nil || p.events == nil || plan == nil {
|
||||
return nil
|
||||
}
|
||||
name := events.EventIntentPlanAwaiting
|
||||
if stepID != "" {
|
||||
name = events.EventIntentPlanStepChanged
|
||||
} else {
|
||||
switch plan.Status {
|
||||
case PlanCompleted, PlanCancelled, PlanExpired, PlanFailed, PlanSuperseded:
|
||||
name = events.EventIntentPlanCompleted
|
||||
}
|
||||
}
|
||||
fact := planFact{
|
||||
PlanID: plan.PlanID,
|
||||
Revision: plan.Revision,
|
||||
Status: string(plan.Status),
|
||||
Environment: plan.Principal.Environment,
|
||||
ProjectID: plan.Principal.ProjectID,
|
||||
UserID: plan.Principal.UserID,
|
||||
SessionID: plan.Principal.SessionID,
|
||||
SummaryRef: plan.SafeSummary,
|
||||
StepID: stepID,
|
||||
}
|
||||
body, err := json.Marshal(fact)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := AssertPlanPayload(name, body); err != nil {
|
||||
return err
|
||||
}
|
||||
eventID := fmt.Sprintf("intent-plan:%s:%s:%d:%s", plan.PlanID, name, plan.Revision, stepID)
|
||||
env := events.Envelope{
|
||||
EventID: eventID, EventName: name, SchemaVersion: events.EnvelopeSchema,
|
||||
Environment: plan.Principal.Environment, ProjectID: plan.Principal.ProjectID,
|
||||
AggregateType: "intent_plan", AggregateID: plan.PlanID, AggregateVersion: plan.Revision,
|
||||
ActorRef: fmt.Sprintf("user:%d", plan.Principal.UserID), IdempotencyKey: eventID,
|
||||
PayloadDigest: events.Digest(body), Producer: "app/intentflow",
|
||||
OccurredAt: now, Payload: body,
|
||||
}
|
||||
return p.events.Append(ctx, env, events.LiveConsumers(name))
|
||||
}
|
||||
|
||||
func AssertPlanPayload(eventName string, body []byte) error {
|
||||
var raw map[string]any
|
||||
if err := json.Unmarshal(body, &raw); err != nil {
|
||||
return err
|
||||
}
|
||||
allowed := map[string]struct{}{}
|
||||
for _, c := range events.StaticContracts() {
|
||||
if c.EventName != eventName {
|
||||
continue
|
||||
}
|
||||
for _, f := range c.PayloadFields {
|
||||
allowed[f] = struct{}{}
|
||||
}
|
||||
}
|
||||
for k := range raw {
|
||||
if _, ok := allowed[k]; !ok {
|
||||
return fmt.Errorf("intentflow: payload field %q not in %s contract", k, eventName)
|
||||
}
|
||||
for _, bad := range []string{"prompt", "slots", "permissions", "result", "input"} {
|
||||
if k == bad {
|
||||
return fmt.Errorf("intentflow: sensitive payload field %s", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package intentflow_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
"chat-agent-system/internal/app/intentflow"
|
||||
"chat-agent-system/internal/events"
|
||||
)
|
||||
|
||||
func TestCreatePlanEmitsAwaitingInput(t *testing.T) {
|
||||
sink := &intentflow.MemorySink{}
|
||||
proj := intentflow.NewProjector()
|
||||
now, opts, _ := testClock()
|
||||
opts.Events = sink
|
||||
p := intentflow.NewPlans(&intentflow.SerialUoW{}, intentflow.NewMemoryStore(), opts)
|
||||
ctx := context.Background()
|
||||
view, err := p.CreatePlan(ctx, draft("digest-a"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
envs := sink.All()
|
||||
if len(envs) != 1 || envs[0].EventName != events.EventIntentPlanAwaiting {
|
||||
t.Fatalf("want one awaiting_input, got %#v", envs)
|
||||
}
|
||||
if envs[0].Producer != "app/intentflow" {
|
||||
t.Fatalf("producer %s", envs[0].Producer)
|
||||
}
|
||||
var payload map[string]any
|
||||
if err := json.Unmarshal(envs[0].Payload, &payload); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, bad := range []string{"prompt", "slots", "permissions", "result", "input"} {
|
||||
if _, ok := payload[bad]; ok {
|
||||
t.Fatalf("sensitive field %s leaked", bad)
|
||||
}
|
||||
}
|
||||
if err := proj.ApplyEnvelope(envs[0]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := proj.ApplyEnvelope(envs[0]); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sh, ok := proj.VisibleShadow(principal(), view.PlanID)
|
||||
if !ok || sh.Revision != 1 {
|
||||
t.Fatalf("shadow %+v ok=%v", sh, ok)
|
||||
}
|
||||
other := principal()
|
||||
other.UserID = 99
|
||||
if _, ok := proj.VisibleShadow(other, view.PlanID); ok {
|
||||
t.Fatal("cross-user shadow must be hidden")
|
||||
}
|
||||
got, err := p.GetPlan(ctx, principal(), view.PlanID)
|
||||
if err != nil || got == nil {
|
||||
t.Fatalf("SSOT GET must work without card success: %v", err)
|
||||
}
|
||||
_ = now
|
||||
}
|
||||
|
||||
func TestProjectionOnlyForwardAndForgedRejected(t *testing.T) {
|
||||
proj := intentflow.NewProjector()
|
||||
newer := events.Envelope{
|
||||
EventID: "e2", EventName: events.EventIntentPlanAwaiting, SchemaVersion: events.EnvelopeSchema,
|
||||
Environment: "dev", ProjectID: 42, AggregateType: "intent_plan", AggregateID: "pln_x",
|
||||
AggregateVersion: 2, Producer: "app/intentflow", Payload: []byte(`{"plan_id":"pln_x","revision":2,"status":"executing","environment":"dev","project_id":42,"user_id":7,"session_id":"sess-u4","summary_ref":""}`),
|
||||
}
|
||||
newer.PayloadDigest = events.Digest(newer.Payload)
|
||||
older := newer
|
||||
older.EventID = "e1"
|
||||
older.AggregateVersion = 1
|
||||
older.Payload = []byte(`{"plan_id":"pln_x","revision":1,"status":"awaiting_confirmation","environment":"dev","project_id":42,"user_id":7,"session_id":"sess-u4","summary_ref":""}`)
|
||||
older.PayloadDigest = events.Digest(older.Payload)
|
||||
if err := proj.ApplyEnvelope(newer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := proj.ApplyEnvelope(older); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sh, _ := proj.Shadow("pln_x")
|
||||
if sh.Revision != 2 || sh.Status != "executing" {
|
||||
t.Fatalf("low revision must not overwrite: %+v", sh)
|
||||
}
|
||||
forged := newer
|
||||
forged.EventID = "e3"
|
||||
forged.Producer = "forged"
|
||||
forged.PayloadDigest = events.Digest(forged.Payload)
|
||||
if err := proj.ApplyEnvelope(forged); !errors.Is(err, events.ErrIntegrityFailure) {
|
||||
t.Fatalf("forged producer: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAwaitingPayloadGolden(t *testing.T) {
|
||||
_, file, _, _ := runtime.Caller(0)
|
||||
raw, err := os.ReadFile(filepath.Join(filepath.Dir(file), "testdata", "intent-plan-awaiting-v1.json"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := intentflow.AssertPlanPayload(events.EventIntentPlanAwaiting, raw); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package intentflow
|
||||
|
||||
import "errors"
|
||||
|
||||
// Sentinel errors use the public API error codes from the design §9.
|
||||
var (
|
||||
ErrPlanNotFoundOrHidden = errors.New("PLAN_NOT_FOUND_OR_HIDDEN")
|
||||
ErrPlanStaleRevision = errors.New("PLAN_STALE_REVISION")
|
||||
ErrPlanExpired = errors.New("PLAN_EXPIRED")
|
||||
ErrPlanDecisionConflict = errors.New("PLAN_DECISION_CONFLICT")
|
||||
ErrPlanDependencyInvalid = errors.New("PLAN_DEPENDENCY_INVALID")
|
||||
ErrPlanActionForbidden = errors.New("PLAN_ACTION_FORBIDDEN")
|
||||
ErrPlanActionVersionConflict = errors.New("PLAN_ACTION_VERSION_CONFLICT")
|
||||
ErrUnauthenticated = errors.New("ERR_UNAUTHENTICATED")
|
||||
)
|
||||
|
||||
var errTurnExists = errors.New("intentflow: turn exists")
|
||||
|
||||
// ErrorCode returns the stable machine code for a sentinel, or empty.
|
||||
func ErrorCode(err error) string {
|
||||
switch {
|
||||
case errors.Is(err, ErrPlanNotFoundOrHidden):
|
||||
return "PLAN_NOT_FOUND_OR_HIDDEN"
|
||||
case errors.Is(err, ErrPlanStaleRevision):
|
||||
return "PLAN_STALE_REVISION"
|
||||
case errors.Is(err, ErrPlanExpired):
|
||||
return "PLAN_EXPIRED"
|
||||
case errors.Is(err, ErrPlanDecisionConflict):
|
||||
return "PLAN_DECISION_CONFLICT"
|
||||
case errors.Is(err, ErrPlanDependencyInvalid):
|
||||
return "PLAN_DEPENDENCY_INVALID"
|
||||
case errors.Is(err, ErrPlanActionForbidden):
|
||||
return "PLAN_ACTION_FORBIDDEN"
|
||||
case errors.Is(err, ErrPlanActionVersionConflict):
|
||||
return "PLAN_ACTION_VERSION_CONFLICT"
|
||||
case errors.Is(err, ErrUnauthenticated):
|
||||
return "ERR_UNAUTHENTICATED"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package intentflow
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// PlanTier is the intentflow rollout switch. It must not be stored on
|
||||
// intent.ActionSpec or intent.FeatureFlags.
|
||||
type PlanTier string
|
||||
|
||||
const (
|
||||
TierLegacy PlanTier = "legacy"
|
||||
TierShadow PlanTier = "shadow"
|
||||
TierAutoRead PlanTier = "auto_read"
|
||||
TierConfirm PlanTier = "confirm"
|
||||
TierFull PlanTier = "full"
|
||||
)
|
||||
|
||||
type FeatureFlags struct {
|
||||
PlanTier PlanTier
|
||||
}
|
||||
|
||||
var (
|
||||
flagsMu sync.RWMutex
|
||||
activeFlags = defaultFeatureFlags()
|
||||
)
|
||||
|
||||
func defaultFeatureFlags() FeatureFlags {
|
||||
return FeatureFlags{PlanTier: parsePlanTier(os.Getenv("MULTI_INTENT_PLAN_TIER"))}
|
||||
}
|
||||
|
||||
func parsePlanTier(raw string) PlanTier {
|
||||
switch strings.ToLower(strings.TrimSpace(raw)) {
|
||||
case "", "legacy":
|
||||
return TierLegacy
|
||||
case "shadow":
|
||||
return TierShadow
|
||||
case "auto_read", "autoread":
|
||||
return TierAutoRead
|
||||
case "confirm":
|
||||
return TierConfirm
|
||||
case "full":
|
||||
return TierFull
|
||||
default:
|
||||
return TierLegacy
|
||||
}
|
||||
}
|
||||
|
||||
func CurrentFeatureFlags() FeatureFlags {
|
||||
flagsMu.RLock()
|
||||
defer flagsMu.RUnlock()
|
||||
return activeFlags
|
||||
}
|
||||
|
||||
func SetFeatureFlagsForTest(f FeatureFlags) {
|
||||
flagsMu.Lock()
|
||||
activeFlags = f
|
||||
flagsMu.Unlock()
|
||||
}
|
||||
|
||||
func ResetFeatureFlagsForTest() {
|
||||
flagsMu.Lock()
|
||||
activeFlags = defaultFeatureFlags()
|
||||
flagsMu.Unlock()
|
||||
}
|
||||
|
||||
// Allows reports whether the current (or supplied) tier may activate a policy row.
|
||||
func (t PlanTier) Allows(min PlanTier) bool {
|
||||
return tierRank(t) >= tierRank(min)
|
||||
}
|
||||
|
||||
func tierRank(t PlanTier) int {
|
||||
switch t {
|
||||
case TierLegacy:
|
||||
return 0
|
||||
case TierShadow:
|
||||
return 1
|
||||
case TierAutoRead:
|
||||
return 2
|
||||
case TierConfirm:
|
||||
return 3
|
||||
case TierFull:
|
||||
return 4
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package intentflow
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDefaultPlanTierIsLegacy(t *testing.T) {
|
||||
t.Setenv("MULTI_INTENT_PLAN_TIER", "")
|
||||
ResetFeatureFlagsForTest()
|
||||
if got := CurrentFeatureFlags().PlanTier; got != TierLegacy {
|
||||
t.Fatalf("default tier = %s, want legacy", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownPlanTierFailsClosedToLegacy(t *testing.T) {
|
||||
if parsePlanTier("definitely-not-a-tier") != TierLegacy {
|
||||
t.Fatal("unknown MULTI_INTENT_PLAN_TIER must fail closed to legacy")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanTierIndependentOfLegacyMultiIntentFlag(t *testing.T) {
|
||||
t.Setenv("MULTI_INTENT_ENABLED", "true")
|
||||
t.Setenv("MULTI_INTENT_PLAN_TIER", "")
|
||||
ResetFeatureFlagsForTest()
|
||||
if CurrentFeatureFlags().PlanTier != TierLegacy {
|
||||
t.Fatal("MULTI_INTENT_ENABLED must not promote plan tier")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanTierEnv(t *testing.T) {
|
||||
if parsePlanTier("shadow") != TierShadow {
|
||||
t.Fatal("shadow")
|
||||
}
|
||||
if parsePlanTier("auto_read") != TierAutoRead {
|
||||
t.Fatal("auto_read")
|
||||
}
|
||||
if parsePlanTier("confirm") != TierConfirm {
|
||||
t.Fatal("confirm")
|
||||
}
|
||||
if parsePlanTier("full") != TierFull {
|
||||
t.Fatal("full")
|
||||
}
|
||||
if !TierConfirm.Allows(TierAutoRead) || TierShadow.Allows(TierConfirm) {
|
||||
t.Fatal("tier rank")
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrorCodes(t *testing.T) {
|
||||
if ErrorCode(ErrPlanNotFoundOrHidden) != "PLAN_NOT_FOUND_OR_HIDDEN" {
|
||||
t.Fatal(ErrorCode(ErrPlanNotFoundOrHidden))
|
||||
}
|
||||
if ErrorCode(ErrPlanStaleRevision) != "PLAN_STALE_REVISION" {
|
||||
t.Fatal("stale")
|
||||
}
|
||||
if ErrorCode(ErrPlanExpired) != "PLAN_EXPIRED" {
|
||||
t.Fatal("expired")
|
||||
}
|
||||
if ErrorCode(ErrPlanDecisionConflict) != "PLAN_DECISION_CONFLICT" {
|
||||
t.Fatal("conflict")
|
||||
}
|
||||
if ErrorCode(ErrPlanDependencyInvalid) != "PLAN_DEPENDENCY_INVALID" {
|
||||
t.Fatal("dep")
|
||||
}
|
||||
if ErrorCode(ErrPlanActionForbidden) != "PLAN_ACTION_FORBIDDEN" {
|
||||
t.Fatal("forbidden")
|
||||
}
|
||||
if ErrorCode(ErrPlanActionVersionConflict) != "PLAN_ACTION_VERSION_CONFLICT" {
|
||||
t.Fatal("version")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRESTPathsFrozen(t *testing.T) {
|
||||
if PathActivePlan != "/api/v1/intent-plans/active" {
|
||||
t.Fatal(PathActivePlan)
|
||||
}
|
||||
if PathPlanByID != "/api/v1/intent-plans/{plan_id}" {
|
||||
t.Fatal(PathPlanByID)
|
||||
}
|
||||
if PathPlanDecisions != "/api/v1/intent-plans/{plan_id}/decisions" {
|
||||
t.Fatal(PathPlanDecisions)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
package intentflow
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/app/uow"
|
||||
)
|
||||
|
||||
type serialScope struct{ ctx context.Context }
|
||||
|
||||
func (s serialScope) Context() context.Context { return s.ctx }
|
||||
|
||||
// SerialUoW serializes commands. Memory tests use it so CAS races have one winner.
|
||||
type SerialUoW struct{ mu sync.Mutex }
|
||||
|
||||
func (s *SerialUoW) Within(ctx context.Context, fn func(uow.TxScope) error) error {
|
||||
if s == nil {
|
||||
return fmt.Errorf("intentflow: serial uow required")
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return fn(serialScope{ctx: ctx})
|
||||
}
|
||||
|
||||
type MemoryStore struct {
|
||||
mu sync.Mutex
|
||||
plans map[string]*Plan
|
||||
turn map[string]string
|
||||
decisions map[string]*Decision
|
||||
}
|
||||
|
||||
func NewMemoryStore() *MemoryStore {
|
||||
return &MemoryStore{
|
||||
plans: map[string]*Plan{},
|
||||
turn: map[string]string{},
|
||||
decisions: map[string]*Decision{},
|
||||
}
|
||||
}
|
||||
|
||||
func turnKey(env, session, turn string) string {
|
||||
return env + "\x1f" + session + "\x1f" + turn
|
||||
}
|
||||
|
||||
func nonceKey(planID, nonce string) string {
|
||||
return planID + "\x1f" + nonce
|
||||
}
|
||||
|
||||
func (m *MemoryStore) InsertPlan(ctx context.Context, scope uow.TxScope, plan *Plan) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if plan == nil || plan.PlanID == "" {
|
||||
return fmt.Errorf("intentflow: plan required")
|
||||
}
|
||||
tk := turnKey(plan.Principal.Environment, plan.Principal.SessionID, plan.ClientTurnID)
|
||||
if existingID, ok := m.turn[tk]; ok {
|
||||
_ = existingID
|
||||
return errTurnExists
|
||||
}
|
||||
if plan.WritePlan && isActiveStatus(plan.Status) {
|
||||
for _, p := range m.plans {
|
||||
if sameScope(p.Principal, plan.Principal) && p.WritePlan && isActiveStatus(p.Status) {
|
||||
return uow.ErrBusy
|
||||
}
|
||||
}
|
||||
}
|
||||
cloned := clonePlan(plan)
|
||||
m.plans[plan.PlanID] = cloned
|
||||
m.turn[tk] = plan.PlanID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) GetPlan(ctx context.Context, scope uow.TxScope, planID string) (*Plan, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
p := m.plans[planID]
|
||||
if p == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return clonePlan(p), nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) GetPlanForUpdate(ctx context.Context, scope uow.TxScope, planID string) (*Plan, error) {
|
||||
return m.GetPlan(ctx, scope, planID)
|
||||
}
|
||||
|
||||
func (m *MemoryStore) GetByTurn(ctx context.Context, scope uow.TxScope, env, sessionID, clientTurnID string) (*Plan, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
id := m.turn[turnKey(env, sessionID, clientTurnID)]
|
||||
if id == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return clonePlan(m.plans[id]), nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) GetActiveWrite(ctx context.Context, scope uow.TxScope, p Principal) (*Plan, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
for _, plan := range m.plans {
|
||||
if sameScope(plan.Principal, p) && plan.WritePlan && isActiveStatus(plan.Status) {
|
||||
return clonePlan(plan), nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) GetActive(ctx context.Context, scope uow.TxScope, p Principal) (*Plan, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
var best *Plan
|
||||
for _, plan := range m.plans {
|
||||
if !sameScope(plan.Principal, p) || !isActiveStatus(plan.Status) {
|
||||
continue
|
||||
}
|
||||
if best == nil || plan.UpdatedAt.After(best.UpdatedAt) {
|
||||
cp := clonePlan(plan)
|
||||
best = cp
|
||||
}
|
||||
}
|
||||
return best, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) CASPlan(ctx context.Context, scope uow.TxScope, planID string, expectedRev int64, from []PlanStatus, to PlanStatus, now time.Time) (int64, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
p := m.plans[planID]
|
||||
if p == nil || p.Revision != expectedRev || !slices.Contains(from, p.Status) {
|
||||
return 0, nil
|
||||
}
|
||||
p.Status = to
|
||||
p.Revision++
|
||||
p.UpdatedAt = now
|
||||
return p.Revision, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) InsertDecision(ctx context.Context, scope uow.TxScope, d *Decision) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
k := nonceKey(d.PlanID, d.Nonce)
|
||||
if _, ok := m.decisions[k]; ok {
|
||||
return uow.ErrDigestConflict
|
||||
}
|
||||
cp := *d
|
||||
cp.StepIDs = slices.Clone(d.StepIDs)
|
||||
m.decisions[k] = &cp
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) GetDecisionByNonce(ctx context.Context, scope uow.TxScope, planID, nonce string) (*Decision, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
d := m.decisions[nonceKey(planID, nonce)]
|
||||
if d == nil {
|
||||
return nil, nil
|
||||
}
|
||||
cp := *d
|
||||
cp.StepIDs = slices.Clone(d.StepIDs)
|
||||
return &cp, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) ReplaceSteps(ctx context.Context, scope uow.TxScope, planID string, steps []Step) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
p := m.plans[planID]
|
||||
if p == nil {
|
||||
return fmt.Errorf("intentflow: plan %s not found", planID)
|
||||
}
|
||||
p.Steps = cloneSteps(steps)
|
||||
p.UpdatedAt = time.Now().UTC()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) ClaimStep(ctx context.Context, scope uow.TxScope, planID, stepID, worker string, until, now time.Time, idempotencyKey string) (*Step, int64, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
p := m.plans[planID]
|
||||
if p == nil {
|
||||
return nil, 0, nil
|
||||
}
|
||||
for i := range p.Steps {
|
||||
s := &p.Steps[i]
|
||||
if s.StepID != stepID {
|
||||
continue
|
||||
}
|
||||
claimable := s.Status == StepEligible ||
|
||||
(s.Status == StepRunning && (s.LeaseUntil == nil || s.LeaseUntil.Before(now)))
|
||||
if !claimable {
|
||||
return nil, 0, nil
|
||||
}
|
||||
p.LastFencingToken++
|
||||
s.Status = StepRunning
|
||||
s.LeaseOwner = worker
|
||||
untilCopy := until
|
||||
s.LeaseUntil = &untilCopy
|
||||
s.Attempt++
|
||||
s.Version++
|
||||
s.FencingToken = p.LastFencingToken
|
||||
if s.IdempotencyKey == "" {
|
||||
s.IdempotencyKey = idempotencyKey
|
||||
}
|
||||
s.UpdatedAt = now
|
||||
p.UpdatedAt = now
|
||||
return cloneStep(s), s.FencingToken, nil
|
||||
}
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) WriteStepReceipt(ctx context.Context, scope uow.TxScope, worker string, token int64, step Step, now time.Time) (bool, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
p := m.plans[step.PlanID]
|
||||
if p == nil {
|
||||
return false, nil
|
||||
}
|
||||
for i := range p.Steps {
|
||||
s := &p.Steps[i]
|
||||
if s.StepID != step.StepID {
|
||||
continue
|
||||
}
|
||||
if s.Status == StepSucceeded && s.ResultDigest == step.ResultDigest {
|
||||
return true, nil
|
||||
}
|
||||
if s.Status != StepRunning || s.LeaseOwner != worker || s.FencingToken != token {
|
||||
return false, nil
|
||||
}
|
||||
s.Status = StepSucceeded
|
||||
s.ResultRef = step.ResultRef
|
||||
s.ResultDigest = step.ResultDigest
|
||||
s.SafeSummary = step.SafeSummary
|
||||
s.LeaseOwner = ""
|
||||
s.LeaseUntil = nil
|
||||
s.Version++
|
||||
s.UpdatedAt = now
|
||||
p.UpdatedAt = now
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) ExpireWaiting(ctx context.Context, scope uow.TxScope, now time.Time) (int, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
n := 0
|
||||
for _, p := range m.plans {
|
||||
if !isWaitingStatus(p.Status) || !now.After(p.ExpiresAt) {
|
||||
continue
|
||||
}
|
||||
p.Status = PlanExpired
|
||||
p.Revision++
|
||||
p.UpdatedAt = now
|
||||
for i := range p.Steps {
|
||||
if p.Steps[i].Status == StepPending || p.Steps[i].Status == StepEligible {
|
||||
p.Steps[i].Status = StepCancelled
|
||||
p.Steps[i].UpdatedAt = now
|
||||
}
|
||||
}
|
||||
n++
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (m *MemoryStore) PurgeClosed(ctx context.Context, scope uow.TxScope, before time.Time) (int, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
n := 0
|
||||
for id, p := range m.plans {
|
||||
switch p.Status {
|
||||
case PlanCompleted, PlanFailed, PlanCancelled, PlanExpired, PlanSuperseded:
|
||||
default:
|
||||
continue
|
||||
}
|
||||
if !p.UpdatedAt.Before(before) {
|
||||
continue
|
||||
}
|
||||
delete(m.turn, turnKey(p.Principal.Environment, p.Principal.SessionID, p.ClientTurnID))
|
||||
for k, d := range m.decisions {
|
||||
if d.PlanID == id {
|
||||
delete(m.decisions, k)
|
||||
}
|
||||
}
|
||||
delete(m.plans, id)
|
||||
n++
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func sameScope(a, b Principal) bool {
|
||||
return a.Environment == b.Environment && a.ProjectID == b.ProjectID && a.SessionID == b.SessionID && a.UserID == b.UserID
|
||||
}
|
||||
|
||||
func clonePlan(p *Plan) *Plan {
|
||||
if p == nil {
|
||||
return nil
|
||||
}
|
||||
cp := *p
|
||||
cp.DisplaySnapshot = slices.Clone(p.DisplaySnapshot)
|
||||
cp.Steps = cloneSteps(p.Steps)
|
||||
return &cp
|
||||
}
|
||||
|
||||
func cloneSteps(in []Step) []Step {
|
||||
out := make([]Step, len(in))
|
||||
for i := range in {
|
||||
out[i] = *cloneStep(&in[i])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneStep(s *Step) *Step {
|
||||
cp := *s
|
||||
cp.Slots = slices.Clone(s.Slots)
|
||||
cp.DependsOn = slices.Clone(s.DependsOn)
|
||||
if s.LeaseUntil != nil {
|
||||
t := *s.LeaseUntil
|
||||
cp.LeaseUntil = &t
|
||||
}
|
||||
return &cp
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user