Compare commits
78
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb22135144 | ||
|
|
b9339cd272 | ||
|
|
792c216c96 | ||
|
|
a90cce73b9 | ||
|
|
a3db288a7a | ||
|
|
f46480a987 | ||
|
|
e5c2519fea | ||
|
|
5bc88faf4f | ||
|
|
b820e0070d | ||
|
|
8d5e782079 | ||
|
|
5679c79011 | ||
|
|
0664abe57d | ||
|
|
714732df5a | ||
|
|
a3f8afbe63 | ||
|
|
650703c5c2 | ||
|
|
d86b4d51ef | ||
|
|
4bb265b431 | ||
|
|
d6ce9abef7 | ||
|
|
d3fda0e834 | ||
|
|
44435691c0 | ||
|
|
87888213da | ||
|
|
4c42d1bf74 | ||
|
|
aea19f70ef | ||
|
|
434d542c3c | ||
|
|
fa5d17a403 | ||
|
|
2952aa5a64 | ||
|
|
6e1d5830b5 | ||
|
|
c46a9c35dc | ||
|
|
73836962a0 | ||
|
|
db859e185e | ||
|
|
193a752f1a | ||
|
|
3eac19cf44 | ||
|
|
d724982acc | ||
|
|
dfd9f6efb3 | ||
|
|
d55488ae37 | ||
|
|
3ba15df875 | ||
|
|
4f581306d7 | ||
|
|
8f77053f51 | ||
|
|
0e05eedade | ||
|
|
4bceb2b4ba | ||
|
|
655fb4f149 | ||
|
|
ef3c770451 | ||
|
|
dddd3fe8c8 | ||
|
|
e4da425b23 | ||
|
|
8f72b6a97c | ||
|
|
73a3aa9286 | ||
|
|
7435f48389 | ||
|
|
f3f23a3018 | ||
|
|
c87d28b343 | ||
|
|
42a9a4be5d | ||
|
|
cb4d2af8d3 | ||
|
|
457e870330 | ||
|
|
6314406701 | ||
|
|
8a9614d19e | ||
|
|
3e534bbb39 | ||
|
|
e7d4743cba | ||
|
|
7f9d01a3b6 | ||
|
|
b1ed8ecfe9 | ||
|
|
56538221f3 | ||
|
|
c713834954 | ||
|
|
774df05998 | ||
|
|
dbe1401455 | ||
|
|
9141741b78 | ||
|
|
e1d6a2c192 | ||
|
|
88b7c11a23 | ||
|
|
4ba60c2c9d | ||
|
|
e1f2c9c57f | ||
|
|
04d7fec493 | ||
|
|
90e146e424 | ||
|
|
f0ecc4c996 | ||
|
|
912957c44e | ||
|
|
ec7148175b | ||
|
|
b35ea39a95 | ||
|
|
a6acdcb30b | ||
|
|
c20c8aa7ab | ||
|
|
8b3da0d297 | ||
|
|
912342ae0a | ||
|
|
22f7e7f3f7 |
@@ -47,6 +47,7 @@
|
||||
| 整改方案 | [remediation/INDEX.md](remediation/INDEX.md) |
|
||||
| 历史归档 | [archive/README.md](archive/README.md) |
|
||||
| 架构设计 | [system-design/README.md](system-design/README.md) |
|
||||
| 用错误码定位失败 | [错误码目录](system-design/2026-09-28-error-code-catalog.md) |
|
||||
| 测试报告 | [test-reports/](test-reports/) |
|
||||
| 历史功能设计 | [archive/design/superpowers/](archive/design/superpowers/) |
|
||||
| Herdr 角色、审批与备援 | [ops/2026-09-13-herdr-agent-roster.md](ops/2026-09-13-herdr-agent-roster.md) |
|
||||
|
||||
+18
-1
@@ -2,10 +2,27 @@
|
||||
|
||||
维护规则:[问题记录与开发经验闭环](../ops/2026-09-23-issue-learning-workflow.md)。每个问题一个稳定 ID;主记录是事实与状态来源,本表为可检索投影。新发现及时登记,修复后保留记录;发布 blocker 仍见 [gap-matrix](../remediation/gap-matrix.md)。
|
||||
|
||||
更新:2026-09-27。上传链路:登记并修复上传文档跨端不可访问(占位模板退化 + 元数据/正文不落服务端,fixing 待 dev 集成)。2026-09-26。docgov 批准链:登记并修复 review_snapshot_id 装载缺失与 uow 行锁自死锁(resolved);memDocs 持久化失败缓存投毒(investigating)。历史 resolved 不表示本日产品回归通过。系统 code review P0/P1 批次修复落账(5 resolved + 1 deferred + 1 open,主记录见 [整改文档](2026-09-26-system-code-review-fixes.md),来源 [审计](2026-09-26-system-code-review.md))。
|
||||
更新:2026-09-28。docgov 共享 map 并发读写曾在 06:38 UTC 打崩 dev 进程,登录等 API 在进程缺席期间 500(verifying,单测 `-race` 已过,dev 重建未做)。只上传文档、无文字时对话 400 已在重载后的 dev 浏览器复验(resolved,`bin/agent-server` 10:22 +0800)。历史任务 run 事件流 HTTP/2 与 502 另记,未在本轮修。激活预览前端预检与管理台密钥 form 已在 dev 浏览器复验(resolved,dev `3e534bbb`,项目 6023)。非编制人触发小队账本提交被 `uow: permission denied` 拒绝(fixing,待 dev 重跑)。test 注册 INTERNAL:标准角色 role-guest 缺失导致 FK 23503,已补种并重启 test(goose 77,resolved)。重复用户名 400 在新代码单测通过;当前 rc 二进制仍返回 INTERNAL,随下次含本提交的 test 制品生效。管理台重置密码入口被 F4-A 误删(端点仍在),已恢复 UI(resolved)。2026-09-27。上传链路:登记并修复上传文档跨端不可访问(占位模板退化 + 元数据/正文不落服务端,fixing 待 dev 集成)。2026-09-26。docgov 批准链:登记并修复 review_snapshot_id 装载缺失与 uow 行锁自死锁(resolved);memDocs 持久化失败缓存投毒(investigating)。历史 resolved 不表示本日产品回归通过。系统 code review P0/P1 批次修复落账(5 resolved + 1 deferred + 1 open,主记录见 [整改文档](2026-09-26-system-code-review-fixes.md),来源 [审计](2026-09-26-system-code-review.md))。
|
||||
|
||||
| issue_id | 模块 / 检索词 | 问题 | 严重度 | issue_state | owner | 证据日期 / 范围 | 唯一主记录 | 经验 |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| ISSUE-20260928-docgov-map-race | docgov / memDocs / concurrent map / GetDocument / 登录 500 | per-doc 锁拆分后共享 map 无互斥,不同文档并发读写 fatal,进程退出期间全部 API 500 | critical | verifying | Cursor | 2026-09-28;`.tmp/launch/server.log` fatal + `web.log` ECONNREFUSED;`TestMemMapsNoRaceAcrossDocs` `-race` PASS(`a90cce73`);dev 重建未做 | [主记录](../ops/short-term/2026-09-28-docgov-shared-map-race.md#issue-20260928-docgov-map-race) | [LESSON-20260928-docgov-shared-map-race](../ops/lessons/2026-09-28-docgov-shared-map-race.md) |
|
||||
| ISSUE-20260928-quality-heading-drift | squad / quality_gate / 缺少必填章节 / State-of-the-Art / H3 | 调研报告章节在,只因 H3 和少空格被判缺章,受控文档不投影 | high | verifying | Cursor | 2026-09-28;dev `research_1790566833205199368` manifest score 85;单测已覆盖,dev 重跑未做 | [主记录](../ops/short-term/2026-09-28-quality-gate-heading-mismatch.md#issue-20260928-quality-heading-drift) | [LESSON-20260928-quality-heading-normalize](../ops/lessons/2026-09-28-quality-heading-normalize.md) |
|
||||
| ISSUE-20260928-data-dir-doubled | workspace / data/dev/data/dev / DataDir | 出现双层 `data/dev/data/dev/workspaces` 且只有孤立 output.md,写入点未证实 | medium | open | — | 2026-09-28;`intake_1790565513115586191` 双路径对照 | [主记录](../ops/short-term/2026-09-28-quality-gate-heading-mismatch.md#issue-20260928-data-dir-doubled) | 本轮不修 |
|
||||
| ISSUE-20260928-progress-query-trigger | intent / matchTriggerTask / QUERY_PROGRESS / 编写进度 | 询问调研报告编写进度时,写动词加任务名词被识别成启动新任务,进度回复不读真实 run | medium | verifying | Cursor | 2026-09-28;「调研报告编写进度怎么样了」单测为 QUERY_PROGRESS;「开始做调研报告」仍为 research。浏览器复验见测试报告 | [主记录](../ops/short-term/2026-09-28-refresh-task-state-recovery.md) | 疑问进度句必须让行查询;显式「开始/重新」仍启动任务 |
|
||||
| ISSUE-20260928-step-empty-output | squad / stepOutputAccepted / output_digest / e3b0c442 / MaterializeTargets | 步骤已把正文写到 output.md,判定仍因 runner Success=false 或空 patch 记空输出失败 | high | verifying | Cursor | 2026-09-28;11:27 `research_1790566028724181453` 的 06_draft 盘上 41KB 但 digest 为空;单测覆盖缺交付物但盘上有正文,以及连接错误仍失败关闭 | [主记录](../ops/short-term/2026-09-28-refresh-task-state-recovery.md) | 传输/可重试失败留下的文件可能是截断的,不能当成功;缺交付物且盘上非空才接受 |
|
||||
| ISSUE-20260928-task-write-verb | intent / hasTaskWriteVerb / 帮我定 / 制定 / AMBIGUOUS_FALLBACK | 「帮我定/制定」设计开发计划任务书未进入任务触发,对话只有掂量阶段模板 | medium | resolved | Cursor | 2026-09-28;test sess-p8-u33 msg 89/90;意图单测 | [主记录](../ops/short-term/2026-09-28-test-user-doc-issues.md) | [LESSON-20260928-task-write-verb-visible-refusal](../ops/lessons/2026-09-28-task-write-verb-visible-refusal.md) |
|
||||
| ISSUE-20260928-workflow-scope-reply | coordinator / ClarificationQuestion / ErrPrerequisiteNotMet / rd_design_plan | 跨工作流澄清与研发前置未满足时,原因没有进入对话 | medium | resolved | Cursor | 2026-09-28;协调器单测。test 原例停在动词未命中,未走到本分支 | [主记录](../ops/short-term/2026-09-28-test-user-doc-issues.md) | [LESSON-20260928-task-write-verb-visible-refusal](../ops/lessons/2026-09-28-task-write-verb-visible-refusal.md) |
|
||||
| ISSUE-20260928-quality-failed-success-copy | bizdev / quality_failed / 正文已保存至 / output.md | 质量未通过仍声称正文已保存,并写出工作区绝对路径 | medium | resolved | Cursor | 2026-09-28;test cdo_quote_1790560155851280170;同步回复单测 | [主记录](../ops/short-term/2026-09-28-test-user-doc-issues.md) | [LESSON-20260928-task-write-verb-visible-refusal](../ops/lessons/2026-09-28-task-write-verb-visible-refusal.md) |
|
||||
| ISSUE-20260928-pi-runner-data-dir | agent / PI runner / DATA_DIR / MISSING_TARGET / 18866 | test 启动时根 .env 的 dev runner 地址盖过本环境 sidecar,工作区被重写到空目录 | high | resolved | Cursor | 2026-09-28;dev `4f581306`。当时 test 二进制仍是修复前制品 | [验收报告](../test-reports/2026-09-28-pi-runner-env-mismatch-test-report.md) | — |
|
||||
| ISSUE-20260928-material-chunk-embed | knowledge / chunk index failed / 8192 / 34635 tokens | 材料分块批超过嵌入模型上下文,索引失败 | medium | open | — | 2026-09-28;test 日志 project 8,文件 W020251117353305579317.docx | [主记录](../ops/short-term/2026-09-28-test-user-doc-issues.md) | 本轮不修 |
|
||||
| ISSUE-20260928-attachment-only-turn | chat / chat/stream / message cannot be empty / HTTP_400 / attachments | 只上传文档、不输入文字时 turn 被空消息 400 拒绝,前端不读信封,用户看不到任何回复 | high | resolved | Cursor | 2026-09-28;dev :8080 重载后浏览器仅附件得到梳理审阅,无关文字先回答再追问;pending 分支 API 200 | [主记录](../ops/short-term/2026-09-28-attachment-only-turn.md) | 空消息门禁要放在附件判定之后;4xx 必须读信封。见[测试报告](../test-reports/2026-09-28-attachment-only-turn-test-report.md) |
|
||||
| ISSUE-20260928-task-run-replay-502 | web / useRecoveredTaskPhases / tasks/runs / ERR_HTTP2_PROTOCOL_ERROR / 502 | 历史失败气泡恢复订阅 task run 事件时出现 HTTP/2 协议错误和 502,与附件空消息 400 无因果关系 | medium | verifying | Cursor | 2026-09-28;终态重放改为最多 4 次退避,401/404 立即停止;进行中订阅外层只再补 1 次,避免和内部 40 次重试相乘。尚未在真实 502 上复验 | [主记录](../ops/short-term/2026-09-28-refresh-task-state-recovery.md) | 重放失败要可重试;鉴权与不存在不要空转 |
|
||||
| ISSUE-20260928-activation-preview-precheck | web / projectSettings / activation-preview / NO_GOVERNED_DOCUMENT / clientDutyIssues | 全部文档未纳入人工审批时前端仍 POST activation-preview,控制台 400 | medium | resolved | Cursor | 2026-09-28;dev 项目 6023 默认计划无 activation-preview 请求,兼任后 preview 200 | [主记录](../ops/short-term/2026-09-28-activation-preview-precheck.md#issue-20260928-activation-preview-precheck) | [LESSON-20260928-activation-preview-client-gate](../ops/lessons/2026-09-28-activation-preview-client-gate.md) |
|
||||
| ISSUE-20260928-admin-secret-password-form | web / EnvSettingsSection / password / form / secrets | 管理台 5 个密钥输入不在 form 内,Chromium 报 password DOM 警告 | low | resolved | Cursor | 2026-09-28;dev 模型与密钥页 passwordInputs=5 outsideForm=0 | [主记录](../ops/short-term/2026-09-28-activation-preview-precheck.md#issue-20260928-admin-secret-password-form) | 密码框放进 form;autocomplete 不能单独消除该 DOM 警告 |
|
||||
| ISSUE-20260928-squad-commit-authority | bizdev / docflow / dutyAuthorizer / uow permission denied / OnBehalfOf / bd_intake | 非编制人触发受控小队任务时,账本提交用触发者身份,被编制人职责门拒绝,正文无法落盘 | high | fixing | Cursor | 2026-09-28;dev task_runs user 74 ≠ author 4(doc_proj6022_bd_intake);单测已绿,dev 重跑未做 | [主记录](../ops/short-term/2026-09-28-squad-commit-authority.md#issue-20260928-squad-commit-authority) | [LESSON-20260928-squad-commit-as-author](../ops/lessons/2026-09-28-squad-commit-as-author.md) |
|
||||
| ISSUE-20260928-register-internal | auth / register / role-guest / system_roles / 23503 / 23505 / INTERNAL | test 缺 role-guest 时注册 FK 失败被脱敏为 INTERNAL;重复用户名唯一冲突同样 500 | high | resolved | Cursor | 2026-09-28;test:8081 补种并重启后注册 200(goose 77,req_regfix_after_restart);重复用户名 400 由单测覆盖,rc 二进制仍为 INTERNAL | [主记录](../ops/short-term/2026-09-28-auth-register-internal.md#issue-20260928-register-internal) | [LESSON-20260928-standard-role-reseed](../ops/lessons/2026-09-28-standard-role-reseed.md) |
|
||||
| ISSUE-20260928-admin-reset-ui-removed | web / UsersSection / 重置密码 / F4-A / adminResetPassword | F4-A 在 F4-B 端点已合入的基线上删除管理台重置密码按钮,管理员无法重置口令 | high | resolved | Cursor | 2026-09-28;dev API :8080 + worktree Vite :3110 真实 UI 探针 PASS(临时口令长度 16、强制改密仅一次、旧口令 401) | [主记录](../ops/short-term/2026-09-28-restore-admin-password-reset.md#issue-20260928-admin-reset-ui-removed) | [LESSON-20260928-ui-dead-control](../ops/lessons/2026-09-28-ui-dead-control.md) |
|
||||
| ISSUE-20260927-upload-doc-cross-device | freedoc / upload / freeform / fileMeta / 占位模板 / 跨端 | 上传文档源文件元数据与正文不落服务端:换浏览器/清存储/共享他人查看时退化为注册占位模板,文本类连二进制都未存(伴生 <512B 显示 "0 KB") | high | resolved | pi | 2026-09-27;dev `86efba2c` 合入并在 dev 环境验证:FS-UPLOAD-01/02 真实浏览器 PASS(跨上下文可见真实正文),DB 核验元数据+asset 落库;存量无元数据旧文档不可恢复(重新上传即可) | [主记录](../ops/short-term/2026-09-27-upload-doc-access.md) | [LESSON-20260927-server-facts-and-iso-db-recipe](../ops/lessons/2026-09-27-server-facts-and-iso-db-recipe.md) |
|
||||
| ISSUE-20260923-nullable-duty | docgov / nullable / 23503 / reviewer_id | 可选职责空值写 0 导致 FK 失败 | high | resolved | Codex(历史补录) | 2026-09-17;历史 PG / API 冒烟;当前未复测 | [主记录](2026-09-23-historical-issue-records.md#nullable-duty) | [LESSON-20260923-nullable-duty](../ops/lessons/2026-09-23-nullable-duty.md) |
|
||||
| ISSUE-20260923-content-hash | docrevision / canonicalize / hard-break / 404 | 规范化破坏 Markdown 语义并造成正文哈希漂移 | critical | resolved | Codex(历史补录) | 2026-09-14;历史真实 UI / 重启;当前未复测 | [主记录](2026-09-23-historical-issue-records.md#content-hash) | [LESSON-20260923-content-hash](../ops/lessons/2026-09-23-content-hash.md) |
|
||||
|
||||
@@ -18,6 +18,20 @@
|
||||
|
||||
| owner | task | branch | worktree | mutex | status |
|
||||
|---|---|---|---|---|---|
|
||||
| Cursor | docgov-shared-map-race-2026-09-28-r2 | fix/docgov-shared-map-race-2026-09-28 | .worktrees/docgov-shared-map-race-2026-09-28 | docgov-shared-map-race | in_progress |
|
||||
| Cursor | promote-rc-beta6-closeout-2026-09-28 | feature/promote-rc-beta6-closeout-2026-09-28 | .worktrees/promote-rc-beta6-closeout-2026-09-28 | git:test+env:test | done |
|
||||
| Cursor | quality-gate-heading-mismatch-2026-09-28-r3 | fix/quality-gate-heading-mismatch-2026-09-28 | .worktrees/quality-gate-heading-mismatch-2026-09-28 | quality-gate-heading | in_progress |
|
||||
| Cursor | agent-reply-llm-narrative-2026-09-28 | feature/agent-reply-llm-narrative-2026-09-28 | .worktrees/agent-reply-llm-narrative-2026-09-28 | chat+coordinator | in_progress |
|
||||
| Cursor | test-user-doc-issues-2026-09-28 | fix/test-user-doc-issues-2026-09-28 | .worktrees/test-user-doc-issues-2026-09-28 | intent-write-verb | done |
|
||||
| Cursor | pi-runner-env-mismatch-2026-09-28 | fix/pi-runner-env-mismatch-2026-09-28 | .worktrees/pi-runner-env-mismatch-2026-09-28 | pi-runner-env | done |
|
||||
| Cursor | error-events-pg-roundtrip-2026-09-28 | feature/error-events-pg-roundtrip-2026-09-28 | .worktrees/error-events-pg-roundtrip-2026-09-28 | error-events-pg-evidence | done |
|
||||
| Cursor | error-code-observability-2026-09-28 | feature/error-code-observability-2026-09-28 | .worktrees/error-code-observability-2026-09-28 | error-code-observability | done |
|
||||
| Cursor | attachment-only-turn-2026-09-28 | fix/attachment-only-turn-2026-09-28 | .worktrees/attachment-only-turn-2026-09-28 | attachment-only-turn | done |
|
||||
| Cursor | activation-preview-precheck-2026-09-28 | fix/activation-preview-400-precheck-2026-09-28 | .worktrees/activation-preview-400-precheck-2026-09-28 | web-activation-preview | done |
|
||||
| Cursor | squad-commit-authority-2026-09-28 | fix/squad-commit-authority-2026-09-28 | .worktrees/squad-commit-authority-2026-09-28 | bizdev+docflow | in_progress |
|
||||
| Cursor | auth-register-internal-2026-09-28 | fix/auth-register-internal-2026-09-28 | .worktrees/auth-register-internal-2026-09-28 | auth-register | done |
|
||||
| Cursor | restore-admin-password-reset-2026-09-28 | feature/restore-admin-password-reset-2026-09-28 | .worktrees/restore-admin-password-reset-2026-09-28 | auth | done |
|
||||
| pi | test-single-binary-2026-09-27 | feature/test-single-binary-2026-09-27 | .worktrees/test-single-binary-2026-09-27 | env:dev+env:test+git:dev+git:test | done |
|
||||
| pi | upload-doc-access-2026-09-27 | fix/upload-doc-access-2026-09-27 | .worktrees/upload-doc-access-2026-09-27 | freedoc+web-upload | done |
|
||||
| pi | frontend-demo-fallback-2026-09-27-r3c | fix/frontend-demo-fallback-2026-09-27-r3 | (已清理) | web-chat-fallback | done |
|
||||
| pi | frontend-demo-fallback-2026-09-27-r2 | fix/frontend-demo-fallback-2026-09-27 | (已清理) | web-chat-fallback | done |
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-activation-preview-client-gate
|
||||
lesson_state: validated
|
||||
owner: Cursor
|
||||
reviewer: Cursor
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: 3e534bbb39d0d957e0b720a4ca06f22dd15959e6
|
||||
source_issues: [ISSUE-20260928-activation-preview-precheck]
|
||||
keywords: [activation-preview, NO_GOVERNED_DOCUMENT, clientDutyIssues, needsGovernedDocument, 400]
|
||||
---
|
||||
|
||||
# 激活门禁要在点击前做同样的前端预检
|
||||
|
||||
- 触发条件:控制台出现 `POST .../activation-preview 400`,响应码是 `NO_GOVERNED_DOCUMENT`。
|
||||
- 机制与来源:服务端 `validateActivationPlan` 要求至少一份完整人工审批。前端 `clientDutyIssues` 只查三权完整性,全部未纳入审批时仍会发请求。见 ISSUE-20260928-activation-preview-precheck。
|
||||
- 开发检查:新增激活条件时,同时改 `validateActivationPlan` 与 `needsGovernedDocument` / `clientDutyIssues`。运行中 `live_edit` 走 `validatePlan`,不要套激活门禁。
|
||||
- 验证方式:默认计划直接预览不得发出 activation-preview;一份兼任文档预览应 200。单测在 `web/src/lib/projectSettingsDuties.test.ts`。
|
||||
- 适用边界:只覆盖激活前规划。已激活实例改职责不要求「至少一份」。
|
||||
- 防护落实:上述单测与 dev 浏览器复验已落地。
|
||||
- 修订与失效:若产品允许零审批激活,应同时删除服务端 `NO_GOVERNED_DOCUMENT` 与前端预检。
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-docgov-shared-map-race
|
||||
lesson_state: candidate
|
||||
owner: Cursor
|
||||
reviewer: Cursor(自审)
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: a90cce73
|
||||
source_issues: [ISSUE-20260928-docgov-map-race]
|
||||
keywords: [docgov, memDocs, memMu, per-doc lock, concurrent map, 登录 500]
|
||||
---
|
||||
|
||||
# 拆细粒度锁后,共享 map 仍要单独互斥
|
||||
|
||||
- 触发条件:把全局锁拆成 per-id 锁,但多个 id 仍读写同一张 Go map(缓存、审计、批注、提案)。
|
||||
- 机制与来源:docgov 的 per-doc 锁不保护 `memDocs` 等 map。不同文档并发时 `GetDocument` 与写入撞上,运行时 fatal,进程退出后所有 HTTP API(含登录)500。证据:2026-09-28 `.tmp/launch/server.log` 与 `web.log` 的 `ECONNREFUSED`。修复见 [任务](../short-term/2026-09-28-docgov-shared-map-race.md)。
|
||||
- 开发检查:map 的读写、遍历、append 都走同一把锁。已持有外层锁的路径不能再锁同一把(Go 互斥锁不可重入)。锁序固定,禁止在 map 锁内再拿文档锁或外层锁。不要用「登录 500」去改登录代码。
|
||||
- 验证方式:不同 docID 并发创建与读取,`go test -race` 覆盖 `TestMemMapsNoRaceAcrossDocs`。进程崩溃类问题还要看服务日志里的 fatal,而不是只看单个 API 状态码。
|
||||
- 适用边界:适用于 docgov 这四张内存 map。文档结构体字段的数据竞争、以及持久化失败后的缓存投毒(`ISSUE-20260926-docgov-memdocs-poison`)不在本条范围内。
|
||||
- 防护落实:`memMu` 与 `TestMemMapsNoRaceAcrossDocs`。没有新增静态检查,漏一个裸访问仍要靠 `-race` 和复查。
|
||||
- 修订与失效:若这四张 map 改为分片或移除,本条对那个存储失效,保留历史。
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-quality-heading-normalize
|
||||
lesson_state: candidate
|
||||
owner: Cursor
|
||||
reviewer: Cursor(自审,待 dev 重跑调研报告后升 validated)
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: 434d542c3cbdbeac38b9c0e547edf75160acf577
|
||||
source_issues: [ISSUE-20260928-quality-heading-drift]
|
||||
keywords: [quality_gate, 缺少必填章节, State-of-the-Art, H3, AutoRepair]
|
||||
---
|
||||
|
||||
# 章节门禁比对标题,不比对空格和层级
|
||||
|
||||
- 触发条件:交付正文章节都在,质量报告仍写「缺少必填章节」,评分往往停在 85。
|
||||
- 机制与来源:模板 H2 与模型常写的 H3、多一个或少一个空格、全角字母,在精确字符串比较下会被当成整章缺失。缺章会短路受控投影。见 ISSUE-20260928-quality-heading-drift。
|
||||
- 开发检查:标题比对先去空白、折全角、忽略大小写,并允许 H2–H4。只在归一化后确实没有该标题时判缺失。层级不一致记软警告,不扣分。不要把「待确认」或材料不足算进这道门禁。
|
||||
- 验证方式:`TestQualityGate_Validate_HeadingLevelAndSpaceDrift` 同时覆盖漂移通过和真实缺章失败。聊天触发须带 `AutoRepair`。
|
||||
- 适用边界:只覆盖 ATX 标题存在性。近义改名、章节被写进代码块、内容空洞仍不在本条范围内。
|
||||
- 防护落实:`internal/squad/quality_gate.go` 与 `quality_gate_test.go`。
|
||||
- 修订与失效:若产品要求章节层级必须与模板一致才可交付,应把软警告改回硬失败,并同步改回归用例。
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-squad-commit-as-author
|
||||
lesson_state: candidate
|
||||
owner: Cursor
|
||||
reviewer: Cursor(自审,待 dev 重跑后升 validated)
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: 774df0599813fb8d7115f95ce255384542d6a0f9
|
||||
source_issues: [ISSUE-20260928-squad-commit-authority]
|
||||
keywords: [bizdev, docflow, dutyAuthorizer, AutoCommitUserID, OnBehalfOf, uow permission denied, 非编制人]
|
||||
---
|
||||
|
||||
# 小队账本自动提交要用编制人身份
|
||||
|
||||
- 触发条件:受控文档小队任务成功生成正文,但落盘报 `uow: permission denied` 或「版本账本/变更报告落盘失败」。
|
||||
- 机制与来源:`dutyAuthorizer` 对 `ActionCommit` 要求 principal 等于 `document_records.author_id`。触发者常常是其他项目成员。见 ISSUE-20260928-squad-commit-authority。
|
||||
- 开发检查:自动提交的 `AutoCommitUserID` 用文档编制人;实际触发用户写入 `OnBehalfOf`。不要为了小队路径放宽编制人校验。触发者或编制人为 0 时不要伪造代理身份。权限失败文案要写明「非编制人」,同时保留 `uow.ErrPermissionDenied` 哨兵。
|
||||
- 验证方式:非编制人触发应成功且 `OnBehalfOf` 为触发者;编制人触发不设置 `OnBehalfOf`;非编制人直接 `ActionCommit` 仍拒绝。关联 `internal/bizdev/squad_commit_actor_test.go` 与 `TestDutyAuthorizerAllowsDocumentAuthorCommit`。dev 原例重跑完成前本条保持 candidate。
|
||||
- 适用边界:只覆盖小队/agent 自动提交。人工编辑、批准、驳回仍按各自职责人校验。高风险候选仍要编制人确认。
|
||||
- 防护落实:上述单测已落地。原例验收是 manual(dev 非编制人重跑)。
|
||||
- 修订与失效:若产品改为「非编制人不得触发生成」,本条应退役并改回触发者身份。
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-standard-role-reseed
|
||||
lesson_state: validated
|
||||
owner: Cursor
|
||||
reviewer: Cursor(自审)
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: 4ba60c2c9d7eaf3e3e824475c0f3a44e10641190
|
||||
source_issues: [ISSUE-20260928-register-internal]
|
||||
keywords: [auth, register, role-guest, system_roles, is_system, 23503, 23505, INTERNAL]
|
||||
---
|
||||
|
||||
# 代码硬编码的标准角色必须可自愈且不可删
|
||||
|
||||
- 触发条件:注册、管理员建号或种子用户写入固定 `role_id`,而该角色只在历史 goose 种子里出现一次。
|
||||
- 机制与来源:`Register` 固定写 `role-guest`。00015 仅 `role-admin` 为 `is_system`。角色一旦被删,goose 不重跑、`BootstrapIAM` 只补用户,`user_role_bindings` 外键失败被脱敏成 INTERNAL。证据日期 2026-09-28,见 [任务](../short-term/2026-09-28-auth-register-internal.md)。
|
||||
- 开发检查:硬编码角色 id 须在迁移里 `ON CONFLICT DO UPDATE` 补种,并标 `is_system`。用户名一类唯一冲突返回领域错误,不要包进 `insert user:` 这类会被当成 500 的前缀。
|
||||
- 验证方式:缺角色的库补种后注册返回 200;重复用户名返回 400 且 `error` 为「用户名已存在」。
|
||||
- 适用边界:适用于 IAM 标准角色。业务自定义角色仍允许删除(无人引用时)。
|
||||
- 防护落实:migration 00077 + `DeleteRole` 既有系统角色拒绝。未新增 lint。
|
||||
- 修订与失效:若注册不再绑定 `role-guest`,本条对那个写入点失效,保留历史。
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-task-write-verb-visible-refusal
|
||||
lesson_state: candidate
|
||||
owner: Cursor
|
||||
reviewer: Cursor(自审,待含本提交的运行制品复验原句)
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: db859e185ebcd0e7eccd2241ca07f0e9f4fe4c6b
|
||||
source_issues: [ISSUE-20260928-task-write-verb, ISSUE-20260928-workflow-scope-reply, ISSUE-20260928-quality-failed-success-copy]
|
||||
keywords: [intent, hasTaskWriteVerb, 帮我定, ClarificationQuestion, ErrPrerequisiteNotMet, quality_failed]
|
||||
---
|
||||
|
||||
# 任务写动词要覆盖「定」,拒绝原因要进对话
|
||||
|
||||
- 触发条件:用户说「帮我定/制定/拟定」某交付物,对话却进入「再掂量一下」;或任务被工作流范围、研发前置、质量门禁挡住,气泡仍像成功或只有协调失败。
|
||||
- 机制与来源:强写动词表原先只有生成/做/跑/出/编写/编制/起草。「定」单独出现会误伤「决定」,所以只认「制定」「拟定」以及「帮我/请/给我/帮忙」后面的「定/拟」。跨流澄清和前置失败必须成为用户可见回复,不能再被阶段模板或错误事件盖掉。质量未通过不要写宿主机路径。见 ISSUE-20260928-task-write-verb。
|
||||
- 开发检查:新增交付动词时补强动词或祈使短语,并加一条反例(决定、看看)。`RequiresClarifying` 的问题原文要到达会话。`ErrPrerequisiteNotMet` 的中文原因用拒绝态返回,错误值为空,避免会话层丢掉 `NaturalReply`。
|
||||
- 验证方式:`go test ./internal/intent/ ./internal/coordinator/` 中写动词、跨流澄清、前置可见、质量失败文案四类用例。原句在运行制品上的复验完成前,本条保持 candidate。
|
||||
- 适用边界:只覆盖中文任务触发与同步回复。材料嵌入分块超限、PI runner 数据目录错配是相邻但独立的问题。
|
||||
- 防护落实:`doc_workflow_scope_test.go` 与 `pending_confirmation_reply_test.go`。
|
||||
- 修订与失效:若产品明确「定」永不表示编写,应删祈使短语并退役本条。
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
lesson_id: LESSON-20260928-ui-dead-control
|
||||
lesson_state: validated
|
||||
owner: Cursor
|
||||
reviewer: Cursor(自审)
|
||||
last_reviewed: 2026-09-28
|
||||
reviewed_revision: 912957c44ec1bd91f6010d657a909e5120546f74
|
||||
source_issues: [ISSUE-20260928-admin-reset-ui-removed]
|
||||
keywords: [web, UsersSection, 重置密码, 死按钮, merge-base, F4-A]
|
||||
---
|
||||
|
||||
# 删「未开通」控件前先核对当前基线是否已有端点
|
||||
|
||||
- 触发条件:准备移除会失败的按钮、菜单或客户端调用,理由是「端点未开通 / 待产品选型」。
|
||||
- 机制与来源:T20-F4-B 已在 `39f8c1d1` 开通重置密码;随后 `d653e32e`(F4-A)仍按旧设计删掉入口。`725181de` 已包含 F4-B。证据日期 2026-09-28,见 [任务](../short-term/2026-09-28-restore-admin-password-reset.md)。
|
||||
- 开发检查:对声称缺失的路由做 `git merge-base --is-ancestor <实现提交> <本任务基线>`,并在当前树 grep 路由注册。祖先关系成立时不得删除对应 UI。注释不能代替这条核对。
|
||||
- 验证方式:恢复后的按钮须打到真实端点(本任务 dev UI 探针:随机口令长度 16、首次登录强制改密、二次登录不再弹出、旧口令 401)。仅存在单测不算 UI 已接上。
|
||||
- 适用边界:适用于「控件调用已实现 API」。端点确实不存在、或产品明确下线该能力时,删除控件仍然正确。
|
||||
- 防护落实:manual。未新增 lint。后续同类删除在任务记录里写下 merge-base 结果。
|
||||
- 修订与失效:若重置密码产品下线并删除路由,本条对那个控件不再适用,保留历史。
|
||||
@@ -4,6 +4,13 @@
|
||||
|
||||
| lesson_id | 触发条件 / 关键词 | 注意事项 | lesson_state | 主记录 / 最近复核 |
|
||||
|---|---|---|---|---|
|
||||
| LESSON-20260928-docgov-shared-map-race | docgov、memDocs、per-doc 锁、concurrent map、登录 500 | 拆锁后共享 map 仍要单独互斥;锁不可重入;全站 500 先看进程是否退出 | candidate | [共享 map 互斥](2026-09-28-docgov-shared-map-race.md);2026-09-28 |
|
||||
| LESSON-20260928-quality-heading-normalize | 缺少必填章节、State-of-the-Art、H3、质量门禁、AutoRepair | 标题比对去空白并跨 H2–H4;层级漂移不扣分;真实缺章仍失败 | candidate | [章节标题归一化](2026-09-28-quality-heading-normalize.md);2026-09-28 |
|
||||
| LESSON-20260928-task-write-verb-visible-refusal | 帮我定、制定、ClarificationQuestion、前置条件、quality_failed | 写动词覆盖制定与帮我定;拒绝和澄清进对话;质量失败不写宿主机路径 | candidate | [写动词与可见拒绝](2026-09-28-task-write-verb-visible-refusal.md);2026-09-28 |
|
||||
| LESSON-20260928-activation-preview-client-gate | activation-preview、NO_GOVERNED_DOCUMENT、clientDutyIssues、400 | 服务端激活门禁要有同等前端预检;live_edit 不套激活门禁 | validated | [激活预检对齐](2026-09-28-activation-preview-client-gate.md);2026-09-28 |
|
||||
| LESSON-20260928-squad-commit-as-author | 小队落盘、uow permission denied、AutoCommitUserID、OnBehalfOf、非编制人 | 自动提交身份用文档编制人,触发者只写入 OnBehalfOf;不要放宽 ActionCommit | candidate | [编制人代理提交](2026-09-28-squad-commit-as-author.md);2026-09-28 |
|
||||
| LESSON-20260928-standard-role-reseed | 注册、role-guest、system_roles、is_system、23503、23505、INTERNAL | 硬编码标准角色须幂等补种并标 is_system;用户名冲突返回领域 400,不要包进 insert user | validated | [标准角色可自愈](2026-09-28-standard-role-reseed.md);2026-09-28 |
|
||||
| LESSON-20260928-ui-dead-control | 死按钮、端点未开通、UsersSection、重置密码、merge-base | 删除「未开通」控件前用当前基线核对路由已存在;注释不能代替 merge-base | validated | [删控件前核对端点](2026-09-28-ui-dead-control.md);2026-09-28 |
|
||||
| LESSON-20260927-server-facts-and-iso-db-recipe | 上传持久化、fileMeta、占位模板、config.Load 默认 DSN、TEST_DATABASE_URL、隔离库、RefuseSharedEnvDSN、goose 顺序 | 服务端事实源优先(本地仅缓存);worktree 测试必须显式钉隔离库并避开 5433/5434/5435 子串端口;隔离库配方=扩展→goose→init SQL,重组件用例先做基线四格对照 | validated | [服务端事实源与隔离库配方](2026-09-27-server-facts-and-iso-db-recipe.md) |
|
||||
| LESSON-20260923-nullable-duty | docgov、SQL、nullable、23503、可选职责、创建/heal | 检查所有写入口的缺席值语义;用真实 PG 验证 NULL/FK | validated | [可选职责持久化](2026-09-23-nullable-duty.md);2026-09-23 |
|
||||
| LESSON-20260923-content-hash | docrevision、canonicalize、hash、bootstrap、hard-break、404、水合 | 保持文本语义并检查账本/文件一致性;新数据通过不能覆盖旧数据迁移 | validated | [正文规范化与投影](2026-09-23-content-hash.md);2026-09-23 |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "修复 docker 构建上下文缺少 web/dist/.gitkeep 导致候选镜像构建失败"
|
||||
task_id: docker-context-gitkeep-2026-09-27
|
||||
status: in_progress
|
||||
status: done
|
||||
created: 2026-09-27
|
||||
updated: 2026-09-27
|
||||
owner: pi
|
||||
@@ -17,8 +17,8 @@ write_scope:
|
||||
allowed_environments: ["dev"]
|
||||
capabilities: [git:dev, env:dev]
|
||||
mutex: env:dev
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: not_required
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: "晋升 rc-v1.1.0-beta.4(dev→test)执行记录"
|
||||
task_id: promote-rc-beta4-2026-09-27
|
||||
status: done
|
||||
created: 2026-09-27
|
||||
updated: 2026-09-27
|
||||
owner: pi
|
||||
task_type: ops
|
||||
task_tier: small
|
||||
policy_revision: "AGENTS+worktree-ops @ 5e409c1e"
|
||||
branch: feature/promote-rc-beta4-2026-09-27
|
||||
worktree: .worktrees/promote-rc-beta4-2026-09-27
|
||||
base_dev_sha: "5e409c1eb237814723f65102cb221a3e2de42e6e"
|
||||
head_candidate: "2fe1e0559106654f7dd360d1f191c4798d467783"
|
||||
write_scope: ["."]
|
||||
allowed_environments: ["test"]
|
||||
capabilities: [git:test, env:test, docs:publish]
|
||||
mutex: git:test+env:test
|
||||
review_state: accepted
|
||||
integration_state: pending_merge
|
||||
deployment: test_ok
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 晋升 rc-v1.1.0-beta.4
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户指令(2026-09-27):把 dev 合入 test。授权来源:本会话明确指令;交付终点 = test 分支 rc 晋升 + 部署验收(单二进制化由伴生任务 test-single-binary-2026-09-27 执行)。
|
||||
|
||||
## 结果
|
||||
|
||||
- 门禁:dev tip `5e409c1e` nightly 五链真实 PI PASS(receipt `5e409c1e…json`,含三镜像 digests;`promotion-receipt-check --require-digests` OK)
|
||||
- 候选:`2fe1e055`(commit-tree 构造 merge,P1=旧 test `0e4b111d`,P2=`5e409c1e`;validate run `2b9bac34`:receipt gate + 拓扑自检)
|
||||
- 执行:`git:test` 租约内 update-ref + `git tag -a rc-v1.1.0-beta.4` + `candidate-images-apply.sh test`
|
||||
- 验收与单二进制转换:见 [伴生测试报告](../../test-reports/2026-09-27-test-single-binary-test-report.md)
|
||||
|
||||
## 验证与证据
|
||||
|
||||
| 项 | 证据 |
|
||||
|---|---|
|
||||
| PASS 收据 + digests | `promotion-receipts/5e409c1eb237814723f65102cb221a3e2de42e6e{.json,.images.json}` |
|
||||
| nightly 证据 | `promotion-receipts/evidence-5e409c1eb237-20260927T183704Z/` |
|
||||
| 过程证据(nightly6 @94c215d3 五链 PASS、镜像步失败) | `promotion-receipts/evidence-94c215d3-recovered-20260927/`(原目录误删,归档完整原始日志,README 说明) |
|
||||
| test 运行态 | health `env=test schema=76`;SPA 200;PI sidecar 18866 真实执行;S0 数据完整 |
|
||||
|
||||
## 收口
|
||||
|
||||
- deployment=test_ok(单二进制,schema 76);remote_sync=not_requested(未 push,origin/test 仍为 83c6a12a…本地 test 已前进两级 rc)
|
||||
- cleanup=pending:本 worktree HEAD 为晋升候选 M2(test 引用内容),集成收据提交后由独立维护者复查移除
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "dev→test 晋升(rc-v1.1.0-beta.4)与 test 单二进制化"
|
||||
task_id: test-single-binary-2026-09-27
|
||||
status: in_progress
|
||||
status: done
|
||||
created: 2026-09-27
|
||||
updated: 2026-09-27
|
||||
owner: pi
|
||||
@@ -21,9 +21,9 @@ write_scope:
|
||||
allowed_environments: ["dev", "test"]
|
||||
capabilities: [docs:publish, env:dev, env:test, git:dev, git:test]
|
||||
mutex: env:dev+env:test+git:dev+git:test
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
deployment: pending
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: test_ok_single_binary_rc_v1.1.0_beta.4
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
@@ -62,19 +62,20 @@ remote_sync: not_requested
|
||||
## 步骤与验收
|
||||
|
||||
1. [x] 建 worktree / 注册 / CURRENT 认领
|
||||
2. [x] 脚本落地(migrate-test-db.sh / launch-single.sh)
|
||||
3. [ ] worktree 验证(bash -n、scripts unittest、门禁套件)
|
||||
4. [ ] 集成入 dev(候选 + validate + integrate)
|
||||
5. [ ] dev tip 全面门禁 + nightly 真实 PI + receipt + candidate images
|
||||
6. [ ] test 晋升(候选 M + rc-v1.1.0-beta.4)
|
||||
7. [ ] test 单二进制转换 + 验收
|
||||
8. [ ] 报告 / CURRENT / 收口
|
||||
2. [x] 脚本落地(migrate-test-db.sh / launch-single.sh;含两处修复:DEV_PG_CONTAINER 变量名、SYSTEM_DB_* 强制覆盖根 .env CONTEXT_DB_*)
|
||||
3. [x] worktree 验证(bash -n、scripts unittest 234、门禁套件)
|
||||
4. [x] 集成入 dev(候选 94c215d3)
|
||||
5. [x] dev tip 全面门禁 + nightly 真实 PI + receipt + candidate images(含 .dockerignore 缺陷修复后 D2=5e409c1e 重跑)
|
||||
6. [x] test 晋升(候选 2fe1e055 + rc-v1.1.0-beta.4,promote-rc-beta4 任务执行)
|
||||
7. [x] test 单二进制转换 + 验收(见测试报告 §5.4–5.6)
|
||||
8. [x] 报告 / CURRENT / 收口
|
||||
|
||||
## 验证与证据
|
||||
|
||||
见 [测试报告](../../test-reports/2026-09-27-test-single-binary-test-report.md)(执行后填写)。
|
||||
见 [测试报告](../../test-reports/2026-09-27-test-single-binary-test-report.md)。过程事件(gate-pg 口令、runner key 清空机制、两次误连 dev 库审计、docker 上下文缺陷)如实记录于报告 §5.8。
|
||||
|
||||
## 收口与交接
|
||||
|
||||
- 分别记录 review_state / integration_state / deployment / cleanup / remote_sync。
|
||||
- 回滚(任一步失败且不可前滚时):容器路径 `docker compose -f docker-compose.test.yml -p agent-test up -d`(volumes 未删);DB 回滚用 S0 快照 restore 到容器 PG。
|
||||
- 分别记录:review_state=accepted;integration_state=merged_local_dev;deployment=test_ok(单二进制,schema 76);cleanup=pending(待独立维护者复查后移除 worktree);remote_sync=not_requested(未 push)。
|
||||
- 回滚(任一步失败且不可前滚时):容器路径 `docker compose -f docker-compose.test.yml -p agent-test up -d`(镜像已按 beta.4 digests pin;volumes 未删);DB 回滚用 S0 快照 restore 到容器 PG。
|
||||
- 待跟进(新任务):① sysadmin 初始 apply 空 key 清空 runner 配置(internal/app/app.go + internal/sysadmin/apply.go;建议 payload 空 key 省略)+ run-nightly 固化 MINIMAX_*/TAVILY 导出注释;② launch.sh sidecar 子 shell 相对 DATA_DIR(本次已在 launch-single.sh 规避,dev 侧 launch.sh 未改);③ systemd/install-test/preflight 打包(设计 §5.1,未在本轮范围)。
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: "修复激活预览 400 与管理台密码框警告"
|
||||
task_id: activation-preview-precheck-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/activation-preview-400-precheck-2026-09-28
|
||||
worktree: .worktrees/activation-preview-400-precheck-2026-09-28
|
||||
base_dev_sha: "b1ed8ecfe9fc5849288b6febf2bb4780319c8aca"
|
||||
write_scope:
|
||||
- web
|
||||
- .doc
|
||||
mutex: web-activation-preview
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: loaded_local_vite
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 修复激活预览 400 与管理台密码框警告
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户在 dev(`frp-mix.com:58880`)创建项目并添加「测试员工」后,浏览器控制台出现 `POST /api/v1/projects/6022/activation-preview 400`,以及 5 条 password 字段不在 form 内的 DOM 警告。授权:检查 dev 是否存在该问题并修复 dev。
|
||||
|
||||
## 检索
|
||||
|
||||
- 检索词:`activation-preview`、`NO_GOVERNED_DOCUMENT`、`clientDutyIssues`、`type="password"`。
|
||||
- 问题台账无 activation-preview / NO_GOVERNED 既有条目。
|
||||
- catalog overlap(mutex `web-activation-preview`)hard/soft 为空。登记时 `integrate-squad-commit-authority-2026-09-28` scope 为 `.`、`squad-commit-authority-2026-09-28` scope 为 `.doc`+`internal`,二者队列或分支均已是 dev 祖先且无活动 run,已 `task close --status done` 以释放写范围,未删除其 worktree。
|
||||
|
||||
## 事实
|
||||
|
||||
dev 库项目 6022「测试项目」(创建人 4,成员 74「测试员工」):`00:43:51` 保存规划 revision 1,激活令牌表无对应行;`00:45:08` 才发出令牌并在 `00:45:09` 激活。最终快照里仅 `bd_intake` 为 `author_only`,其余文档未纳入人工审批。服务端 `validateActivationPlan` 在零份完整职责时返回 400 `NO_GOVERNED_DOCUMENT`,行为符合门禁。缺口是前端 `clientDutyIssues` 不预检该门禁,用户可直接提交必然失败的计划。
|
||||
|
||||
5 条 DOM 警告对应管理台「模型与密钥」恰好 5 个 `Secret: true` 输入(`EnvSettingsSection`),`type=password` 且不在 `<form>` 内。登录与改密弹窗的密码框已在 form 内。
|
||||
|
||||
## ISSUE-20260928-activation-preview-precheck
|
||||
|
||||
issue_id: ISSUE-20260928-activation-preview-precheck
|
||||
issue_state: resolved
|
||||
module: web / projectSettings / activation-preview
|
||||
symptom: 全部文档未纳入人工审批时,点击「校验并预览」仍请求 activation-preview,控制台 400。
|
||||
cause: 前端预检未对齐 `validateActivationPlan` 的「至少一份完整人工审批」。
|
||||
fix: `needsGovernedDocument` 在非 live_edit 保存前本地拦截;配置页提示同一句文案。
|
||||
verification: `web` `npm test` 560 通过、`npm run build` 通过。dev 项目 6023:默认计划无 activation-preview 请求;兼任后 preview 200。报告见 `.doc/test-reports/2026-09-28-activation-preview-precheck-test-report.md`。
|
||||
|
||||
## ISSUE-20260928-admin-secret-password-form
|
||||
|
||||
issue_id: ISSUE-20260928-admin-secret-password-form
|
||||
issue_state: resolved
|
||||
module: web / admin / EnvSettingsSection
|
||||
symptom: 打开模型与密钥页时 Chromium 报 5 次 Password field is not contained in a form。
|
||||
cause: 5 个密钥 input 使用 password 类型但没有 form。
|
||||
fix: 每个设置行包在 form 内,密钥框 `autoComplete=new-password`。
|
||||
verification: dev 模型与密钥页 5 个 password 输入均在 form 内。
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: "助手回复智能体叙述优先"
|
||||
task_id: "agent-reply-llm-narrative-2026-09-28"
|
||||
status: in_progress
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: implementation
|
||||
task_tier: multi_stage
|
||||
policy_revision: "agent-governance-2026-09-21-r1 @ 8f77053f5169502eaf3e4e4135a082e8914f3704"
|
||||
branch: feature/agent-reply-llm-narrative-2026-09-28
|
||||
worktree: .worktrees/agent-reply-llm-narrative-2026-09-28
|
||||
base_dev_sha: "8f77053f5169502eaf3e4e4135a082e8914f3704"
|
||||
write_scope: ["internal/coordinator", ".doc"]
|
||||
allowed_environments: ["dev"]
|
||||
head_sha: ""
|
||||
mutex: "chat+coordinator"
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
deployment: pending
|
||||
cleanup: pending
|
||||
cleanup_owner: "独立维护者"
|
||||
cleanup_trigger: "dev 合入且验收证据落盘后复查 worktree"
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 助手回复智能体叙述优先
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
- 用户目标:助手回复尽可能由智能体生成,减少模板直答。授权来自本会话「实施助手回复智能化改造方案」。
|
||||
- 交付终点:T1/T2 叙述与 T3 结果通报走 PI Agent,失败回退模板;T4 安全话术保持模板;单测与 dev 真实 Runner 证据落盘后合入 local dev。
|
||||
- 禁止项:不 push、不晋升 test/main、不改确认卡结构与权限拒绝话术。
|
||||
- 例外:注册本任务前,`integrate-attachment-only-turn-2026-09-28` 以 scope `.` 仍为 active,但其分支已是当时 dev 祖先且队列为空。已将其 task state 记为 done 以解除 same_scope 硬门禁。未删除其 worktree。
|
||||
|
||||
## 范围与非目标
|
||||
|
||||
- 允许写入:`internal/coordinator` 叙述管道与意图 handler;本任务记录与测试报告。
|
||||
- 非目标:不改交互卡、挂起期望、澄清追问、权限不足与安全拦截文案的生成路径;不替换 `templates/docs` 交付物模板。
|
||||
|
||||
## 相关问题与经验
|
||||
|
||||
- issue_ids:无对应未关闭问题。
|
||||
- 开工检索 ISSUES / lessons INDEX(模板回复、答非所问、reply_source):无命中可复用条目。
|
||||
- 不新增 lesson:本次是既有「LLM 优先、模板兜底」机制的扩展,尚未出现新的复发机制。
|
||||
|
||||
## 步骤与验收
|
||||
|
||||
1. [x] 统一 `narrateReply` / `applyNarrative`,事实块进入提示词,开关 `AGENT_REPLY_LLM_ENABLED`。
|
||||
2. [x] T1 查询、T2 帮助、T3 已受理/已完成通报接入;确认提问与权限拒绝不接入。
|
||||
3. [x] `go test -short ./...`、`go vet`、`arch-check --mode block`,以及 `RUN_PI_E2E=1` 的真实 Runner 叙述用例。验收见 [测试报告](../../test-reports/2026-09-28-agent-reply-llm-narrative-test-report.md)。
|
||||
|
||||
按 [验证契约](../2026-09-21-validation-contract.md):Go 单测 + 产品 PI 受影响链路。
|
||||
|
||||
## 验证与证据
|
||||
|
||||
| 范围 / 被测 SHA | 命令与环境 | 预期 | 实际 / 判定 | 证据 / 脱敏说明 |
|
||||
|---|---|---|---|---|
|
||||
| coordinator 单测与全量 short | `go test -short ./...`;`arch-check --mode block`;`go vet ./...` | PASS | PASS | 见测试报告 |
|
||||
| 真实 Runner T1/T2/T3 | `RUN_PI_E2E=1 go test -run TestIntentReply_RealPI`,模型 MiniMax-M2.7-highspeed | reply_source=pi-agent | PASS(26.90s) | [测试报告](../../test-reports/2026-09-28-agent-reply-llm-narrative-test-report.md);未记录 token |
|
||||
|
||||
## 收口与交接
|
||||
|
||||
- 剩余工作:真实 Runner 证据、合入 local dev。
|
||||
- 本地提交 / dev 集成 / 部署 / 远端:尚未提交。
|
||||
- cleanup:合入后由独立维护者复查。
|
||||
- 需求目录:`R-agent-reply-llm-narrative`。
|
||||
|
||||
## 相关链接
|
||||
|
||||
- 方案:助手回复智能化改造(LLM 叙述优先、模板兜底)
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: "只上传文档时不再返回裸 HTTP 400"
|
||||
task_id: attachment-only-turn-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/attachment-only-turn-2026-09-28
|
||||
worktree: .worktrees/attachment-only-turn-2026-09-28
|
||||
base_dev_sha: "3e534bbb39d0d957e0b720a4ca06f22dd15959e6"
|
||||
write_scope:
|
||||
- internal
|
||||
- web
|
||||
- .doc
|
||||
mutex: attachment-only-turn
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: loaded_dev
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 只上传文档时不再返回裸 HTTP 400
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户只上传文档、不输入文字时,界面显示 `请求失败(HTTP_400)`,助手没有任何回复。授权按已确认方案修复:turn 协议携带附件引用;无文字时做结构化梳理或解析引导,并给出下一步选项;有文字但未要求处理文档时,先回答原文再追问是否总结或更新。
|
||||
|
||||
## 检索
|
||||
|
||||
- 检索词:`message cannot be empty`、`chat/stream`、`HTTP_400`、`@latest_upload`。
|
||||
- catalog overlap 语句探测 hard/soft 均为空。注册时若绑定 intent,会与仍为 active、但运行已结束的 `integrate-activation-preview-precheck-2026-09-28`(scope `.`)以及 `activation-preview-precheck-2026-09-28`(scope `.doc`+`web`)发生 same_scope。本次因此不绑 intent/mutex 到目录库,mutex 只写在 CURRENT 认领行。
|
||||
- 采纳现有 `DocumentSummaryReader`、`UploadParseStateGuidance` 和 `PendingExpectation`,不新开一条上传通道。
|
||||
|
||||
## 根因
|
||||
|
||||
前端允许仅附件发送。`POST /api/v1/chat/stream` 在 `message == ""` 时直接 400,且前端不读响应体,信封里的 `message cannot be empty` 被丢弃。附件从未进入 turn。
|
||||
|
||||
## 修复
|
||||
|
||||
- 空文字且带附件时合成落库句「已上传文档:《文件名》」,并把附件引用放进当轮上下文。
|
||||
- 无文字:解析未完成则说明状态并询问;正文可读则梳理、审阅并挂 1/2/3 选项(总结、说明如何修订、先不处理)。
|
||||
- 有文字但意图没有消费文档:正常回复后追加一次追问。
|
||||
- 聊天 SSE 的 4xx 读取信封;`VALIDATION` 展示具体原因,而不是 `HTTP_400`。
|
||||
|
||||
## 验证
|
||||
|
||||
见 [测试报告](../../test-reports/2026-09-28-attachment-only-turn-test-report.md)。代码候选 `cb4d2af8` 已在 local dev。`./scripts/launch.sh --no-docker` 于 2026-09-28 10:22(+0800)重建 `bin/agent-server` 并重启 :8080(pid 1002830,schema 78)。同一 Vite(:3100)上仅附件发送得到梳理与审阅,无关文字先回答再追问。
|
||||
|
||||
## 范围外
|
||||
|
||||
历史任务气泡重放 `tasks/runs/.../events` 的 HTTP/2 错误和 502 与这次 400 无因果关系,见 ISSUE-20260928-task-run-replay-502。
|
||||
|
||||
## 五态
|
||||
|
||||
- review_state: accepted(dev 浏览器三条路径已复验)
|
||||
- integration_state: merged_local_dev(代码 `cb4d2af8`,第一父 `63144067`)
|
||||
- deployment: loaded_dev(`bin/agent-server` 10:22 +0800,pid 1002830,`/health` schema 78)
|
||||
- cleanup: pending
|
||||
- remote_sync: not_requested
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: "修复 test 环境注册 INTERNAL"
|
||||
task_id: auth-register-internal-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/auth-register-internal-2026-09-28
|
||||
worktree: .worktrees/auth-register-internal-2026-09-28
|
||||
base_dev_sha: "4ba60c2c9d7eaf3e3e824475c0f3a44e10641190"
|
||||
write_scope:
|
||||
- deploy
|
||||
- internal
|
||||
- .doc
|
||||
mutex: auth-register
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: test_restarted
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 修复 test 环境注册 INTERNAL
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户在 test 环境注册新用户时收到 `{"code":"INTERNAL","message":"请求无法完成","error":"INTERNAL"}`。授权:完整修复(补种标准角色、重复用户名改为 400、500 补日志、回归与 test 实测)。
|
||||
|
||||
## 检索
|
||||
|
||||
- 检索词:注册、`role-guest`、`auth/register`、INTERNAL、23503。
|
||||
- ISSUES.md 无同因条目。catalog overlap(mutex `auth-register`)hard/soft 均为空。
|
||||
- 采纳:不改注册角色语义;修复缺失角色的自愈与唯一冲突误判。
|
||||
|
||||
## 根因
|
||||
|
||||
见 [ISSUE-20260928-register-internal](#issue-20260928-register-internal)。
|
||||
|
||||
## 变更
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 迁移 00077 | 幂等补种 role-director/tech-lead/engineer/guest,并置 `is_system=true` |
|
||||
| CreateUser | 用户名/account_id 唯一冲突返回 `ErrUsernameExists`(400) |
|
||||
| handler | 注册与登录的基础设施失败打 `slog.Error`(带 request_id);登录基础设施失败改为 500 |
|
||||
|
||||
## 验证
|
||||
|
||||
见 [测试报告](../../test-reports/2026-09-28-auth-register-internal-test-report.md)。
|
||||
|
||||
## ISSUE-20260928-register-internal
|
||||
|
||||
- 预期:test 允许自主注册时,新用户名注册成功;重复用户名返回可理解的 400。
|
||||
- 实际:test `POST /api/v1/auth/register` 必现 INTERNAL(复现 `req_diag_repro_002`);dev 新用户名成功,重复用户名也是 INTERNAL(`req_f0a8c723ed8e6c4a`)。
|
||||
- 已证实根因:test 库 `system_roles` 缺 `role-guest`,`user_role_bindings.role_id` 外键 23503。00015 只保护 `role-admin`,其余标准角色可删且启动引导不补种。重复用户名 23505 被 `insert user:` 判成基础设施 500。
|
||||
- 修复:00077 + `ErrUsernameExists` + 500 日志。
|
||||
- 状态:resolved。合入 `9141741b`;test 重启后 goose 记 version 77,注册 HTTP 200(`req_regfix_after_restart`,user_id 45,已删除)。
|
||||
|
||||
## 禁止
|
||||
|
||||
- 未授权 `git push` / 晋升 test/main
|
||||
- 用 `--build` 替换 rc 制品 `bin/agent-server-test`
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: "docgov 共享 map 并发读写导致进程崩溃"
|
||||
status: in_progress
|
||||
created: 2026-09-28
|
||||
owner: Cursor
|
||||
task_id: docgov-shared-map-race-2026-09-28-r2
|
||||
policy_revision: issue-learning-2026-09-23-r1 @ a3db288a
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
deployment: pending
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
updated: 2026-09-28
|
||||
write_scope: internal/docgov .doc/ops/CURRENT.md .doc/ops/short-term/2026-09-28-docgov-shared-map-race.md .doc/test-reports/2026-09-28-docgov-shared-map-race-test-report.md .doc/audit/ISSUES.md .doc/ops/lessons/2026-09-28-docgov-shared-map-race.md .doc/ops/lessons/INDEX.md
|
||||
mutex: docgov-shared-map-race
|
||||
base_dev_sha: a3db288a7aa055ff5884e3aa4d91511959cff721
|
||||
---
|
||||
|
||||
# docgov 共享 map 并发读写
|
||||
|
||||
## 范围与授权
|
||||
|
||||
用户报告 dev(`frp-mix.com:58880`)登录及多个 API 返回 500,并说明没有改登录代码。授权是查清原因并修复。允许写路径见 front matter。交付终点:共享 map 并发读写有回归测试,合入 local dev 后重建并复验 `/health` 与登录接口不再因进程死亡返回 500。不改登录协议,不晋升 test/main,不 push。
|
||||
|
||||
## 问题登记与经验检索
|
||||
|
||||
- issue_id: `ISSUE-20260928-docgov-map-race`
|
||||
- 检索词:`docgov`、`memDocs`、`concurrent map`、`500`、`登录`
|
||||
- 命中:`ISSUE-20260926-docgov-memdocs-poison`(同模块内存态与库分叉,机制不同,本轮不关)。无「per-doc 锁拆分后共享 map 无互斥」的既有经验。
|
||||
- 采纳:修共用 map 互斥,不用登录特例。
|
||||
|
||||
## 现象
|
||||
|
||||
2026-09-28 06:38 UTC,dev `agent-server` 在 `GetDocument`(`internal/docgov/engine_read.go`)触发 `fatal error: concurrent map read and map write` 后退出。06:38–06:49 Vite 代理 `ECONNREFUSED 127.0.0.1:8080`,登录、`auth/me`、通知、维护状态等全部 500。06:49 进程被重新拉起后接口恢复。登录代码未改。
|
||||
|
||||
## 根因
|
||||
|
||||
`340342fa` 把 docgov 全局锁拆成 per-doc 锁。per-doc 锁只串行同一 `docID`。`memDocs`、`memAudits`、`memComms`、`memProps` 仍被不同文档并发读写。`e.mu` 不是可重入锁,且部分调用方已经持有它,所以新增 `memMu` 专门保护这四张 map。锁序:docLocks → `e.mu` → `memMu`。
|
||||
|
||||
## 修复
|
||||
|
||||
`a90cce73`。回归:`TestMemMapsNoRaceAcrossDocs`(`go test -race`)。
|
||||
|
||||
## 五态
|
||||
|
||||
| 字段 | 值 |
|
||||
|---|---|
|
||||
| review_state | pending |
|
||||
| integration_state | pending |
|
||||
| deployment | pending(合入后需重建 dev `agent-server`) |
|
||||
| cleanup | pending |
|
||||
| remote_sync | not_requested |
|
||||
|
||||
## ISSUE-20260928-docgov-map-race
|
||||
|
||||
- 预期:文档治理并发不杀死 HTTP 进程;登录等无关 API 保持可用。
|
||||
- 实际:2026-09-28 06:38 UTC 进程 fatal,约 11 分钟内全部 API 500。
|
||||
- 状态:verifying(单测已过;dev 重建复验尚未做)。
|
||||
- 同类:所有裸读写上述四张 map 的路径,已收口到 `memMu` 辅助函数。`ISSUE-20260926-docgov-memdocs-poison` 仍是另一机制。
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: "统一错误码、结构化日志与错误审计"
|
||||
task_id: "error-code-observability-2026-09-28"
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: implementation
|
||||
task_tier: multi_stage
|
||||
policy_revision: "agent-governance-2026-09-21-r1 @ 3e534bbb39d0d957e0b720a4ca06f22dd15959e6"
|
||||
branch: feature/error-code-observability-2026-09-28
|
||||
worktree: .worktrees/error-code-observability-2026-09-28
|
||||
base_dev_sha: "3e534bbb39d0d957e0b720a4ca06f22dd15959e6"
|
||||
write_scope: ["internal", "deploy/postgres/goose", "web", ".doc"]
|
||||
allowed_environments: []
|
||||
head_sha: "dddd3fe8c828867116b602208dfd5783f2b9d2ab"
|
||||
mutex: error-code-observability
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: not_required
|
||||
cleanup: pending
|
||||
cleanup_owner: "独立集成/维护执行者"
|
||||
cleanup_trigger: "dev 合入且验收证据落盘后复查 worktree"
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 统一错误码、结构化日志与错误审计
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
- 用户目标:为系统加入详细错误码、日志和审计,使失败能凭 `code + request_id` 定位,不必靠翻代码。审计覆盖 HTTP 与异步错误;错误码覆盖全部模块。授权来自本对话对计划「统一错误码 + 结构化日志 + 错误审计体系」的实施指令。
|
||||
- 交付终点:注册表、HTTP 错误日志、`error_events`、管理台查询、流式分类读取类型化错误码、`err.Error()` 透传收敛、错误码目录,以及验证报告后合入 local dev。
|
||||
- 明确禁止项:不 push,不晋升 test/main,不改 FEATURE-MATRIX 状态值,不操作共享运行环境。
|
||||
- 例外:无。
|
||||
|
||||
## 范围与非目标
|
||||
|
||||
- 允许写入:`internal/errcode`、`internal/errorevents`、`internal/httpx`、`internal/server`、`internal/stream`、`internal/app`、`internal/events`、`internal/taskrun`、`internal/ctxmgr`、`deploy/postgres/goose/00078_*`、`web` 管理台与失败气泡、`.doc` 目录与任务记录。
|
||||
- 非目标:不引入 OpenTelemetry;不改变错误信封的顶层字段名;不把审计写失败变成请求失败。
|
||||
|
||||
## 相关问题与经验
|
||||
|
||||
- issue_ids:无单独问题单。开工检索 `错误码`、`writeSafeError`、`error_events`:问题台账与 lessons 索引没有可复用的统一错误码条目。采纳的检查是模块边界 allowlist、信封脱敏 `LooksInternal`、审计写失败不阻断请求。
|
||||
- 不新增 lesson:机制已写进错误码目录;待合入后再看是否需要经验条目。
|
||||
|
||||
## 步骤与验收
|
||||
|
||||
1. [x] `internal/errcode` 注册表与唯一性/脱敏测试。
|
||||
2. [x] `httpx` 错误日志、`X-Request-ID` 始终下发、访问日志 `err_code`。
|
||||
3. [x] 迁移 `00078`、`errorevents` 写端口、`app` 注入、异步失败上报。
|
||||
4. [x] 管理台 `GET /api/v1/admin/system/error-events` 与错误审计界面。
|
||||
5. [x] `ClassifyError` 优先读取 `ErrorCode()`。
|
||||
6. [x] 带 `.Error()` 的 `writeSafeError` 改为 `writeDomainError`;字面量仍走 `FromLegacy`。
|
||||
7. [x] 错误码目录与文档地图。
|
||||
8. [x] `arch-check`、`go vet`、`go test -short`、前端测试与构建,测试报告。
|
||||
9. [x] `validate` 后 `queue enqueue` 合入 dev。实现提交 `dddd3fe8c828867116b602208dfd5783f2b9d2ab` 已在 local dev。
|
||||
|
||||
## 验证与证据
|
||||
|
||||
| 范围 / 被测 SHA | 命令与环境 | 预期 | 实际 / 判定 | 证据 / 脱敏说明 |
|
||||
|---|---|---|---|---|
|
||||
| 工作树未提交源码,基线 3e534bbb | 见测试报告第五节 | 工程门禁与前端测试通过 | PASS;审计 PG 往返 SKIP | [测试报告](../../test-reports/2026-09-28-error-code-audit-test-report.md) |
|
||||
|
||||
产品 PI 全链路不在本次范围:改动是错误信封、日志和审计查询,不改变 Runner 协议。未运行的 PI 链路不记为 PASS。
|
||||
|
||||
## 收口与交接
|
||||
|
||||
- 剩余工作:无功能残项。`TestStoreRoundTrip` 仍待隔离测试库。
|
||||
- 本地提交 / dev 集成 / 部署制品 / 远端状态:实现已合入 local dev `dddd3fe8`;deployment=not_required;remote_sync=not_requested。cleanup=pending,不删除 worktree。
|
||||
- cleanup:合入后由独立维护者复查,本任务不删除 worktree。
|
||||
|
||||
## 相关链接
|
||||
|
||||
- [错误码目录](../../system-design/2026-09-28-error-code-catalog.md)
|
||||
- [测试报告](../../test-reports/2026-09-28-error-code-audit-test-report.md)
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "补跑错误审计表隔离库往返"
|
||||
task_id: "error-events-pg-roundtrip-2026-09-28"
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: implementation
|
||||
task_tier: small
|
||||
policy_revision: "agent-governance-2026-09-21-r1 @ 655fb4f149de23154aa05aa2b9eff83d2d02388a"
|
||||
branch: feature/error-events-pg-roundtrip-2026-09-28
|
||||
worktree: .worktrees/error-events-pg-roundtrip-2026-09-28
|
||||
base_dev_sha: "655fb4f149de23154aa05aa2b9eff83d2d02388a"
|
||||
write_scope: [".doc"]
|
||||
allowed_environments: []
|
||||
head_sha: ""
|
||||
mutex: error-events-pg-evidence
|
||||
review_state: accepted
|
||||
integration_state: pending
|
||||
deployment: not_required
|
||||
cleanup: pending
|
||||
cleanup_owner: "独立集成/维护执行者"
|
||||
cleanup_trigger: "报告合入 dev 后复查 worktree"
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 补跑错误审计表隔离库往返
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
- 延续错误码审计任务。合入前 `TestStoreRoundTrip` 因没有 `TEST_DATABASE_URL` 被跳过。本次只补跑隔离库并更新测试报告。
|
||||
- 不改产品代码,不连开发库,不 push。
|
||||
|
||||
## 验证与证据
|
||||
|
||||
一次性 `pgvector/pgvector:pg16`,端口 `127.0.0.1:15432`,库 `agent_itest`。迁移到 78 后 `TestStoreRoundTrip` PASS(0.428s)。容器已删除。
|
||||
|
||||
## 收口
|
||||
|
||||
- review_state:accepted
|
||||
- integration_state:pending(本记录随候选合入)
|
||||
- deployment:not_required
|
||||
- cleanup:pending
|
||||
- remote_sync:not_requested
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: "晋升 rc-v1.1.0-beta.5(当前 dev→test)并重启 test"
|
||||
task_id: promote-rc-beta5-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: ops
|
||||
task_tier: small
|
||||
policy_revision: "AGENTS+worktree-ops @ 193a752f"
|
||||
branch: feature/promote-rc-beta5-2026-09-28
|
||||
worktree: .worktrees/promote-rc-beta5-2026-09-28
|
||||
base_dev_sha: "193a752f1a540fb22e9b54feb56d8aa8e2f30cc1"
|
||||
head_candidate: "73836962a0932d7be868f593804b09a321e0902c"
|
||||
write_scope: ["."]
|
||||
allowed_environments: ["test"]
|
||||
capabilities: [git:test, env:test, docs:publish, docs:admin]
|
||||
mutex: git:test+env:test
|
||||
review_state: accepted
|
||||
integration_state: merged_local_test
|
||||
deployment: test_ok
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 晋升 rc-v1.1.0-beta.5
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户指令(2026-09-28):不要继续跑长门禁,把当前运行中的 dev 合入 test,并重启最新 test 服务;工作区与数据库连接不得串到 dev。授权来源:本会话明确指令。未授权 push。
|
||||
|
||||
已中止本会话启动的 nightly(`run-nightly-real-pi.sh` @ `8f77053f`,FullNoneMixedChain 首轮 MISSING_TARGET 后仍在跑 TestManager)。不把未完成的 nightly 写成 PASS 收据。
|
||||
|
||||
## 结果
|
||||
|
||||
- 冻结并晋升的 dev:`193a752f`(含 PI runner 数据目录校验)。test 从 `2fe1e055`(rc-v1.1.0-beta.4)前进到 `73836962`。
|
||||
- 候选:commit-tree,P1=`2fe1e055`,P2=`193a752f`,树与 dev 相同。validate run `21f631ce`(拓扑 + `git diff --quiet`)。
|
||||
- `git:test` 租约内 `update-ref refs/heads/test` + tag `rc-v1.1.0-beta.5`。
|
||||
- 制品:主仓 `bin/agent-server-test`,由 `193a752f` 工作树构建(demo seeds off)。`launch-single.sh test` 在清空调用方 `DATA_DIR` / `PI_AGENT_RUNNER_URL` 后启动,避免根 `.env` 的 dev 值生效。
|
||||
- 租约因 nohup 进程组未退出记 `recovery_required`(run `eaf7e2e4`)。服务改由独立会话拉起后,`recover --reason verified:` 已收口。
|
||||
|
||||
## 连接核对(重启后)
|
||||
|
||||
| 项 | 实际 |
|
||||
|---|---|
|
||||
| health/ready `:8081` | `env=test`,`schema_version=78`,`database_ready/kb_ready=true`,SPA 200 |
|
||||
| 进程 | `bin/agent-server-test`,`SEED_DEMO_USERS=false` |
|
||||
| 系统库 | `127.0.0.1:5434/agent_system_test`(连接已建立;projects=11,users=11,与重启前相同) |
|
||||
| 共享 KB | 宿主将 `shuimu-kb-shared` 规范为 `127.0.0.1:5432/regulations` |
|
||||
| 工作区 | `DATA_DIR` 解析为 `data/test`;sidecar `:18866` 的 `data_dir=data/test/workspaces` |
|
||||
| dev 未串 | test 进程无到 `:5433` 的连接;dev `:8080` 仍在,projects=25;sidecar `:18865` 仍是 `data/dev/workspaces` |
|
||||
|
||||
## 清理
|
||||
|
||||
已合入 dev 且任务 done 的 worktree,在去掉可再生忽略文件后 `agent-worktree.sh remove --delete-branch`。未动:进行中的 agent-reply / test-user-doc 现场、squad evidence 未提交文档、u9u12(用户 shell 占用)、intent-material-fallback(有未提交跟踪修改)、pi-runner 任务目录(本地 `configs/.env.test` 与主仓不一致)。
|
||||
|
||||
`feature/full-system-browser-e2e-2026-09-26` 分支已 `-d`(祖先为 `a9d79b99`)。目录残留 root 拥有的 `playwright-output-main/`,普通删除被拒绝,保留待授权清理。
|
||||
|
||||
## 收口
|
||||
|
||||
- deployment=test_ok;remote_sync=not_requested。
|
||||
- 本记录提交在晋升分支上。当时另有 integrate 候选未合入 dev,故未把本文件 enqueue 进 dev,避免挤占对方基线。
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
title: "晋升 rc-v1.1.0-beta.6(dev→test)与已结束 worktree 清理"
|
||||
task_id: promote-rc-beta6-closeout-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: ops
|
||||
task_tier: small
|
||||
policy_revision: "AGENTS+worktree-ops @ 714732df"
|
||||
branch: feature/promote-rc-beta6-closeout-2026-09-28
|
||||
worktree: .worktrees/promote-rc-beta6-closeout-2026-09-28
|
||||
base_dev_sha: "714732df5a378eae43df0f73ad6a059a4840c3e1"
|
||||
head_candidate: "0664abe57d85f7776874728e92476c5360388b2a"
|
||||
write_scope: [".doc"]
|
||||
allowed_environments: ["test"]
|
||||
capabilities: [docs:publish, docs:admin]
|
||||
mutex: git:test+env:test
|
||||
review_state: accepted
|
||||
integration_state: merged_local_test
|
||||
deployment: test_ok
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 晋升 rc-v1.1.0-beta.6
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户指令:继续把 dev 合入 test,并清理已结束现场。不跑 nightly,不 push。
|
||||
|
||||
## 结果
|
||||
|
||||
- beta.5 记录先合入 dev:`714732df`(`merge: candidate land-promote-rc-beta5-record-2026-09-28 into dev`)。首次入队因主仓未跟踪的中止 nightly 证据被 `DIRTY_TREE` 拒绝;证据移到 `/tmp/agent-nightly-aborted-8f77053f/` 后,r2 候选合入。
|
||||
- test 从 `73836962`(rc-v1.1.0-beta.5)前进到 `0664abe5`,标签 `rc-v1.1.0-beta.6`。第一父是上一轮 test,第二父是 `714732df`,树与该 dev 相同。validate run `f3fed9d6`。
|
||||
- 制品:主仓 `bin/agent-server-test`,由 `714732df` 构建。启动前清掉调用方 `DATA_DIR` 与 `PI_AGENT_RUNNER_URL`。
|
||||
- 租约 run `c1eb671a` 因后台进程组未退出进入 `recovery_required`。服务改由独立会话拉起后已 `recover`。
|
||||
|
||||
## 连接核对
|
||||
|
||||
| 项 | 实际 |
|
||||
|---|---|
|
||||
| health `:8081` | `env=test`,schema 78,数据库与共享知识库就绪;首页 200 |
|
||||
| 系统库 | `127.0.0.1:5434/agent_system_test`;projects=11,users=11,与重启前相同 |
|
||||
| 工作区 | `DATA_DIR` 解析为 `data/test`;sidecar `:18866` 数据目录为 `data/test/workspaces` |
|
||||
| dev 未串 | test 进程无到 `:5433` 的连接;dev `:8080` 仍在;`:18865` 仍是 `data/dev/workspaces` |
|
||||
|
||||
构建把主仓已跟踪的 `web/dist/.gitkeep` 从工作区删掉,已 `git checkout` 恢复,未形成新提交。
|
||||
|
||||
## 清理
|
||||
|
||||
已删除:`fix/test-user-doc-issues-2026-09-28`(只剩 `.codegraph/`);`feature/integrate-land-promote-rc-beta5-record-2026-09-28-r2`(已是 dev)。
|
||||
|
||||
留下:`feature/integrate-land-promote-rc-beta5-record-2026-09-28`(首个候选不是 dev 祖先,`cleanup_pending`);进行中的 agent-reply、quality-gate、refresh-task-state、subagent-process-view、e2e-wipe 及其 integrate 场;intent-material-fallback 与 squad evidence 的未提交修改;pi-runner 本地 `configs/.env.test` 与主仓不一致;u9u12 仍被 PID 3386059 占用;root 拥有的 e2e `playwright-output-main/`。
|
||||
|
||||
## 收口
|
||||
|
||||
deployment=test_ok;remote_sync=not_requested。本记录随后合入 dev。test 这一刀不含本文件。
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
title: "质量门禁章节标题漂移不再误判缺章"
|
||||
task_id: quality-gate-heading-mismatch-2026-09-28-r2
|
||||
status: in_progress
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/quality-gate-heading-mismatch-2026-09-28
|
||||
worktree: .worktrees/quality-gate-heading-mismatch-2026-09-28
|
||||
base_dev_sha: "434d542c3cbdbeac38b9c0e547edf75160acf577"
|
||||
write_scope:
|
||||
- internal/squad
|
||||
- internal/coordinator
|
||||
- .doc
|
||||
mutex: quality-gate-heading
|
||||
review_state: pending
|
||||
integration_state: local_only
|
||||
deployment: not_deployed
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 质量门禁章节标题漂移不再误判缺章
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
dev「吞咽电刺激」调研报告已写完,助手称已生成,界面却是「质量未通过」,受控文档没有更新。用户要求先确认失败原因;若只是项目信息仍在迭代,不得因此判质量不通过,并给出可落地修复。用户确认:标题做归一化并跨 H2–H4 匹配;聊天触发任务默认打开质量自动修复;门禁修复合入后重新发起调研报告。
|
||||
|
||||
## 检索
|
||||
|
||||
- 检索词:`quality_report`、`缺少必填章节`、`extractHeadings`、`质量未通过`、`AutoRepair`。
|
||||
- 命中 [ISSUE-20260928-quality-failed-success-copy](../../audit/ISSUES.md):同步回复在质量失败时不得写宿主机路径、不得声称已完成。当前 `formatTriggerTaskReply` 已把非完成态交给 `CompletionSummary`,本任务不改这句文案,只补聊天链路的 `AutoRepair`。
|
||||
- catalog overlap 语义层无命中。注册时若绑定 intent,会与仍为 active 的 `agent-reply-llm-narrative-2026-09-28`(scope `internal`+`.doc`)以及若干 scope `.` 的 integrate 任务发生 same_scope。该叙述任务改过 `engine_task.go` 的返回包装,与本次 `TaskRunRequest` 字段不在同一行。本次因此不绑 intent/mutex 到目录库,mutex 只写在 CURRENT 认领行。首个 task id 因 scope 不含 `.doc/ops` 无法认领,已 cancelled,改用 `quality-gate-heading-mismatch-2026-09-28-r2`。
|
||||
|
||||
## 根因
|
||||
|
||||
`research_1790566833205199368/manifest.json` 的 `quality_report.passed=false`,唯一违规是缺少「技术路线与 State-of-the-Art」。终稿该节在 `output.md` 第 279 行,标题是 `### 技术路线与State-of-the-Art`:层级降成 H3,且「与」后少了空格。门禁原先只抽 H2,清洗序号后做字符串精确相等,因此把格式漂移当成整章缺失。评分 85 仍高于 80,但缺章直接 `Passed=false`。
|
||||
|
||||
质量失败后 `finalizeSquadDeliverable` 按设计不投影受控文档,所以正文留在隔离工作区、项目文档不更新。这次 `workspace.json` 的 `project_id` 为 0,docID 为空,聊天触发又没设 `AutoRepair`,修复轮为 0。
|
||||
|
||||
门禁不检查「待确认」数量。信息还在迭代补齐,不是这次失败的原因。
|
||||
|
||||
## 修复
|
||||
|
||||
- 模板 H2 与正文 H2–H4 按归一化标题比对:去掉全部空白(含全角空格)、全角 ASCII 折半角、英文字母小写。只在 H3/H4 命中时记「章节层级与模板不一致」,不扣分、不阻断。归一化后仍没有的章节继续判缺失。
|
||||
- `handleTriggerTask` 设置 `AutoRepair: true`,修复轮上限仍是 `DefaultMaxRepairRounds`。
|
||||
- `module-boundaries.yaml` 为 coordinator 补上已有的 `projectworkflow` 依赖。该 import 在基线 `434d542c` 的 `engine_task.go` 里就存在,本 diff 没有新增 import;block 模式基线计数为 0,不补允许项则门禁对当前 dev 也是红的。
|
||||
|
||||
## 同类
|
||||
|
||||
dev 历史 `passed: false` 工作区里,`test_manager_1790215680339783789` 的「签署/说明」是「十一、」「十二、」序号,现有序号清洗已能对上。`intake_1789329815528283509` 当前正文已有「阻塞信息」「非阻塞信息」H2,不能用现状复现当时的缺章。`intake_1789269755280857331` 模板要「正文」,成稿没有这个标题,缺章判定仍然正确。
|
||||
|
||||
## 验收
|
||||
|
||||
单测覆盖:空格/全角/大小写漂移通过且有层级软警告;真实缺「正文」仍失败;聊天触发 `AutoRepair=true`;质量失败回复不含「已完成生成」。报告见 [质量门禁标题漂移测试报告](../../test-reports/2026-09-28-quality-gate-heading-mismatch-test-report.md)。合入 dev 后从项目上下文重跑调研报告,确认 `project_id>0` 且 `quality_report.passed=true`、受控文档有新 head。
|
||||
|
||||
## ISSUE-20260928-quality-heading-drift
|
||||
|
||||
- 预期:模板要求的章节只要正文里有同名内容,就不因空格或降为 H3/H4 被判整章缺失。
|
||||
- 实际:调研报告终稿被判缺少「技术路线与 State-of-the-Art」,评分 85,文档不投影。
|
||||
- 状态:verifying。单测已覆盖原例形状;dev 重跑调研报告后改为 resolved。
|
||||
|
||||
## ISSUE-20260928-data-dir-doubled
|
||||
|
||||
- 观察:存在 `data/dev/data/dev/workspaces/bizdev/intake_1790565513115586191/output.md`,该目录没有 `workspace.json`。正确工作区在 `data/dev/workspaces/bizdev/intake_1790565513115586191/`。
|
||||
- 假设:某处把已含 `data/dev` 的 DataDir 又拼了一次。未沿调用链证实,本任务不修。
|
||||
- 状态:open。复查触发:下次出现交付路径含 `data/dev/data/dev` 时沿写入点追查。
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
title: "刷新后恢复任务进度并纠正进度问询"
|
||||
task_id: refresh-task-state-recovery-2026-09-28
|
||||
status: in_progress
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/refresh-task-state-recovery-2026-09-28
|
||||
worktree: .worktrees/refresh-task-state-recovery-2026-09-28
|
||||
base_dev_sha: "4c42d1bf74e262930bcf127e517ab6b76a0dda71"
|
||||
write_scope:
|
||||
- internal
|
||||
- web
|
||||
- .doc
|
||||
mutex: refresh-task-state-recovery
|
||||
review_state: pending
|
||||
integration_state: branch_only
|
||||
deployment: not_loaded
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 刷新后恢复任务进度并纠正进度问询
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户发起调研报告后,聊天下方的任务进度在刷新页面时消失。随后两次询问「调研报告编写进度怎么样了」,没有看到调研报告生成。用户要求浏览器和服务器同时记下进行中的任务:刷新或重连后先显示本地缓存,再按会话和任务标识向服务器收敛。授权范围同时包含进度问句被当成新任务,以及 11:27 / 11:38 两次步骤被判空输出失败。
|
||||
|
||||
## 检索
|
||||
|
||||
- 问题台账命中 ISSUE-20260928-task-run-replay-502(历史失败气泡重放 502)。本轮给重放补了退避,并保持终态 `replay_only`。
|
||||
- catalog overlap 探测无硬重叠。mutex 为 `refresh-task-state-recovery`,不占用 `chat+coordinator` 与 `bizdev+docflow`。
|
||||
|
||||
## 根因
|
||||
|
||||
1. `run_id` 与阶段快照只在任务终态写回助手消息。窗口缓存只保存服务端窗口,刷新后没有锚点,进度卡片无法重放。
|
||||
2. 「调研报告编写进度怎么样了」含写动词「编写」和任务名词「调研报告」。`matchTriggerTask` 排在进度查询之前,于是又启动了 research。进度回复只读模板,不读真实 run。
|
||||
3. 步骤判定把 runner 的 `Success=false` 当成失败,即使盘上已经有正文。连接错误留下的文件仍可能是截断的,这条不能放宽。
|
||||
|
||||
## 修复
|
||||
|
||||
- run 启动和绑定助手消息时写入 `{run_id, task_status: running}`。
|
||||
- `GET /api/v1/tasks/runs?session_id=&active=1` 只返回当前用户、当前会话里仍为 pending/running 的 run。
|
||||
- 浏览器 `smdf_agent_workbench_v6_active_tasks` 在窗口就绪后先画出进行中卡片,再用活跃列表收敛;终态删除缓存。
|
||||
- 有 run 锚点但还没有 `task_status` 和阶段快照时,消息保持 `streaming_status`。终态重放对 502 退避,401/404 不再试。
|
||||
- 疑问进度句让行 `QUERY_PROGRESS`。回复读取该会话最近一次 run 的真实状态。
|
||||
- 盘上已有非空正文,且失败原因不是传输/可重试错误时,步骤接受该文件。空 patch 不覆盖已有 `output.md`。
|
||||
|
||||
## 验证
|
||||
|
||||
见 [测试报告](../../test-reports/2026-09-28-refresh-task-state-recovery-test-report.md)。
|
||||
|
||||
## 五态
|
||||
|
||||
合入与 dev 重载完成后回写。当前仍是任务分支上的实现。
|
||||
@@ -0,0 +1,67 @@
|
||||
---
|
||||
title: "恢复管理台重置密码入口"
|
||||
task_id: restore-admin-password-reset-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: feature/restore-admin-password-reset-2026-09-28
|
||||
worktree: .worktrees/restore-admin-password-reset-2026-09-28
|
||||
base_dev_sha: "912957c44ec1bd91f6010d657a909e5120546f74"
|
||||
write_scope:
|
||||
- web
|
||||
- .doc
|
||||
mutex: auth
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: not_required
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 恢复管理台「重置密码」
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
管理员在「用户与准入治理」重置用户密码:服务端生成随机临时口令;被重置用户下次登录必须修改密码,且仅这一次。来源:用户当次会话授权修复,禁止移除该能力。
|
||||
|
||||
## 检索
|
||||
|
||||
- 检索词:重置密码、`adminResetPassword`、`UsersSection`、T20-F4。
|
||||
- 命中:[ISSUE-20260924-admin-reset-dead](../../audit/2026-09-24-admin-password-reset-issues.md)(resolved)。端点 `POST /api/v1/admin/users/{id}/reset-password` 已在 `39f8c1d1` 合入,且 `d653e32e` 的基线 `725181de` 包含该提交。
|
||||
- 采纳:不重做 API、审计表或强制改密弹窗。本任务只恢复被误删的 UI。根因不同,另立 [ISSUE-20260928-admin-reset-ui-removed](#issue-20260928-admin-reset-ui-removed)。
|
||||
- catalog overlap(mutex `auth`):hard/soft 均为空,无需 ack。
|
||||
|
||||
## 根因
|
||||
|
||||
`d653e32e`(T20-S1 F4-A)按过期设计注释删除了 `UsersSection` 的「重置密码」按钮和 `handleResetUserPassword`,并写明「端点未开通」。当时 F4-B 端点、`authClient.adminResetPassword`、`must_change_password` 与 `FirstLoginPasswordModal` 均已在 dev。同类入口(停用、编辑资料)未受影响。
|
||||
|
||||
## 变更
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| UI | 恢复确认框、`adminResetPassword`、一次性临时口令提示、成功通知 |
|
||||
| 后端 | 无改动。随机 16 位口令、`must_change_password=true`、撤销会话、审计表保持 F4-B 行为 |
|
||||
|
||||
## 验证
|
||||
|
||||
见 [测试报告](../../test-reports/2026-09-28-admin-password-reset-restore-test-report.md)。
|
||||
|
||||
## ISSUE-20260928-admin-reset-ui-removed
|
||||
|
||||
- 预期:管理员可在用户与准入治理重置密码。
|
||||
- 实际:按钮消失;后端路由仍在 `internal/server/server.go`。
|
||||
- 已证实根因:F4-A 在端点已存在的基线上删除 UI,注释与 `git merge-base` 事实不符。
|
||||
- 修复:恢复 `web/src/components/admin/console/sections/UsersSection.tsx` 入口。
|
||||
- 状态:resolved。UI 已随 `04d7fec4` 合入 local dev;证据见测试报告。
|
||||
|
||||
## 经验小结
|
||||
|
||||
删除「端点未开通」的界面前,用当前基线 SHA 核对路由是否已存在(`git merge-base --is-ancestor`),不要只信设计文档里的「待产品选型」。详见 [LESSON-20260928-ui-dead-control](../lessons/2026-09-28-ui-dead-control.md)。
|
||||
|
||||
## 禁止
|
||||
|
||||
- 未授权 `git push` / 晋升 test/main
|
||||
- 临时口令写入 git、聊天或报告正文
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
title: "修复非编制人触发小队账本提交被拒"
|
||||
task_id: squad-commit-authority-2026-09-28
|
||||
status: in_progress
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/squad-commit-authority-2026-09-28
|
||||
worktree: .worktrees/squad-commit-authority-2026-09-28
|
||||
base_dev_sha: "774df0599813fb8d7115f95ce255384542d6a0f9"
|
||||
write_scope:
|
||||
- internal
|
||||
- .doc
|
||||
mutex: bizdev+docflow
|
||||
review_state: pending
|
||||
integration_state: pending
|
||||
deployment: pending
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 修复非编制人触发小队账本提交被拒
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户生成《用户初始需求收集表》时小队任务失败,诊断为 `TASK_FAILED` / `uow: permission denied`。授权:以编制人身份自动提交账本,并用 `OnBehalfOf` 记录实际触发用户;先用 dev 库核实身份后再改代码。
|
||||
|
||||
## 检索
|
||||
|
||||
- 检索词:`uow: permission denied`、`ErrPermissionDenied`、`文档版本账本/变更报告落盘失败`、`bd_intake`、非编制。
|
||||
- 命中 [ISSUE-20260924-non-author-400-duty](../../audit/ISSUES.md) 与 [LESSON-20260924-deny-only-submit](../lessons/2026-09-24-deny-only-submit.md):成员可以跑草稿,但下游门必须一起放行。本问题是账本 `ActionCommit` 仍按触发者比对编制人,属于该教训的下游缺口,不是同一 HTTP 400。
|
||||
- 命中 [ISSUE-20260926-docgov-uow-deadlock](../../audit/ISSUES.md):同为 uow 失败,机制是行锁自死锁,不适用。
|
||||
- catalog overlap(mutex `bizdev+docflow`)hard/soft 为空。登记时 `integrate-restore-admin-password-reset-2026-09-28` 与其 close 任务仍 `active` 且 scope 为 `.`,队列已 completed、提交已是 dev 祖先,已 `task close --status done` 以释放仓库级写范围,未删除其 worktree。
|
||||
|
||||
## ISSUE-20260928-squad-commit-authority
|
||||
|
||||
issue_id: ISSUE-20260928-squad-commit-authority
|
||||
issue_state: fixing
|
||||
severity: high
|
||||
owner: Cursor
|
||||
task_ids: [squad-commit-authority-2026-09-28]
|
||||
created: 2026-09-28
|
||||
occurred_at: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
recurrence_count: 0
|
||||
evidence_basis: current
|
||||
lesson_ids: [LESSON-20260928-squad-commit-as-author]
|
||||
|
||||
### 事实与证据
|
||||
|
||||
预期:项目成员触发受控文档生成后,小队正文能写入版本账本。实际:任务 `run_1790556318606671340`、`run_1790556736148378090`(project 6022,task_key `intake`,user_id 74)失败,`error_message=uow: permission denied`。界面文案为「《用户初始需求收集表》未成功落盘」加上裸 `uow: permission denied`。
|
||||
|
||||
dev 库只读核实(2026-09-28,`agent_system_dev`):`document_records.doc_proj6022_bd_intake` 的 `author_id=4`(admin,项目 owner,`document_duty=author`);触发者 74 是成员 `ceshi`,`project_role=viewer`。项目创建者是 user 4。
|
||||
|
||||
### 根因与同类范围
|
||||
|
||||
已证实:`finalizeSquadDeliverable` 把 `AutoCommitUserID` 设为触发者 `req.UserID`。生产路径经 `docflow.Commands.MaterializeAgent` 用该 id 做 `ActionCommit`。`dutyAuthorizer` 在编制人与触发者都非 0 且不相等时返回 `uow.ErrPermissionDenied`。小队正文与质量门禁已通过,失败只发生在账本提交。
|
||||
|
||||
同类:API 直连已把该哨兵映射为 403。缺口只在小队自动提交。编制人自己触发、高风险 `needs_confirmation`、批准/驳回职责检查应保持不变。
|
||||
|
||||
### 修复思路与过程
|
||||
|
||||
选择以文档编制人作为自动提交身份,触发者写入已有 `OnBehalfOf`。不放宽 `dutyAuthorizer`,避免 viewer 直接获得编制人编辑权。高风险候选仍待编制人确认。
|
||||
|
||||
| 日期 | 动作 | 结果 | 下一步 |
|
||||
|---|---|---|---|
|
||||
| 2026-09-28 | dev 库核对 author 与 task_runs.user_id | 4 ≠ 74,两次失败均为 permission denied | 按编制人代理提交实现 |
|
||||
| 2026-09-28 | `squadCommitActor` + 回归 | 内存单测通过;dev 真实重跑未做 | 合入 dev 后用非编制人重跑 |
|
||||
|
||||
### 验收与关闭
|
||||
|
||||
尚未关闭。原例待 dev 重跑;变体与正常路径见 `TestExecuteTask_NonAuthorTriggerMaterializesAsAuthor`、`TestExecuteTask_AuthorTriggerDoesNotSetOnBehalfOf`、`TestExecuteTask_NonAuthorPassesDutyAuthorizer`、`TestDutyAuthorizerAllowsDocumentAuthorCommit`。
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: "修复第三方 test 用户文档三问题"
|
||||
task_id: test-user-doc-issues-2026-09-28
|
||||
status: done
|
||||
created: 2026-09-28
|
||||
updated: 2026-09-28
|
||||
owner: Cursor
|
||||
task_type: fix
|
||||
policy_revision: "AGENTS.md + agent-worktree-workflow @ 2026-09-21"
|
||||
branch: fix/test-user-doc-issues-2026-09-28
|
||||
worktree: .worktrees/test-user-doc-issues-2026-09-28
|
||||
base_dev_sha: "8f77053f5169502eaf3e4e4135a082e8914f3704"
|
||||
write_scope:
|
||||
- internal
|
||||
- .doc
|
||||
mutex: intent-write-verb
|
||||
review_state: accepted
|
||||
integration_state: merged_local_dev
|
||||
deployment: not_redeployed
|
||||
cleanup: pending
|
||||
remote_sync: not_requested
|
||||
---
|
||||
|
||||
# 修复第三方 test 用户文档三问题
|
||||
|
||||
## 用户目标与授权
|
||||
|
||||
用户提供《AI 测试问题.docx》(放在仓库 `.tmp/`)。授权:阅读图文、定位并修复第三方用户在 test 环境遇到的问题。
|
||||
|
||||
## 检索与重叠
|
||||
|
||||
- 检索词:`帮我定设计开发计划任务书`、`hasTaskWriteVerb`、`质量检查未通过`、`PI runner data_dir`。
|
||||
- P1(只上传附件被空消息拒绝)已由 ISSUE-20260928-attachment-only-turn 在 dev 修复。
|
||||
- catalog overlap(无 scope 绑定)hard/soft 为空。带 `--intent` 注册被 `same_scope` 拒绝,持有者 `agent-reply-llm-narrative-2026-09-28`(scopes `internal`+`.doc`)。本任务不改其文件(`dialogue_llm.go` / `intent_reply_llm.go` 等),只改意图动词与任务回复文案。
|
||||
- P3/P4 的 runner 数据目录错配由并行任务 `pi-runner-env-mismatch-2026-09-28`(`4f581306`)修复。开工时其 integrate 为 DIRTY_TREE;收口前已确认该提交是 local dev `193a752f` 的祖先。本任务不代合入、不改其文件。
|
||||
|
||||
## 事实
|
||||
|
||||
test 库 `agent_system_test`(127.0.0.1:5434)会话 `sess-p8-u33`(2026-09-28):
|
||||
|
||||
- 「帮我定设计开发计划任务书」落到 `handleAmbiguousConsult` 模板「完全理解您想再掂量一下」,未触发 `rd_design_plan`。`hasTaskWriteVerb` 不含「制定 / 帮我定」。
|
||||
- 「帮我生成报价单」回复声称正文已保存到宿主机 `cdo_quote_*/output.md`。该工作区 `quality_report.passed=false`(缺报价范围/模型/说明/约束)。质量失败仍走成功文案。
|
||||
- `bd_intake` run `run_1790558895559080556` 为 `quality_failed`,writer 修复步 `MISSING_TARGET`。sidecar 把 test 工作区交给了数据目录不一致的 runner(见并行任务提交说明)。
|
||||
|
||||
## 修复
|
||||
|
||||
- 写动词增加「制定」「拟定」,以及祈使「帮我定 / 请定」;「决定」不计。
|
||||
- 质量未通过或未完成时,同步回复改用 `CompletionSummary`,不展示宿主机路径、不声称正文已保存。
|
||||
- `ErrPrerequisiteNotMet` 以中文前置条件回复结束回合,不再把哨兵错误当成协调失败丢掉回复。
|
||||
- 模糊咨询若已带澄清问题,直接透传,不再覆盖成阶段对照模板。
|
||||
|
||||
## 验证
|
||||
|
||||
单测与 test 进程核对见 [测试报告](../../test-reports/2026-09-28-test-user-doc-issues-test-report.md)。报价单未在本轮重跑。test 进程在核对时已指向 18866 与 `data/test`。回复文案随本任务进入 local dev 后,test 二进制尚未按新 dev 重放。
|
||||
|
||||
## 收口
|
||||
|
||||
- review_state: accepted
|
||||
- integration_state: merged_local_dev(候选 `6e1d5830`,随后本收口提交再合一次)
|
||||
- deployment: not_redeployed(未持有 env:test,未重启 test)
|
||||
- cleanup: pending
|
||||
- remote_sync: not_requested
|
||||
@@ -0,0 +1,228 @@
|
||||
# 错误码目录
|
||||
|
||||
日期:2026-09-28。稳定码注册在 `internal/errcode`。HTTP 响应信封仍是 `code`、`message`、`request_id`、`error`、`details`。`details.guide` 是本页对应码的排查短句。
|
||||
|
||||
## 怎么定位一次失败
|
||||
|
||||
1. 从响应、聊天失败气泡或访问日志取出 `code` 与 `request_id`。
|
||||
2. 在服务日志里检索 `request_id`(错误日志字段还有 `code`、`status`、`method`、`path`)。5xx 记为 Error,4xx 记为 Warn。日志不写原始 SQL、密钥或堆栈。
|
||||
3. 管理台「错误审计」调用 `GET /api/v1/admin/system/error-events`(权限 `system:audit:read`),可按 `code`、`request_id`、`class`、时间范围过滤。
|
||||
4. 异步失败(任务收尾、事件死信/隔离、上下文后台扫描、提醒扫描)写入同一张表,`source=async`。没有 HTTP 请求时,`request_id` 可能是任务或事件标识。
|
||||
|
||||
## 常见原因
|
||||
|
||||
| 类别 | 常见原因 | 下一步 |
|
||||
|---|---|---|
|
||||
| transient | 超时、暂时不可用、后台扫描失败 | 稍后重试;用 request_id 看是否连续出现 |
|
||||
| resumable | 文档忙、租约占用、阶段未完成 | 等待当前编辑或阶段结束后继续 |
|
||||
| fatal | 权限、校验、不存在、账本不一致 | 按码的含义修正输入或权限,不要盲目重试 |
|
||||
| cancelled | 任务被取消 | 确认是否为用户取消 |
|
||||
|
||||
## 负责模块与相关表
|
||||
|
||||
- 表 `error_events` 的唯一写者是 `internal/errorevents`(迁移 `deploy/postgres/goose/00078_2026-09-28-error-events-audit.sql`)。按环境数据库隔离,表内没有环境列。
|
||||
- 审计写入超时或失败只降级为日志 `error_event_audit_degraded`,不改变 HTTP 响应。
|
||||
- 领域哨兵仍留在各领域包。`internal/server/domain_http.go` 在启动时 `errcode.Bind`。`stream.ClassifyError` 优先读错误上的 `ErrorCode()`,字符串启发式只作为旧路径兜底。
|
||||
|
||||
## 码表
|
||||
|
||||
下表每行一条注册码:含义、排查步骤、负责模块。HTTP 列为建议状态;处理器已显式给出的状态优先。
|
||||
|
||||
| 错误码 | HTTP | 类别 | 模块 | 可重试 | 含义 | 排查 |
|
||||
|---|---:|---|---|---|---|---|
|
||||
| `APPROVER_CANNOT_EDIT` | 403 | fatal | docgov | 否 | 批准人不能修改文档内容 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 APPROVER_CANNOT_EDIT。负责模块:docgov。 |
|
||||
| `ASSET_KEY_AND_FILE_REQUIRED` | 400 | fatal | server | 否 | asset_key and file required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 ASSET_KEY_AND_FILE_REQUIRED。负责模块:server。 |
|
||||
| `ASSET_NOT_FOUND` | 404 | fatal | server | 否 | asset not found | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 ASSET_NOT_FOUND。负责模块:server。 |
|
||||
| `AUTHOR_ONLY_EDIT` | 403 | fatal | docgov | 否 | 只有编制人可以修改文档内容 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTHOR_ONLY_EDIT。负责模块:docgov。 |
|
||||
| `AUTH_BAD_CREDENTIALS` | 401 | fatal | auth | 否 | 用户名或密码错误 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTH_BAD_CREDENTIALS。负责模块:auth。 |
|
||||
| `AUTH_FORBIDDEN` | 403 | fatal | auth | 否 | 无权访问 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTH_FORBIDDEN。负责模块:auth。 |
|
||||
| `AUTH_LOGIN_REQUIRED` | 401 | fatal | auth | 否 | 请先登录 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTH_LOGIN_REQUIRED。负责模块:auth。 |
|
||||
| `AUTH_SESSION_EXPIRED` | 401 | fatal | auth | 否 | 未登录或登录已过期 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTH_SESSION_EXPIRED。负责模块:auth。 |
|
||||
| `AUTH_UNAUTHENTICATED` | 401 | fatal | auth | 否 | 未登录或登录已过期 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTH_UNAUTHENTICATED。负责模块:auth。 |
|
||||
| `AUTH_USERNAME_EXISTS` | 409 | fatal | auth | 否 | 用户名已存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 AUTH_USERNAME_EXISTS。负责模块:auth。 |
|
||||
| `BATCH_NOT_FOUND` | 404 | fatal | server | 否 | batch not found | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 BATCH_NOT_FOUND。负责模块:server。 |
|
||||
| `CANNOT_STORE_EMPTY_FILE` | 400 | fatal | server | 否 | cannot store empty file | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CANNOT_STORE_EMPTY_FILE。负责模块:server。 |
|
||||
| `CHANGE_PROPOSAL_PENDING` | 409 | resumable | docgov | 是 | 文档仍有待编制人确认的变更提案 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CHANGE_PROPOSAL_PENDING。负责模块:docgov。 |
|
||||
| `CHAT_MESSAGES_IMPORT_ENDPOINT_IS_ONLY_AVAILABLE_IN_DEV_D` | 400 | fatal | server | 否 | chat messages import endpoint is only available in dev/demo environment | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CHAT_MESSAGES_IMPORT_ENDPOINT_IS_ONLY_AVAILABLE_IN_DEV_D。负责模块:server。 |
|
||||
| `CHAT_TIMEOUT` | 504 | transient | stream | 是 | 生成回复超时,请稍后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CHAT_TIMEOUT。负责模块:stream。 |
|
||||
| `CHAT_TURN_NOT_FOUND` | 404 | fatal | ctxmgr | 否 | 对话回合不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CHAT_TURN_NOT_FOUND。负责模块:ctxmgr。 |
|
||||
| `CLIENT_TURN_ID_AND_SESSION_ID_REQUIRED` | 400 | fatal | server | 否 | client_turn_id and session_id required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CLIENT_TURN_ID_AND_SESSION_ID_REQUIRED。负责模块:server。 |
|
||||
| `CTXMGR_BACKGROUND` | 500 | transient | ctxmgr | 是 | 上下文后台任务失败 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 CTXMGR_BACKGROUND。负责模块:ctxmgr。 |
|
||||
| `DECISION_NONCE_AND_DECISION_DIGEST_REQUIRED` | 400 | fatal | server | 否 | decision_nonce and decision_digest required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DECISION_NONCE_AND_DECISION_DIGEST_REQUIRED。负责模块:server。 |
|
||||
| `DOCUMENT_CONTENT_ERROR` | 409 | fatal | docgov | 否 | 文档内容读取失败 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_CONTENT_ERROR。负责模块:docgov。 |
|
||||
| `DOCUMENT_CONTENT_INTEGRITY_MISMATCH` | 409 | fatal | docgov | 否 | 文档内容校验不一致 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_CONTENT_INTEGRITY_MISMATCH。负责模块:docgov。 |
|
||||
| `DOCUMENT_CONTENT_PROJECTION_DRIFT` | 409 | fatal | docgov | 否 | 文档内容投影与账本不一致 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_CONTENT_PROJECTION_DRIFT。负责模块:docgov。 |
|
||||
| `DOCUMENT_CONTENT_PROJECTION_EMPTY` | 409 | fatal | docgov | 否 | 文档内容投影为空 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_CONTENT_PROJECTION_EMPTY。负责模块:docgov。 |
|
||||
| `DOCUMENT_CONTENT_PROJECTION_MISSING` | 409 | fatal | docgov | 否 | 文档内容投影缺失 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_CONTENT_PROJECTION_MISSING。负责模块:docgov。 |
|
||||
| `DOCUMENT_LOCKED` | 409 | resumable | docgov | 是 | 文档已锁定 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_LOCKED。负责模块:docgov。 |
|
||||
| `DOCUMENT_NOT_FOUND` | 404 | fatal | docgov | 否 | 文档不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOCUMENT_NOT_FOUND。负责模块:docgov。 |
|
||||
| `DOC_BUSY` | 409 | fatal | docgov | 否 | 该文档正在编辑中,请等待现有任务完成 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOC_BUSY。负责模块:docgov。 |
|
||||
| `DOC_ID_CANNOT_BE_EMPTY` | 400 | fatal | server | 否 | doc_id cannot be empty | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOC_ID_CANNOT_BE_EMPTY。负责模块:server。 |
|
||||
| `DOC_ID_REQUIRED` | 400 | fatal | server | 否 | doc_id required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOC_ID_REQUIRED。负责模块:server。 |
|
||||
| `DOC_LEDGER_ERROR` | 500 | fatal | docgov | 否 | 文档职责账本写入失败,请重新开始会话 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOC_LEDGER_ERROR。负责模块:docgov。 |
|
||||
| `DOC_TASK_BUSY` | 409 | resumable | projectinstance | 是 | 文档任务正在执行,暂不能改派 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 DOC_TASK_BUSY。负责模块:projectinstance。 |
|
||||
| `EVENTS_AUTH_FAILURE` | 403 | fatal | events | 否 | 事件未通过授权 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 EVENTS_AUTH_FAILURE。负责模块:events。 |
|
||||
| `EVENTS_DEAD` | 500 | fatal | events | 否 | 事件投递已进入死信 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 EVENTS_DEAD。负责模块:events。 |
|
||||
| `EVENTS_INTEGRITY` | 500 | fatal | events | 否 | 事件完整性校验失败 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 EVENTS_INTEGRITY。负责模块:events。 |
|
||||
| `EVENTS_QUARANTINE` | 500 | fatal | events | 否 | 事件已隔离,不会自动重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 EVENTS_QUARANTINE。负责模块:events。 |
|
||||
| `EVENTS_STALE_FENCING` | 409 | resumable | events | 是 | 事件租约令牌已过期 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 EVENTS_STALE_FENCING。负责模块:events。 |
|
||||
| `FILE_REQUIRED` | 400 | fatal | server | 否 | file required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FILE_REQUIRED。负责模块:server。 |
|
||||
| `FILE_TYPE_NOT_SUPPORTED_BY_PARSER` | 400 | fatal | server | 否 | file type not supported by parser | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FILE_TYPE_NOT_SUPPORTED_BY_PARSER。负责模块:server。 |
|
||||
| `FORCE_EDIT_NOT_ALLOWED` | 409 | fatal | docgov | 否 | 当前不允许强制直接编辑 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FORCE_EDIT_NOT_ALLOWED。负责模块:docgov。 |
|
||||
| `FREEDOC_CONFLICT` | 409 | resumable | freedoc | 是 | 自由文档版本冲突 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FREEDOC_CONFLICT。负责模块:freedoc。 |
|
||||
| `FREEDOC_FORBIDDEN` | 403 | fatal | freedoc | 否 | 无权访问该自由文档 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FREEDOC_FORBIDDEN。负责模块:freedoc。 |
|
||||
| `FREEDOC_INVALID_PARAM` | 400 | fatal | freedoc | 否 | 自由文档参数无效 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FREEDOC_INVALID_PARAM。负责模块:freedoc。 |
|
||||
| `FREEDOC_NOT_EXPORTABLE` | 400 | fatal | freedoc | 否 | 该消息不能导出为文档 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FREEDOC_NOT_EXPORTABLE。负责模块:freedoc。 |
|
||||
| `FREEDOC_NOT_FOUND` | 404 | fatal | freedoc | 否 | 自由文档不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 FREEDOC_NOT_FOUND。负责模块:freedoc。 |
|
||||
| `IAM` | 400 | fatal | server | 否 | 工作流定义服务需要数据库 IAM | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 IAM。负责模块:server。 |
|
||||
| `ID` | 400 | fatal | server | 否 | 无效的 id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 ID。负责模块:server。 |
|
||||
| `IDEMPOTENCY_CONFLICT` | 409 | resumable | server | 是 | 重复提交 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 IDEMPOTENCY_CONFLICT。负责模块:server。 |
|
||||
| `IDEMPOTENCY_KEY_REUSED` | 409 | fatal | ctxmgr | 否 | 重复提交的内容不一致 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 IDEMPOTENCY_KEY_REUSED。负责模块:ctxmgr。 |
|
||||
| `ID_2` | 400 | fatal | server | 否 | 无效的用户ID | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 ID_2。负责模块:server。 |
|
||||
| `ID_3` | 400 | fatal | server | 否 | 无效的角色 ID | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 ID_3。负责模块:server。 |
|
||||
| `INSTANCE_ACTIVATION_INVALID` | 400 | fatal | projectinstance | 否 | 激活令牌无效或已过期 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_ACTIVATION_INVALID。负责模块:projectinstance。 |
|
||||
| `INSTANCE_ALREADY_ACTIVE` | 409 | resumable | projectinstance | 是 | 项目已有运行中的工作流实例 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_ALREADY_ACTIVE。负责模块:projectinstance。 |
|
||||
| `INSTANCE_AUTHOR_ONLY_CHANGED` | 409 | resumable | projectinstance | 是 | 兼任总授权已变更,请重新预览并确认激活 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_AUTHOR_ONLY_CHANGED。负责模块:projectinstance。 |
|
||||
| `INSTANCE_AUTHOR_ONLY_DISABLED` | 403 | fatal | projectinstance | 否 | 系统未授权编制人兼任审核批准 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_AUTHOR_ONLY_DISABLED。负责模块:projectinstance。 |
|
||||
| `INSTANCE_AUTHOR_ONLY_UNAVAILABLE` | 503 | transient | projectinstance | 是 | 兼任总授权存储不可用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_AUTHOR_ONLY_UNAVAILABLE。负责模块:projectinstance。 |
|
||||
| `INSTANCE_CONFLICT` | 409 | resumable | projectinstance | 是 | 项目版本冲突,请刷新后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_CONFLICT。负责模块:projectinstance。 |
|
||||
| `INSTANCE_DOC_TASK_NOT_FOUND` | 404 | fatal | projectinstance | 否 | 文档任务不存在或已禁用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_DOC_TASK_NOT_FOUND。负责模块:projectinstance。 |
|
||||
| `INSTANCE_DUTY_FORBIDDEN` | 403 | fatal | projectinstance | 否 | 无权改派文档职责 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_DUTY_FORBIDDEN。负责模块:projectinstance。 |
|
||||
| `INSTANCE_FORBIDDEN_NOT_CREATOR` | 403 | fatal | projectinstance | 否 | 仅项目创建人可配置工作流 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_FORBIDDEN_NOT_CREATOR。负责模块:projectinstance。 |
|
||||
| `INSTANCE_INVALID_STAGE` | 400 | fatal | projectinstance | 否 | 无效的阶段 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_INVALID_STAGE。负责模块:projectinstance。 |
|
||||
| `INSTANCE_LEGACY_SWITCH_BLOCKED` | 409 | fatal | projectinstance | 否 | 新项目请通过项目设置完成工作流激活 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_LEGACY_SWITCH_BLOCKED。负责模块:projectinstance。 |
|
||||
| `INSTANCE_NOT_AVAILABLE` | 503 | transient | projectinstance | 是 | 项目实例服务不可用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_NOT_AVAILABLE。负责模块:projectinstance。 |
|
||||
| `INSTANCE_NOT_FOUND` | 404 | fatal | projectinstance | 否 | 工作流实例不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_NOT_FOUND。负责模块:projectinstance。 |
|
||||
| `INSTANCE_PLAN_CONFLICT` | 409 | resumable | projectinstance | 是 | 规划版本冲突,请刷新后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_PLAN_CONFLICT。负责模块:projectinstance。 |
|
||||
| `INSTANCE_PLAN_FROZEN` | 409 | fatal | projectinstance | 否 | 工作流已激活,规划已冻结 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_PLAN_FROZEN。负责模块:projectinstance。 |
|
||||
| `INSTANCE_PLAN_RECONFIRM` | 409 | resumable | projectinstance | 是 | 规划已变更,请重新预览并确认 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_PLAN_RECONFIRM。负责模块:projectinstance。 |
|
||||
| `INSTANCE_RECHECK_REQUIRED` | 409 | fatal | projectinstance | 否 | 该阶段有待复核标记,推进前须确认已知悉 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_RECHECK_REQUIRED。负责模块:projectinstance。 |
|
||||
| `INSTANCE_REVISION_CONFLICT` | 409 | resumable | projectinstance | 是 | 实例版本冲突,请刷新后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_REVISION_CONFLICT。负责模块:projectinstance。 |
|
||||
| `INSTANCE_STAGE_GATE` | 400 | fatal | projectinstance | 否 | 阶段门禁未满足,必需文档尚未全部批准 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_STAGE_GATE。负责模块:projectinstance。 |
|
||||
| `INSTANCE_STAGE_NOT_ACTIVE` | 409 | fatal | projectinstance | 否 | 目标阶段不是当前活动阶段 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_STAGE_NOT_ACTIVE。负责模块:projectinstance。 |
|
||||
| `INSTANCE_STAGE_NOT_COMPLETED` | 400 | fatal | projectinstance | 否 | 只能再打开已完成的阶段 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_STAGE_NOT_COMPLETED。负责模块:projectinstance。 |
|
||||
| `INSTANCE_SWITCH_FROZEN` | 409 | fatal | projectinstance | 否 | 运行中不能切换工作流,只能调整职责、审批和文档启用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_SWITCH_FROZEN。负责模块:projectinstance。 |
|
||||
| `INSTANCE_TERMINATION_DENIED` | 409 | fatal | projectinstance | 否 | 当前状态不允许终止 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_TERMINATION_DENIED。负责模块:projectinstance。 |
|
||||
| `INSTANCE_VALIDATION_FAILED` | 400 | fatal | projectinstance | 否 | 工作流配置校验未通过 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INSTANCE_VALIDATION_FAILED。负责模块:projectinstance。 |
|
||||
| `INTERNAL` | 500 | fatal | server | 否 | 请求无法完成 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INTERNAL。负责模块:server。 |
|
||||
| `INTERNAL_ERROR` | 500 | fatal | server | 否 | 系统内部错误,请重新开始会话 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INTERNAL_ERROR。负责模块:server。 |
|
||||
| `INVALID_ACTION_MUST_BE_APPROVE_OR_REJECT` | 400 | fatal | server | 否 | invalid action: must be approve or reject | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_ACTION_MUST_BE_APPROVE_OR_REJECT。负责模块:server。 |
|
||||
| `INVALID_ASSET_ID` | 400 | fatal | server | 否 | invalid asset id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_ASSET_ID。负责模块:server。 |
|
||||
| `INVALID_ASSET_KEY` | 400 | fatal | server | 否 | invalid asset key | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_ASSET_KEY。负责模块:server。 |
|
||||
| `INVALID_BATCH_ID` | 400 | fatal | server | 否 | invalid batch id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_BATCH_ID。负责模块:server。 |
|
||||
| `INVALID_COMMENT_ID` | 400 | fatal | server | 否 | invalid comment id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_COMMENT_ID。负责模块:server。 |
|
||||
| `INVALID_EDGE_ID` | 400 | fatal | server | 否 | invalid edge id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_EDGE_ID。负责模块:server。 |
|
||||
| `INVALID_INSTANCE_ID` | 400 | fatal | server | 否 | invalid instance id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_INSTANCE_ID。负责模块:server。 |
|
||||
| `INVALID_MARK_ID` | 400 | fatal | server | 否 | invalid mark id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_MARK_ID。负责模块:server。 |
|
||||
| `INVALID_MULTIPART` | 400 | fatal | server | 否 | invalid multipart | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_MULTIPART。负责模块:server。 |
|
||||
| `INVALID_PROJECT_ID` | 400 | fatal | server | 否 | invalid project id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_PROJECT_ID。负责模块:server。 |
|
||||
| `INVALID_REPO_PATH` | 400 | fatal | server | 否 | invalid repo_path | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_REPO_PATH。负责模块:server。 |
|
||||
| `INVALID_REQUEST_ID` | 400 | fatal | server | 否 | invalid request id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_REQUEST_ID。负责模块:server。 |
|
||||
| `INVALID_STATE_TRANSITION` | 409 | fatal | docgov | 否 | 文档状态不能这样流转 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_STATE_TRANSITION。负责模块:docgov。 |
|
||||
| `INVALID_TASK_KEY` | 400 | fatal | server | 否 | invalid task key | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_TASK_KEY。负责模块:server。 |
|
||||
| `INVALID_VERSION` | 409 | resumable | server | 是 | invalid version | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_VERSION。负责模块:server。 |
|
||||
| `INVALID_WORKFLOW_ID` | 400 | fatal | server | 否 | invalid workflow id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_WORKFLOW_ID。负责模块:server。 |
|
||||
| `INVALID_WORKSPACE_PATH` | 400 | fatal | server | 否 | invalid workspace path | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 INVALID_WORKSPACE_PATH。负责模块:server。 |
|
||||
| `KIND_MUST_BE_CONFIRM_OR_CANCEL` | 400 | fatal | server | 否 | kind must be confirm or cancel | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 KIND_MUST_BE_CONFIRM_OR_CANCEL。负责模块:server。 |
|
||||
| `LEASE_EXPIRED` | 409 | resumable | docgov | 是 | 文档编辑租约已过期 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 LEASE_EXPIRED。负责模块:docgov。 |
|
||||
| `LEASE_NOT_HELD` | 409 | resumable | docgov | 是 | 当前没有文档编辑租约 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 LEASE_NOT_HELD。负责模块:docgov。 |
|
||||
| `LEASE_STALE` | 409 | resumable | docgov | 是 | 文档编辑租约已失效 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 LEASE_STALE。负责模块:docgov。 |
|
||||
| `LIMIT` | 400 | fatal | server | 否 | 无效的 limit | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 LIMIT。负责模块:server。 |
|
||||
| `LIST_EXECUTIONS_FAILED` | 400 | fatal | server | 否 | list executions failed | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 LIST_EXECUTIONS_FAILED。负责模块:server。 |
|
||||
| `MAINTENANCE_BAD_STATUS` | 409 | fatal | maintenance | 否 | 当前状态不可取消 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MAINTENANCE_BAD_STATUS。负责模块:maintenance。 |
|
||||
| `MAINTENANCE_CONFLICT_OPEN` | 409 | resumable | maintenance | 是 | 已有未结束的维护窗口 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MAINTENANCE_CONFLICT_OPEN。负责模块:maintenance。 |
|
||||
| `MAINTENANCE_INVALID_WINDOW` | 400 | fatal | maintenance | 否 | 维护窗口参数无效 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MAINTENANCE_INVALID_WINDOW。负责模块:maintenance。 |
|
||||
| `MAINTENANCE_NOT_FOUND` | 404 | fatal | maintenance | 否 | 维护窗口不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MAINTENANCE_NOT_FOUND。负责模块:maintenance。 |
|
||||
| `MESSAGE_CANNOT_BE_EMPTY` | 400 | fatal | server | 否 | message cannot be empty | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MESSAGE_CANNOT_BE_EMPTY。负责模块:server。 |
|
||||
| `MESSAGE_MUST_BE_SENT_VIA_POST_JSON_BODY_NOT_GET_QUERY_T2` | 400 | fatal | server | 否 | message must be sent via POST JSON body, not GET query (T20-B11) | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MESSAGE_MUST_BE_SENT_VIA_POST_JSON_BODY_NOT_GET_QUERY_T2。负责模块:server。 |
|
||||
| `MISSING_DATE_DAY_KEY_OR_ANCHOR_ID_QUERY_PARAM` | 400 | fatal | server | 否 | missing date/day_key or anchor_id query param | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_DATE_DAY_KEY_OR_ANCHOR_ID_QUERY_PARAM。负责模块:server。 |
|
||||
| `MISSING_DOC_ID_QUERY_PARAM` | 400 | fatal | server | 否 | missing doc_id query param | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_DOC_ID_QUERY_PARAM。负责模块:server。 |
|
||||
| `MISSING_OR_EMPTY_QUERY_PARAM_Q` | 400 | fatal | server | 否 | missing or empty query param 'q' | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_OR_EMPTY_QUERY_PARAM_Q。负责模块:server。 |
|
||||
| `MISSING_OR_INVALID_PROJECT_ID_QUERY_PARAM` | 400 | fatal | server | 否 | missing or invalid project_id query param | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_OR_INVALID_PROJECT_ID_QUERY_PARAM。负责模块:server。 |
|
||||
| `MISSING_QUERY_PARAM` | 400 | fatal | server | 否 | missing query param | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_QUERY_PARAM。负责模块:server。 |
|
||||
| `MISSING_REQUIRED_FIELDS_SESSION_ID_OR_DAY_KEY` | 400 | fatal | server | 否 | missing required fields 'session_id' or 'day_key' | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_REQUIRED_FIELDS_SESSION_ID_OR_DAY_KEY。负责模块:server。 |
|
||||
| `MISSING_REQUIRED_QUERY_PARAM_SESSION_ID` | 400 | fatal | server | 否 | missing required query param 'session_id' | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_REQUIRED_QUERY_PARAM_SESSION_ID。负责模块:server。 |
|
||||
| `MISSING_SESSION_ID` | 400 | fatal | server | 否 | missing session_id | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_SESSION_ID。负责模块:server。 |
|
||||
| `MISSING_SESSION_ID_QUERY_PARAM` | 400 | fatal | server | 否 | missing session_id query param | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MISSING_SESSION_ID_QUERY_PARAM。负责模块:server。 |
|
||||
| `MSG_` | 400 | fatal | server | 否 | 仅原批准人或(批准人缺位时)项目创建人可批准再打开 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG_。负责模块:server。 |
|
||||
| `MSG__2` | 400 | fatal | server | 否 | 只有该阶段文档职责人或创建人可以申请再打开 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__2。负责模块:server。 |
|
||||
| `MSG__3` | 400 | fatal | server | 否 | 姓名不能为空 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__3。负责模块:server。 |
|
||||
| `MSG__4` | 400 | fatal | server | 否 | 指定的角色不存在或已停用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__4。负责模块:server。 |
|
||||
| `MSG__5` | 404 | fatal | server | 否 | 未找到该项目的打开标记 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__5。负责模块:server。 |
|
||||
| `MSG__6` | 400 | fatal | server | 否 | 申请不属于该项目 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__6。负责模块:server。 |
|
||||
| `MSG__7` | 400 | fatal | server | 否 | 看不见下游文档,不能裁决 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__7。负责模块:server。 |
|
||||
| `MSG__8` | 400 | fatal | server | 否 | 至少提供一个可更新字段 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__8。负责模块:server。 |
|
||||
| `MSG__9` | 400 | fatal | server | 否 | 追踪索引不可用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 MSG__9。负责模块:server。 |
|
||||
| `NETWORK_ERROR` | 502 | transient | stream | 是 | 网络连接异常,请稍后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 NETWORK_ERROR。负责模块:stream。 |
|
||||
| `PARSE_IS_IN_PROGRESS_OR_ALREADY_COMPLETE` | 409 | resumable | server | 是 | parse is in progress or already complete | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PARSE_IS_IN_PROGRESS_OR_ALREADY_COMPLETE。负责模块:server。 |
|
||||
| `PROJECT_NAME_DUPLICATE` | 409 | fatal | projectworkflow | 否 | 项目名称已存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROJECT_NAME_DUPLICATE。负责模块:projectworkflow。 |
|
||||
| `PROJECT_NOT_FOUND` | 404 | fatal | projectworkflow | 否 | 项目不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROJECT_NOT_FOUND。负责模块:projectworkflow。 |
|
||||
| `PROJECT_ROLE_REQUIRED_WHEN_MEMBER_DOES_NOT_EXIST` | 400 | fatal | server | 否 | project_role required when member does not exist | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROJECT_ROLE_REQUIRED_WHEN_MEMBER_DOES_NOT_EXIST。负责模块:server。 |
|
||||
| `PROJECT_ROLE_REQUIRED_WITH_DOCUMENT_DUTY` | 400 | fatal | server | 否 | project_role required with document_duty | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROJECT_ROLE_REQUIRED_WITH_DOCUMENT_DUTY。负责模块:server。 |
|
||||
| `PROPOSAL_ALREADY_DECIDED` | 409 | fatal | docgov | 否 | 变更提案已裁决 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROPOSAL_ALREADY_DECIDED。负责模块:docgov。 |
|
||||
| `PROPOSAL_ID_CANNOT_BE_EMPTY` | 400 | fatal | server | 否 | proposal_id cannot be empty | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROPOSAL_ID_CANNOT_BE_EMPTY。负责模块:server。 |
|
||||
| `PROPOSAL_NOT_FOUND` | 404 | fatal | docgov | 否 | 变更提案不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROPOSAL_NOT_FOUND。负责模块:docgov。 |
|
||||
| `PROPOSED_CHANGES_CANNOT_BE_EMPTY` | 400 | fatal | server | 否 | proposed_changes cannot be empty | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 PROPOSED_CHANGES_CANNOT_BE_EMPTY。负责模块:server。 |
|
||||
| `RATE_LIMITED` | 429 | transient | server | 是 | 请求过于频繁,请稍后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 RATE_LIMITED。负责模块:server。 |
|
||||
| `READ_FILE_FAILED` | 400 | fatal | server | 否 | read file failed | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 READ_FILE_FAILED。负责模块:server。 |
|
||||
| `REJECT_REASON_REQUIRED` | 400 | fatal | docgov | 否 | 驳回必须填写原因 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REJECT_REASON_REQUIRED。负责模块:docgov。 |
|
||||
| `REMINDER_SCAN_FAILED` | 500 | transient | notification | 是 | 阶段提醒扫描失败 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REMINDER_SCAN_FAILED。负责模块:notification。 |
|
||||
| `REPO_PATH_REQUIRED` | 400 | fatal | server | 否 | repo_path required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REPO_PATH_REQUIRED。负责模块:server。 |
|
||||
| `REQUEST_BODY_INVALID` | 400 | fatal | server | 否 | 无效的请求体 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REQUEST_BODY_INVALID。负责模块:server。 |
|
||||
| `REQUEST_INVALID` | 400 | fatal | server | 否 | 请求参数无效 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REQUEST_INVALID。负责模块:server。 |
|
||||
| `REQUEST_JSON_INVALID` | 400 | fatal | server | 否 | 无效的 JSON 请求体 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REQUEST_JSON_INVALID。负责模块:server。 |
|
||||
| `REQUEST_METHOD_NOT_ALLOWED` | 405 | fatal | server | 否 | 不支持的请求方法 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REQUEST_METHOD_NOT_ALLOWED。负责模块:server。 |
|
||||
| `RESOURCE_CONFLICT` | 409 | resumable | server | 是 | 资源版本冲突 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 RESOURCE_CONFLICT。负责模块:server。 |
|
||||
| `RESOURCE_NOT_FOUND` | 404 | fatal | server | 否 | 资源不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 RESOURCE_NOT_FOUND。负责模块:server。 |
|
||||
| `REVIEWER_CANNOT_EDIT` | 403 | fatal | docgov | 否 | 审核人不能修改文档内容 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 REVIEWER_CANNOT_EDIT。负责模块:docgov。 |
|
||||
| `RUNNER_RESULT_REJECTED` | 502 | fatal | stream | 否 | 助手执行结果校验失败,请重新开始任务 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 RUNNER_RESULT_REJECTED。负责模块:stream。 |
|
||||
| `RUN_ID_REQUIRED` | 400 | fatal | server | 否 | run_id required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 RUN_ID_REQUIRED。负责模块:server。 |
|
||||
| `RUN_NOT_FOUND` | 404 | fatal | server | 否 | run not found | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 RUN_NOT_FOUND。负责模块:server。 |
|
||||
| `SAVE_BINDING_FAILED` | 400 | fatal | server | 否 | save binding failed | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SAVE_BINDING_FAILED。负责模块:server。 |
|
||||
| `SERVICE_UNAVAILABLE` | 503 | transient | server | 是 | 服务暂不可用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SERVICE_UNAVAILABLE。负责模块:server。 |
|
||||
| `SESSION_OR_PROJECT_CONTEXT_NOT_FOUND` | 404 | fatal | server | 否 | session or project context not found | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SESSION_OR_PROJECT_CONTEXT_NOT_FOUND。负责模块:server。 |
|
||||
| `SESSION_OWNER_MISMATCH` | 403 | fatal | ctxmgr | 否 | 无权访问该会话 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SESSION_OWNER_MISMATCH。负责模块:ctxmgr。 |
|
||||
| `SETTING_INVALID_VALUE` | 400 | fatal | sysadmin | 否 | 设置值类型不匹配 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_INVALID_VALUE。负责模块:sysadmin。 |
|
||||
| `SETTING_NOT_FOUND` | 404 | fatal | sysadmin | 否 | 设置不存在 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_NOT_FOUND。负责模块:sysadmin。 |
|
||||
| `SETTING_READ_ONLY` | 403 | fatal | sysadmin | 否 | 该设置为只读 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_READ_ONLY。负责模块:sysadmin。 |
|
||||
| `SETTING_REVISION_CONFLICT` | 409 | resumable | sysadmin | 是 | 设置版本冲突,请刷新后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_REVISION_CONFLICT。负责模块:sysadmin。 |
|
||||
| `SETTING_REVISION_REQUIRED` | 400 | fatal | sysadmin | 否 | 该设置需要 expected_revision | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_REVISION_REQUIRED。负责模块:sysadmin。 |
|
||||
| `SETTING_STORE_UNAVAILABLE` | 503 | transient | sysadmin | 是 | 设置存储不可用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_STORE_UNAVAILABLE。负责模块:sysadmin。 |
|
||||
| `SETTING_UNKNOWN` | 400 | fatal | sysadmin | 否 | 未知的设置键 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SETTING_UNKNOWN。负责模块:sysadmin。 |
|
||||
| `STREAMING_UNSUPPORTED` | 400 | fatal | server | 否 | streaming unsupported | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 STREAMING_UNSUPPORTED。负责模块:server。 |
|
||||
| `STREAMING_UNSUPPORTED_BY_UNDERLYING_CONNECTION` | 400 | fatal | server | 否 | streaming unsupported by underlying connection | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 STREAMING_UNSUPPORTED_BY_UNDERLYING_CONNECTION。负责模块:server。 |
|
||||
| `SWBOOT_MERGE_FORBIDDEN` | 403 | fatal | swboot | 否 | 受控执行不会合并、推送或部署 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SWBOOT_MERGE_FORBIDDEN。负责模块:swboot。 |
|
||||
| `SWBOOT_PATCH_DISABLED` | 403 | fatal | swboot | 否 | 受控补丁执行未开启 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SWBOOT_PATCH_DISABLED。负责模块:swboot。 |
|
||||
| `SWBOOT_PATCH_UNIMPLEMENTED` | 501 | fatal | swboot | 否 | 受控补丁执行尚未放量 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SWBOOT_PATCH_UNIMPLEMENTED。负责模块:swboot。 |
|
||||
| `SWBOOT_REPO_NOT_ALLOWLISTED` | 403 | fatal | swboot | 否 | 仓库路径不在允许列表 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 SWBOOT_REPO_NOT_ALLOWLISTED。负责模块:swboot。 |
|
||||
| `TASKRUN_ALREADY_ACTIVE` | 409 | resumable | taskrun | 是 | 任务已在执行 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_ALREADY_ACTIVE。负责模块:taskrun。 |
|
||||
| `TASKRUN_BACKGROUND` | 500 | transient | taskrun | 是 | 任务后台处理失败 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_BACKGROUND。负责模块:taskrun。 |
|
||||
| `TASKRUN_CLEANUP_BLOCKED` | 409 | fatal | taskrun | 否 | 任务清理尚未满足核对条件 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_CLEANUP_BLOCKED。负责模块:taskrun。 |
|
||||
| `TASKRUN_IDEMPOTENCY_CONFLICT` | 409 | resumable | taskrun | 是 | 重复的任务提交 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_IDEMPOTENCY_CONFLICT。负责模块:taskrun。 |
|
||||
| `TASKRUN_NOT_RESUMABLE` | 409 | fatal | taskrun | 否 | 该任务不能继续 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_NOT_RESUMABLE。负责模块:taskrun。 |
|
||||
| `TASKRUN_SENSITIVE_PAYLOAD` | 400 | fatal | taskrun | 否 | 任务输入包含不允许的内容 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_SENSITIVE_PAYLOAD。负责模块:taskrun。 |
|
||||
| `TASKRUN_STORE_UNAVAILABLE` | 503 | transient | taskrun | 是 | 任务存储不可用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_STORE_UNAVAILABLE。负责模块:taskrun。 |
|
||||
| `TASKRUN_TERMINAL_CONFLICT` | 409 | fatal | taskrun | 否 | 任务已结束,不能再次收口 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_TERMINAL_CONFLICT。负责模块:taskrun。 |
|
||||
| `TASKRUN_UNAUTHORIZED_BACKEND` | 403 | fatal | taskrun | 否 | 任务执行器未授权 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASKRUN_UNAUTHORIZED_BACKEND。负责模块:taskrun。 |
|
||||
| `TASK_INTERRUPTED` | 409 | resumable | taskrun | 是 | 任务执行中断,可继续或重新开始 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASK_INTERRUPTED。负责模块:taskrun。 |
|
||||
| `TASK_KEY` | 400 | fatal | server | 否 | 客户端不可覆盖 task_key | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASK_KEY。负责模块:server。 |
|
||||
| `TASK_SCOPE_UNRESOLVED` | 400 | fatal | projectinstance | 否 | 无法确定任务所属阶段 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TASK_SCOPE_UNRESOLVED。负责模块:projectinstance。 |
|
||||
| `TURN_NOT_FOUND` | 404 | fatal | server | 否 | turn not found | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 TURN_NOT_FOUND。负责模块:server。 |
|
||||
| `UNAUTHORIZED_ACTOR` | 403 | fatal | docgov | 否 | 当前身份不能执行该文档动作 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 UNAUTHORIZED_ACTOR。负责模块:docgov。 |
|
||||
| `UNKNOWN_WORKFLOW` | 400 | fatal | server | 否 | unknown workflow | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 UNKNOWN_WORKFLOW。负责模块:server。 |
|
||||
| `UNSUPPORTED_CATEGORY` | 400 | fatal | server | 否 | unsupported category | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 UNSUPPORTED_CATEGORY。负责模块:server。 |
|
||||
| `UPLOAD_TOO_LARGE` | 400 | fatal | server | 否 | upload too large | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 UPLOAD_TOO_LARGE。负责模块:server。 |
|
||||
| `USER_ID_AND_PROJECT_ROLE_REQUIRED` | 400 | fatal | server | 否 | user_id and project_role required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 USER_ID_AND_PROJECT_ROLE_REQUIRED。负责模块:server。 |
|
||||
| `USER_ID_QUERY_REQUIRED` | 400 | fatal | server | 否 | user_id query required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 USER_ID_QUERY_REQUIRED。负责模块:server。 |
|
||||
| `USER_ID_REQUIRED` | 400 | fatal | server | 否 | user_id required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 USER_ID_REQUIRED。负责模块:server。 |
|
||||
| `VERSION_CONFLICT` | 409 | resumable | server | 是 | 资源版本冲突 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 VERSION_CONFLICT。负责模块:server。 |
|
||||
| `WORKFLOW_CATALOG_UNAVAILABLE` | 503 | transient | server | 是 | workflow catalog unavailable | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_CATALOG_UNAVAILABLE。负责模块:server。 |
|
||||
| `WORKFLOW_CONCURRENT_CONFLICT` | 409 | resumable | projectworkflow | 是 | 工作流选择版本落后或并发冲突,请刷新后重试 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_CONCURRENT_CONFLICT。负责模块:projectworkflow。 |
|
||||
| `WORKFLOW_FORBIDDEN_NOT_CREATOR` | 403 | fatal | projectworkflow | 否 | 仅项目创建人有权切换激活工作流 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_FORBIDDEN_NOT_CREATOR。负责模块:projectworkflow。 |
|
||||
| `WORKFLOW_INVALID_INPUT` | 400 | fatal | projectworkflow | 否 | 工作流参数无效 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_INVALID_INPUT。负责模块:projectworkflow。 |
|
||||
| `WORKFLOW_KEY_IS_REQUIRED` | 400 | fatal | server | 否 | workflow_key is required | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_KEY_IS_REQUIRED。负责模块:server。 |
|
||||
| `WORKFLOW_LEGACY_SWITCH_BLOCKED` | 409 | fatal | projectworkflow | 否 | 请通过项目设置完成工作流规划与激活 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_LEGACY_SWITCH_BLOCKED。负责模块:projectworkflow。 |
|
||||
| `WORKFLOW_NOT_FOUND` | 404 | fatal | projectworkflow | 否 | 工作流定义不存在或未在项目启用 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_NOT_FOUND。负责模块:projectworkflow。 |
|
||||
| `WORKFLOW_PREREQUISITE` | 400 | fatal | projectworkflow | 否 | 上游文档尚未满足,不能继续 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_PREREQUISITE。负责模块:projectworkflow。 |
|
||||
| `WORKFLOW_UNAUTHENTICATED` | 401 | fatal | projectworkflow | 否 | 需要登录后操作工作流 | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKFLOW_UNAUTHENTICATED。负责模块:projectworkflow。 |
|
||||
| `WORKSPACE_NOT_AVAILABLE_FOR_RUN` | 503 | transient | server | 是 | workspace not available for run | 用 request_id 在服务日志或管理台「错误审计」中检索错误码 WORKSPACE_NOT_AVAILABLE_FOR_RUN。负责模块:server。 |
|
||||
@@ -290,6 +290,7 @@
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [./2026-09-22-t20-hardening-design.md](./2026-09-22-t20-hardening-design.md) | T20 W4 设计决策 SSOT(本目录仅留迁址桩);配套 [任务](../ops/short-term/2026-09-22-t20-design-items.md) |
|
||||
| [./2026-09-28-error-code-catalog.md](./2026-09-28-error-code-catalog.md) | 统一错误码、结构化错误日志与 `error_events` 审计;配套 [任务](../ops/short-term/2026-09-28-error-code-observability.md) |
|
||||
|
||||
## 🔗 相关资源
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ imports:
|
||||
- kb
|
||||
- maturity
|
||||
- projectinstance
|
||||
- projectworkflow
|
||||
- squad
|
||||
- stream
|
||||
- workflowscope
|
||||
@@ -84,6 +85,7 @@ imports:
|
||||
ctxmgr:
|
||||
- app/uow
|
||||
- docgov
|
||||
- errcode
|
||||
- replyexport
|
||||
- storage
|
||||
conflictresolve:
|
||||
@@ -115,6 +117,8 @@ imports:
|
||||
- ctxmgr
|
||||
- docgov
|
||||
- docrevision
|
||||
- errcode
|
||||
- errorevents
|
||||
- events
|
||||
- freedoc
|
||||
- intent
|
||||
@@ -247,6 +251,8 @@ imports:
|
||||
- docgov
|
||||
- docquery
|
||||
- docrevision
|
||||
- errcode
|
||||
- errorevents
|
||||
- events
|
||||
- freedoc
|
||||
- handoff
|
||||
@@ -284,7 +290,8 @@ imports:
|
||||
- workflowdef
|
||||
storage:
|
||||
- config
|
||||
stream: []
|
||||
stream:
|
||||
- errcode
|
||||
stream/transport:
|
||||
- stream
|
||||
swboot: []
|
||||
@@ -293,6 +300,7 @@ imports:
|
||||
- artifactvault
|
||||
- bizdev
|
||||
- ctxmgr
|
||||
- errcode
|
||||
- events
|
||||
- projectworkflow
|
||||
- stream
|
||||
@@ -313,8 +321,12 @@ imports:
|
||||
- workflowdef
|
||||
workspace:
|
||||
- app/uow
|
||||
errcode: []
|
||||
errorevents:
|
||||
- errcode
|
||||
events:
|
||||
- app/uow
|
||||
- errcode
|
||||
artifactvault:
|
||||
- app/uow
|
||||
- fsutil
|
||||
@@ -463,6 +475,8 @@ table_owners:
|
||||
- sysadmin
|
||||
system_setting_policy_audits:
|
||||
- sysadmin
|
||||
error_events:
|
||||
- errorevents
|
||||
maintenance_windows:
|
||||
- maintenance
|
||||
# FIND-ARCH-01 回归补登记(2026-09-26):以下为既有写者的真实表。
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
# dev→test 晋升(rc-v1.1.0-beta.4)与 test 单二进制化 — 测试报告
|
||||
|
||||
## 一、测试背景 (Background)
|
||||
|
||||
用户指令:把 `dev` 合入 `test`,并将 test 环境转换为单二进制服务(与 dev 同形态)。dev 领先 test 273 提交(含单二进制运行时、9 月 24 日以来的功能与修复);test 原为 4 容器形态(app/events/pi-agent/system-pg,schema 66)。
|
||||
|
||||
过程中发现并处置三个阻断问题(详见 §5.8):
|
||||
1. gate-pg 隔离库口令与首次假设不符(全 SKIP,nightly 门禁正确拒绝出收据);
|
||||
2. nightly 测试内嵌 app 启动时的 sysadmin 初始 apply 会用测试库的空 `secrets.minimax_api_key` 清空真实 runner 的 models.json key(已证实机制,nightly 环境补导出正确值规避;产品缺陷待修复任务);
|
||||
3. `.dockerignore` 排除整个 `web/dist`,与 `web/embed.go`(`all:dist`)组合导致候选镜像构建自 P1 起即坏(fix: `!web/dist/.gitkeep`,随本轮入 dev)。
|
||||
|
||||
## 二、测试目标 (Test Objectives)
|
||||
|
||||
- dev 全面门禁绿(arch-check/vet/short/npm/scripts unittest)后晋升 test:`--no-ff` P1=旧 test `0e4b111d`,tag `rc-v1.1.0-beta.4`,镜像 digests 入收据
|
||||
- test 转单二进制:容器 system-db 数据迁入本机 localpg `:5434`(PGDATA=`data/test/pg`,volume 保留可回滚);停 app/events/pi-agent/system-pg 容器;从 **rc tag 源码** 构建 `bin/agent-server-test`;test PI sidecar `:18866` + agent-server(ENV=test, HTTP 8081, MiniMax-M2.7-highspeed, SEED_DEMO_USERS=false)
|
||||
- 验收:health/ready、embed SPA、DB 数据保留与迁移、真实 Runner 执行、dev 环境不受扰
|
||||
|
||||
## 三、测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
| 项 | 值 |
|
||||
|----|-----|
|
||||
| OS | Linux (brew postgresql@18.6 + pgvector) |
|
||||
| 晋升前 dev tip | `5e409c1e`(= D2;含 docker 上下文修复 `e40a9989` + 脚本 `d91dafc1`) |
|
||||
| 晋升前 test tip | `0e4b111d`(rc-v1.1.0-beta.3, schema 66) |
|
||||
| promote M | `2fe1e055`(P1=`0e4b111d`, P2=`5e409c1e`),tag `rc-v1.1.0-beta.4` |
|
||||
| 制品 | `bin/agent-server-test`,sha256 `5796ecb913fd8421d968ffbba29e411301e28dbdf8eeea65452976b4b72e474a`(32MB,`-X main.version=rc-v1.1.0-beta.4`,git archive @ tag 构建) |
|
||||
| 门禁/nightly | gate-pg `127.0.0.1:5436/agent_gate`;dev runner `:18865`;test runner `:18866` |
|
||||
| S0 快照 | `/tmp/agent-test-snap-s0-pre-beta4-20260927T172223Z`(goose 66 / projects 9 / task_runs 9 / users 9,pg_dump -Fc) |
|
||||
| 层级 | 静态门禁 + nightly 真实 PI 五链 + test 部署验收(迁移/配置层 + 业务链路) |
|
||||
|
||||
## 四、预期结果 (Expected Results)
|
||||
|
||||
- nightly 五例(U8 + FullNoneMixed + FullChain×3)全部 PASS 且逐项核对执行;receipt `verdict=pass` + 三镜像 digests
|
||||
- test 候选 first parent = 旧 test tip;tag/rc 校验一致
|
||||
- 迁移后 localpg `:5434/agent_system_test` 数据 = S0;agent-server 启动自动 goose 66→76
|
||||
- test health/ready:`env=test, schema_version=76, database_ready/kb_ready/events_ready=true, shared_kb_port=5432`
|
||||
- SPA 200(embed);PI sidecar `:18866` 真实执行一次 pi run;dev 环境(8080/5433/18865)不受扰
|
||||
|
||||
## 五、实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 5.1 静态门禁(dev tip 94c215d3 = 候选 1)
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| `arch-check.sh --mode block` | PASS |
|
||||
| `go vet ./...` | PASS |
|
||||
| `go test -short ./...` | PASS |
|
||||
| `web/ npm test`(34 例) | PASS |
|
||||
| `web/ npm run build`(demo seeds off + precompress) | PASS |
|
||||
| scripts unittest(234 例) | PASS |
|
||||
|
||||
证据:`/tmp/tsb-gate/01..06`(validate 收据 run `a835747e` @ `94c215d3`)。
|
||||
|
||||
### 5.2 nightly 真实 PI(dev tip `5e409c1e`,nightly7)
|
||||
|
||||
- **输入**:`run-nightly-real-pi.sh` @ `5e409c1e`;`TEST_DATABASE_URL=…:5436/agent_gate`;绝对 `DATA_DIR=data/dev`;`MINIMAX_API_KEY/MINIMAX_MODEL_ID/TAVILY_API_KEYS` 显式导出(见 §5.8-2);KB 预检 OK `127.0.0.1:5432/regulations`
|
||||
- **实际**(首轮 FullNoneMixedChain 命中已知 MISSING_TARGET flake 43s,脚本内整组重试一次):
|
||||
|
||||
| 用例 | 首轮 | 重试 |
|
||||
|------|------|------|
|
||||
| TestMultiIntentU8_RealPI_ConfirmGenerate_PG | PASS 312.5s | PASS 309.2s |
|
||||
| TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain | FAIL 43.1s (MISSING_TARGET) | **PASS 1153.2s** |
|
||||
| TestWorkflowGovernance_PiAgent_PG_FullChain | PASS 309.8s | PASS 364.6s |
|
||||
| TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain | PASS 1199.9s | PASS 1058.9s |
|
||||
| TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain | PASS 1274.6s | (重试组末例由 expected-tests 逐项核对,见 expected-tests.json) |
|
||||
|
||||
- receipt:`.doc/test-reports/assets/promotion-receipts/5e409c1eb237814723f65102cb221a3e2de42e6e.json` `verdict=pass`,model `MiniMax-M2.7-highspeed`,digests app/events=`sha256:c1601783…`、pi-agent=`sha256:c26508b6…`;`promotion-receipt-check --require-digests` OK
|
||||
- **判定**:PASS(expected-tests 逐项核对五例执行且最终轮全 PASS;flake 首轮-重试关系保留如上)
|
||||
|
||||
### 5.3 test 晋升
|
||||
|
||||
- 候选 `2fe1e055`(commit-tree 构造,P1=`0e4b111d`);validate 收据 run `2b9bac34`(receipt gate + 拓扑自检)
|
||||
- `git:test` 租约内:`update-ref refs/heads/test 2fe1e055 0e4b111d`;tag `rc-v1.1.0-beta.4`;`candidate-images-apply.sh test`(app/events/pi-agent 镜像按收据 digest 重打 tag,compose 回滚路径就绪)
|
||||
- **判定**:PASS
|
||||
|
||||
### 5.4 test DB 迁移(容器 → localpg :5434)
|
||||
|
||||
- **输入**:`migrate-dev-db.sh` 以 test 参数运行(CONTAINER=shuimu-system-pg-test、DATA_DIR=data/test、5434/agent_system_test;wrapper 脚本 `migrate-test-db.sh` 的变量名缺陷当场以显式环境变量等价执行,修复随任务入 dev)
|
||||
- **实际**:dump→restore 完成(3 条扩展 COMMENT 噪声,与 dev 迁移一致);restore 后 goose=66、projects/task_runs/users=9/9/9(与 S0 一致);system-db 容器停止(volume 保留)
|
||||
- **判定**:PASS
|
||||
|
||||
### 5.5 单二进制构建与启动
|
||||
|
||||
- **输入**:`git archive rc-v1.1.0-beta.4` → 临时目录;web `npm ci` + `env -u VITE_ENABLE_DEMO_SEEDS npm run build`(precompress 66 br/gz);`CGO_ENABLED=0 go build -ldflags "-s -w -X main.version=rc-v1.1.0-beta.4"` → `bin/agent-server-test`
|
||||
- **实际**:启动后 health/ready `env=test, schema_version=76`(服务端 goose 66→76 自动迁移),`database_ready/kb_ready/events_ready/task_store_ready=true`,`shared_kb_port=5432`(共享 KB 容器,非 dev 库)
|
||||
- **判定**:PASS
|
||||
|
||||
### 5.6 test 验收明细
|
||||
|
||||
| 项 | 实际 | 判定 |
|
||||
|---|---|---|
|
||||
| health/ready `:8081` | `ok / test / schema 76`;ready 同 | PASS |
|
||||
| SPA embed | `GET / → 200`,标题「水木东方 · 医疗器械现代 AI 协同工作台」 | PASS |
|
||||
| DB 数据保留 | localpg :5434 goose=76(数值 cast 核对),projects/users/task_runs=9/9/9 | PASS |
|
||||
| app→DB 连接 | `ss` 确认 agent-server-test ↔ 127.0.0.1:5434 | PASS |
|
||||
| PI sidecar `:18866` | health ok,model MiniMax-M2.7-highspeed,data_dir=data/test/workspaces | PASS |
|
||||
| 真实 PI 执行 | `POST /v1/run`(test sidecar)→ `ok:true` + sidecar 日志 `[runner] Starting pi run … tsb-verify-beta4` | PASS |
|
||||
| 业务管道 | admin 登录 48B token;`POST /api/v1/chat` 两条 → intent+KB 应答 1322 字(模板路径,非寒暄句式不足以触发 dialogue runner;真实 runner 链由 nightly 五链 @ 同代码覆盖 + 上行直调覆盖) | PASS |
|
||||
| 容器状态 | app/events/pi-agent/system-pg-test 全部 Exited(volume 保留);shuimu-kb-shared Up | PASS |
|
||||
| dev 不受扰 | dev health `dev/76`;dev 库 goose=76、projects=22、task_runs=9、窗口期 chat_messages=0(见 §5.8-3) | PASS |
|
||||
|
||||
### 5.7 回滚路径
|
||||
|
||||
- 容器:`docker compose -f docker-compose.test.yml -p agent-test up -d`(镜像已按 beta.4 digests pin;system-db volume 未动)
|
||||
- 数据:S0 快照 restore;localpg 数据可 `pg_dump` 回容器
|
||||
- 单二进制:`bin/agent-server-test` 为制品身份(sha256 见 §三)
|
||||
|
||||
### 5.8 过程事件与现场处置(如实记录)
|
||||
|
||||
1. **gate-pg 口令**:首轮 nightly 全 SKIP(SASL 401)→ 脚本正确写 infra_fail 拒绝晋升;改用容器实际口令(app/app)后正常。
|
||||
2. **runner key 被清空(机制已证实)**:`internal/app/app.go` 每个 app 启动即向 runner `POST /admin/reload` 推送 sysadmin 库解析值;nightly 测试 app 连 gate-pg(`secrets.minimax_api_key` 为空)→ runner `models.json` apiKey 被写空 → pi 以空 key 解析失败后回落内置 MiniMax 目录(anthropic-messages @ api.minimax.io)→ 401。验证:models.json 空 key 必现 401/路由漂移,恢复字面 key 后同请求即 PASS 且 key 不被运行剥离。规避:nightly 环境导出 `MINIMAX_API_KEY/MODEL_ID/ENDPOINT/API_TYPE/TAVILY_API_KEYS` 使推送值正确。**产品缺陷待修复**(建议:payload 空 key 时省略字段或 apply 不以空覆盖),另记 launch.sh sidecar 子 shell 相对 DATA_DIR 扩展路径问题。
|
||||
3. **两次 test server 误连 dev 库(已审计无污染)**:launch-single.sh 首版映射用 `:-` 回退,被分层加载的根 .env `CONTEXT_DB_*`(dev 值)压过;脚本内 `set -a` 重载再次覆盖外部导出。两次均在启动后 ≤2 分钟发现并 kill。dev 库审计:goose=76 未变、projects=22/task_runs=9 稳定、窗口期新增 chat_messages=0(首次窗口 15min、二次 10min 各核一次)。修复(SYSTEM_DB_* 强制覆盖 + 注释说明)已随任务提交。
|
||||
4. **docker 候选镜像构建缺陷**:见背景;修复 `e40a9989` 经真实 `docker build`(git archive 上下文)验证后入 dev(D2),nightly7 在 D2 重跑并产出全 digests PASS 收据。nightly6 @94c215d3 的五链 PASS(收据 infra_fail 于镜像步)保留为过程证据。
|
||||
5. **测试 workspaces/杂散目录**:sidecar 相对路径时期产生的 `deploy/pi-agent/data/`(396K,错误路由产物)已删除(未跟踪垃圾,非证据)。
|
||||
|
||||
## 六、自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 套件 | 范围/SHA | 结果 |
|
||||
|---|---|---|
|
||||
| arch-check block / go vet / go test -short / npm test+build / scripts unittest(234) | 候选 94c215d3 | 全 PASS(§5.1) |
|
||||
| nightly 真实 PI 五链(非 stub,真实 Runner+gate-pg+共享 KB) | dev 5e409c1e | PASS(§5.2) |
|
||||
| docker build(app 镜像,git archive 上下文) | e40a9989 | PASS(sha256:0d5f6663…) |
|
||||
| test 部署验收(health/ready/SPA/迁移/连接/runner/chat) | rc-v1.1.0-beta.4 制品 | PASS(§5.6) |
|
||||
|
||||
## 七、测试结论与后续 (Conclusion & Next Steps)
|
||||
|
||||
**结论**:`rc-v1.1.0-beta.4`(`2fe1e055`)已晋升 test 并以单二进制形态落地:localpg `:5434`(schema 76、S0 数据完整)、agent-server-test(tag 源码构建、sha256 入档)、PI sidecar `:18866`、共享 KB 保持容器形态;容器 compose 路径与 S0 快照构成回滚面。dev 环境全程无扰动(两次误连均已审计)。
|
||||
|
||||
**后续**:
|
||||
1. 产品缺陷修复任务:sysadmin 初始 apply 空 key 清空 runner 配置(§5.8-2);launch.sh sidecar 相对路径;建议随修复把 nightly 的 MINIMAX_* 显式导出固化进 run-nightly 脚本注释/模板
|
||||
2. systemd 单元与 `install-test.sh`/preflight 打包(设计 §5.1)未在本轮范围,test 先以 nohup 形态长期运行(与 dev 一致)
|
||||
3. embedding 401 运维债不变(非 blocker)
|
||||
4. main 未晋升;远端未 push(未请求)
|
||||
|
||||
**证据路径**:receipt/evidence 见 `.doc/test-reports/assets/promotion-receipts/5e409c1e…{json,-images.json}` 与 `evidence-5e409c1e…/`、`evidence-94c215d3…-171311Z/`(过程);门禁日志 `/tmp/tsb-gate/`;nightly 日志 `/tmp/tsb-nightly/nightly{1..7}.log`;转换日志 `/tmp/tsb-convert/`(本机,未入库);服务日志 `.tmp/launch/{server,pi-sidecar}-test.log`。
|
||||
@@ -0,0 +1,46 @@
|
||||
# 激活预览前端预检 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
dev 项目 6022 在全部文档未纳入人工审批时,`POST /api/v1/projects/6022/activation-preview` 返回 400 `NO_GOVERNED_DOCUMENT`。服务端门禁正确,前端缺少同等预检。管理台「模型与密钥」另有 5 个密码框不在 form 内,触发 Chromium DOM 警告。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 默认计划直接点「校验并预览」时不发出 activation-preview 请求,并显示本地提示。
|
||||
- 至少一份文档纳入人工审批(兼任模式)后,activation-preview 返回 200。
|
||||
- 模型与密钥页 5 个密码框都在 form 内。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- 环境:本机 dev,`https://frp-mix.com:58880` → Vite `:3100` → `127.0.0.1:8080`。合入后的 dev `3e534bbb`。Vite 已提供含 `needsGovernedDocument` 的源码。
|
||||
- 层级:前端单测 + 构建;dev 真实浏览器(登录后新建项目「预检回归-0928」,仅创建人一名成员)。
|
||||
- Go 服务未改,未重建 `bin/agent-server`。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- 未纳入人工审批:页面提示「至少一份文档必须纳入人工审批才能激活工作流」,网络无 activation-preview。
|
||||
- 兼任编制人后:`workflow-plan` 与 `activation-preview` 均为 200。
|
||||
- 密钥页:`input[type=password]` 数量 5,且 `closest('form')` 均存在。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
- **测试输入 (Input)**:admin 登录 → 新建立项「预检回归-0928」→ 商务对接流程默认计划 → 「校验并预览」。
|
||||
- **实际输出 (Actual Output)**:页面含该提示句。注入的 fetch 记录只有 `GET /api/v1/projects/6023/workflow-plan/default` 200,没有 activation-preview。
|
||||
- **评价判定**:PASS
|
||||
- **性能与耗时**:页面即时拦截,无额外请求。
|
||||
|
||||
- **测试输入 (Input)**:勾选「用户初始需求收集表 / 纳入人工审批 / 由编制人兼任审核、批准」,编制人选系统管理员,再点「校验并预览」。
|
||||
- **实际输出 (Actual Output)**:`PUT /api/v1/projects/6023/workflow-plan` 200;`POST /api/v1/projects/6023/activation-preview` 200。进入确认激活步骤。未点击最终激活。
|
||||
- **评价判定**:PASS
|
||||
|
||||
- **测试输入 (Input)**:系统管理 → 模型与密钥。
|
||||
- **实际输出 (Actual Output)**:`passwordInputs=5`,`outsideForm=0`,五个 `autocomplete=new-password`。
|
||||
- **评价判定**:PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
在 worktree `web/`:`npm test` 526 + vitest 34 通过;`npm run build` 通过。`agentctl validate` 收据任务 `integrate-activation-preview-precheck-2026-09-28`,sha `3e534bbb39d0d957e0b720a4ca06f22dd15959e6`。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
授权范围内的 dev 复验通过。项目 6023 停在规划确认步,未激活。远端未推送。
|
||||
@@ -0,0 +1,77 @@
|
||||
# 管理台重置密码入口恢复 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
管理员在「用户与准入治理」找不到重置密码。F4-B 端点已在 dev(`39f8c1d1`),F4-A(`d653e32e`)误删了按钮。本轮只恢复 UI 接线。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 用户列表重新出现「重置密码」,并调用已有 `POST /api/v1/admin/users/{id}/reset-password`
|
||||
- 临时口令为服务端随机值(长度 16),不落报告正文
|
||||
- 已完成过首次改密的账号,被重置后的下一次登录必须改密;再下一次登录不再弹出
|
||||
- 重置前的口令失效
|
||||
- 前端 `tsc --noEmit` 与 `npm test` 通过
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS: Linux;Node v26.10.0;worktree `feature/restore-admin-password-reset-2026-09-28` @ `f0ecc4c9`(UI 提交;文档提交在其后)
|
||||
- 前端单测在 worktree `web/`(`node_modules` 链接主目录,未入库)
|
||||
- 真实 UI:worktree Vite `127.0.0.1:3110` 代理本机 dev API `127.0.0.1:8080`(`/health` 200)。未替换用户正在使用的 `:3100` 进程
|
||||
- **NOT REQUIRED**:产品 PI 全链路。依据:IAM/管理台工程变更,不改工作流模板或提示词;见 PROJECT.md「验证入口」与测试报告规范的工程例外。同 [2026-09-24 报告](./2026-09-24-admin-password-reset-test-report.md)
|
||||
- **NOT REQUIRED**:`go test`。本任务无 Go 差异
|
||||
|
||||
证据:[assets/2026-09-28-admin-password-reset-restore/](./assets/2026-09-28-admin-password-reset-restore/)
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 用例 | 预期 |
|
||||
|---|---|
|
||||
| 探针账号开通后首次登录 | `must_change_password=true` |
|
||||
| 自行改密后再次登录 | `must_change_password=false` |
|
||||
| 管理台重置 | 确认框 + 临时口令长度 16 + 「密码已重置」 |
|
||||
| 用临时口令登录 | 出现「首次登录安全改密」 |
|
||||
| 改密后再次登录 | 进入工作台,强制改密弹窗数量为 0 |
|
||||
| 重置前口令 | HTTP 401 |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
探针账号 `pwreset_probe_mukj4wsy`(user id 77)。测完已停用。临时口令与管理员口令不写入本报告。
|
||||
|
||||
### 用例 1:前端类型检查与单测
|
||||
|
||||
- **输入**:`npx tsc --noEmit`;`npm test`
|
||||
- **实际输出**:`TSC_EXIT=0`。node:test `pass 525` / `fail 0`(1487ms);vitest `3 files / 34 passed`(327ms)
|
||||
- **判定**:PASS
|
||||
|
||||
### 用例 2:重置前账号处于「已改密、不再强制」
|
||||
|
||||
- **输入**:管理员 API 开通探针 → 初始口令登录 → `change-password` → 再登录
|
||||
- **实际输出**:见 `result.json`:`probe_initial_login_must_change` 200/`true`;`probe_settled_login_no_force` 200/`false`
|
||||
- **判定**:PASS
|
||||
- **耗时**:含在整段探针内(成功那次进程约 3.2s;前一次因管理台内找不到工作台退出按钮失败,已改为先「返回工作台」)
|
||||
|
||||
### 用例 3:管理台重置并强制改密仅一次
|
||||
|
||||
- **输入**:`http://127.0.0.1:3110` 管理员进入「用户与准入治理」,搜索探针账号,点击「重置密码」;用临时口令登录并改密;退出后再登录
|
||||
- **实际输出**:
|
||||
- 按钮可见:`01-reset-button.png`
|
||||
- 确认文案含「一次性临时口令」「下次登录将被强制改密」;`ui_prompt_temp_password.length=16`;toast「密码已重置」
|
||||
- 临时口令登录出现「首次登录安全改密」:`02-force-change-modal.png`
|
||||
- 改密后进入工作台;再次登录 `modal_count=0`:`03-second-login-workbench.png`
|
||||
- 重置前口令登录 `status=401`
|
||||
- **判定**:PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
```text
|
||||
npx tsc --noEmit # exit 0
|
||||
npm test # 525 + 34 PASS,fail 0
|
||||
go test # 未运行(无 Go 差异)
|
||||
产品 PI nightly # NOT REQUIRED(见第三节)
|
||||
```
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
- UI 恢复达到合入 local dev 的验收。运行中的 `:3100` 在本提交进入主目录 `dev` 后由既有 Vite 热更新;本报告的浏览器证据来自 `:3110`。
|
||||
- 强制改密复用既有 `FirstLoginPasswordModal`,文案仍写「账号由管理员开通」。行为满足「重置后第一次登录必须改密」。
|
||||
- 探针账号 76(失败重试)与 77 均已置为 disabled。
|
||||
@@ -0,0 +1,83 @@
|
||||
# 助手回复智能体叙述 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
项目助手大量查询、帮助和操作回执仍由 Go 硬编码模板直接返回。本轮把这些路径改为:系统先生成确定性事实底稿,再由产品 PI Agent Runner 组织自然语言;Runner 失败、开关关闭或无 backend 时回退原模板。安全拦截、权限不足和确认提问不进入叙述。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- T1 权责查询、T2 能力帮助、T3 暂缓回执由真实 Runner 生成,`reply_source=pi-agent`,且保留底稿中的人名、文档名或项目名。
|
||||
- Runner 失败时回退模板,并记录 `agent_reply_fallback`。
|
||||
- 开关关闭时不调用 backend。
|
||||
- 安全拦截话术不被叙述改写。
|
||||
- 存量 `go test -short ./...` 与 `arch-check --mode block` 通过。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS:Linux。Go 模块测试在任务 worktree `feature/agent-reply-llm-narrative-2026-09-28`,基线 dev `8f77053f5169502eaf3e4e4135a082e8914f3704`。
|
||||
- 真实 Runner:宿主机 `http://127.0.0.1:18865/health` 返回 200。模型按本机批准配置 `PI_AGENT_PROVIDER=minimax`、`PI_AGENT_MODEL=MiniMax-M2.7-highspeed`。凭证只从本机 `.env` 读取,不写入报告。
|
||||
- 层级:Go 单测(scripted backend)+ 受影响产品 PI 链路(`RUN_PI_E2E=1`)。未跑 nightly 五项全量,因为本变更不改工作流生成链。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- 有 backend 且开关开启:`ReplySource=pi-agent`,提示词含「系统确定性底稿」。
|
||||
- backend 返回失败:`ReplySource=template`,正文仍含模板标题「我能帮您做什么」。
|
||||
- `AGENT_REPLY_LLM` 测试开关关闭:不调用 backend。
|
||||
- `SECURITY_FORBIDDEN`:正文不含脚本注入的智能体改写句。
|
||||
- 真实 Runner 三轮均 `source=pi-agent`,且分别保留「张工/用户需求表」「查询/补充」「肌骨超声项目」。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:真实 Runner T1/T2/T3
|
||||
|
||||
- **测试输入 (Input)**:`RUN_PI_E2E=1 go test -count=1 -timeout 8m -v ./internal/coordinator/ -run TestIntentReply_RealPI_NarratesQueryHelpAndDecline`
|
||||
- **实际输出 (Actual Output)**:
|
||||
|
||||
```text
|
||||
intent=QUERY_USER_RIGHTS source=pi-agent duration=8.919s
|
||||
intent=HELP_CAPABILITIES source=pi-agent duration=11.655s
|
||||
intent=DECLINE_EXPECTATION source=pi-agent duration=6.329s
|
||||
--- PASS: TestIntentReply_RealPI_NarratesQueryHelpAndDecline (26.90s)
|
||||
```
|
||||
|
||||
权责回复含「张工」与「用户需求表」;帮助回复含「查询项目进展与风险」「补充项目事实」,并保留「请前往项目设置界面」;暂缓回复含「肌骨超声项目暂不推进」。路由日志里的 `channel=TEMPLATE` 是 R0 意图通道名,不是回复来源;回复来源字段为 `pi-agent`。
|
||||
|
||||
- **评价判定**:PASS
|
||||
- **性能与耗时**:三轮合计 26.90s(8.919s / 11.655s / 6.329s)
|
||||
|
||||
### 用例 2:backend 失败回退模板
|
||||
|
||||
- **测试输入**:`go test -short -v -run TestIntentReply_BackendFailureFallsBackToTemplate`
|
||||
- **实际输出**:
|
||||
|
||||
```text
|
||||
INFO agent_reply_fallback handler=handleHelpCapabilities intent=HELP_CAPABILITIES reason="forced failure"
|
||||
--- PASS: TestIntentReply_BackendFailureFallsBackToTemplate (0.00s)
|
||||
```
|
||||
|
||||
- **评价判定**:PASS
|
||||
- **性能与耗时**:<1s(scripted backend,非真实 Runner)
|
||||
|
||||
### 用例 3:开关关闭与安全话术
|
||||
|
||||
- **测试输入**:`TestIntentReply_FlagOffKeepsTemplate`、`TestIntentReply_SecurityForbiddenStaysTemplate`
|
||||
- **实际输出**:两者 PASS。安全用例未调用 dialogue backend。
|
||||
- **评价判定**:PASS
|
||||
- **性能与耗时**:<1s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| `./scripts/arch-check.sh --mode block` | PASS(production gate passed) |
|
||||
| `go vet ./...` | PASS(exit 0) |
|
||||
| `go test -short -count=1 -timeout 8m ./...` | PASS(含 `internal/coordinator` 0.042s、`internal/server` 20.498s) |
|
||||
| `RUN_PI_E2E=1` 叙述三轮 | PASS(26.90s) |
|
||||
|
||||
未运行 nightly 全量五项。不把未运行记为产品全链路 PASS。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
授权范围内的叙述改造达到本轮验收:真实 Runner 能在保留确定性事实的前提下改写查询、帮助和暂缓回执;失败与安全边界仍走模板。
|
||||
|
||||
后续可观察线上 `agent_reply_fallback` 比例,再决定是否把仍保持模板的确认提问也改为叙述。确认卡选项与权限拒绝本轮故意不改。
|
||||
@@ -0,0 +1,65 @@
|
||||
# 只上传文档的对话回合 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
只上传文档、不输入文字时,`POST /api/v1/chat/stream` 返回 400 `message cannot be empty`。前端丢弃响应体,气泡显示 `请求失败(HTTP_400)`。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 无文字且无附件仍拒绝。
|
||||
- 无文字但有附件不再因空消息被拒绝;解析未完成时返回可阅读的引导,而不是 400。
|
||||
- 正文可读且没有对话模型时,回退为包含正文要点和下一步编号的回复。
|
||||
- 有文字且未要求处理附件时,在原回复后追问一次。
|
||||
- 4xx 信封能还原成具体文案。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS:Linux;工作区 `.worktrees/attachment-only-turn-2026-09-28`;基线 `3e534bbb39d0d957e0b720a4ca06f22dd15959e6`。
|
||||
- 合入:候选 `cb4d2af8d30cecf8a1ca0f36eafbf46d56888387`(第一父 `63144067`)经 `validate` 后由 daemon `--ff-only` 进入 local dev。
|
||||
- 层级:工程单测、重载后的 dev API,以及同一 Vite(:3100)上的真实浏览器。`./scripts/launch.sh --no-docker` 于 10:22(+0800)重建并重启 :8080。
|
||||
- 解析未完成时不调用对话模型;正文可读时回复来自运行中的 dev 助手(`agent_backend=pi-agent`),不是测试桩。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- 双空请求 400,正文含 `message cannot be empty`。
|
||||
- 仅附件且 `parse_state=pending` 的同步对话返回 200,回复含「解析」。
|
||||
- 可读正文的协调结果含正文片段和 `1.` 选项,并挂 3 个期望选项。
|
||||
- 无关文字追加「另外已收到」;总结意图不追加。
|
||||
- 前端把 `VALIDATION` + `message cannot be empty` 显示为「请输入文字,或上传文档后再发送」。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
- **输入**:`go test -count=1 -timeout 180s -v ./internal/server/ -run 'TestPrepareChatTurn|TestTurnAttachmentHashKey|TestChatStream_Empty|TestChatStream_AttachmentOnly|TestChat_AttachmentOnly'`
|
||||
- **输出**:5 个用例 PASS(约 0.31s)。`TestChat_AttachmentOnlyPendingRepliesInsteadOf400` 为 200 且断言回复含「解析」。
|
||||
- **判定**:PASS
|
||||
|
||||
- **输入**:`go test -count=1 ./internal/coordinator/ -run 'TestHandleUploadIntake|TestAnnotateUnrelatedUploads'`
|
||||
- **输出**:`ok chat-agent-system/internal/coordinator`
|
||||
- **判定**:PASS(模板回退,不是 PI Agent)
|
||||
|
||||
- **输入**:`go test -short -count=1 ./internal/coordinator/ ./internal/chat/ ./internal/ctxmgr/ ./internal/server/`
|
||||
- **输出**:四个包均 ok;server 包 20.553s。合入候选 `cb4d2af8` 上由 `agentctl validate` 复跑同一命令,server 包 20.406s,四个包均 ok。
|
||||
- **判定**:PASS
|
||||
|
||||
- **输入**:`go vet ./internal/server/ ./internal/coordinator/ ./internal/chat/ ./internal/ctxmgr/`
|
||||
- **输出**:无诊断
|
||||
- **判定**:PASS
|
||||
|
||||
- **输入**:在 `web/` 执行 `npx tsx --test src/lib/turnAttachments.test.ts`
|
||||
- **输出**:2 pass / 0 fail,duration_ms 152
|
||||
- **判定**:PASS
|
||||
|
||||
- **浏览器 / 重载后的 dev**(2026-09-28 10:22 之后,pid 1002830,schema 78)
|
||||
- **仅附件、解析未完成**(API,`parse_state=pending`):`POST /api/v1/chat/stream` 200,约 11.6s。回复:「《F-030-verify.pdf》仍在解析中,请稍后再试总结。」并说明回复「总结」后会梳理。`GET` 对应 turn 200 `completed`。
|
||||
- **仅附件、浏览器**:发送按钮在选中 PDF 后可用;用户气泡为「已上传文档:《F-030-verify.pdf》」;助手给出结构化梳理、初步审阅和编号下一步。`chat/stream` 200。未见「请输入文字,或上传文档后再发送」。截图见 [assets](assets/2026-09-28-attachment-only-turn/02-structured-review.png)。
|
||||
- **无关文字 + 附件**:浏览器输入「今天天气怎么样」并附上同一 PDF。先回复天气,再追加「另外已收到《F-030-verify.pdf》…」。`chat/stream` 200,约 22s。同一句话的 API 路径约 17s,追问文案一致。
|
||||
- **双空**:浏览器发送按钮保持禁用。API `message=""` 且无附件返回 400,`error` 为 `message cannot be empty`,turn 不创建。
|
||||
- **判定**:PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
本次实际运行的是上述包测试、一条前端用例,以及重载后的 dev API 与 :3100 浏览器三条路径。不是全量 `go test ./...` 或完整 `npm test`。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
只上传文档不再被空消息拒绝。解析未完成时给出引导;浏览器里这份验证 PDF 在解析有结果后得到梳理、审阅和下一步。无关文字先回答再追问。用户此前看到的「请输入文字,或上传文档后再发送」来自新前端配旧二进制;10:22 重载后的 :8080 已包含本修复。历史任务事件流的 HTTP/2 与 502 仍未处理。
|
||||
@@ -0,0 +1,84 @@
|
||||
# 注册 INTERNAL(标准角色缺失)测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
test 环境(`:8081`)注册新用户返回 `INTERNAL` / 「请求无法完成」。dev(`:8080`)新用户名可成功,但重复用户名同样是 `INTERNAL`。根因是 test 库缺 `role-guest`(FK 23503),以及用户名唯一冲突被当成基础设施错误。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- test 补种标准角色后,新用户名注册返回 200
|
||||
- 重复用户名在新代码下返回 400,`error` 为「用户名已存在」
|
||||
- 既有注册成功路径(审核中)不回归
|
||||
- 不替换 rc 制品 `bin/agent-server-test`
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS: Linux;worktree `fix/auth-register-internal-2026-09-28`,基线 `4ba60c2c9d7eaf3e3e824475c0f3a44e10641190`
|
||||
- 单测:`go test` 内存库与冲突分类(不连 5433/5434)
|
||||
- 实库:test localpg `:5434` / `agent_system_test`。合入前手工执行 00077 Up(当时 goose 仍为 76);合入 `9141741b` 后 `./scripts/launch-single.sh test`(未 `--build`)重启,日志 `goose: successfully migrated database to version: 77`
|
||||
- 运行中的 `:8081` 仍是 rc 单二进制,不含本次 Go 改动
|
||||
- **NOT REQUIRED**:产品 PI 全链路。依据:IAM 注册与迁移,不改工作流模板或提示词
|
||||
|
||||
证据目录:[assets/2026-09-28-auth-register-internal/](./assets/2026-09-28-auth-register-internal/)
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
| 用例 | 预期 |
|
||||
|---|---|
|
||||
| test 缺 role-guest 时注册 | 修复前 INTERNAL;补种后 200 |
|
||||
| 新代码重复用户名 | 400,`error` 含「已存在」,`code=VALIDATION` |
|
||||
| 当前 rc 二进制重复用户名 | 仍 INTERNAL(制品未换) |
|
||||
| dev 新用户名 | 200 |
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 1. 修复前复现
|
||||
|
||||
- **输入**:`POST /api/v1/auth/register` 用户名 `diag_user_0928`
|
||||
- **实际输出**:dev `{"status":"active",...,"user_id":75}`;test `{"code":"INTERNAL","message":"请求无法完成","request_id":"req_diag_repro_002","error":"INTERNAL"}`。dev 重复同一用户名:`request_id=req_f0a8c723ed8e6c4a`,同样 INTERNAL
|
||||
- **评价**:PASS(复现)
|
||||
- **耗时**:约 150ms
|
||||
|
||||
### 2. 补种后 test 注册
|
||||
|
||||
- **输入**:00077 Up(`INSERT 0 4` 角色);`POST :8081/api/v1/auth/register` 用户名 `regfix_0928a`,`X-Request-ID: req_regfix_fresh_0928`
|
||||
- **实际输出**:HTTP 200 `{"status":"active","message":"注册成功,已激活,请返回登录","user_id":43}`。`role-guest/director/engineer/tech-lead` 的 `is_system=t`。探测用户与 dev 上的 `diag_user_0928`、`regfix_dev_0928a` 已删除
|
||||
- **评价**:PASS
|
||||
- **耗时**:注册请求 < 1s
|
||||
|
||||
### 3. 当前 test 二进制的重复用户名
|
||||
|
||||
- **输入**:再次注册 `regfix_0928a`,`X-Request-ID: req_regfix_dup_0928`
|
||||
- **实际输出**:`{"code":"INTERNAL","message":"请求无法完成","request_id":"req_regfix_dup_0928","error":"INTERNAL"}`
|
||||
- **评价**:符合预期(rc 制品尚无 `ErrUsernameExists`)。400 行为由单测覆盖,随下次含本提交的 test 制品生效
|
||||
- **耗时**:< 1s
|
||||
|
||||
### 4. dev 新用户名对照
|
||||
|
||||
- **输入**:`POST :8080` 用户名 `regfix_dev_0928a`
|
||||
- **实际输出**:`{"status":"active","message":"注册成功,已激活,请返回登录","user_id":79}`(随后删除)
|
||||
- **评价**:PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
```
|
||||
ok chat-agent-system/internal/auth 0.087s
|
||||
TestIsUsernameConflict PASS(23505 用户名约束为真,23503 与其它唯一约束为假)
|
||||
TestErrUsernameExistsIsNotInfrastructureShaped PASS
|
||||
ok chat-agent-system/internal/server 0.349s
|
||||
TestAuthHandlers_RegisterAndApproval PASS
|
||||
TestAuthHandlers_RegisterDuplicateUsername PASS(400 / VALIDATION / error 含「已存在」)
|
||||
```
|
||||
|
||||
`TestPgStore_CreateUserDuplicateUsername` 在未设置 `TEST_DATABASE_URL` 时 Skip,不连共享库。
|
||||
|
||||
### 5. 合入后重启 test
|
||||
|
||||
- **输入**:`./scripts/launch-single.sh test`(不 `--build`,沿用 rc 二进制);再 `POST :8081/api/v1/auth/register` 用户名 `regfix_0928b`,`X-Request-ID: req_regfix_after_restart`
|
||||
- **实际输出**:`.tmp/launch/server-test.log` 含 `OK 00077_2026-09-28-reseed-standard-roles.sql` 与 `goose: successfully migrated database to version: 77`。`goose_db_version` 最新为 77。HTTP 200 `{"status":"active","message":"注册成功,已激活,请返回登录","user_id":45}`。该用户已删除
|
||||
- **评价**:PASS
|
||||
- **耗时**:重启至健康检查约 12s
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
test 注册失败已解除:标准角色已补种,goose 77,重启后的 `:8081` 注册返回 200。重复用户名的 400 在本提交单测通过;正在运行的 rc 二进制仍会把重复用户名报成 INTERNAL,随下次包含本提交的 test 制品生效。不要为这条 400 替换当前 rc 二进制。
|
||||
@@ -0,0 +1,47 @@
|
||||
# docgov 共享 map 并发读写 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
2026-09-28 06:38 UTC,dev 后端因 `internal/docgov` 共享 map 并发读写 fatal 退出。Vite 代理在后端缺席期间对登录等全部 API 返回 500。本报告记录修复后的工程回归。产品 PI 全链路不适用:变更是治理引擎内存锁,不改对话或文档业务规则。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 不同 docID 并发创建、读取、列审计/批注、写批注时,`-race` 不报告 data race,进程不 fatal。
|
||||
- 并发结束后每个 docID 仍能读回。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS:Linux;`go version go1.27.1 linux/amd64`
|
||||
- 工作区:`.worktrees/docgov-shared-map-race-2026-09-28`,提交 `a90cce73`
|
||||
- 层级:模块单元测试 + race detector。无数据库。产品 PI:NOT REQUIRED(非产品工作流变更;依据验证契约对纯工程锁修复的范围,以及本报告不把单测写成产品 PASS)。
|
||||
- 用例:`TestMemMapsNoRaceAcrossDocs`
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
`go test -race` 该用例 PASS,且 48 个文档均可 `GetDocument`。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
- 测试输入 (Input):`go test -race -count=1 -timeout 180s -v ./internal/docgov/ -run TestMemMapsNoRaceAcrossDocs`
|
||||
- 实际输出 (Actual Output):
|
||||
|
||||
```
|
||||
=== RUN TestMemMapsNoRaceAcrossDocs
|
||||
--- PASS: TestMemMapsNoRaceAcrossDocs (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/docgov 1.012s
|
||||
```
|
||||
|
||||
- 评价判定 (Evaluation / Verdict):PASS
|
||||
- 性能与耗时 (Duration & Latency):包测试约 1.012s;用例本身 0.00s(race 插桩耗时在包级)
|
||||
|
||||
同一次会话里不带 `-run` 的 `go test -race -count=1 -timeout 180s ./internal/docgov/` 亦为 `ok`(1.012s)。dev 进程重建后的 `/health` 与登录复验在合入之后补记,本段不将其记为已完成。
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
- `go test -race ./internal/docgov/`:PASS(含 `TestMemMapsNoRaceAcrossDocs`)
|
||||
- 未跑产品 PI、未跑全仓 `go test`
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
工程回归达到本修复的单测终点。合入 local dev 后需重建 `bin/agent-server` 并确认 `/health` 与空登录请求返回 401 而不是 500。`ISSUE-20260926-docgov-memdocs-poison` 仍开放。
|
||||
@@ -0,0 +1,95 @@
|
||||
# 统一错误码与错误审计 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
HTTP 错误以前经 `writeSafeError` 只返回信封,不写服务端日志,`request_id` 无法和失败原因对照。本轮加入 `internal/errcode` 注册表、结构化错误日志、`error_events` 审计和管理台查询。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 错误码唯一,公开文案不包含内部片段。
|
||||
- 错误日志带 `code` 与 `request_id`,不写调用方原文。
|
||||
- 处理器显式给出的 HTTP 状态保持不变;信封 `code` 使用稳定细码。
|
||||
- 流式分类优先读取类型化错误码。
|
||||
- 管理台错误审计在无 `system:audit:read` 时拒绝。
|
||||
- 模块边界门禁、`go vet`、`go test -short`、前端测试与构建通过。
|
||||
- 产品 PI 全链路不在本次范围。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS:Linux。Go 模块 `chat-agent-system`。工作树 `feature/error-code-observability-2026-09-28`,基线 `3e534bbb39d0d957e0b720a4ca06f22dd15959e6`。
|
||||
- 前端:`web/` 内 `npm ci` 后执行 `npm test` 与 `npm run build`。
|
||||
- 层级:工程单测与前端单测。隔离 PostgreSQL 需要 `TEST_DATABASE_URL`,本次环境未设置。
|
||||
- 产品 Runner 全链路:NOT REQUIRED。本次不改变 PI 协议,只改变错误分类、日志和审计查询。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- `arch-check --mode block` 通过。
|
||||
- `go test -short ./...` 通过。重复用户名注册仍是 HTTP 400,信封码为 `AUTH_USERNAME_EXISTS`。
|
||||
- `TestStoreRoundTrip` 在没有测试库时 SKIP,不得连开发库。
|
||||
- 前端 `npm test` 0 fail,`npm run build` 退出码 0。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 1. 模块边界
|
||||
|
||||
- 输入:`./scripts/arch-check.sh --mode block`
|
||||
- 实际输出:`arch-check block: production gate passed`(`internal/archtest` 两次 `ok`,0.217s 与 0.197s)
|
||||
- 判定:PASS
|
||||
|
||||
### 2. 注册表、日志、分类与异步包
|
||||
|
||||
- 输入:`go test -count=1 -timeout 180s ./internal/errcode ./internal/httpx ./internal/stream ./internal/errorevents ./internal/events ./internal/taskrun ./internal/ctxmgr`
|
||||
- 实际输出:上述包全部 `ok`(errcode/httpx/stream/errorevents 约 0.003s,taskrun 0.172s,ctxmgr 0.104s)
|
||||
- 判定:PASS
|
||||
|
||||
### 3. 全量 short 测试的第一轮
|
||||
|
||||
- 输入:`go vet ./... && go test -short -count=1 -timeout 20m ./...`
|
||||
- 实际输出:`go vet` 无诊断。随后仅 `TestAuthHandlers_RegisterDuplicateUsername` 失败:`duplicate username must be 400, got 409`。日志为 `http_error code=AUTH_USERNAME_EXISTS status=409`。其余已跑完的包为 `ok`。
|
||||
- 判定:FAIL。原因是注册表建议状态覆盖了处理器传入的 400。
|
||||
|
||||
### 4. 保持处理器状态后的第二轮
|
||||
|
||||
- 输入:同一条 `go test -short ./...`
|
||||
- 实际输出:`http_error code=AUTH_USERNAME_EXISTS status=400`。断言改为检查细码前,失败信息是 `expected VALIDATION, got "AUTH_USERNAME_EXISTS"`。
|
||||
- 判定:FAIL。HTTP 状态已恢复为 400。失败点是旧测试仍要求粗码 `VALIDATION`。
|
||||
|
||||
### 5. 更新测试期望后的 server 包
|
||||
|
||||
- 输入:`go test -short -count=1 -timeout 10m ./internal/server`
|
||||
- 实际输出:`ok chat-agent-system/internal/server 20.288s`
|
||||
- 判定:PASS。重复用户名单测单独复跑亦为 `ok`(0.175s)。
|
||||
|
||||
### 6. 审计表集成
|
||||
|
||||
- 输入(合入前):`go test -short -count=1 -v ./internal/errorevents -run TestStoreRoundTrip`
|
||||
- 实际输出:`TEST_DATABASE_URL not set; skipping PostgreSQL integration test`,`--- SKIP: TestStoreRoundTrip (0.00s)`
|
||||
- 判定:SKIP。当时没有隔离库,未连接开发库。
|
||||
|
||||
- 输入(补跑,2026-09-28):一次性容器 `pgvector/pgvector:pg16` 映射 `127.0.0.1:15432`,库名 `agent_itest`。`TEST_DATABASE_URL` 指向该库。测完容器已删除。
|
||||
- 实际输出:`OK 00078_2026-09-28-error-events-audit.sql (3.3ms)`,`goose: successfully migrated database to version: 78`,`--- PASS: TestStoreRoundTrip (0.42s)`,`ok chat-agent-system/internal/errorevents 0.428s`
|
||||
- 判定:PASS。写入后按 `request_id` 读回一条,且 `upstream` 为空。
|
||||
|
||||
### 7. 前端
|
||||
|
||||
- 输入:`npm ci`,然后 `npm test && npm run build`
|
||||
- 实际输出:`added 245 packages`。node:test `tests 526` / `pass 526` / `fail 0`。vitest `Test Files 3 passed` / `Tests 34 passed`。构建结束 `precompress: wrote 66 .br and 66 .gz`,退出码 0。
|
||||
- 判定:PASS
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| `./scripts/arch-check.sh --mode block` | PASS |
|
||||
| `go vet ./...` | PASS(无诊断后进入测试) |
|
||||
| 相关包单测(errcode、httpx、stream、events、taskrun、ctxmgr) | PASS |
|
||||
| `go test -short ./internal/server`(修复期望后) | PASS,20.288s |
|
||||
| `go test -short ./...` 第一轮 | FAIL,1 个用例;修复后未整库重跑,变更只影响 server 错误状态与一条断言,server 包已重跑通过 |
|
||||
| `TestStoreRoundTrip` | 合入前 SKIP;隔离库补跑 PASS,0.428s |
|
||||
| `npm test` | PASS,526 + 34 |
|
||||
| `npm run build` | PASS |
|
||||
| 产品 PI 全链路 | NOT REQUIRED |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
授权范围内的工程验证已达到合入前门槛。隔离库补跑后,`error_events` 的写入和按 `request_id` 读回通过。部署验证不在本次授权内。
|
||||
@@ -0,0 +1,84 @@
|
||||
# PI runner 环境错配(MISSING_TARGET)测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
test 环境用户发送「1」确认推进后,对话返回 `INTERNAL_ERROR` / `fatal`,upstream 为 `step step_03_regulatory failed: MISSING_TARGET`(requestId `req_1790558986255320703`,session `sess-p5-u32`)。
|
||||
|
||||
已证实根因:test 服务器进程的 `PI_AGENT_RUNNER_URL` 来自根 `.env` 的 dev sidecar `http://127.0.0.1:18865`,压过 `configs/.env.test` 的端口约定 `18866`。dev sidecar 的 `resolveWorkspace` 把 `data/test/workspaces/...` 重写到 `data/dev/workspaces/...` 影子目录。影子目录没有 `context/`、`template.md`、`blackboard.json`,模型无法写出 `output.md`,runner 报 `MISSING_TARGET`,步骤按 permanent-missing 不再重试。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- test 进程连到本环境 sidecar `18866`,不再使用根 `.env` 泄漏的 `18865`。
|
||||
- 发往 runner 之前,工作区必须位于该 runner `data_dir` 之下;不一致时 fail-fast,错误码 `RUNNER_MISMATCH`。
|
||||
- 与故障同构的确认「1」推进 V0.5 时,`bd_research`(含原先失败的 `step_03_regulatory`)在 `data/test/workspaces` 本地执行并成功,且不在 `data/dev/workspaces` 生成影子目录。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS:Linux;test 后端 `bin/agent-server-test` pid `1222963`,`ENV=test`,`DATA_DIR=/home/weichen/projects/Agent-System/data/test`。
|
||||
- 启动:worktree 内 `env -u PI_AGENT_RUNNER_URL ./scripts/launch-single.sh test`。sidecar `18866` 已健康,脚本未重启 sidecar。
|
||||
- 层级:`go test` 覆盖 agent/stream/errcode;产品验收为 test 环境真实 PI runner(MiniMax-M2.7-highspeed),对话 `sess-p5-u32` 发送「1」,命中 `ADVANCE_STAGE` / `EXPECTATION_HIT`,目标阶段 `V0.5_feasibility`。
|
||||
- 验收会话为一次性 `auth_sessions` 行(user 32),验收后已 `revoked_at`。令牌未写入本报告。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- 进程环境 `PI_AGENT_RUNNER_URL=http://127.0.0.1:18866`;`18866` 的 `data_dir` 为 `data/test/workspaces`。
|
||||
- 首次 `/v1/run` 前日志出现 `pi runner data_dir check passed`。
|
||||
- `bd_research` 七步 `completed`,`step_03_regulatory/output.md` 非空,且路径在 test 工作区。
|
||||
- 不出现 `MISSING_TARGET` / `RUNNER_MISMATCH`。
|
||||
- 单测:data_dir 不一致时不调用 `/v1/run`;一致时透传;分类码为 `RUNNER_MISMATCH` 且不泄漏路径。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:进程指向与健康检查
|
||||
|
||||
- **输入**:重启后读 `/proc/1222963/environ`,`GET /health`,`GET` 两个 sidecar `/health`。
|
||||
- **输出**:`PI_AGENT_RUNNER_URL=http://127.0.0.1:18866`;`DATA_DIR=.../data/test`;应用 health `schema_version=78`、`agent_backend=pi-agent`;18866 `data_dir=.../data/test/workspaces`;18865 仍为 `.../data/dev/workspaces`。见 `assets/2026-09-28-pi-runner-env-mismatch/unit-and-runtime.txt`。
|
||||
- **判定**:PASS。
|
||||
- **说明**:新二进制首次启动把 test 库 schema 从 77 升到 78(`00078` 只新增 `error_events`,加法迁移)。这是基线已有迁移随本次二进制生效,不是 runner 修复本身。
|
||||
|
||||
### 用例 2:真实对话推进(与故障同构)
|
||||
|
||||
- **输入**:`POST /api/v1/chat/stream`,`session_id=sess-p5-u32`,`project_id=5`,`message=1`,`client_turn_id=e2e-pi-runner-20260928`。
|
||||
- **输出**:
|
||||
- HTTP 200,`X-Request-Id: req_1790565623110640277`。
|
||||
- 意图 `ADVANCE_STAGE`,分支 `EXPECTATION_HIT`,目标 `V0.5_feasibility`。
|
||||
- 服务器日志三次 `pi runner data_dir check passed`(并行前三步)。
|
||||
- sidecar 工作区全部位于 `data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/...`。
|
||||
- `bd_research` 七步均为 `completed`;`tasks/03_regulatory/output.md` 19851 字节;工作区含 `context/knowledge/hits.md`。
|
||||
- 同名目录在 `data/dev/workspaces` 不存在。
|
||||
- SSE `done.status=completed`,`duration_ms=1046800`。对话流中无 `MISSING_TARGET`、`INTERNAL_ERROR`、`RUNNER_MISMATCH`。
|
||||
- `chat_turns.id=32` 状态 `completed`。
|
||||
- **判定**:PASS(本次缺陷:错配导致的 MISSING_TARGET 未再现,原先失败步骤在 test 工作区成功)。
|
||||
- **耗时**:整段 SSE 1046.8s(03:20:23Z–03:37:49Z)。`step_03_regulatory` 阶段事件耗时 151081ms。
|
||||
|
||||
摘录:`assets/2026-09-28-pi-runner-env-mismatch/sse-phases.txt`、`server-data-dir-check.txt`、`sidecar-workspace-lines.txt`。
|
||||
|
||||
### 用例 3:阶段链在质量门禁处停止(非本次缺陷)
|
||||
|
||||
- **实际**:`bd_research` 质量门禁 100/100 后,`bd_feasibility_dev` 两步执行完成,门禁 85/100,原因「缺少必填章节: 输入摘要」。`classifyStageTaskHalt` 按既有规则停止阶段链,后续 `bd_feasibility_reg`、`bd_user_requirements`、`bd_prelim_design` 未启动。
|
||||
- **对话文案**仍写「已为您成功推进并完成了【V0.5…】」。协调器在 `ExecuteStage` 返回 `err=nil` 时不读取 `Success=false`(`internal/coordinator/engine_stage.go`)。数据库 `projects.id=5` 的 `current_stage` 仍为 `V0.1_triage`。
|
||||
- **判定**:不计入本次修复 FAIL。这是质量门禁停链与成功文案不一致,超出本任务范围(不改 `resolveWorkspace`、不改 phase 归类、不改质量门禁)。
|
||||
|
||||
### 数据质量警示
|
||||
|
||||
2026-09-28 01:40 与 01:56(UTC)两次在错配 runner 下生成的 V0.5 产物未读 test 侧 `context/`。本任务不清洗、不自动重跑,由业务 owner 决定是否作废重做。
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
在 worktree `fix/pi-runner-env-mismatch-2026-09-28` 执行:
|
||||
|
||||
- `go test ./internal/agent/ ./internal/stream/ ./internal/errcode/ -count=1`:三包 `ok`。
|
||||
- `go test -run TestPiAgentRemoteRunner_DataRoot` 与 `TestClassifyError_RunnerDataRootMismatch`:PASS。完整输出见 `assets/2026-09-28-pi-runner-env-mismatch/unit-and-runtime.txt`。
|
||||
|
||||
未跑全仓 `go test`。产品链路以第五节真实 PI 为准,不用 stub。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
本次授权范围内的缺陷已关闭:test 进程连接 `18866`,工作区与 runner `data_dir` 一致,`bd_research` 全步骤(含原 `MISSING_TARGET` 的法规初筛)在 test 工作区成功。
|
||||
|
||||
残留(不在本任务实施):
|
||||
|
||||
- 质量门禁未通过时阶段链停止,但协调器文案仍宣称阶段完成;项目阶段列未更新。
|
||||
- 错配期间已生成的文档需要业务 owner 决定是否重跑。
|
||||
|
||||
五态(收口时填写):review_state=accepted;integration_state 以合入结果为准;deployment=test 环境已用本 worktree 二进制重启(schema 78);cleanup=pending;remote_sync=not_requested。
|
||||
@@ -0,0 +1,77 @@
|
||||
# 质量门禁章节标题漂移 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
dev 项目「吞咽电刺激」调研报告 `research_1790566833205199368` 已生成正文,但 `manifest.json` 的 `quality_report.passed=false`,唯一违规是缺少「技术路线与 State-of-the-Art」。终稿该节实际在 H3,且标题少一个空格。质量失败短路了受控文档投影。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 空格、全角、大小写和 H3/H4 漂移不再被判成缺章,只记层级软警告。
|
||||
- 正文确实没有的模板 H2 仍然失败。
|
||||
- 聊天触发任务带上 `AutoRepair`。
|
||||
- 质量失败的同步回复不声称「已完成生成」。
|
||||
- `arch-check --mode block`、`go vet ./...`、`go test -short ./...` 通过。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- 环境:Linux,worktree `.worktrees/quality-gate-heading-mismatch-2026-09-28`,基线 `434d542c`,修复提交 `aea19f70`、边界补记 `87888213`。
|
||||
- 层级:工程工具 / Go 单测。产品 PI 全链路重跑调研报告不在本报告的工程门禁内,合入并重载 dev 后另验。
|
||||
- 未改前端,不跑 `npm test`。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- `TestQualityGate_Validate_HeadingLevelAndSpaceDrift`:漂移稿通过且评分 100,并含层级软警告;缺「正文」失败。
|
||||
- `TestSyncTriggerTask_EnablesAutoRepair`:`AutoRepair=true`。
|
||||
- `TestFormatTriggerTaskReply_QualityFailedOmitsHostPath`:回复含「质量检查未通过」和违规摘要,不含「已完成生成」。
|
||||
- 短测与 arch-check 退出码 0。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:标题漂移与真实缺章
|
||||
|
||||
- 输入:`go test ./internal/squad/ ./internal/coordinator/ ./internal/bizdev/ -count=1 -timeout 240s`
|
||||
- 实际输出:
|
||||
|
||||
```
|
||||
ok chat-agent-system/internal/squad 0.041s
|
||||
ok chat-agent-system/internal/coordinator 0.015s
|
||||
ok chat-agent-system/internal/bizdev 0.227s
|
||||
```
|
||||
|
||||
- 判定:PASS
|
||||
- 耗时:约 2.5s(含同次 `go vet` 三个包,vet 退出码 0)
|
||||
|
||||
### 用例 2:arch-check
|
||||
|
||||
- 输入:`./scripts/arch-check.sh --mode block`
|
||||
- 第一次实际输出(补允许项之前):`NEW import coordinator internal/coordinator/engine_task.go projectworkflow`,退出码 1。该 import 在基线 `434d542c` 已存在,不是本次功能 diff 引入。
|
||||
- 补记 coordinator 允许依赖 `projectworkflow` 后:
|
||||
|
||||
```
|
||||
ok chat-agent-system/internal/archtest 0.203s
|
||||
ok chat-agent-system/internal/archtest 0.216s
|
||||
arch-check block: production gate passed
|
||||
```
|
||||
|
||||
- 判定:PASS
|
||||
- 耗时:约 0.7s
|
||||
|
||||
### 用例 3:vet 与 short 全量
|
||||
|
||||
- 输入:`go vet ./... && go test -short ./... -count=1 -timeout 20m`
|
||||
- 实际输出:退出码 0。抽查 `internal/squad` `0.038s`、`internal/server` `20.426s`,无 FAIL 行。
|
||||
- 判定:PASS
|
||||
- 耗时:25.2s
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| `go test ./internal/squad/ ./internal/coordinator/ ./internal/bizdev/` | PASS |
|
||||
| `go vet ./...` | PASS |
|
||||
| `./scripts/arch-check.sh --mode block` | PASS(允许项补记后) |
|
||||
| `go test -short ./...` | PASS |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
工程门禁达到本修复的单测交付点。合入 local dev 并重载 dev 制品后,须从项目上下文重跑「吞咽电刺激」调研报告,确认 `project_id>0`、`quality_report.passed=true`,且受控文档 head 更新。双层路径 `data/dev/data/dev` 未修,见 ISSUE-20260928-data-dir-doubled。
|
||||
@@ -0,0 +1,80 @@
|
||||
# 刷新后任务状态恢复 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
刷新页面后,进行中的调研报告进度卡片消失。询问「调研报告编写进度怎么样了」又启动了新的 research 工作区。11:27 的 `step_06_draft` 与 11:38 的并行步骤被记成空输出失败,盘上的 `output.md` 已经有正文。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 进行中的 run 在刷新后仍能回到进度卡片。
|
||||
- 疑问进度句查询真实 run,不新建工作区。
|
||||
- 盘上已有非空正文且不是传输失败时,步骤不再被空结果否决。
|
||||
- 连接错误留下的文件仍然失败关闭。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- OS:Linux。工作树:`.worktrees/refresh-task-state-recovery-2026-09-28`,基线 `4c42d1bf`。
|
||||
- 层级:Go/接口短测、前端单测与构建、架构边界检查。产品 PI 浏览器链路在 dev 重载后另记,本文件先记录已跑命令。
|
||||
- 证据目录:`.doc/test-reports/assets/2026-09-28-refresh-task-state-recovery/`。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- `go vet ./...` 无输出。
|
||||
- 本改动涉及的包 `go test -short` 通过。
|
||||
- `web` 的 `npm test` 与 `npm run build` 通过。
|
||||
- 「调研报告编写进度怎么样了」不是写意图;「开始做调研报告」解析为 research。
|
||||
- 缺交付物但盘上有正文时步骤接受;`Connection error` 且可重试时拒绝。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:意图与进度回复
|
||||
|
||||
- 输入:`go test -short -count=1 ./internal/intent/ ./internal/coordinator/`
|
||||
- 实际输出:两包 `ok`(intent 0.179s,coordinator 0.034s,见 `go-test-short.txt`)。新增用例「调研报告编写进度怎么样了」为 `QUERY_PROGRESS`,「开始做调研报告」为 `research`。
|
||||
- 判定:PASS
|
||||
- 耗时:见短测日志
|
||||
|
||||
### 用例 2:空输出判定与空 patch
|
||||
|
||||
- 输入:`go test -short -count=1 ./internal/squad/ ./internal/agent/`
|
||||
- 实际输出:两包 `ok`(squad 0.041s,agent 2.252s)。连接错误仍失败关闭的既有用例通过。
|
||||
- 判定:PASS
|
||||
|
||||
### 用例 3:锚点、活跃列表、消息映射、重放退避、本地缓存
|
||||
|
||||
- 输入:`go test -short ./internal/taskrun/ ./internal/server/`;`npm test` 中的 `activeTaskCache`、`useRecoveredTaskPhases`、`useChatWindow`、`templateMatch`
|
||||
- 实际输出:taskrun `ok` 0.171s,server `ok` 20.914s。`npm test` 532 通过、vitest 34 通过,`NPM_TEST:0`。
|
||||
- 判定:PASS
|
||||
|
||||
### 用例 4:全量短测与架构边界
|
||||
|
||||
- 输入:`go vet ./...`;`go test -short -count=1 ./...`;`./scripts/arch-check.sh --mode block`
|
||||
- 实际输出:`VET:0`。短测唯一失败是 `internal/archtest`:`NEW import coordinator internal/coordinator/engine_task.go projectworkflow`。该文件相对基线 `4c42d1bf` 的 diff 为 0,导入来自已合入的 `agent-reply-llm-narrative`,不是本任务新增。`ARCH:1` 与之相同。
|
||||
- 判定:本任务包 PASS;架构边界 FAIL 记为基线既有项,本任务未改该导入
|
||||
|
||||
### 用例 5:前端构建
|
||||
|
||||
- 输入:`npm run build`
|
||||
- 实际输出:`NPM_BUILD:0`,precompress 写出 66 个 br/gz。
|
||||
- 判定:PASS
|
||||
|
||||
### 用例 6:dev 浏览器与真实 PI Runner
|
||||
|
||||
- 输入:发起调研报告,执行中刷新,完成后刷新,再问编写进度。
|
||||
- 实际输出:本段写入时尚未在已加载新代码的 dev 上运行。
|
||||
- 判定:未运行
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| go vet ./... | PASS(VET:0) |
|
||||
| go test -short ./... | 除既有 archtest 外 PASS |
|
||||
| arch-check --mode block | FAIL(基线既有 coordinator→projectworkflow) |
|
||||
| npm test | PASS(532 + 34) |
|
||||
| npm run build | PASS |
|
||||
| dev 浏览器 + 真实 PI | 未运行 |
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
实现与单测、前端构建已通过。交付终点还差:把候选合入 local dev、重载服务后,用真实 PI Runner 走刷新恢复和进度问句。架构边界失败不由本 diff 引入,不在本 mutex 里改 `engine_task.go`。
|
||||
@@ -0,0 +1,96 @@
|
||||
# 第三方 test 用户文档问题 测试报告
|
||||
|
||||
## 一、 测试背景 (Background)
|
||||
|
||||
第三方用户在 test 环境整理了《AI 测试问题》。只上传附件被空消息拒绝已由 ISSUE-20260928-attachment-only-turn 修复。本轮处理另外两类:
|
||||
|
||||
- 「帮我定设计开发计划任务书」没有进入任务,对话是掂量阶段模板。
|
||||
- 「帮我生成报价单」气泡写成正文已保存到宿主机路径,工作区实际是质量未通过的阻塞说明。根因是 PI runner 数据目录错配,已由 `4f581306` 合入 local dev。
|
||||
|
||||
主记录:[2026-09-28-test-user-doc-issues](../ops/short-term/2026-09-28-test-user-doc-issues.md)。
|
||||
|
||||
## 二、 测试目标 (Test Objectives)
|
||||
|
||||
- 「帮我定设计开发计划任务书」在商务流激活时进入任务,并带出研发流澄清;「决定」不触发编写。
|
||||
- 研发前置未满足时,用户看到中文原因,而不是协调失败。
|
||||
- 质量未通过的同步回复使用质量摘要,不写宿主机路径,不声称正文已保存。
|
||||
- 核对 test 进程是否已经指向本环境 runner 与 `data/test`。
|
||||
|
||||
## 三、 测试方案与环境 (Test Plan & Environment)
|
||||
|
||||
- 源码:worktree `.worktrees/test-user-doc-issues-2026-09-28`,提交 `db859e185ebcd0e7eccd2241ca07f0e9f4fe4c6b`,基线 `8f77053f`。
|
||||
- 命令:`go test ./internal/intent/ ./internal/coordinator/ -count=1 -timeout 180s`,以及 `-run` 聚焦用例;`go vet` 同两包。
|
||||
- test 运行制品:`bin/agent-server-test` 修改时间 2026-09-28 04:04:03 +0000,主目录 `HEAD` `193a752f`(含 `4f581306`)。进程 pid `1450126`,`ENV=test`,`DATA_DIR=.../data/test`,`PI_AGENT_RUNNER_URL=http://127.0.0.1:18866`。18866 的 `data_dir` 为 `data/test/workspaces`。本提交的回复文案尚未打进该二进制。
|
||||
- 未用第三方账号再跑「生成报价单」。该操作会写入其项目;本会话没有登录凭证。runner 数据目录的产品链路证据见 [PI runner 环境错配报告](./2026-09-28-pi-runner-env-mismatch-test-report.md) 的 `bd_research` 实测。竞品视频未发现独立处理缺陷,未扩测。
|
||||
|
||||
## 四、 预期结果 (Expected Results)
|
||||
|
||||
- 「帮我定设计开发计划任务书」+ 激活 `main`:`TRIGGER_TASK`,工作流范围不匹配,澄清含研发设计控制流程,`RequiresClarifying`。
|
||||
- 激活 `rdev` 时「帮我制定…」命中 `rd_design_plan` 且不拦截。
|
||||
- 「我决定先放一放,再看看进展」不是 `TRIGGER_TASK`。
|
||||
- 质量失败回复不含「正文已保存」和 `output.md` 绝对路径。
|
||||
- 前置未满足回复含「请先完成商务对接流程」,错误值为空。
|
||||
- 已完成回复仍含「正文已保存。」
|
||||
- test 进程 runner 为 18866,数据目录为 test。
|
||||
|
||||
## 五、 实际测试结果与判定 (Actual Results & Evaluation)
|
||||
|
||||
### 用例 1:帮我定 + 商务流
|
||||
|
||||
- **输入**:`TestWriteVerb_DingDesignPlanCrossFlow`
|
||||
- **实际输出**:`intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86`,`PASS`
|
||||
- **判定**:PASS
|
||||
- **耗时**:包内 <0.01s
|
||||
|
||||
### 用例 2:制定 + 研发流
|
||||
|
||||
- **输入**:`TestWriteVerb_ZhidingDesignPlanOnRdev`
|
||||
- **实际输出**:同上 `TRIGGER_TASK`,`PASS`(断言任务键 `rd_design_plan` 且无范围拦截)
|
||||
- **判定**:PASS
|
||||
|
||||
### 用例 3:决定不是编写
|
||||
|
||||
- **输入**:`TestWriteVerb_DecideIsNotWrite`
|
||||
- **实际输出**:`QUERY_PROGRESS` / `CASUAL_CHAT`,无 `TRIGGER_TASK`,`PASS`
|
||||
- **判定**:PASS
|
||||
|
||||
### 用例 4:质量失败文案
|
||||
|
||||
- **输入**:`TestFormatTriggerTaskReply_QualityFailedOmitsHostPath`
|
||||
- **实际输出**:`PASS`(回复走质量摘要,不含宿主机路径)
|
||||
- **判定**:PASS
|
||||
|
||||
### 用例 5:前置条件可见
|
||||
|
||||
- **输入**:`TestSyncTriggerTask_PrerequisiteIsUserVisible`
|
||||
- **实际输出**:`PASS`
|
||||
- **判定**:PASS
|
||||
|
||||
### 用例 6:成功文案仍保留「正文已保存。」
|
||||
|
||||
- **输入**:`TestSyncTriggerTask_Committed_KeepsSavedWording`
|
||||
- **实际输出**:`PASS`
|
||||
- **判定**:PASS
|
||||
|
||||
### 用例 7:test 进程 runner 指向
|
||||
|
||||
- **输入**:读 pid `1450126` 的 `ENV`、`DATA_DIR`、`PI_AGENT_RUNNER_URL`;`GET` 18866 与 8081 `/health`;在二进制中查找 `RUNNER_MISMATCH` 用户文案。
|
||||
- **实际输出**:`ENV=test`;`DATA_DIR=/home/weichen/projects/Agent-System/./data/test`;`PI_AGENT_RUNNER_URL=http://127.0.0.1:18866`;18866 `data_dir=/home/weichen/projects/Agent-System/data/test/workspaces`;health `schema_version=78` `agent_backend=pi-agent`;二进制含「模型执行环境与数据目录不一致」。
|
||||
- **判定**:PASS(runner 接线)。报价单全链路本轮未运行。
|
||||
- **耗时**:健康检查 <1s。
|
||||
|
||||
日志:`.doc/test-reports/assets/2026-09-28-test-user-doc-issues/go-test-focused.txt`、`go-test-packages.txt`、`go-vet.txt`。
|
||||
|
||||
## 六、 自动化测试套件汇总 (Test Suite Execution)
|
||||
|
||||
| 命令 | 结果 |
|
||||
|---|---|
|
||||
| `go test ./internal/intent/ ./internal/coordinator/ -count=1 -timeout 180s` | PASS(intent 0.078s,coordinator 0.015s) |
|
||||
| 聚焦 `-run 'TestWriteVerb_\|TestFormatTriggerTaskReply_QualityFailed\|TestSyncTriggerTask_Prerequisite\|TestSyncTriggerTask_Committed_KeepsSavedWording'` | PASS |
|
||||
| `go vet ./internal/intent/ ./internal/coordinator/` | 无输出,退出码 0 |
|
||||
|
||||
未跑全量 `go test ./...`,也未跑 nightly 五项。本变更不改运行模板。材料嵌入超限(约 34635 tokens,模型上限 8192)只登记 ISSUE-20260928-material-chunk-embed,未测修复。
|
||||
|
||||
## 七、 测试结论与后续优化建议 (Conclusion & Next Steps)
|
||||
|
||||
意图动词、澄清透传、前置可见、质量失败文案由单测覆盖,达到本任务的代码验收。test 当前制品已指向本环境 runner,runner 错配修复在 dev `193a752f`。本提交的回复文案还没进 `bin/agent-server-test`。报价单没有在本轮用第三方项目重跑。嵌入分块超限仍开放。
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 56 KiB |
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"username": "pwreset_probe_mukj4wsy",
|
||||
"log": [
|
||||
{
|
||||
"step": "admin_api_login",
|
||||
"ok": true,
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"step": "admin_create_probe_user",
|
||||
"ok": true,
|
||||
"status": 200,
|
||||
"username": "pwreset_probe_mukj4wsy",
|
||||
"user_id": 77
|
||||
},
|
||||
{
|
||||
"step": "probe_initial_login_must_change",
|
||||
"ok": true,
|
||||
"status": 200,
|
||||
"must_change_password": true
|
||||
},
|
||||
{
|
||||
"step": "probe_clear_initial_must_change",
|
||||
"ok": true,
|
||||
"status": 200
|
||||
},
|
||||
{
|
||||
"step": "probe_settled_login_no_force",
|
||||
"ok": true,
|
||||
"status": 200,
|
||||
"must_change_password": false
|
||||
},
|
||||
{
|
||||
"step": "ui_admin_login",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"step": "ui_reset_button_visible",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"step": "ui_confirm_reset",
|
||||
"ok": true,
|
||||
"message": "确定要重置【重置探针】的密码吗?系统将生成一次性临时口令,该用户下次登录将被强制改密。临时口令仅展示一次。"
|
||||
},
|
||||
{
|
||||
"step": "ui_prompt_temp_password",
|
||||
"ok": true,
|
||||
"length": 16
|
||||
},
|
||||
{
|
||||
"step": "ui_reset_success_toast",
|
||||
"ok": true,
|
||||
"temp_len": 16
|
||||
},
|
||||
{
|
||||
"step": "ui_force_change_modal",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"step": "ui_entered_after_change",
|
||||
"ok": true
|
||||
},
|
||||
{
|
||||
"step": "ui_second_login_no_force_modal",
|
||||
"ok": true,
|
||||
"modal_count": 0
|
||||
},
|
||||
{
|
||||
"step": "old_settled_password_rejected",
|
||||
"ok": true,
|
||||
"status": 401
|
||||
},
|
||||
{
|
||||
"step": "probe_user_disabled",
|
||||
"ok": true,
|
||||
"status": 200,
|
||||
"user_id": 77
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 241 KiB |
@@ -0,0 +1,16 @@
|
||||
dev 复验摘录(2026-09-28,二进制 bin/agent-server 重建于 10:22 +0800,pid 1002830,/health schema_version=78)
|
||||
|
||||
API 仅附件、parse_state=pending:HTTP 200,约 11.6s
|
||||
《F-030-verify.pdf》仍在解析中,请稍后再试总结。
|
||||
解析完成后直接回复「总结」,我会给出结构化梳理和初步审阅,并问你下一步要不要据此修订文档。
|
||||
GET turn:200 completed
|
||||
|
||||
API 双空:HTTP 400,error=message cannot be empty;turn 未创建(404)
|
||||
|
||||
API 无关文字+附件:HTTP 200,约 17s
|
||||
先回答天气,再追加:另外已收到《F-030-verify.pdf》。这条消息没有要求总结或依据文档编写。需要我总结,或据此更新对应文档吗?
|
||||
|
||||
浏览器 http://127.0.0.1:3100(与 frp :58880 同一 Vite):
|
||||
- 仅附件发送按钮可用;用户气泡为「已上传文档:《F-030-verify.pdf》」;助手给出结构化梳理、初步审阅与 1/2/3 下一步。chat/stream 200。
|
||||
- 无文字且无附件:发送按钮保持禁用。
|
||||
- 文字「今天天气怎么样」+同一 PDF:先回复天气,再出现「另外已收到《F-030-verify.pdf》…」。chat/stream 200。
|
||||
@@ -0,0 +1,20 @@
|
||||
=== RUN TestIsUsernameConflict
|
||||
=== RUN TestIsUsernameConflict/username_index
|
||||
=== RUN TestIsUsernameConflict/account_id
|
||||
=== RUN TestIsUsernameConflict/username_key
|
||||
=== RUN TestIsUsernameConflict/fk_is_not_username
|
||||
=== RUN TestIsUsernameConflict/other_unique
|
||||
=== RUN TestIsUsernameConflict/plain_error
|
||||
--- PASS: TestIsUsernameConflict (0.00s)
|
||||
--- PASS: TestIsUsernameConflict/username_index (0.00s)
|
||||
--- PASS: TestIsUsernameConflict/account_id (0.00s)
|
||||
--- PASS: TestIsUsernameConflict/username_key (0.00s)
|
||||
--- PASS: TestIsUsernameConflict/fk_is_not_username (0.00s)
|
||||
--- PASS: TestIsUsernameConflict/other_unique (0.00s)
|
||||
--- PASS: TestIsUsernameConflict/plain_error (0.00s)
|
||||
=== RUN TestErrUsernameExistsIsNotInfrastructureShaped
|
||||
--- PASS: TestErrUsernameExistsIsNotInfrastructureShaped (0.00s)
|
||||
=== RUN TestMemoryStore_DevEnvSeedsDemoUsers
|
||||
--- PASS: TestMemoryStore_DevEnvSeedsDemoUsers (0.08s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/auth 0.087s
|
||||
@@ -0,0 +1,8 @@
|
||||
=== RUN TestAuthHandlers_RegisterAndApproval
|
||||
time=2026-09-28T01:11:09.621Z level=INFO msg="[kb] offline=true reason=empty_kb_db_password detail=config: KB_DB_PASSWORD is empty; provide it in root .env (layered with configs/.env.{ENV}) or process environment"
|
||||
--- PASS: TestAuthHandlers_RegisterAndApproval (0.17s)
|
||||
=== RUN TestAuthHandlers_RegisterDuplicateUsername
|
||||
time=2026-09-28T01:11:09.792Z level=INFO msg="[kb] offline=true reason=empty_kb_db_password detail=config: KB_DB_PASSWORD is empty; provide it in root .env (layered with configs/.env.{ENV}) or process environment"
|
||||
--- PASS: TestAuthHandlers_RegisterDuplicateUsername (0.17s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 0.349s
|
||||
@@ -0,0 +1 @@
|
||||
{"status":"active","message":"注册成功,已激活,请返回登录","user_id":43}
|
||||
@@ -0,0 +1,3 @@
|
||||
40:{"time":"2026-09-28T03:20:25.737217126Z","level":"INFO","msg":"pi runner data_dir check passed"}
|
||||
41:{"time":"2026-09-28T03:20:25.737493268Z","level":"INFO","msg":"pi runner data_dir check passed"}
|
||||
42:{"time":"2026-09-28T03:20:25.738223226Z","level":"INFO","msg":"pi runner data_dir check passed"}
|
||||
@@ -0,0 +1,9 @@
|
||||
13:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/02_market, model: MiniMax-M2.7-highspeed
|
||||
14:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/03_regulatory, model: MiniMax-M2.7-highspeed
|
||||
15:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/01_search, model: MiniMax-M2.7-highspeed
|
||||
16:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/04_plan, model: MiniMax-M2.7-highspeed
|
||||
17:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/05_review_plan, model: MiniMax-M2.7-highspeed
|
||||
18:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/06_draft, model: MiniMax-M2.7-highspeed
|
||||
19:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_research/tasks/07_review, model: MiniMax-M2.7-highspeed
|
||||
20:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_feasibility_dev/tasks/01_draft, model: MiniMax-M2.7-highspeed
|
||||
21:[runner] Starting pi run in workspace: /home/weichen/projects/Agent-System/data/test/workspaces/bizdev/stage_V0.5_feasibility_1790565623120057798/bd_feasibility_dev/tasks/02_review, model: MiniMax-M2.7-highspeed
|
||||
@@ -0,0 +1,107 @@
|
||||
event: phase
|
||||
data: {"id":"evt_1790565623115044567_1","type":"phase","timestamp":"2026-09-28T03:20:23.115046566Z","phase":{"phase_id":"intent_recognizing","message":"正在研判您的意图与项目上下文...","role":"coordinator"}}
|
||||
|
||||
event: turn_ack
|
||||
data: {"id":"evt_1790565623118588251_2","type":"turn_ack","timestamp":"2026-09-28T03:20:23.118589961Z","turn":{"client_turn_id":"e2e-pi-runner-20260928","user_message_id":95,"status":"processing"}}
|
||||
|
||||
event: status
|
||||
data: {"id":"evt_1790565623119470725_3","type":"status","timestamp":"2026-09-28T03:20:23.119471465Z","status":{"intent":"ADVANCE_STAGE","branch":"EXPECTATION_HIT","current_stage":"V0.1_triage","patches":{"target_stage":"V0.5_feasibility"},"message":"识别分支: EXPECTATION_HIT (置信度: 98%)"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565623119857514_4","type":"phase","timestamp":"2026-09-28T03:20:23.119859693Z","phase":{"phase_id":"dialogue_generating","message":"正在整理回复...","role":"assistant","progress":40}}
|
||||
|
||||
event: status
|
||||
data: {"id":"evt_1790565623119924622_5","type":"status","timestamp":"2026-09-28T03:20:23.119925612Z","status":{"intent":"ADVANCE_STAGE","branch":"EXPECTATION_HIT","current_stage":"V0.1_triage","patches":{"target_stage":"V0.5_feasibility"},"message":"意图判定: ADVANCE_STAGE (置信度: 98%)"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565623120033928_6","type":"phase","timestamp":"2026-09-28T03:20:23.120034458Z","phase":{"phase_id":"stage_transition","message":"准备推进项目成熟度阶段至【V0.5_feasibility】...","role":"coordinator"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565623120257272_7","type":"phase","timestamp":"2026-09-28T03:20:23.120257652Z","phase":{"phase_id":"stage_started","message":"开始推进商务成熟度阶段【V0.5_feasibility】(包含 5 项任务序列)...","role":"coordinator","total_steps":5,"progress":5}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565623120306040_8","type":"phase","timestamp":"2026-09-28T03:20:23.12030643Z","phase":{"phase_id":"knowledge_retrieval","message":"项目助手正在检索权威法规知识库并筛选适用条款(关键词: 医疗器械研发项目)...","role":"regulatory","progress":10}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565625734830247_9","type":"phase","timestamp":"2026-09-28T03:20:25.734831767Z","phase":{"phase_id":"knowledge_retrieved","message":"法规知识库初筛完成,精准命中 5 条国家与行业标准条款","role":"regulatory","progress":15}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565625736184437_10","type":"phase","timestamp":"2026-09-28T03:20:25.736184847Z","phase":{"phase_id":"squad_assembly","message":"正在组建并启动【调研报告】智能体小队(后端: pi-agent)...","role":"leader","progress":5}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565625736408330_11","type":"phase","timestamp":"2026-09-28T03:20:25.73640907Z","phase":{"phase_id":"step_executing","message":"法规专员正在进行:医疗器械法规与指导原则初筛...","role":"regulatory"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565625736428550_13","type":"phase","timestamp":"2026-09-28T03:20:25.73642911Z","phase":{"phase_id":"step_executing","message":"市场情报专员正在进行:市场格局与竞品同维度对比...","role":"market"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565625736413970_12","type":"phase","timestamp":"2026-09-28T03:20:25.7364153Z","phase":{"phase_id":"step_executing","message":"资料检索专员正在进行:公开资料与标准检索...","role":"searcher"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565769142850003_14","type":"phase","timestamp":"2026-09-28T03:22:49.142850863Z","phase":{"phase_id":"step_completed","message":"市场情报专员完成任务:市场格局与竞品同维度对比 (耗时 143404ms)","role":"market"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565776819693644_15","type":"phase","timestamp":"2026-09-28T03:22:56.819694444Z","phase":{"phase_id":"step_completed","message":"法规专员完成任务:医疗器械法规与指导原则初筛 (耗时 151081ms)","role":"regulatory"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565786074672686_16","type":"phase","timestamp":"2026-09-28T03:23:06.074673966Z","phase":{"phase_id":"step_completed","message":"资料检索专员完成任务:公开资料与标准检索 (耗时 160336ms)","role":"searcher"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565786075423684_17","type":"phase","timestamp":"2026-09-28T03:23:06.075424624Z","phase":{"phase_id":"step_executing","message":"撰写专员正在进行:撰写调研报告段落计划...","role":"writer"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565909928606231_18","type":"phase","timestamp":"2026-09-28T03:25:09.928610311Z","phase":{"phase_id":"step_completed","message":"撰写专员完成任务:撰写调研报告段落计划 (耗时 123852ms)","role":"writer"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790565909928909502_19","type":"phase","timestamp":"2026-09-28T03:25:09.928910012Z","phase":{"phase_id":"step_executing","message":"审核主管正在进行:审核调研报告撰写计划...","role":"leader"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566029437296969_20","type":"phase","timestamp":"2026-09-28T03:27:09.437297799Z","phase":{"phase_id":"step_completed","message":"审核主管完成任务:审核调研报告撰写计划 (耗时 119506ms)","role":"leader"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566029437606029_21","type":"phase","timestamp":"2026-09-28T03:27:09.437606359Z","phase":{"phase_id":"step_executing","message":"撰写专员正在进行:按计划合成调研报告正文...","role":"writer"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566212844798701_22","type":"phase","timestamp":"2026-09-28T03:30:12.844803911Z","phase":{"phase_id":"step_completed","message":"撰写专员完成任务:按计划合成调研报告正文 (耗时 183406ms)","role":"writer"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566212845147631_23","type":"phase","timestamp":"2026-09-28T03:30:12.845148571Z","phase":{"phase_id":"step_executing","message":"审核主管正在进行:终审并定稿...","role":"leader"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566364912367169_24","type":"phase","timestamp":"2026-09-28T03:32:44.912367969Z","phase":{"phase_id":"step_completed","message":"审核主管完成任务:终审并定稿 (耗时 152064ms)","role":"leader"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566364912870564_25","type":"phase","timestamp":"2026-09-28T03:32:44.912871504Z","phase":{"phase_id":"quality_gate","message":"审核主管正在核验交付物规范并执行质量门禁把关...","role":"leader","progress":85}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566364913381949_26","type":"phase","timestamp":"2026-09-28T03:32:44.913382489Z","phase":{"phase_id":"quality_gate","message":"质量门禁审核通过(评分: 100.0 / 100)","role":"leader","progress":95}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566364914441848_28","type":"phase","timestamp":"2026-09-28T03:32:44.914442348Z","phase":{"phase_id":"advisor_briefing","message":"贴身业务参谋正在提炼关键决策摘要与风险雷达...","role":"coordinator","progress":98}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566364915348721_31","type":"phase","timestamp":"2026-09-28T03:32:44.915349271Z","phase":{"phase_id":"squad_assembly","message":"正在组建并启动【设计开发可行性评估报告】智能体小队(后端: pi-agent)...","role":"leader","progress":5}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566364915498706_32","type":"phase","timestamp":"2026-09-28T03:32:44.915499226Z","phase":{"phase_id":"step_executing","message":"撰写专员正在进行:撰写初稿...","role":"writer"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566494739847744_33","type":"phase","timestamp":"2026-09-28T03:34:54.739848934Z","phase":{"phase_id":"step_completed","message":"撰写专员完成任务:撰写初稿 (耗时 129822ms)","role":"writer"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566494740139705_34","type":"phase","timestamp":"2026-09-28T03:34:54.740140415Z","phase":{"phase_id":"step_executing","message":"审核主管正在进行:审核定稿...","role":"leader"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566669911651657_35","type":"phase","timestamp":"2026-09-28T03:37:49.911652837Z","phase":{"phase_id":"step_completed","message":"审核主管完成任务:审核定稿 (耗时 175167ms)","role":"leader"}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566669912136492_36","type":"phase","timestamp":"2026-09-28T03:37:49.912137252Z","phase":{"phase_id":"quality_gate","message":"审核主管正在核验交付物规范并执行质量门禁把关...","role":"leader","progress":85}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566669912488342_37","type":"phase","timestamp":"2026-09-28T03:37:49.912488672Z","phase":{"phase_id":"quality_gate","message":"质量门禁未通过(评分: 85.0 / 100):缺少必填章节: 输入摘要","role":"leader","progress":95}}
|
||||
|
||||
event: phase
|
||||
data: {"id":"evt_1790566669912824672_39","type":"phase","timestamp":"2026-09-28T03:37:49.912824872Z","phase":{"phase_id":"advisor_briefing","message":"贴身业务参谋正在提炼关键决策摘要与风险雷达...","role":"coordinator","progress":98}}
|
||||
|
||||
event: done
|
||||
data: {"id":"evt_1790566669915344077_43","type":"done","timestamp":"2026-09-28T03:37:49.915344407Z","done":{"session_id":"sess-p5-u32","client_turn_id":"e2e-pi-runner-20260928","duration_ms":1046800,"total_events":42,"user_message_id":95,"message_id":99,"status":"completed","content_revision":1,"content_sha256":"97614c72ccb9eb2a8ef3794bf84a10aee429b53e73dee16b629c311aa3f3722e","export_capability":{"policy":"full","formats":["rich_clipboard","markdown","docx","pdf","private_document"],"body_selector":"content_only","content_revision":1,"content_sha256":"97614c72ccb9eb2a8ef3794bf84a10aee429b53e73dee16b629c311aa3f3722e"}}}
|
||||
@@ -0,0 +1,33 @@
|
||||
# 2026-09-28 worktree go test(新增用例)
|
||||
|
||||
=== RUN TestPiAgentRemoteRunner_DataRootMismatchSkipsRun
|
||||
2026/09/28 03:41:20 pi runner data_dir check passed
|
||||
2026/09/28 03:41:20 pi runner data root mismatch; refusing /v1/run
|
||||
--- PASS: TestPiAgentRemoteRunner_DataRootMismatchSkipsRun (0.00s)
|
||||
=== RUN TestPiAgentRemoteRunner_DataRootMatchStillRuns
|
||||
2026/09/28 03:41:20 pi runner data_dir check passed
|
||||
--- PASS: TestPiAgentRemoteRunner_DataRootMatchStillRuns (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/agent 0.004s
|
||||
|
||||
=== RUN TestClassifyError_RunnerDataRootMismatch
|
||||
--- PASS: TestClassifyError_RunnerDataRootMismatch (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
|
||||
# 同目录包回归
|
||||
ok chat-agent-system/internal/agent 3.663s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/errcode 0.003s
|
||||
|
||||
# test 进程(pid 1222963,监听 8081)environ 摘录
|
||||
ENV=test
|
||||
DATA_DIR=/home/weichen/projects/Agent-System/data/test
|
||||
PI_AGENT_RUNNER_URL=http://127.0.0.1:18866
|
||||
|
||||
# GET /health
|
||||
{"status":"ok","env":"test","agent_backend":"pi-agent","schema_version":78,"schema_ready":true}
|
||||
|
||||
# runner /health data_dir
|
||||
18866 data_dir=/home/weichen/projects/Agent-System/data/test/workspaces
|
||||
18865 data_dir=/home/weichen/projects/Agent-System/data/dev/workspaces
|
||||
@@ -0,0 +1,16 @@
|
||||
arch-check mode=block
|
||||
boundaries=/home/weichen/projects/Agent-System/.worktrees/refresh-task-state-recovery-2026-09-28/.doc/system-design/module-boundaries.yaml
|
||||
--- FAIL: TestArchitectureBoundaries (0.19s)
|
||||
arch_test.go:32: archtest findings=1 excepted=0 unmatched=1
|
||||
import=1
|
||||
sql_write=0
|
||||
path=0
|
||||
event=0
|
||||
REGRESSION import: 1 > baseline 0
|
||||
NEW import coordinator internal/coordinator/engine_task.go projectworkflow (production import coordinator -> projectworkflow)
|
||||
|
||||
FAIL
|
||||
FAIL chat-agent-system/internal/archtest 0.195s
|
||||
FAIL
|
||||
arch-check: new, expired, or unowned findings failed go test ./internal/archtest
|
||||
ARCH:1
|
||||
@@ -0,0 +1,99 @@
|
||||
? chat-agent-system/cmd/artifact-vault [no test files]
|
||||
ok chat-agent-system/cmd/bizdev-cli 2.985s
|
||||
? 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/maintpage [no test files]
|
||||
? chat-agent-system/cmd/recategorize [no test files]
|
||||
ok chat-agent-system/cmd/server 0.012s
|
||||
ok chat-agent-system/internal/agent 2.252s
|
||||
ok chat-agent-system/internal/agentx 0.023s
|
||||
ok chat-agent-system/internal/agentx/abtest 0.004s
|
||||
ok chat-agent-system/internal/agentx/llm 0.024s
|
||||
ok chat-agent-system/internal/agentx/session 0.008s
|
||||
ok chat-agent-system/internal/agentx/tools 0.006s
|
||||
ok chat-agent-system/internal/app 0.046s
|
||||
ok chat-agent-system/internal/app/chatflow 0.018s
|
||||
ok chat-agent-system/internal/app/docadvance 0.015s
|
||||
ok chat-agent-system/internal/app/docflow 0.009s
|
||||
ok chat-agent-system/internal/app/docnotify 0.005s
|
||||
ok chat-agent-system/internal/app/docproject 0.003s
|
||||
? chat-agent-system/internal/app/eventsconsumer [no test files]
|
||||
ok chat-agent-system/internal/app/fav 0.007s
|
||||
ok chat-agent-system/internal/app/intentflow 0.088s
|
||||
ok chat-agent-system/internal/app/stageflow 0.010s
|
||||
ok chat-agent-system/internal/app/uow 0.005s
|
||||
--- FAIL: TestArchitectureBoundaries (0.50s)
|
||||
arch_test.go:32: archtest findings=1 excepted=0 unmatched=1
|
||||
import=1
|
||||
sql_write=0
|
||||
path=0
|
||||
event=0
|
||||
REGRESSION import: 1 > baseline 0
|
||||
NEW import coordinator internal/coordinator/engine_task.go projectworkflow (production import coordinator -> projectworkflow)
|
||||
|
||||
FAIL
|
||||
FAIL chat-agent-system/internal/archtest 0.507s
|
||||
ok chat-agent-system/internal/artifactvault 0.005s
|
||||
ok chat-agent-system/internal/auth 1.494s
|
||||
ok chat-agent-system/internal/authz 0.007s
|
||||
ok chat-agent-system/internal/bizdev 0.418s
|
||||
ok chat-agent-system/internal/chat 0.067s
|
||||
ok chat-agent-system/internal/config 0.009s
|
||||
ok chat-agent-system/internal/conflictresolve 0.006s
|
||||
? chat-agent-system/internal/contracts/vocabulary [no test files]
|
||||
ok chat-agent-system/internal/coordinator 0.034s
|
||||
ok chat-agent-system/internal/ctxmgr 0.174s
|
||||
ok chat-agent-system/internal/dataset 0.010s
|
||||
ok chat-agent-system/internal/db 0.007s
|
||||
ok chat-agent-system/internal/dialoguectx 0.007s
|
||||
ok chat-agent-system/internal/doccontent 0.004s
|
||||
ok chat-agent-system/internal/docduty 0.004s
|
||||
ok chat-agent-system/internal/docgov 0.006s
|
||||
ok chat-agent-system/internal/docquery 0.004s
|
||||
ok chat-agent-system/internal/docrevision 0.017s
|
||||
ok chat-agent-system/internal/errcode 0.007s
|
||||
ok chat-agent-system/internal/errorevents 0.008s
|
||||
ok chat-agent-system/internal/events 0.012s
|
||||
ok chat-agent-system/internal/freedoc 0.035s
|
||||
ok chat-agent-system/internal/fsutil 0.005s
|
||||
ok chat-agent-system/internal/handoff 0.008s
|
||||
ok chat-agent-system/internal/httpx 0.004s
|
||||
ok chat-agent-system/internal/intent 0.179s
|
||||
ok chat-agent-system/internal/jevdecide 0.274s
|
||||
ok chat-agent-system/internal/kb 0.013s
|
||||
ok chat-agent-system/internal/localpg 0.598s
|
||||
ok chat-agent-system/internal/maintenance 0.005s
|
||||
ok chat-agent-system/internal/materialindex 0.007s
|
||||
ok chat-agent-system/internal/maturity 0.007s
|
||||
ok chat-agent-system/internal/mineru 3.008s
|
||||
ok chat-agent-system/internal/notification 0.005s
|
||||
? chat-agent-system/internal/observability [no test files]
|
||||
ok chat-agent-system/internal/projectcontext 0.005s
|
||||
ok chat-agent-system/internal/projectinstance 0.010s
|
||||
ok chat-agent-system/internal/projectworkflow 0.003s
|
||||
ok chat-agent-system/internal/quote 0.012s
|
||||
ok chat-agent-system/internal/replyexport 0.002s
|
||||
ok chat-agent-system/internal/server 20.914s
|
||||
ok chat-agent-system/internal/squad 0.041s
|
||||
ok chat-agent-system/internal/storage 0.003s
|
||||
ok chat-agent-system/internal/stream 0.003s
|
||||
ok chat-agent-system/internal/stream/transport 0.003s
|
||||
ok chat-agent-system/internal/supplementimpact 0.003s
|
||||
ok chat-agent-system/internal/swboot 0.070s
|
||||
ok chat-agent-system/internal/sysadmin 0.003s
|
||||
ok chat-agent-system/internal/taskrun 0.171s
|
||||
ok chat-agent-system/internal/template 1.059s
|
||||
ok chat-agent-system/internal/traceimpact 0.003s
|
||||
ok chat-agent-system/internal/upload 0.002s
|
||||
? chat-agent-system/internal/workflow [no test files]
|
||||
ok chat-agent-system/internal/workflow/runtime 0.004s
|
||||
ok chat-agent-system/internal/workflowdef 0.004s
|
||||
ok chat-agent-system/internal/workflowscope 0.002s
|
||||
ok chat-agent-system/internal/workspace 0.003s
|
||||
? chat-agent-system/templates [no test files]
|
||||
? chat-agent-system/web [no test files]
|
||||
FAIL
|
||||
TEST:1
|
||||
@@ -0,0 +1 @@
|
||||
VET:0
|
||||
@@ -0,0 +1,291 @@
|
||||
|
||||
> shuimu-workbench@1.0.0 build
|
||||
> tsc && vite build && node scripts/precompress-dist.mjs
|
||||
|
||||
vite v7.3.6 building client environment for production...
|
||||
transforming...
|
||||
✓ 4169 modules transformed.
|
||||
rendering chunks...
|
||||
computing gzip size...
|
||||
dist/index.html 0.72 kB │ gzip: 0.45 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-Bq7tVxen.css 6.58 kB │ gzip: 1.99 kB
|
||||
dist/assets/katex-BOvhZl6_.css 30.25 kB │ gzip: 8.09 kB
|
||||
dist/assets/channel-DHR9WBLM.js 0.12 kB │ gzip: 0.13 kB
|
||||
dist/assets/katexRender-DyvI-2y4.js 0.15 kB │ gzip: 0.15 kB
|
||||
dist/assets/init-Gi6I4Gst.js 0.15 kB │ gzip: 0.13 kB
|
||||
dist/assets/chunk-2Q5K7J3B-CHsI7zem.js 0.19 kB │ gzip: 0.16 kB
|
||||
dist/assets/chunk-JWPE2WC7-CeOXuZlw.js 0.23 kB │ gzip: 0.17 kB
|
||||
dist/assets/chunk-XXDRQBXY-Cu_mBr7x.js 0.23 kB │ gzip: 0.21 kB
|
||||
dist/assets/git-branch-D2R7ViCv.js 0.26 kB │ gzip: 0.21 kB
|
||||
dist/assets/chunk-5VM5RSS4-lzTX0tjp.js 0.37 kB │ gzip: 0.27 kB
|
||||
dist/assets/stateDiagram-v2-MP3YSRHH-dJKbyi-1.js 0.43 kB │ gzip: 0.30 kB
|
||||
dist/assets/classDiagram-ZZMXUADV-CTPa2PBn.js 0.47 kB │ gzip: 0.32 kB
|
||||
dist/assets/classDiagram-v2-VYDZK3BY-CTPa2PBn.js 0.47 kB │ gzip: 0.32 kB
|
||||
dist/assets/chunk-POPQ4Y6H-B2jpZUkp.js 0.51 kB │ gzip: 0.36 kB
|
||||
dist/assets/swimlanesDiagram-VR7AAH4N-jP-BQxXC.js 0.55 kB │ gzip: 0.37 kB
|
||||
dist/assets/calculator-K0r_LA6K.js 0.56 kB │ gzip: 0.30 kB
|
||||
dist/assets/infoDiagram-27XIBGKW-BO8R-0BH.js 0.59 kB │ gzip: 0.40 kB
|
||||
dist/assets/sizeCapture-INFHLROL-KBPVYQON.js 0.94 kB │ gzip: 0.53 kB
|
||||
dist/assets/downloadDocx-Ep6Y-mWJ.js 1.13 kB │ gzip: 0.77 kB
|
||||
dist/assets/ordinal-Cboi1Yqb.js 1.19 kB │ gzip: 0.57 kB
|
||||
dist/assets/railroadDiagram-O6MQD6OU-3o3NI4V-.js 1.61 kB │ gzip: 0.76 kB
|
||||
dist/assets/MathBlockView-CP3gIAfz.js 1.67 kB │ gzip: 0.97 kB
|
||||
dist/assets/abnfDiagram-VCTEODGH-Bv_S-VQO.js 1.81 kB │ gzip: 0.89 kB
|
||||
dist/assets/chunk-F27PBJKO-DwG2Zkg1.js 1.88 kB │ gzip: 0.83 kB
|
||||
dist/assets/pegDiagram-XKGWAZYB-BRKb5jpA.js 1.96 kB │ gzip: 0.92 kB
|
||||
dist/assets/ebnfDiagram-PWID7BFC-CAlTqs1O.js 2.01 kB │ gzip: 0.88 kB
|
||||
dist/assets/xlsxRenderer-BQPATLFB.js 2.79 kB │ gzip: 1.69 kB
|
||||
dist/assets/arc-DOxBXeCg.js 3.44 kB │ gzip: 1.48 kB
|
||||
dist/assets/MermaidBlockView-BNZ12-FU.js 3.69 kB │ gzip: 1.80 kB
|
||||
dist/assets/diagram-Z3DM3KII-iO8-m9Hl.js 4.21 kB │ gzip: 1.83 kB
|
||||
dist/assets/defaultLocale-DX6XiGOO.js 4.69 kB │ gzip: 2.18 kB
|
||||
dist/assets/renderClipboardHtml-BXoFMW-3.js 5.18 kB │ gzip: 1.78 kB
|
||||
dist/assets/ExcelViewer-BZSJZn5Y.js 5.55 kB │ gzip: 2.21 kB
|
||||
dist/assets/linear-BDZQyaJG.js 5.66 kB │ gzip: 2.31 kB
|
||||
dist/assets/diagram-UQ7AKVKN-BnBJ_2R3.js 6.08 kB │ gzip: 2.62 kB
|
||||
dist/assets/pieDiagram-E7YTZNPT-nrtuGrNr.js 6.29 kB │ gzip: 2.62 kB
|
||||
dist/assets/ChatExportModal-Bfjz4958.js 7.58 kB │ gzip: 3.29 kB
|
||||
dist/assets/diagram-S7CK7UJ4-T-Bxl4t1.js 8.22 kB │ gzip: 3.67 kB
|
||||
dist/assets/cynefinDiagram-5FMLGOSQ-CnH3Z2JB.js 10.10 kB │ gzip: 3.63 kB
|
||||
dist/assets/stateDiagram-D77RDMKH-DVKtcg-v.js 10.36 kB │ gzip: 3.62 kB
|
||||
dist/assets/dagre-GXQ25YYZ-4R6bcum3.js 10.68 kB │ gzip: 4.03 kB
|
||||
dist/assets/diagram-VSXAHHWV-DLnsWaIP.js 10.72 kB │ gzip: 4.13 kB
|
||||
dist/assets/chunk-SVP7TREG-BhgGIDFD.js 15.74 kB │ gzip: 4.41 kB
|
||||
dist/assets/diagram-VX7I27RA-Duotn1-e.js 15.96 kB │ gzip: 5.70 kB
|
||||
dist/assets/ishikawaDiagram-5VMMS53U-Cg4LfJyo.js 17.47 kB │ gzip: 6.64 kB
|
||||
dist/assets/kanban-definition-UXKFOSKX-BALPAjTC.js 20.29 kB │ gzip: 7.20 kB
|
||||
dist/assets/BlockEditorModal-BOLlSDTH.js 22.24 kB │ gzip: 6.47 kB
|
||||
dist/assets/mindmap-definition-YA3MSWOX-pgZMQ8uL.js 23.18 kB │ gzip: 7.83 kB
|
||||
dist/assets/sankeyDiagram-P5KCCOFB-cHAs8eQM.js 23.20 kB │ gzip: 8.56 kB
|
||||
dist/assets/journeyDiagram-3NMN7TZE-DXSneWK0.js 23.57 kB │ gzip: 8.35 kB
|
||||
dist/assets/wardleyDiagram-VM6X3IG4-83YMC1gW.js 25.50 kB │ gzip: 6.79 kB
|
||||
dist/assets/gitGraphDiagram-WWUBYQGX-3ajohVe1.js 29.42 kB │ gzip: 8.70 kB
|
||||
dist/assets/FilePreviewPanel-BaAl4sya.js 30.12 kB │ gzip: 8.97 kB
|
||||
dist/assets/erDiagram-RLTQ6QDP-BDpOdOIc.js 30.79 kB │ gzip: 10.59 kB
|
||||
dist/assets/timeline-definition-24CTP7MA-d7EudEZG.js 30.83 kB │ gzip: 10.15 kB
|
||||
dist/assets/requirementDiagram-BXWQKSXE-2YVxwHhy.js 31.00 kB │ gzip: 9.73 kB
|
||||
dist/assets/quadrantDiagram-AXDQQJYC-DHNugfXZ.js 34.01 kB │ gzip: 9.98 kB
|
||||
dist/assets/layout-BrexQxSk.js 35.44 kB │ gzip: 12.75 kB
|
||||
dist/assets/chunk-IMKFNOWR-DL3J6pk5.js 38.08 kB │ gzip: 12.51 kB
|
||||
dist/assets/docxRenderer-Ilu9VYYG.js 40.90 kB │ gzip: 12.04 kB
|
||||
dist/assets/blockDiagram-I7D4REHJ-ozi4Xk9Q.js 41.76 kB │ gzip: 13.58 kB
|
||||
dist/assets/vennDiagram-4TSXK5OY-Dswu0LDK.js 41.96 kB │ gzip: 15.70 kB
|
||||
dist/assets/xychartDiagram-S5SC5T6Z-Do0p5dm5.js 44.51 kB │ gzip: 12.60 kB
|
||||
dist/assets/chunk-TICWLB2K-CsHC9dlc.js 49.18 kB │ gzip: 15.74 kB
|
||||
dist/assets/flowDiagram-HODETNUW-BGwlzTt0.js 61.85 kB │ gzip: 19.87 kB
|
||||
dist/assets/c4Diagram-7LVT6UL2-MxYk0iqL.js 65.47 kB │ gzip: 18.79 kB
|
||||
dist/assets/ganttDiagram-EL5Y4UJY-ijkjYohu.js 69.70 kB │ gzip: 23.56 kB
|
||||
dist/assets/AdminConsoleView-C6f6_5zf.js 74.34 kB │ gzip: 18.18 kB
|
||||
dist/assets/cose-bilkent-JH36ORCC-DW6Qeju_.js 81.70 kB │ gzip: 22.47 kB
|
||||
dist/assets/swimlanes-42K2YHIH-BaJ44xBg.js 115.79 kB │ gzip: 42.51 kB
|
||||
dist/assets/sequenceDiagram-WJ2MYXX4-BqEzakUS.js 116.96 kB │ gzip: 31.13 kB
|
||||
dist/assets/architectureDiagram-5GKGNRK7-BW5RJe7u.js 151.83 kB │ gzip: 43.14 kB
|
||||
dist/assets/DocxViewer-thvChHTS.js 175.87 kB │ gzip: 52.31 kB
|
||||
dist/assets/katex-HP8lGamR.js 261.31 kB │ gzip: 77.57 kB
|
||||
dist/assets/katex-BJxdM42i.js 261.44 kB │ gzip: 77.80 kB
|
||||
dist/assets/index-BXtlAAcH.js 365.75 kB │ gzip: 104.72 kB
|
||||
dist/assets/xlsx-Cig0qvpi.js 424.39 kB │ gzip: 141.60 kB
|
||||
dist/assets/cytoscape.esm-BB4DxJjf.js 443.04 kB │ gzip: 141.98 kB
|
||||
dist/assets/mermaid.core-C3o1vFDn.js 682.57 kB │ gzip: 168.90 kB
|
||||
dist/assets/cynefin-OW5HDTMX-Ca8YX88f.js 687.91 kB │ gzip: 154.14 kB
|
||||
dist/assets/index-cbAtdfhj.js 814.04 kB │ gzip: 239.32 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 8.74s
|
||||
precompress: 66 candidate(s) under /home/weichen/projects/Agent-System/.worktrees/refresh-task-state-recovery-2026-09-28/web/dist
|
||||
br assets/AdminConsoleView-C6f6_5zf.js 74340 → 14847 (−80.0%)
|
||||
gzip assets/AdminConsoleView-C6f6_5zf.js 74340 → 17742 (−76.1%)
|
||||
br assets/BlockEditorModal-BOLlSDTH.js 22241 → 5389 (−75.8%)
|
||||
gzip assets/BlockEditorModal-BOLlSDTH.js 22241 → 6375 (−71.3%)
|
||||
br assets/ChatExportModal-Bfjz4958.js 7581 → 2732 (−64.0%)
|
||||
gzip assets/ChatExportModal-Bfjz4958.js 7581 → 3242 (−57.2%)
|
||||
br assets/DocxViewer-thvChHTS.js 175867 → 46191 (−73.7%)
|
||||
gzip assets/DocxViewer-thvChHTS.js 175867 → 52082 (−70.4%)
|
||||
br assets/ExcelViewer-BZSJZn5Y.js 5552 → 1885 (−66.0%)
|
||||
gzip assets/ExcelViewer-BZSJZn5Y.js 5552 → 2194 (−60.5%)
|
||||
br assets/FilePreviewPanel-BaAl4sya.js 30116 → 7564 (−74.9%)
|
||||
gzip assets/FilePreviewPanel-BaAl4sya.js 30116 → 8813 (−70.7%)
|
||||
br assets/MathBlockView-CP3gIAfz.js 1669 → 800 (−52.1%)
|
||||
gzip assets/MathBlockView-CP3gIAfz.js 1669 → 962 (−42.4%)
|
||||
br assets/MermaidBlockView-BNZ12-FU.js 3690 → 1499 (−59.4%)
|
||||
gzip assets/MermaidBlockView-BNZ12-FU.js 3690 → 1794 (−51.4%)
|
||||
br assets/abnfDiagram-VCTEODGH-Bv_S-VQO.js 1809 → 785 (−56.6%)
|
||||
gzip assets/abnfDiagram-VCTEODGH-Bv_S-VQO.js 1809 → 895 (−50.5%)
|
||||
br assets/arc-DOxBXeCg.js 3441 → 1296 (−62.3%)
|
||||
gzip assets/arc-DOxBXeCg.js 3441 → 1455 (−57.7%)
|
||||
br assets/architectureDiagram-5GKGNRK7-BW5RJe7u.js 151827 → 36975 (−75.6%)
|
||||
gzip assets/architectureDiagram-5GKGNRK7-BW5RJe7u.js 151827 → 42841 (−71.8%)
|
||||
br assets/blockDiagram-I7D4REHJ-ozi4Xk9Q.js 41757 → 11969 (−71.3%)
|
||||
gzip assets/blockDiagram-I7D4REHJ-ozi4Xk9Q.js 41757 → 13469 (−67.7%)
|
||||
br assets/c4Diagram-7LVT6UL2-MxYk0iqL.js 65473 → 15133 (−76.9%)
|
||||
gzip assets/c4Diagram-7LVT6UL2-MxYk0iqL.js 65473 → 18679 (−71.5%)
|
||||
br assets/chunk-F27PBJKO-DwG2Zkg1.js 1883 → 742 (−60.6%)
|
||||
gzip assets/chunk-F27PBJKO-DwG2Zkg1.js 1883 → 831 (−55.9%)
|
||||
br assets/chunk-IMKFNOWR-DL3J6pk5.js 38076 → 10974 (−71.2%)
|
||||
gzip assets/chunk-IMKFNOWR-DL3J6pk5.js 38076 → 12434 (−67.3%)
|
||||
br assets/chunk-SVP7TREG-BhgGIDFD.js 15735 → 3966 (−74.8%)
|
||||
gzip assets/chunk-SVP7TREG-BhgGIDFD.js 15735 → 4418 (−71.9%)
|
||||
br assets/chunk-TICWLB2K-CsHC9dlc.js 49178 → 13033 (−73.5%)
|
||||
gzip assets/chunk-TICWLB2K-CsHC9dlc.js 49178 → 15645 (−68.2%)
|
||||
br assets/cose-bilkent-JH36ORCC-DW6Qeju_.js 81701 → 19574 (−76.0%)
|
||||
gzip assets/cose-bilkent-JH36ORCC-DW6Qeju_.js 81701 → 22391 (−72.6%)
|
||||
br assets/cynefin-OW5HDTMX-Ca8YX88f.js 687913 → 124540 (−81.9%)
|
||||
gzip assets/cynefin-OW5HDTMX-Ca8YX88f.js 687913 → 153068 (−77.7%)
|
||||
br assets/cynefinDiagram-5FMLGOSQ-CnH3Z2JB.js 10097 → 3248 (−67.8%)
|
||||
gzip assets/cynefinDiagram-5FMLGOSQ-CnH3Z2JB.js 10097 → 3620 (−64.1%)
|
||||
br assets/cytoscape.esm-BB4DxJjf.js 443036 → 119602 (−73.0%)
|
||||
gzip assets/cytoscape.esm-BB4DxJjf.js 443036 → 141741 (−68.0%)
|
||||
br assets/dagre-GXQ25YYZ-4R6bcum3.js 10676 → 3680 (−65.5%)
|
||||
gzip assets/dagre-GXQ25YYZ-4R6bcum3.js 10676 → 4046 (−62.1%)
|
||||
br assets/defaultLocale-DX6XiGOO.js 4688 → 2012 (−57.1%)
|
||||
gzip assets/defaultLocale-DX6XiGOO.js 4688 → 2166 (−53.8%)
|
||||
br assets/diagram-S7CK7UJ4-T-Bxl4t1.js 8217 → 3326 (−59.5%)
|
||||
gzip assets/diagram-S7CK7UJ4-T-Bxl4t1.js 8217 → 3677 (−55.3%)
|
||||
br assets/diagram-UQ7AKVKN-BnBJ_2R3.js 6079 → 2367 (−61.1%)
|
||||
gzip assets/diagram-UQ7AKVKN-BnBJ_2R3.js 6079 → 2617 (−57.0%)
|
||||
br assets/diagram-VSXAHHWV-DLnsWaIP.js 10716 → 3782 (−64.7%)
|
||||
gzip assets/diagram-VSXAHHWV-DLnsWaIP.js 10716 → 4154 (−61.2%)
|
||||
br assets/diagram-VX7I27RA-Duotn1-e.js 15957 → 5171 (−67.6%)
|
||||
gzip assets/diagram-VX7I27RA-Duotn1-e.js 15957 → 5707 (−64.2%)
|
||||
br assets/diagram-Z3DM3KII-iO8-m9Hl.js 4211 → 1642 (−61.0%)
|
||||
gzip assets/diagram-Z3DM3KII-iO8-m9Hl.js 4211 → 1818 (−56.8%)
|
||||
br assets/docxRenderer-Ilu9VYYG.js 40904 → 10539 (−74.2%)
|
||||
gzip assets/docxRenderer-Ilu9VYYG.js 40904 → 11977 (−70.7%)
|
||||
br assets/downloadDocx-Ep6Y-mWJ.js 1130 → 612 (−45.8%)
|
||||
gzip assets/downloadDocx-Ep6Y-mWJ.js 1130 → 767 (−32.1%)
|
||||
br assets/ebnfDiagram-PWID7BFC-CAlTqs1O.js 2005 → 784 (−60.9%)
|
||||
gzip assets/ebnfDiagram-PWID7BFC-CAlTqs1O.js 2005 → 884 (−55.9%)
|
||||
br assets/erDiagram-RLTQ6QDP-BDpOdOIc.js 30790 → 9175 (−70.2%)
|
||||
gzip assets/erDiagram-RLTQ6QDP-BDpOdOIc.js 30790 → 10542 (−65.8%)
|
||||
br assets/flowDiagram-HODETNUW-BGwlzTt0.js 61847 → 16384 (−73.5%)
|
||||
gzip assets/flowDiagram-HODETNUW-BGwlzTt0.js 61847 → 19717 (−68.1%)
|
||||
br assets/ganttDiagram-EL5Y4UJY-ijkjYohu.js 69695 → 20666 (−70.3%)
|
||||
gzip assets/ganttDiagram-EL5Y4UJY-ijkjYohu.js 69695 → 23425 (−66.4%)
|
||||
br assets/gitGraphDiagram-WWUBYQGX-3ajohVe1.js 29417 → 7789 (−73.5%)
|
||||
gzip assets/gitGraphDiagram-WWUBYQGX-3ajohVe1.js 29417 → 8695 (−70.4%)
|
||||
br assets/index-BXtlAAcH.js 365745 → 89917 (−75.4%)
|
||||
gzip assets/index-BXtlAAcH.js 365745 → 104064 (−71.5%)
|
||||
br assets/index-Bq7tVxen.css 6576 → 1656 (−74.8%)
|
||||
gzip assets/index-Bq7tVxen.css 6576 → 1974 (−70.0%)
|
||||
br assets/index-cbAtdfhj.js 814041 → 187943 (−76.9%)
|
||||
gzip assets/index-cbAtdfhj.js 814041 → 236064 (−71.0%)
|
||||
br assets/ishikawaDiagram-5VMMS53U-Cg4LfJyo.js 17469 → 6007 (−65.6%)
|
||||
gzip assets/ishikawaDiagram-5VMMS53U-Cg4LfJyo.js 17469 → 6634 (−62.0%)
|
||||
br assets/journeyDiagram-3NMN7TZE-DXSneWK0.js 23571 → 7531 (−68.0%)
|
||||
gzip assets/journeyDiagram-3NMN7TZE-DXSneWK0.js 23571 → 8331 (−64.7%)
|
||||
br assets/kanban-definition-UXKFOSKX-BALPAjTC.js 20291 → 6409 (−68.4%)
|
||||
gzip assets/kanban-definition-UXKFOSKX-BALPAjTC.js 20291 → 7172 (−64.7%)
|
||||
br assets/katex-BJxdM42i.js 261435 → 63900 (−75.6%)
|
||||
gzip assets/katex-BJxdM42i.js 261435 → 77355 (−70.4%)
|
||||
br assets/katex-BOvhZl6_.css 30249 → 6978 (−76.9%)
|
||||
gzip assets/katex-BOvhZl6_.css 30249 → 8010 (−73.5%)
|
||||
br assets/katex-HP8lGamR.js 261313 → 63694 (−75.6%)
|
||||
gzip assets/katex-HP8lGamR.js 261313 → 77109 (−70.5%)
|
||||
br assets/layout-BrexQxSk.js 35436 → 11571 (−67.3%)
|
||||
gzip assets/layout-BrexQxSk.js 35436 → 12751 (−64.0%)
|
||||
br assets/linear-BDZQyaJG.js 5661 → 2117 (−62.6%)
|
||||
gzip assets/linear-BDZQyaJG.js 5661 → 2318 (−59.1%)
|
||||
br assets/mermaid.core-C3o1vFDn.js 682569 → 140363 (−79.4%)
|
||||
gzip assets/mermaid.core-C3o1vFDn.js 682569 → 168123 (−75.4%)
|
||||
br assets/mindmap-definition-YA3MSWOX-pgZMQ8uL.js 23175 → 6998 (−69.8%)
|
||||
gzip assets/mindmap-definition-YA3MSWOX-pgZMQ8uL.js 23175 → 7799 (−66.3%)
|
||||
br assets/ordinal-Cboi1Yqb.js 1189 → 497 (−58.2%)
|
||||
gzip assets/ordinal-Cboi1Yqb.js 1189 → 574 (−51.7%)
|
||||
br assets/pegDiagram-XKGWAZYB-BRKb5jpA.js 1956 → 821 (−58.0%)
|
||||
gzip assets/pegDiagram-XKGWAZYB-BRKb5jpA.js 1956 → 927 (−52.6%)
|
||||
br assets/pieDiagram-E7YTZNPT-nrtuGrNr.js 6294 → 2407 (−61.8%)
|
||||
gzip assets/pieDiagram-E7YTZNPT-nrtuGrNr.js 6294 → 2629 (−58.2%)
|
||||
br assets/quadrantDiagram-AXDQQJYC-DHNugfXZ.js 34010 → 8523 (−74.9%)
|
||||
gzip assets/quadrantDiagram-AXDQQJYC-DHNugfXZ.js 34010 → 9876 (−71.0%)
|
||||
br assets/railroadDiagram-O6MQD6OU-3o3NI4V-.js 1606 → 683 (−57.5%)
|
||||
gzip assets/railroadDiagram-O6MQD6OU-3o3NI4V-.js 1606 → 758 (−52.8%)
|
||||
br assets/renderClipboardHtml-BXoFMW-3.js 5180 → 1452 (−72.0%)
|
||||
gzip assets/renderClipboardHtml-BXoFMW-3.js 5180 → 1778 (−65.7%)
|
||||
br assets/requirementDiagram-BXWQKSXE-2YVxwHhy.js 31000 → 8241 (−73.4%)
|
||||
gzip assets/requirementDiagram-BXWQKSXE-2YVxwHhy.js 31000 → 9661 (−68.8%)
|
||||
br assets/sankeyDiagram-P5KCCOFB-cHAs8eQM.js 23198 → 7819 (−66.3%)
|
||||
gzip assets/sankeyDiagram-P5KCCOFB-cHAs8eQM.js 23198 → 8565 (−63.1%)
|
||||
br assets/sequenceDiagram-WJ2MYXX4-BqEzakUS.js 116962 → 25735 (−78.0%)
|
||||
gzip assets/sequenceDiagram-WJ2MYXX4-BqEzakUS.js 116962 → 30955 (−73.5%)
|
||||
br assets/stateDiagram-D77RDMKH-DVKtcg-v.js 10361 → 3334 (−67.8%)
|
||||
gzip assets/stateDiagram-D77RDMKH-DVKtcg-v.js 10361 → 3623 (−65.0%)
|
||||
br assets/swimlanes-42K2YHIH-BaJ44xBg.js 115791 → 36679 (−68.3%)
|
||||
gzip assets/swimlanes-42K2YHIH-BaJ44xBg.js 115791 → 42170 (−63.6%)
|
||||
br assets/timeline-definition-24CTP7MA-d7EudEZG.js 30829 → 9133 (−70.4%)
|
||||
gzip assets/timeline-definition-24CTP7MA-d7EudEZG.js 30829 → 10143 (−67.1%)
|
||||
br assets/vennDiagram-4TSXK5OY-Dswu0LDK.js 41961 → 13993 (−66.7%)
|
||||
gzip assets/vennDiagram-4TSXK5OY-Dswu0LDK.js 41961 → 15643 (−62.7%)
|
||||
br assets/wardleyDiagram-VM6X3IG4-83YMC1gW.js 25502 → 6077 (−76.2%)
|
||||
gzip assets/wardleyDiagram-VM6X3IG4-83YMC1gW.js 25502 → 6751 (−73.5%)
|
||||
br assets/xlsx-Cig0qvpi.js 424392 → 117659 (−72.3%)
|
||||
gzip assets/xlsx-Cig0qvpi.js 424392 → 140814 (−66.8%)
|
||||
br assets/xlsxRenderer-BQPATLFB.js 2785 → 1354 (−51.4%)
|
||||
gzip assets/xlsxRenderer-BQPATLFB.js 2785 → 1677 (−39.8%)
|
||||
br assets/xychartDiagram-S5SC5T6Z-Do0p5dm5.js 44509 → 11058 (−75.2%)
|
||||
gzip assets/xychartDiagram-S5SC5T6Z-Do0p5dm5.js 44509 → 12534 (−71.8%)
|
||||
br fonts/OFL.txt 4474 → 1437 (−67.9%)
|
||||
gzip fonts/OFL.txt 4474 → 1980 (−55.7%)
|
||||
precompress: wrote 66 .br and 66 .gz
|
||||
NPM_BUILD:0
|
||||
@@ -0,0 +1,651 @@
|
||||
|
||||
> 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 超级管理员鉴权 (2.388929ms)
|
||||
✔ AuthClient: 自主注册受控流程(仅填用户名密码姓名,职位强制绑定访客待指派) (0.448527ms)
|
||||
✔ AuthClient: 开启注册需审批时,注册账号处于待审状态并禁止登录 (0.495266ms)
|
||||
✔ AuthClient: 管理员创建账号必须在首次登录修改密码 (0.258262ms)
|
||||
✔ authErrorMessage: 优先信封 error 领域原因,避免裸 JSON / 无权访问误导 (0.227843ms)
|
||||
✔ mapUserAccount: snake_case Go contract → camelCase (1.231233ms)
|
||||
✔ mapUserAccount: prefers snake_case when both present (0.164515ms)
|
||||
✔ mapLoginResult/mapMeResult use top-level must_change_password as sole authority (0.211534ms)
|
||||
✔ mapUserAccountList maps admin users list (0.116027ms)
|
||||
✔ AuthClient.login + fetchMe map real snake_case wire payloads (36.529405ms)
|
||||
✔ shouldAutoRetryChat: disabled until idempotency (0.913842ms)
|
||||
✔ shouldAutoRetryTask: transient only, max 2 (0.229563ms)
|
||||
✔ shouldAutoRetryTask: document busy never retries (0.136656ms)
|
||||
✔ shouldAutoRetry alias delegates to task path (0.137816ms)
|
||||
✔ autoRetryDelayMs: 1s then 2s (0.137336ms)
|
||||
✔ fallbackErrorClass: network → transient, workspace → resumable (1.663131ms)
|
||||
✔ upsertChatSession surfaces safe INTERNAL envelope instead of raw JSON text (79.905537ms)
|
||||
[sse] 忽略无法解析的帧: {not valid json SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)
|
||||
at JSON.parse (<anonymous>)
|
||||
at parseFrame (/home/weichen/projects/Agent-System/.worktrees/refresh-task-state-recovery-2026-09-28/web/src/api/chatStream.ts:126:26)
|
||||
at parseSSEChunk (/home/weichen/projects/Agent-System/.worktrees/refresh-task-state-recovery-2026-09-28/web/src/api/chatStream.ts:199:20)
|
||||
at TestContext.<anonymous> (/home/weichen/projects/Agent-System/.worktrees/refresh-task-state-recovery-2026-09-28/web/src/api/chatStream.test.ts:41:31)
|
||||
at Test.runInAsyncScope (node:async_hooks:226:14)
|
||||
at Test.run (node:internal/test_runner/test:1402:25)
|
||||
at Test.processPendingSubtests (node:internal/test_runner/test:974:18)
|
||||
at Test.postRun (node:internal/test_runner/test:1542:19)
|
||||
at Test.run (node:internal/test_runner/test:1467:12)
|
||||
at async Test.processPendingSubtests (node:internal/test_runner/test:974:7)
|
||||
✔ parseSSEChunk: parses event and data lines (1.00906ms)
|
||||
✔ parseSSEChunk: keeps incomplete frame in rest (0.231474ms)
|
||||
✔ parseSSEChunk: flush parses final frame without trailing delimiter (0.224793ms)
|
||||
✔ parseSSEChunk: ignores heartbeat comments and keeps last id (0.139066ms)
|
||||
✔ parseSSEChunk: skips a single malformed frame and keeps parsing the next valid frame (5.017202ms)
|
||||
✔ parseSSEChunk: parses CRLF-delimited frames (0.229503ms)
|
||||
✔ parseSSEChunk: mixed LF and CRLF delimiters (0.137336ms)
|
||||
✔ API_BASE is empty relative base (1.037719ms)
|
||||
✔ apiFetch attaches Bearer from session storage (64.929112ms)
|
||||
✔ apiFetch retries GET on 503 then succeeds (201.72881ms)
|
||||
✔ apiFetch does not retry POST by default (0.516094ms)
|
||||
✔ readApiError preserves typed envelope for error cards (1.498965ms)
|
||||
✔ apiFetch auth:false skips Authorization (0.530665ms)
|
||||
▶ docgov lifecycle API client
|
||||
✔ claimDocument posts to /api/v1/docgov/claim with author role (23.291168ms)
|
||||
✔ submitForReview posts to /api/v1/docgov/submit-review (0.706349ms)
|
||||
✔ reviewDecision posts action and optional reason (0.817416ms)
|
||||
✔ approverDecision posts action and rollback_to (0.954792ms)
|
||||
✔ proposeModification posts to /api/v1/docgov/proposal (1.198325ms)
|
||||
✔ decideModificationProposal posts to /api/v1/docgov/proposal/decide (0.720289ms)
|
||||
✔ docgov lifecycle API client (28.742506ms)
|
||||
✔ updateFreeformDoc exposes CONCURRENCY_CONFLICT on 409 (22.916699ms)
|
||||
▶ notifications inbox helpers
|
||||
✔ ranks action_required / proposal ahead of info (0.65737ms)
|
||||
✔ notifications inbox helpers (1.486036ms)
|
||||
✔ addProjectMember exposes structured ProjectSettingsApiError on 403 (25.801144ms)
|
||||
✔ updateProjectMember surfaces safe INTERNAL message on 500 duty-sync failure (0.822326ms)
|
||||
▶ projectSettingsError
|
||||
✔ keeps status, code, message and issues on PLAN_FROZEN (1.624582ms)
|
||||
✔ maps revision and concurrent conflicts to distinct recovery (0.172775ms)
|
||||
✔ joins validation issues but still keeps typed codes (0.189844ms)
|
||||
✔ prefers envelope code over legacy error field (0.138986ms)
|
||||
✔ unwraps nested business JSON inside VERSION_CONFLICT envelope (0.187354ms)
|
||||
✔ maps bare VERSION_CONFLICT envelope to retry_after_switch (0.106467ms)
|
||||
✔ retains the local draft when a late tab hits PLAN_FROZEN (0.114897ms)
|
||||
✔ prefers error_code over legacy bare error string (DOC_BUSY) (0.128807ms)
|
||||
✔ projectSettingsError (4.087899ms)
|
||||
✔ fetchProjectTrace turns null arrays into empty arrays (25.555001ms)
|
||||
✔ fetchProjectTrace keeps real arrays and rejects failed responses (1.302701ms)
|
||||
✔ Project workflow types validation (2.125657ms)
|
||||
✔ createTaskRun exposes DOC_BUSY detail without a retryable run (27.347498ms)
|
||||
✔ parseSSEChunk tracks id seq for after_seq reconnect (0.474346ms)
|
||||
✔ subscribeTaskRunEvents reconnects on EOF with advancing after_seq (6.424009ms)
|
||||
✔ readTaskRunSSEOnce marks non-terminal EOF for reconnect (0.68087ms)
|
||||
✔ subscribeTaskRunEvents fails fast on 401 without retrying (0.491175ms)
|
||||
✔ subscribeTaskRunEvents fails fast on 404 without retrying (1.400458ms)
|
||||
✔ buildTaskRequest: maps five project fields + task_key + user identity (0.757228ms)
|
||||
✔ buildTaskRequest: omits optional fields when absent (0.164035ms)
|
||||
✔ buildTaskRequest: includes materials when provided and non-empty (0.755688ms)
|
||||
✔ buildResumeRequest: adds work_dir on top of task request (0.175045ms)
|
||||
✔ buildTaskRequest: canonicalizes legacy doc-p doc_id (0.260083ms)
|
||||
✔ buildTaskRequest: UI-05 pinned intake keeps task_key + doc_proj6109_intake (0.193434ms)
|
||||
✔ buildResumeRequest: forwards add_steps when provided (0.153185ms)
|
||||
✔ CategoryDock: 渲染顶部 🔔 未读提醒项及角标数字 (20.272788ms)
|
||||
✔ CategoryDock: isAllReadCompleted 为 true 时渲染完成态提示 (9.797689ms)
|
||||
✔ CategoryDock: 0 未读时不渲染红色未读角标 (6.548825ms)
|
||||
✔ CategoryDock: 分类项包含依次跳转与遍历提示信息 (5.285423ms)
|
||||
✔ chat column lives outside the workbench shell (0.954951ms)
|
||||
✔ InputArea keeps draft when send preflight fails (1.420548ms)
|
||||
✔ InputArea clears draft only after accepted send (2.463867ms)
|
||||
✔ InputArea shows thinking block message (0.197614ms)
|
||||
✔ InputArea keeps draft when attachment registration fails (0.247822ms)
|
||||
✔ TaskRunCard renders timeline with title badge and current step (13.771851ms)
|
||||
✔ TaskRunCard completed state keeps card with duration and artifact (2.308901ms)
|
||||
✔ TaskRunCard sanitizes frozen progress labels on completed steps (1.979611ms)
|
||||
✔ TaskRunCard keeps shell when only taskRunId is present (0.864224ms)
|
||||
✔ active document pane lives outside the workbench shell (1.437047ms)
|
||||
✔ isTemplateOnly 交付物应正确识别为初始模板展示态 (7.921545ms)
|
||||
✔ workbench shell lives outside App (4.726439ms)
|
||||
✔ 左侧栏鼠标严密绝对跟随与夹紧测试 (Left Rail Exact Pointer Following & Clamping) (0.713178ms)
|
||||
✔ 右侧栏鼠标严密绝对跟随与反向位移测试 (Right Rail Exact Pointer Following & Inverted Delta) (0.126506ms)
|
||||
✔ trace panel is not mounted above the chat stream (5.641603ms)
|
||||
✔ detects legacy mock and neuropulse/ten-projects ids (0.864744ms)
|
||||
✔ detects colliding demo project ids (0.132876ms)
|
||||
✔ applyRestoredFileRaw: 以 prev 为权威,只补丁缺失 fileRaw,不丢新增条目 (1.154566ms)
|
||||
✔ applyRestoredFileRaw: 无可用 fileRaw 时返回同一引用 (0.187955ms)
|
||||
✔ login member sync stays one request for 1, 30 and 100 projects (6.07364ms)
|
||||
✔ viewer seed keeps session visibility without a member-list call (0.397488ms)
|
||||
✔ later session response cannot overwrite a newer user (0.190665ms)
|
||||
✔ in-flight member sync collapses to one call (0.263752ms)
|
||||
✔ 每人独立私聊:同一项目不同用户拥有不同 sessionId (0.881204ms)
|
||||
✔ 左侧会话列表按当前用户过滤,不可见他人私聊 (0.256262ms)
|
||||
✔ 消息严格归属各自私聊 session,无跨用户混聊 (0.870234ms)
|
||||
✔ 切换用户时 resolve 到该用户同项目私聊会话 (0.244812ms)
|
||||
✔ resolve 优先有消息的私聊,跳过空壳 sess-p{N}-u{id} (1.166125ms)
|
||||
✔ ensurePrivateSessionsForUser 为缺失用户补齐空私聊 (0.593802ms)
|
||||
✔ 多项目会话消息隔离测试仍成立(endo vs ultrasound) (0.33904ms)
|
||||
✔ window cache LRU: 驱逐带 userId 前缀的完整 cache key,不留孤儿条目 (1.36061ms)
|
||||
✔ window cache: 无 schema 的旧载荷不当作有效缓存 (7.710341ms)
|
||||
✔ window cache: 读写同一 userId 前缀,跨用户不串读 (0.273892ms)
|
||||
✔ 残留的 legacy demo sessionId 被读取侧清除并返回 fallback (0.905753ms)
|
||||
✔ 真实 sessionId 不被误清 (0.152565ms)
|
||||
✔ 无 window 环境(SSR)安全返回 fallback (0.068078ms)
|
||||
✔ same account and first login do not reset workbench storage (1.144056ms)
|
||||
✔ switching accounts resets workbench storage (0.182865ms)
|
||||
✔ resetWorkbenchStorage preserves org user directory for cross-account project create (1.219384ms)
|
||||
✔ parseAnchorHash: 正确解析标准深链 hash (1.438807ms)
|
||||
✔ formatAnchorHash: 正确构造深链格式 (0.106107ms)
|
||||
✔ navigateToAnchor: 快路径直接命中 DOM 节点 (0.388478ms)
|
||||
✔ navigateToAnchor: 慢路径拉取分片后命中 (79.542228ms)
|
||||
✔ resolveTurnAnchorId: 方案 A 轮次归一化测试 (0.507675ms)
|
||||
✔ 全链路场景 1: 用户自主受控注册(仅填用户名/密码/姓名,职位严格绑定访客待指派) (1.552684ms)
|
||||
✔ 全链路场景 2: 系统准入策略(关闭自主注册与开启强制审批流转) (0.647091ms)
|
||||
✔ 全链路场景 3: 管理员开通账号首次强制改密闭环 (0.242653ms)
|
||||
✔ 全链路场景 4: 环境标识随登录会话返回(dev/test/main) (0.261022ms)
|
||||
✔ cleanHeadingContent: 手工多级序号前缀清洗与专业词汇保护 (2.277532ms)
|
||||
✔ 标题多层级自动编号:单 H1 文档总标题自适应模式 (1 -> 1.1 -> 1.1.1) (0.34501ms)
|
||||
✔ 标题多层级自动编号:多 H1 标准大章模式 (0.137276ms)
|
||||
✔ 跨章节图、表、公式多级按章重编号测试 (表 1-1, 表 2-1, 图 3-1, 式 (4-1)) (0.154156ms)
|
||||
✔ 有序列表与无序列表编号与渲染功能测试 (2.399788ms)
|
||||
✔ 动态块操作闭环重编号验证 (Insert, Move, Delete) (3.589093ms)
|
||||
✔ findMatchingBlockForReview: 能够精准按审查关键词(电气安全/EMC/竞品)定位段落块 (0.848975ms)
|
||||
✔ findMatchingBlockForReview: 能够按外部指定 hint 线索精确命中目标块 (0.170635ms)
|
||||
✔ createRejectConfirmationCard: 生成合规危险级驳回门禁卡片 (0.605742ms)
|
||||
✔ isAffirmativeResponse: 准确识别双轨交互中的肯定意图输入 (0.205574ms)
|
||||
✔ findLastActiveCard: 正确在会话历史中提取最新的待决策卡片 (0.201834ms)
|
||||
✔ decrementActiveCardsTtl: 多轮对话超时递减与自动失效归档 (0.163195ms)
|
||||
✔ applyConfirmRejectToDoc & applyUndoRejectToDoc: 驳回挂载批注与60s窗口期撤销完整闭环 (0.251372ms)
|
||||
✔ resolveCardInMessages & cancelCardInMessages: 消息流中卡片终态沉淀 (0.151626ms)
|
||||
✔ classifyRejectUtterance: 询问原因 → QUERY_REJECT_REASON (1.295522ms)
|
||||
✔ classifyRejectUtterance: 明确执行 → EXECUTE_REJECT (0.177635ms)
|
||||
✔ classifyRejectUtterance: 模糊 → OTHER (0.197495ms)
|
||||
✔ resolveDocGovCard: 编制人查询 → 信息卡且无 confirm_reject (0.788967ms)
|
||||
✔ resolveDocGovCard: 审核人执行 + reviewing → 确认卡 (0.289862ms)
|
||||
✔ resolveDocGovCard: 编制人误说执行驳回 → 无权纯文本 (0.141016ms)
|
||||
✔ resolveDocGovCard: 批准人 + approving → 终审确认卡 (0.274622ms)
|
||||
✔ resolveDocGovCard: 编制人 OTHER → 引导查询无危险按钮 (0.128557ms)
|
||||
✔ canConfirmReject: 仅审核/批准 (0.537784ms)
|
||||
✔ deriveFallbackCategory identifies categories correctly (0.870374ms)
|
||||
✔ enrichMessagesWithCategories backfills categories without overwriting existing ones (0.313601ms)
|
||||
✔ Markdown ➔ Block AST 解析测试 (标题自适应编号与图表公式全链路) (4.275193ms)
|
||||
✔ 动态重编号引擎测试 (多 H1 规范章节重排验证) (0.980431ms)
|
||||
✔ Block AST ➔ Markdown 双向无损往返还原测试 (0.843655ms)
|
||||
✔ 三层交付物多用户隐私绝对隔离测试 (Multi-user Strict Privacy Isolation) (1.088098ms)
|
||||
✔ 一键共享至项目参考库流转测试 (Promote to Shared Reference Test) (0.221383ms)
|
||||
✔ 撤回共享恢复私有草稿测试 (Revoke Shared Reference Test) (0.408948ms)
|
||||
✔ 受控工作流纯净性红线检验 (Workflow Purity Security Red Line) (0.129456ms)
|
||||
✔ isSameMessage: clientTurnId match (1.861744ms)
|
||||
✔ isSameMessage: serverId match without turn (0.175055ms)
|
||||
✔ filterPendingLiveMessages: real temp vs server id (0.137566ms)
|
||||
✔ mergeLiveOverHistory preserves server id from live (0.173595ms)
|
||||
✔ mergeLiveOverHistory does not let inflight live mask terminal history (0.134716ms)
|
||||
✔ mergeLiveOverHistory keeps live terminal over history inflight (0.112497ms)
|
||||
✔ applyPhaseEvent: appends first phase as running node (1.403038ms)
|
||||
✔ applyPhaseEvent: completes predecessors when a new phase arrives (0.249813ms)
|
||||
✔ applyPhaseEvent: same phase refreshes label in place (no duplicate node) (0.243692ms)
|
||||
✔ applyPhaseEvent: unknown phase falls back to hourglass meta (0.130056ms)
|
||||
✔ applyPhaseEvent: prefers backend message over short label (0.114206ms)
|
||||
✔ applyPhaseEvent: step_completed closes running entry without appending (0.239473ms)
|
||||
✔ applyPhaseEvent: stage_completed closes entries (0.163325ms)
|
||||
✔ applyPhaseEvent: task_failed appends warning node (0.133246ms)
|
||||
✔ applyPhaseEvent: decorates label with step index / total steps (0.137436ms)
|
||||
✔ applyPhaseEvent: repeated step_executing with step_index gets separate nodes (0.200365ms)
|
||||
✔ applyPhaseEvent: ignores event without phase payload (0.097807ms)
|
||||
✔ applyPhaseEvent: step_failed marks running entry as failed (keeps step label) (0.114317ms)
|
||||
✔ applyPhaseEvent: step_failed appends failed node when no running entry exists (1.234163ms)
|
||||
✔ applyPhaseEvent: retry of a failed step resets it to running (0.141366ms)
|
||||
✔ applyPhaseEvent: stores detail from phase.message (0.075458ms)
|
||||
✔ PHASE_META: document_parsing and document_summarizing are registered (0.114747ms)
|
||||
✔ PLAN_CONFIRM 卡片来自 PlanView 且不触达 AST (1.988191ms)
|
||||
✔ 409 冲突把卡片标为 outdated 并换上最新 revision (0.252702ms)
|
||||
✔ GET reconcile 用权威 PlanView 覆盖本地 executing,不假装成功 (0.226923ms)
|
||||
✔ 过期计划映射 expired (0.125736ms)
|
||||
✔ 非计划卡不被误判 (0.112107ms)
|
||||
✔ 集成验证:项目切换时交付物严格隔离,新建项目即刻包含 7 份模板副本 (6.355481ms)
|
||||
✔ 集成验证:三层隐私与项目物理隔离双重约束 (8.259005ms)
|
||||
✔ 用例 1: DEFAULT_ROLES 包含 5 种默认角色且具备预期权限 (4.314872ms)
|
||||
✔ 用例 2: 系统管理员 (ADMIN) 与具备 perm:manage 用户的通配豁免特权 (0.226003ms)
|
||||
✔ 用例 3: 常规工作流基线可见性 (workflow:view_all) 判定 (0.249052ms)
|
||||
✔ 用例 4: 单文档覆盖 - designated_only (仅编制/审核/批准人可见,其他用户被精确拦截) (0.145636ms)
|
||||
✔ 用例 5: 单文档覆盖 - role_whitelist (仅白名单内角色可见,其他角色被精确拦截) (0.127306ms)
|
||||
✔ 用例 6: 单文档覆盖 - public (放宽可见性,无 workflow:view_all 权限的访客也能查阅) (0.100067ms)
|
||||
✔ 用例 7: 私密文档隔离强红线 (category === private 无论任何管理员或单文档覆盖,非创建者绝对不可见) (0.111796ms)
|
||||
✔ 用例 8: 核心业务动作权限拦截判定 (canPerformDocAction & hasPermission) (0.149616ms)
|
||||
✔ 用例 9: filterVisibleDeliverablesWithRBAC 能够批处理过滤大盘交付物 (5.913474ms)
|
||||
✔ 集成场景 1: 动态新增合规审计员角色,并配置其仅能查阅特定单文档覆盖 (1.047099ms)
|
||||
✔ 集成场景 2: 服务端 capabilities 变更后权限即刻生效 (0.168345ms)
|
||||
✔ 集成场景 3: 单文档覆盖 designated_only 严格收紧与撤回恢复全流程 (0.148375ms)
|
||||
✔ renderInlineMarkdown: renders bold, italic, strikethrough (1.362779ms)
|
||||
✔ renderInlineMarkdown: escapes raw HTML tags to prevent XSS (0.653981ms)
|
||||
✔ renderInlineMarkdown: blocks javascript: link hrefs (0.305061ms)
|
||||
✔ renderInlineMarkdown: renders inline code and preserved line breaks (0.290592ms)
|
||||
✔ renderInlineMarkdown: renders headings lists and tables for chat replies (0.487936ms)
|
||||
✔ renderInlineMarkdown loads katex only after a formula is seen (19.51147ms)
|
||||
✔ sanitizeMermaidCode: auto wraps unquoted labels containing brackets or comparison operators (0.422077ms)
|
||||
(node:1877659) ExperimentalWarning: localStorage is not available because --localstorage-file was not provided.
|
||||
(Use `node --trace-warnings ...` to show where the warning was created)
|
||||
✔ DOCX 渲染器行内文本与公式解析测试 (parseInlineContent) (4.879835ms)
|
||||
✔ DOCX 渲染器 LaTeX 原生 OMML 转换引擎测试 (latexToOmml) (2.009401ms)
|
||||
✔ DOCX 渲染器 Mermaid 语法净化与容错测试 (sanitizeMermaidCode) (0.3103ms)
|
||||
✔ DOCX 渲染器 SVG 净化防 Canvas 污染测试 (cleanSvgForCanvas) (0.367549ms)
|
||||
✔ DOCX 渲染器全量编译测试 (buildDocxModel & exportDocumentToDocx) (61.249852ms)
|
||||
✔ XLSX 渲染器多表提取与工作簿编译测试 (buildXlsxWorkbook & exportDocumentToXlsx) (6.587554ms)
|
||||
▶ Reply Document IR & Export Engine
|
||||
✔ deriveReplyTitle and sanitizeFilename derive title and safe file name (1.768507ms)
|
||||
✔ deriveReplyTitle handles text without heading (0.285461ms)
|
||||
✔ parseReplyMarkdown parses headers, lists, code, and tables (1.728138ms)
|
||||
✔ renderClipboardHtml renders self-contained styling for office tools (0.462936ms)
|
||||
✔ renderClipboardHtml converts LaTeX formulas to native MathML for Word/Office (4.016571ms)
|
||||
✔ renderPlainText strips formatting cleanly (0.481286ms)
|
||||
✔ serializeMarkdown round-trips to valid markdown (0.33855ms)
|
||||
✔ stripUnsafeHtml strips script tags and dangerous event handlers (0.549014ms)
|
||||
✔ escapeHtml escapes math error payloads used by BlockEditorModal catch path (0.196264ms)
|
||||
✔ Reply Document IR & Export Engine (11.579927ms)
|
||||
✔ createProjectTemplateDeliverables: 必须精确生成 7 份全生命周期受控文档副本 (3.852105ms)
|
||||
✔ resolveRequirementsTaskKey prefers intake for 初始需求表 (1.199405ms)
|
||||
✔ resolveRequirementsTaskKey selects user_requirements for explicit URS (0.156685ms)
|
||||
✔ UI-02 first-round prompt with 首轮+用户需求+摸底 must be intake not user_requirements (0.478466ms)
|
||||
✔ 首轮 / 需求摸底 / 摸底 beat bare 用户需求 (0.106416ms)
|
||||
✔ bare 用户需求 without V0.1 markers stays user_requirements (0.107757ms)
|
||||
✔ matchTemplateDeliverable uses intake key when pool only has URS template (0.258242ms)
|
||||
✔ resolveTaskTemplateForMessage keeps intake key with URS-only pool (0.149816ms)
|
||||
✔ matchTemplateDeliverable prefers intake when both templates exist (0.126717ms)
|
||||
✔ read-only request does not start a document task: 总结一下用户初始需求表 (0.294921ms)
|
||||
✔ read-only request does not start a document task: 查看用户初始需求表 (0.145125ms)
|
||||
✔ read-only request does not start a document task: 用户初始需求表现在谁在编辑 (0.090967ms)
|
||||
✔ read-only request does not start a document task: 分析一下用户需求表里的风险 (0.070788ms)
|
||||
✔ read-only request does not start a document task: 用户初始需求表 (0.054098ms)
|
||||
✔ explicit write action still starts intake (0.136246ms)
|
||||
✔ explicit update action still starts URS (0.190135ms)
|
||||
✔ UI-05 prompt without active doc still keyword-routes to feasibility_reg (0.294701ms)
|
||||
✔ UI-05 prompt + registered intake pins intake and doc_proj6109_intake (0.235983ms)
|
||||
✔ read-only current-doc request does not start a task (0.071978ms)
|
||||
✔ summary/analysis with write verbs stays chat (read-only priority) (0.089587ms)
|
||||
✔ pure write intent still routes to task (0.053668ms)
|
||||
✔ template-only active slot is not pinned; keywords still apply (0.096717ms)
|
||||
✔ explicit named deliverable can switch away from active intake (0.165225ms)
|
||||
✔ domain 注册法规 without current-doc deixis still routes feasibility_reg (0.088787ms)
|
||||
✔ mismatched title vs docId suffix prefers docId taskKey (0.093428ms)
|
||||
✔ deixis 当前文档 pins registered intake (0.095807ms)
|
||||
✔ deixis 本文件 pins registered intake (0.047478ms)
|
||||
✔ deixis 这份文档 pins registered intake (0.050108ms)
|
||||
✔ deixis 本文档 pins registered intake (0.044218ms)
|
||||
✔ deixis 本受控文档 pins registered intake (0.041788ms)
|
||||
✔ no active doc does not invent a pin (0.096247ms)
|
||||
✔ UI-11 named 系统设计输入 beats negated 需求 background (0.076237ms)
|
||||
✔ mixed generate-design + do-not-cover-requirements stays prelim_design (0.055108ms)
|
||||
✔ current-doc pin still wins when no other deliverable is named (0.083417ms)
|
||||
✔ v3 bd_ task key wins over unprefixed intake alias (0.124346ms)
|
||||
✔ word-order variants of the intake sheet stay on intake, not the shorter URS title (0.195294ms)
|
||||
✔ resolveTaskTemplateForMessage blocks cross-workflow document mentions (2.185825ms)
|
||||
✔ resolveTaskTemplateForMessage keeps in-scope main docs when active is main (0.129286ms)
|
||||
✔ weighted mode does not let a cross-workflow title hijack an in-scope write (0.537474ms)
|
||||
✔ progress question is read-only; explicit start still resolves research (0.093728ms)
|
||||
▶ document revision overlay modes
|
||||
✔ pure hides all decorations (0.811806ms)
|
||||
✔ manual only marks human hunks (0.160956ms)
|
||||
✔ all marks human and agent differently (0.137306ms)
|
||||
✔ same human hunk stays amber in manual and all (no pairwise style guarantee) (0.135026ms)
|
||||
✔ exposes needs-content error code for empty orphan docs (0.094397ms)
|
||||
✔ matches overlay hunks by section or text when ids differ (0.272582ms)
|
||||
✔ aligns client block ids from head_block_map by order (0.217134ms)
|
||||
✔ document revision overlay modes (2.925713ms)
|
||||
▶ toolbar refresh + report entry reachability
|
||||
✔ pickLatestChangeReportId prefers highest version with report (0.33787ms)
|
||||
✔ first squad run alone still exposes a reachable report id (0.165395ms)
|
||||
✔ second squad run keeps both history report entries and latest shortcut (0.778567ms)
|
||||
✔ revisionRefreshKey is an independent refresh signal from docId (0.127386ms)
|
||||
✔ toolbar refresh + report entry reachability (1.69243ms)
|
||||
▶ change report view model
|
||||
✔ surfaces risk items, project impact, doc impacts with advice, and open questions (0.67743ms)
|
||||
✔ marks complete analysis as PI narrative vs factual fields (0.187924ms)
|
||||
✔ preferReportId prioritizes pending over committed latest (0.096757ms)
|
||||
✔ change report view model (1.147986ms)
|
||||
▶ revisionToolbarMount
|
||||
✔ exposes clear non-error template preview hint copy (2.417999ms)
|
||||
✔ template doc-p + isTemplateOnly=true does not mount (0.162285ms)
|
||||
✔ legacy doc-001 does not mount (0.156295ms)
|
||||
✔ unregistered doc-upload orphan does not mount (must register first) (0.145726ms)
|
||||
✔ server-registered upload (doc-free) and freeform mount (0.156935ms)
|
||||
✔ canonical doc_proj and generated non-template doc-p mount (0.193634ms)
|
||||
✔ revisionToolbarMount (4.318292ms)
|
||||
✔ login workspace sync lives in one hook (1.204984ms)
|
||||
✔ block editing lives in one hook (0.957632ms)
|
||||
✔ interactive card actions live in one hook (1.048618ms)
|
||||
✔ useChatWindow: 所有 saveSessionWindowCache 调用必须传入 userId (1.066258ms)
|
||||
✔ loadOlder race: stale resolve ignored by generation (1.557084ms)
|
||||
✔ window fetch race: stale response ignored by generation (4.517886ms)
|
||||
✔ mapRecordToMessage: 正确映射服务端消息记录为前端 ChatMessage (1.654151ms)
|
||||
✔ refresh window: 空 messages 日桶不算有效窗口 (0.192455ms)
|
||||
✔ mapRawBucket: 正确映射服务端按日分片桶 (0.312121ms)
|
||||
✔ Category navigation: chip 选中后准确匹配目标分类最新轮次并触发归一化定位 (0.286702ms)
|
||||
✔ mapRecordToMessage: restores task phase snapshot into card fields (0.236783ms)
|
||||
✔ mapRecordToMessage: run anchor without task_status stays streaming (0.180904ms)
|
||||
✔ controlled document hydration lives in one hook (1.096208ms)
|
||||
✔ project creation lives in one hook called before the login return (0.755868ms)
|
||||
✔ document lifecycle actions live in one hook (1.109877ms)
|
||||
✔ freeform document actions live in one hook (1.755868ms)
|
||||
✔ in-flight states cover pending and running only (6.667272ms)
|
||||
✔ hasInFlightParse detects parse polling needs (0.246373ms)
|
||||
✔ hook + reparse API surface wired (0.298551ms)
|
||||
✔ project member writes live in one hook before the login return (1.318591ms)
|
||||
✔ replay retries 502 and stops on auth or not-found (0.66772ms)
|
||||
✔ sending a message lives in one hook (1.01656ms)
|
||||
✔ server document list sync lives in one hook (1.393729ms)
|
||||
✔ chat and task attempts live in one hook (1.34513ms)
|
||||
✔ stage unresolved and not-in-active-stage degrade to chat once (0.155916ms)
|
||||
✔ failed run with error_message surfaces TASK_FAILED not NETWORK_ERROR (0.770138ms)
|
||||
✔ snake_case blocked_pending_governance is governance, not a network error (0.34381ms)
|
||||
✔ unknown 4xx business code is not reported as a network error (0.377559ms)
|
||||
✔ turn runtime: session A stream survives session B switch (0.649891ms)
|
||||
✔ abortAllSessions aborts controllers across all sessions (0.192954ms)
|
||||
✔ App persists workbench state through one hook and migrates legacy messages once (0.968861ms)
|
||||
✔ active task cache keeps an in-progress run and drops it when finished (1.106048ms)
|
||||
✔ syncAdminUserDirectories calls local reload then parent onRefreshUsers (1.624912ms)
|
||||
✔ syncAdminUserDirectories fails closed when onRefreshUsers is a dead/missing prop (0.614612ms)
|
||||
✔ syncAdminUserDirectories surfaces parent refresh errors (no silent swallow) (2.138076ms)
|
||||
✔ afterProjectMemberPersisted syncs members then refreshes workflow docs (1.172795ms)
|
||||
✔ afterProjectMemberPersisted does not refresh when member sync fails (0.463506ms)
|
||||
▶ blockEditorDialogPolicy
|
||||
✔ pins an accessible dialog label and exact save name (0.492506ms)
|
||||
✔ rejects page-wide fuzzy /保存/ that would hit private-library buttons (0.258003ms)
|
||||
✔ blockEditorDialogPolicy (1.557624ms)
|
||||
▶ resolveSaveTargetBlock
|
||||
✔ keeps the editor and does not fake success when the block id is gone (0.635451ms)
|
||||
✔ never retargets another block that happens to share the same content (0.705099ms)
|
||||
✔ resolveSaveTargetBlock (2.244724ms)
|
||||
▶ editor session document binding
|
||||
✔ fail-closes when activeDocId drifts away from the opened editor doc (0.173244ms)
|
||||
✔ accepts a save only when the editor is still bound to the active doc (0.099087ms)
|
||||
✔ blocks switching documents while the editor is open (0.139706ms)
|
||||
✔ editor session document binding (0.614882ms)
|
||||
▶ interpretBlockSaveError
|
||||
✔ 409 keeps the draft in the editor (0.170955ms)
|
||||
✔ other PATCH failures also keep the editor (0.192604ms)
|
||||
✔ interpretBlockSaveError (0.782167ms)
|
||||
▶ blockedGovernanceCopy
|
||||
✔ recognizes blocked run status and fixed hint, not generation success (0.736178ms)
|
||||
✔ blockedGovernanceCopy (1.654011ms)
|
||||
▶ resolveChatComposerStreaming
|
||||
✔ is false when no inflight assistant bubbles (0.472606ms)
|
||||
✔ is true when inflight bubble and live turn (0.106117ms)
|
||||
✔ is true when inflight bubble and live task run (0.078888ms)
|
||||
✔ is false for orphan streaming_status after runtime cleared (0.059708ms)
|
||||
✔ resolveChatComposerStreaming (1.616372ms)
|
||||
▶ commentPolicy
|
||||
✔ applies stage matrix for add (0.6784ms)
|
||||
✔ keeps viewer read-only (0.206644ms)
|
||||
✔ resolves author role literally (0.119417ms)
|
||||
✔ gates resolve by stage (0.206814ms)
|
||||
✔ commentPolicy (4.325182ms)
|
||||
▶ controlledContentInvalidation
|
||||
✔ hydrate success then late list_sync keeps cache/ready and does not bump resume (1.722119ms)
|
||||
✔ post_task invalidation drops active cache and requires a new hydrate epoch (0.221513ms)
|
||||
✔ editor open / save epoch keeps draft and rejects a stale GET after PATCH (0.351609ms)
|
||||
✔ never drops the active doc without signaling rehydrate (0.138126ms)
|
||||
✔ candidate helper keeps template / doc-001 / freeform / upload out of wipe lists (0.450837ms)
|
||||
✔ dropRecordKeys is a no-op when ids are absent (0.219383ms)
|
||||
✔ controlledContentInvalidation (4.35165ms)
|
||||
▶ controlledDocHydrate
|
||||
✔ shouldLoadControlledContent when non-template workflow doc (3.012441ms)
|
||||
✔ shouldLoadControlledContent rejects local legacy/mock ids like doc-001 (0.181415ms)
|
||||
✔ shouldLoadControlledContent keeps canonical, freeform-off, and template preview rules (0.164175ms)
|
||||
✔ hydrateControlledDocumentContent never requests content/revision for doc-001 (0.383468ms)
|
||||
✔ hydrateControlledDocumentContent never requests for template preview or registered freeform (0.181555ms)
|
||||
✔ shouldLoadControlledContent stays inside toolbar server-backed eligibility (0.313571ms)
|
||||
✔ resolveCanonicalDocId maps doc-p56-intake to doc_proj56_intake (0.490665ms)
|
||||
✔ canonicalDocIdForTask maps doc-p56-research to doc_proj56_research (0.230063ms)
|
||||
✔ hydrate treats projection missing as ledger content, not 404 (1.823986ms)
|
||||
✔ attaches hydrate ETag as PATCH baseline and ignores a later GET (1.028349ms)
|
||||
✔ rejects hydrate when revision-state network or 5xx fails (0.841565ms)
|
||||
✔ aligns markdownToBlockAST random ids onto revision-state head_block_map (1.830716ms)
|
||||
✔ leaves Math.random ids when head_block_map is omitted (why gate + fail-closed remain) (1.067668ms)
|
||||
✔ rejects controlled hydrate on NOT_FOUND or NEEDS_CONTENT (0.377559ms)
|
||||
✔ fingerprint stays stable when only object identity changes (0.269112ms)
|
||||
✔ dedupes in-flight hydrate for the same doc fingerprint (0.449247ms)
|
||||
✔ aligned late hydrate still cannot overwrite a PATCH-success baseline (0.455086ms)
|
||||
✔ controlledDocHydrate (15.550208ms)
|
||||
✔ createClientTurnId uses randomUUID when available (0.815456ms)
|
||||
✔ createClientTurnId falls back to getRandomValues UUID v4 (0.421077ms)
|
||||
✔ createClientTurnId throws when no secure random API exists (0.35659ms)
|
||||
✔ selectNonCreatorInitialMembers skips creator only (1.587573ms)
|
||||
✔ buildManagedMemberUpsertPayload sends document_duty on add/update/restore (0.270002ms)
|
||||
✔ buildInitialMemberUpsertPayload maps reviewer UI role to member API role (0.191914ms)
|
||||
✔ persistInitialProjectMembers awaits each add and stops on failure (0.65355ms)
|
||||
✔ ensureCreatedProjectWithMembers skips recreate on bootstrap id and retries members (0.549973ms)
|
||||
✔ beginCreateProjectSubmit rejects concurrent second entry until end (31.813816ms)
|
||||
✔ resolveCreateProjectSubmitPhase uses bootstrap to choose syncing label (0.723658ms)
|
||||
✔ createProjectSubmitButtonLabel and close block while submitting (0.200754ms)
|
||||
✔ shouldCloneMedicalTemplates skips the 7-pack for software domain (0.131006ms)
|
||||
▶ resolveCurrentDocRole
|
||||
✔ resolves A as author by authoritative user id (0.752448ms)
|
||||
✔ does not promote reviewer B or stranger to author (0.123077ms)
|
||||
✔ resolves real USER_B id as reviewer and never name-promotes placeholder 2 (0.095468ms)
|
||||
✔ fail-closes unknown identity to viewer even if projectPermission says author (0.076527ms)
|
||||
✔ matches name only for legacy local docs without duty ids (0.105767ms)
|
||||
✔ does not name-promote when server controlled duties are zero ids (0.160535ms)
|
||||
✔ resolveCurrentDocRole (3.184245ms)
|
||||
▶ currentProjectRestore
|
||||
✔ rejects empty project names (0.827155ms)
|
||||
✔ rejects page-wide project name when banner and sidebar both match (0.185724ms)
|
||||
✔ scopes the visible entry to complementary exact title (2.776877ms)
|
||||
✔ scopes the current project assertion to banner exact text (0.35035ms)
|
||||
✔ currentProjectRestore (5.071659ms)
|
||||
▶ deliverableLeaseSync
|
||||
✔ returns the same array reference when leases are unchanged (0.753007ms)
|
||||
✔ returns a new array only when a lease actually changes (0.177275ms)
|
||||
✔ deliverableLeaseSync (1.904263ms)
|
||||
▶ docGovActionVisibility
|
||||
✔ hides all approval actions on unmanaged docs (1.605673ms)
|
||||
✔ gates separated duties by user id, not folded role label (0.172974ms)
|
||||
✔ author_only: same user holds all three duties and sees all actions (0.106427ms)
|
||||
✔ author_only: non-duty user sees no actions (0.104037ms)
|
||||
✔ docGovActionVisibility (3.05592ms)
|
||||
▶ documentBlockDomAttrs
|
||||
✔ marks a real DocumentBlock in pure mode without overlay kind (1.241673ms)
|
||||
✔ keeps the same stable attrs when overlay is later attached separately (0.197974ms)
|
||||
✔ documentBlockDomAttrs (2.573574ms)
|
||||
✔ author can edit drafting when unlocked (0.720368ms)
|
||||
✔ active project member can edit drafting when unlocked (deny_only_submit) (0.129316ms)
|
||||
✔ non-member viewer cannot edit drafting (0.089708ms)
|
||||
✔ lease blocks edit even for author and member (0.093477ms)
|
||||
✔ reviewing is not editable via drafting affordance (0.080617ms)
|
||||
▶ durableBodySnippet
|
||||
✔ rejects empty persisted snippets (0.850954ms)
|
||||
✔ lets a later successful revision replace the old snippet (0.988341ms)
|
||||
✔ does not promote a conflict-failed draft to the expected body (0.174115ms)
|
||||
✔ durableBodySnippet (2.940223ms)
|
||||
▶ dutyCellAssertion
|
||||
✔ parses author, reviewer, and viewer from select value or badge role (0.890893ms)
|
||||
✔ must not infer author from a row whose option labels include 编制负责人 (0.499835ms)
|
||||
✔ accepts only a disabled non-assignable reviewer select (0.122916ms)
|
||||
✔ rejects an enabled reviewer select when the reviewer cannot assign leads (0.098187ms)
|
||||
✔ rejects canAssignLead=true even if the reviewer select is disabled (0.249163ms)
|
||||
✔ rejects viewer, author, approver, and unknown values for USER_B (0.265472ms)
|
||||
✔ dutyCellAssertion (6.592245ms)
|
||||
▶ decideHydrationApply
|
||||
✔ applies only when gen, doc, save epoch match and editor is closed (1.170076ms)
|
||||
✔ rejects a response for another document (0.146755ms)
|
||||
✔ rejects a superseded generation (0.104287ms)
|
||||
✔ decideHydrationApply (2.515795ms)
|
||||
▶ createEditorHydrationGate
|
||||
✔ does not start a new hydrate while the editor is open (UI-06 fill-window GET) (0.449467ms)
|
||||
✔ deferred hydrate that resolves after the editor opens does not replace the session (0.162255ms)
|
||||
✔ covers hydrate resolving between fill and save (0.149286ms)
|
||||
✔ asks for a hydrate resume after editor_open blocked the first apply (0.370859ms)
|
||||
✔ asks for a hydrate resume when beginHydration is skipped while editing (0.298281ms)
|
||||
✔ requestHydrationResume is consumed once after a protected edit session (0.252152ms)
|
||||
✔ late hydrate after a successful PATCH does not roll back the new baseline (0.412608ms)
|
||||
✔ createEditorHydrationGate (2.69034ms)
|
||||
▶ formatFileSize
|
||||
✔ renders bytes below 1KB without rounding to 0 (0.834686ms)
|
||||
✔ renders KB/MB with sensible precision (0.260662ms)
|
||||
✔ degrades gracefully for invalid input (0.270781ms)
|
||||
✔ formatFileSize (2.69142ms)
|
||||
▶ deliverableFromServerSummary
|
||||
✔ restores uploaded file routing metadata from server facts (0.903473ms)
|
||||
✔ keeps plain freeform docs without upload metadata on the editor path (0.214224ms)
|
||||
✔ handles legacy rows with filename but zero size gracefully (0.130076ms)
|
||||
✔ maps shared space to shared category (0.139396ms)
|
||||
✔ deliverableFromServerSummary (3.529395ms)
|
||||
✔ redactResourceUrl drops query and origin (1.247093ms)
|
||||
✔ summarizeResources flags deferred heavy chunks (1.146446ms)
|
||||
✔ firstPaintHeavyHits lists only deferred module paths (0.186145ms)
|
||||
✔ countInitRequests separates member fanout from session lists (0.283052ms)
|
||||
✔ percentile uses nearest-rank and stays null on empty input (0.167675ms)
|
||||
✔ summarizeLatencies reports p50/p75/p95 (0.216413ms)
|
||||
✔ mergeSessionUser prefers session identity over stale catalog entry (1.251713ms)
|
||||
▶ playwrightPhaseArtifacts
|
||||
✔ defaults unknown or empty UI_PHASE to main (0.723149ms)
|
||||
✔ keeps post-restart distinct from main so the second run cannot overwrite traces (0.178675ms)
|
||||
✔ keeps main results at the historical filename and isolates post-restart recordPass (2.574403ms)
|
||||
✔ shares phase-state and secrets across phases (0.211744ms)
|
||||
✔ defaults assets to the 2026-09-22 rerun tree, not project-143 history (0.330121ms)
|
||||
✔ refuses historical controlled-content and Round20 evidence dirs (2.076958ms)
|
||||
✔ lists closeout groups covering UI-03/05/06/07-08-09/11/13/post-restart (0.811166ms)
|
||||
✔ playwrightPhaseArtifacts (9.540066ms)
|
||||
✔ resolvePostTaskActiveDocId prefers server doc_proj for taskKey (0.9999ms)
|
||||
✔ resolvePostTaskActiveDocId honors preferred server doc id (0.195745ms)
|
||||
✔ shouldSwitchTemplateSlotToServer when active is local template slot (0.169585ms)
|
||||
✔ pollUntilPostTaskServerDoc retries until same taskKey server doc appears (0.495385ms)
|
||||
✔ pollUntilPostTaskServerDoc returns null after maxAttempts without relying on setState (0.206394ms)
|
||||
✔ mapServerProjectToProjectInfo maps creator and preserves local members (0.899954ms)
|
||||
✔ mergeProjectLists drops local-only demo seed projects by default (0.32681ms)
|
||||
✔ mergeProjectLists can retain local-only demo when explicitly opted in (0.158635ms)
|
||||
✔ documentDutyFromMemberRole maps UI reviewer and creator (0.739068ms)
|
||||
✔ exclusiveMemberRoleChange keeps a single reviewer (0.189214ms)
|
||||
✔ memberRoleFromDocumentDuty does not invent reviewer from access role (0.116077ms)
|
||||
✔ toApiProjectRole maps doc roles to member and creator to owner (0.735568ms)
|
||||
✔ fromApiProjectRole maps owner to creator for project creator (0.143375ms)
|
||||
✔ mapApiMemberToProjectMember builds UI record (0.188675ms)
|
||||
▶ projectSettingsDuties
|
||||
✔ toggles full to none by atomically clearing duties (1.726969ms)
|
||||
✔ blocks partial saves and locates required/governance issue codes (0.607871ms)
|
||||
✔ blocks activation preview when no document is under human approval (0.31043ms)
|
||||
✔ allows an all-none configurable draft without three members (0.430327ms)
|
||||
✔ requires three members once any document is managed (0.135766ms)
|
||||
✔ resolves author_only to A/A/A without three-member requirement (0.243022ms)
|
||||
✔ rejects author_only without author or with conflicting reviewers (0.159025ms)
|
||||
✔ mixed full + author_only still requires three members for the full doc (0.324181ms)
|
||||
✔ toggleAuthorOnly clears review/approve slots and restores on disable (0.178825ms)
|
||||
✔ folds later rdev stages and batches human approval keys (0.263173ms)
|
||||
✔ projectSettingsDuties (6.032391ms)
|
||||
▶ projectSettingsMode
|
||||
✔ enters frozen when can_edit_plan is false or the project is active (0.766867ms)
|
||||
✔ keeps an active workflow editable except the definition switch (0.161595ms)
|
||||
✔ stays planning only for an editable draft (0.076008ms)
|
||||
✔ lists enabled duties for the frozen snapshot and skips disabled tasks (0.714029ms)
|
||||
✔ keeps the local draft after PLAN_FROZEN refresh and switches to frozen (0.123676ms)
|
||||
✔ projectSettingsMode (2.846246ms)
|
||||
▶ recheckAck
|
||||
✔ requires an explicit acknowledgement before advance (0.745668ms)
|
||||
✔ recheckAck (1.588373ms)
|
||||
▶ revisionEtag
|
||||
✔ uses stale hydrate ETag for PATCH and never the latest GET (0.492745ms)
|
||||
✔ does not invent 0:0 when controlled hydrate misses etag or errors (0.153046ms)
|
||||
✔ refuses controlled save without a hydrate ETag (0.493985ms)
|
||||
✔ allows freeform bootstrap 0:0 only (0.125246ms)
|
||||
✔ revisionEtag (2.533935ms)
|
||||
▶ saveControlledBlockEdit
|
||||
✔ successful save calls PATCH once with bound docId, hydrate ETag, body and client_block_map (2.507325ms)
|
||||
✔ does not PATCH when editorDocId and activeDocId diverge (0.239383ms)
|
||||
✔ does not PATCH on stale block id and keeps the draft (0.185995ms)
|
||||
✔ 409 does not close the editor or drop the draft (0.854364ms)
|
||||
✔ network errors do not close the editor or drop the draft (0.441767ms)
|
||||
✔ saveControlledBlockEdit (5.514056ms)
|
||||
✔ parseProjectIdFromSessionId decodes sess-p{id}-u{user} (1.520394ms)
|
||||
✔ resolveSessionProjectId prefers explicit id then session id encoding (0.212014ms)
|
||||
✔ mapServerSessionToProjectSession fills project metadata (0.627971ms)
|
||||
✔ mergeSessionLists keeps local stage while applying server counts (0.223494ms)
|
||||
▶ squadCompletionObservation
|
||||
✔ accepts a directly completed adjacent assistant without requiring inflight (1.388318ms)
|
||||
✔ accepts a turn that passed through inflight then completed (0.127666ms)
|
||||
✔ rejects error terminals, missing correspondence, and visible errors (0.093147ms)
|
||||
✔ keeps waiting while still inflight and does not treat inflight as success (0.067458ms)
|
||||
✔ cancelInflightAssistantMessages settles only this-session assistant inflight (0.128636ms)
|
||||
✔ squadCompletionObservation (2.6832ms)
|
||||
✔ running bubble without phases needs replay (0.889653ms)
|
||||
✔ interrupted bubble without phases needs replay (1.515235ms)
|
||||
✔ bubble that already has phases is not replayed (0.164685ms)
|
||||
✔ completed bubble without snapshot needs replay for legacy rows (0.096507ms)
|
||||
✔ completed bubble with snapshot is not replayed (0.113237ms)
|
||||
✔ phase replay key ignores completed chatter (0.153825ms)
|
||||
✔ resolveTaskRunCardTitle prefers artifact title (0.909703ms)
|
||||
✔ resolveTaskRunCardTitle falls back to user message then taskKey (0.208703ms)
|
||||
✔ truncateTitle ellipsizes long text (0.164275ms)
|
||||
✔ formatTaskDuration covers seconds minutes hours (0.160255ms)
|
||||
✔ resolveTaskRunCardBadge maps terminal and live states (0.775347ms)
|
||||
✔ shouldRenderTaskRunCard keeps card shape when run id exists (0.158936ms)
|
||||
✔ runningPhaseDetail prefers live label when it differs from step (0.142095ms)
|
||||
✔ 403 revision denial is not reported as a network error (0.930763ms)
|
||||
✔ 403 author-duty denial surfaces draft-vs-submit guidance (0.157385ms)
|
||||
✔ DOC_DUTY_FORBIDDEN keeps draft-vs-submit guidance (0.754727ms)
|
||||
✔ TASK_SCOPE_UNRESOLVED names the missing workflow stage (0.094747ms)
|
||||
✔ resolveReconnectRunId prefers explicit opts and ignores attempt without opts (0.622101ms)
|
||||
✔ shouldSubscribeExistingRun only for in-flight statuses (0.139905ms)
|
||||
✔ isRemoteTaskTerminal covers confirmation and quality_failed (0.112477ms)
|
||||
✔ nextAttemptOpts carries retained runId for reconnect without new POST (1.610892ms)
|
||||
✔ template documents are labeled as preview, not 编制中 or 已生效受控 (0.958361ms)
|
||||
✔ turnAttachmentRefs keeps doc and parse facts (1.178685ms)
|
||||
✔ describeChatHttpFailure prefers the public validation error (0.460687ms)
|
||||
▶ uploadFreeformRegister
|
||||
✔ buildUploadClientKey prefers explicit hint then doc-upload stamp (0.955591ms)
|
||||
✔ registerUploadAttachments hard-fails without creating orphan on API error (16.603197ms)
|
||||
✔ registerUploadAttachments rejects local doc-upload id from server (0.370409ms)
|
||||
✔ registerUploadAttachments returns server doc-free ids and freeform facts (0.548384ms)
|
||||
✔ deliverableFromFreeformUpload maps server id and upload facts (0.167475ms)
|
||||
✔ buildUploadRegistrationMarkdown embeds real text content when provided (0.144066ms)
|
||||
✔ buildUploadRegistrationMarkdown keeps placeholder for binary files without textContent (0.250482ms)
|
||||
✔ registerUploadAttachments persists source file metadata as server facts (0.301371ms)
|
||||
✔ uploadFreeformRegister (20.688145ms)
|
||||
▶ workflowCategoryNavigation
|
||||
✔ private menu cannot see doc_proj* so it must switch to workflow before exact select (1.049129ms)
|
||||
✔ fail-closes when the workflow menu is showing but the exact doc is missing (0.190554ms)
|
||||
✔ label and taskKey opens always require the workflow category (0.170195ms)
|
||||
✔ workflowCategoryNavigation (3.520565ms)
|
||||
✔ rdev selection explains the CDO prerequisite (0.787547ms)
|
||||
✔ login shell does not statically import export, preview, admin, or chart engines (27.783405ms)
|
||||
▶ no external Google Fonts on login shell
|
||||
✔ index.html has no fonts.googleapis / fonts.gstatic (0.930232ms)
|
||||
✔ styles reference self-hosted fonts.css (0.365889ms)
|
||||
✔ no external Google Fonts on login shell (2.449468ms)
|
||||
▶ 用户上传文档多格式在线预览体系与渲染分流测试
|
||||
✔ 1. 上传附件时正确注入 sourceType: "uploaded_file" 与完整 fileMeta 元数据 (0.865104ms)
|
||||
✔ 2. 扩展名分类规则准确分发至对应的高保真渲染器类型 (0.258543ms)
|
||||
✔ 3. 受控工作流交付物严格隔离:绝不命中 FilePreviewPanel,保持 BlockRenderer 纯净 (0.176665ms)
|
||||
✔ 4. 上传文档支持受控流转:从个人私密一键共享至项目参考库后,在线预览依然可用且权限标态正确 (0.179385ms)
|
||||
✔ 用户上传文档多格式在线预览体系与渲染分流测试 (2.772037ms)
|
||||
▶ 项目立项、成员职责分配与退出留痕治理测试套件
|
||||
✔ 1. 默认项目库包含完整元数据与法定三权成员 (active 状态) (0.6818ms)
|
||||
✔ 2. 跨用户会话可见性严格隔离:未加入成员完全不可见 (0.273272ms)
|
||||
✔ 3. 创建者添加新成员并分配职责后,新成员即刻可见该项目会话 (0.165275ms)
|
||||
✔ 4. 中途加入后期退出 (exited):保留项目会话但标记已退出只读留痕 (0.162316ms)
|
||||
✔ 5. 超级管理员 (ADMIN) 享有全量通配可见与管理兜底特权 (0.093258ms)
|
||||
✔ 项目立项、成员职责分配与退出留痕治理测试套件 (2.459847ms)
|
||||
▶ 新建项目工程文档模板质量与纯净性保障套件(对标官方参考系统)
|
||||
✔ 1. 必须精确生成 7 份官方全流程受控工作流模板且标记纯净 (0.848355ms)
|
||||
✔ 2. 杜绝旧项目 CUSA-NeuroPulse 串号泄露,动态注入新项目信息 (0.701719ms)
|
||||
✔ 3. 严格对标参考系统模板规范要素,绝非 3 行残缺摘要 (0.411778ms)
|
||||
✔ 4. 缓存丢失场景下即时自愈重建 AST 能力验证 (0.532624ms)
|
||||
✔ 新建项目工程文档模板质量与纯净性保障套件(对标官方参考系统) (7.526547ms)
|
||||
▶ 用户上传文档私密归档与共享流转测试
|
||||
✔ 10 个评审项目均包含已共享的 URS 交付物与 AST,支持跨角色合规查阅且会话均以 assistant 闭环 (1.469307ms)
|
||||
✔ 用户上传附件自动生成私密交付物并在 AST 中建立隔离,支持流转至项目参考库 (1.644061ms)
|
||||
✔ 单轮对话支持一次上传多个文档(上限5个),批量生成私密交付物并遵循数量约束 (0.552124ms)
|
||||
✔ 用户上传文档私密归档与共享流转测试 (4.558774ms)
|
||||
▶ 工作流切换与消息展示时序测试套件
|
||||
✔ 1. 当存在历史 seed 消息且追加新实时消息时,新消息必须严格沉淀在末尾 (1.243133ms)
|
||||
✔ 2. 切回项目时相同正文不应因 temp/server id 差异重复展示 (0.185805ms)
|
||||
✔ 工作流切换与消息展示时序测试套件 (2.221984ms)
|
||||
✔ DeliverableItem 必须包含 projectId 与 isTemplateOnly 属性 (0.775697ms)
|
||||
ℹ tests 532
|
||||
ℹ suites 41
|
||||
ℹ pass 532
|
||||
ℹ fail 0
|
||||
ℹ cancelled 0
|
||||
ℹ skipped 0
|
||||
ℹ todo 0
|
||||
ℹ duration_ms 1586.5667
|
||||
|
||||
RUN v5.0.0 /home/weichen/projects/Agent-System/.worktrees/refresh-task-state-recovery-2026-09-28/web
|
||||
|
||||
|
||||
Test Files 3 passed (3)
|
||||
Tests 34 passed (34)
|
||||
Start at 06:12:03
|
||||
Duration 333ms (transform 67%, import 25%, tests 6%, worker 2%)
|
||||
|
||||
NPM_TEST:0
|
||||
@@ -0,0 +1,23 @@
|
||||
=== RUN TestWriteVerb_DingDesignPlanCrossFlow
|
||||
2026/09/28 04:05:41 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestWriteVerb_DingDesignPlanCrossFlow (0.00s)
|
||||
=== RUN TestWriteVerb_ZhidingDesignPlanOnRdev
|
||||
2026/09/28 04:05:41 INFO intent_recognition intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0.86
|
||||
--- PASS: TestWriteVerb_ZhidingDesignPlanOnRdev (0.00s)
|
||||
=== RUN TestWriteVerb_DecideIsNotWrite
|
||||
2026/09/28 04:05:41 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
2026/09/28 04:05:41 INFO intent_recognition intent=CASUAL_CHAT branch=AMBIGUOUS_FALLBACK confidence=0.2
|
||||
2026/09/28 04:05:41 INFO intent_recognition intent=QUERY_PROGRESS branch=NEW_INTENT_PREEMPT confidence=0.9
|
||||
--- PASS: TestWriteVerb_DecideIsNotWrite (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/intent 0.008s
|
||||
=== RUN TestSyncTriggerTask_Committed_KeepsSavedWording
|
||||
2026/09/28 04:05:41 INFO coordinator_route intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0 channel=SQUAD_FIXED reason=标准任务/阶段推进/工作流运行/长任务续跑指令,进入小队受控执行
|
||||
--- PASS: TestSyncTriggerTask_Committed_KeepsSavedWording (0.00s)
|
||||
=== RUN TestFormatTriggerTaskReply_QualityFailedOmitsHostPath
|
||||
--- PASS: TestFormatTriggerTaskReply_QualityFailedOmitsHostPath (0.00s)
|
||||
=== RUN TestSyncTriggerTask_PrerequisiteIsUserVisible
|
||||
2026/09/28 04:05:41 INFO coordinator_route intent=TRIGGER_TASK branch=NEW_INTENT_PREEMPT confidence=0 channel=SQUAD_FIXED reason=标准任务/阶段推进/工作流运行/长任务续跑指令,进入小队受控执行
|
||||
--- PASS: TestSyncTriggerTask_PrerequisiteIsUserVisible (0.00s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/coordinator 0.007s
|
||||
@@ -0,0 +1,2 @@
|
||||
ok chat-agent-system/internal/intent 0.078s
|
||||
ok chat-agent-system/internal/coordinator 0.015s
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"commit": "5e409c1eb237814723f65102cb221a3e2de42e6e",
|
||||
"source_tree": "64499b34881422207a82f220fa3f5ab5dfe1828b",
|
||||
"source_context": "git-archive",
|
||||
"recorded_at": "2026-09-27T20:36:33Z",
|
||||
"tags": {
|
||||
"app": "shuimu-agent-app:candidate-5e409c1eb237",
|
||||
"events": "shuimu-agent-events:candidate-5e409c1eb237",
|
||||
"pi-agent": "shuimu-pi-agent:candidate-5e409c1eb237"
|
||||
},
|
||||
"image_ids": {
|
||||
"app": "sha256:c1601783dd897617d9da5a8d5cffc9a05596f9c594742fc15f475705a5d0ab4c",
|
||||
"events": "sha256:c1601783dd897617d9da5a8d5cffc9a05596f9c594742fc15f475705a5d0ab4c",
|
||||
"pi-agent": "sha256:c26508b6bbee96bb8c9109f6ccc825b0e9f5f00255b582d0861f9955c590e714"
|
||||
},
|
||||
"image_digests": {
|
||||
"app": "shuimu-agent-app@sha256:c1601783dd897617d9da5a8d5cffc9a05596f9c594742fc15f475705a5d0ab4c",
|
||||
"events": "shuimu-agent-app@sha256:c1601783dd897617d9da5a8d5cffc9a05596f9c594742fc15f475705a5d0ab4c",
|
||||
"pi-agent": "shuimu-pi-agent@sha256:c26508b6bbee96bb8c9109f6ccc825b0e9f5f00255b582d0861f9955c590e714"
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"verdict": "pass",
|
||||
"commit": "5e409c1eb237814723f65102cb221a3e2de42e6e",
|
||||
"recorded_at": "2026-09-27T20:36:33Z",
|
||||
"runner_url": "http://127.0.0.1:18865",
|
||||
"model_id": "MiniMax-M2.7-highspeed",
|
||||
"protocol": "typed-result-v1",
|
||||
"image_digests": {
|
||||
"app": "shuimu-agent-app@sha256:c1601783dd897617d9da5a8d5cffc9a05596f9c594742fc15f475705a5d0ab4c",
|
||||
"events": "shuimu-agent-app@sha256:c1601783dd897617d9da5a8d5cffc9a05596f9c594742fc15f475705a5d0ab4c",
|
||||
"pi-agent": "shuimu-pi-agent@sha256:c26508b6bbee96bb8c9109f6ccc825b0e9f5f00255b582d0861f9955c590e714"
|
||||
},
|
||||
"suite": "nightly-real-pi-u8-four-workflows",
|
||||
"failure_class": "none",
|
||||
"evidence_refs": [
|
||||
"/home/weichen/projects/Agent-System/.doc/test-reports/assets/promotion-receipts/evidence-5e409c1eb237-20260927T183704Z/go-test.txt",
|
||||
"/home/weichen/projects/Agent-System/.doc/test-reports/assets/promotion-receipts/evidence-5e409c1eb237-20260927T183704Z/runner-health.json"
|
||||
]
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"expected": ["TestMultiIntentU8_RealPI_ConfirmGenerate_PG", "TestWorkflowGovernance_PiAgent_PG_FullChain", "TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain", "TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain", "TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain"], "observed": {"TestMultiIntentU8_RealPI_ConfirmGenerate_PG": ["PASS"], "TestWorkflowGovernance_PiAgent_PG_FullChain": ["PASS"], "TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain": ["PASS"], "TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain": ["PASS"], "TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain": ["PASS"]}, "passed": true}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
=== RUN TestMultiIntentU8_RealPI_ConfirmGenerate_PG
|
||||
2026/09/27 19:29:25 goose: no migrations to run. current version: 76
|
||||
2026/09/27 19:29:25 goose: no migrations to run. current version: 76
|
||||
2026/09/27 19:29:25 [kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable
|
||||
multi_intent_u8_piagent_pg_test.go:228: ✓ [1. awaiting] plan_id=pln_0d61966f4140bf750dcde9bf2e84252c revision=1 starts=0
|
||||
{"time":"2026-09-27T19:29:26.065360678Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6057,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927192924772010756c14228f52mVMawXH) (batch=1 est_tokens≈57)"}
|
||||
{"time":"2026-09-27T19:34:34.933496396Z","level":"INFO","msg":"taskrun_status_transition","run_id":"run_1790537365945499577","status":"completed","workspace_id":"/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev/intake_1790537366071288822","error":""}
|
||||
multi_intent_u8_piagent_pg_test.go:268: ✓ [2. real PI generate] run_id=run_1790537365945499577 status=completed elapsed=5m9s
|
||||
multi_intent_u8_piagent_pg_test.go:277: ✓ [3. idempotent replay] starts still 1
|
||||
multi_intent_u8_piagent_pg_test.go:287: ✓ [4. revoke] TaskRunAdapter denied
|
||||
multi_intent_u8_piagent_pg_test.go:310: ✓ [5. PG restart recovery] plan_id=pln_0d61966f4140bf750dcde9bf2e84252c status=executing
|
||||
multi_intent_u8_piagent_pg_test.go:321: ✓ [6. HTTP refresh] GET plan 486 bytes
|
||||
--- PASS: TestMultiIntentU8_RealPI_ConfirmGenerate_PG (309.23s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain
|
||||
{"time":"2026-09-27T19:34:34.945272597Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:34:34.954429555Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:34:34.961392248Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:149: ✓ [1. activate] instance=48 full=intake none=research(disabled until stage)
|
||||
{"time":"2026-09-27T19:34:35.300212097Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6058,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927193434002303342c14228f5DOEKagUf) (batch=1 est_tokens≈18)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:205: ✓ pi-agent bd_intake doc=doc_proj6058_bd_intake elapsed=5m38s
|
||||
workflow_governance_full_none_piagent_pg_test.go:220: ✓ [2. full intake] cross-user approve complete
|
||||
workflow_governance_full_none_piagent_pg_test.go:232: ✓ [3. advance V0.1] ok
|
||||
{"time":"2026-09-27T19:40:13.808480985Z","level":"WARN","msg":"material chunk index failed","file":"research_scope.md","project_id":6058,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927194012513851422c14228f5LGVQWUXL) (batch=1 est_tokens≈32)"}
|
||||
{"time":"2026-09-27T19:40:13.843141086Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927194012548709059c14228f5vv4MlGSD) (batch=1 est_tokens≈14)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:234: ✓ pi-agent research doc=doc_proj6058_bd_research elapsed=13m34s
|
||||
workflow_governance_full_none_piagent_pg_test.go:253: ✓ [4. none research] generate ok; submit-review denied HTTP 403
|
||||
workflow_governance_full_none_piagent_pg_test.go:282: ✓ [5. readiness] none does not block
|
||||
workflow_governance_full_none_piagent_pg_test.go:308: ✓ [6. advance V0.5] none non-blocking PASS
|
||||
workflow_governance_full_none_piagent_pg_test.go:318: ✓ [7. refresh] settings still readable
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain (1153.20s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
{"time":"2026-09-27T19:53:48.146973908Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:53:48.156873524Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:53:48.165357912Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [1. 项目创建] id=6059 code=pg-piagent-治-6a05e634 wf=main
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [2. 工作流激活] instance_id=49
|
||||
{"time":"2026-09-27T19:53:48.49578996Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6059,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927195347198641783c14228f5J6TSZTg4) (batch=1 est_tokens≈102)"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [3. pi-agent intake] doc=doc_proj6059_bd_intake title=用户初始需求收集表 elapsed=6m4s
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=main
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullChain (364.57s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain
|
||||
{"time":"2026-09-27T19:59:52.719259149Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:59:52.727973731Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:59:52.736926955Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [1. 项目创建] id=6060 code=pg-piagent-产-629d788e wf=product_manager
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [2. 工作流激活] instance_id=50
|
||||
{"time":"2026-09-27T19:59:53.045699026Z","level":"WARN","msg":"material chunk index failed","file":"intake_summary.md","project_id":6060,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927195951750252980c14228f53SCC45YU) (batch=1 est_tokens≈77)"}
|
||||
{"time":"2026-09-27T19:59:53.079992338Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927195951784770762c14228f5VOgqBs70) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [3. pi-agent system_reqs] doc=doc_proj6060_pm_system_reqs title=系统需求规格书 elapsed=17m39s
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=product_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain (1058.94s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain
|
||||
{"time":"2026-09-27T20:17:31.660650278Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T20:17:31.672257153Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T20:17:31.679944205Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [1. 项目创建] id=6061 code=pg-piagent-测-497b181b wf=test_manager
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [2. 工作流激活] instance_id=51
|
||||
{"time":"2026-09-27T20:17:32.00173052Z","level":"WARN","msg":"material chunk index failed","file":"verification_scope.md","project_id":6061,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927201730699255534c14228f53gTZpjNJ) (batch=1 est_tokens≈88)"}
|
||||
{"time":"2026-09-27T20:17:32.040011273Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927201730737390698c14228f53I4b1Cqz) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [3. pi-agent test_manager] doc=doc_proj6061_tm_system_verification title=系统验证方案及计划 elapsed=18m57s
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=test_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain (1137.69s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 4023.651s
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
=== RUN TestMultiIntentU8_RealPI_ConfirmGenerate_PG
|
||||
2026/09/27 18:37:05 goose: no migrations to run. current version: 76
|
||||
2026/09/27 18:37:05 goose: no migrations to run. current version: 76
|
||||
2026/09/27 18:37:05 [kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable
|
||||
multi_intent_u8_piagent_pg_test.go:228: ✓ [1. awaiting] plan_id=pln_109140def6593f29e80d463cc22de537 revision=1 starts=0
|
||||
{"time":"2026-09-27T18:37:05.714556865Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6052,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927183704422688182c14228f52SdOhQd1) (batch=1 est_tokens≈57)"}
|
||||
{"time":"2026-09-27T18:42:17.865734427Z","level":"INFO","msg":"taskrun_status_transition","run_id":"run_1790534225595811661","status":"completed","workspace_id":"/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev/intake_1790534225721291105","error":""}
|
||||
multi_intent_u8_piagent_pg_test.go:268: ✓ [2. real PI generate] run_id=run_1790534225595811661 status=completed elapsed=5m12s
|
||||
multi_intent_u8_piagent_pg_test.go:277: ✓ [3. idempotent replay] starts still 1
|
||||
multi_intent_u8_piagent_pg_test.go:287: ✓ [4. revoke] TaskRunAdapter denied
|
||||
multi_intent_u8_piagent_pg_test.go:310: ✓ [5. PG restart recovery] plan_id=pln_109140def6593f29e80d463cc22de537 status=executing
|
||||
multi_intent_u8_piagent_pg_test.go:321: ✓ [6. HTTP refresh] GET plan 485 bytes
|
||||
--- PASS: TestMultiIntentU8_RealPI_ConfirmGenerate_PG (312.52s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain
|
||||
{"time":"2026-09-27T18:42:17.877855777Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T18:42:17.888146732Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T18:42:17.895420186Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:149: ✓ [1. activate] instance=43 full=intake none=research(disabled until stage)
|
||||
{"time":"2026-09-27T18:42:18.212086593Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6053,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927184216923241093c14228f5xn0VCeLb) (batch=1 est_tokens≈18)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:205: pi-agent bd_intake HTTP 500: {"task_key":"bd_intake","artifact_title":"用户初始需求收集表","markdown_body":"","extracted_data":null,"attachments":null,"work_dir":"/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev/bd_intake_1790534538219730296","backend_used":"pi-agent","duration":42752775860,"success":false,"error_reason":"step step_01_organize failed: MISSING_TARGET"}
|
||||
--- FAIL: TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain (43.11s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
{"time":"2026-09-27T18:43:00.983514629Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T18:43:00.994237701Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T18:43:01.002411668Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [1. 项目创建] id=6054 code=pg-piagent-治-40a1667f wf=main
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [2. 工作流激活] instance_id=44
|
||||
{"time":"2026-09-27T18:43:01.324082297Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6054,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927184300033590564c14228f5ljOaDLM9) (batch=1 est_tokens≈102)"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [3. pi-agent intake] doc=doc_proj6054_bd_intake title=用户初始需求收集表 elapsed=5m9s
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=main
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullChain (309.76s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain
|
||||
{"time":"2026-09-27T18:48:10.741906742Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T18:48:10.752444379Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T18:48:10.760924457Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [1. 项目创建] id=6055 code=pg-piagent-产-fae1702b wf=product_manager
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [2. 工作流激活] instance_id=45
|
||||
{"time":"2026-09-27T18:48:11.076655652Z","level":"WARN","msg":"material chunk index failed","file":"intake_summary.md","project_id":6055,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927184809782195631c14228f539SpRont) (batch=1 est_tokens≈77)"}
|
||||
{"time":"2026-09-27T18:48:11.113256095Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927184809819177239c14228f5qh0GRTc0) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [3. pi-agent system_reqs] doc=doc_proj6055_pm_system_reqs title=系统需求规格书 elapsed=20m0s
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=product_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain (1199.90s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain
|
||||
{"time":"2026-09-27T19:08:10.643334732Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:08:10.655267647Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:08:10.661666627Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [1. 项目创建] id=6056 code=pg-piagent-测-3a00d5ad wf=test_manager
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [2. 工作流激活] instance_id=46
|
||||
{"time":"2026-09-27T19:08:10.973231026Z","level":"WARN","msg":"material chunk index failed","file":"verification_scope.md","project_id":6056,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927190809680227338c14228f5FJl3zDXd) (batch=1 est_tokens≈88)"}
|
||||
{"time":"2026-09-27T19:08:11.008141699Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927190809715440319c14228f5MSTlyNHh) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [3. pi-agent test_manager] doc=doc_proj6056_tm_system_verification title=系统验证方案及计划 elapsed=21m14s
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=test_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain (1274.56s)
|
||||
FAIL
|
||||
FAIL chat-agent-system/internal/server 3139.856s
|
||||
FAIL
|
||||
==> retry once after quality_failed/deadline/MISSING_TARGET flake...
|
||||
=== RUN TestMultiIntentU8_RealPI_ConfirmGenerate_PG
|
||||
2026/09/27 19:29:25 goose: no migrations to run. current version: 76
|
||||
2026/09/27 19:29:25 goose: no migrations to run. current version: 76
|
||||
2026/09/27 19:29:25 [kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable
|
||||
multi_intent_u8_piagent_pg_test.go:228: ✓ [1. awaiting] plan_id=pln_0d61966f4140bf750dcde9bf2e84252c revision=1 starts=0
|
||||
{"time":"2026-09-27T19:29:26.065360678Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6057,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927192924772010756c14228f52mVMawXH) (batch=1 est_tokens≈57)"}
|
||||
{"time":"2026-09-27T19:34:34.933496396Z","level":"INFO","msg":"taskrun_status_transition","run_id":"run_1790537365945499577","status":"completed","workspace_id":"/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev/intake_1790537366071288822","error":""}
|
||||
multi_intent_u8_piagent_pg_test.go:268: ✓ [2. real PI generate] run_id=run_1790537365945499577 status=completed elapsed=5m9s
|
||||
multi_intent_u8_piagent_pg_test.go:277: ✓ [3. idempotent replay] starts still 1
|
||||
multi_intent_u8_piagent_pg_test.go:287: ✓ [4. revoke] TaskRunAdapter denied
|
||||
multi_intent_u8_piagent_pg_test.go:310: ✓ [5. PG restart recovery] plan_id=pln_0d61966f4140bf750dcde9bf2e84252c status=executing
|
||||
multi_intent_u8_piagent_pg_test.go:321: ✓ [6. HTTP refresh] GET plan 486 bytes
|
||||
--- PASS: TestMultiIntentU8_RealPI_ConfirmGenerate_PG (309.23s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain
|
||||
{"time":"2026-09-27T19:34:34.945272597Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:34:34.954429555Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:34:34.961392248Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:149: ✓ [1. activate] instance=48 full=intake none=research(disabled until stage)
|
||||
{"time":"2026-09-27T19:34:35.300212097Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6058,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927193434002303342c14228f5DOEKagUf) (batch=1 est_tokens≈18)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:205: ✓ pi-agent bd_intake doc=doc_proj6058_bd_intake elapsed=5m38s
|
||||
workflow_governance_full_none_piagent_pg_test.go:220: ✓ [2. full intake] cross-user approve complete
|
||||
workflow_governance_full_none_piagent_pg_test.go:232: ✓ [3. advance V0.1] ok
|
||||
{"time":"2026-09-27T19:40:13.808480985Z","level":"WARN","msg":"material chunk index failed","file":"research_scope.md","project_id":6058,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927194012513851422c14228f5LGVQWUXL) (batch=1 est_tokens≈32)"}
|
||||
{"time":"2026-09-27T19:40:13.843141086Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927194012548709059c14228f5vv4MlGSD) (batch=1 est_tokens≈14)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:234: ✓ pi-agent research doc=doc_proj6058_bd_research elapsed=13m34s
|
||||
workflow_governance_full_none_piagent_pg_test.go:253: ✓ [4. none research] generate ok; submit-review denied HTTP 403
|
||||
workflow_governance_full_none_piagent_pg_test.go:282: ✓ [5. readiness] none does not block
|
||||
workflow_governance_full_none_piagent_pg_test.go:308: ✓ [6. advance V0.5] none non-blocking PASS
|
||||
workflow_governance_full_none_piagent_pg_test.go:318: ✓ [7. refresh] settings still readable
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain (1153.20s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
{"time":"2026-09-27T19:53:48.146973908Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:53:48.156873524Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:53:48.165357912Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [1. 项目创建] id=6059 code=pg-piagent-治-6a05e634 wf=main
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [2. 工作流激活] instance_id=49
|
||||
{"time":"2026-09-27T19:53:48.49578996Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6059,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927195347198641783c14228f5J6TSZTg4) (batch=1 est_tokens≈102)"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [3. pi-agent intake] doc=doc_proj6059_bd_intake title=用户初始需求收集表 elapsed=6m4s
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=main
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullChain (364.57s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain
|
||||
{"time":"2026-09-27T19:59:52.719259149Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:59:52.727973731Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T19:59:52.736926955Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [1. 项目创建] id=6060 code=pg-piagent-产-629d788e wf=product_manager
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [2. 工作流激活] instance_id=50
|
||||
{"time":"2026-09-27T19:59:53.045699026Z","level":"WARN","msg":"material chunk index failed","file":"intake_summary.md","project_id":6060,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927195951750252980c14228f53SCC45YU) (batch=1 est_tokens≈77)"}
|
||||
{"time":"2026-09-27T19:59:53.079992338Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927195951784770762c14228f5VOgqBs70) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [3. pi-agent system_reqs] doc=doc_proj6060_pm_system_reqs title=系统需求规格书 elapsed=17m39s
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=product_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain (1058.94s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain
|
||||
{"time":"2026-09-27T20:17:31.660650278Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T20:17:31.672257153Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T20:17:31.679944205Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [1. 项目创建] id=6061 code=pg-piagent-测-497b181b wf=test_manager
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [2. 工作流激活] instance_id=51
|
||||
{"time":"2026-09-27T20:17:32.00173052Z","level":"WARN","msg":"material chunk index failed","file":"verification_scope.md","project_id":6061,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927201730699255534c14228f53gTZpjNJ) (batch=1 est_tokens≈88)"}
|
||||
{"time":"2026-09-27T20:17:32.040011273Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927201730737390698c14228f53I4b1Cqz) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [3. pi-agent test_manager] doc=doc_proj6061_tm_system_verification title=系统验证方案及计划 elapsed=18m57s
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=test_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain (1137.69s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 4023.651s
|
||||
+1
@@ -0,0 +1 @@
|
||||
shared KB preflight OK 127.0.0.1:5432/regulations
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"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":"/home/weichen/projects/Agent-System/data/dev/workspaces","uptime":6767.175219496}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
# evidence-94c215d3 恢复说明
|
||||
|
||||
原始目录 `evidence-94c215d3…-171311Z`(nightly6 @ dev 94c215d3:五链真实 PI 全 PASS,
|
||||
其后候选镜像构建步失败 → infra_fail 收据)在 worktree 收口暂存搬运中被误删
|
||||
(.tmp-staging 已不存在,无法恢复原目录内的 expected-tests.json / runner-health.json / go-test.txt 分件)。
|
||||
|
||||
本目录归档同一运行在 /tmp/tsb-nightly/nightly6.log 的完整原始输出(含五例 PASS/耗时、
|
||||
expected-tests 校验通过后的 image build DIRTY_TREE 失败与 infra_fail 收据写入记录),
|
||||
作为该过程证据的真实来源备份。判定链以 5e409c1e(nightly7 全绿 PASS 收据)为准。
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
{"generation": 1576, "run_id": "58582b05-c06c-4c20-bd31-2c06027831d5", "status": "running"}
|
||||
env: MINIMAX_API_KEY len=126 tavily_keys=2
|
||||
==> nightly real-PI suite commit=94c215d36e09 runner=http://127.0.0.1:18865
|
||||
==> DATA_DIR=/home/weichen/projects/Agent-System/data/dev
|
||||
shared KB preflight OK 127.0.0.1:5432/regulations
|
||||
=== RUN TestMultiIntentU8_RealPI_ConfirmGenerate_PG
|
||||
2026/09/27 17:13:12 goose: no migrations to run. current version: 76
|
||||
2026/09/27 17:13:12 goose: no migrations to run. current version: 76
|
||||
2026/09/27 17:13:12 [kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable
|
||||
multi_intent_u8_piagent_pg_test.go:228: ✓ [1. awaiting] plan_id=pln_c962074513e2cd53c48f4b80150fff67 revision=1 starts=0
|
||||
{"time":"2026-09-27T17:13:12.681820385Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6047,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927171311387783833c14228f5fP5PZK2r) (batch=1 est_tokens≈57)"}
|
||||
{"time":"2026-09-27T17:19:33.890702477Z","level":"INFO","msg":"taskrun_status_transition","run_id":"run_1790529192556071349","status":"completed","workspace_id":"/home/weichen/projects/Agent-System/data/dev/workspaces/bizdev/intake_1790529192693648584","error":""}
|
||||
multi_intent_u8_piagent_pg_test.go:268: ✓ [2. real PI generate] run_id=run_1790529192556071349 status=completed elapsed=6m21s
|
||||
multi_intent_u8_piagent_pg_test.go:277: ✓ [3. idempotent replay] starts still 1
|
||||
multi_intent_u8_piagent_pg_test.go:287: ✓ [4. revoke] TaskRunAdapter denied
|
||||
multi_intent_u8_piagent_pg_test.go:310: ✓ [5. PG restart recovery] plan_id=pln_c962074513e2cd53c48f4b80150fff67 status=executing
|
||||
multi_intent_u8_piagent_pg_test.go:321: ✓ [6. HTTP refresh] GET plan 486 bytes
|
||||
--- PASS: TestMultiIntentU8_RealPI_ConfirmGenerate_PG (381.59s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain
|
||||
{"time":"2026-09-27T17:19:33.901979192Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:19:33.912304495Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:19:33.919476192Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:149: ✓ [1. activate] instance=38 full=intake none=research(disabled until stage)
|
||||
{"time":"2026-09-27T17:19:34.234595435Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6048,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927171932942038116c14228f5rmMmfqTs) (batch=1 est_tokens≈18)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:205: ✓ pi-agent bd_intake doc=doc_proj6048_bd_intake elapsed=4m44s
|
||||
workflow_governance_full_none_piagent_pg_test.go:220: ✓ [2. full intake] cross-user approve complete
|
||||
workflow_governance_full_none_piagent_pg_test.go:232: ✓ [3. advance V0.1] ok
|
||||
{"time":"2026-09-27T17:24:18.5979371Z","level":"WARN","msg":"material chunk index failed","file":"research_scope.md","project_id":6048,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927172417306287388c14228f5jxv16ywp) (batch=1 est_tokens≈32)"}
|
||||
{"time":"2026-09-27T17:24:18.633158575Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927172417337672932c14228f51RuHsBll) (batch=1 est_tokens≈14)"}
|
||||
workflow_governance_full_none_piagent_pg_test.go:234: ✓ pi-agent research doc=doc_proj6048_bd_research elapsed=13m58s
|
||||
workflow_governance_full_none_piagent_pg_test.go:253: ✓ [4. none research] generate ok; submit-review denied HTTP 403
|
||||
workflow_governance_full_none_piagent_pg_test.go:282: ✓ [5. readiness] none does not block
|
||||
workflow_governance_full_none_piagent_pg_test.go:308: ✓ [6. advance V0.5] none non-blocking PASS
|
||||
workflow_governance_full_none_piagent_pg_test.go:318: ✓ [7. refresh] settings still readable
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullNoneMixedChain (1122.75s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_FullChain
|
||||
{"time":"2026-09-27T17:38:16.64716614Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:38:16.655726396Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:38:16.66266847Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [1. 项目创建] id=6049 code=pg-piagent-治-ec1edd36 wf=main
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [2. 工作流激活] instance_id=39
|
||||
{"time":"2026-09-27T17:38:17.016344108Z","level":"WARN","msg":"material chunk index failed","file":"project_brief.md","project_id":6049,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927173815718971474c14228f5Nnu9ycXd) (batch=1 est_tokens≈102)"}
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [3. pi-agent intake] doc=doc_proj6049_bd_intake title=用户初始需求收集表 elapsed=4m51s
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:265: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=main
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_FullChain (291.34s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain
|
||||
{"time":"2026-09-27T17:43:07.983649214Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:43:07.99321182Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:43:08.000588331Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [1. 项目创建] id=6050 code=pg-piagent-产-e39edc4b wf=product_manager
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [2. 工作流激活] instance_id=40
|
||||
{"time":"2026-09-27T17:43:08.330541784Z","level":"WARN","msg":"material chunk index failed","file":"intake_summary.md","project_id":6050,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927174307039072005c14228f5ps0Y4TTH) (batch=1 est_tokens≈77)"}
|
||||
{"time":"2026-09-27T17:43:08.365551614Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927174307074004417c14228f5VYqAcHMo) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [3. pi-agent system_reqs] doc=doc_proj6050_pm_system_reqs title=系统需求规格书 elapsed=13m33s
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:279: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=product_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_ProductManager_FullChain (813.17s)
|
||||
=== RUN TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain
|
||||
{"time":"2026-09-27T17:56:41.152911299Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:56:41.163258861Z","level":"INFO","msg":"goose: no migrations to run. current version: 76"}
|
||||
{"time":"2026-09-27T17:56:41.170354291Z","level":"INFO","msg":"[kb] online=true dsn=postgres://regkb:***@127.0.0.1:5432/regulations?sslmode=disable"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [1. 项目创建] id=6051 code=pg-piagent-测-34dc1585 wf=test_manager
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [2. 工作流激活] instance_id=41
|
||||
{"time":"2026-09-27T17:56:41.491774337Z","level":"WARN","msg":"material chunk index failed","file":"verification_scope.md","project_id":6051,"err":"http 401 Unauthorized: 无效的令牌 (request id: 20260927175640199356760c14228f58Kq00tyV) (batch=1 est_tokens≈88)"}
|
||||
{"time":"2026-09-27T17:56:41.531040871Z","level":"INFO","msg":"[kb-retriever] embed failed: http 401 Unauthorized: 无效的令牌 (request id: 20260927175640238710728c14228f5qye8omGY) (batch=1 est_tokens≈21)"}
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [3. pi-agent test_manager] doc=doc_proj6051_tm_system_verification title=系统验证方案及计划 elapsed=19m29s
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [4. 文档批准] approve chain complete
|
||||
workflow_governance_piagent_pg_test.go:294: ✓ [5. 阶段推进] PG + pi-agent 治理全链路完成 wf=test_manager
|
||||
--- PASS: TestWorkflowGovernance_PiAgent_PG_TestManager_FullChain (1169.28s)
|
||||
PASS
|
||||
ok chat-agent-system/internal/server 3778.125s
|
||||
==> building candidate images for digest pin...
|
||||
{"code": "DIRTY_TREE", "message": "Source worktree must be clean; only generated build evidence is excepted", "status": "denied"}
|
||||
candidate image build failed
|
||||
/home/weichen/projects/Agent-System/.doc/test-reports/assets/promotion-receipts/94c215d36e090ad6c1541f64bd625067d7fce4fc.json
|
||||
wrote promotion receipt: /home/weichen/projects/Agent-System/.doc/test-reports/assets/promotion-receipts/94c215d36e090ad6c1541f64bd625067d7fce4fc.json
|
||||
infrastructure failure: candidate image build
|
||||
{"child_group_alive": false, "run_id": "58582b05-c06c-4c20-bd31-2c06027831d5", "status": "recovery_required"}
|
||||
@@ -28,6 +28,9 @@ KB_DB_PORT=5432
|
||||
|
||||
# 5. Cursor / LLM Agent Runner 服务
|
||||
PI_AGENT_RUNNER_PORT=18866
|
||||
# 与端口一致。本文件在根 .env 之后加载,可盖住根 .env 里的 dev runner URL。
|
||||
# launch-single.sh 在进程启动前未导出 URL 时仍按端口派生,避免 dev sidecar 泄漏。
|
||||
PI_AGENT_RUNNER_URL=http://127.0.0.1:18866
|
||||
AGENT_BACKEND=pi-agent
|
||||
AGENT_TIMEOUT=60m
|
||||
# app 与 pi-agent 容器共享(test 环境建议设置非空值)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
-- +goose Up
|
||||
-- 注册与管理员建号硬编码依赖 role-guest / role-engineer / role-director / role-tech-lead。
|
||||
-- 00015 仅把 role-admin 标为 is_system,其余四个标准角色可被角色管理删除,
|
||||
-- 且 goose 不会重跑种子、启动引导也不补角色,缺失后注册写入 user_role_bindings 触发 FK 23503。
|
||||
-- 幂等补种并升为系统角色(禁删、禁改名;权限矩阵仍可编辑)。
|
||||
|
||||
INSERT INTO system_roles (id, code, name, description, is_system) VALUES
|
||||
('role-director', 'DIRECTOR', '研发总监', '负责研发中心整体项目决策、立项审查、权限监督与终审批准。', true),
|
||||
('role-tech-lead', 'TECH_LEAD', '研发技术主管', '负责具体研发管线的进度把控、文档责任人分配与技术审核。', true),
|
||||
('role-engineer', 'ENGINEER', '方案工程师', '负责医疗器械规格设计、受控正文编制、技术测算与推演。', true),
|
||||
('role-guest', 'GUEST', '外部审计/访客', '默认最小权限,仅在被授权范围内查阅。', true)
|
||||
ON CONFLICT (id) DO UPDATE SET is_system = true;
|
||||
|
||||
INSERT INTO system_role_permissions (role_id, permission_id, effect)
|
||||
SELECT 'role-director', p.id, 'allow' FROM system_permissions p
|
||||
WHERE p.perm_key IN ('project:create','project:assign_lead','workflow:config_visibility','doc:override_visibility','doc:export','workflow:view_all')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO system_role_permissions (role_id, permission_id, effect)
|
||||
SELECT 'role-tech-lead', p.id, 'allow' FROM system_permissions p
|
||||
WHERE p.perm_key IN ('project:create','project:assign_lead','doc:override_visibility','doc:export','workflow:view_all')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO system_role_permissions (role_id, permission_id, effect)
|
||||
SELECT 'role-engineer', p.id, 'allow' FROM system_permissions p
|
||||
WHERE p.perm_key IN ('doc:export','workflow:view_all')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
INSERT INTO system_role_permissions (role_id, permission_id, effect)
|
||||
SELECT 'role-guest', p.id, 'allow' FROM system_permissions p
|
||||
WHERE p.perm_key IN ('doc:export')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- +goose Down
|
||||
UPDATE system_roles SET is_system = false
|
||||
WHERE id IN ('role-director', 'role-tech-lead', 'role-engineer', 'role-guest');
|
||||
@@ -0,0 +1,36 @@
|
||||
-- +goose Up
|
||||
-- 统一错误事件审计:HTTP 与异步失败按 code + request_id 检索。
|
||||
CREATE TABLE IF NOT EXISTS error_events (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
code TEXT NOT NULL,
|
||||
class TEXT NOT NULL DEFAULT 'fatal',
|
||||
http_status INT,
|
||||
request_id TEXT,
|
||||
session_id TEXT,
|
||||
workspace_id TEXT,
|
||||
module TEXT,
|
||||
phase_id TEXT,
|
||||
path TEXT,
|
||||
method TEXT,
|
||||
source TEXT NOT NULL DEFAULT 'http',
|
||||
upstream TEXT,
|
||||
actor_user_id BIGINT,
|
||||
retryable BOOLEAN NOT NULL DEFAULT false,
|
||||
user_message TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_error_events_request_id
|
||||
ON error_events (request_id);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_error_events_code_created
|
||||
ON error_events (code, created_at DESC);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_error_events_created
|
||||
ON error_events (created_at DESC);
|
||||
|
||||
-- +goose Down
|
||||
DROP INDEX IF EXISTS idx_error_events_created;
|
||||
DROP INDEX IF EXISTS idx_error_events_code_created;
|
||||
DROP INDEX IF EXISTS idx_error_events_request_id;
|
||||
DROP TABLE IF EXISTS error_events;
|
||||
@@ -368,3 +368,86 @@ func TestPiAgentRemoteRunner_BodyTooLargeDoesNotWrite(t *testing.T) {
|
||||
t.Fatal("must not materialize after body-too-large reject")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPiAgentRemoteRunner_DataRootMismatchSkipsRun(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
var runHits int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/health":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"data_dir": filepath.Join(dir, "other-root")})
|
||||
case "/v1/run":
|
||||
runHits++
|
||||
http.Error(w, "should not be called", http.StatusInternalServerError)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
res, err := agent.NewBackend("pi-agent", &config.Config{
|
||||
AgentBackend: "pi-agent",
|
||||
PiAgentRunnerURL: ts.URL,
|
||||
PiAgentModel: "MiniMax-M3",
|
||||
PiAgentProvider: "minimax",
|
||||
AgentTimeout: 5 * time.Second,
|
||||
}).Execute(context.Background(), agent.Request{
|
||||
WorkDir: dir, Prompt: "draft", Targets: []string{"output.md"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if res.Success || res.ErrorReason != "pi runner data root mismatch" {
|
||||
t.Fatalf("got success=%v reason=%q", res.Success, res.ErrorReason)
|
||||
}
|
||||
if strings.Contains(res.ErrorReason, dir) {
|
||||
t.Fatalf("reason leaked a path: %s", res.ErrorReason)
|
||||
}
|
||||
if runHits != 0 {
|
||||
t.Fatalf("/v1/run hits=%d", runHits)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPiAgentRemoteRunner_DataRootMatchStillRuns(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
var runHits int
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/health":
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"data_dir": dir})
|
||||
case "/v1/run":
|
||||
runHits++
|
||||
body := "ok"
|
||||
runID := filepath.Base(dir)
|
||||
rv := agent.BuildResultV1(runID, "success", false, "", []struct {
|
||||
RelPath string
|
||||
Content []byte
|
||||
}{{"output.md", []byte(body)}})
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"ok": true, "run_id": runID, "runner_protocol": "typed-v1",
|
||||
"patches": []map[string]string{{"rel_path": "output.md", "content": body}},
|
||||
"result_v1": rv,
|
||||
})
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
}))
|
||||
defer ts.Close()
|
||||
res, err := agent.NewBackend("pi-agent", &config.Config{
|
||||
AgentBackend: "pi-agent",
|
||||
PiAgentRunnerURL: ts.URL,
|
||||
PiAgentModel: "MiniMax-M3",
|
||||
PiAgentProvider: "minimax",
|
||||
AgentTimeout: 5 * time.Second,
|
||||
}).Execute(context.Background(), agent.Request{
|
||||
WorkDir: dir, Prompt: "draft", Targets: []string{"output.md"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !res.Success {
|
||||
t.Fatalf("matched data_dir must run: %s", res.ErrorReason)
|
||||
}
|
||||
if runHits != 1 {
|
||||
t.Fatalf("/v1/run hits=%d", runHits)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +83,31 @@ func TestMaterializeTargets_MissingAndEmptyFail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaterializeTargets_EmptyPatchKeepsExistingFile(t *testing.T) {
|
||||
workDir := t.TempDir()
|
||||
body := []byte("# 调研报告\n已写在盘上的正文\n")
|
||||
path := filepath.Join(workDir, "output.md")
|
||||
if err := os.WriteFile(path, body, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := MaterializeTargets(workDir, []string{"output.md"}, map[string][]byte{
|
||||
"output.md": nil,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(got["output.md"]) != string(body) {
|
||||
t.Fatalf("collected %q", got["output.md"])
|
||||
}
|
||||
disk, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(disk) != string(body) {
|
||||
t.Fatalf("disk overwritten with %q", disk)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaterializeTargets_RejectsSymlinkEscape(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
outside := t.TempDir()
|
||||
|
||||
@@ -6,11 +6,13 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/config"
|
||||
@@ -155,7 +157,60 @@ func (p *PiAgentBackend) runnerPayload(req Request, workDir string, remote bool,
|
||||
return body
|
||||
}
|
||||
|
||||
// runnerDataRoots caches a successful /health data_dir per runner URL.
|
||||
// A failed probe is not cached: the next call may try again, and this call skips the check.
|
||||
var runnerDataRoots sync.Map
|
||||
|
||||
func probeRunnerDataRoot(ctx context.Context, runnerURL string) (string, bool) {
|
||||
if v, ok := runnerDataRoots.Load(runnerURL); ok {
|
||||
root, _ := v.(string)
|
||||
return root, root != ""
|
||||
}
|
||||
probeCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
|
||||
defer cancel()
|
||||
httpReq, err := http.NewRequestWithContext(probeCtx, http.MethodGet, runnerURL+"/health", nil)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
client := &http.Client{Timeout: 2 * time.Second}
|
||||
resp, err := client.Do(httpReq)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", false
|
||||
}
|
||||
var body struct {
|
||||
DataDir string `json:"data_dir"`
|
||||
}
|
||||
if err := json.NewDecoder(io.LimitReader(resp.Body, 1<<20)).Decode(&body); err != nil {
|
||||
return "", false
|
||||
}
|
||||
root := filepath.Clean(strings.TrimSpace(body.DataDir))
|
||||
if root == "" || root == "." {
|
||||
return "", false
|
||||
}
|
||||
runnerDataRoots.Store(runnerURL, root)
|
||||
log.Printf("pi runner data_dir check passed")
|
||||
return root, true
|
||||
}
|
||||
|
||||
func workDirWithinRunnerRoot(workDir, root string) bool {
|
||||
rel, err := filepath.Rel(filepath.Clean(root), filepath.Clean(workDir))
|
||||
if err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *PiAgentBackend) executeRemote(ctx context.Context, runnerURL string, req Request, workDir string, timeout time.Duration) (*Result, error) {
|
||||
if root, ok := probeRunnerDataRoot(ctx, runnerURL); ok && !workDirWithinRunnerRoot(workDir, root) {
|
||||
// Do not include either path: the caller classifies this phrase, and paths leak host layout.
|
||||
log.Printf("pi runner data root mismatch; refusing /v1/run")
|
||||
return &Result{Success: false, ErrorReason: "pi runner data root mismatch"}, nil
|
||||
}
|
||||
|
||||
expectedRunID := filepath.Base(workDir)
|
||||
if expectedRunID == "" || expectedRunID == "." || expectedRunID == string(filepath.Separator) {
|
||||
expectedRunID = "unknown"
|
||||
|
||||
@@ -26,6 +26,8 @@ import (
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/docrevision"
|
||||
"chat-agent-system/internal/errcode"
|
||||
"chat-agent-system/internal/errorevents"
|
||||
"chat-agent-system/internal/events"
|
||||
"chat-agent-system/internal/freedoc"
|
||||
"chat-agent-system/internal/intent"
|
||||
@@ -184,6 +186,9 @@ func Assemble(cfg *config.Config, svc *bizdev.Service) (*Runtime, error) {
|
||||
intentflow.SetLLMSegmentProposer(&PiSegmentProposer{Backend: dialogueBackend, Model: model, DataDir: dataDir})
|
||||
}
|
||||
pool := parts.Pool
|
||||
if pool != nil {
|
||||
errorevents.Install(errorevents.NewStore(pool))
|
||||
}
|
||||
stores, storeErr := auth.NewStores(context.Background(), pool, cfg)
|
||||
if storeErr != nil {
|
||||
return nil, fmt.Errorf("auth store: %w", storeErr)
|
||||
@@ -239,6 +244,7 @@ func Assemble(cfg *config.Config, svc *bizdev.Service) (*Runtime, error) {
|
||||
stages := stageflow.New(svc)
|
||||
coordEngine.SetStageTaskRunner(stages)
|
||||
coordEngine.SetContextServices(parts.Ctx, parts.KB)
|
||||
coordEngine.SetSessionRunReader(sessionRunAdapter{mgr: taskMgr})
|
||||
if instSvc != nil && instSvc.Available() {
|
||||
coordEngine.SetInstanceService(instSvc)
|
||||
}
|
||||
@@ -608,6 +614,12 @@ func (r *Runtime) runStageAdvanceReminders(ctx context.Context) {
|
||||
n, err := r.Notify.ProcessStageAdvanceReminders(ctx)
|
||||
if err != nil {
|
||||
slog.Warn("stage advance reminder scan failed", "error", err)
|
||||
errcode.Report(ctx, errcode.Event{
|
||||
Code: "REMINDER_SCAN_FAILED",
|
||||
Module: "notification",
|
||||
Source: "async",
|
||||
Upstream: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if n > 0 {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"chat-agent-system/internal/app/intentflow"
|
||||
"chat-agent-system/internal/bizdev"
|
||||
"chat-agent-system/internal/chat"
|
||||
"chat-agent-system/internal/coordinator"
|
||||
"chat-agent-system/internal/ctxmgr"
|
||||
"chat-agent-system/internal/taskrun"
|
||||
)
|
||||
@@ -117,6 +118,10 @@ func (a chatTaskStarter) CreateAndStart(ctx context.Context, runID string, recor
|
||||
}, bizdev.StageRunRequest{}, resumeDir)
|
||||
}
|
||||
|
||||
func (a chatTaskStarter) BindAssistantMsgID(ctx context.Context, runID string, assistantMsgID int64) error {
|
||||
return a.inner.BindAssistantMsgID(ctx, runID, assistantMsgID)
|
||||
}
|
||||
|
||||
// BindChatSession attaches composition-root adapters onto a chat session.
|
||||
// Callers that keep a mutable intentflow.Service (e.g. server test hooks) should
|
||||
// prefer AdaptChat* helpers with their own fields so swaps stay visible.
|
||||
@@ -138,3 +143,25 @@ func (rt *Runtime) BindChatSession(sess *chat.Session, env string) {
|
||||
Environment: env,
|
||||
}
|
||||
}
|
||||
|
||||
type sessionRunAdapter struct {
|
||||
mgr *taskrun.Manager
|
||||
}
|
||||
|
||||
func (a sessionRunAdapter) LatestSessionRun(ctx context.Context, sessionID string) (*coordinator.SessionRunSnapshot, error) {
|
||||
if a.mgr == nil {
|
||||
return nil, nil
|
||||
}
|
||||
rec, err := a.mgr.LatestSessionRun(ctx, sessionID)
|
||||
if err != nil || rec == nil {
|
||||
return nil, err
|
||||
}
|
||||
return &coordinator.SessionRunSnapshot{
|
||||
RunID: rec.RunID,
|
||||
TaskKey: rec.TaskKey,
|
||||
Status: rec.Status,
|
||||
WorkspaceID: rec.WorkspaceID,
|
||||
ErrorMessage: rec.ErrorMessage,
|
||||
UpdatedAt: rec.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -145,6 +145,20 @@ func TestIdempotentHumanEditSameDigest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDutyAuthorizerAllowsDocumentAuthorCommit(t *testing.T) {
|
||||
rec := &docgov.DocumentRecord{DocID: "doc_flow_author_commit", AuthorID: 4, ApproverID: 9}
|
||||
auth := DutyAuthorizer()
|
||||
if err := auth.Authorize(context.Background(), Principal{UserID: 4}, rec, ActionCommit); err != nil {
|
||||
t.Fatalf("document author must pass agent commit: %v", err)
|
||||
}
|
||||
if err := auth.Authorize(context.Background(), Principal{UserID: 74}, rec, ActionCommit); err != uow.ErrPermissionDenied {
|
||||
t.Fatalf("non-author commit must be denied, got %v", err)
|
||||
}
|
||||
if err := auth.Authorize(context.Background(), Principal{UserID: 4}, rec, ActionEdit); err != nil {
|
||||
t.Fatalf("document author must still pass edit: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReauthDeniesWrongAuthor(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
gov := docgov.NewGovernanceEngine(nil)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"chat-agent-system/internal/config"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
@@ -161,6 +162,9 @@ func (s *PgStore) CreateUser(ctx context.Context, user *UserAccount) (*UserAccou
|
||||
`, user.Username, user.Name, roleLegacy, user.Status, user.MustChangePassword,
|
||||
user.RoleID, user.Position, user.Department, user.EmployeeID, user.Email).Scan(&id)
|
||||
if err != nil {
|
||||
if isUsernameConflict(err) {
|
||||
return nil, ErrUsernameExists
|
||||
}
|
||||
return nil, fmt.Errorf("insert user: %w", err)
|
||||
}
|
||||
|
||||
@@ -188,6 +192,20 @@ func (s *PgStore) CreateUser(ctx context.Context, user *UserAccount) (*UserAccou
|
||||
return s.GetUserByID(ctx, id)
|
||||
}
|
||||
|
||||
func isUsernameConflict(err error) bool {
|
||||
var pgErr *pgconn.PgError
|
||||
if !errors.As(err, &pgErr) || pgErr.Code != "23505" {
|
||||
return false
|
||||
}
|
||||
switch pgErr.ConstraintName {
|
||||
case "uq_users_username", "users_account_id_key", "users_username_key":
|
||||
return true
|
||||
default:
|
||||
name := strings.ToLower(pgErr.ConstraintName)
|
||||
return strings.Contains(name, "username") || strings.Contains(name, "account_id")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *PgStore) UpdateUser(ctx context.Context, user *UserAccount, actorID int64) (*UserAccount, error) {
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
UPDATE users SET
|
||||
|
||||
@@ -2,6 +2,7 @@ package auth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -80,6 +81,48 @@ func TestPgStore_SessionSurvivesNewStoreInstance(t *testing.T) {
|
||||
_ = store2.RevokeByTokenHash(ctx, tokenHash)
|
||||
}
|
||||
|
||||
func TestPgStore_CreateUserDuplicateUsername(t *testing.T) {
|
||||
pool := openTestPool(t)
|
||||
if pool == nil {
|
||||
return
|
||||
}
|
||||
defer pool.Close()
|
||||
|
||||
cfg := &config.Config{Env: "dev"}
|
||||
ctx := context.Background()
|
||||
store, err := auth.NewPgStore(pool, cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("NewPgStore: %v", err)
|
||||
}
|
||||
username := "dup_" + time.Now().Format("150405.000000")
|
||||
account := &auth.UserAccount{
|
||||
Username: username,
|
||||
Name: "重复探测",
|
||||
PasswordHash: "hash",
|
||||
Status: auth.StatusActive,
|
||||
RoleID: "role-guest",
|
||||
Position: "访客/待指派",
|
||||
}
|
||||
created, err := store.CreateUser(ctx, account)
|
||||
if err != nil {
|
||||
t.Fatalf("first CreateUser: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_, _ = pool.Exec(context.Background(), `DELETE FROM users WHERE id = $1`, created.ID)
|
||||
})
|
||||
_, err = store.CreateUser(ctx, &auth.UserAccount{
|
||||
Username: username,
|
||||
Name: "重复探测",
|
||||
PasswordHash: "hash",
|
||||
Status: auth.StatusActive,
|
||||
RoleID: "role-guest",
|
||||
Position: "访客/待指派",
|
||||
})
|
||||
if !errors.Is(err, auth.ErrUsernameExists) {
|
||||
t.Fatalf("duplicate username = %v, want ErrUsernameExists", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPgStore_DisabledUserSessionRejected(t *testing.T) {
|
||||
pool := openTestPool(t)
|
||||
if pool == nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -10,6 +11,9 @@ import (
|
||||
"chat-agent-system/internal/config"
|
||||
)
|
||||
|
||||
// ErrUsernameExists 用户名或 account_id 唯一约束冲突。调用方应返回 400,而不是基础设施 500。
|
||||
var ErrUsernameExists = errors.New("用户名已存在")
|
||||
|
||||
// AuthStore 用户与认证配置存储接口
|
||||
type AuthStore interface {
|
||||
GetUserByUsername(ctx context.Context, username string) (*UserAccount, error)
|
||||
@@ -162,7 +166,7 @@ func (s *MemoryStore) CreateUser(ctx context.Context, user *UserAccount) (*UserA
|
||||
|
||||
for _, existing := range s.users {
|
||||
if strings.EqualFold(existing.Username, user.Username) {
|
||||
return nil, fmt.Errorf("username already exists: %s", user.Username)
|
||||
return nil, ErrUsernameExists
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
)
|
||||
|
||||
func TestIsUsernameConflict(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
err error
|
||||
want bool
|
||||
}{
|
||||
{"username index", &pgconn.PgError{Code: "23505", ConstraintName: "uq_users_username"}, true},
|
||||
{"account id", &pgconn.PgError{Code: "23505", ConstraintName: "users_account_id_key"}, true},
|
||||
{"username key", &pgconn.PgError{Code: "23505", ConstraintName: "users_username_key"}, true},
|
||||
{"fk is not username", &pgconn.PgError{Code: "23503", ConstraintName: "user_role_bindings_role_id_fkey"}, false},
|
||||
{"other unique", &pgconn.PgError{Code: "23505", ConstraintName: "user_credentials_pkey"}, false},
|
||||
{"plain error", errors.New("insert user: boom"), false},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := isUsernameConflict(tc.err); got != tc.want {
|
||||
t.Fatalf("isUsernameConflict() = %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestErrUsernameExistsIsNotInfrastructureShaped(t *testing.T) {
|
||||
if !errors.Is(ErrUsernameExists, ErrUsernameExists) {
|
||||
t.Fatal("sentinel identity")
|
||||
}
|
||||
if ErrUsernameExists.Error() != "用户名已存在" {
|
||||
t.Fatalf("message = %q", ErrUsernameExists.Error())
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@ import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/app/uow"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/docrevision"
|
||||
"chat-agent-system/internal/projectworkflow"
|
||||
@@ -27,6 +29,17 @@ func autoRepairForControlledSquad(reqAutoRepair bool, docID string, docRec *docg
|
||||
return reqAutoRepair
|
||||
}
|
||||
|
||||
// squadCommitActor 让受控账本提交通过编制人职责门。
|
||||
// 触发者不是编制人时,以文档编制人作为 AutoCommitUserID,并把触发者写入 OnBehalfOf。
|
||||
// 触发者或编制人缺失时保持原触发者,避免把 0 写成代理身份。
|
||||
func squadCommitActor(triggerUserID int64, docRec *docgov.DocumentRecord) (int64, *int64) {
|
||||
if docRec == nil || docRec.AuthorID <= 0 || triggerUserID <= 0 || docRec.AuthorID == triggerUserID {
|
||||
return triggerUserID, nil
|
||||
}
|
||||
onBehalf := triggerUserID
|
||||
return docRec.AuthorID, &onBehalf
|
||||
}
|
||||
|
||||
func qualityFailedErrorReason(report *squad.QualityReport) string {
|
||||
if report == nil {
|
||||
return "质量门禁未通过"
|
||||
@@ -87,15 +100,20 @@ func (s *Service) finalizeSquadDeliverable(
|
||||
// Squad may have already written candidate body to workDir/output.md — pending must restore ledger head.
|
||||
if s.docRev != nil && docRec != nil && strings.TrimSpace(docRec.DocID) != "" {
|
||||
actor := docrevision.ActorSnapshot{SquadName: "bizdev-squad", Model: res.BackendUsed}
|
||||
commitUserID, onBehalfOf := squadCommitActor(req.UserID, docRec)
|
||||
mat, matErr := s.materializeAgentOutput(ctx, docrevision.AgentMaterializeRequest{
|
||||
DocID: docID, RunID: fmt.Sprintf("bizdev-%d-%s", time.Now().UnixNano(), req.TaskKey),
|
||||
ProposalID: appliedProposalID, OutputMarkdown: res.MarkdownBody,
|
||||
ProjectID: req.ProjectID, WorkDir: res.WorkDir,
|
||||
ActorKind: docrevision.ActorAgentSquad, ActorSnapshot: actor,
|
||||
AutoCommitUserID: req.UserID,
|
||||
OnBehalfOf: onBehalfOf,
|
||||
AutoCommitUserID: commitUserID,
|
||||
})
|
||||
if matErr != nil {
|
||||
reason := fmt.Sprintf("文档版本账本/变更报告落盘失败: %v", matErr)
|
||||
if errors.Is(matErr, uow.ErrPermissionDenied) {
|
||||
reason = fmt.Sprintf("触发用户非文档编制人,账本提交被拒: %v", matErr)
|
||||
}
|
||||
return &TaskRunResult{
|
||||
TaskKey: res.TaskKey,
|
||||
ArtifactTitle: res.ArtifactTitle,
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
package bizdev
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"chat-agent-system/internal/app/docflow"
|
||||
"chat-agent-system/internal/app/uow"
|
||||
"chat-agent-system/internal/config"
|
||||
"chat-agent-system/internal/docgov"
|
||||
"chat-agent-system/internal/docrevision"
|
||||
)
|
||||
|
||||
type recordingMaterializer struct {
|
||||
inner AgentOutputMaterializer
|
||||
got docrevision.AgentMaterializeRequest
|
||||
err error
|
||||
}
|
||||
|
||||
func (r *recordingMaterializer) MaterializeAgentOutput(ctx context.Context, req docrevision.AgentMaterializeRequest) (*docrevision.AgentMaterializeResult, error) {
|
||||
r.got = req
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
if r.inner == nil {
|
||||
return nil, errors.New("recording materializer has no inner")
|
||||
}
|
||||
return r.inner.MaterializeAgentOutput(ctx, req)
|
||||
}
|
||||
|
||||
func TestSquadCommitActor_UsesAuthorWhenTriggerDiffers(t *testing.T) {
|
||||
author, behalf := squadCommitActor(74, &docgov.DocumentRecord{AuthorID: 4})
|
||||
if author != 4 {
|
||||
t.Fatalf("commit actor want 4 got %d", author)
|
||||
}
|
||||
if behalf == nil || *behalf != 74 {
|
||||
t.Fatalf("on behalf want 74 got %v", behalf)
|
||||
}
|
||||
same, behalfSame := squadCommitActor(4, &docgov.DocumentRecord{AuthorID: 4})
|
||||
if same != 4 || behalfSame != nil {
|
||||
t.Fatalf("author trigger must not proxy: actor=%d behalf=%v", same, behalfSame)
|
||||
}
|
||||
missing, behalfMissing := squadCommitActor(74, &docgov.DocumentRecord{})
|
||||
if missing != 74 || behalfMissing != nil {
|
||||
t.Fatalf("unset author must keep trigger: actor=%d behalf=%v", missing, behalfMissing)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteTask_NonAuthorTriggerMaterializesAsAuthor(t *testing.T) {
|
||||
svc := MustNewService(t, &config.Config{DataDir: t.TempDir(), AgentBackend: "stub"})
|
||||
ctx := context.Background()
|
||||
const (
|
||||
projectID = int64(6022)
|
||||
authorID = int64(4)
|
||||
triggerID = int64(74)
|
||||
docID = "doc_proj6022_bd_intake"
|
||||
)
|
||||
if _, err := svc.docGov.CreateOrGetDocument(ctx, docID, projectID, "bd_intake", "用户初始需求收集表", "V0.1_triage", "", authorID, "admin", 0, "", authorID, "admin"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rec := &recordingMaterializer{inner: revMaterializer{rev: svc.docRev}}
|
||||
svc.SetAgentMaterializer(rec)
|
||||
|
||||
res, err := svc.ExecuteTask(ctx, TaskRunRequest{
|
||||
TaskKey: "intake", ProjectID: projectID, ProjectName: "测试项目",
|
||||
CustomerName: "C", DeviceType: "医疗器械", Backend: "stub",
|
||||
Timeout: 10 * time.Second, DocID: docID, UserID: triggerID,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("ExecuteTask: %v reason=%v", err, res)
|
||||
}
|
||||
if res == nil || !res.Success {
|
||||
t.Fatalf("non-author trigger must succeed, got %#v", res)
|
||||
}
|
||||
if rec.got.AutoCommitUserID != authorID {
|
||||
t.Fatalf("AutoCommitUserID want %d got %d", authorID, rec.got.AutoCommitUserID)
|
||||
}
|
||||
if rec.got.OnBehalfOf == nil || *rec.got.OnBehalfOf != triggerID {
|
||||
t.Fatalf("OnBehalfOf want %d got %v", triggerID, rec.got.OnBehalfOf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteTask_AuthorTriggerDoesNotSetOnBehalfOf(t *testing.T) {
|
||||
svc := MustNewService(t, &config.Config{DataDir: t.TempDir(), AgentBackend: "stub"})
|
||||
ctx := context.Background()
|
||||
const (
|
||||
projectID = int64(6023)
|
||||
authorID = int64(4)
|
||||
docID = "doc_proj6023_bd_intake"
|
||||
)
|
||||
if _, err := svc.docGov.CreateOrGetDocument(ctx, docID, projectID, "bd_intake", "用户初始需求收集表", "V0.1_triage", "", authorID, "admin", 0, "", 0, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rec := &recordingMaterializer{inner: revMaterializer{rev: svc.docRev}}
|
||||
svc.SetAgentMaterializer(rec)
|
||||
|
||||
res, err := svc.ExecuteTask(ctx, TaskRunRequest{
|
||||
TaskKey: "intake", ProjectID: projectID, ProjectName: "P",
|
||||
CustomerName: "C", DeviceType: "医疗器械", Backend: "stub",
|
||||
Timeout: 10 * time.Second, DocID: docID, UserID: authorID,
|
||||
})
|
||||
if err != nil || res == nil || !res.Success {
|
||||
t.Fatalf("author trigger failed: err=%v res=%#v", err, res)
|
||||
}
|
||||
if rec.got.AutoCommitUserID != authorID || rec.got.OnBehalfOf != nil {
|
||||
t.Fatalf("author path changed: user=%d behalf=%v", rec.got.AutoCommitUserID, rec.got.OnBehalfOf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteTask_NonAuthorPassesDutyAuthorizer(t *testing.T) {
|
||||
svc := MustNewService(t, &config.Config{DataDir: t.TempDir(), AgentBackend: "stub"})
|
||||
ctx := context.Background()
|
||||
const (
|
||||
projectID = int64(6024)
|
||||
authorID = int64(4)
|
||||
triggerID = int64(74)
|
||||
docID = "doc_proj6024_bd_intake"
|
||||
)
|
||||
if _, err := svc.docGov.CreateOrGetDocument(ctx, docID, projectID, "bd_intake", "用户初始需求收集表", "V0.1_triage", "", authorID, "admin", 0, "", 0, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc.SetAgentMaterializer(&docflow.Commands{Gov: svc.docGov, Rev: svc.docRev, Auth: docflow.DutyAuthorizer()})
|
||||
|
||||
res, err := svc.ExecuteTask(ctx, TaskRunRequest{
|
||||
TaskKey: "intake", ProjectID: projectID, ProjectName: "P",
|
||||
CustomerName: "C", DeviceType: "医疗器械", Backend: "stub",
|
||||
Timeout: 10 * time.Second, DocID: docID, UserID: triggerID,
|
||||
})
|
||||
if err != nil || res == nil || !res.Success {
|
||||
t.Fatalf("duty authorizer must accept author-proxy commit: err=%v reason=%v", err, errorReason(res))
|
||||
}
|
||||
if strings.Contains(errorReason(res), "permission denied") {
|
||||
t.Fatalf("permission denied leaked: %s", res.ErrorReason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteTask_PermissionDeniedNamesNonAuthor(t *testing.T) {
|
||||
svc := MustNewService(t, &config.Config{DataDir: t.TempDir(), AgentBackend: "stub"})
|
||||
ctx := context.Background()
|
||||
const docID = "doc_perm_denied"
|
||||
if _, err := svc.docGov.CreateOrGetDocument(ctx, docID, 77, "research", "调研", "V0.5", "", 4, "admin", 0, "", 0, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
svc.SetAgentMaterializer(&recordingMaterializer{err: uow.ErrPermissionDenied})
|
||||
|
||||
res, err := svc.ExecuteTask(ctx, TaskRunRequest{
|
||||
TaskKey: "research", ProjectID: 77, ProjectName: "P",
|
||||
CustomerName: "C", DeviceType: "医疗器械", Backend: "stub",
|
||||
Timeout: 10 * time.Second, DocID: docID, UserID: 74,
|
||||
})
|
||||
if err == nil || res == nil || res.Success {
|
||||
t.Fatalf("want visible permission failure, err=%v res=%#v", err, res)
|
||||
}
|
||||
if !strings.Contains(res.ErrorReason, "触发用户非文档编制人") {
|
||||
t.Fatalf("reason must name non-author denial, got %q", res.ErrorReason)
|
||||
}
|
||||
if !errors.Is(err, uow.ErrPermissionDenied) {
|
||||
t.Fatalf("sentinel must stay errors.Is compatible, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
type revMaterializer struct {
|
||||
rev *docrevision.Service
|
||||
}
|
||||
|
||||
func (r revMaterializer) MaterializeAgentOutput(ctx context.Context, req docrevision.AgentMaterializeRequest) (*docrevision.AgentMaterializeResult, error) {
|
||||
return r.rev.MaterializeAgentOutput(ctx, req)
|
||||
}
|
||||
|
||||
func errorReason(res *TaskRunResult) string {
|
||||
if res == nil {
|
||||
return ""
|
||||
}
|
||||
return res.ErrorReason
|
||||
}
|
||||
@@ -70,6 +70,7 @@ type IntentStepView struct {
|
||||
// TaskStarter starts a task run without exposing bizdev/stageflow request types to chat.
|
||||
type TaskStarter interface {
|
||||
CreateAndStart(ctx context.Context, runID string, record *taskrun.RunRecord, start TaskStartRequest, resumeDir string) (*taskrun.RunRecord, error)
|
||||
BindAssistantMsgID(ctx context.Context, runID string, assistantMsgID int64) error
|
||||
}
|
||||
|
||||
// TaskStartRequest carries the chat-owned fields needed to start or resume a run.
|
||||
|
||||
@@ -465,6 +465,9 @@ func (s *Session) sendMessageInternal(ctx context.Context, userInput string, str
|
||||
streamer.EmitPhase("dialogue_generating", "正在整理回复...", "assistant", 0, 0, 40)
|
||||
}
|
||||
s.EnsureDocResolver()
|
||||
if s.UserCtx != nil {
|
||||
s.UserCtx.ChatSessionID = s.ID
|
||||
}
|
||||
coordRes, err := s.Coordinator.ProcessIntent(ctx, recRes, s.UserCtx)
|
||||
if err != nil {
|
||||
if streamer != nil {
|
||||
@@ -473,11 +476,16 @@ func (s *Session) sendMessageInternal(ctx context.Context, userInput string, str
|
||||
return nil, fmt.Errorf("coordination execution failed: %w", err)
|
||||
}
|
||||
|
||||
var startedRunID string
|
||||
if coordRes.PendingAction != nil {
|
||||
execResult, execErr := s.executeAction(ctx, coordRes.PendingAction, s.UserCtx)
|
||||
if execResult != nil {
|
||||
startedRunID = execResult.RunID
|
||||
}
|
||||
coordRes.NaturalReply = renderActionReply(coordRes.PendingAction, execResult, execErr)
|
||||
coordRes.PendingAction = nil
|
||||
}
|
||||
coordRes = coordinator.AnnotateUnrelatedUploads(s.UserCtx, userInput, recRes, coordRes)
|
||||
|
||||
// 3. 更新上下文与挂起预期生命周期
|
||||
if coordRes.UpdatedContext != nil {
|
||||
@@ -591,8 +599,17 @@ func (s *Session) sendMessageInternal(ctx context.Context, userInput string, str
|
||||
asstMeta["client_turn_id"] = clientTurnID
|
||||
asstMeta["client_id"] = clientTurnID + ":assistant"
|
||||
}
|
||||
if startedRunID != "" {
|
||||
asstMeta["run_id"] = startedRunID
|
||||
if asstMeta["task_status"] == nil || asstMeta["task_status"] == "" {
|
||||
asstMeta["task_status"] = "running"
|
||||
}
|
||||
}
|
||||
|
||||
asstMsgID, _ := s.CtxMgr.RecordUserMessageWithID(ctx, s.ID, 0, "assistant", coordRes.NaturalReply, string(coordRes.Intent), string(recRes.Branch), asstMeta)
|
||||
if startedRunID != "" && asstMsgID > 0 && s.Actions != nil && s.Actions.TaskRuns != nil {
|
||||
_ = s.Actions.TaskRuns.BindAssistantMsgID(ctx, startedRunID, asstMsgID)
|
||||
}
|
||||
|
||||
// 异步记录问答切片到向量记忆库 (P2 检索增强,不阻塞流式或同步答复)
|
||||
sessID := s.ID
|
||||
|
||||
@@ -222,12 +222,28 @@ type UserProjectContext struct {
|
||||
RegulationHits []kb.HitItem `json:"-"`
|
||||
// UpgradeOffered 路由升级建议冷却标记(每会话至多主动建议一次,防打扰——对齐"参谋不强推"人设)
|
||||
UpgradeOffered bool `json:"-"`
|
||||
// ChatSessionID 当前对话会话,供进度问询读取真实 task run。不序列化。
|
||||
ChatSessionID string `json:"-"`
|
||||
// DocumentSummaryReader 仅用于服务端鉴权后的只读正文访问,不序列化。
|
||||
DocumentSummaryReader DocumentSummaryReader `json:"-"`
|
||||
// RealtimeSnippet 本轮实时检索(天气/新闻等)成功结果,供 Prompt 注入;不序列化。
|
||||
RealtimeSnippet string `json:"-"`
|
||||
// RealtimeUnavailable 本轮命中实时查询但检索失败/空结果,强制拒答约束;不序列化。
|
||||
RealtimeUnavailable bool `json:"-"`
|
||||
// PendingTurnAttachments 本轮上传引用,只活在当前请求,不写入快照。
|
||||
PendingTurnAttachments []TurnAttachmentRef `json:"-"`
|
||||
// AttachmentOnlyTurn 用户没有另写文字,只上传了文档。
|
||||
AttachmentOnlyTurn bool `json:"-"`
|
||||
// UploadFollowupFingerprint 已追问过的附件组合,避免同一批附件每轮都再问一次。
|
||||
UploadFollowupFingerprint string `json:"-"`
|
||||
}
|
||||
|
||||
// TurnAttachmentRef 对话回合携带的已登记上传,不含文件字节。
|
||||
type TurnAttachmentRef struct {
|
||||
Filename string
|
||||
DocID string
|
||||
AssetID int64
|
||||
ParseState string
|
||||
}
|
||||
|
||||
// ContextAssembler 上下文组装服务
|
||||
|
||||
@@ -37,29 +37,6 @@ func (e *CoordinatorEngine) generateDialogueReply(
|
||||
return "", ReplySourceTemplate
|
||||
}
|
||||
|
||||
workRoot := strings.TrimSpace(e.dataDir)
|
||||
if workRoot == "" {
|
||||
// U5: runtime roots come from config/workspace; never invent a data/dev fallback.
|
||||
return "", ReplySourceTemplate
|
||||
}
|
||||
sessionKey := "anon"
|
||||
if userCtx != nil && userCtx.SnapshotID != "" {
|
||||
sessionKey = userCtx.SnapshotID
|
||||
} else if userCtx != nil && userCtx.Project.ID != "" {
|
||||
sessionKey = userCtx.Project.ID
|
||||
}
|
||||
// 每轮独立子目录,避免复用上一轮残留的 reply.md(曾导致「问驳回却答疲劳寿命」)
|
||||
workDir := filepath.Join(
|
||||
workRoot,
|
||||
"workspaces",
|
||||
"dialogue",
|
||||
sanitizePathSegment(sessionKey),
|
||||
fmt.Sprintf("turn_%d", time.Now().UnixNano()),
|
||||
)
|
||||
if err := os.MkdirAll(workDir, 0o755); err != nil {
|
||||
return "", ReplySourceTemplate
|
||||
}
|
||||
|
||||
if userCtx != nil {
|
||||
userCtx.RealtimeSnippet = ""
|
||||
userCtx.RealtimeUnavailable = false
|
||||
@@ -100,8 +77,46 @@ func (e *CoordinatorEngine) generateDialogueReply(
|
||||
10. 隐私与跨用户边界:【相关历史片段】与【项目基准与协同上下文】中涉及其他成员姓名、个人沟通习惯、私人事实的内容仅用于理解语境,不得在答复中复述、评价或转述给当前用户;引用项目事件仅限客观结论(如谁完成了什么交付物)。
|
||||
11. 身份一致性:始终以「项目助手」自称,不得扮演医生/监管审评员等法定角色给出诊疗或注册裁决性结论,法规与型检解读须提示"以官方发文与实际检测为准"。`
|
||||
|
||||
if st := stream.FromContext(ctx); st != nil {
|
||||
st.EmitPhase("dialogue_generating", "正在生成项目助手回复...", "assistant", 0, 0, 60)
|
||||
content, reason := e.runDialogueBackend(ctx, userCtx, prompt, instructions, "dialogue_generating", "正在生成项目助手回复...")
|
||||
if reason != "" || strings.TrimSpace(content) == "" {
|
||||
return "", ReplySourceTemplate
|
||||
}
|
||||
return content, ReplySourcePiAgent
|
||||
}
|
||||
|
||||
// runDialogueBackend 在独立工作目录执行一轮 reply.md 生成。失败时 content 为空,reason 供观测。
|
||||
func (e *CoordinatorEngine) runDialogueBackend(
|
||||
ctx context.Context,
|
||||
userCtx *UserProjectContext,
|
||||
prompt, instructions, phaseName, phaseText string,
|
||||
) (content string, reason string) {
|
||||
if e == nil || e.dialogueBackend == nil {
|
||||
return "", "backend_nil"
|
||||
}
|
||||
workRoot := strings.TrimSpace(e.dataDir)
|
||||
if workRoot == "" {
|
||||
// U5: runtime roots come from config/workspace; never invent a data/dev fallback.
|
||||
return "", "no_data_dir"
|
||||
}
|
||||
sessionKey := "anon"
|
||||
if userCtx != nil && userCtx.SnapshotID != "" {
|
||||
sessionKey = userCtx.SnapshotID
|
||||
} else if userCtx != nil && userCtx.Project.ID != "" {
|
||||
sessionKey = userCtx.Project.ID
|
||||
}
|
||||
// 每轮独立子目录,避免复用上一轮残留的 reply.md(曾导致「问驳回却答疲劳寿命」)
|
||||
workDir := filepath.Join(
|
||||
workRoot,
|
||||
"workspaces",
|
||||
"dialogue",
|
||||
sanitizePathSegment(sessionKey),
|
||||
fmt.Sprintf("turn_%d", time.Now().UnixNano()),
|
||||
)
|
||||
if err := os.MkdirAll(workDir, 0o755); err != nil {
|
||||
return "", "mkdir_failed"
|
||||
}
|
||||
if st := stream.FromContext(ctx); st != nil && phaseName != "" {
|
||||
st.EmitPhase(phaseName, phaseText, "assistant", 0, 0, 60)
|
||||
}
|
||||
|
||||
runCtx, cancel := context.WithTimeout(ctx, dialogueTimeout)
|
||||
@@ -116,10 +131,15 @@ func (e *CoordinatorEngine) generateDialogueReply(
|
||||
Timeout: dialogueTimeout,
|
||||
})
|
||||
if err != nil || res == nil || !res.Success {
|
||||
return "", ReplySourceTemplate
|
||||
if err != nil {
|
||||
return "", err.Error()
|
||||
}
|
||||
if res != nil && strings.TrimSpace(res.ErrorReason) != "" {
|
||||
return "", res.ErrorReason
|
||||
}
|
||||
return "", "execute_failed"
|
||||
}
|
||||
|
||||
content := ""
|
||||
if b, ok := res.Patches["reply.md"]; ok {
|
||||
content = string(b)
|
||||
}
|
||||
@@ -134,9 +154,9 @@ func (e *CoordinatorEngine) generateDialogueReply(
|
||||
}
|
||||
content = strings.TrimSpace(content)
|
||||
if content == "" {
|
||||
return "", ReplySourceTemplate
|
||||
return "", "empty_reply"
|
||||
}
|
||||
return content, ReplySourcePiAgent
|
||||
return content, ""
|
||||
}
|
||||
|
||||
func buildDialoguePrompt(userInput string, userCtx *UserProjectContext) string {
|
||||
|
||||
@@ -83,6 +83,7 @@ type CoordinatorEngine struct {
|
||||
docResolver DocResolver
|
||||
pendingSupps PendingSupplementReader
|
||||
reopenLister ReopenLister
|
||||
sessionRuns SessionRunReader
|
||||
// OnSupplement is optional; composition typically wires supplementimpact.TriggerAsync.
|
||||
// Nil-safe: unset hooks are skipped.
|
||||
OnSupplement func(ctx context.Context, projectID, userID int64, sessionID, summary, markdown string)
|
||||
@@ -108,6 +109,27 @@ func (e *CoordinatorEngine) tasks() StageTaskRunner {
|
||||
return e.stageTasks
|
||||
}
|
||||
|
||||
// SessionRunSnapshot 是进度问询可读的任务运行投影,不含工作目录绝对路径。
|
||||
type SessionRunSnapshot struct {
|
||||
RunID string
|
||||
TaskKey string
|
||||
Status string
|
||||
WorkspaceID string
|
||||
ErrorMessage string
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// SessionRunReader 按会话读取最近一次任务运行。未注入时进度问询保持模板答复。
|
||||
type SessionRunReader interface {
|
||||
LatestSessionRun(ctx context.Context, sessionID string) (*SessionRunSnapshot, error)
|
||||
}
|
||||
|
||||
func (e *CoordinatorEngine) SetSessionRunReader(reader SessionRunReader) {
|
||||
if e != nil {
|
||||
e.sessionRuns = reader
|
||||
}
|
||||
}
|
||||
|
||||
func (e *CoordinatorEngine) SetContextServices(ctxMgr *ctxmgr.ContextManager, kbClient *kb.Client) {
|
||||
if e != nil {
|
||||
e.ctxMgr = ctxMgr
|
||||
@@ -231,6 +253,13 @@ func (e *CoordinatorEngine) ProcessIntent(
|
||||
}
|
||||
}
|
||||
|
||||
if userCtx.AttachmentOnlyTurn && len(userCtx.PendingTurnAttachments) > 0 {
|
||||
return e.handleUploadIntake(ctx, userCtx)
|
||||
}
|
||||
if top.FilledSlots["upload_action"] == uploadActionReviseGuidance {
|
||||
return handleUploadReviseGuidance(top, userCtx), nil
|
||||
}
|
||||
|
||||
// Phase 5:RankedFrames 写/读冲突二次门禁
|
||||
if intent.RankedFrameConflictRequiresClarification(recRes) {
|
||||
msg := "检测到查询与写操作意图接近,为避免误执行,请明确您是要查询状态,还是要执行变更操作?"
|
||||
|
||||
@@ -11,6 +11,17 @@ import (
|
||||
|
||||
// handleAmbiguousConsult 处理用户犹豫或征询建议 (分支 3 模糊分忧)
|
||||
func (e *CoordinatorEngine) handleAmbiguousConsult(ctx context.Context, cand *intent.CandidateIntent, userCtx *UserProjectContext, rawInput string) (*CoordinationResult, error) {
|
||||
if cand != nil && strings.TrimSpace(cand.ClarificationQuestion) != "" {
|
||||
return &CoordinationResult{
|
||||
Status: StatusClarificationRequired,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
ClarificationPrompt: cand.ClarificationQuestion,
|
||||
NaturalReply: cand.ClarificationQuestion,
|
||||
UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
currentStage := userCtx.Project.CurrentStage
|
||||
projName := userCtx.Project.Name
|
||||
if projName == "" {
|
||||
|
||||
@@ -233,7 +233,7 @@ func (e *CoordinatorEngine) handleDocGovApprove(ctx context.Context, cand *inten
|
||||
|
||||
reply := fmt.Sprintf("正在处理您对《%s》的审核通过请求…", docName)
|
||||
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovApprove", "", "这是审核通过请求的受理通报。必须保留文档名,并说明正在处理,不得宣称已经批准归档。", &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
@@ -244,7 +244,7 @@ func (e *CoordinatorEngine) handleDocGovApprove(ctx context.Context, cand *inten
|
||||
DocID: docName,
|
||||
Comment: cand.FilledSlots[intent.SlotRejectReason],
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
// handleDocGovClaim 解析门 → 确认卡 → 拍板后 PendingAction(docgov.claim)
|
||||
@@ -353,7 +353,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
rollback = vocabulary.StateDrafting
|
||||
}
|
||||
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
@@ -366,7 +366,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
Reason: reason,
|
||||
Rollback: rollback,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_final_approve" {
|
||||
@@ -375,7 +375,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
@@ -386,7 +386,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
Kind: "docgov.approver_approve",
|
||||
DocID: docName,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_claim" {
|
||||
@@ -395,7 +395,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
userCtx.dismissCard("resolved")
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
@@ -407,7 +407,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
DocID: docName,
|
||||
TaskKey: payload["task_key"],
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_submit_review" {
|
||||
@@ -417,13 +417,13 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
taskKey := payload["task_key"]
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: fmt.Sprintf("正在处理《%s》的送审…", docName),
|
||||
UpdatedContext: userCtx,
|
||||
ClearExpectation: true,
|
||||
PendingAction: &PendingAction{Kind: "docgov.submit_review", DocID: docName, TaskKey: taskKey},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_workflow_run" {
|
||||
@@ -442,7 +442,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
if wfKey == "" {
|
||||
wfKey = "main"
|
||||
}
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
@@ -453,7 +453,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
Kind: "workflow.run",
|
||||
WorkflowKey: wfKey,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_comment_add" {
|
||||
@@ -462,7 +462,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
userCtx.dismissCard("resolved")
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: fmt.Sprintf("正在为《%s》添加批注…", docName),
|
||||
UpdatedContext: userCtx, ClearExpectation: true,
|
||||
@@ -474,7 +474,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
Comment: payload["comment_content"],
|
||||
Reason: payload["comment_type"],
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_comment_resolve" {
|
||||
@@ -483,7 +483,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
userCtx.dismissCard("resolved")
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: fmt.Sprintf("正在解决《%s》的批注…", docName),
|
||||
UpdatedContext: userCtx, ClearExpectation: true,
|
||||
@@ -493,7 +493,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
Role: payload["role"],
|
||||
Section: payload["target_section"],
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_reopen_request" {
|
||||
@@ -502,7 +502,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
userCtx.dismissCard("resolved")
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: fmt.Sprintf("正在提交《%s》的重开申请…", docName),
|
||||
UpdatedContext: userCtx, ClearExpectation: true,
|
||||
@@ -513,7 +513,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
Reason: payload["reopen_reason"],
|
||||
Role: payload["role"],
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "confirm_reopen_approve" {
|
||||
@@ -523,7 +523,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
reqID, _ := strconv.ParseInt(payload["request_id"], 10, 64)
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: "正在批准重开申请…",
|
||||
UpdatedContext: userCtx, ClearExpectation: true,
|
||||
@@ -532,7 +532,7 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
DocID: docName,
|
||||
RequestID: reqID,
|
||||
},
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
if targetAction == "cancel" {
|
||||
@@ -541,14 +541,14 @@ func (e *CoordinatorEngine) handleDocGovProposalDecide(ctx context.Context, cand
|
||||
}
|
||||
userCtx.applyPending(nil)
|
||||
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleDocGovProposalDecide", "", "这是已确认或已取消后的受理通报。必须保留文档名与动作边界,不得把受理说成已经归档生效。", &CoordinationResult{
|
||||
Status: StatusAccepted,
|
||||
Intent: cand.Intent,
|
||||
Branch: cand.Branch,
|
||||
NaturalReply: fmt.Sprintf("已取消针对《%s》的操作,文档状态保持不变。", docName),
|
||||
UpdatedContext: userCtx,
|
||||
ClearExpectation: true,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
// 默认分支:禁止假成功——缺确认动作时诚实澄清
|
||||
|
||||
@@ -162,10 +162,10 @@ func (e *CoordinatorEngine) handleQueryPendingSupplements(ctx context.Context, c
|
||||
docID = strings.TrimSpace(cand.FilledSlots[intent.SlotTargetDoc])
|
||||
}
|
||||
if e == nil || e.pendingSupps == nil {
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleQueryPendingSupplements", "", "", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: "积压补充查询尚未接到当前环境。", UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
rows, err := e.pendingSupps.ListPendingSupplements(ctx, projectID, docID)
|
||||
if err != nil {
|
||||
@@ -176,10 +176,10 @@ func (e *CoordinatorEngine) handleQueryPendingSupplements(ctx context.Context, c
|
||||
}, nil
|
||||
}
|
||||
if len(rows) == 0 {
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleQueryPendingSupplements", "", "", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: "当前没有未消化的锁定期间积压补充。", UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
var b strings.Builder
|
||||
b.WriteString(fmt.Sprintf("共有 %d 条待消化积压补充:\n", len(rows)))
|
||||
@@ -194,8 +194,8 @@ func (e *CoordinatorEngine) handleQueryPendingSupplements(ctx context.Context, c
|
||||
}
|
||||
b.WriteString("\n")
|
||||
}
|
||||
return &CoordinationResult{
|
||||
return e.applyNarrative(ctx, userCtx, "handleQueryPendingSupplements", "", "", &CoordinationResult{
|
||||
Status: StatusAccepted, Intent: cand.Intent, Branch: cand.Branch,
|
||||
NaturalReply: b.String(), UpdatedContext: userCtx,
|
||||
}, nil
|
||||
}), nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user