Compare commits

..
Author SHA1 Message Date
weichen 8c9a12d996 release-candidate: 汇集 dev 功能至 test 分支,准备长期实测 [Tag: rc-v1.0.0-beta.2] 2026-09-16 05:19:59 +00:00
weichen 50f800a409 merge: feature/matrix-deep-test-promote-test
Matrix deep-test evidence and CURRENT slot claim prior to test promote.
2026-09-16 05:18:52 +00:00
weichenandCursor 0743fb90ec docs(ops): advance integration slot to merging for test promote
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:18:52 +00:00
weichenandCursor 895d5f002a test(ops): capture matrix deep-test Wave 1–3 evidence artifacts
Automated short/module/governance-PG outputs plus live :8080 smoke and
PI typed-result sample for promote gate.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:18:52 +00:00
weichenandCursor 4f997a9438 docs(ops): register matrix deep-test claim on CURRENT
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:14:00 +00:00
weichenandCursor ef84d1d8f7 docs(ops): claim infra slot for matrix deep test and test promote
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 05:13:38 +00:00
weichen 4298701b2a merge: docs/archive-production-ready-gates 2026-09-16 04:16:03 +00:00
weichenandCursor 28d1512e6e docs(ops): archive completed production-ready gates short-term task
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:16:03 +00:00
weichen 4d048cc4a3 merge: docs/production-ready-flip
Flip SSOT production_ready=yes after release gates and main schema align.
2026-09-16 04:15:55 +00:00
weichenandCursor 1027026e7a docs(ops): flip production_ready=yes after B1–B4 gates and schema 47
Align FEATURE-MATRIX, gap-matrix, and CURRENT; main rebuilt to schema 47
with dev/test. Release blockers closed; backlog items remain partial/planned.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:15:55 +00:00
weichen 8dae227f8c merge: feature/pi-three-workflow-e2e
Release gates B2–B4 evidence, PI E2E harness fixes, and settings conflict recovery.
2026-09-16 04:14:07 +00:00
weichenandCursor 05a84e6677 fix(web): include nested error field in VERSION_CONFLICT unwrap typing
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:13:35 +00:00
weichenandCursor 23a5f6f589 docs(ops): claim integration slot for production-ready gate merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:12:09 +00:00
weichenandCursor 1f35593dcd docs(test): archive B2–B4 release-gate evidence and check gap boxes
PI three-workflow E2E, chat refresh+restart, and frontend conflict/
termination-preview reports; mark corresponding gap-matrix gates done.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichenandCursor 736857a292 fix(web): unwrap nested VERSION_CONFLICT business codes for settings recovery
HTTP envelope wraps PLAN_FROZEN/ERR_CONCURRENT_SWITCH; reload settings on
conflict so operators refresh instead of blind retry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichenandCursor 64ac437a90 fix(test): upsert project members before SavePlan in chat-refresh live
Duty assignees must be active members or activation path returns 400.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichenandCursor 3b80582123 fix(pi-agent): stabilize real PI three-workflow E2E harness
Use shared DATA_DIR permissions (umask/chmod) and drop obsolete sync
notify asserts so governance PG PI chains can complete on MiniMax runner.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 04:11:54 +00:00
weichen 3b56816f4e merge: fix/ci-governance-pg-members 2026-09-16 03:20:32 +00:00
weichenandCursor 56c85bba11 fix(ci): green governance PG on isolated TEST_DATABASE_URL
Add duty holders as project members, drop sync notification assert
after outbox cutover, and add an explicit CI governance PG step.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:20:32 +00:00
weichen eaffe3eb31 merge: docs/demo-seed-merge-closeout 2026-09-16 03:17:37 +00:00
weichenandCursor c8052c8882 docs(ops): close DEMO-DB-SEED after schema 47 migrate and smoke
Record npm/go gates, empty project 6357 docs=0, and release the
integration slot; gap-matrix DEMO-DB-SEED → PASS.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:17:37 +00:00
weichen 511012cede merge: fix/demo-chat-sessions-retire-00047 2026-09-16 03:14:59 +00:00
weichenandCursor c741d26eeb fix(db): add goose 00047 to retire demo project chat sessions
Dev already applied 00046 (projects only) before session retirement
was folded into that file; 00047 closes the gap idempotently.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:14:59 +00:00
weichen 0917f39f80 merge: fix/demo-data-pollution-web
Gate demo seeds, retire goose demo projects/sessions, reject stub in
main/prod, and respect SEED_DEMO_USERS=false.
2026-09-16 03:13:51 +00:00
weichenandCursor 765a418df1 docs(ops): claim integration slot for demo-data-pollution merge
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:13:51 +00:00
weichenandCursor 66c56324ad docs(ops): backlink 2026-09-15 audit and record review P0/P1 evidence
Cherry-picked SEED_DEMO_USERS separately; document npm test gate,
session retire in 00046, and P2 follow-ups.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:13:25 +00:00
weichen 53bb71adae fix(auth): respect SEED_DEMO_USERS=false to prevent re-seeding demo users 2026-09-16 03:12:31 +00:00
weichenandCursor fbda195b7f fix(db): retire demo chat sessions with projects in 00046
Extend unapplied migration to mark 6001–6010 sessions demo_retired
and filter them (and retired projects) out of ListChatSessions.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:12:25 +00:00
weichenandCursor a44df9280c fix(web): rewrite demoSeedIds tests for node:test npm gate
Vitest-style suite was caught by tsx --test and broke npm test.
Align with storage.test.ts and narrow vitest include to chat suites.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 03:11:36 +00:00
weichenandCursor 1e19f5c52f docs(test): archive demo seed pollution remediation evidence
Record systemic audit, wave plan status, gap-matrix blockers, and unit/
bundle scan results for the demo-data pollution fix.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichenandCursor 8a8197a4f2 fix(taskrun): reject stub backend in main/prod
Require ResolveBackendInEnv to deny stub (and empty stub fallback) when
env is main/prod so production cannot request simulated agent output.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichenandCursor bdc6415944 fix(db): retire goose-seeded demo projects from lists
Mark projects 6001–6010 as demo_retired and exclude them from default
project list queries so demo seeds no longer pollute real workspaces.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichenandCursor 855363fd60 fix(web): gate demo seeds and reclaim mock deliverables
Stop shipping hard-coded demo docs/projects into production builds,
drop local mock items on authoritative empty server lists, and purge
stale demo seed residue from localStorage on boot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:50:34 +00:00
weichen 2005a4ca0c merge: chore/release-multi-intent-u8-slot 2026-09-16 02:26:03 +00:00
weichenandCursor 8b228e2101 chore(ops): release the U8 integration slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:26:03 +00:00
weichen 50cf271b53 merge: feature/multi-intent-u8-task-generate 2026-09-16 02:24:39 +00:00
weichenandCursor bf55278740 docs(test): record U8 task generate adapter report
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:24:23 +00:00
weichenandCursor 2e99ee3661 feat(intentflow): route confirmed generate steps through a task adapter
Persist ComboNeedsConfirm plans at confirm tier without executing writes, then run task.run via OwnerMux and a stable idempotency key.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 02:24:23 +00:00
weichen aec374c5dc merge: chore/release-multi-intent-u7-slot 2026-09-16 01:42:42 +00:00
weichenandCursor ad3d10b72d chore(ops): release the U7 integration slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:42:42 +00:00
weichen 276ceb42b3 merge: feature/multi-intent-u7-auto-read 2026-09-16 01:40:07 +00:00
weichenandCursor fb19b63baf docs(test): record U7 auto_read query execution report
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:40:07 +00:00
weichenandCursor 702cf6f949 feat(intentflow): execute auto_read query plans from HandleTurn
Default legacy stays a no-op; QueryGuard refuses generate keys until U8.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:40:07 +00:00
weichen 5c4caa375e merge: chore/release-multi-intent-u6-slot 2026-09-16 01:11:28 +00:00
weichenandCursor c7677b09f6 chore(ops): release the U6 integration slot
Restore the U5 SSOT rows dropped during the U6 docs commit.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:11:28 +00:00
weichen b94873ab18 merge: feature/multi-intent-u6-web-cards 2026-09-16 01:09:05 +00:00
weichenandCursor ba713c266b docs(test): record U6 plan card web report
Keep Playwright dual-tab behind RUN_UI_ACCEPTANCE.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:09:05 +00:00
weichenandCursor 29bb63f766 feat(web): render PLAN_CONFIRM from PlanView without local AST writes
Plan actions post to the decision API and reconcile on 409 instead of mutating documents.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:09:05 +00:00
weichen 4044b68c9e merge: chore/release-multi-intent-u5-slot 2026-09-16 01:02:19 +00:00
weichenandCursor 0dd7a412c2 chore(ops): release the U5 integration slot
Drop accidental pycache from the docs commit and ignore Python bytecode.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:02:19 +00:00
weichen 741089eca3 merge: feature/multi-intent-u5-decision-api 2026-09-16 01:01:39 +00:00
weichenandCursor e16fb7eff2 docs(test): record U5 decision API and authorization report
Close the U5 checklist with HTTP scope negatives and same-nonce receipts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:01:39 +00:00
weichenandCursor 3d444fa5e4 feat(api): mount authenticated intent plan decision routes
Principal comes from the session and query scope; body identifiers are ignored and admins cannot skip membership.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:01:39 +00:00
weichenandCursor 08aa56b16c feat(intentflow): re-authorize steps before confirm and execute
Confirmation stays a command receipt; FakeActionOwner now fail-closes on revoke and resource version drift.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 01:01:39 +00:00
weichen f35d265721 merge: chore/release-multi-intent-u4-slot 2026-09-16 00:52:59 +00:00
weichenandCursor 131c86a919 chore(ops): release the U4 integration slot
U4 smoke (go vet + go test -short) passed; no shared-env rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:52:59 +00:00
weichen 839368198a merge: feature/multi-intent-u4-outbox-projection 2026-09-16 00:50:32 +00:00
weichenandCursor 46ee9fe647 chore(ops): occupy the U4 integration slot
Remove accidental promote-dev and pycache files from the U4 docs commit and hold the merge slot.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:50:26 +00:00
weichenandCursor 2755d916f4 docs(test): record U4 outbox projection report
Close the U4 checklist with golden payload and only-forward projection evidence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:46:09 +00:00
weichenandCursor c36d891b05 feat(intentflow): emit plan facts onto Track E outbox
Append awaiting/step/completed envelopes in the command UoW and project them without changing dispatcher leases.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:46:09 +00:00
weichenandCursor cf063f5727 feat(db): add intent plan projection shadow tables
Store idempotent event outcomes and an only-forward shadow without replacing plan SSOT.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:46:09 +00:00
weichenandCursor 1afd39c9e8 docs(ops): claim U4 intent plan outbox projection
Register the events mutex before appending intent.plan facts onto Track E.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 00:40:57 +00:00
weichen 0f656638eb merge: chore/release-multi-intent-u3-slot 2026-09-15 23:47:19 +00:00
weichenandCursor 223b2841d7 chore(ops): release the U3 integration slot
Smoke already passed on the feature branch; shared env stays on schema 43 until a planned rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:47:19 +00:00
weichen 26f1632a21 merge: feature/multi-intent-u3-intentflow-pg 2026-09-15 23:46:55 +00:00
weichenandCursor 4cfe6ff59d chore(ops): occupy the U3 integration slot
Hold the shared merge slot for the no-ff merge of the intentflow PG owner.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:46:55 +00:00
weichenandCursor b6956003d5 docs(test): record U3 intentflow PG CAS lease report
Close the U3 checklist with CAS/lease/fencing evidence while leaving chat routing on legacy.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:46:34 +00:00
weichenandCursor 1385002350 feat(app): assemble intentflow plan owner
Wire the composition root without letting chat or coordinator call CreatePlan yet.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:43:46 +00:00
weichenandCursor da0b3d812b feat(intentflow): persist plans with CAS lease and fencing
Own plan/step/decision writes behind UoW so two workers cannot both execute the same step.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:43:46 +00:00
weichenandCursor 7dfd6d6f33 feat(db): add intent plan tables in goose 00044
Persist plans, steps, and append-only decisions with typed CAS, lease, and nonce columns.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:43:37 +00:00
weichenandCursor a75aa45129 docs(ops): claim U3 intentflow PG CAS lease
Register the intent-plan mutex and freeze U3 scope before schema or repository work.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:33:15 +00:00
weichen 53c0722925 merge: chore/release-multi-intent-u2-slot 2026-09-15 23:18:37 +00:00
weichenandCursor 86f25b26c4 chore(ops): release the U2 integration slot
Smoke already passed on the feature branch; U2 has no schema or container change.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:18:37 +00:00
weichen 53d4077f06 merge: feature/multi-intent-u2-segmenter 2026-09-15 23:18:10 +00:00
weichenandCursor 91edeccb26 chore(ops): occupy the U2 integration slot
Hold the shared merge slot for the no-ff merge of the rule-segmenter shadow proposal.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:18:10 +00:00
weichenandCursor c2e79c8a1d docs(test): record U2 rule segmenter shadow proposal report
Close the U2 checklist with golden/hard-negative evidence while keeping production routing unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:17:45 +00:00
weichenandCursor 932ba87daf feat(intent): add rule segmenter and shadow PlanProposal
Generate 2–4 step L1 proposals with stable digests while leaving TopIntent and the legacy IntentPlan router unchanged.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:14:29 +00:00
weichenandCursor 9005766b62 test(intent): lock legacy multi-intent plan routing
Keep write combos and internal-chain summaries on the current TopIntent path so U2 shadow proposals cannot silently change production.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:07:46 +00:00
weichenandCursor 475134802b docs(ops): claim U2 multi-intent rule segmenter
Register the independent U2 short-term on the intent mutex so shadow proposals can land without touching production routing.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 23:06:29 +00:00
weichen 8ac3d3fbc6 merge: chore/release-multi-intent-u1-slot 2026-09-15 16:28:07 +00:00
weichenandCursor 3171e4f0e5 chore(ops): release the U1 integration slot
Smoke already passed on the feature branch; U1 has no schema or container rebuild.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:28:07 +00:00
weichen 29d9c65603 merge: feature/multi-intent-u1-contracts 2026-09-15 16:27:29 +00:00
weichenandCursor 42c8ae2ccd chore(ops): occupy the integration slot for U1 merge
Serialize the local --no-ff merge of multi-intent U1 contracts onto dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:27:29 +00:00
weichenandCursor 3d326ad81e docs(status): record U1 multi-intent contract freeze
Archive the arch/parity/short evidence and mark the U1 claim done so U2 can take the intent mutex next.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:27:03 +00:00
weichenandCursor 9364da4974 feat(intentflow): freeze plan lifecycle contracts and batch policy
Add the app/intentflow skeleton so HITL state, error codes, REST shapes, and BatchActionPolicy live outside intent and default to the legacy tier.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:22:52 +00:00
weichenandCursor aefb1e45a6 feat(events): register intent.plan contracts and table owners
Freeze the three fact events, intentflow allowlist, and plan table ownership so later units cannot invent producers or write paths outside app/intentflow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:20:19 +00:00
weichenandCursor bdccb4dbfe docs(ops): claim U1 multi-intent HITL contract freeze
Register the independent U1 short-term, checklist, and CURRENT mutex so architecture-docs and events stay serial while contracts land.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:19:12 +00:00
weichen dd30e061d8 merge: sync test promotion notes from local dev 2026-09-15 16:04:59 +00:00
weichen 987423794f merge: feature/test-env-smoke-notes 2026-09-15 16:04:59 +00:00
weichenandCursor 8919ca9842 docs(ops): record the test promotion smoke and release the slot
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 16:04:59 +00:00
183 changed files with 12263 additions and 1169 deletions
@@ -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)
+29 -10
View File
@@ -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 |
@@ -72,7 +83,7 @@
| Cursor | phase2-closeout-inventories | feature/phase2-closeout-inventories | - | architecture-docs | done |
| Cursor | event-shared-live-cutover | feature/event-shared-live-cutover | - | events | done |
| Cursor | pi-typed-result | feature/pi-typed-result | - | pi-agent | done |
| Cursor | promote-dev-to-test-2026-09-15 | feature/promote-dev-to-test-2026-09-15 | - | infra | in_progress |
| Cursor | promote-dev-to-test-2026-09-15 | feature/promote-dev-to-test-2026-09-15 | - | infra | done |
> 新任务开始前登记。`branch` 必须为 `feature/<slug>` 或 `fix/<slug>`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。
@@ -84,7 +95,7 @@
| holder | phase | since | scope | queue |
|--------|-------|-------|-------|-------|
| Cursor | merging | 2026-09-15 | promote local dev → test + test rebuild | - |
| 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 | 25→27* | healthy |
| 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 审计回链
+13 -10
View File
@@ -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 叙事。
+8 -7
View File
@@ -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` |
---
+6
View File
@@ -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 只能提出不可信分段建议。
+36
View File
@@ -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]
@@ -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
+5
View File
@@ -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
View File
@@ -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
View File
@@ -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})
+3
View File
@@ -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;
+1
View File
@@ -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"
+2
View File
@@ -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
View File
@@ -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()
+126
View File
@@ -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)
}
}
+14
View File
@@ -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
+122
View File
@@ -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
}
+106
View File
@@ -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)
}
}
+41
View File
@@ -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 ""
}
}
+89
View File
@@ -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
}
}
+82
View File
@@ -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)
}
}

Some files were not shown because too many files have changed in this diff Show More