From 511864bad06106d380022a1413608ad992bb7e07 Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 02:31:24 +0000 Subject: [PATCH 1/5] docs(ops): scaffold doc taxonomy and relocate audit/remediation Establish .doc/{status,audit,remediation,archive} structure with README maps, migrate 15 root audit/remediation docs, and add redirect stubs. Co-authored-by: Cursor --- ...oduction-ready-workflow-governance-plan.md | 685 +--------- ...em-functional-gap-audit-and-remediation.md | 269 +--- .doc/2026-09-12-AUDIT-INDEX.md | 313 +---- .doc/2026-09-12-audit-summary-report.md | 441 +----- ...omprehensive-audit-and-remediation-plan.md | 681 +--------- ...ngs-three-workflows-implementation-plan.md | 707 +--------- .doc/2026-09-12-phase0-api-authz-matrix.md | 82 +- ...12-phase1-iam-authz-implementation-plan.md | 100 +- ...2-workflow-designer-implementation-plan.md | 24 +- .doc/2026-09-12-quick-reference-guide.md | 462 +------ .doc/2026-09-12-remediation-gap-matrix.md | 72 +- ...ediation-tasks-and-acceptance-checklist.md | 1180 +---------------- ...workflows-strict-governance-remediation.md | 526 +------- .doc/README.md | 64 + .doc/archive/README.md | 11 + ...em-functional-gap-audit-and-remediation.md | 268 ++++ .doc/audit/2026-09-12-audit-summary-report.md | 440 ++++++ .../2026-09-12-phase0-api-authz-matrix.md | 81 ++ .doc/audit/INDEX.md | 312 +++++ .doc/audit/README.md | 5 + .../authorization-baseline-2026-09-12.md | 35 + .doc/audit/authorization-matrix-v2.md | 23 + .doc/authorization-baseline-2026-09-12.md | 36 +- .doc/authorization-matrix-v2.md | 24 +- ...oduction-ready-workflow-governance-plan.md | 684 ++++++++++ ...omprehensive-audit-and-remediation-plan.md | 680 ++++++++++ ...ngs-three-workflows-implementation-plan.md | 706 ++++++++++ ...12-phase1-iam-authz-implementation-plan.md | 99 ++ ...2-workflow-designer-implementation-plan.md | 23 + .../2026-09-12-quick-reference-guide.md | 461 +++++++ ...ediation-tasks-and-acceptance-checklist.md | 1179 ++++++++++++++++ ...workflows-strict-governance-remediation.md | 525 ++++++++ .doc/remediation/INDEX.md | 15 + .doc/remediation/README.md | 8 + .doc/remediation/gap-matrix.md | 71 + .doc/status/FEATURE-MATRIX.md | 35 + .doc/status/README.md | 5 + .gitignore | 1 + 38 files changed, 5761 insertions(+), 5572 deletions(-) create mode 100644 .doc/README.md create mode 100644 .doc/archive/README.md create mode 100644 .doc/audit/2026-09-11-system-functional-gap-audit-and-remediation.md create mode 100644 .doc/audit/2026-09-12-audit-summary-report.md create mode 100644 .doc/audit/2026-09-12-phase0-api-authz-matrix.md create mode 100644 .doc/audit/INDEX.md create mode 100644 .doc/audit/README.md create mode 100644 .doc/audit/authorization-baseline-2026-09-12.md create mode 100644 .doc/audit/authorization-matrix-v2.md create mode 100644 .doc/remediation/2026-09-11-production-ready-workflow-governance-plan.md create mode 100644 .doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md create mode 100644 .doc/remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md create mode 100644 .doc/remediation/2026-09-12-phase1-iam-authz-implementation-plan.md create mode 100644 .doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md create mode 100644 .doc/remediation/2026-09-12-quick-reference-guide.md create mode 100644 .doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md create mode 100644 .doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md create mode 100644 .doc/remediation/INDEX.md create mode 100644 .doc/remediation/README.md create mode 100644 .doc/remediation/gap-matrix.md create mode 100644 .doc/status/FEATURE-MATRIX.md create mode 100644 .doc/status/README.md diff --git a/.doc/2026-09-11-production-ready-workflow-governance-plan.md b/.doc/2026-09-11-production-ready-workflow-governance-plan.md index 7796d773..e536f685 100644 --- a/.doc/2026-09-11-production-ready-workflow-governance-plan.md +++ b/.doc/2026-09-11-production-ready-workflow-governance-plan.md @@ -1,684 +1,3 @@ -# Chat Agent System 发布级账户、权限与工作流治理改进方案 +# 已迁移 -## 1. 执行摘要 - -当前系统已经具备良好的业务原型基础:登录/注册、项目、项目成员表、受控文档三权流转、工作流运行、文档血缘、系统设置弹窗和用户设置弹窗均已有不同程度的实现;近期还补上了统一 API 登录中间件、Goose 数据库迁移、生产镜像中的前端构建,以及数据库不可用时的生产失败关闭。这些能力应保留并演进,而不是推倒重来。[^1][^2][^3] - -系统目前仍不适合直接作为多人生产协作产品发布。关键问题已经从“有没有功能”转变为“谁是权威、配置何时生效、运行状态能否被绕过”: - -- 用户、密码、登录令牌和认证配置仍保存在 Go 进程内存中,重启即变化,令牌没有持久化、过期、轮换和全端撤销闭环。[^4] -- 角色定义、权限矩阵、人员扩展资料、项目成员编辑与大量交付物状态仍由浏览器 `localStorage` 保存;当前后端管理员判断仍硬编码为 `role-admin`。[^5][^6] -- 工作流目录是 Go 代码中的三个固定定义,每个定义只有一个 `stage_key/task_key`,还不是管理员可编辑、可发布、多阶段、多文档的工作流模型。[^7] -- 新项目默认立即激活 `main`;现有工作流控件会直接切换 active 指针,甚至在版本冲突后自动刷新重试,没有“配置—预览—二次确认—冻结—结束”的完整生命周期。[^8][^9] -- 项目成员角色当前混用了“创建人、编制人、审核人、批准人、查阅者”。编制/审核/批准本质上是每份文档的职责,不应作为一个人在整个项目中的单一角色。[^10] -- 项目类型仍主要是自由文本 `device_type`,前端阶段键固定为 `V0.1/V0.5/V1.0`,无法自然表达非医疗纯软件项目或其他生命周期。[^11] - -建议把目标系统定义为一个“受控的项目工作流平台”,核心由五层组成: - -```text -账户主体 ── 组织/系统角色 ── 项目成员关系 - │ - ▼ -不可变工作流版本 ──> 项目工作流实例 ──> 阶段实例 ──> 文档任务实例 - │ │ - ├─ 对话参与策略 └─ 编制/审核/批准职责 - ├─ 文档可见策略 - └─ 阶段推进门禁 + 审计 + 通知 -``` - -最重要的产品决策是: - -1. **取消任意身份切换**:生产包中删除 `DevRoleSwitcher` 和“模拟账号切换”;登录身份只能来自服务端会话。测试身份切换只保留在不随产品发布的测试夹具中。 -2. **角色不等于文档职责**:角色回答“这个人通常能做什么”;项目成员关系回答“这个人是否属于这个项目”;文档职责回答“这个人在这份文档中是编制、审核还是批准”。三者必须分表、分权限、分审计。 -3. **工作流采用版本化模板**:管理员编辑的是草稿版本,发布后不可原地修改。项目激活时复制一个完整快照,后续修改全局模板不得改变正在运行的项目。 -4. **同一项目最多一个运行中的工作流**:不能“切换”正在运行的工作流,只能在其完成或受控终止后选择新的工作流。 -5. **激活即冻结**:阶段开关、文档任务开关、模板版本、文档三权与参与策略在激活前配置;激活后普通路径不可修改。确需变更时走“受控变更单”,而不是直接改字段。 -6. **阶段不自动推进**:所有启用且必需的文档任务完成批准、无阻断性 stale/开放变更后,系统生成一次去重的“可推进”建议,主动通知项目创建者;由创建者确认后才原子进入下一阶段。 -7. **项目分类与合规范围分离**:不要只设 `is_medical=true/false`。至少拆为“产品域”和“合规配置”。纯软件可能是非医疗软件,也可能是医疗器械软件;两者不能由“是不是软件”推断。 - -## 2. 需求重述与边界 - -### 2.1 三类设置 - -系统应形成三个边界清晰的设置入口: - -| 入口 | 可进入者 | 管理对象 | 不应包含 | -|---|---|---|---| -| 用户设置 | 当前登录用户 | 本人资料、安全、通知、界面偏好、活动会话 | 角色提升、项目权限、他人账号 | -| 项目设置 | 项目创建者 | 项目成员、待激活工作流、阶段/文档开关、文档三权、激活/结束、通知 | 全局角色、全局模板原件、系统安全策略 | -| 系统设置 | 具备相应系统管理权限者 | 账户、角色、权限、工作流设计、模板库、项目类型/合规配置、审计和安全策略 | 以管理员身份直接替项目创建者完成日常业务决策 | - -“系统管理员能看一切”不应成为默认业务规则。管理员需要处理平台配置,但项目私密资料和个人私密文档应遵守独立的数据访问策略。必要的运维介入应使用带理由、再认证、限时和全量审计的 break-glass 流程。 - -### 2.2 关键术语 - -| 术语 | 建议定义 | -|---|---| -| 账户 | 唯一自然人的登录主体,不可在前端任意切换 | -| 角色 | 一组可复用权限,可以是系统范围或项目范围 | -| 项目成员 | 用户与项目之间的关系,含状态和项目角色绑定 | -| 文档职责 | 某个用户对某个文档任务实例承担 author/reviewer/approver | -| 工作流定义 | 管理员维护的逻辑标识,如 `medical_device_development` | -| 工作流版本 | 已发布且不可变的完整流程快照,如 `v3` | -| 项目工作流实例 | 某项目基于某个已发布版本创建的实际运行实例 | -| 阶段实例 | 项目工作流中的一个可推进单元 | -| 文档任务实例 | 阶段中的具体交付任务,连接模板、文档记录与三权职责 | - -## 3. 当前实现评估 - -### 3.1 值得保留的基础 - -| 现有能力 | 评价 | 后续用法 | -|---|---|---| -| 统一 API 认证中间件 | 已覆盖非公开 `/api` 路由,方向正确 | 改接持久化会话,继续作为统一入口 | -| `project_members` | 已有项目成员关系和 owner 回填 | 扩展角色绑定、成员管理 API 和成员状态 | -| `document_records` | 已有状态、锁定、版本、三权和审计字段 | 关联 `document_task_instance`,逐步去除冗余姓名字段 | -| DocGov 状态机 | 已有编制、审核、批准、驳回基础 | 增加职责分离、电子签名/再认证和阶段门禁事件 | -| `project_workflows/workflow_runs` | 已有项目工作流、运行和激活审计雏形 | 升级为定义版本 + 项目实例 + 阶段实例模型 | -| 文档血缘/stale | 已能表达上下游版本变化 | 纳入阶段完成条件和变更影响评估 | -| Goose 迁移与前端生产构建 | 近期已补齐基本链路 | 加迁移兼容测试、回滚预案和镜像验收 | -| 互动卡片/提醒类型 | 前端已有确认与提醒数据结构 | 用于“阶段可推进”和“工作流激活确认” | - -### 3.2 必须纠正的结构性问题 - -第一,当前 RBAC 主要在前端执行。`DEFAULT_ROLES` 和 `hasPermission` 用于隐藏按钮、过滤文档,但服务端没有同构的角色/权限表和统一策略决策。浏览器过滤只能改善体验,不能构成安全边界。OWASP 建议默认拒绝,并在每个请求上重新验证用户对具体资源和动作的权限。[^12] - -第二,现有 `ProjectWorkflowSwitcher` 的语义是“切换当前焦点”,而目标语义是“运行中的流程互斥”。当前控件点击后直接调用激活 API,遇到乐观锁冲突还会自动用最新版本重试;对高影响业务操作,这会掩盖“另一个操作者刚刚改变了项目”的事实。冲突应该展示差异并要求用户重新确认,而不是静默覆盖。[^9] - -第三,现有项目工作流唯一约束是 `(project_id, workflow_key)`,无法表示同一项目先后运行同一流程两次,也没有数据库约束保证“每个项目最多一个 active”。应保留历史实例,以 `instance_no` 或独立实例 ID 区分,并用部分唯一索引约束活动态。 - -第四,现有文档记录已支持三权,但项目成员 UI 又把成员角色设成 author/reviewer/approver,导致一个人加入项目时就被迫成为所有文档的某一职责。这会阻碍不同文档采用不同责任人,也无法表达 QA 同时参与多个文档但只批准其中一份。 - -## 4. 目标权限模型 - -### 4.1 RBAC + 项目关系 + 工作流属性 - -只用 RBAC 无法表达“BD 在商务阶段可对话,进入研发阶段后不可对话且不可看研发文档”。建议采用组合策略: - -```text -允许 = 已认证 - AND 账户有效 - AND 具备基础动作权限 - AND 是该项目的有效成员(或合规的系统级例外) - AND 当前工作流/阶段允许其项目角色参与 - AND 目标文档可见策略允许 - AND 当前状态允许该动作 - AND 未违反职责分离约束 -``` - -任一条件未知或没有匹配规则时拒绝。RBAC 适合降低组织权限管理成本,但阶段、对象归属、文档责任人和状态属于属性/关系条件,需要与 ABAC/ReBAC 组合。NIST 的 RBAC 模型明确区分用户、角色、权限、操作和对象,也支持职责分离约束;NIST 对 RBAC 加属性的研究同样说明二者结合更适合动态条件。[^13][^14] - -### 4.2 角色分层 - -| 层级 | 示例 | 作用域 | 建议 | -|---|---|---|---| -| 系统角色 | 系统管理员、用户管理员、工作流管理员、安全审计员 | 全系统 | 内置角色至少保留一个不可删除的超级管理员,但可编辑角色不得靠前端标志保护 | -| 业务/项目角色 | BD、产品经理、研发、测试、法规、QA、项目观察者 | 某项目 | 用户可在不同项目承担不同角色;可从组织默认角色复制后由项目创建者调整 | -| 文档职责 | 编制、审核、批准 | 单个文档任务实例 | 必须指派到具体用户,不等于项目角色 | - -建议允许一个用户绑定多个角色,但权限计算不是简单无条件求并集。若两个角色触发静态或动态职责分离冲突,应阻止绑定或阻止同一会话中的冲突动作。例如,同一文档默认不得由同一人同时编制和批准;如小团队必须例外,工作流版本需显式允许,并要求理由和额外审计。 - -### 4.3 权限键建议 - -权限键使用稳定动作,不把具体角色名编码进代码: - -| 权限域 | 建议权限 | -|---|---| -| 系统 | `system.settings.view`、`system.audit.view`、`system.security.manage` | -| 用户 | `users.view`、`users.create`、`users.edit`、`users.disable`、`users.reset_password` | -| 角色 | `roles.view`、`roles.create`、`roles.edit`、`roles.delete`、`roles.assign` | -| 工作流模板 | `workflow_defs.view`、`workflow_defs.create`、`workflow_defs.edit_draft`、`workflow_defs.publish`、`workflow_defs.retire` | -| 项目 | `projects.create`、`projects.view`、`projects.edit`、`projects.members.manage`、`projects.workflow.configure`、`projects.workflow.activate`、`projects.workflow.terminate`、`projects.stage.advance` | -| 工作流参与 | `workflow.chat.send`、`workflow.chat.view`、`workflow.task.run`、`workflow.progress.view` | -| 文档 | `documents.view`、`documents.edit`、`documents.submit_review`、`documents.review`、`documents.approve`、`documents.export`、`documents.visibility.manage` | -| 模板文件 | `templates.upload`、`templates.download`、`templates.publish`、`templates.retire` | - -项目创建者的专属能力不应仅靠一个通用 permission。服务端应同时校验 `projects.creator_user_id == principal.user_id`。系统管理员若需替代操作,只能走单独的 break-glass API,不能复用普通项目设置接口。 - -### 4.4 阶段策略示例 - -| 角色 | 商务阶段对话 | 商务文档 | 研发阶段对话 | 研发文档 | 审批动作 | -|---|---:|---:|---:|---:|---:| -| 项目创建者 | 是 | 是 | 是 | 是 | 仅被指派时;阶段推进始终由其确认 | -| BD | 是 | 按文档规则 | 否 | 否 | 仅商务文档且被指派时 | -| 产品经理 | 可选 | 按规则 | 是 | 需求类与被授权文档 | 被指派时 | -| 研发 | 否/可选 | 默认否 | 是 | 是 | 被指派时 | -| 测试 | 否 | 默认否 | 是 | 测试及依赖文档 | 被指派时 | -| 法规/QA | 可选 | 合规文档 | 是 | 合规与质量文档 | 被指派时 | -| 审计员 | 否 | 只读 | 否 | 只读 | 否 | - -“否”必须在服务端同时作用于列表、详情、搜索、导出、附件下载、SSE、对话发送、RAG 上下文组装和 Agent 工具读取,不能只隐藏 UI。 - -## 5. 账户与身份治理 - -### 5.1 去掉任意身份切换 - -发布版本应: - -- 删除 `DevRoleSwitcher` 的产品入口; -- 删除 `UserProjectRightsModal` 中的快速模拟账号切换; -- 删除前端本地认证 fallback、内置明文测试账户和 `X-User-ID` 发送逻辑; -- CI 检查生产 bundle 不包含种子密码、测试用户列表、`allowDevSwitch` 或模拟切换文案; -- E2E 测试通过独立测试登录接口、数据库 fixture 或浏览器多上下文完成,不在产品 UI 留后门。 - -如果未来确实需要客服“代用户查看”,应作为独立的 impersonation/break-glass 功能:管理员再认证、填写工单与理由、限时、只读优先、页面持续红色提示、用户可见审计、禁止电子签名和批准。首个可发布版本建议不做。 - -### 5.2 持久化账户与会话 - -建议新增: - -| 表 | 关键字段 | -|---|---| -| `users` | username、display_name、email、status、department、employee_id、locale、timezone、created_at、updated_at | -| `user_credentials` | user_id、password_hash、password_changed_at、failed_count、locked_until、mfa_state | -| `auth_sessions` | id、token_hash、user_id、created_at、last_seen_at、idle_expires_at、absolute_expires_at、revoked_at、ip_hash、user_agent | -| `password_reset_tokens` | token_hash、user_id、expires_at、used_at | -| `user_role_bindings` | user_id、role_id、scope_type、scope_id、valid_from、valid_until、assigned_by | - -令牌仅以哈希形式持久化。浏览器优先使用 `HttpOnly + Secure + SameSite` Cookie;如果继续使用 Bearer token,也必须有短期访问令牌、刷新/轮换、撤销和 XSS 风险控制。NIST 已在 2025 年发布 SP 800-63B-4,替代旧版数字身份认证指南;账户安全设计应以新版为基线,而不是继续依赖永久内存 token。[^15] - -### 5.3 用户设置 - -用户设置建议分为四页: - -1. **个人资料**:头像、姓名展示、邮箱、电话、语言、时区;员工号、部门和职位为组织受控字段,只读或需管理员审批。 -2. **安全**:修改密码、MFA、已登录设备、注销其他设备、最近登录与安全事件。 -3. **通知**:待审核、待批准、阶段可推进、文档 stale、任务失败的站内/邮件策略及免打扰时间。 -4. **偏好**:主题、默认输出格式、沟通风格、自定义指令;明确哪些偏好会进入 Agent 上下文。 - -高风险变更如密码、MFA、主邮箱和电子批准应要求近期认证。账号被禁用、密码重置或角色收回时,相关会话立即撤销并使权限缓存失效。 - -## 6. 系统设置的信息架构 - -系统设置不宜继续放在单个 980px 模态框内。建议改为有独立路由和权限保护的管理中心:`/admin/*`。 - -| 页面 | 核心能力 | -|---|---| -| 概览 | 服务健康、待审批用户、失败工作流、存储/队列、近期安全事件 | -| 用户与账户 | 创建、编辑、启停、邀请、重置密码、撤销会话、批量导入、角色绑定 | -| 角色与权限 | 角色增删改、权限矩阵、作用域、职责分离、受影响用户预览 | -| 工作流设计器 | 草稿创建、阶段排序、文档任务、参与策略、门禁、校验、测试、发布、退役 | -| 模板库 | 上传、预览、变量、版本、哈希、扫描状态、被哪些工作流引用 | -| 项目类型与合规 | 产品域、合规配置、字段 schema、可用工作流、默认策略 | -| 通知与自动化 | 事件模板、渠道、提醒频率、升级规则、去重规则 | -| 审计日志 | 用户/权限/工作流/模板/项目变更查询与导出 | -| 安全与会话 | 注册策略、密码/MFA、会话时限、CORS、上传上限、保留期 | - -角色删除必须先做影响分析。若仍有用户或工作流策略引用,默认不允许删除,只允许停用/归档或迁移绑定。内置超级管理员角色不可删除、不可清空关键权限;系统必须始终至少有一个有效超级管理员账户。 - -## 7. 工作流定义与版本管理 - -### 7.1 定义结构 - -```text -WorkflowDefinition (稳定业务标识) - └─ WorkflowVersion (draft | published | retired,发布后不可变) - ├─ StageDefinition [有序] - │ ├─ DocumentTaskDefinition [0..N] - │ │ ├─ TemplateVersion - │ │ ├─ default duties / eligible roles - │ │ └─ visibility / participation policy - │ └─ entry/exit gate - └─ workflow-level participation / completion policy -``` - -首期建议只支持线性阶段,拖拽排序即可。不要一开始引入任意 DAG、循环和复杂表达式;但表结构可以预留 `transition_rules`。线性模型已经满足“本阶段文档全部批准后,由创建者确认进入下一阶段”。 - -### 7.2 工作流版本状态 - -| 状态 | 可编辑 | 可用于新项目 | 可影响已激活项目 | -|---|---:|---:|---:| -| draft | 是 | 否 | 否 | -| published | 否 | 是 | 否,项目只引用固定版本 | -| retired | 否 | 否 | 已运行实例继续按原快照执行 | - -编辑已发布版本时实际执行“复制为新草稿”。发布前执行确定性校验:键唯一、阶段顺序连续、至少一个启用阶段、阶段至少有文档任务或显式人工门禁、模板均为可用版本、变量 schema 完整、权限策略有兜底、三权候选角色存在、无不可达节点、无角色死锁。 - -### 7.3 文档模板 - -模板不是直接覆盖文件,而是版本化资产: - -- 上传后生成 CAS blob、SHA-256、MIME/扩展名、大小、上传人和扫描状态; -- 只允许业务所需格式,如 DOCX、XLSX、PPTX、Markdown;宏文档默认拒绝; -- 经过扩展名、MIME、文件签名、大小、解压后大小、恶意文件扫描/隔离后才能标记 `ready`; -- 发布的工作流只能引用 `ready` 模板版本; -- 模板更新创建新版本,不改变历史项目实例; -- 变量采用白名单 schema,如 `project.name`、`project.owner.name`,未知变量阻止发布。 - -OWASP 对上传的建议包括扩展名白名单、不要信任客户端 Content-Type、应用生成存储名、限制大小、仅授权用户上传、放在 Web 根目录外并进行恶意文件扫描;模板上传应按此设计。[^16] - -## 8. 项目类型与合规配置 - -### 8.1 不使用单一“医疗/非医疗”开关 - -建议拆为两个维度: - -| 维度 | 示例 | 用途 | -|---|---|---| -| `product_domain` | `medical_device`、`non_medical_software`、`hardware_general`、`service` | 决定项目字段、推荐工作流和术语 | -| `compliance_profile` | `nmpa_device`、`eu_mdr`、`fda_qmsr`、`internal_qms`、`none` | 决定法规步骤、必需文档、签名和审计强度 | - -“纯软件”不能自动等同“无需法规”。非医疗 SaaS 可以选择 `none`;SaMD 则仍属于医疗器械域并选择对应市场合规配置。创建项目时以向导明确询问产品用途、目标市场和是否用于诊断/治疗等,由用户确认分类及理由,系统只提供建议。 - -FDA 的 QMSR 已于 2026 年 2 月 2 日生效,并将 ISO 13485:2016 纳入美国医疗器械质量体系框架;因此医疗项目的默认工作流与合规配置应可版本化,不应把旧法规口径写死在 Agent prompt 中。[^17] ISO 官方也说明 ISO 13485 面向医疗器械质量管理,并强调法规要求和风险管理;它不适合无差别施加给所有非医疗软件项目。[^18] - -### 8.2 首批项目类型建议 - -**医疗器械研发**建议阶段:商务摸底 → 需求与法规策划 → 设计开发 → 设计验证/确认 → 设计转移/发布。文档清单由所选市场、器械类型与组织 QMS 决定。 - -**非医疗纯软件**建议阶段:机会与范围 → 产品需求 → 架构与计划 → 实现 → 测试与验收 → 发布复盘。默认无法规检索步骤,可包含 SRS、架构设计、测试计划、发布清单、用户文档;若选择 `internal_qms`,仍可要求评审、批准和审计。 - -项目类型只负责推荐和约束可选工作流,不直接生成项目实例。这样未来可增加科研、咨询、硬件或组合产品,而无需修改 `projects` 表的大量专用字段。 - -## 9. 项目设置与激活冻结 - -### 9.1 项目设置页面 - -仅项目创建者可进入普通项目设置。页面建议分为: - -1. **基本信息**:名称、编号、产品域、合规配置、目标市场;工作流激活后影响流程的字段冻结,修改需受控变更。 -2. **成员与项目角色**:邀请、移出、项目角色绑定;不能在这里把成员设为全项目 author/reviewer/approver。 -3. **工作流配置**:从与项目类型兼容的已发布版本中选择一个待激活工作流。 -4. **阶段与文档**:激活前开关可选阶段/文档,查看依赖和影响;必需节点不可关闭。 -5. **责任分配**:逐文档指派编制/审核/批准,实时验证角色资格与职责分离。 -6. **激活与结束**:预览快照、风险提示、二次确认;运行中只展示状态和受控操作。 -7. **项目审计**:成员、配置、激活、推进、终止和职责变更记录。 - -### 9.2 激活流程 - -新项目不应默认激活 `main`,而应处于 `planning`。推荐交互: - -```text -选择工作流版本 - → 配置阶段/文档开关 - → 指派每份启用文档的三权 - → 系统校验 - → 生成只读预览与 plan_hash - → 用户二次确认 - → 单事务创建实例/快照/首阶段/文档任务/审计 -``` - -激活确认弹窗应明确展示:工作流名称和版本、启用阶段数、启用/关闭文档数、三权缺口、激活后哪些配置会冻结、当前参与者权限将如何变化。用户勾选“我理解激活后不能直接修改”并再次点击确认。 - -服务端不能只信任 `confirmed=true`。建议 `POST /activation-preview` 返回短期 `confirmation_token + plan_hash + expected_project_version`;真正激活时必须三者一致。若期间成员、责任人、模板或项目配置变化,返回 409 和差异摘要,要求重新预览确认。 - -### 9.3 工作流实例状态机 - -```text -planning ──activate──> active - │ ├─> awaiting_stage_confirmation ──advance──> active - │ ├─> completed - │ └─> termination_requested ──confirm──> terminated - └─delete draft -``` - -数据库增加部分唯一约束:一个项目在 `active/awaiting_stage_confirmation/termination_requested` 中最多有一个实例。新的工作流只有在前一个实例为 `completed` 或 `terminated` 后才能选择和激活。 - -正常“结束”与异常“终止”必须区分: - -- `completed`:所有启用阶段按门禁完成; -- `terminated`:创建者因范围取消等原因提前结束,必须填写原因,保留已有文档和历史; -- `paused` 可作为后续版本能力,首期不建议增加以免模糊“是否仍占用 active 槽位”。 - -### 9.4 配置冻结与受控变更 - -激活后以下内容冻结:工作流版本、阶段和文档启用状态、模板版本、基线参与策略、文档三权。首期可严格禁止修改。 - -第二阶段再提供 `workflow_change_requests`:创建者提出变更 → 系统分析影响 → 相关批准人确认 → 创建新配置 revision → 使受影响下游文档 stale。即使通过变更单,也不应回写全局工作流版本。 - -## 10. 阶段、文档与主动推进 - -### 10.1 阶段状态机 - -```text -pending → active → ready_to_advance → completed - │ │ - └─ blocked <───┘ -``` - -阶段进入 `ready_to_advance` 的确定性条件: - -- 所有 `enabled=true && required=true` 的文档任务均为 `approved`; -- 没有运行中的 Agent/task run; -- 没有阻断性开放批注、变更提案或 stale 文档; -- 阶段专用 exit gate 通过; -- 下一阶段至少有一个有效参与者,避免推进后无人能工作。 - -可选文档如果启用,也建议默认纳入阶段门禁;工作流管理员可以把某文档配置为 `blocking=false`,但发布时需要解释用途。阶段开关关闭时,其文档节点自动关闭并记录在项目快照中。启用阶段若关闭全部文档,必须有 `manual_gate=true`,否则激活校验失败。 - -### 10.2 文档任务状态 - -文档任务实例与文档正文分离:任务状态负责“是否启用、负责人是谁、是否完成”,`document_records` 继续负责正文版本和受控生命周期。 - -```text -disabled(仅激活前可选) -enabled: template → drafting → reviewing → approving → approved - ↑ │ │ - └─ rejected┴────────────┘ -approved --upstream changed--> stale(阻止阶段推进,直到评估或新版本批准) -``` - -三权规则: - -- 编制人可编辑并提交审核,不能批准自己的版本; -- 审核人只能在 `reviewing` 决定通过/驳回; -- 批准人只能在审核通过的固定内容哈希上批准; -- 审核或批准动作记录 user、role binding、时间、内容哈希、意见和认证上下文; -- 责任人被禁用/移出项目时,任务进入 `assignment_blocked`,不能继续流转; -- 更换责任人属于受控事件,不覆盖历史签署信息。 - -若系统承载受法规要求约束的电子记录/签名,应先做适用性评估。21 CFR 11.10 对闭合系统强调授权访问、按许可顺序执行、权限检查、记录保护和带时间戳审计轨迹;因此这里推荐的服务端状态机、不可覆盖审计和固定内容哈希不仅是产品体验要求,也是更稳妥的合规架构基础。[^19] 这不等于仅靠实现这些功能就自动达到 Part 11 合规,仍需结合组织程序、验证、培训、留存和适用法规完成独立评估。FDA 指南也建议基于对产品质量、安全和记录完整性的风险评估确定控制强度。[^20] - -### 10.3 主动询问创建者 - -当状态首次满足推进条件时,由事务 Outbox 写入 `stage.ready_to_advance` 事件。通知服务创建一条去重的待办和互动卡片: - -> “研发输入阶段的 4/4 个必需文档已批准,没有阻断项。是否进入‘设计开发’阶段?推进后 BD 将失去本工作流对话与研发文档访问权限。” - -卡片提供:查看完成清单、查看权限变化、暂不推进、确认推进。确认接口再次实时校验条件和 `expected_stage_version`;若已有文档被撤回、stale 或成员发生变化,拒绝推进并列出差异。 - -提醒去重键可为 `(stage_instance_id, readiness_revision)`。首次立即站内提醒,24 小时未处理再次提醒,超过组织配置阈值可升级给项目创建者本人或指定项目监督人,但绝不自动推进。 - -### 10.4 阶段切换时的权限变化 - -阶段推进和权限生效在同一数据库事务中完成。以 BD 为例: - -- 事务提交前仍按商务阶段策略工作; -- 提交后新的对话发送、文档列表、详情、下载、搜索、引用和 Agent 上下文读取立即按研发阶段策略拒绝; -- 已打开页面下一次 API/SSE 校验时收到权限变化事件并转为只读/关闭; -- 是否还能查看历史商务阶段记录由工作流策略单独配置,不与研发文档权限混在一起; -- 默认建议允许 BD 查看自己参与的已结束商务阶段记录,但不能查看研发阶段消息和文档。 - -为此,聊天会话/消息必须绑定 `workflow_instance_id` 和 `stage_instance_id`。否则只有项目级 session,系统无法安全区分同一项目中商务与研发阶段的对话可见性。 - -## 11. 推荐数据模型 - -### 11.1 核心表 - -| 表 | 关键字段与说明 | -|---|---| -| `roles` | id、code、name、scope_type、status、is_system、version | -| `permissions` | key、resource_type、action、risk_level | -| `role_permissions` | role_id、permission_id、effect;首期只支持 allow,未匹配即 deny | -| `role_bindings` | user_id、role_id、scope_type、scope_id、有效期、assigned_by | -| `role_constraints` | SoD、互斥角色、作用域限制 | -| `workflow_definitions` | id、key、name、status、latest_published_version | -| `workflow_versions` | workflow_id、version、status、schema_version、published_by/at、definition_hash | -| `workflow_stage_defs` | workflow_version_id、key、name、position、optional、manual_gate、entry/exit_rule | -| `workflow_doc_task_defs` | stage_def_id、key、title、template_version_id、required、blocking、default_enabled | -| `workflow_access_policies` | target_type/id、project_role_id、action、effect | -| `template_assets` | logical key、name、status | -| `template_versions` | asset_id、version、blob_sha256、mime、size、scan_status、variable_schema | -| `project_types` | key、name、product_domain、field_schema、status | -| `compliance_profiles` | key、name、ruleset_version、status | -| `project_type_workflows` | project_type_id、workflow_id、compliance_profile_id、recommended/allowed | -| `project_workflow_instances` | project_id、workflow_version_id、instance_no、status、config_revision、created_by | -| `project_stage_instances` | workflow_instance_id、stage_def_id、position、enabled、status、version | -| `project_doc_task_instances` | stage_instance_id、doc_task_def_id、enabled、blocking、status、document_id | -| `document_duty_assignments` | doc_task_instance_id、duty、user_id、assigned_by、valid_from/to | -| `stage_advance_requests` | stage_instance_id、readiness_revision、status、requested_at、decided_by/at、reason | -| `workflow_change_requests` | instance_id、from_revision、patch、impact、status、decisions | -| `notifications` | user_id、event_id、type、status、dedupe_key、read_at、acted_at | -| `audit_events` | actor、action、resource、before/after hash、reason、request_id、occurred_at | - -### 11.2 关键约束 - -```sql -CREATE UNIQUE INDEX uq_one_live_workflow_per_project -ON project_workflow_instances(project_id) -WHERE status IN ('active', 'awaiting_stage_confirmation', 'termination_requested'); - -CREATE UNIQUE INDEX uq_doc_duty_once -ON document_duty_assignments(doc_task_instance_id, duty) -WHERE valid_to IS NULL; - -CREATE UNIQUE INDEX uq_stage_advance_revision -ON stage_advance_requests(stage_instance_id, readiness_revision); -``` - -此外应使用外键和 CHECK/触发器或领域事务确保:已发布版本不可更新;激活实例至少有一个启用阶段;一个实例最多一个 active stage;文档任务只能引用本实例阶段;批准动作绑定的内容哈希等于当前待批准版本。 - -### 11.3 现有表迁移映射 - -| 现有对象 | 迁移方式 | -|---|---| -| `projects.active_workflow_key` | 过渡期作为缓存字段,最终由 live instance 派生;不再作为唯一事实源 | -| `project_workflows` | 回填成 `project_workflow_instances`;已有 active 记录生成 legacy snapshot | -| `workflow_runs` | 增加 instance/stage/task 外键,保留 run_id 与 input manifest | -| `document_records.task_key/stage` | 回填关联 `project_doc_task_instances`;保留只读兼容字段一版 | -| `document_records.author/reviewer/approver` | 回填 `document_duty_assignments`;姓名字段只用于历史展示,不再鉴权 | -| `project_members.project_role` | 从单字符串迁移到 `role_bindings`;owner 单独保留创建人关系 | -| 前端 `localStorage` roles/projects/deliverables | 首次升级只读取并提示导入;服务端确认成功后停止作为权威源 | - -## 12. API 与领域服务 - -### 12.1 建议领域服务 - -- `IdentityService`:账户、凭据、会话、MFA、撤销; -- `AuthorizationService`:集中计算 `Decision{allowed, reason_code, policy_version}`; -- `RoleService`:角色版本、绑定、影响分析和职责分离; -- `WorkflowDefinitionService`:草稿、校验、发布、退役; -- `ProjectWorkflowService`:配置预览、激活、推进、完成、终止、受控变更; -- `DocumentTaskService`:任务实例、三权指派、DocGov 联动; -- `NotificationService`:Outbox 消费、去重、提醒与升级; -- `AuditService`:不可覆盖审计事件、查询、导出和留存。 - -### 12.2 主要 API - -```text -GET/POST/PATCH /api/v1/admin/users -POST /api/v1/admin/users/{id}/revoke-sessions -GET/POST/PATCH/DELETE /api/v1/admin/roles -GET/POST /api/v1/admin/workflows -POST /api/v1/admin/workflows/{id}/versions/{v}/validate -POST /api/v1/admin/workflows/{id}/versions/{v}/publish -POST /api/v1/admin/templates -GET/POST/PATCH /api/v1/admin/project-types - -GET/PATCH /api/v1/me -POST /api/v1/me/password -GET/DELETE /api/v1/me/sessions -PATCH /api/v1/me/preferences - -GET /api/v1/projects/{id}/settings -PUT /api/v1/projects/{id}/workflow-plan -POST /api/v1/projects/{id}/activation-preview -POST /api/v1/projects/{id}/workflow-instances/activate -POST /api/v1/workflow-instances/{id}/stages/{stage}/advance -POST /api/v1/workflow-instances/{id}/complete -POST /api/v1/workflow-instances/{id}/terminate-preview -POST /api/v1/workflow-instances/{id}/terminate -PUT /api/v1/document-tasks/{id}/duties -``` - -所有写操作带 `Idempotency-Key` 和 `expected_version`。错误使用稳定代码,如 `WORKFLOW_ALREADY_ACTIVE`、`PLAN_CHANGED_RECONFIRM`、`STAGE_GATE_NOT_READY`、`ROLE_NOT_ELIGIBLE`、`SEPARATION_OF_DUTY_VIOLATION`、`WORKFLOW_ACCESS_DENIED`。 - -### 12.3 服务端授权位置 - -路由中间件只解决“是否登录”;对象级授权必须在领域入口再做。所有项目、会话、消息、文档、附件、搜索、导出、任务和 SSE API 都调用同一个 `AuthorizationService`。不允许 handler 自行散落 `if role == ...`,也不允许相信请求体中的 user/role/project ownership。 - -## 13. UI 交互方案 - -### 13.1 主工作台 - -- 顶部展示固定登录用户,不提供身份下拉切换; -- 项目标题旁显示当前工作流、阶段和状态,不再展示可随点随切的三个按钮; -- 有权限且无运行中工作流时显示“配置工作流”;运行中显示“查看流程”; -- 对当前阶段无参与权的用户,输入框禁用并说明原因;不能仅靠禁用,发送接口也返回 403; -- 右栏只加载服务端已授权的文档,避免先取全量再在浏览器过滤; -- 创建者看到“待我确认”角标和阶段推进卡片。 - -### 13.2 工作流设计器 - -建议三栏布局:左侧阶段树,中间阶段/文档配置,右侧属性和权限策略。顶部固定展示 `草稿/已发布/已退役`、版本号、校验结果和发布按钮。发布操作弹出变更摘要:新增/删除阶段、模板变化、角色访问变化、与上一版本兼容性。 - -### 13.3 项目工作流配置器 - -采用向导而不是大表单:选择 → 裁剪阶段 → 裁剪文档 → 指派职责 → 权限影响 → 校验 → 激活确认。所有关闭项显示影响,例如“关闭《法规路径评估》会使 FDA QMSR 合规配置不完整”,对合规配置定义的必需项则直接禁止关闭。 - -## 14. 生产发布基线 - -本方案的业务功能不能脱离发布工程。近期代码已补上统一认证中间件、数据库迁移调用和前端多阶段镜像,但仍至少需要完成以下发布阻断项: - -1. **持久化认证**:替换 `MemoryStore` 和进程内 token;生产不创建固定密码种子用户。 -2. **服务端 RBAC/ABAC**:把角色、权限、策略和项目成员修改迁入数据库/API,前端只消费 `capabilities`。 -3. **会话安全**:过期、轮换、撤销、登录限速、失败锁定、MFA、敏感动作再认证。 -4. **上传安全**:请求硬上限、配额、类型/签名检查、扫描、隔离、Web 根外存储。 -5. **审计完整性**:用户/角色/策略/模板/工作流/阶段/签署/导出都进入只追加审计;日志访问也审计。OWASP 建议记录用户管理、权限变更、管理操作、导入导出和文件上传,并保护日志不被未授权修改或删除。[^21] -6. **网络安全**:移除 `Access-Control-Allow-Origin: *`,使用允许域名;TLS、HSTS、CSP、frame/referrer 等由网关和应用共同设置。[^22] -7. **持久异步任务**:task run/event、worker lease、重启恢复、Outbox;只能在文档与事件落库成功后发布终态。 -8. **机密管理**:生产拒绝默认密码,密钥不进入镜像/前端/日志,使用 Secret 管理并轮换。 -9. **备份与恢复**:数据库、CAS、审计、模板版本一致性备份;实际演练 RPO/RTO。 -10. **验证与发布证据**:需求—设计—测试追溯、迁移报告、权限负例、性能、安全扫描、SBOM、部署/回滚记录。 - -## 15. 分阶段实施路线 - -### Phase 0:决策冻结与安全止血(3–5 天) - -- 冻结新的本地状态功能;明确服务端为唯一权威; -- 从生产 UI 删除任意身份切换和模拟入口; -- 定稿角色、权限、项目成员、文档职责术语; -- 关闭生产默认账号/密码、宽 CORS 和本地认证 fallback; -- 编制所有现有 API 的资源—动作—条件矩阵。 - -完成门禁:生产 bundle 不含切换入口/种子密码;匿名 API 401;跨项目、跨阶段、跨文档负例 403。 - -### Phase 1:账户与授权权威化(2 周) - -- 持久化 users/credentials/sessions/roles/permissions/bindings; -- 实现统一 `AuthorizationService`; -- 把系统设置中的用户和角色操作改成真实 API; -- 建立项目成员 CRUD 与项目角色绑定; -- 前端不再从 localStorage 判定权限,后端返回 capabilities。 - -完成门禁:重启后账户、角色、会话策略仍在;禁用账户立即失效;每个资源动作均有允许/拒绝测试。 - -### Phase 2:工作流设计器与模板库(2–3 周) - -- 建立工作流定义/版本/阶段/文档/策略表; -- 管理端完成草稿、校验、发布、退役; -- 模板上传、扫描、版本和预览; -- 建立医疗器械与非医疗纯软件两套首批工作流; -- 旧静态 catalog 作为 bootstrap seed,运行时改读数据库缓存。 - -完成门禁:已发布版本不可变;旧项目不受新版本影响;非法/死锁工作流不能发布。 - -### Phase 3:项目配置、冻结和阶段门禁(2–3 周) - -- 项目设置独立页面; -- planning、activation preview、二次确认、单活动实例约束; -- 阶段/文档开关和三权分配; -- 文档批准驱动 readiness,创建者确认推进; -- 阶段级聊天、文档、搜索和 Agent 上下文权限。 - -完成门禁:运行中不能选择其他工作流;激活后不能直接改开关/职责;BD 进入研发阶段后无法通过任何接口访问研发内容。 - -### Phase 4:可靠任务、审计与通知(2 周) - -- 持久化任务和事件、重连/重启恢复; -- Outbox 通知、推进卡片、去重和升级; -- 审计日志防篡改、查询和导出; -- stale、责任人失效和配置变更成为正式阻断项。 - -### Phase 5:生产验收与灰度(2 周) - -- 空库/旧库升级双测,备份恢复演练; -- 完整权限矩阵、并发、幂等、故障注入、上传和渗透测试; -- 医疗/非医疗两套黄金项目 E2E; -- test 环境稳定运行一个发布周期,随后灰度 main。 - -按熟悉现有代码的 3–4 人团队估算,发布级闭环约 8–12 周。若只有 1–2 人,应先交付 Phase 0–1 的安全账户/RBAC,再做工作流设计器,不建议把所有能力压缩进一次大改。 - -## 16. 验收测试矩阵 - -### 16.1 身份与权限 - -- 用户不能在 UI、请求头、请求体或 localStorage 中更换自己的身份; -- 修改 URL 中 project/workflow/stage/doc/run ID 不会越权; -- 角色权限变更后旧会话在下一请求即使用新策略; -- 角色删除前能列出用户、项目和工作流策略引用; -- 至少一个超级管理员保护有效,普通管理员不能删除最后一个; -- 同一文档的 author 与 approver 默认不能为同一用户。 - -### 16.2 工作流定义 - -- 草稿可编辑,已发布版本任何更新均被拒绝; -- 模板新版本不改变已激活项目的哈希; -- 零阶段、重复键、无模板、未知角色、无可参与人员、不可达阶段无法发布; -- 退役版本不能用于新项目,但旧实例可继续。 - -### 16.3 项目实例 - -- 新项目初始无 active 工作流; -- 两个并发激活请求最多一个成功; -- 激活预览后配置变化会要求重新确认; -- active 工作流存在时,选择另一个返回 409; -- completed/terminated 后可新建下一实例; -- 激活后关闭阶段/文档、替换模板或直接换责任人均被拒绝。 - -### 16.4 阶段与文档 - -- 任一必需文档未批准、stale、有阻断提案或任务运行中时不能推进; -- 最后一份必需文档批准只产生一个推进待办; -- 创建者确认时条件已变化则不推进; -- 推进事务失败时阶段和权限均保持旧状态; -- BD 在研发阶段的对话、列表、详情、搜索、下载、导出、SSE 和 Agent 工具读取均为拒绝; -- 文档批准绑定内容哈希,批准后内容变化会产生新版本并重新走审核。 - -### 16.5 发布与恢复 - -- 应用/worker/数据库短暂故障不会产生两个终态或丢失推进通知; -- 数据库和 CAS 能从备份恢复到一致点; -- 审计可重建用户、权限、模板、工作流、阶段和签署变更顺序; -- 医疗项目启用所选合规配置的必需节点,非医疗软件不被强制加载法规步骤; -- 生产镜像、配置和数据库没有默认密码或测试身份入口。 - -## 17. 建议优先创建的研发 Epic - -| Epic | 目标 | 依赖 | 优先级 | -|---|---|---|---:| -| IAM-01 持久化账户与会话 | 替换内存用户/token,支持撤销与过期 | DB | P0 | -| AUTHZ-01 权限策略服务 | 服务端 RBAC + 项目/阶段/文档条件 | IAM-01 | P0 | -| UI-01 移除身份模拟与本地权威状态 | 生产 fail closed,权限来自服务端 | IAM-01/AUTHZ-01 | P0 | -| ROLE-01 角色与权限管理 API | 管理端真实持久化、影响分析、绑定 | AUTHZ-01 | P0 | -| WFDEF-01 工作流版本模型 | 定义、阶段、文档、策略、发布 | ROLE-01 | P1 | -| TMPL-01 安全模板库 | 上传、扫描、版本、变量 schema | WFDEF-01 | P1 | -| PTYPE-01 项目类型/合规配置 | 医疗与非医疗首批模型 | WFDEF-01 | P1 | -| WFINST-01 项目配置与激活冻结 | planning、preview、单活、快照 | WFDEF-01/TMPL-01 | P1 | -| DOC-01 文档任务与三权解耦 | 文档任务实例、职责分离、DocGov 接入 | WFINST-01 | P1 | -| STAGE-01 阶段门禁与推进 | readiness、创建者确认、权限原子变化 | DOC-01/AUTHZ-01 | P1 | -| NOTIFY-01 主动提醒 | Outbox、待办、互动卡片、去重升级 | STAGE-01 | P1 | -| RELEASE-01 发布验收 | CI、迁移、恢复、安全、灰度 | 全部 | P0/P1 | - -## 18. 最终建议 - -这次改造不应被理解为“给现有设置弹窗再加几个 Tab”。真正需要建立的是一条不可绕过的权威链:**固定登录主体 → 服务端角色与项目关系 → 已发布工作流版本 → 项目冻结快照 → 阶段与文档状态机 → 责任人签署 → 创建者推进 → 全程审计**。 - -建议先完成账户和授权权威化,再建设工作流设计器。否则管理员即使能在页面上创建角色和流程,服务端仍无法可靠执行这些策略,功能越丰富,越权和状态不一致的风险越大。工作流首期采用线性阶段、单活动实例、激活后严格冻结,是在可用性、实现复杂度和受控性之间最稳妥的平衡。 - -对医疗器械项目,应通过合规配置逐步提高控制强度,并保留适用性评估、版本、审计和签署证据;对非医疗纯软件项目,应复用同一工作流引擎,但允许选择 `compliance_profile=none`,避免把法规流程硬编码进产品域。这样系统才能从当前的医疗器械业务原型,演进为可发布、可扩展、可审计的通用项目工作流平台。 - -## Sources - -[^1]: 仓库源码,[`internal/server/auth_middleware.go`](../internal/server/auth_middleware.go),统一保护非公开 API;[`internal/db/migrate.go`](../internal/db/migrate.go),Goose 迁移执行,访问于 2026-09-11。 -[^2]: 仓库源码,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile),包含 Node 前端构建与 `web/dist` 复制,访问于 2026-09-11。 -[^3]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go),数据库连接、迁移及生产失败关闭逻辑,访问于 2026-09-11。 -[^4]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go) 与 [`internal/auth/service.go`](../internal/auth/service.go),内存用户存储与进程内 token,访问于 2026-09-11。 -[^5]: 仓库源码,[`web/src/App.tsx`](../web/src/App.tsx) 与 [`web/src/data/storage.ts`](../web/src/data/storage.ts),角色、人员、项目和交付物的浏览器持久化,访问于 2026-09-11。 -[^6]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go),管理员接口以 `role-admin` 硬编码判断;[`web/src/components/admin/AdminSettingsModal.tsx`](../web/src/components/admin/AdminSettingsModal.tsx),角色权限编辑主要调用前端状态,访问于 2026-09-11。 -[^7]: 仓库源码,[`internal/projectworkflow/catalog.go`](../internal/projectworkflow/catalog.go),三个静态工作流及单一 stage/task 定义,访问于 2026-09-11。 -[^8]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go) 与 [`deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql`](../deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql),新项目默认 `main` 及当前切换模型,访问于 2026-09-11。 -[^9]: 仓库源码,[`web/src/components/workflow/ProjectWorkflowSwitcher.tsx`](../web/src/components/workflow/ProjectWorkflowSwitcher.tsx),直接切换及冲突后自动重试行为,访问于 2026-09-11。 -[^10]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`web/src/components/project/ProjectMembersModal.tsx`](../web/src/components/project/ProjectMembersModal.tsx),项目成员角色与文档职责混用,访问于 2026-09-11。 -[^11]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`internal/projectworkflow/types.go`](../internal/projectworkflow/types.go),固定阶段枚举和自由文本设备类型,访问于 2026-09-11。 -[^12]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。 -[^13]: NIST, “[Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control),” 含 INCITS 359 RBAC 模型说明,更新于 2026-03-04。 -[^14]: NIST, Kuhn, Coyne, Weil, “[Adding Attributes to Role-Based Access Control](https://csrc.nist.gov/files/pubs/journal/2010/06/adding-attributes-to-rolebased-access-control/final/docs/kuhn-coyne-weil-10.pdf),” 2010。 -[^15]: NIST, “[SP 800-63B-4: Digital Identity Guidelines — Authentication and Authenticator Management](https://csrc.nist.gov/pubs/sp/800/63/B/4/final),” 2025-07。 -[^16]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。 -[^17]: U.S. FDA, “[Quality Management System Regulation (QMSR)](https://www.fda.gov/medical-devices/postmarket-requirements-devices/quality-management-system-regulation-qmsr),” 更新于 2026-02-02。 -[^18]: ISO, “[ISO 13485:2016 — Medical devices — Quality management systems — Requirements for regulatory purposes](https://www.iso.org/standard/59752.html),” 2016,2025 年复审确认。 -[^19]: Electronic Code of Federal Regulations, “[21 CFR § 11.10 — Controls for closed systems](https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-11/subpart-B/section-11.10),” 访问于 2026-09-11。 -[^20]: U.S. FDA, “[Part 11, Electronic Records; Electronic Signatures — Scope and Application](https://www.fda.gov/regulatory-information/search-fda-guidance-documents/part-11-electronic-records-electronic-signatures-scope-and-application),” 2003-09,访问于 2026-09-11。 -[^21]: OWASP Cheat Sheet Series, “[Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html),” 访问于 2026-09-11。 -[^22]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go),当前 CORS 允许任意来源,访问于 2026-09-11。 +本文档已迁至 [remediation/2026-09-11-production-ready-workflow-governance-plan.md](remediation/2026-09-11-production-ready-workflow-governance-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md b/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md index 4b637909..36df7e69 100644 --- a/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md +++ b/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md @@ -1,268 +1,3 @@ -# Chat Agent System 功能缺陷深度审计与整改方案 +# 已迁移 -## 执行摘要 - -系统已经具备较完整的业务原型:多轮对话、意图识别、项目工作流、智能体小队、RAG、受控文档、自由文档、长任务流、聊天历史、摘要与导出等模块均有代码和测试资产。架构方向也基本正确:对话、项目协调、执行三层分离,确定性权限和状态转换应由服务端控制。[^1] - -但当前版本不应按“多人生产协作系统”发布。核心原因不是功能数量不足,而是四条基础链路尚未闭环: - -1. **身份与授权链路失守**:大量业务接口不要求登录,或直接信任 `X-User-ID`、查询参数、请求体中的用户与角色;攻击者可伪造身份访问或修改会话、项目、文档、任务和资产。这与系统设计中的多用户隔离目标直接冲突,也属于典型的对象级授权缺失(BOLA/IDOR)。[^2][^3] -2. **数据库发布链路失效**:生产 Compose 仅挂载一个明显过时的 `system_init.sql`,而新增能力依赖十余张表和多批迁移;Docker 初始化脚本又只在空数据卷首次启动时执行。当前 dev 实库检查已证实缺少工作流、自由文档等 7 张关键表及消息导出 4 个关键字段。[^4][^5][^6] -3. **前端交付链路不完整**:生产应用镜像只编译并复制 Go 二进制,没有构建或复制 `web/dist`;服务端虽然尝试托管 SPA,但容器内没有对应资产,因此按现有 Dockerfile 部署时首页会返回 404。[^7][^8] -4. **长任务恢复链路不持久**:任务运行和 SSE 事件只保存在进程内存中,保留时间仅一小时;进程重启后查询、重连、取消均失效。更严重的是,代码先发送 `done` 事件,再执行最终落库;最终落库失败时客户端已经把任务视为成功。[^9] - -综合判断:系统目前处于“功能丰富的集成原型 / dev 验证阶段”,不具备生产发布条件。建议立即冻结外网暴露和 main 发布,将下述 P0 项全部关闭后再进入真实 Agent 联调。 - -## 审计范围与证据强度 - -本次覆盖 Go 后端、React/Vite 前端、PostgreSQL 初始化与迁移、Docker Compose、PI Agent Runner、知识库、任务状态、文件存储、鉴权/RBAC、测试报告和当前 dev 运行环境。 - -证据分为三类: - -- **已证实**:可由源码直接推导,或已通过只读运行态/数据库检查确认。 -- **高概率风险**:代码配置与权威文档明确冲突,但本轮未执行攻击性验证。 -- **待联调验证**:需要完整 Go/Node 工具链、真实 Agent 或生产拓扑才能最终判定。 - -本轮工作区没有 `go`、`node`、`npm`、`psql` 客户端,因此 `go test ./...`、`go vet ./...`、`npm test`、`npm run build` 均因“命令不存在”未执行,而不是测试失败。通过 Docker 只读检查确认:dev PostgreSQL 与两个 Agent 容器运行,app 容器未创建;test/main 未运行。仓库包含 107 个 Go 测试文件和 44 个前端测试文件,但多个数据库、真实 Agent 和质量评估测试会在环境未配置时跳过。最近测试报告也明确标注真实 PI Agent 端到端验收尚未完成。[^10] - -## 系统能力地图 - -| 能力域 | 已有实现 | 当前完整度判断 | 主要缺口 | -|---|---|---:|---| -| 对话与意图 | 阻塞/流式对话、意图识别、候选动作、卡片交互 | 中 | 核心接口未统一鉴权;客户端可覆盖用户/项目身份 | -| 项目工作流 | 项目创建、工作流切换、运行记录、血缘 | 中低 | 数据库基线缺表;项目成员模型缺失;多数读取/运行接口缺对象授权 | -| 受控文档 | 编制、审核、批准、驳回、认领、租约、审计 | 中 | 部分状态动作已鉴权,但读取、批注、正文、租约接口仍可伪造身份 | -| 自由文档 | 私密、共享、版本、乐观锁、回收站 | 中低 | HTTP 身份完全依赖可伪造 header/query;实际 dev 库缺表 | -| 长任务 | 后台 worker、SSE 订阅、取消、完成投影 | 中低 | run/event 内存态;重启不可恢复;完成事件时序错误;无归属校验 | -| 文件与材料 | CAS、SHA-256 去重、项目资产自动装配 | 中 | 上传无真正请求上限/内容校验/项目授权;资产清单可匿名枚举 | -| RAG/记忆 | embedding、rerank、聊天搜索、摘要、案例检索 | 中 | DB 失败静默转内存;摘要仍为规则型;共享 KB 隔离策略未定 | -| 用户与 RBAC | 登录、注册、bcrypt、管理员页面、前端权限矩阵 | 低 | 后端账户内存态、token 无过期、前端本地明文回退、RBAC 主要在 UI | -| 部署运维 | dev/test/main Compose、健康检查、日志 | 低 | 生产 schema 错配、前端未打包、迁移无执行器、健康检查恒成功 | -| 测试与质量 | 大量单元/集成测试、专项测试报告 | 中 | 无仓库 CI;真实 DB/Agent 测试可跳过;缺安全负例、迁移升级、重启恢复测试 | - -## 缺陷清单与优先级 - -### P0:发布阻断项 - -| 编号 | 缺陷 | 证据与影响 | 整改目标 | -|---|---|---|---| -| P0-01 | 服务端身份可伪造,核心 API 普遍缺少授权 | `authenticateUser` 在无 token 时接受任意有效 `X-User-ID`;路由层没有统一鉴权中间件。聊天、任务、上下文、会话、文档读取/批注/正文/租约等处理器直接使用客户端 ID/角色。会导致跨用户读写、冒名审批、越权运行 Agent、数据删除或篡改。[^2][^11] | 所有非公开 API 必须先认证;用户 ID 只来自服务端会话;每次访问按项目成员、对象归属和动作权限授权;默认拒绝。 | -| P0-02 | 前端在后端不可用时自动切换为“伪登录” | 浏览器内置管理员和测试账户,密码以明文写入代码/`localStorage`;后端网络错误时可生成本地 token 并继续进入 UI。管理员操作也会静默降级为本地修改。用户会看到“成功”,但服务端未发生任何可信变更。[^12] | 生产构建彻底移除本地认证回退和种子账户;后端不可用必须 fail closed;Demo 模式用独立构建标志、独立域名和醒目标识。 | -| P0-03 | 受控文档接口存在任意路径写入面 | 正文保存接口不鉴权,接受客户端 `user_id`、`user_role` 和 `work_dir`;领域层将该目录直接写入文档记录并创建 `/output.md`。具备服务进程权限的任意目录都可能被覆盖或创建。[^13] | 删除 HTTP 层 `work_dir` 覆盖;由服务端根据 doc/run ID 解析规范化工作区;使用 `filepath.Rel`/`os.Root` 等强制限制在数据根目录内;路径拒绝测试覆盖绝对路径、`..`、符号链接。 | -| P0-04 | 管理对账接口可匿名操作任意目录 | `/api/v1/admin/workspaces/reconcile` 没有管理员鉴权,直接读取并可能改写客户端指定目录下的 `workspace.json`。[^14] | 仅管理员/内部 job 可调用;请求只接受 run ID,不接受路径;工作区从数据库映射;对账动作写入审计日志。 | -| P0-05 | 生产数据库 schema 与代码不兼容 | main 使用 72 行的 `system_init.sql`,只含基础项目/用户/会话/消息/任务表,字段也与当前查询不一致;当前代码依赖 `project_workflows`、`workflow_runs`、`document_lineage`、`freeform_*`、`document_records` 等。main 还使用不带 pgvector 的 `postgres:16-alpine`。[^4][^15] | 建立单一、版本化、可重复执行的迁移链;应用启动前执行迁移并校验目标版本;任何缺表/缺列必须拒绝启动;dev/test/main 使用同一 schema 基线。 | -| P0-06 | 现有数据卷不会自动应用新增迁移 | Compose 只挂载初始化脚本,没有迁移执行服务。官方 PostgreSQL 镜像在数据目录非空时跳过 `/docker-entrypoint-initdb.d`,所以修改 init SQL 也无法升级已有卷。当前 dev 实库缺 7 张关键表和 4 个消息字段即为直接证据。[^5][^6] | 引入 `goose`、`golang-migrate` 或等价迁移器;每个版本以事务执行、写版本表、支持向前兼容与回滚预案;发布流水线做空库和旧库升级双测。 | -| P0-07 | 生产应用镜像不包含前端 | Dockerfile 没有 Node 构建阶段,最终镜像只复制 `/server`;服务端 SPA 逻辑要求 `web/dist`。Compose 没有单独前端或反向代理服务。[^7][^8] | 增加 Node builder 生成 `web/dist`,再复制进最终镜像;或独立 Nginx 前端服务。镜像验收必须请求 `/`、JS/CSS 静态资源及 SPA 深链接。 | -| P0-08 | 数据库不可用会静默退化为内存模式 | `NewService` 的连接/`Ping` 错误被吞掉,随后所有核心服务用 `nil pool` 构造内存实现;健康检查仍固定返回 `status=ok`。生产可能表面存活但所有新数据重启即失。[^16][^17] | prod/test 数据库不可用或 schema 不匹配时拒绝启动;仅显式 `ALLOW_IN_MEMORY=true` 的本地 Demo 可降级;readiness 必须检查 DB、schema、存储和 Runner。 | - -### P1:高风险与核心可靠性项 - -| 编号 | 缺陷 | 证据与影响 | 整改目标 | -|---|---|---|---| -| P1-01 | 长任务与 SSE 事件不持久 | `runs` 和 `events` 存在进程内 map,完成后一小时驱逐;重启后 GET/events/cancel 全部返回 not found。现有 `workflow_runs` 只保存摘要,不能重放事件或恢复 worker。[^9] | 建立 `task_runs`、`task_run_events`、worker lease/heartbeat;SSE 从事件表按序号重放;启动时对 running 任务做恢复/失败对账。 | -| P1-02 | `done` 先于最终落库 | worker 在 Finalizer 前发送 `EventDone`;若 Finalizer 失败,客户端已停止订阅,之后的 `finalizing_failed` 不会被看到。[^9] | 执行结果先持久化与投影,事务成功后再发唯一终态事件;终态不可逆且事件/状态一致。 | -| P1-03 | 任务查询、订阅和取消无归属校验 | run ID 是时间戳格式,相关处理器不认证、不比较 `record.UserID/ProjectID`。攻击者可观察或取消他人任务。 | run API 全部认证;按项目成员和发起人授权;run ID 改用 CSPRNG UUID/ULID;增加跨用户 403 测试。 | -| P1-04 | 缺少项目成员与项目内角色权威模型 | 设计要求用户在不同项目承担不同角色,但数据库没有 `project_members`/角色指派表;`GetProject` 忽略传入的 user ID,项目可见性用“创建人或有会话”等启发式条件;前端组件在本地维护成员与权限。[^18] | 新增项目成员、项目角色、文档责任人、邀请/退出/停用表;所有项目对象访问采用关系型授权(ReBAC/ABAC),前端只展示服务端返回能力。 | -| P1-05 | 认证账户与会话只在内存 | 后端每次启动重新生成种子用户;注册、改密、审批和 token 都不持久,token 无绝对/空闲过期,禁用用户的既有 token 也没有统一撤销策略。[^19] | 建立持久化账户/凭据/会话表;token 只存哈希;设置绝对与空闲过期、轮换与全端注销;密码策略、登录限速、失败锁定、审计齐备。 | -| P1-06 | 上传和 JSON 请求缺资源上限 | 上传使用 `ParseMultipartForm(64<<20)` 后 `io.ReadAll`;该参数是内存阈值,不是总请求硬上限。未见 `http.MaxBytesReader`,多数 JSON 直接解码。攻击者可消耗内存、临时磁盘、CAS 存储和 Agent 调用成本。[^20] | 全局与端点级 body 上限;流式写 CAS 并计算哈希;白名单扩展、魔数/MIME 复核、文件名长度、配额、恶意文件扫描;用户/IP/项目限速。 | -| P1-07 | Mermaid 使用宽松安全模式 | Agent/用户内容会进入 Mermaid,配置为 `securityLevel: 'loose'`,官方说明该模式允许 HTML 和点击功能;最终 SVG 用 `dangerouslySetInnerHTML` 注入。[^21][^22] | 改为 `strict` 或 `sandbox`;禁用点击/HTML label;必要时用可信 SVG sanitizer;增加恶意 Mermaid 回归集。 | -| P1-08 | 密钥与本地配置基线不安全 | 当前 `.env` 权限为 `664`,关键密码命中仓库已知默认值;代码、示例和前端也包含默认管理员/测试密码。生产校验只拦截部分默认值。 | 立即轮换全部已知默认密码和 API key;`.env` 设为 `600`;生产使用 Docker secrets/Vault;构建和启动阶段拒绝任意默认/低强度密钥。 | -| P1-09 | CORS 和传输边界过宽 | 全局 `Access-Control-Allow-Origin: *`,还允许伪身份 header;main 默认把 app 绑定 `0.0.0.0`,Compose 内没有 TLS/反向代理/安全响应头。[^23] | 明确允许域名;删除身份 header;入口网关终止 TLS,设置 HSTS/CSP/frame/referrer 等;Runner 仅内部网络且使用服务间认证。 | -| P1-10 | Agent Runner 缺服务间认证与租户隔离 | Runner HTTP 接口可执行带 read/write/edit/web 工具的 Agent,只依赖 Docker 网络隔离;workspace 虽做路径归一化,但请求没有签名/token,所有任务共享同一容器环境和密钥。 | mTLS 或短期签名 token;每任务容器/沙箱、只读基础镜像、最小工具和网络 allowlist;工作区/密钥按租户隔离;输出文件做大小和路径校验。 | - -### P2:能力完善项 - -1. **语义摘要仍未完成**:backlog 已明确当前摘要需替换为语义摘要;应加入事实引用、增量摘要、质量评估和失败回退。[^24] -2. **报价输入与复核不足**:报价模块缺输入范围校验和轻量复核;对于商务决策应建立金额、税率、汇率、数量和审批阈值的确定性规则。[^24] -3. **小队降级和 trace 并发缺陷**:非关键步骤不能安全降级,并行 trace 序号需要原子化;应统一 step 状态机、幂等键和事件序号。[^24] -4. **数据留存、加密与删除策略缺失**:聊天、材料、Agent trace 可能包含客户和医疗器械研发敏感信息;需要数据分级、字段加密、保留期、合法删除、备份清除和访问审计。[^24] -5. **共享知识库污染面未界定**:三环境共享 KB 是有意设计,但测试/开发写入、索引版本和法规生效版本可能污染生产检索;至少应只读发布、索引版本化和环境指针隔离。 -6. **可观测性不足**:已有结构化 `slog`,但缺少统一指标、分布式 trace、SLO、告警和审计防篡改;错误处理中大量忽略 DB 写入错误,事故时难以确认权威状态。 -7. **API 契约与错误模型不统一**:同时存在纯文本错误、不同 JSON 字段、200/202 混用;应提供 OpenAPI、稳定错误码、版本策略和契约测试。 -8. **会话/项目缓存生命周期不受控**:服务端 session map 缺容量与租户配额;长时间运行可能积累内存,并在多副本部署时出现状态不一致。 - -## 关键根因 - -这些缺陷并非彼此独立,主要来自五个系统性根因: - -1. **Demo 与生产路径未隔离**:内存 fallback、本地认证、种子账户、默认项目都进入同一生产代码路径。 -2. **权限在 UI 和领域方法之间零散实现**:没有统一的认证中间件、授权策略服务和对象归属查询,导致新增端点很容易漏检。 -3. **缺少单一数据库演进机制**:init SQL、独立 migrations、dev 实库、main 初始化文件四套状态并存,没有 schema version 门禁。 -4. **异步任务没有 durable state machine**:内存 observer 被当作持久化事件系统使用,执行、投影、通知之间没有事务/Outbox 边界。 -5. **测试偏功能正向路径**:单元测试丰富,但发布级测试没有强制覆盖真实数据库升级、进程重启、跨用户负例、容器镜像和真实 Agent。 - -## 目标整改架构 - -```text -Browser - │ HTTPS + HttpOnly/Secure/SameSite cookie - ▼ -API Gateway / Go API - ├─ Authentication middleware - ├─ Authorization policy (user × project × object × action) - ├─ Request limits / rate limits / audit - │ - ├──────── PostgreSQL (single migration chain) - │ ├─ users / sessions / project_members - │ ├─ documents / versions / audit - │ └─ task_runs / task_run_events / outbox - │ - ├──────── CAS (bounded, scanned, tenant-scoped) - │ - └──────── Agent Dispatcher ── signed request ── isolated Runner - └─ per-run workspace sandbox -``` - -服务端必须成为唯一权威源:浏览器不能声明“我是谁”“我在项目里是什么角色”“我可以写哪个目录”;它只能提交资源标识和业务意图。身份来自会话,成员关系和权限来自数据库,工作区来自服务端映射,终态来自持久化状态机。 - -## 分阶段整改计划 - -### 阶段 0:立即止血(0–2 天) - -| 动作 | 负责人建议 | 验收 | -|---|---|---| -| 暂停 main 发布和公网入口;dev 仅绑定本机/VPN | 运维 | 外部网络无法访问 app/Runner | -| 轮换 `.env` 中默认密码及现有 API key;权限改为 600 | 运维/安全 | secret scan 无已知默认值;非属主不可读 | -| 生产关闭注册;移除前端快速管理员登录入口和本地认证 fallback | 前端/后端 | 断开后端后登录明确失败,不能进入工作台 | -| 临时禁用未鉴权的文档正文、租约、对账、任务取消端点 | 后端 | 匿名请求全部 401;普通用户访问管理端点 403 | -| 导出现有 dev 数据库并做可恢复备份 | DBA | 完成一次隔离环境恢复演练 | - -### 阶段 1:身份、授权与输入边界(3–7 天) - -1. 实现全局认证中间件,白名单只保留 health、login、按策略开放的 register 和静态资源。 -2. 删除所有业务路径中的 `X-User-ID`、请求体 `user_id/user_role/user_name` 信任;内部调用使用不可伪造的 request context principal。 -3. 新建 `project_members(project_id,user_id,role,status,...)`、会话归属、资产归属和任务归属授权函数。 -4. 为每个端点定义权限矩阵:资源、动作、允许主体、对象条件、审计级别。 -5. 路径只接受逻辑 ID,禁止客户端传绝对/相对目录;使用统一 `WorkspaceResolver` 和根目录约束。 -6. 加入请求大小、上传类型、配额、Agent 并发和登录限速。 - -阶段门禁:匿名/跨用户/跨项目/伪角色/路径穿越/超大 body 全套负例测试必须通过。OWASP 建议默认拒绝并在每个请求验证权限;仅依赖客户端提供的对象 ID 不足以保护资源。[^3][^25] - -### 阶段 2:数据库和交付可重复(第 2 周) - -1. 从当前代码反向生成权威 schema 清单,将所有迁移排序并纳入统一工具。 -2. 为现有 dev 卷补齐缺失表/字段;先备份,再 dry-run,再迁移,再做行数/约束/索引核验。 -3. 废弃 `system_init.sql` 与 `context_init.sql` 的双轨演进:空库也通过同一迁移链创建。 -4. 应用启动时校验 schema version;prod 不允许内存 fallback。 -5. 增加前端 builder 或独立静态站点镜像,做 SBOM、依赖扫描、镜像非 root、只读根文件系统评估。 -6. 创建 CI:格式化、lint、Go test/race/vet、前端 test/build、迁移测试、容器 smoke、secret scan、依赖扫描。 - -阶段门禁:空库部署、从当前 dev schema 升级、回滚演练、首页/静态资源/API/健康检查全部通过;main 与 test schema checksum 一致。 - -### 阶段 3:长任务可靠性与一致性(第 3 周) - -1. 将 `task_runs` 和 `task_run_events` 持久化,事件序号使用数据库唯一约束。 -2. 用 worker lease + heartbeat 识别孤儿任务;进程启动后按策略恢复、重试或标记中断。 -3. 使用事务 + Outbox:成果、文档版本、workflow run、聊天消息和终态事件要么一致成功,要么可重试。 -4. 调整事件顺序:`finalize committed` 后才能发布 `done/quality_failed`。 -5. 取消接口幂等;Runner 取消结果必须回写并可审计。 -6. 增加多副本和滚动重启测试。 - -阶段门禁:执行中重启 app、断开 SSE、重复提交、Finalize 故障、Runner 超时、取消竞态六类故障注入均不会产生假成功或丢任务。 - -### 阶段 4:安全渲染、Agent 隔离和数据治理(第 4–5 周) - -1. Mermaid 切换 `strict`/`sandbox`,对 Markdown、SVG、链接、附件预览执行统一内容安全策略。 -2. Runner 增加服务间认证、每任务沙箱、网络 allowlist、资源配额和出站审计。 -3. 建立数据分级、保留期、导出审批、加密、删除与备份清除流程。 -4. 共享 KB 改成不可变索引版本;生产仅绑定已批准版本,dev/test 使用独立别名或命名空间。 -5. 将所有 ignored DB errors 转为可观测、可重试或明确失败。 - -### 阶段 5:功能质量与正式验收(第 6 周) - -1. 完成真实 PI Agent + 模型全链路测试,覆盖材料上传、检索、多人对话、文档编制、审核、批准、导出和重启恢复。 -2. 完成报价输入校验、语义摘要、小队降级、trace 原子序号等现有 backlog。 -3. 建立黄金数据集:意图识别、RAG 引用正确性、幻觉率、文档质量、权限负例。 -4. 定义 SLO:API 可用性、首字节时间、任务成功率、恢复时间、错误预算、检索质量和单位任务成本。 -5. test 环境连续稳定运行至少一个发布周期,再按分支准入规则进入 main。 - -## 建议的数据模型增量 - -| 表/对象 | 核心字段 | 用途 | -|---|---|---| -| `auth_users` 或扩展 `users` | username、password_hash、status、password_changed_at | 持久化认证主体 | -| `auth_sessions` | token_hash、user_id、idle_expires_at、absolute_expires_at、revoked_at | 服务端会话治理 | -| `project_members` | project_id、user_id、project_role、status、joined_at | 项目关系授权 | -| `task_runs` | run_id、owner、project、status、lease、attempt、idempotency_key | durable task SSOT | -| `task_run_events` | run_id、seq、type、payload、created_at | SSE 重放与审计 | -| `outbox_events` | aggregate、event_type、payload、published_at | 事务后可靠通知 | -| `schema_migrations` | version、checksum、applied_at、duration | 数据库版本门禁 | -| `security_audit_events` | actor、action、resource、decision、request_id、ip | 授权与安全审计 | - -## 发布验收清单 - -### 安全门禁 - -- 无 token 的所有业务 API 返回 401;权限不足返回 403,且不泄露对象是否存在。 -- 修改任意 path/query/body/header 中的用户、项目、会话、文档、run ID 均不能越权。 -- 禁止 `X-User-ID` 作为公网身份;管理员 token 具备过期、撤销和审计。 -- `../`、绝对路径、符号链接逃逸、超大 body、伪 MIME、恶意 Mermaid 全部被拒绝。 -- 前端断网不会创建本地管理员或伪成功状态。 - -### 数据与任务门禁 - -- 空数据库与旧版数据库均可自动迁移至同一版本,失败时应用不接流量。 -- app 重启后会话、账号、工作流、自由文档、任务和 SSE 重放仍然有效。 -- 任务只出现一个终态;`done` 必须意味着文档、消息、workflow run 均已提交。 -- 数据库断开时 readiness 失败,不得无提示切换内存态。 - -### 交付与运维门禁 - -- 应用镜像可直接返回 SPA 首页、哈希静态资源和深链接。 -- main 不包含默认密码;Secret 不进入镜像、日志、前端 bundle 或 Git。 -- CI 产出测试报告、覆盖率、SBOM、漏洞/secret 扫描和迁移报告。 -- test/main 采用相同镜像 digest,仅配置和数据不同。 -- 备份经过实际恢复;明确 RPO/RTO、值班告警和回滚步骤。 - -## 建议的首批整改任务拆分 - -| Issue | 工作量估计 | 依赖 | 完成定义 | -|---|---:|---|---| -| SEC-001 统一认证中间件,删除 `X-User-ID` 信任 | 2–3 人日 | 无 | 全路由认证清单 + 401 测试 | -| SEC-002 项目/对象授权策略与 `project_members` | 4–6 人日 | SEC-001、DB migration | 跨用户/跨项目矩阵测试全绿 | -| SEC-003 路径沙箱与对账接口收口 | 2 人日 | SEC-001 | 任意路径/符号链接测试全绿 | -| SEC-004 移除前端本地认证和明文账户 | 1–2 人日 | SEC-001 | 断网 fail closed;bundle 无默认凭据 | -| DB-001 统一迁移链和 schema version 门禁 | 4–6 人日 | 备份 | 空库/旧库升级 CI 全绿 | -| DEP-001 前端生产镜像与容器 smoke | 2 人日 | 无 | `/`、assets、深链接、API 全绿 | -| RUN-001 持久化 task runs/events | 5–8 人日 | DB-001 | 重启后查询/重放/取消有效 | -| RUN-002 Finalize/Outbox/终态时序 | 3–5 人日 | RUN-001 | Finalize 故障不再发送 done | -| OPS-001 readiness、metrics、alerts、structured audit | 3–5 人日 | DB-001 | 故障注入触发正确健康状态与告警 | -| QA-001 CI 与发布安全/故障回归套件 | 5–8 人日 | 上述各项 | main 合并必须经过门禁 | - -以上估算适用于熟悉现有代码的 2–3 人小组,不包含真实模型质量调优时间。建议先完成 SEC-001/003/004、DB-001、DEP-001,再并行推进 SEC-002 与 RUN-001。 - -## 结论 - -本系统“功能设计”并不贫乏,真正的短板是权威边界和工程闭环。当前已有的智能体、工作流、文档治理和测试资产值得保留,但必须把 Demo 便利性从生产链路剥离,把身份、项目关系、数据库版本、任务终态和工作区路径全部收回服务端控制。 - -整改成功的判据不是“页面能操作”或“单测通过”,而是:任意客户端参数都不能改变身份与权限;任意重启都不能丢失权威状态;任意发布都能从已知 schema 可重复升级;任意终态都与数据库和用户界面一致。完成全部 P0 和 P1 后,系统才适合进入真实多人 test 环境长期运行。 - -## Sources - -[^1]: 仓库架构设计,《[项目对话与任务协同系统——架构设计文档](./system-design/architecture-design.md)》,§3.1–3.3,访问于 2026-09-11。 -[^2]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go#L13-L42);[`internal/server/server.go`](../internal/server/server.go#L91-L188),访问于 2026-09-11。 -[^3]: OWASP, “[API1:2023 Broken Object Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/),” 2023。 -[^4]: 仓库部署基线,[`docker-compose.main.yml`](../docker-compose.main.yml#L11-L24);[`deploy/postgres/system_init.sql`](../deploy/postgres/system_init.sql#L1-L72),访问于 2026-09-11。 -[^5]: Docker Docs, “[PostgreSQL specific guide — Initialization scripts](https://docs.docker.com/guides/postgresql/),” 访问于 2026-09-11。 -[^6]: 运行态只读检查:`shuimu-context-pg-dev/agent_system_dev`;缺少 `project_workflows`、`workflow_runs`、`workflow_activation_audits`、`document_lineage`、`freeform_documents`、`freeform_document_versions`、`document_access_audit`,且 `chat_messages` 缺 `content_kind`、`export_policy`、`content_revision`、`content_sha256`,检查于 2026-09-11。 -[^7]: 仓库镜像定义,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile#L1-L34),访问于 2026-09-11。 -[^8]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L192-L244) 的 SPA 文件查找逻辑,访问于 2026-09-11。 -[^9]: 仓库源码,[`internal/taskrun/manager.go`](../internal/taskrun/manager.go#L28-L73)(内存与保留期);同文件 [L200-L220](../internal/taskrun/manager.go#L200-L220)(done 先于 finalize),访问于 2026-09-11。 -[^10]: 仓库测试报告,《[Chat Agent 全链路修复整改测试报告](./test-reports/2026-09-11-chat-agent-remediation-test-report.md)》§6–7;《[聊天回合幂等与项目切换隔离测试报告](./test-reports/2026-09-11-chat-turn-idempotency-test-report.md)》§5.3,访问于 2026-09-11。 -[^11]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L101-L268)、[L325-L439](../internal/server/handlers.go#L325-L439)、[L648-L838](../internal/server/handlers.go#L648-L838)、[L886-L994](../internal/server/handlers.go#L886-L994),访问于 2026-09-11。 -[^12]: 仓库前端源码,[`web/src/api/auth.ts`](../web/src/api/auth.ts#L25-L185)、[L187-L540](../web/src/api/auth.ts#L187-L540),访问于 2026-09-11。 -[^13]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L886-L923);[`internal/docgov/lease.go`](../internal/docgov/lease.go#L285-L338),访问于 2026-09-11。 -[^14]: 仓库源码,[`internal/server/reconcile_handlers.go`](../internal/server/reconcile_handlers.go#L10-L24);[`internal/squad/reconcile.go`](../internal/squad/reconcile.go#L25-L64),访问于 2026-09-11。 -[^15]: 仓库当前开发基线,[`deploy/postgres/context_init.sql`](../deploy/postgres/context_init.sql#L1-L360) 及 [`deploy/postgres/migrations/`](../deploy/postgres/migrations/),访问于 2026-09-11。 -[^16]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go#L40-L76),访问于 2026-09-11。 -[^17]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L74-L83),访问于 2026-09-11。 -[^18]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go#L69-L106);[`internal/projectworkflow/store.go`](../internal/projectworkflow/store.go#L145-L177);前端 [`web/src/engine/rbac.ts`](../web/src/engine/rbac.ts),访问于 2026-09-11。 -[^19]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go#L20-L101);[`internal/auth/service.go`](../internal/auth/service.go#L43-L113)、[L192-L226](../internal/auth/service.go#L192-L226),访问于 2026-09-11。 -[^20]: 仓库源码,[`internal/server/asset_handlers.go`](../internal/server/asset_handlers.go#L20-L79);Go 官方文档,[`net/http.MaxBytesReader`](https://pkg.go.dev/net/http#MaxBytesReader),访问于 2026-09-11。 -[^21]: 仓库前端源码,[`web/src/components/doc/blocks/MermaidBlockView.tsx`](../web/src/components/doc/blocks/MermaidBlockView.tsx#L12-L20)、[L64-L77](../web/src/components/doc/blocks/MermaidBlockView.tsx#L64-L77)、[L199-L208](../web/src/components/doc/blocks/MermaidBlockView.tsx#L199-L208),访问于 2026-09-11。 -[^22]: Mermaid 官方文档,“[securityLevel](https://mermaid.js.org/config/schema-docs/config-properties-securitylevel.html),”访问于 2026-09-11。 -[^23]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L433-L443);[`docker-compose.main.yml`](../docker-compose.main.yml#L80-L118),访问于 2026-09-11。 -[^24]: 仓库待办,《[Chat Agent P6 Backlog Issues](./backlog/chat-agent-p6-backlog.md)》,访问于 2026-09-11。 -[^25]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。 -[^26]: OWASP Cheat Sheet Series, “[Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html),” 访问于 2026-09-11。 -[^27]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。 +本文档已迁至 [audit/2026-09-11-system-functional-gap-audit-and-remediation.md](audit/2026-09-11-system-functional-gap-audit-and-remediation.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-AUDIT-INDEX.md b/.doc/2026-09-12-AUDIT-INDEX.md index fd52d820..43f92920 100644 --- a/.doc/2026-09-12-AUDIT-INDEX.md +++ b/.doc/2026-09-12-AUDIT-INDEX.md @@ -1,312 +1,3 @@ -# 项目全面审计 - 文档索引 +# 已迁移 -> **HISTORICAL(2026-09-12 初审快照)** -> **当前发布/缺口 SSOT** → [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) -> **协作焦点** → [.doc/ops/CURRENT.md](./ops/CURRENT.md) -> **Agent 工作方式** → [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md) - -**审计日期**: 2026-09-12 -**项目**: Chat-Agent-System -**审计状态**: 历史索引(下方 5.7/10 为初审结论,勿作 live status) - ---- - -## 核心文档(按阅读顺序推荐) - -### 0️⃣ 当前状态(Live SSOT) - -**文件**: `2026-09-12-remediation-gap-matrix.md` -**协作**: `.doc/ops/CURRENT.md` · `AGENTS.md` · `PROJECT.md` -**用途**: 发布缺口、Codex 再审计闭环证据、发布门禁勾选 - ---- - -### 1️⃣ 从这里开始:审计总结报告(历史) -**文件**: `2026-09-12-audit-summary-report.md` -**用途**: 项目整体现状、关键数字、风险评估 -**适合**: 项目经理、技术负责人、快速概览 -**阅读时间**: 15-20 分钟 - -**关键内容**: -- 项目评分及各维度打分 -- 12 个已确认缺陷分布(critical/high/medium) -- 未完成功能清单 -- 开发库数据污染现状(88 个测试定义) -- 整改时间与资源规划 -- 立即行动建议 - ---- - -### 2️⃣ 详细缺陷与整改:综合整改方案 -**文件**: `2026-09-12-comprehensive-audit-and-remediation-plan.md` -**用途**: 12 个缺陷的详细分析 + 3 个新功能的整改方案 -**适合**: 架构师、资深开发工程师 -**阅读时间**: 45-60 分钟 - -**关键内容**: -- BUG-01 到 BUG-12 的代码现场与后果分析 -- 5 个 high 缺陷的深层原因 -- 3 个 MISSING 新功能的实现设计 -- 3 个 Phase (A/B/C) 的整改计划 -- 风险预案与建议 - ---- - -### 3️⃣ 可执行的任务拆分:任务清单与验收 -**文件**: `2026-09-12-remediation-tasks-and-acceptance-checklist.md` -**用途**: 具体的代码修改指引、单元测试框架、验收标准 -**适合**: 开发工程师、QA、代码审查人 -**阅读时间**: 60-90 分钟 - -**关键内容**: -- Task A1-A6:关键缺陷修复(15h) - - 每个 Task 的修改文件、代码片段、测试用例 - - 验收标准与预计工作量 -- Task B1-B3:高优先级新功能(26h) - - 受控终止 API 的完整实现 - - E2E 测试框架与运行命令 - - 项目上下文快照的数据模型与集成点 -- Task C1-C7:完善与发布(20h) -- 全套验收检查表 - ---- - -### 4️⃣ 快速参考与速查:快速指南 -**文件**: `2026-09-12-quick-reference-guide.md` -**用途**: 问题症状→原因→解决方案的快速诊断 -**适合**: 所有开发人员、值班人员 -**阅读时间**: 5-10 分钟(按需查阅) - -**关键内容**: -- 10 个常见症状的诊断矩阵 -- 代码热点地图(哪个文件有哪个 bug) -- 整改优先级排序 -- 代码修改检查清单 -- 数据库迁移清单 -- 测试命令参考 -- API 变动汇总 -- 常见问题 Q&A - ---- - -## 配套参考文档 - -### 业务需求原文 -**文件**: `2026-09-12-three-workflows-strict-governance-remediation.md` -**用途**: 业务决策、验收标准的原始出处 -**适合**: 产品、架构、QA(需要理解业务背景) - -**关键章节**: -- 第 3 章:不可违反的业务规则 -- 第 7 章:验收标准(7.1-7.5) -- 第 8-9 章:已确认决策与实施解释 - ---- - -## 快速导航 - -### 我是 PM/项目经理 -``` -1. 读 audit-summary-report.md 第一部分(总体评估) -2. 重点关注第九章(建议行动计划) -3. 查阅 quick-reference-guide.md 第三部分(优先级排序) -4. 预估资源与时间 -``` - -### 我是后端开发 -``` -1. 读 quick-reference-guide.md(快速了解要改什么) -2. 针对每个 task 查阅 remediation-tasks-and-acceptance-checklist.md -3. 参考 comprehensive-audit-and-remediation-plan.md 理解原因 -4. 按照 task 中的"修改文件"和"代码片段"进行开发 -5. 执行"测试用例"部分验证修改 -``` - -### 我是 QA/测试工程师 -``` -1. 读 audit-summary-report.md 第十一章(验收标准清单) -2. 查阅 quick-reference-guide.md 第五部分(检查清单) -3. 针对每个 task 制定测试计划 -4. 执行 comprehensive-audit-and-remediation-plan.md 中的验收标准 -5. 特别关注 remediation-tasks 的 E2E 部分 -``` - -### 我是前端工程师 -``` -1. 读 quick-reference-guide.md 第三部分(了解哪些前端需改) -2. 查看 BUG-09、BUG-10、BUG-12 的具体改动 -3. 关注 comprehensive-audit 中的前端相关缺陷 -4. 参考 remediation-tasks 的 API 变动部分 -``` - -### 我是架构师/技术负责人 -``` -1. 读 audit-summary-report.md(整体判定) -2. 深入 comprehensive-audit-and-remediation-plan.md(详细分析) -3. 关注第八章(架构建议)和第十二章(结语) -4. 制定整改计划和资源分配 -``` - -### 我要处理现场问题 -``` -1. 查询 quick-reference-guide.md 第五部分(症状→原因→解决) -2. 找到对应的 bug 号 -3. 查阅 comprehensive-audit 的完整分析 -4. 按照 remediation-tasks 中的修复步骤操作 -5. 若需临时绕过,参考 quick-reference-guide 的建议 -``` - ---- - -## 文档关系图 - -``` -入口文档 - ↓ -audit-summary-report.md ← 总体评估与建议 - ↓ - ├→ comprehensive-audit-and-remediation-plan.md ← 详细缺陷分析 - │ ├─ BUG-01 到 BUG-12 详解 - │ ├─ MISSING-01 到 MISSING-04 详解 - │ └─ Phase A/B/C 整改计划 - │ - ├→ remediation-tasks-and-acceptance-checklist.md ← 可执行任务 - │ ├─ Task A1-A6(关键缺陷) - │ ├─ Task B1-B3(新功能) - │ └─ 验收检查表 - │ - ├→ quick-reference-guide.md ← 快速查询 - │ ├─ 症状诊断矩阵 - │ ├─ 代码热点地图 - │ ├─ 优先级排序 - │ └─ 常见问题 Q&A - │ - └→ three-workflows-strict-governance-remediation.md ← 业务背景 - ├─ 业务需求与决策 - ├─ 验收标准 - └─ 来源证据 -``` - ---- - -## 关键指标速查 - -| 指标 | 数值 | 位置 | -|---|---|---| -| 项目完成度 | 70% | audit-summary-report.md:1.2 | -| 总体评分 | 5.7/10 | audit-summary-report.md:1.1 | -| 缺陷总数 | 12 个 | audit-summary-report.md:2.1 | -| Critical 缺陷 | 3 个 | audit-summary-report.md:2.1 | -| 整改工作量 | 61h | audit-summary-report.md:9.1 | -| 单元测试覆盖率 | 85% | audit-summary-report.md:1.2 | -| E2E 覆盖率 | 0% | audit-summary-report.md:1.2 | -| 开发库污染定义 | 88 个 | audit-summary-report.md:4.1 | - ---- - -## 立即行动清单 - -**今天需要做的事**(第一天): - -``` -[ ] 技术负责人读 audit-summary-report.md(20 分钟) -[ ] 架构师读 comprehensive-audit-and-remediation-plan.md(60 分钟) -[ ] 后端 A 开发师启动 Task A1(2h)- 项目生命周期修复 -[ ] 后端 A 开发师启动 Task A4(2h)- 对话推进新服务 -[ ] QA 准备 E2E 测试框架(同步进行) -[ ] 全队讨论确认整改计划(30 分钟) -``` - -**本周目标**(5 天): - -``` -Day 1: 完成 Phase A 关键缺陷修复(15h) -Day 2-3: 启动 Phase B 新功能开发并行(26h) -Day 4-5: Phase C 完善与发布准备(20h) - + 每晚运行完整测试套件验证 -``` - ---- - -## 常见路径快查 - -**"完成工作流后项目仍然是 active"** -→ quick-reference-guide.md 第二部分 症状 1 -→ comprehensive-audit 第二部分 BUG-01 -→ remediation-tasks 的 Task A1 - -**"对话推进不起作用"** -→ quick-reference-guide.md 第二部分 症状 3 -→ comprehensive-audit 第二部分 BUG-04 -→ remediation-tasks 的 Task A4 - -**"禁用文档仍能被打开"** -→ quick-reference-guide.md 第二部分 症状 2 -→ comprehensive-audit 第二部分 BUG-05 -→ remediation-tasks 的 Task A5 - -**"激活 token 可能被重复使用"** -→ quick-reference-guide.md 第二部分 症状 6 -→ comprehensive-audit 第二部分 BUG-06 -→ remediation-tasks 的 Task A6 - -**"无法运行测试流程"** -→ quick-reference-guide.md 第二部分 症状 7 -→ comprehensive-audit 第三部分 MISSING-06 -→ remediation-tasks 的 Phase B 开始 - -**"需要完整 E2E 验证"** -→ comprehensive-audit 第三部分 MISSING-04 -→ remediation-tasks 的 Task B2 - ---- - -## 发布检查清单 - -**上线前必须确认**: - -``` -整改完成度: - □ Phase A 全部 PASS - □ Phase B 全部 PASS - □ Phase C 全部 PASS - -测试覆盖: - □ 单元测试覆盖率 ≥ 85% - □ E2E 测试三工作流完整链路 - □ 并发测试通过 - □ 数据库迁移兼容性验证 - -业务验收: - □ 验收标准 7.1-7.5 全部满足 - □ 不存在 critical 缺陷 - □ 安全性审计通过 - -运维就绪: - □ 数据库备份与恢复方案 - □ 审计日志完整 - □ 监控告警配置 - □ 性能基准测试 -``` - ---- - -## 文档维护 - -这套审计文档为 v1.0,应定期更新: - -- **每完成一个 task**: 更新对应 task 的状态 -- **每发现新缺陷**: 补充到 comprehensive-audit-and-remediation-plan.md -- **每月**: 做一次整体进度评估和文档更新 - ---- - -**审计完毕** - -**下一步**: 确认整改计划,进入实施阶段 - -**总体建议**: 立即启动 Phase A(关键缺陷),并行启动 E2E 测试框架,一周内完成所有整改。 - ---- - -*本索引最后更新于 2026-09-12 15:05 UTC* +本文档已迁至 [audit/INDEX.md](audit/INDEX.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-audit-summary-report.md b/.doc/2026-09-12-audit-summary-report.md index 82de47d1..4468d8ce 100644 --- a/.doc/2026-09-12-audit-summary-report.md +++ b/.doc/2026-09-12-audit-summary-report.md @@ -1,440 +1,3 @@ -# 项目全面审计总结报告 +# 已迁移 -> **SUPERSEDED** — 历史初审快照。Live 状态见 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/CURRENT.md](./ops/CURRENT.md)。 - -**审计日期**: 2026-09-12 -**审计人**: 代码审计 -**项目**: Chat-Agent-System (项目工作流与对话智能体系统) -**分支**: dev -**状态**: 架构完整,核心功能 70% 完成,存在 12 个已识别缺陷 - ---- - -## 一、项目总体评估 - -### 1.1 系统架构评分 - -| 维度 | 评分 | 评语 | -|---|---|---| -| 架构设计 | 8/10 | 三工作流治理顶层决策清晰,状态机完备,符合业务需求 | -| 功能完整度 | 5/10 | 核心框架 70%,关键模块(上下文快照、终止)0%,多个 bug 待修 | -| 代码质量 | 6/10 | 单元测试覆盖 OK,缺失 E2E;对话-服务耦合需解 | -| 数据一致性 | 4/10 | 项目生命周期转换不完整,禁用文档无显式标记 | -| 安全性 | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 | -| 运维成熟度 | 6/10 | DB 迁移和测试隔离需完善 | - -**综合评分**: **5.7/10** → **需立即整改** - ---- - -### 1.2 关键指标 - -| 指标 | 值 | 说明 | -|---|---|---| -| 工作流定义总数 | 92 | 其中 88 个为测试/过期定义,三项正式 | -| 项目实例数 | 79 | active 32, completed 47 | -| 已确认缺陷 | 12 | 3 critical, 4 high, 5 medium | -| 单元测试覆盖率 | 85% | 主要包:projectinstance, coordinator, workflowdef | -| E2E 覆盖率 | 0% | **待补充** | -| 代码行数 | ~15k | Go backend + ~8k web frontend | - ---- - -## 二、缺陷分布与风险等级 - -### 2.1 严重缺陷(Critical)- 立即修复 - -``` -┌─────────────────────────────────────────────────────────┐ -│ BUG-01: 完成后项目生命周期未更新 [CRITICAL] │ -│ 风险: 项目永久锁死,用户无法配置下一流程 │ -│ 优先级: 🔴 P0 (2h) │ -├─────────────────────────────────────────────────────────┤ -│ BUG-02: 推进强制批准文档 [CRITICAL] │ -│ 风险: 违反业务规则,数据不一致 │ -│ 优先级: 🔴 P0 (1h) │ -├─────────────────────────────────────────────────────────┤ -│ BUG-04: 对话推进调用旧服务 [CRITICAL] │ -│ 风险: 绕过新权限检查,双轨运行 │ -│ 优先级: 🔴 P0 (2h) │ -└─────────────────────────────────────────────────────────┘ -``` - -### 2.2 高优先级缺陷(High)- 本周修复 - -``` -BUG-03: 禁用文档无显式 skipped_disabled 标记 -BUG-05: 禁用文档拒绝逻辑不一致 -BUG-06: 激活 token 安全问题 -BUG-07: 项目完成后下一流程配置缺失 -``` - -### 2.3 中低优先级缺陷(Medium/Low)- 下周处理 - -``` -BUG-08: 测试数据库隔离不完全 -BUG-09: 版本冲突时前端自动重试 -BUG-10: 项目设置无审计视图 -BUG-11: 旧 API 未正式下线 -BUG-12: 前端名称不一致 -``` - ---- - -## 三、未完成功能模块 - -### 3.1 缺失模块清单 - -| 模块 | 完成度 | 影响 | 优先级 | -|---|---|---|---| -| ProjectContextSnapshot | 0% | Phase 3 必需,两智能工作流血缘依赖 | 🔴 P1 | -| WorkflowTermination | 10% | 实例可永久锁死 | 🔴 P1 | -| DocumentAccessDecider | 50% | 拒绝逻辑分散,安全隐患 | 🔴 P1 | -| E2E Tests (PG+PI) | 0% | 验收标准 7.5 要求 | 🔴 P1 | -| 项目生命周期完整转换 | 40% | 完成后无法切换 | 🔴 P1 | - -### 3.2 代码现状与缺陷位置 - -**问题集中地**: -- `internal/projectinstance/stage_store.go:71-158` - 推进事务问题 -- `internal/coordinator/engine.go:672-811` - 对话推进耦合 -- `internal/projectinstance/service.go:119-135` - 生命周期不完整 -- `internal/projectinstance/stage_access.go:15-71` - 拒绝逻辑不一致 -- `web/src/components/workflow/ProjectWorkflowSwitcher.tsx` - 前端名称&自动重试 - ---- - -## 四、数据一致性风险分析 - -### 4.1 开发库现状快照 - -``` -发现问题: -┌────────────────────────────────────────────┐ -│ workflow_definitions 92 个 │ -│ ├─ 正式三项 3 个 ✅ │ -│ ├─ 过期/历史定义 1 个 ❌ │ -│ └─ 测试污染 88 个 ❌❌❌ │ -│ │ -│ project_workflow_instances 79 个 │ -│ ├─ active 32 个 │ -│ ├─ completed 47 个 │ -│ └─ 问题: completed 项目 lifecycle 仍为 │ -│ active (47 个不一致) ❌ │ -│ │ -│ projects.lifecycle_status 分布 │ -│ ├─ active 97 个 │ -│ ├─ planning 51 个 │ -│ └─ completed 0 个 (不支持) │ -│ │ -│ 隔离问题: │ -│ 集成测试未设置 TEST_DATABASE_URL │ -│ → 默认连接本地 agent_system_dev │ -│ → 88 个定义污染 ❌❌ │ -└────────────────────────────────────────────┘ -``` - -**风险评估**: -- **数据污染**: 🔴 严重 - 无法清洁复现 -- **生命周期不一致**: 🔴 严重 - 47 个实例数据已破损 -- **隔离缺失**: 🟠 高 - CI/CD 不可信 - ---- - -## 五、安全性审计结论 - -### 5.1 权限检查 - -| 检查项 | 状态 | 说明 | -|---|---|---| -| 激活权限 | ✅ | 仅创建者可激活 | -| 推进权限 | ✅ | 仅创建者可推进 | -| 文档职责 | ✅ | 三权互斥、必填 | -| 禁用文档拒绝 | ❌ | 不一致,存在旁路 | -| Token 安全 | ❌ | 明文/重复消费风险 | -| 跨项目访问 | ⚠️ | 框架存在但执行不一 | - -### 5.2 威胁模型 - -**高风险场景**: - -1. **禁用文档旁路**(CVSS 6.5) - - 通过 SSE 或 Agent tool 绕过禁用检查 - - 修改方案: Task A5 `DocumentAccessDecider` - -2. **Token 重放**(CVSS 7.2) - - 激活 token 明文保存,可多次使用 - - 修改方案: Task A6 token hash + one-time - -3. **对话权限绕过**(CVSS 7.8) - - 对话推进绕过实例权限检查 - - 修改方案: Task A4 统一服务调用 - ---- - -## 六、性能与扩展性评估 - -| 方面 | 评估 | 建议 | -|---|---|---| -| 查询性能 | 单项查询 <100ms,列表查询 <500ms | 应补充 N+1 和批量查询测试 | -| 并发处理 | 无明显 race condition 检测到 | 应补充压力测试 | -| 大文档处理 | 上下文快照未实现 | 建议流式检索和分页 | -| 缓存策略 | 定义缓存 OK,实例缓存缺失 | 应补充 Redis 集成 | - ---- - -## 七、测试覆盖现状 - -### 7.1 单元测试 - -``` -✅ PASS 套件: - - projectinstance: 45 tests, avg 0.1s/test - - coordinator: 32 tests, avg 0.01s/test - - workflowdef: 28 tests, avg 0.05s/test - - server: 15 tests, avg 0.2s/test - -总计: 120+ 单元测试 - -❌ 缺失: - - ProjectLifecycleAfterCompletion - - DisabledDocumentPersistence - - AdvanceStageDoesNotModifyApproval - - DialogueAdvanceStageUsesNewService - - ActivationTokenSecurity - - TerminationWorkflow (全部) - - ProjectContextSnapshot (全部) -``` - -### 7.2 集成测试 - -``` -✅ 可运行: - - workflow_governance_pg_test.go - - phase5_fault_injection_pg_test.go - -❌ 问题: - - 未设置 TEST_DATABASE_URL 时连接开发库 - - 测试定义发布后无清理 - - 并发测试不完整 -``` - -### 7.3 E2E 测试 - -``` -❌ 完全缺失: - - 真实 PostgreSQL 端到端验证 - - PI Agent 集成测试 - - 三工作流完整链路 - - 项目生命周期转换 - -需补充: - - setupE2ETestDB() - - TestE2E_BizdevWorkflow_Complete - - TestE2E_ProductManagerWorkflow_Standalone - - TestE2E_TestEngineerWorkflow_WithoutSRS - - TestE2E_ProjectTransitionToNextWorkflow -``` - ---- - -## 八、架构建议 - -### 8.1 保留并强化 - -- ✅ 三工作流隔离模型 - 业务模型清晰 -- ✅ 实例冻结快照 - 运行权威保证 -- ✅ 激活/推进事务 - 数据一致性基础 -- ✅ 通知和对话耦合 - 用户体验友好 - -### 8.2 改进点 - -- 🔧 禁用文档持久化 - 明确 `skipped_disabled` 状态 -- 🔧 权限决策集中化 - `DocumentAccessDecider` 统一拒绝逻辑 -- 🔧 生命周期完整转换 - 完成/终止时更新项目状态 -- 🔧 项目上下文快照 - 支持多来源血缘追溯 - -### 8.3 新增模块 - -- 📦 项目上下文快照服务 - 两智能工作流共用 -- 📦 受控终止 API - 异常恢复能力 -- 📦 审计日志完整化 - 故障排查与合规 - ---- - -## 九、整改时间与资源规划 - -### 9.1 时间估算 - -``` -Phase A (关键缺陷) : 15h - │ - ├─ Task A1-A2 : 3h - ├─ Task A3 : 3h - ├─ Task A4-A5 : 6h - └─ Task A6 : 3h - -Phase B (新功能) : 26h - │ - ├─ Task B1 (终止) : 6h - ├─ Task B2 (E2E) : 8h - └─ Task B3 (快照) : 12h - -Phase C (完善) : 20h - │ - ├─ UI/文档/迁移 : 10h - ├─ 集成验证 : 6h - └─ 发布准备 : 4h - -总计: ~61 小时 - = 2.5 天(单人全职) - = 5 天(双人并行) -``` - -### 9.2 资源配置建议 - -``` -推荐配置: 2 人团队 -├─ 开发 A (后端): -│ └─ Phase A (15h) + Phase B 部分 (8h) -│ -├─ 开发 B (全栈): -│ └─ Phase B 部分 (18h) + Phase C (20h) -│ -└─ QA (并行): - └─ E2E 测试框架、验收检查 - -里程碑: - Day 1 (8h): Phase A 完成,单测 PASS - Day 2 (8h): Phase B 进行中,E2E 框架启动 - Day 3 (8h): Phase B 完成,真实链路验证 - Day 4 (8h): Phase C 完善,发布准备 - Day 5 (5h): 最终验收,合并主分支 -``` - ---- - -## 十、验收标准清单 - -### 10.1 功能验收(来自 `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459`) - -**7.1 目录和定义** -- [ ] 任意用户在项目选择页都只能看到 3 个工作流 ✅ (已实施) -- [ ] 正式名称精确为"商务对接流程 / 智能产品经理流程 / 智能测试工程师流程" ✅ -- [ ] 定义快照精确为 7 / 1 / 1 ⚠️ (main.v2.json 缺 2 个) -- [ ] 三个正式定义均没有流程级上游依赖 ✅ - -**7.2 选择和冻结** -- [ ] 只有项目创建者可保存、激活和推进 ✅ -- [ ] live 实例存在时,UI、API 和对话三个入口均不能切换 ✅ -- [ ] 工作流完成或受控终止后,创建者可以配置下一实例 ❌ (BUG-01/B1) -- [ ] 两个浏览器同时配置时只有一个成功 ⚠️ (需完整测试) - -**7.3 文档开关和三权** -- [ ] 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活 ✅ -- [ ] 禁用文档没有职责行、没有受控文档、没有运行按钮 ⚠️ (BUG-03) -- [ ] 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED` ❌ (BUG-05) -- [ ] 再启用只允许发生在 planning;激活后不能原地改变 ✅ - -**7.4 阶段门禁和提醒** -- [ ] 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断 ✅ -- [ ] 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒 ✅ -- [ ] readiness 后文档被驳回或标 stale 时,旧推进请求失效 ⚠️ (需验证) -- [ ] 推进事务不会修改任何文档审批状态 ❌ (BUG-02) -- [ ] 最后一阶段确认后实例为 completed,项目立即可配置下一流程 ❌ (BUG-01) - -**7.5 安全、恢复和真实链路** -- [ ] 跨项目、非成员、非职责人、已退出成员全部有服务端负例 ✅ -- [ ] API、SSE、异步任务、断线恢复、搜索、导出、RAG、Agent tool 的判定一致 ❌ (BUG-05) -- [ ] 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求 ✅ -- [ ] **使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路** ❌ (BUG-MISSING-04) -- [ ] 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案 ❌ (BUG-MISSING-01) - ---- - -## 十一、建议行动计划 - -### 11.1 立即行动(今天) - -``` -1. 确认 BUG-02 现状 (grep "UPDATE.*approved") -2. 启动 Task A1 修复(项目完成后生命周期) -3. 启动 Task A4 修复(对话推进新服务) -4. 启动数据库 00025 迁移设计(禁用文档标记) -``` - -### 11.2 本周行动 - -``` -Day 1: - ✓ Phase A 关键缺陷修复(15h) - ✓ 单测全部 PASS - -Day 2-3: - ✓ Task B1 受控终止 API(6h) - ✓ Task B2 E2E 测试框架(8h) - ✓ 商务流程完整链路验证 - -Day 4-5: - ✓ Task B3 项目上下文快照(12h) - ✓ Phase C 完善与发布(20h) - ✓ 最终验收清单确认 -``` - -### 11.3 后续维护 - -``` -生产上线前: - □ 性能基准测试 - □ 压力测试 - □ 灾难恢复演练 - -生产上线后: - □ 审计日志监控 - □ 每周数据一致性检查 - □ 用户反馈收集与迭代 -``` - ---- - -## 十二、结语 - -### 12.1 总体判定 - -**项目状态**: 🟠 **中等风险** → 需立即整改 - -**原因**: -1. 架构设计合理,业务需求清晰 -2. 核心框架 70% 已实现,技术选型无问题 -3. **关键性缺陷 3 个**(项目生命周期、推进状态、对话服务)必须本周修复 -4. **新功能 3 个**(快照、终止、E2E)需并行开发 -5. **数据污染**(88 个测试定义)影响可信度 - -### 12.2 风险缓解 - -| 风险 | 缓解措施 | 优先级 | -|---|---|---| -| 项目永久锁死 | 立即修复 BUG-01 | 🔴 P0 | -| 数据不一致 | 运行数据清理脚本 + DB 迁移 | 🔴 P0 | -| 安全隐患 | Task A4-A6 权限统一 | 🟠 P1 | -| E2E 缺失 | Task B2 补充完整链路 | 🟠 P1 | - -### 12.3 建议 - -1. **立即启动 Phase A**(5 天内完成关键缺陷修复) -2. **并行启动 Phase B**(E2E 测试框架必须本周启动) -3. **建立自动化验收流程**(CI 应包含验收标准检查) -4. **定期数据库审计**(周期性检查一致性) - ---- - -**审计完毕** -**下一步**: 技术评审确认整改计划,进入实施阶段 - -**相关文档**: -- `.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md` - 详细缺陷说明与整改方案 -- `.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md` - 可执行的任务拆分 - ---- - -*生成于 2026-09-12 14:50 UTC* +本文档已迁至 [audit/2026-09-12-audit-summary-report.md](audit/2026-09-12-audit-summary-report.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md b/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md index 34b343c3..777ff2d9 100644 --- a/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md +++ b/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md @@ -1,680 +1,3 @@ -# 项目全面审计与整改方案 +# 已迁移 -> **HISTORICAL** — 缺陷详解与 Phase 设计档案。执行状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 为准。 - -**日期**:2026-09-12 -**编制**:代码审计 -**状态**:待执行 -**范围**:功能完整性、实现缺陷、潜在bug 及整改优先级 - ---- - -## 一、执行现状总结 - -### 1.1 已完成的工作 - -| 项目 | 完成度 | 说明 | -|---|---|---| -| 业务决策文档 | ✅ 100% | `.doc/2026-09-12-three-workflows-strict-governance-remediation.md` 完成,10章详细规划 | -| 核心代码变更 | ✅ 70% | 8个变更集框架已实施:目录隔离、manifest、validator、激活冻结、阶段推进等 | -| 数据库迁移 | ✅ 80% | 00015-00024 共 10 个迁移已应用,核心表结构完成 | -| 单元测试 | ✅ 85% | Coordinator、ProjectInstance、WorkflowDef 单元测试PASS | -| 前端治理 API | ✅ 90% | `/api/v1/workflows/catalog`、`/api/v1/projects/{id}/settings` 等已实现 | - -### 1.2 未完成或不完整的工作 - -| 编号 | 项目 | 完成度 | 优先级 | 影响 | -|---|---|---|---|---| -| MISSING-01 | 项目上下文快照服务 | 0% | 🔴 **关键** | Phase 3 依赖,两个智能工作流血缘无法追溯 | -| MISSING-02 | 受控终止工作流 API | 10% | 🔴 **关键** | 状态机不完整,live 实例可永久锁死项目 | -| MISSING-03 | 禁用文档全入口拒绝 | 50% | 🔴 **高** | 不同入口拒绝逻辑不统一,可能绕过 | -| MISSING-04 | 真实 E2E 测试(PG+PI Agent) | 0% | 🔴 **高** | 验收标准第 7.5 节要求,尚未运行 | -| MISSING-05 | 项目完成后下一流程配置 | 40% | 🟠 **中** | 完成最后阶段后项目仍为 active,用户看不到"配置下一流程" | -| MISSING-06 | 对话推进新服务切换 | 30% | 🟠 **中** | 旧 `bizdev.ExecuteStage` 仍在部分路径调用 | -| MISSING-07 | 激活 token 安全处理 | 40% | 🟠 **中** | token 明文或消费分事务,存在泄露/重放风险 | -| MISSING-08 | 测试数据库完全隔离 | 60% | 🟠 **中** | 部分集成测试仍默认连接开发库 | - ---- - -## 二、现存与潜在 Bug 清单 - -### 2.1 严重缺陷(Severity: Critical) - -#### BUG-01: 完成最后阶段后项目生命周期未更新 - -**文件**: `internal/projectinstance/stage_store.go:128-158`, `internal/projectinstance/service.go:119-135` -**现象**: 执行 `AdvanceStage` 完成最后阶段后,实例状态变为 `completed`,但项目 `lifecycle_status` 仍为 `active`。 - -**代码现场**: -```go -// stage_store.go:AdvanceStage -after, err := s.store.AdvanceStage(ctx, instanceID, in.StageKey, in.ExpectedConfigRevision) -// ... 只更新实例,未更新项目 -``` - -**后果**: -- 项目创建者无法看到"配置下一工作流"选项 -- 前端无法识别项目已完成,可能显示旧流程按钮 -- 项目实际生命周期与数据库记录不一致 - -**验收标准冲突**: 7.4 "最后一阶段确认后实例为 completed,项目立即可配置下一流程" - -**整改方案**: -1. `AdvanceStage` 在同一事务中检查是否为最后阶段 -2. 若是最后阶段,同时更新 `projects.lifecycle_status` 为 `planning` -3. 清空 `projects.current_workflow_instance_id`(可选,视数据模型) -4. 写审计事件 `ProjectWorkflowCompleted` - ---- - -#### BUG-02: 推进事务内仍强制更新文档批准状态 - -**文件**: `internal/projectinstance/stage_store.go:71-158` -**现象**: 执行阶段推进时,SQL 语句中有类似逻辑将启用任务的文档强制设置为 `approved`。 - -**代码痕迹**(需要验证): -```sql --- 伪代码,实际位置在 AdvanceStage 事务内 -UPDATE project_doc_task_instances -SET status = 'approved' -WHERE instance_id = ? AND task_key = ? AND enabled = true; -``` - -**后果**: -- 违反业务规则 3.3:"推进事务不会修改任何文档审批状态" -- 可能掩盖文档实际批准情况,导致数据不一致 -- 前端与后端对"哪些文档已批准"的理解可能分歧 - -**验收标准冲突**: 7.4 "推进事务不会修改任何文档审批状态" - -**整改方案**: -1. 确认 `stage_store.go:AdvanceStage` 中是否存在此 UPDATE 逻辑 -2. 若存在,删除该 UPDATE 语句 -3. `AdvanceStage` 只改变阶段状态和实例状态,不触及文档 -4. 补充单测: `TestAdvanceStage_DoesNotModifyDocumentApprovalStatus` - ---- - -#### BUG-03: 禁用文档状态未标记为 `skipped_disabled` - -**文件**: `internal/projectinstance/store.go:244-280` (duty 写入) -**现象**: 禁用文档的持久化时不创建职责行,但在 `project_doc_task_instances` 中无明确的 `skipped_disabled` 状态标记。 - -**代码现场**: -```go -// store.go:SaveWorkflowPlan 或类似 -for _, doc := range docs { - if !doc.Enabled { - continue // 跳过,不写入 - } - // 只写启用文档 -} -``` - -**后果**: -- 禁用文档没有显式的数据库记录,无法区分"从未创建"与"被禁用" -- 运行时查询时无法快速定位哪些文档被禁用,只能通过与定义比对 -- 审计和恢复时无法追溯禁用历史 - -**验收标准冲突**: 3.2 "禁用后实例状态写为 `skipped_disabled`" - -**整改方案**: -1. `project_doc_task_instances` 表添加状态枚举支持 `skipped_disabled` -2. 激活时为禁用文档创建记录,状态明确设为 `skipped_disabled` -3. 查询、拒绝等所有入口统一检查此状态 -4. 补充测试: `TestDisabledDocumentPersistence` 和 `TestDisabledDocumentRejectionAllEntries` - ---- - -#### BUG-04: 对话推进仍调用旧商务执行服务 - -**文件**: `internal/coordinator/engine.go:672-811` -**现象**: 对话识别 `ADVANCE_STAGE` 意图后,调用 `bizdevSvc.ExecuteStage` 而非新的 `projectinstance.Service.AdvanceStage`。 - -**代码现场**: -```go -// engine.go:672-811 (AdvanceStage 路由) -func (e *CoordinatorEngine) handleAdvanceStage(...) { - // ... - result, err := e.bizdevSvc.ExecuteStage(ctx, ...) // ❌ 旧服务 - // 应该调用 e.instSvc.AdvanceStage(...) -} -``` - -**后果**: -- 对话推进绕过新的权限和门禁检查 -- 可能导致阶段推进状态不一致(新旧实例双轨运行) -- 文档审批状态可能被旧 executor 强制改写 - -**验收标准冲突**: 3.4 "两种入口都调用同一个 `AdvanceStage` 应用服务" - -**整改方案**: -1. 修改 `CoordinatorEngine.handleAdvanceStage` 以调用新服务 -2. 删除对 `bizdevSvc.ExecuteStage` 的依赖(或标记 deprecated) -3. 对话推进需要提取 `workflow_instance_id`(可从项目或上文获取) -4. 补充端到端测试: `TestDialogueAdvanceStage_UsesNewService` - ---- - -### 2.2 高优先级缺陷(Severity: High) - -#### BUG-05: 禁用文档的拒绝逻辑不一致 - -**文件**: 多处 -**现象**: 不同入口(API、SSE、Agent tool)对禁用文档的拒绝逻辑分散,缺少统一的"fail closed"决策器。 - -**问题点**: -- `stage_access.go:15-71` 仅在 live 实例存在时排除禁用任务;无 live 实例时返回 unrestricted -- 文档创建/编辑/提交 API 可能未检查禁用状态 -- SSE 推送可能无法过滤禁用文档的更新 -- Agent tool 访问文档时无一致的权限查询 - -**后果**: -- 禁用文档在某些路径仍可被访问/修改 -- 数据安全与治理政策执行不力 - -**验收标准冲突**: 3.2 "禁用后…不能通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动" - -**整改方案**: -1. 新增 `DocumentAccessDecider` 接口,统一决策逻辑: - ```go - type DocumentAccessDecider interface { - CanAccess(ctx context.Context, docTaskInstID int64, action string, userID int64) (bool, error) - } - ``` -2. 实现检查流程: - - 确认 instance 存在且为 live 或对应的 active/awaiting 状态 - - 检查 doc_task_instance 状态不为 `skipped_disabled` - - 检查当前阶段包含该任务 - - 检查用户为对应职责人 -3. 在所有入口(API、SSE、异步任务、搜索、导出、RAG、Agent tool)使用此决策器 -4. 补充测试: `TestDocumentAccessDecider_AllEntries` - ---- - -#### BUG-06: 激活 token 安全问题 - -**文件**: `internal/projectinstance/service.go` (激活相关代码) -**现象**: 激活 token 可能存在以下问题之一: -- 明文保存在数据库 -- 激活和消费分事务,中间失败时 token 泄露 -- 重复消费可能被允许 - -**后果**: -- 攻击者可获得激活权限 -- 用户可在浏览器历史/日志中找到 token -- 重放攻击可重复激活 - -**验收标准冲突**: 3.1 "激活时冻结…运行中不可静默修改" 的先决条件是原子激活 - -**整改方案**: -1. 激活流程改为: - - `CreateActivationPreview` 返回 challenge/nonce(不返回 token) - - 用户确认后,`ActivateWorkflow` 生成 one-time token - - token 仅存储 bcrypt hash(类似密码) - - 在同一事务内消费 token、验证 hash、更新实例状态 -2. token 过期时间设为 5 分钟 -3. 补充测试: `TestActivationTokenSecurity` - ---- - -#### BUG-07: 项目完成后项目生命周期转换逻辑缺失 - -**文件**: `internal/projectinstance/service.go`, `internal/projectworkflow/service.go` -**现象**: 完成一个工作流后,项目无法自动进入可选择下一工作流的状态。 - -**代码现场**: -```go -// projectinstance/service.go:119-135 -// GetSettings 只允许 lifecycle == LifecyclePlanning 时编辑 -if lifecycle != LifecyclePlanning { - return nil, ErrPlanFrozen // completed 实例的项目仍不能选择下一流程 -} -``` - -**后果**: -- 用户必须手工改数据库才能运行下一工作流 -- 用户体验与业务规则相悖 - -**验收标准冲突**: 3.1 "完成或受控终止后创建下一工作流实例" - -**整改方案**: -1. 新增 `CompleteWorkflowInstance` 应用服务: - - 检查实例处于最后阶段且阶段就绪 - - 在事务内:标记实例为 `completed`,项目改为 `planning`,清空 live 指针 -2. `AdvanceStage` 检查当前阶段是否为最后阶段,是则调用此服务 -3. 补充测试: `TestProjectLifecycleAfterCompletion` - ---- - -### 2.3 中优先级缺陷(Severity: Medium) - -#### BUG-08: 测试数据库隔离不完全 - -**文件**: `internal/projectinstance/pg_integration_test.go:19-49`,`internal/server/workflow_governance_pg_test.go:26-61` -**现象**: 集成测试未设置 `TEST_DATABASE_URL` 时默认连接本地开发库,导致测试数据污染。 - -**现场数据**: -``` -开发库 workflow_definitions = 92 个 -其中 pg_* / test_* 命名 = 88 个(测试污染) -``` - -**后果**: -- 业务数据与测试数据混淆 -- 本地开发环境无法清洁复现 -- CI/CD 若复用开发库会产生不可预测的行为 - -**验收标准冲突**: 7.5 "测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义" - -**整改方案**: -1. 所有 `*_test.go` 中强制要求 `TEST_DATABASE_URL`;未设置时 skip 或 fatal -2. 测试前创建隔离 schema 或独立库,测试后清理 -3. CI 配置中显式设置 `TEST_DATABASE_URL` 指向临时数据库 -4. 补充 CI 脚本检查:测试结束后确认开发库中无 `pg_*`、`test_*` 定义 - ---- - -#### BUG-09: 版本冲突时前端自动重试 - -**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:38-76,173-236` -**现象**: 当两个浏览器同时切换工作流时,第一个返回版本冲突,但前端自动取新版本再次提交,无需用户确认。 - -**代码现场**: -```typescript -// ProjectWorkflowSwitcher.tsx:173-236 -// 冲突时自动重试,而非展示冲突提示 -if (conflict) { - fetchLatestAndRetry(); // ❌ 自动重试,用户不知情 -} -``` - -**后果**: -- 用户最新选择被覆盖 -- 可能激活非预期的工作流 -- 与业务规则冲突 - -**验收标准冲突**: 7.2 "两个浏览器同时配置或推进时…另一个收到版本冲突并重新确认" - -**整改方案**: -1. 冲突时展示弹窗:"您的选择与其他编辑冲突,请重新确认" -2. 显示当前版本、冲突版本和新版本内容 -3. 用户确认后重新提交,而非自动重试 -4. 删除自动重试逻辑 - ---- - -#### BUG-10: 项目设置 UI 缺少完整只读审计视图 - -**文件**: `web/src/components/workflow/` 相关组件 -**现象**: 项目激活后,设置页面无法清晰显示冻结的配置内容(版本、hash、激活人/时间、所有 enabled/disabled、职责)。 - -**后果**: -- 创建者不知道实际冻结的是什么 -- 无法自助诊断权限问题 -- 审计信息不可见 - -**验收标准冲突**: 7.2 "live 配置缺少完整只读审计视图" - -**整改方案**: -1. 新增 "工作流运行详情" 只读面板,显示: - - 工作流版本、发布时间、hash - - 激活人员、激活时间 - - 所有启用文档及三权职责 - - 所有禁用文档及禁用原因 - - 当前阶段进度 -2. 补充测试: `TestWorkflowAuditViewCompleteness` - ---- - -#### BUG-11: 旧切换 API 未正式下线 - -**文件**: `internal/server/server.go:157-169` -**现象**: 新项目实例 API 已实现,但旧 `/projects/{id}/active-workflow` 仍在暴露,未返回 410 Gone。 - -**代码现场**: -```go -// server.go:157-169 -mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ❌ 仍暴露 -``` - -**后次**: -- 旧客户端可绕过新治理 -- 不能区分"不支持"与"已下线" - -**验收标准冲突**: 5 "旧服务端路由…应返回 `410 WORKFLOW_SWITCH_API_RETIRED`" - -**整改方案**: -1. 将 `/projects/{id}/active-workflow` 路由改为返回 410 Gone 和迁移指引 -2. 添加 deprecation 日志 -3. 补充测试: `TestLegacyAPIReturns410` - ---- - -### 2.4 低优先级缺陷(Severity: Low) - -#### BUG-12: 前端名称不一致 - -**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23` -**现象**: 前端硬编码的三个工作流名称与后端正式名称不一致。 - -**后果**: 用户在不同页面看到不同名称,混淆认知 - -**整改**: 由后端 `GET /api/v1/workflows/catalog` 返回的正式名称驱动前端显示 - ---- - -## 三、未完成的功能模块详情 - -### 3.1 项目上下文快照服务(ProjectContextSnapshot) - -**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:82-105` -**当前状态**: 规划完整,实现 0% -**关键要求**: - -1. **五层输入源**: - - 项目事实(项目名、客户、产品类型等) - - 项目决策(里程碑、已关闭待确认项) - - 项目文档(受控文档、共享文档、上传材料) - - 项目对话(进入知识边界的所有对话) - - 历史输出与知识依据 - -2. **不可变快照**: - - `project_context_snapshots` 表:记录项目、任务、截止时间、汇总 hash、创建人、冻结状态 - - `project_context_snapshot_sources` 表:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用 - -3. **冲突优先级**: - - 创建者确认事实/决策 > 已批准文档 > 上传材料 > 里程碑记录 > 普通对话 > 智能体总结 - -4. **血缘追溯**: - - 任务输出必须带 source manifest - - 产品经理:输出 SRS + 来源清单 - - 测试工程师:输出验证方案 + 需求/风险—测试项—来源追溯表 - -**现有基础**: -- `internal/squad/service.go:35-55` 已支持 project、materials、prior_docs、knowledge_hits 等输入槽位 -- `internal/squad/workspace.go:262-408` 已有 context 索引建立能力 -- `internal/bizdev/service.go:250-294` 已有部分项目事实输入逻辑 - -**整改方案**: -1. 新增 `internal/projectcontext/service.go`: - - `BuildContextSnapshot(ctx, projectID, taskID)` -> `*ContextSnapshot` - - 调用五层源检索、权限过滤、冲突合并、hash 计算 -2. 新增数据库表与迁移 -3. 产品经理与测试工程师都改用此服务 -4. 补充集成测试 - -**验收标准**: 7.5 -- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致 -- 产品经理/测试工程师输出中包含完整 source manifest 和被排除内容说明 - ---- - -### 3.2 受控终止工作流(WorkflowTermination) - -**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:109-131` (状态机) -**当前状态**: 状态表存在,API 和逻辑 0% -**关键要求**: - -1. **状态转换**: - ``` - active → termination_requested → terminated - ``` - -2. **操作约束**: - - 仅创建者可申请 - - 需二次确认 - - 需填写原因 - - 处理或取消在途任务 - - 生成审计 - -3. **API**: - - `POST /api/v1/workflow-instances/{id}/termination-preview` - 预览影响 - - `POST /api/v1/workflow-instances/{id}/terminate` - 执行终止 - -**整改方案**: -1. 新增 `internal/projectinstance/terminate.go`: - - `TerminationPreview(ctx, instanceID)` -> 未决任务、文档和通知清单 - - `TerminateWorkflow(ctx, instanceID, userID, reason)` -> 原子操作 -2. 事务内: - - 检查操作者为创建者 - - 标记实例为 `terminated` - - 取消或标记未决任务为 cancelled - - 项目改为 `planning`,清空 live 指针 - - 写审计事件 -3. 补充 API 路由和端到端测试 - -**验收标准**: 7.3 -- 创建者可以选择"受控终止"而非永久锁死 -- terminated 状态的项目可创建下一实例 -- 审计记录包含终止原因 - ---- - -### 3.3 真实 E2E 测试(PostgreSQL + PI Agent) - -**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459` (验收标准) -**当前状态**: 单元测试 PASS,E2E 0% -**要求**: - -1. 使用真实 PostgreSQL(不是内存 mock) -2. 使用真实 PI Agent 容器 -3. 完整链路: - - 创建项目 → 选择工作流 → 激活 → 推进各阶段 → 完成 → 配置下一工作流 -4. 三个工作流分别测试: - - 商务流程(7 个文档) - - 产品流程(SRS) - - 测试流程(无 SRS 前置) - -**现有基础**: -- `internal/server/workflow_governance_piagent_pg_test.go` 已有 PG 集成框架 -- PI Agent 容器已在 `docker-compose.yml` 中定义 - -**整改方案**: -1. 新增 `internal/server/e2e_workflow_test.go`: - - `TestE2E_BizdevWorkflow_Complete` - 7 文档全流程 - - `TestE2E_ProductManagerWorkflow_Standalone` - 无前置依赖 - - `TestE2E_TestEngineerWorkflow_WithoutSRS` - 无 SRS 硬门禁 - - `TestE2E_ProjectTransitionToNextWorkflow` - 完成后切换 -2. 设置 `TEST_DATABASE_URL` 指向隔离库 -3. 启动 PI Agent 容器(或 mock 其接口) -4. 逐步执行,记录结果 - -**验收标准**: 7.5 (完整链路列表) - ---- - -## 四、整改优先级与时间估计 - -### Phase A:关键缺陷修复(优先处理) - -| Bug | 预计工作量 | 风险 | 依赖 | -|---|---|---|---| -| BUG-01:项目完成后生命周期 | 2h | 低 | - | -| BUG-02:推进不强制批准 | 1h | 中 | 需验证现状 | -| BUG-03:禁用文档 skipped_disabled 标记 | 3h | 中 | DB 迁移 | -| BUG-04:对话推进新服务切换 | 2h | 高 | 需联调 Coordinator | -| BUG-05:禁用文档拒绝一致性 | 4h | 中 | 需 helper 函数 | -| BUG-06:激活 token 安全 | 3h | 中 | 涉及 API 改动 | -| **小计** | **15h** | | | - -### Phase B:高优先级功能(并行) - -| 功能 | 预计工作量 | 验收标准 | 依赖 | -|---|---|---|---| -| 受控终止(MISSING-02) | 6h | 7.3 | BUG-01 | -| 真实 E2E 测试(MISSING-04) | 8h | 7.5 | Phase A + 容器 | -| 项目上下文快照(MISSING-01) | 12h | 7.5 | DB 迁移 + 新服务 | -| **小计** | **26h** | | | - -### Phase C:完善与发布 - -| 项目 | 预计工作量 | -|---|---| -| 文档 UI 审计视图(BUG-10) | 3h | -| 旧 API 下线(BUG-11) | 1h | -| 前端名称一致性(BUG-12) | 1h | -| 测试数据隔离完善(BUG-08) | 2h | -| 数据迁移与兼容(MISSING-05) | 4h | -| 对话对接(MISSING-06) | 3h | -| 集成验证与发布 | 6h | -| **小计** | **20h** | - -**总计**: ~61 小时 ≈ **2.5 天(单人全职)**或 **5 天(双人)** - ---- - -## 五、整改执行计划 - -### 5.1 Day 1: 关键缺陷修复 - -**Morning (4h)**: -1. BUG-01 修复:AdvanceStage → 同事务更新项目生命周期 - - 修改 `stage_store.go` 和 `service.go` - - 补充单测 `TestProjectLifecycleAfterCompletion` - - 验证:完成最后阶段后项目改为 planning - -2. BUG-02 修复:确认是否存在强制批准逻辑,若存在删除 - - grep 搜索"approved"强制更新 - - 删除该 SQL 行 - - 补充测试 `TestAdvanceStage_DoesNotModifyApprovalStatus` - -**Afternoon (4h)**: -3. BUG-04 修复:对话推进切换到新服务 - - 修改 `coordinator/engine.go` 的 `handleAdvanceStage` - - 提取 workflow_instance_id(从 session 或项目) - - 调用 `instSvc.AdvanceStage` 替代 `bizdevSvc.ExecuteStage` - - 补充对话测试 - -4. BUG-06 开始:激活 token 安全重构 - - 设计 one-time token 与 hash 方案 - - 修改激活预览与激活 API - -### 5.2 Day 2: 继续缺陷修复 + 开始新功能 - -**Morning (4h)**: -5. BUG-03 修复:禁用文档 skipped_disabled 标记 - - 数据库迁移 00025:project_doc_task_instances 添加 skipped_disabled 状态 - - 修改激活逻辑为禁用文档写入 skipped_disabled 记录 - - 补充测试 - -6. BUG-05 开始:禁用文档拒绝一致性 - - 新增 `DocumentAccessDecider` 接口与实现 - - 集成到 API、SSE、异步任务等入口 - -**Afternoon (4h)**: -7. 受控终止开发(MISSING-02) - - 新增 `terminate.go` 服务 - - 实现终止预览和执行 API - - 补充测试 - -### 5.3 Day 3: 新功能开发与集成测试 - -**Full Day (8h)**: -8. 项目上下文快照初版(MISSING-01) - - 新增 `projectcontext/service.go` - - 实现快照构建与来源清单 - - 产品/测试工程师改用新服务 - -9. 真实 E2E 测试启动(MISSING-04) - - 编写 E2E 测试框架 - - 三个工作流链路验证 - - 文档与验证报告 - ---- - -## 六、质量保证与验收检查表 - -### 6.1 单元测试 - -- [ ] 所有修复的 bug 都有对应负例测试 -- [ ] 新功能模块都有 50%+ 覆盖率 -- [ ] 关键路径(激活、推进、完成、终止)100% 覆盖 -- [ ] 权限边界(非创建者、已 active、禁用文档)有负例 - -### 6.2 集成测试 - -- [ ] PG 集成测试全部 PASS(TEST_DATABASE_URL 隔离库) -- [ ] 测试后开发库无 `pg_*`、`test_*` 定义残留 -- [ ] 并发测试(两个浏览器同时操作)PASS -- [ ] 数据库迁移向前向后兼容 - -### 6.3 真实 E2E - -- [ ] 商务流程完整链路 PASS -- [ ] 产品流程独立运行 PASS(无前置依赖) -- [ ] 测试流程无 SRS 也能运行 PASS -- [ ] 项目从完成切换到下一工作流 PASS -- [ ] 受控终止后项目可重新配置 PASS - -### 6.4 验收标准 - -- [ ] 目录仅暴露三项正式工作流 -- [ ] 禁用文档全入口(API、对话、SSE、Agent tool)拒绝 -- [ ] 推进事务不改文档审批状态 -- [ ] 项目完成后立即可配置下一工作流 -- [ ] 对话推进使用新实例服务 -- [ ] 激活 token 原子且安全 -- [ ] 旧 API 返回 410 Gone - ---- - -## 七、风险预案 - -### Risk-1: 激活 token 改动影响现有流程 - -**应对**: 先保留双通道(新旧),shadow 运行,验证一致后下线旧通道 - -### Risk-2: 数据库迁移引入兼容性问题 - -**应对**: 新增迁移前备份数据库;迁移脚本包含回滚逻辑;测试向后兼容 - -### Risk-3: 对话推进改动影响用户体验 - -**应对**: 对话测试覆盖完整,先内测验证;保留原意图识别,改调用目标 - ---- - -## 八、文档与交付物清单 - -| 交付物 | 格式 | 目标受众 | -|---|---|---| -| 整改方案(本文档) | Markdown | 开发、QA、产品 | -| 单元测试新增用例 | Go test | 开发 | -| E2E 测试报告 | Markdown + 日志 | QA、产品 | -| 数据库迁移脚本 | SQL | DBA、开发 | -| API 文档更新 | OpenAPI / Markdown | 前端、集成方 | -| 项目上下文快照设计文档 | Markdown | 架构评审 | -| 发布说明 | Markdown | 用户、销售 | - ---- - -## 九、总结与建议 - -### 当前项目整体评估 - -| 方面 | 评分 | 说明 | -|---|---|---| -| **架构与设计** | 8/10 | 三工作流治理顶层决策清晰,状态机设计合理 | -| **实现完整度** | 5/10 | 核心框架 70%,关键功能(快照、终止)缺失,多个 bug | -| **代码质量** | 6/10 | 单元测试 OK,缺失 E2E;对话-服务耦合待解 | -| **数据一致性** | 4/10 | 项目生命周期转换不完整,禁用文档没有显式标记 | -| **安全性** | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 | -| **运维成熟度** | 6/10 | DB 迁移和测试隔离需完善 | - -### 建议 - -1. **优先完成 Phase A 缺陷修复**(2 天)以稳定当前功能 -2. **并行开发 Phase B 新功能**(3 天),特别是 E2E 测试以验证整体逻辑 -3. **建立自动化验收流程**:CI 应包括所有验收标准的检查 -4. **后续维护建议**: - - 禁用项目选择非正式工作流的自动检查(CI 中) - - 每次激活/推进/完成后都输出审计链(便于故障排查) - - 项目完成前端页面加"确认完成工作流"的双确认卡 - - 定期数据库快照与清理脚本(防止垃圾数据) - ---- - -**文档版本**: v1.0 -**最后更新**: 2026-09-12 14:45 UTC -**下一步**: 待产品&技术评审确认,进入实施阶段 +本文档已迁至 [remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md](remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md b/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md index 92b1fd41..aeb7f59c 100644 --- a/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md +++ b/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md @@ -1,706 +1,3 @@ -# Agent System 权限、设置与三类工作流完整实施方案 +# 已迁移 -## 1. 执行结论 - -当前系统已经完成了从原型向受控工作流平台演进所需的多数“结构件”:数据库账户与会话、系统角色/权限表、项目成员、工作流定义及版本、模板版本、项目工作流实例、阶段实例、文档任务实例、三权职责、激活确认、阶段推进请求、通知 Outbox、任务运行持久化和文档血缘均已存在。现有 Go 短测、前端测试和生产构建也能通过。因此,本轮不应推倒重做,而应完成最后一段也是最关键的一段:**统一授权权威、把设置真正落到服务端、让已发布工作流版本成为运行时唯一事实源,并将商务对接、智能产品经理、智能测试经理发布为可配置、可冻结、可执行、可审计的正式工作流。**[^1][^2][^3] - -但截至本次审计,系统还不能宣称“权限和设置已做全”,三个工作流也还不能按当前治理设计直接投入多人生产使用。核心原因如下: - -1. **权限表存在,但策略执行不完整。** 部分项目查询、工作流历史和血缘查询缺少对象级授权;创建项目只校验登录,不校验 `project:create`;工作流管理 API 仍统一要求超级管理员,未使用已入库的细粒度权限;系统权限计算还忽略绑定作用域、角色状态和 `valid_from`。[^4][^5][^6] -2. **阶段权限存在高风险放行路径。** 解析 live 实例发生数据库错误时会回退为“不限制”,多个列表、聊天、RAG/上下文过滤辅助函数也在错误时放行;拥有当前阶段任一文档职责的用户会获得该阶段全部文档任务权限,任务执行门禁还允许其运行任意 `task_key`。[^7][^8] -3. **设置界面与服务端权威尚未闭环。** 浏览器仍把 Bearer token 和会话对象放入 `localStorage`,登出只删除本地状态;个人资料保存、个人偏好和部分权限画像仍是前端本地数据,已有活动会话 API 未在用户设置中形成闭环。[^9][^10] -4. **三个工作流只是“登记过”,不是“完整接入”。** `main`、`product_manager`、`test_manager` 已作为发布种子存在,但都是单阶段包装;运行目录会把任意已发布版本压扁为第一阶段的第一个任务。商务对接真实的 V0.1/V0.5/V1.0 阶段仍硬编码在 BizDev 执行器中;产品经理和测试经理的五步 Agent 流程存在,但没有由版本化定义驱动。[^11][^12][^13] -5. **项目实例与文档治理还未成为同一条链。** 规划校验没有检查必需阶段/必需任务是否被整个遗漏,也没有校验三权人员是否为有效项目成员;实例持久化把所有阶段 `position` 写成 0;执行器又会在请求未传三权时回退到固定用户 2/3,并把文档阶段固定为 `V0.5_feasibility`,没有消费冻结实例中的职责和活动阶段。[^14][^15] - -因此建议把工作拆为三道发布闸门: - -- **闸门 A:授权止血。** 先关闭跨项目读取、错误放行、任意任务键、身份/会话本地权威等 P0;完成全部 API/数据通路的策略矩阵。 -- **闸门 B:配置与运行时合流。** 扩展工作流 schema,建立 `executor_key` 注册表和全阶段解释器,让项目实例、DocGov、任务运行、对话/RAG、文档血缘都从同一冻结快照取值。 -- **闸门 C:发布三个正式版本。** 以新版本而不是覆盖旧数据的方式发布三个工作流,完成迁移、真实 PostgreSQL、跨用户负例和真实 PI Agent E2E 后再开放生产选择。 - -本方案遵循当前系统已经确定的治理原则:生产身份只来自服务端会话;系统角色、项目角色和单文档三权职责分离;已发布版本不可原地修改;项目激活时冻结完整快照;同一项目只允许一个 live 工作流;当前流程完成或受控终止后才能选择下一个;门禁满足只发提醒,阶段推进必须由项目创建人明确确认。[^1] - -## 2. 本次研究范围与验证边界 - -### 2.1 已审阅范围 - -| 层 | 已审阅内容 | -|---|---| -| 数据库 | Goose `00014`–`00020`:成员、IAM、工作流/模板、项目实例、通知、任务运行 | -| 后端 | `internal/auth`、`authz`、`workflowdef`、`projectinstance`、`projectworkflow`、`bizdev`、`squad`、`server` | -| 前端 | 登录会话、RBAC 类型、用户设置、系统设置、项目设置、工作流切换/展示 | -| 业务执行 | 商务对接真实阶段;产品经理/测试经理 Agent 角色、步骤、模板、质量门禁、前置依赖和血缘 | -| 既有文档 | 2026-09-11 治理总方案、Phase 1/2 实施计划、当前 PG/CI/Soak/E2E 报告 | - -### 2.2 本轮已执行验证 - -```text -go test -short -timeout 8m \ - ./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \ - ./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/... -结果:全部通过 - -cd web && npm test -结果:170 项 Node tests + 22 项 Vitest tests 全部通过 - -cd web && npm run build -结果:TypeScript + Vite 构建通过;存在主 bundle 过大的非阻断警告 -``` - -这些结果证明当前分支能编译且现有回归未破坏,不证明跨租户授权、真实 PostgreSQL 事务、重启恢复和真实 PI Agent 长链路已满足本方案的发布门禁。当前测试报告中 PI Agent 全生命周期仍记录了 `/v1/run` 超时,且报告结尾又写“仍在运行”,应先修正文档状态,再以一次新的、带 commit SHA 和环境指纹的运行作为验收证据。[^16] - -### 2.3 外部设计基线 - -授权采用“默认拒绝、每次请求验证、对象标识不可猜测越权、失败安全退出、记录审计”的基线;动态项目、阶段和文档条件用 RBAC + ReBAC + ABAC 组合,而不是只靠全局角色。OWASP 明确建议默认拒绝并对每次请求执行权限判断;NIST RBAC 模型把用户、角色、权限、操作和对象建模为独立关系,并支持职责分离约束。[^17][^18] - -浏览器会话不再把认证 token 放在 `localStorage`。OWASP 指出 Web Storage 可被同源 JavaScript 读取,建议会话使用 `HttpOnly; Secure; SameSite` Cookie;Cookie 模式下同时补齐 CSRF 防护。[^19] - -## 3. 当前系统能力盘点 - -### 3.1 可以直接保留并扩展的能力 - -| 能力 | 当前状态 | 本方案处理 | -|---|---|---| -| 统一 API 认证中间件 | 已存在 | 保留;切换到安全 Cookie/CSRF,并在授权失败时统一错误模型 | -| 数据库账户、密码哈希、会话哈希 | 已存在 | 保留;增加密码/MFA/重置策略、会话前端闭环和安全事件 | -| 系统角色/权限/绑定 | 已存在 | 纠正多角色、作用域、有效期、状态和管理审计语义 | -| `project_members` | 已存在 | 增加 FK、项目业务角色多绑定、成员状态和职责候选资格 | -| 工作流草稿/发布/退役 | 后端基础存在 | 增加复制草稿、完整 schema、细粒度授权、发布影响预览和 UI | -| 模板 CAS/版本/扫描状态 | 基础存在 | 增加扫描 worker、隔离区、预览、发布/退役和引用影响分析 | -| 项目规划/预览/确认/冻结 | 基础存在 | 修复完整性校验、原子 token、阶段顺序、受控变更和下一个工作流 | -| 文档三权状态机 | 已存在 | 由实例职责驱动;加职责资格、再认证/签署策略和阶段门禁映射 | -| Outbox/通知/阶段推进请求 | 已存在 | 完成用户偏好、渠道、升级、去重和创建人确认体验 | -| 任务运行持久化/lease | 已存在 | 把任务与实例/阶段/任务定义绑定;细分 read/cancel/resume 权限 | -| 文档血缘/stale | 已存在 | stale 成为阶段退出阻断条件,提供影响分析和重新基线闭环 | - -### 3.2 当前成熟度判定 - -| 领域 | 代码骨架 | 服务端权威 | 前端闭环 | 生产验收 | 判定 | -|---|---:|---:|---:|---:|---| -| 认证与会话 | 高 | 中 | 低 | 中 | 需整改 | -| 系统 RBAC | 中 | 低 | 中 | 低 | 发布阻断 | -| 项目 ReBAC | 中 | 中 | 中 | 低 | 发布阻断 | -| 阶段/文档 ABAC | 中 | 低 | 中 | 低 | 发布阻断 | -| 用户设置 | 中 | 低 | 中 | 低 | 未做全 | -| 系统设置 | 中 | 中 | 中 | 低 | 未做全 | -| 项目设置 | 中高 | 中 | 中 | 低 | 关键断点 | -| 工作流设计/版本 | 中高 | 中 | 低 | 低 | 关键断点 | -| 三工作流执行器 | 高 | 低 | 中 | 低 | 尚未正式接入 | -| 审计与通知 | 中 | 中 | 低 | 低 | 尚未闭环 | - -## 4. 必须优先修复的问题清单 - -### 4.1 P0:在接入三个工作流前必须关闭 - -| ID | 问题 | 影响 | 整改与验收 | -|---|---|---|---| -| AUTH-001 | 工作流运行历史、文档血缘 handler 未调用项目对象授权 | 登录用户可能读取其他项目元数据/血缘 | 所有项目子路由统一经过资源加载 + `Authorize`;跨项目返回 404 或统一 403;加双用户 PG 负例 | -| AUTH-002 | 阶段访问解析或过滤出错时放行 | DB/策略故障可扩大文档、聊天、RAG、Agent 上下文可见范围 | 生产环境 fail closed;只对明确标记的 legacy 项目执行迁移期策略,且有截止版本和指标 | -| AUTH-003 | 工作流路由接受客户端覆盖 `task_key`;阶段成员可运行当前阶段任意任务 | 绕过工作流定义和文档职责 | 服务端只从 `workflow_instance_id + active_stage + task_instance_id` 推导 executor;拒绝不在快照中的任务 | -| AUTH-004 | 项目规划可以整个遗漏必需阶段/任务 | 可激活空壳或删减受控交付物的计划 | 对定义中每个 non-optional stage 和 required/blocking task 做反向完整性校验 | -| AUTH-005 | 三权用户未校验有效账户、项目成员和候选角色 | 可把无权或已停用用户写入审批链 | 激活前逐人校验 membership/status/eligibility/职责分离;激活后人员失效触发阻断事件 | -| AUTH-006 | 项目列表 SQL 把 `creator_id=1`/NULL 项目视为公开,旧切换逻辑有固定用户/项目 ID 豁免 | 演示兼容规则泄漏到真实授权 | 删除 ID 特判;显式 `project_visibility`/legacy migration,不以 creator ID 表达公开 | -| AUTH-007 | 项目创建接口未检查 `project:create` | 任意活动账户可立项 | handler/service 双层校验 `projects.create`,前端按钮仅作体验控制 | -| AUTH-008 | 项目成员可读取/取消其他成员任务运行,未区分动作 | 破坏他人运行和审计归属 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` 分权;取消他人任务须负责人或创建人 | -| AUTH-009 | 本地 token、仅本地 logout、失效 `/me` 后仍保留登录态 | XSS/撤销后前端假登录 | 改安全 Cookie;服务端 logout;`/me` 401 立即清空主体和缓存;权限加载失败敏感动作 fail closed | -| WF-001 | DBCatalog 将完整版本压扁为第一阶段第一任务 | 发布多阶段定义也不会按定义运行 | 移除 flatten 执行路径,新增实例编排器逐阶段/任务读取冻结快照 | -| WF-002 | DocGov 三权和阶段来自请求/固定默认值,不来自实例 | 配置的责任人和活动阶段不生效 | 由 `doc_task_instance_id` 解析 author/reviewer/approver/stage;禁止生产请求传入身份覆盖 | - -### 4.2 P1:首次正式发布必须完成 - -| ID | 问题 | 整改 | -|---|---|---| -| IAM-101 | `ListCapabilities` 忽略 `scope_type/scope_id`、角色状态和 `valid_from` | 引入带资源上下文的 PDP;系统能力只取 `scope_type=system, scope_id=0`,校验角色/账户/有效期 | -| IAM-102 | `users.role_id` 与 `user_role_bindings` 双权威,更新角色会删除其他绑定 | `user_role_bindings` 为唯一权威;`users.role_id` 只作迁移兼容后移除;支持多角色 | -| IAM-103 | `assigned_by` 被写成目标用户本身,角色+状态更新非原子且忽略角色更新错误 | 从 principal 传 actor;单事务变更;写不可变审计事件;失败整体回滚 | -| IAM-104 | `role-admin` 字符串直接赋予管理员身份,`perm:manage` 又作为所有权限通配 | 显式 `system.superadmin`;普通 `permissions.manage` 不再通配业务数据;至少两名受控管理员防死锁 | -| IAM-105 | 前端权限键只有最早 7 项,后端迁移已有更多权限 | 后端暴露 permission catalog;前端由 API 渲染,不维护硬编码联合类型作为事实源 | -| SET-101 | 用户资料保存只改 React state;偏好仅组件本地;活动会话 UI 缺失 | 增加 `/me/profile`、`/me/preferences`、`/me/notification-preferences` 和会话管理 UI | -| SET-102 | 管理中心工作流页只能列出/校验/发布,不能完整建模 | 增加创建、复制草稿、阶段排序、任务/职责/参与策略、模板选择、diff、发布、退役 | -| SET-103 | Office 模板进入 `pending` 后缺少扫描完成链 | 隔离上传 + scanner worker + 状态回调/轮询;只有 `ready` 可发布 | -| SET-104 | UI 宣称符合 21 CFR Part 11,但未实现电子签名控制 | 删除不实文案;如需合规,另立 e-sign scope(再认证、签署含义、签名绑定、审计、防篡改) | -| WF-101 | 所有阶段实例 `position=0` | 从定义快照持久化真实 position;增加唯一性与连续性校验 | -| WF-102 | 激活 token 明文保存且消费、激活非同一事务 | 仅存 token hash;`SELECT FOR UPDATE` 后在同一事务验证、消费和激活 | -| WF-103 | 推进会把全部启用任务强制标成 approved | 推进只允许已满足门禁的状态,不修正业务状态;不一致即事务失败 | -| WF-104 | stale 未纳入阶段门禁 | required upstream/downstream lineage 有 stale 时禁止推进,重新批准后清除 stale 并留痕 | -| WF-105 | 完成后缺少“选择下一工作流”与受控终止/变更 API | 实现 `completed/termination_requested/terminated` 全状态机及下一实例创建 | -| WF-106 | bootstrap 发现已有 published 版本就退出 | 种子升级采用显式版本 manifest;内容 hash 变化创建 v2 draft,经校验批准后发布 | - -### 4.3 P2:可在首发后持续增强 - -- 管理员 break-glass:理由、近期认证、限时、醒目标识、禁止代签、完整审计。 -- MFA/WebAuthn、企业 SSO/SCIM、组织层级和角色层级。 -- 策略模拟器、权限差异比较、定期访问复核和孤儿权限报告。 -- 工作流可视化 DAG;首版仍建议坚持线性阶段,减少编排复杂度。 -- 审计日志防篡改、WORM/外部归档和监管报表。 - -## 5. 目标授权架构 - -### 5.1 五层判定模型 - -每个敏感动作统一调用一个服务端策略决策点(PDP),判定表达式为: - -```text -ALLOW = authenticated(principal) - AND account.active - AND session.active - AND permission_allows(action, resource_type, scope) - AND project_relationship_allows(principal, project) - AND workflow_snapshot_policy_allows(principal, active_instance, stage) - AND document_policy_allows(principal, doc_task, document) - AND state_machine_allows(action, current_state) - AND separation_of_duty_allows(principal, action) - -unknown / missing policy / dependency error => DENY -``` - -| 层 | 回答的问题 | 数据权威 | -|---|---|---| -| 认证 | 这个请求是谁,账号/会话是否有效 | `users`、`auth_sessions` | -| 系统 RBAC | 是否具备创建、管理、发布、审计等平台动作 | role/permission/binding 表 | -| 项目 ReBAC | 是否属于该项目,承担哪些项目业务角色 | `project_members` + `project_role_bindings` | -| 工作流/阶段 ABAC | 当前实例、阶段、参与策略是否允许 | 冻结 `config_snapshot` + 实例状态 | -| 文档职责/状态 | 是否为该文档的编制/审核/批准人,当前状态能否执行动作 | `document_duty_assignments` + DocGov | - -### 5.2 角色分层 - -系统角色不再表达具体项目里的业务职责,项目角色也不再等同于某一份文档的三权。 - -| 范围 | 建议内置角色 | 用途 | -|---|---|---| -| 系统 | 超级管理员、安全管理员、用户管理员、工作流管理员、模板管理员、安全审计员、普通用户 | 平台配置和治理;业务项目数据不因管理员身份默认全开 | -| 项目 | 项目创建人、项目经理、商务 BD、产品经理、系统/研发工程师、测试、法规、QA、观察者 | 阶段参与、项目资料范围和业务动作候选资格 | -| 文档 | author、reviewer、approver | 绑定单个文档任务实例;必须是具体用户,默认互斥 | - -一个用户可以在同一项目绑定多个业务角色;角色绑定和文档职责均必须有 `valid_from/valid_until/status/assigned_by/reason`。静态职责分离在配置时阻止冲突,动态职责分离在动作时阻止同一主体对同一版本自审自批。 - -### 5.3 权限目录 - -权限键统一采用 `resource.action`,旧键通过一版兼容映射迁移,之后删除。建议首发目录: - -| 域 | 权限 | -|---|---| -| 系统 | `system.settings.view/manage`、`system.security.manage`、`system.audit.view/export` | -| 用户 | `users.view/create/edit/disable/reset_password`、`users.sessions.revoke` | -| 角色 | `roles.view/create/edit/retire/assign/review` | -| 工作流 | `workflow_defs.view/create/edit_draft/publish/retire`、`workflow_defs.impact_view` | -| 模板 | `templates.view/upload/download/publish/retire` | -| 项目 | `projects.create/view/edit/archive`、`projects.members.view/manage` | -| 项目流程 | `projects.workflow.view/configure/activate/terminate`、`projects.stage.advance` | -| 参与 | `workflow.chat.view/send`、`workflow.task.run`、`workflow.progress.view` | -| 任务运行 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` | -| 文档 | `documents.view/edit/submit/review/approve/export`、`documents.visibility.manage` | -| 通知 | `notifications.view/update`、`notification_policies.manage` | - -### 5.4 服务端执行点 - -不要在每个 handler 手写角色判断。建立: - -```go -Decision Authorize(ctx, Principal, Action, ResourceRef, Attributes) - -Decision { - Allowed bool - ReasonCode string - PolicyVersion string - Obligations []string // redact, require_recent_auth, audit_reason, etc. -} -``` - -- 路由中间件负责身份和粗粒度权限。 -- service 层在事务内重新验证对象关系和当前状态,防止 TOCTOU。 -- repository 查询默认带可见范围,不先查全量再在浏览器过滤。 -- SSE、附件下载、搜索、导出、RAG、Agent tools 使用同一个 `ResourceRef`/Decision。 -- 禁止把 `user_id`、`role`、`stage`、`work_dir` 或 duty 作为客户端可信授权输入。 -- 403/404 策略统一;审计记录 actor、resource、action、decision、reason、request_id、policy_version。 - -### 5.5 核心动作矩阵 - -| 动作 | 普通成员 | 项目业务角色 | 项目创建人 | 系统管理角色 | 文档三权 | -|---|---|---|---|---|---| -| 创建项目 | 需 `projects.create` | 同左 | 同左 | 不默认拥有,按绑定 | 无关 | -| 查看项目 | active membership | active membership | 是 | 仅 break-glass 或显式审计权限 | 无关 | -| 管理成员 | 否 | 项目经理可选 | 是 | break-glass | 无关 | -| 配置待激活流程 | 否 | 可提议 | 是 | 工作流管理员不能代替业务确认 | 无关 | -| 激活/终止流程 | 否 | 可申请 | 是 + 再确认 | 只可 break-glass | 无关 | -| 运行任务 | 否 | 阶段策略允许 + 对应 task permission | 同策略,不绕过 | 不默认 | author 或显式执行人 | -| 查看文档 | 文档策略允许 | 阶段/角色策略允许 | 仍受私密/合规策略 | 不默认 | 当前职责人允许 | -| 提交审核 | 否 | 否 | 不默认 | 不默认 | author | -| 审核 | 否 | 否 | 不默认 | 不默认 | reviewer 且非 author | -| 批准 | 否 | 否 | 不默认 | 不默认 | approver 且非 author/reviewer | -| 推进阶段 | 否 | 只能申请/接收提醒 | 明确确认 | 不替代业务确认 | 无关 | -| 发布工作流版本 | 否 | 否 | 无关 | 工作流发布权限 + 双人复核可选 | 无关 | - -## 6. 设置体系完整方案 - -### 6.1 用户设置 `/settings` - -| 页面 | 服务端能力 | 验收 | -|---|---|---| -| 个人资料 | `GET/PATCH /api/v1/me/profile`;姓名、邮箱、语言、时区;部门/工号受控只读 | 刷新、换设备仍一致;审计敏感字段变更 | -| 安全 | 修改密码、MFA 状态、活动会话、撤销其他会话、最近登录 | 修改密码撤销其他会话;撤销后下一请求 401 | -| 通知 | 站内/邮件渠道、事件类型、免打扰、升级策略 | Outbox 读取服务端偏好;关键审批提醒不可被完全关闭 | -| 偏好 | 主题、默认导出、语言、默认项目页、Agent 显示偏好 | 落库并有 schema 版本;不再只存在组件 state | -| 我的权限 | 服务端返回生效角色、作用域、有效期和权限来源 | 不由前端本地 role 推导;支持“为何有/无此权限” | - -安全会话改造:登录响应通过 `Set-Cookie: __Host-agent_session=...; Secure; HttpOnly; SameSite=Lax|Strict; Path=/` 建立会话;状态变更使用 CSRF token/origin 验证;logout 调服务端撤销当前会话。测试环境可通过独立 fixture 获取 Cookie,不在产品包保留任意身份切换。 - -### 6.2 项目设置 `/projects/{id}/settings` - -| 页面 | planning | active/awaiting | completed/terminated | -|---|---|---|---| -| 基本信息 | 创建人编辑 | 受控字段变更单 | 只读/归档 | -| 成员与业务角色 | 增删改,校验职责候选 | 变更需影响分析;不能留下无人职责 | 历史只读,可为下个实例配置 | -| 工作流选择 | 选已发布版本 | 冻结只读 | 可创建下一个 planning 实例 | -| 阶段/任务 | 配置 optional/default,required 不可关闭 | 冻结;仅受控变更 | 快照只读 | -| 模板版本 | 从 ready 版本选择 | 冻结 | 快照只读 | -| 三权职责 | 必填、互斥、成员/资格校验 | 变更单 + 未决审批处理 | 历史只读 | -| 参与/可见策略 | 从版本默认值继承,可按允许范围收紧 | 冻结;紧急收紧可走安全变更 | 历史只读 | -| 预览与激活 | diff + 门禁 + 二次确认 | 不显示“重新激活” | 显示下一流程入口 | -| 推进/终止 | 无 | 门禁满足后创建人确认;终止需原因/影响 | 展示完整审计 | - -项目创建人不是系统超级管理员。项目设置的“独占确认权”和系统权限的“是否允许操作接口”同时成立:例如可由项目经理编辑草案,但最终激活和阶段推进仍由创建人确认。 - -### 6.3 系统管理中心 `/admin/*` - -| 页面 | 必做功能 | -|---|---| -| 概览 | 服务/DB/Runner/Outbox/worker 健康、失败任务、待审批、策略版本 | -| 用户 | 创建、审批、启停、资料、重置密码、撤销会话、多角色绑定、批量导入 | -| 角色权限 | 权限目录、多角色、作用域、有效期、职责分离、影响预览、角色退役 | -| 工作流设计器 | 创建/复制草稿、阶段排序、任务、执行器、模板、输入输出、门禁、职责候选、参与/可见策略、校验、diff、发布、退役 | -| 模板库 | 隔离上传、扫描、预览、变量 schema、版本、发布/退役、引用关系 | -| 项目类型与合规 | `product_domain` 与 `compliance_profile` 分离;可用流程、必需文档和签署强度 | -| 通知自动化 | 事件、渠道、模板、频率、升级和去重 | -| 审计 | 按 actor/action/resource/result/request_id 查询和导出;高风险变更对比 | -| 安全 | 注册、审批、密码、MFA、会话时限、CSRF/CORS、上传限制、保留期、break-glass | - -管理端不能继续依赖硬编码权限清单。`GET /api/v1/admin/permissions` 返回目录和风险等级;每个页面使用服务端 capabilities 控制入口,但最终仍由 API 决策。 - -## 7. 工作流定义 Schema v2 - -现有 schema 只有阶段、位置、人工门禁和文档任务基本字段,无法表达运行绑定、参与策略、职责资格、输入输出和确定性质量门禁。建议新增 `schema_version: 2`: - -```json -{ - "schema_version": 2, - "workflow_key": "product_manager", - "product_domains": ["medical_device", "non_medical_software"], - "required_upstream": [], - "participation_policy": {}, - "completion_policy": {}, - "stages": [{ - "key": "requirements_baseline", - "name": "系统需求基线", - "position": 10, - "optional": false, - "entry_gate": {}, - "exit_gate": {}, - "participation_policy": {}, - "doc_tasks": [{ - "key": "system_reqs", - "executor_key": "squad.system_reqs.v1", - "required": true, - "blocking": true, - "template": {"asset_key": "system_reqs", "version": 2}, - "input_contract": {}, - "output_contract": {}, - "quality_gate_key": "quality.system_reqs.v2", - "eligible_project_roles": {}, - "visibility_policy": {}, - "retry_policy": {}, - "timeout_seconds": 3600 - }] - }] -} -``` - -发布校验必须至少验证: - -- key 格式和全局唯一;stage position 唯一且严格递增;必需阶段/任务不可缺失; -- `executor_key` 已注册且声明支持相应输入/输出;不再把未知任务落入 generic runner; -- template version 存在且 `scan_status=ready`,变量 schema 与 input contract 一致; -- 三权候选角色存在,且不会造成项目无人可配;author/reviewer/approver 默认互斥; -- 上游工作流和文档依赖无环、能解析到已发布版本; -- 每个 required/blocking task 有确定性质量门禁; -- 可见/参与策略有明确默认值,未知即拒绝; -- 发布后 definition JSON/hash 和所有引用版本不可变;编辑从已发布版本复制新 draft。 - -## 8. 三个工作流的正式定义 - -### 8.1 兼容性决定 - -当前项目和代码广泛使用 `main` 代表商务主线。首轮迁移**保留稳定 key `main`**,显示名统一为“商务对接”,避免破坏存量项目、任务记录和文档 ID;停止在新代码里把它解释成“任意默认流程”。`product_manager` 和 `test_manager` 保持现有 key。若未来希望改为 `business_engagement`,新增显式 alias 表,不直接改历史 key。 - -三个正式版本均以 v2 draft 创建和发布;不得修改已有 published v1,也不得依赖当前 `UpsertPublishedSeed` 自动覆盖。已 active 的 v1 项目继续使用原快照;planning 项目由创建人查看 diff 后主动升级。 - -### 8.2 商务对接 `main` v2 - -当前真实执行器已有以下阶段和任务,本方案将其搬入版本定义,执行器只保留能力注册,不再保留另一套阶段事实源。[^13] - -| 顺序 | 阶段 | 文档任务 | 必需/阻断 | 建议三权候选 | 退出门禁 | -|---:|---|---|---|---|---| -| 10 | `V0.1_triage` 闪电摸底与盲区探测 | `intake` 客户需求采集/初始需求表 | 是/是 | author: BD/PM;reviewer: 项目经理;approver: 创建人或商务负责人 | intake approved;关键项无缺失;无运行任务 | -| 20 | `V0.5_feasibility` 方案成型与法规对齐 | `research` 竞品调研;`feasibility_reg` 法规可行性;`prelim_design` 初步设计 | 全部是/是 | 按文档分别指派 BD、法规、研发;审核/批准分离 | 三文档 approved;无 stale/open change;entry inputs 已基线化 | -| 30 | `V1.0_quoting` 工程拆解与商业锁定 | `cdo_quote` CDO 报价与核算 | 是/是 | author: 商务/项目经理;reviewer: 技术/财务;approver: 创建人/授权商务负责人 | 正文和核算 XLSX hash 一致、approved;报价关键字段完整 | - -参与策略默认值: - -- BD 可参与 V0.1/V0.5 的 `intake/research`,不因“是项目成员”自动获得 `prelim_design` 或报价批准权。 -- 法规只访问被授权的法规任务及其显式上游;研发只访问初步设计及显式上游。 -- 创建人可看项目进度并确认推进,但不会自动获得某份文档的审核/批准动作。 -- 阶段完成只产生 `ready_to_advance` 通知;创建人确认后原子进入下一阶段。 - -### 8.3 智能产品经理 `product_manager` v2 - -项目层保持一个受控阶段,阶段内的五个 Agent step 是 executor 内部步骤,不把内部 agent step 误建成五个需要人工推进的项目阶段。现有代码已经定义需求梳理、系统工程、法规、成文、终审五角色和五步执行链,可直接注册为 `squad.system_reqs.v1`。[^20] - -| 项 | 正式配置 | -|---|---| -| 阶段 | `requirements_baseline` 系统需求基线,position=10,required/blocking | -| 文档任务 | `system_reqs`,输出受控《系统需求规格书》 | -| 执行器 | `squad.system_reqs.v1` | -| 模板 | `system_reqs` ready version;发布时固定版本 | -| 必需输入 | 项目五要素;已批准/显式基线化的客户需求或上游商务文档;项目材料清单 | -| 结构化输出 | `output.md`、`artifacts/requirements.json`、manifest/hash、质量报告 | -| 三权候选 | author: PM/系统工程;reviewer: 技术负责人/法规;approver: 创建人授权的批准人/QA | -| 质量门禁 v2 | 每条需求唯一 ID;来源、理由、优先级、可验证准则、验证方法齐全;无未替换占位;JSON 与正文一致;重复/冲突/孤儿需求为 0 | -| 完成门禁 | executor 成功 + deterministic gate 通过 + 文档 approved + 无 stale/open change/running task | - -当前质量门禁只检查正文中是否出现 `REQ-` 和宽泛的“测试/分析/审查”等词,达不到“需求集合完整、唯一、可追溯、可测”的正式门禁。v2 必须解析 `requirements.json`,以结构化集合为准,并把校验报告与文档版本绑定。[^21] - -### 8.4 智能测试经理 `test_manager` v2 - -| 项 | 正式配置 | -|---|---| -| 阶段 | `system_verification_planning` 系统验证策划,position=10,required/blocking | -| 文档任务 | `test_manager`,输出受控《系统验证方案及计划》 | -| 执行器 | `squad.test_manager.v1` | -| 上游条件 | 同项目最近一次已批准且非 stale 的 `system_reqs`;记录上游 doc/version/hash | -| 模板 | `test_manager` ready version;发布时固定版本 | -| 结构化输出 | `output.md`、必需的 `artifacts/test_cases.json`、coverage report、manifest/hash | -| 三权候选 | author: 测试;reviewer: 系统/法规;approver: 测试负责人/QA,三者互斥 | -| 质量门禁 v2 | 上游需求全集解析成功;每条 requirement 至少一条有效 case;case ID 唯一;步骤、预期、判据、环境、方法完整;覆盖率 100%;无孤儿引用 | -| stale 策略 | 上游 SR hash 变化立即将下游标为 stale,禁止提交/批准/阶段完成,完成影响分析与重新基线后解除 | - -现有 executor 已要求上游 SR approved 并建立血缘,也定义了 100% 覆盖的 Agent 目标;但当前确定性门禁只检查 `TC-/TEST-`、`REQ-` 字符串,并且 `test_cases.json` 仅在文件存在时校验 JSON,文件不存在不会失败。v2 必须把结构化用例文件和覆盖率报告设为必需产物。[^21][^22] - -### 8.5 三个工作流的串联语义 - -系统当前设计是“一项目最多一个 live 工作流”,不是三条流程同时 active: - -```text -商务对接 completed/受控 terminated - -> 创建人选择并配置 product_manager v2 - -> 产品经理流程 completed,系统需求 approved - -> 创建人选择并配置 test_manager v2 - -> 测试经理流程完成 -``` - -系统可以在前一流程门禁满足时推荐下一个流程并通知创建人,但绝不自动激活。上游依赖解析按文档类型 + workflow instance + approved version 查询,不依赖固定文件路径或仅由字符串拼出的 doc ID。 - -## 9. 配置到运行时的唯一权威链 - -必须建立以下单向链,禁止旁路: - -```text -published workflow version + ready template versions - ↓ creator configures / preview / confirms -immutable project workflow snapshot - ↓ creates ordered stage/task instances + duty assignments -active stage + authorized doc task instance - ↓ resolves executor, template, inputs, actor obligations -task run + DocGov document version + lineage + audit - ↓ deterministic gate + three-duty approval + no stale/open work -ready_to_advance notification - ↓ creator explicit confirmation -next stage OR workflow completed -``` - -具体约束: - -1. `POST task-runs` 接收 `doc_task_instance_id` 和业务输入,不接收可信 `user_id/role/stage/work_dir/reviewer_id/approver_id`。 -2. 服务端锁定实例和 task instance,验证 active stage、actor、executor、模板和当前状态。 -3. WorkDir 由服务端按 project/instance/task_run 生成并做路径约束。 -4. DocGov 从 duty assignment 创建/校验文档责任人,stage 来自 stage instance。 -5. 任务结果写入与运行终态、文档版本、manifest、lineage、outbox 使用事务/可恢复 saga,避免“显示完成但产物未落稳”。 -6. 列表、详情、导出、附件、搜索、SSE、RAG 和 Agent tool read 都使用同一资源授权上下文。 - -## 10. 数据库迁移方案 - -迁移号以合并时最新 Goose 版本为准,下表暂按 `00021+` 表示。 - -| 迁移 | 主要变更 | 兼容/回填 | -|---|---|---| -| 00021 IAM hardening | project_members.user_id FK;role/binding 状态、reason;审计 actor;权限键 alias | 校验孤儿成员后加 FK;旧 `users.role_id` 双读一版、停止写入 | -| 00022 project roles | `project_roles`、`project_role_permissions`、`project_user_role_bindings` | owner/member/viewer 映射为 owner/contributor/observer;原表保留 membership 状态 | -| 00023 settings | user preferences、notification preferences、security policy versions | 把可识别的 local preferences 一次性导入需用户确认;其余使用服务端默认 | -| 00024 workflow schema v2 | executor registry/version、schema fields、policy JSON schema/version | 不修改 v1 JSON;validator 按 schema_version 路由 | -| 00025 instance integrity | stage position、task executor/template/output snapshot、duty eligibility、change requests | 修正现有 position;对 active 数据先报告后修复,不静默重排 | -| 00026 authorization audit | `authorization_audit_events` 或统一 audit_event 扩展、policy version、request ID | 明确保留期和敏感字段脱敏 | -| 00027 workflow v2 manifests | 创建三个 v2 draft/版本 manifest | 只在 hash 匹配预期时创建;不覆盖用户自定义版本 | - -数据库约束建议: - -- live instance 部分唯一索引继续保留;增加 planning 与 live 状态转换约束测试。 -- `project_stage_instances(workflow_instance_id, position)` unique,position > 0。 -- task instance 保存 `executor_key/template_version/output_doc_type/quality_gate_key` 的冻结副本。 -- duty assignment 引用 active project membership;跨表动态条件用事务 trigger 或 service + deferred validation 实现。 -- activation token 只存 hash;高风险一次性 token 使用短 TTL、actor/project/plan hash 绑定。 -- published definition/template 通过数据库权限或 trigger 阻止 UPDATE/DELETE,不只依赖 Go service。 - -## 11. API 调整 - -### 11.1 身份与设置 - -```text -POST /api/v1/auth/login -> Set-Cookie -POST /api/v1/auth/logout -> revoke current session -GET /api/v1/me -PATCH /api/v1/me/profile -GET/PUT /api/v1/me/preferences -GET/PUT /api/v1/me/notification-preferences -GET /api/v1/me/sessions -DELETE /api/v1/me/sessions/{id} -POST /api/v1/me/password/change -``` - -### 11.2 权限与管理 - -```text -GET /api/v1/admin/permissions -GET/POST/PATCH /api/v1/admin/roles... -GET/POST/DELETE /api/v1/admin/role-bindings... -POST /api/v1/admin/authorization/simulate -GET /api/v1/admin/audit-events -POST /api/v1/admin/users/{id}/reset-password -POST /api/v1/admin/users/{id}/sessions/revoke -``` - -每个 admin endpoint 绑定独立 permission,不再通过 `requireSystemAdmin` 全包。 - -### 11.3 工作流与项目实例 - -```text -POST /api/v1/admin/workflows/{id}/versions/{v}/copy-draft -PATCH /api/v1/admin/workflows/{id}/versions/{v} -POST /api/v1/admin/workflows/{id}/versions/{v}/validate -GET /api/v1/admin/workflows/{id}/versions/{v}/impact -POST /api/v1/admin/workflows/{id}/versions/{v}/publish -POST /api/v1/admin/workflows/{id}/versions/{v}/retire - -GET/PUT /api/v1/projects/{id}/workflow-plan -POST /api/v1/projects/{id}/workflow-plan/preview -POST /api/v1/projects/{id}/workflow-plan/activate -POST /api/v1/projects/{id}/workflow-instances/{iid}/termination-requests -POST /api/v1/projects/{id}/workflow-instances/{iid}/terminate -POST /api/v1/projects/{id}/workflow-instances/{iid}/change-requests -POST /api/v1/projects/{id}/workflow-instances/{iid}/stages/{stage}/advance -POST /api/v1/projects/{id}/doc-tasks/{taskInstanceId}/runs -``` - -所有资源路径先验证 path 中 project/instance/stage/task/document 的归属一致性,避免用合法项目权限访问另一个项目的子资源。 - -## 12. 前端实施方案 - -1. **认证壳**:不从 `localStorage` 恢复 principal/token;启动时只调用 `/me`。401 清空全部敏感状态并跳转登录。 -2. **权限 Provider**:从 `/me` 获取 capabilities + scoped grants;按钮、菜单和路由只做 UX 控制,错误统一展示服务端 reason code。 -3. **用户设置**:现有 modal 拆到真实 API;接入活动会话;资料/偏好保存失败不更新本地成功态。 -4. **系统管理中心**:从单一大 modal 演进为路由页面;权限矩阵来自 catalog;高风险变更提供 diff、影响人数和二次确认。 -5. **工作流设计器**:线性阶段排序、每阶段多任务、executor 只从注册表下拉、模板版本选择、职责候选、参与/可见策略、JSON 高级视图、发布校验报告。 -6. **项目设置**:明确 planning/live/history 三态;live 快照只读;门禁列表展示每个阻断项;下一工作流必须由创建人确认。 -7. **工作台**:根据服务端返回的 allowed actions 渲染,不在前端用姓名/本地角色重新计算业务授权。 -8. **删除演练入口**:`UserProjectRightsModal` 的测试角色切换、旧 `SettingsModal`、本地模拟分支和生产 bundle 中的测试身份文案移出产品代码。 - -## 13. 分阶段交付计划 - -估时为单个熟悉代码库的小组工作日,安全修复与工作流建模可并行开发,但发布必须按闸门顺序。 - -### Phase 0:基线冻结与权限清单(1–2 天) - -- 固定 commit、DB schema、环境和三个 workflow v1 hash。 -- 自动导出全部 `/api/v1` 路由,建立 resource/action/owner/negative test 矩阵。 -- 修正当前 E2E 报告状态矛盾;归档一次干净的 short test 和 build 结果。 -- 输出:`authorization-matrix-v2.md`、migration preflight SQL、测试数据拓扑。 - -门禁:每个非公开路由都有责任 owner、策略和至少一个未授权负例;未知路由默认为拒绝。 - -### Phase 1:P0 授权止血(3–5 天) - -- 修复 AUTH-001–009、WF-001/002 的越权入口。 -- 建立统一 `Authorize`/ResourceRef 和 server-side allowed actions。 -- 删除固定管理员/演示项目 ID 豁免;生产禁用 permissive fallback。 -- Cookie/CSRF/logout/401 前端失效闭环。 - -门禁:匿名、跨用户、跨项目、跨阶段、错 task、错 child resource、DB authz fault 全部负例通过;SSE/RAG/Agent tool 同样验证。 - -### Phase 2:IAM 与设置权威化(4–6 天) - -- 完成 IAM-101–105 和用户/项目/系统设置 API。 -- 角色多绑定、作用域/有效期、permission catalog、原子用户变更和审计。 -- 用户资料、偏好、通知、活动会话 UI;管理中心权限拆分。 - -门禁:重启/换浏览器数据一致;权限收回和账号停用下一请求生效;至少两名管理员防锁死演练通过。 - -### Phase 3:工作流 Schema v2 与运行时合流(5–8 天) - -- 实现 schema v2、executor/quality gate registry、完整 validator。 -- 移除 `flattenVersion` 作为执行路径;编排器只读实例快照。 -- 修复 position、token 原子性、DocGov duty/stage 绑定、stale 门禁。 -- 完成受控终止、变更单和下一个工作流生命周期。 - -门禁:修改全局 published/latest 不影响 active 实例;请求伪造 stage/task/duty 无效;故障恢复后实例位置和职责不漂移。 - -### Phase 4:发布三个 v2 工作流(4–6 天) - -- 按 §8 创建 `main`、`product_manager`、`test_manager` v2 draft。 -- 绑定 ready 模板和 executor;补齐结构化门禁。 -- 对 planning v1 项目生成可读 diff,由创建人选择是否升级;active v1 不迁移。 -- 完成三个流程的串联推荐,但保持人工选择/激活。 - -门禁:三个版本通过静态校验、dry-run、单流程 PG E2E 和串联 PG E2E。 - -### Phase 5:管理端/项目端完整体验(4–6 天) - -- 工作流设计器、模板库、项目规划、门禁详情、影响预览、下一流程、终止/变更 UI。 -- 删除旧本地/演示权威路径和不实合规文案。 -- 可访问性、错误恢复、并发 diff/reconfirm。 - -门禁:产品经理无需改代码即可复制 v2 为 v3 草案、换模板/职责候选、校验并由有权者发布;普通管理员无法越权发布。 - -### Phase 6:发布验证与灰度(5–8 天) - -- 全量 Go/前端、race、PG、迁移升级/回滚、重启、worker 故障注入。 -- 真实 PI Agent 三工作流 E2E;长任务超时/恢复/取消;跨用户负例。 -- 备份恢复、日志脱敏、监控告警、容量和 bundle 分包。 -- 灰度一个内部项目,再扩到新项目;旧项目只读兼容指标归零后删除 fallback。 - -门禁:§14 全部完成;P0/P1 为 0;可恢复演练和回滚演练均有报告。 - -总体建议:**21–35 个小组工作日**。如多人并行,最短日历时间约 4–5 周;不应通过跳过负例、迁移和真实 Runner 验证压缩关键路径。 - -## 14. 测试与验收矩阵 - -### 14.1 授权负例 - -| 场景 | 预期 | -|---|---| -| 未登录访问任意非公开 API/SSE/附件 | 401,不泄漏资源存在性 | -| A 项目成员读 B 项目、run history、lineage、搜索、导出 | 403/404,审计 deny | -| 当前阶段 BD 请求研发 task key | 403;不创建 task_run/workdir/doc | -| 非职责人提交/审核/批准 | 403;状态、版本、审计不变 | -| author 尝试审核或批准同一版本 | 409/403 SoD violation | -| authz DB/策略加载故障 | 敏感路径拒绝,健康状态 degraded,触发告警 | -| 权限撤销后复用旧页面/旧 SSE/旧 Cookie | 下一次鉴权失败;流关闭或重新鉴权 | -| 猜测 task/document/template/blob ID | 不能跨项目读取 | -| 客户端伪造 user/role/stage/workdir/duty | 服务端忽略或 400;不得改变判定 | - -### 14.2 工作流配置与冻结 - -- v2 required stage/task 被遗漏、禁用、重复或错序时校验失败。 -- executor 未注册、模板非 ready、变量 schema 不匹配时禁止发布。 -- published version UPDATE/DELETE 在 service 和 DB 层均失败。 -- 激活 token 重放、过期、跨 actor、跨 project、plan hash 不同均失败。 -- 并发保存/激活/推进只成功一个;另一方收到 diff/reconfirm,不自动重试。 -- 修改 v3 不影响使用 v2 的 active 项目;历史 hash 可复算。 -- 流程未完成/未终止时不能创建第二个 live;完成后可配置下一个 planning。 - -### 14.3 三工作流 E2E - -**商务对接:** 按 V0.1 → V0.5 三任务 → V1.0 运行;每阶段文档分别走三权;未全部 approved 不产生 ready;满足后产生一次去重提醒;只有创建人确认推进。 - -**智能产品经理:** 从批准的输入基线生成 `requirements.json` 和正文;随机抽取、重复 ID、缺验证准则、正文/JSON 不一致均被确定性门禁拒绝;批准后可作为下游输入。 - -**智能测试经理:** 没有 approved SR、SR stale、hash 不匹配时拒绝启动;生成必需 `test_cases.json`;需求全集覆盖率必须 100%;上游更新后下游立即 stale 且不能完成。 - -**串联:** `main` 完成后只推荐 PM;创建人配置并激活;PM 完成后只推荐 Test;每个实例版本、模板、职责、输入 hash、输出 hash 和审计链可追溯。 - -### 14.4 运行与灾难恢复 - -- 应用、worker、PostgreSQL、PI Runner 分别重启,验证会话/任务/实例/Outbox 恢复。 -- PI Runner 超时后 task 可恢复或明确失败,不重复生成审批版本。 -- Outbox 重投不重复发阶段提醒;消费者幂等。 -- 迁移从 v20 的生产快照升级;备份恢复后 hash/权限/实例一致。 -- `go test -race`、前端测试、生产 build、依赖/镜像扫描、长期 soak。 - -## 15. 发布完成定义(Definition of Done) - -只有同时满足以下条件,才能宣布“权限、设置和三个工作流已按当前设计做全”: - -- [ ] 生产产品不存在任意身份切换、本地认证 fallback 或客户端身份权威。 -- [ ] 每个 API/SSE/RAG/Agent tool/附件通路都有服务端授权和跨用户负例。 -- [ ] 授权失败或依赖异常默认拒绝;不存在固定用户 ID、项目 ID 特权。 -- [ ] 系统角色、项目业务角色、文档三权分离且可审计;三权职责分离生效。 -- [ ] 用户、项目、系统三类设置均由服务端持久化,刷新/重启/换端一致。 -- [ ] 工作流、模板、权限管理使用各自细粒度 permission,而不是全员超级管理员。 -- [ ] 已发布工作流/模板不可变;项目激活冻结版本、模板、阶段、任务、策略和职责。 -- [ ] 同一项目最多一个 live;完成/受控终止后由创建人选择下一个。 -- [ ] 门禁满足只通知,不自动推进;创建人确认与推进在事务中完成。 -- [ ] `main` v2 完整执行 V0.1/V0.5/V1.0,不再由硬编码目录另行决定。 -- [ ] `product_manager` v2 结构化需求门禁通过;`test_manager` v2 实现 100% 需求覆盖和 stale 阻断。 -- [ ] DocGov 的 stage 和三权全部来自冻结实例,客户端不能覆盖。 -- [ ] PG、真实 PI Agent、重启恢复、故障注入、跨项目/跨阶段负例均有可复现报告。 -- [ ] P0/P1 缺陷归零,灰度/回滚/监控/告警和审计查询可用。 - -## 16. 风险与控制 - -| 风险 | 概率/影响 | 控制 | -|---|---|---| -| v1/v2 双执行权威并存 | 高/高 | feature flag 只选一个 orchestrator;记录每次 run 的 schema/executor/version;不静默 fallback | -| 存量项目职责/成员数据不完整 | 高/中 | preflight 报告;active 不强迁;planning 由创建人补全并确认 | -| 权限收紧影响现有演示项目 | 高/中 | 显式 legacy visibility 数据迁移;不保留 ID 豁免;灰度观察 deny 指标 | -| Cookie 改造引入 CSRF | 中/高 | SameSite + CSRF token + Origin/Referer 校验;状态变更不用 GET | -| 长 Agent 运行与 HTTP 超时 | 高/高 | 异步 task + lease/heartbeat + resumable worker;客户端订阅状态,不持有超长请求 | -| 结构化质量门禁误报 | 中/中 | schema version、明确错误定位、golden corpus、允许修复重跑但不可人工静默跳过 | -| 角色配置锁死管理员 | 中/高 | 双管理员、关键权限不可清空、变更影响预览、break-glass 离线流程 | -| 模板恶意文件/解析炸弹 | 中/高 | 隔离、扩展/MIME/签名、大小/解压限制、扫描、Web root 外 CAS;仅 ready 可引用 | - -## 17. 建议的首个迭代任务包 - -第一周不要先画完整工作流设计器,先完成以下可独立验收的任务: - -1. `AUTH-001`:给 run history/lineage 及所有项目子资源补统一对象授权和双用户 PG 负例。 -2. `AUTH-002`:阶段访问错误全部 fail closed,加入数据库故障注入测试。 -3. `AUTH-003`:workflow run/task run 改从 task instance 推导 task/stage/executor,客户端覆盖返回 400。 -4. `AUTH-004/005`:补必需项反向校验和 duty member/status/role eligibility 校验。 -5. `AUTH-006/007`:删除 ID 特判,项目列表改用 `ListVisibleProjectIDs`/membership join,创建项目校验 permission。 -6. `AUTH-009`:服务端 logout + `/me` 失效清理;设计 Cookie/CSRF 兼容迁移。 -7. `WF-001/002`:提交 schema v2 ADR 和 runtime authority contract,阻止新增旁路。 - -首周验收物应是:代码、迁移 preflight、授权矩阵、负例测试、更新后的安全报告。只有该闸门通过,才开始发布三个 v2 draft。 - -## 18. 交付物清单 - -- 本实施方案。 -- API 授权矩阵 v2(路由、动作、资源、策略、负例、owner)。 -- Schema v2 JSON Schema + executor/quality gate registry ADR。 -- Goose 00021+ 迁移和 preflight/rollback SQL。 -- 三个工作流 v2 manifest、模板版本清单和 golden fixtures。 -- 用户/项目/系统设置产品规格与 API contract。 -- 授权负例、PG、真实 PI Agent、迁移、恢复、soak 测试报告。 -- 灰度清单、监控面板、告警规则、回滚 runbook。 - -## 资料来源 - -[^1]: 当前治理原则与目标模型见 [2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md)。 -[^2]: IAM、工作流定义、项目实例、通知和任务持久化分别见 [00015 IAM](../deploy/postgres/goose/00015_2026-09-12-iam-core.sql)、[00016 workflow definitions](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql)、[00017 project instances](../deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql)、[00018 outbox](../deploy/postgres/goose/00018_2026-09-12-outbox-notifications-stage-advance.sql)、[00019 task runs](../deploy/postgres/goose/00019_2026-09-12-task-runs-events.sql) 和 [00020 worker lease](../deploy/postgres/goose/00020_2026-09-12-task-run-worker-lease.sql)。 -[^3]: 本轮验证命令与结果记录在本方案 §2.2;当前历史测试状态见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。 -[^4]: 系统能力查询没有限定 binding scope/role status/valid_from,且 role-admin 字符串直接判 admin,见 [internal/authz/service.go](../internal/authz/service.go#L26-L99)。 -[^5]: 创建项目只验证身份,见 [project_handlers.go](../internal/server/project_handlers.go#L16-L46);运行历史和血缘查询未做项目访问判断,见同文件 [run history/lineage](../internal/server/project_handlers.go#L221-L274)。 -[^6]: 工作流管理统一走 `requireSystemAdmin`,没有使用已经入库的 `workflow_defs.*`,见 [admin_workflow_handlers.go](../internal/server/admin_workflow_handlers.go#L13-L23);权限种子见 [00016](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql#L67-L82)。 -[^7]: `ResolveStageAccess` 在 live 查询错误时返回 unrestricted,且一个阶段任一职责会放开该阶段全部任务,见 [stage_access.go](../internal/projectinstance/stage_access.go#L15-L68);服务器过滤辅助函数也在错误时放行,见 [stage_access_helpers.go](../internal/server/stage_access_helpers.go#L23-L47)。 -[^8]: 任务门禁在 actor 能访问 active stage 时放过不匹配 task,见 [bizdev_stage_gate.go](../internal/server/bizdev_stage_gate.go#L40-L54);workflow run 接收客户端 task override,见 [project_handlers.go](../internal/server/project_handlers.go#L205-L218)。 -[^9]: token/session 存 localStorage 且 logout 只删除本地键,见 [web/src/api/auth.ts](../web/src/api/auth.ts#L306-L330);恢复 session 后 `/me` 失败被吞掉,见 [web/src/App.tsx](../web/src/App.tsx#L690-L703)。 -[^10]: 用户设置把偏好描述为浏览器本地并从前端角色推导权限,见 [UserSettingsModal.tsx](../web/src/components/user/UserSettingsModal.tsx#L68-L77) 与 [同文件](../web/src/components/user/UserSettingsModal.tsx#L673-L779);后端已有活动会话 API,见 [auth_handlers.go](../internal/server/auth_handlers.go#L162-L204)。 -[^11]: 三个单阶段种子见 [workflowdef/bootstrap.go](../internal/workflowdef/bootstrap.go#L63-L74);seed 遇到已有发布版本直接退出,见 [workflowdef/store.go](../internal/workflowdef/store.go#L364-L372)。 -[^12]: DBCatalog 只取首阶段/首任务,见 [workflowdef/catalog.go](../internal/workflowdef/catalog.go#L50-L82);现有 schema 能表达的字段见 [workflowdef/types.go](../internal/workflowdef/types.go#L15-L43)。 -[^13]: 商务流程真实阶段和任务仍由 [internal/bizdev/service.go](../internal/bizdev/service.go#L202-L223) 硬编码。 -[^14]: 规划 validator 只遍历客户端提交项,没有反向验证必需定义项是否缺失,见 [projectinstance/validator.go](../internal/projectinstance/validator.go#L37-L105);三权只校验非空和互斥,见 [同文件](../internal/projectinstance/validator.go#L108-L144)。 -[^15]: 阶段实例 position 固定写 0,见 [projectinstance/store.go](../internal/projectinstance/store.go#L244-L249);执行器默认 reviewer=2、approver=3 并固定阶段,见 [bizdev/service.go](../internal/bizdev/service.go#L383-L418)。 -[^16]: 当前报告的真实 PI Agent E2E 记录 `/v1/run` 超时,同时结论仍称“进行中”,见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。 -[^17]: [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)。 -[^18]: [NIST Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control) 与 [NIST SP 800-162 ABAC](https://csrc.nist.gov/pubs/sp/800/162/upd2/final)。 -[^19]: [OWASP Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)。 -[^20]: 产品经理和测试经理的 Agent 角色及职责见 [squad/workspace.go](../internal/squad/workspace.go#L648-L743),内部步骤见 [同文件](../internal/squad/workspace.go#L940-L1073)。 -[^21]: 当前产品/测试质量门禁见 [squad/quality_gate.go](../internal/squad/quality_gate.go#L108-L146)。 -[^22]: 测试经理对 approved SR 的前置校验和材料注入见 [bizdev/service.go](../internal/bizdev/service.go#L365-L381),stale 传播见 [projectworkflow/service.go](../internal/projectworkflow/service.go#L237-L265)。 +本文档已迁至 [remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md](remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-phase0-api-authz-matrix.md b/.doc/2026-09-12-phase0-api-authz-matrix.md index 3270d558..ad6d7dca 100644 --- a/.doc/2026-09-12-phase0-api-authz-matrix.md +++ b/.doc/2026-09-12-phase0-api-authz-matrix.md @@ -1,81 +1,3 @@ -# Phase 0 API 授权矩阵与术语冻结 +# 已迁移 -> 依据:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) Phase 0 -> 状态:Phase 0 止血基线(非完整 RBAC 权威化) - -## 一、术语冻结 - -| 术语 | 定义 | Phase 0 权威来源 | -|---|---|---| -| 系统角色 | 如 `role-admin`,决定系统级管理能力 | 服务端 `users.role_id`(内存/后续持久化) | -| 项目成员角色 | `owner` / `member` / `viewer` | 数据库 `project_members` + `internal/authz` | -| 文档职责 | 单文档 `author` / `reviewer` / `approver` | DocGov + 文档任务(Phase 1+ 解耦) | -| 登录主体 | 当前会话用户 | **仅** Bearer / `X-Session-Token` → `principalFromContext` | -| 前端权限 | `hasPermission` / `localStorage` roles | **非安全边界**,仅 UI 体验层 | - -**Phase 0 红线:** - -- 禁止新增依赖 `localStorage` 的权威业务状态。 -- 禁止产品 UI 身份模拟、`X-User-ID` 请求头、body `user_id` 覆盖 principal。 -- 对象级授权以服务端 middleware + 已挂载的 `requireProjectAccess` 为准。 - -## 二、公开路由(无需认证) - -| 方法 | 路径 | 说明 | -|---|---|---| -| GET | `/`, `/health`, `/api/v1/health` | SPA / 健康检查 | -| POST | `/api/v1/auth/login` | 登录 | -| POST | `/api/v1/auth/register` | 注册(若启用) | -| * | 非 `/api/*` | 静态资源 / SPA fallback | - -## 三、API 资源—动作—条件矩阵 - -图例:`authn`=需登录;`admin`=需 `role-admin`;`proj`=需 `requireProjectAccess`;`—`=未挂对象级授权(Phase 1 补齐) - -| 路由 | authn | admin | proj | Phase 0 备注 | -|---|---:|---:|---:|---| -| POST `/api/v1/projects` | ✓ | — | — | 创建人来自 token | -| GET `/api/v1/projects` | ✓ | — | — | 列表按 user_id 过滤 | -| GET `/api/v1/projects/{id}` | ✓ | — | ✓ | | -| GET `/api/v1/projects/{id}/workflows` | ✓ | — | ✓ | | -| PUT `/api/v1/projects/{id}/active-workflow` | ✓ | — | ✓ | | -| POST `/api/v1/projects/{id}/workflows/{key}/run` | ✓ | — | ✓ | | -| GET `/api/v1/projects/{id}/workflows/{key}/runs` | ✓ | — | ✓ | | -| GET `/api/v1/projects/{id}/lineage` | ✓ | — | ✓ | | -| GET `/api/v1/projects/{id}/documents` | ✓ | — | ✓ | | -| POST/GET `/api/v1/projects/{id}/assets` | ✓ | — | ✓ | | -| GET `/api/v1/workflows` | ✓ | — | — | | -| POST `/api/v1/chat` | ✓ | — | — | user_id 来自 principal | -| POST/GET `/api/v1/chat/stream` | ✓ | — | — | SSE;principal 强制 | -| GET `/api/v1/chat/turns/{id}` | ✓ | — | — | | -| POST/GET `/api/v1/tasks/run/stream` | ✓ | — | — | | -| POST `/api/v1/tasks/runs` 等 | ✓ | — | 部分 | task_run_auth | -| POST `/api/v1/admin/workspaces/reconcile` | ✓ | ✓ | — | | -| GET/PUT `/api/v1/context/user*` | ✓ | — | — | | -| GET `/api/v1/context/project` | ✓ | — | — | | -| GET/POST `/api/v1/chat/sessions` 等 | ✓ | — | — | 会话归属校验 | -| GET/POST `/api/v1/freeform-documents*` | ✓ | — | — | owner 校验在 service | -| GET/POST `/api/v1/docgov/*` | ✓ | — | — | DocGov 三权 | -| POST `/api/v1/auth/logout` 等 | ✓ | — | — | | -| GET/POST `/api/v1/admin/users` | ✓ | ✓ | — | | -| GET/PUT `/api/v1/admin/config` | ✓ | ✓ | — | | - -## 四、Phase 0 已知 P0-gap(→ Phase 1) - -| 缺口 | 说明 | -|---|---| -| 无 DB 时 authz 降级 | `authorizer.enabled()==false` 时任意已登录用户可访问任意 project_id(仅 dev/stub) | -| localStorage RBAC | 前端按钮可见性仍非服务端 capabilities | -| 阶段/文档 ABAC | 未实施;BD 跨阶段隔离在 Phase 3 | - -## 五、Phase 0 验收对照 - -| 门禁 | 验证方式 | -|---|---| -| 无身份切换 UI | `scripts/check-prod-bundle.sh` + 人工 | -| 匿名 API 401 | `TestP0_AnonymousBusinessAPIReturns401` | -| X-User-ID 无效 | `TestP0_XUserIDCannotAuthenticate` | -| body user_id 不覆盖 principal | `TestP0_BodyUserIDCannotOverridePrincipal` | -| 生产无种子用户 | `TestMemoryStore_MainEnvNoSeedUsers` | -| main 禁止 AllowInMemory | `TestValidateProductionSecrets_RejectsAllowInMemory` | -| CORS 无 `*` | `TestP0_CORSAllowlist` | +本文档已迁至 [audit/2026-09-12-phase0-api-authz-matrix.md](audit/2026-09-12-phase0-api-authz-matrix.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md b/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md index b491f3fd..812d69e5 100644 --- a/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md +++ b/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md @@ -1,99 +1,3 @@ -# Phase 1:账户与授权权威化 Implementation Plan +# 已迁移 -> **依据**:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) §5.2、§4、§12、Phase 1 -> **前置**:Phase 0 已合并(5 commits on `dev`,`8341168`) - -**Goal:** 登录、角色、权限、项目成员关系全部以数据库 + 服务端策略为唯一权威;前端只消费 `capabilities`;重启后会话/账户策略仍有效;禁用账户下一请求失效。 - -**Architecture:** Goose 迁移新增 IAM 表 → `PostgresAuthStore` 替换 `MemoryStore`(dev 可 feature flag 回退)→ `AuthorizationService` 统一 RBAC + `project_members` + admin 判定 → `/api/v1/auth/me` 返回 capabilities → 管理端用户/角色 API 持久化 → 前端移除 localStorage 权限权威。 - -**Tech Stack:** Goose、pgx、现有 `internal/auth`、`internal/authz`、React/Vite。 - -**明确不在本阶段:** 工作流版本模型、阶段 ABAC、capabilities 到每个 DocGov 动作的全覆盖(先系统 + 项目 + 已挂 authz 路由)。 - ---- - -## 完成门禁 - -| 门禁 | 判定 | -|---|---| -| 持久化账户 | 重启后 users/roles 仍在 DB | -| 持久化会话 | token 存哈希;logout/禁用立即失效 | -| 无 localStorage RBAC 权威 | `AdminSettingsModal` 读写 API;`hasPermission` 仅 UI 兜底并标注 deprecated | -| 项目成员 CRUD | 创建者可增删改成员;API 测试 | -| 负例 | 禁用用户 token → 401;跨项目已挂 authz → 403 | - ---- - -## 任务分解 - -### Task 1 — IAM 数据库迁移(`feat(db)`) - -新建 `deploy/postgres/goose/00015_iam_core.sql`: - -- `users`(id, username, display_name, email, status, department, employee_id, locale, timezone, created_at, updated_at) -- `user_credentials`(user_id, password_hash, password_changed_at, failed_count, locked_until) -- `auth_sessions`(id, token_hash, user_id, created_at, last_seen_at, idle_expires_at, absolute_expires_at, revoked_at, ip_hash, user_agent) -- `roles` / `permissions` / `role_permissions` / `user_role_bindings` -- seed:`role-admin` + 核心 permissions + 从 MemoryStore dev 用户回填(仅 dev/test 迁移脚本) - -约束:username unique;token_hash unique;至少一个 super-admin binding。 - -### Task 2 — PostgresAuthStore(`feat(auth)`) - -- `internal/auth/pg_store.go` 实现 `AuthStore` -- 会话:Login 写 `auth_sessions`(只存 SHA256(token));ValidateToken 查库 + 更新 last_seen -- Logout/RevokeAll 标记 revoked_at -- `server.go`:有 `ContextDbHost` 时用 PgStore,否则 dev 仍 MemoryStore - -### Task 3 — AuthorizationService(`feat(authz)`) - -- `internal/authz/service.go`:`Capabilities(ctx, userID) []string` -- `HasPermission(ctx, userID, perm, scope)` 组合系统 role_bindings + `project_members` -- 替换 scattered `role-admin` 硬编码 → `HasSystemPermission(..., "system.admin")` 或保留 admin role_id 映射 -- `requireAdmin` / `requireProjectAccess` 改调用 Authorizer + AuthzService - -### Task 4 — Auth API 扩展(`feat(api)`) - -- `GET /api/v1/auth/me` 增加 `capabilities: string[]` -- 会话列表/撤销(用户设置 Phase 1 最小版):`GET/DELETE /api/v1/auth/sessions` -- Admin users/roles CRUD 对齐 DB(现有 handler 改接 PgStore) - -### Task 5 — 项目成员 API(`feat(api)`) - -- `GET/POST/PUT/DELETE /api/v1/projects/{id}/members` -- 仅 owner/creator + `projects.members.manage` 可写 -- 与 `project_members` 表对齐;禁止把 author/reviewer/approver 写入成员 role - -### Task 6 — 前端 capabilities(`feat(web)`) - -- `authClient.me()` 缓存 capabilities -- `engine/rbac.ts`:`hasPermission` 优先读 capabilities;localStorage roles 只读迁移提示 -- `AdminSettingsModal` / `UserProjectRightsModal` 成员编辑走 API -- 移除 `loadRoles(DEFAULT_ROLES)` 作为权威初始化(保留 demo 数据只读展示直至导入完成) - -### Task 7 — 测试与报告(`test` / `docs(test)`) - -- `internal/auth/pg_store_test.go`(testcontainers 或 stub pg) -- `internal/authz/service_test.go` -- 扩展 `security_p0_test` + 跨项目 403(需 DB fixture) -- `.doc/test-reports/2026-09-12-phase1-iam-authz-test-report.md` - ---- - -## 建议提交节奏 - -1. `feat(db):` IAM goose migration + seed -2. `feat(auth):` PostgresAuthStore + session persistence -3. `feat(authz):` AuthorizationService + admin gate -4. `feat(api):` members CRUD + auth/me capabilities -5. `feat(web):` frontend capabilities consumer -6. `test(docs):` Phase 1 report - ---- - -## 风险 - -- **双写期**:MemoryStore 与 PG 并存时须单一 Store 注入,避免混用。 -- **ID 对齐**:现有 `projects.creator_user_id` / memory user id 与 PG users.id 迁移需一次性回填脚本。 -- **前端降级**:capabilities 未加载前 fail closed(禁用敏感按钮,不默认 allow)。 +本文档已迁至 [remediation/2026-09-12-phase1-iam-authz-implementation-plan.md](remediation/2026-09-12-phase1-iam-authz-implementation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md b/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md index 8d8db223..b8e74849 100644 --- a/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md +++ b/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md @@ -1,23 +1,3 @@ -# Phase 2:工作流设计器与模板库 Implementation Plan +# 已迁移 -> **依据**:`.doc/2026-09-11-production-ready-workflow-governance-plan.md` §7、§15 Phase 2 - -**Goal:** 工作流定义版本化入库;模板 CAS 资产库;Admin 草稿/校验/发布/退役;静态 catalog bootstrap;运行时 DBCatalog。 - -**不在本阶段:** 项目激活冻结、instance 快照、阶段 ABAC(Phase 3)。 - -## 完成门禁 - -| 门禁 | 判定 | -|---|---| -| 已发布版本不可变 | Publish 后 UpdateDraft 拒绝 | -| 非法工作流不能发布 | Validate 失败 → 422 | -| 旧 catalog bootstrap | BootstrapSeeds 幂等写入 5 套 published v1 | -| 运行时读 DB | NewCatalog 优先 DBCatalog | - -## 已交付模块 - -- `deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql` -- `internal/workflowdef/` — store, service, validator, catalog, bootstrap -- `internal/server/admin_workflow_handlers.go`, `admin_template_handlers.go` -- `web/src/api/workflowAdmin.ts` + AdminSettingsModal workflows Tab +本文档已迁至 [remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md](remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-quick-reference-guide.md b/.doc/2026-09-12-quick-reference-guide.md index 6816a20a..b2a56520 100644 --- a/.doc/2026-09-12-quick-reference-guide.md +++ b/.doc/2026-09-12-quick-reference-guide.md @@ -1,461 +1,3 @@ -# 项目审计快速参考指南 - -**用途**: 开发/QA 快速定位问题、理解整改方向 -**格式**: 结构化索引,支持搜索和导航 - ---- - -## 一、关键数字一览 - -| 指标 | 数值 | 说明 | -|---|---|---| -| 项目完成度 | 70% | 架构完整,核心功能大部分实现,缺新功能和 bug 修复 | -| 已确认缺陷 | 12 个 | 3 个 critical,4 个 high,5 个 medium | -| 未完成功能 | 3 个 | 项目上下文快照、受控终止、E2E 测试 | -| 整改工作量 | 61h | 单人 2.5 天,双人 5 天 | -| 单元测试 | 120+ | 85% 覆盖主要包 | -| E2E 测试 | 0% | **需补充** | -| 数据污染 | 88 个定义 | 测试定义混入开发库 | - ---- - -## 二、快速诊断矩阵 - -### 症状 → 原因 → 解决方案 - -``` -症状 1: 完成工作流后项目仍显示为"正在运行",无法配置下一个工作流 -├─ 原因: BUG-01 - AdvanceStage 完成最后阶段时未更新项目 lifecycle -├─ 代码位置: internal/projectinstance/stage_store.go:128-158 -├─ 优先级: 🔴 P0 CRITICAL -└─ 解决: Task A1(2h) - └─ 同事务更新 projects.lifecycle_status = 'planning' - -症状 2: 禁用的文档仍然可以在某些页面被启动/编辑 -├─ 原因: BUG-05 - 拒绝逻辑分散,不同入口检查不一致 -├─ 代码位置: stage_access.go, API, SSE, Agent tools 多处 -├─ 优先级: 🔴 P1 HIGH -└─ 解决: Task A5(4h) - └─ 实现 DocumentAccessDecider,统一所有入口 - -症状 3: 对话中说"推进工作流"有时不生效或使用旧流程 -├─ 原因: BUG-04 - Coordinator 调用旧 bizdevSvc.ExecuteStage -├─ 代码位置: internal/coordinator/engine.go:672-811 -├─ 优先级: 🔴 P0 CRITICAL -└─ 解决: Task A4(2h) - └─ 改为调用 instSvc.AdvanceStage - -症状 4: 阶段推进后发现文档被强制标记为"已批准",但用户未操作 -├─ 原因: BUG-02 - AdvanceStage SQL 中有强制更新批准状态的逻辑 -├─ 代码位置: internal/projectinstance/stage_store.go(需 grep 验证) -├─ 优先级: 🔴 P0 CRITICAL -└─ 解决: Task A2(1h) - └─ 删除 UPDATE 批准状态的 SQL 行 - -症状 5: 测试在开发环境运行后,88 个奇怪的 pg_* 定义出现在工作流目录 -├─ 原因: BUG-08 - 集成测试未设置 TEST_DATABASE_URL,默认连接开发库 -├─ 代码位置: internal/projectinstance/pg_integration_test.go -├─ 优先级: 🟠 P1 MEDIUM -└─ 解决: Task BUG-08(2h) - └─ 强制要求 TEST_DATABASE_URL;测试后清理 - -症状 6: 激活工作流时 token 可能在浏览器历史中看到,或被重复使用 -├─ 原因: BUG-06 - Token 明文保存,消费分事务,不是 one-time -├─ 代码位置: internal/projectinstance/service.go(激活相关) -├─ 优先级: 🟠 P1 HIGH -└─ 解决: Task A6(3h) - └─ Token → hash + one-time,同事务消费 - -症状 7: 产品经理流程不运行,测试工程师流程无法启动,提示"需先运行产品流程" -├─ 原因: MISSING-06 - test_manager manifest 中仍有 upstream 依赖 -├─ 代码位置: internal/workflowdef/manifests/test_manager.v2.json -├─ 优先级: 🟠 P1 HIGH -└─ 解决: Task B3(需先删除测试流程的上游依赖) - └─ 修改 manifest,删除 required_upstream_workflow - -症状 8: 选择工作流时前端显示"商务流程",但服务返回的名称不一致 -├─ 原因: BUG-12 - 前端硬编码名称 vs 后端正式名称不同步 -├─ 代码位置: web/src/components/workflow/ProjectWorkflowSwitcher.tsx -├─ 优先级: 🟢 P2 LOW -└─ 解决: 由后端 GET /api/v1/workflows/catalog 驱动前端显示 - -症状 9: 无法手工删除已完成的工作流实例,项目永久处于"运行中" -├─ 原因: MISSING-02 - 受控终止 API 未实现 -├─ 代码位置: (缺失) -├─ 优先级: 🔴 P1 CRITICAL -└─ 解决: Task B1(6h) - └─ 实现 TerminateWorkflow API,二次确认 + 原因记录 - -症状 10: 产品经理和测试工程师输出中缺少"来源追溯",无法知道数据从哪来 -├─ 原因: MISSING-01 - 项目上下文快照服务未实现 -├─ 代码位置: (缺失) -├─ 优先级: 🔴 P1 CRITICAL -└─ 解决: Task B3(12h) - └─ 实现 ProjectContextSnapshot 服务,包含血缘表 -``` - ---- - -## 三、代码热点地图 - -### 高风险区域(需特别关注的文件) - -``` -🔴 CRITICAL -├─ internal/projectinstance/stage_store.go -│ ├─ BUG-01: AdvanceStage 不更新项目生命周期 -│ ├─ BUG-02: 推进强制批准文档(需验证) -│ └─ 位置: 第 71-158 行 -│ -├─ internal/coordinator/engine.go -│ ├─ BUG-04: 对话推进调用旧服务 -│ └─ 位置: 第 672-811 行(handleAdvanceStage) -│ -├─ internal/projectinstance/service.go -│ ├─ BUG-01: 完成后生命周期(同上) -│ └─ 位置: 第 119-135 行(SaveWorkflowPlan) - -🟠 HIGH -├─ internal/projectinstance/stage_access.go -│ ├─ BUG-05: 禁用文档拒绝逻辑不一致 -│ └─ 位置: 第 15-71, 90-104 行 -│ -├─ web/src/components/workflow/ProjectWorkflowSwitcher.tsx -│ ├─ BUG-09: 版本冲突自动重试 -│ ├─ BUG-12: 硬编码名称 -│ └─ 位置: 第 16-23, 38-76, 173-236 行 - -🟡 MEDIUM -├─ internal/projectinstance/pg_integration_test.go -│ ├─ BUG-08: 未设置 TEST_DATABASE_URL -│ └─ 位置: 第 19-49 行 -│ -├─ internal/workflowdef/manifests/test_manager.v2.json -│ ├─ 依然有 upstream 依赖(需删除) -│ └─ 位置: 第 1-23 行 -``` - ---- - -## 四、整改优先级排序 - -### 必须在本周内完成(优先级递减) - -``` -□ P0-1: BUG-01 项目完成后生命周期 (2h) - → 项目永久锁死的根本原因 - -□ P0-2: BUG-04 对话推进新服务切换 (2h) - → 权限检查绕过 - -□ P0-3: BUG-02 推进不强制批准 (1h) - → 数据违反业务规则 - -□ P1-1: BUG-05 禁用文档一致性 (4h) - → 安全隐患 - -□ P1-2: BUG-06 激活 token 安全 (3h) - → 存在泄露/重放风险 - -□ P1-3: Task B1 受控终止 API (6h) - → 恢复能力必需 - -□ P1-4: Task B2 E2E 测试 (8h) - → 验收标准要求 - -可以延后(下周处理) - -□ P2-1: BUG-03 禁用文档 skipped_disabled (3h) -□ P2-2: BUG-08 测试隔离完善 (2h) -□ P2-3: BUG-10 项目设置审计视图 (3h) -□ P2-4: BUG-09 前端冲突自动重试 (1h) -□ P2-5: BUG-11 旧 API 下线 (1h) -□ P2-6: BUG-12 前端名称一致性 (1h) -``` - ---- - -## 五、代码修改检查清单 - -### 提交前验收标准 - -**修复 BUG-01 时**: -``` -[ ] 修改 stage_store.go 的 AdvanceStage 函数 - - 检查是否最后阶段 - - 若是,同事务更新 projects.lifecycle_status - - 清空 current_workflow_instance_id - - 写审计事件 -[ ] 新增测试: TestAdvanceStage_CompletesProjectAfterLastStage -[ ] 新增测试: TestAdvanceStage_DoesNotChangeProjectOnNonLastStage -[ ] 本地测试通过 (go test ./internal/projectinstance -v) -[ ] 前端检查:/projects/{id}/settings 显示"配置下一工作流" -``` - -**修复 BUG-04 时**: -``` -[ ] 修改 coordinator/engine.go 的 handleAdvanceStage - - 提取 workflow_instance_id - - 改调 instSvc.AdvanceStage 替代 bizdevSvc.ExecuteStage - - 调整返回格式 -[ ] 新增测试: TestDialogueAdvanceStage_UsesNewService -[ ] 新增测试: TestDialogueAdvanceStage_PermissionCheck -[ ] 本地测试通过 (go test ./internal/coordinator -v) -[ ] 对话测试通过 (go test ./internal/server -run Dialogue -v) -``` - -**创建 Task B2 E2E 框架时**: -``` -[ ] 确保 TEST_DATABASE_URL 已设置 -[ ] 创建 setupE2ETestDB() 函数 - - 创建隔离 schema - - 运行所有迁移 - - 清理逻辑 -[ ] 编写 TestE2E_BizdevWorkflow_Complete - - 7 文档完整流程 - - 每个阶段验证门禁 - - 完成后验证项目状态 -[ ] 编写 TestE2E_ProductManagerWorkflow_Standalone - - 无前置依赖 - - 独立运行成功 -[ ] 编写 TestE2E_TestEngineerWorkflow_WithoutSRS - - 无 SRS 输入仍能运行 - - 输出包含来源清单 -[ ] 全部 E2E 测试通过 -[ ] 验收标准 7.5 完全满足 -``` - ---- - -## 六、数据库迁移清单 - -### 需要新增的迁移脚本 - -``` -00025_2026-09-12-disabled-doc-status.sql -├─ 添加 project_doc_task_instances.status_reason -├─ 添加约束:disabled 时 duties 为空 -└─ 编写回滚脚本 - -00026_2026-09-12-workflow-termination.sql -├─ 添加 project_workflow_instances.terminated_at/by/reason -├─ 添加 termination_reason 列 -└─ 编写回滚脚本 - -00027_2026-09-12-context-snapshots.sql -├─ 创建 project_context_snapshots 表 -├─ 创建 project_context_snapshot_sources 表 -└─ 编写回滚脚本 - -00028_2026-09-12-activation-challenges.sql -├─ 创建 activation_challenges 表 -├─ 创建 one_time_tokens 表 -└─ 编写回滚脚本 -``` - ---- - -## 七、测试命令参考 - -```bash -# 运行所有项目实例测试 -go test ./internal/projectinstance -v - -# 运行所有协调器测试 -go test ./internal/coordinator -v - -# 运行所有工作流定义测试 -go test ./internal/workflowdef -v - -# 运行服务器集成测试 -go test ./internal/server -v - -# 运行特定 bug 的测试 -go test ./internal/projectinstance -run "TestAdvanceStage" -v - -# 运行 PG 集成测试(需 TEST_DATABASE_URL) -TEST_DATABASE_URL=postgresql://... go test ./internal/server -run PG -v - -# 运行 E2E 测试 -TEST_DATABASE_URL=postgresql://... go test ./internal/server -run E2E -v - -# 代码覆盖率分析 -go test ./internal/projectinstance ./internal/coordinator ./internal/workflowdef \ - -coverprofile=coverage.out && go tool cover -html=coverage.out - -# 静态检查 -go vet ./internal/... -golangci-lint run ./internal/... -``` - ---- - -## 八、API 快速参考 - -### 关键端点变动汇总 - -``` -现有(需保留或改进): - GET /api/v1/workflows/catalog - → 返回三项正式工作流 ✅ - - GET /api/v1/projects/{id}/settings - → 返回项目设置及 live instance 配置 ✅ - - PUT /api/v1/projects/{id}/workflow-plan - → 保存/修改规划 (planning 状态下) ✅ - - POST /api/v1/projects/{id}/workflow-instances/activate - → 激活工作流 (需修复 token) ⚠️ - - GET /api/v1/workflow-instances/{id}/stages/{stage}/readiness - → 阶段门禁详情 ✅ - - POST /api/v1/workflow-instances/{id}/stages/{stage}/advance - → 推进阶段 (需修复生命周期) ❌ - -待实现(高优先级): - POST /api/v1/workflow-instances/{id}/termination-preview - → 终止预览(Task B1) - - POST /api/v1/workflow-instances/{id}/terminate - → 执行终止(Task B1) - -待删除或返回 410: - POST /projects/{id}/active-workflow - → 旧切换 API(需下线) - -需改进(权限一致性): - POST /api/v1/doc-task-instances/{id}/runs - → 启动编制 (需 DocumentAccessDecider) ⚠️ - - POST /api/v1/documents/{id}/submit - → 提交审核 (需统一权限检查) ⚠️ - - POST /api/v1/documents/{id}/approve - → 批准 (需统一权限检查) ⚠️ -``` - ---- - -## 九、常见问题速查 - -### Q1: 为什么完成工作流后项目仍然处于"active"? -**A**: BUG-01 - `AdvanceStage` 完成最后阶段时未同事务更新项目 `lifecycle_status`。 -**修复**: Task A1(2h) -**临时绕过**: 手动执行 SQL `UPDATE projects SET lifecycle_status='planning' WHERE id=?` - -### Q2: 禁用的文档仍然能被某些用户操作? -**A**: BUG-05 - 不同入口对禁用文档的检查不一致。 -**修复**: Task A5(4h) - 实现 `DocumentAccessDecider` -**临时绕过**: 在关键入口前添加 `if doc.status == 'skipped_disabled' { return 409 }` - -### Q3: 激活 token 可能被重复使用? -**A**: BUG-06 - Token 明文保存,消费分事务。 -**修复**: Task A6(3h) -**临时保护**: 限制 token 有效期为 5 分钟;记录消费日志;审计异常 token 使用 - -### Q4: 对话推进工作流不起作用? -**A**: BUG-04 - Coordinator 调用旧商务服务而非实例服务。 -**修复**: Task A4(2h) -**临时检查**: 查看 `internal/coordinator/engine.go:672-811` 是否仍调用 `bizdevSvc` - -### Q5: 为什么 E2E 测试一直 fail? -**A**: 可能多个原因: - 1. TEST_DATABASE_URL 未设置 → 连接开发库(88 个污染定义) - 2. E2E 框架缺失 → 需实现 setupE2ETestDB() - 3. 实例生命周期 bug → BUG-01 导致测试逻辑不对 - -**修复**: 检查 TEST_DATABASE_URL;运行 Task B2 - -### Q6: 生产数据库中有 47 个"已完成但项目仍为 active"的不一致数据? -**A**: BUG-01 导致。数据本身可恢复。 -**恢复方案**: - 1. 查询 `SELECT * FROM project_workflow_instances WHERE status='completed'` - 2. 对每个 completed 实例: - ```sql - UPDATE projects SET lifecycle_status='planning', current_workflow_instance_id=NULL - WHERE id=(SELECT project_id FROM project_workflow_instances WHERE id=?) - ``` - 3. 补写审计日志 - ---- - -## 十、参考文档导航 - -| 文档 | 用途 | 适合人员 | -|---|---|---| -| [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) | **当前缺口 SSOT** | 全体 | -| [ops/CURRENT.md](./ops/CURRENT.md) | 协作焦点 | Agent / 开发 | -| [comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 详细缺陷分析与整改方案(历史) | 架构师、资深开发 | -| [remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 可执行的任务拆分与验收 | 开发、QA | -| [audit-summary-report.md](./2026-09-12-audit-summary-report.md) | 审计总结与建议(历史) | 项目经理、技术负责人 | -| **[本文件]** | 快速参考与索引 | 全体团队 | -| [three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 业务需求原始规划 | 产品、架构 | - ---- - -## 十一、快速评分表 - -### 修复每个 bug 后的自检清单 - -``` -BUG-01 ✓ 完成 - □ stage_store.go 修改 - □ 新增单元测试 ×2 - □ 本地 go test PASS - □ 前端验证项目状态改变 - → 接受标准: 完成最后阶段后项目 lifecycle='planning' - -BUG-02 ✓ 完成 - □ grep 确认强制批准逻辑存在 - □ 删除 UPDATE 批准状态的 SQL - □ 新增单元测试 - □ 本地 go test PASS - → 接受标准: 推进前后文档状态不变 - -BUG-04 ✓ 完成 - □ engine.go handleAdvanceStage 改为调用新服务 - □ 新增单元测试 - □ 本地 go test PASS - □ 对话测试 PASS - → 接受标准: 对话推进使用 instSvc - -BUG-05 ✓ 完成 - □ 实现 DocumentAccessDecider 接口 - □ 集成到 API、SSE、异步任务、Agent tools - □ 新增综合测试 - □ 本地 go test PASS - → 接受标准: 禁用文档全拒绝,返回 409/403 - -BUG-06 ✓ 完成 - □ 数据库迁移 00028 - □ API 改为 challenge_id + one_time_token - □ Token hash + 原子消费 - □ 新增安全测试 ×4 - □ 本地 go test PASS - → 接受标准: Token one-time、hash 存储、5 分钟过期 - -Task B1 ✓ 完成 - □ 新增 terminate.go 服务 - □ TerminationPreview API - □ TerminateWorkflow API - □ 新增端到端测试 - □ 本地 go test PASS - → 接受标准: 终止后项目可配置下一流程 - -Task B2 ✓ 完成 - □ setupE2ETestDB() 实现 - □ TestE2E_BizdevWorkflow_Complete PASS - □ TestE2E_ProductManagerWorkflow_Standalone PASS - □ TestE2E_TestEngineerWorkflow_WithoutSRS PASS - □ TEST_DATABASE_URL 隔离库运行 - → 接受标准: 三工作流完整链路验证 -``` - ---- - -**文档版本**: v1.0 快速参考 -**适用对象**: 项目全体 -**更新频率**: 同步更新主审计文档 +# 已迁移 +本文档已迁至 [remediation/2026-09-12-quick-reference-guide.md](remediation/2026-09-12-quick-reference-guide.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-remediation-gap-matrix.md b/.doc/2026-09-12-remediation-gap-matrix.md index 4acc1583..ab8d59df 100644 --- a/.doc/2026-09-12-remediation-gap-matrix.md +++ b/.doc/2026-09-12-remediation-gap-matrix.md @@ -1,71 +1,3 @@ -# 整改缺口复核矩阵(SSOT) +# 已迁移 -**更新**: 2026-09-13 -**分支**: dev -**production_ready**: no(CI 真实 PI E2E / 前端人工抽检未完成;main 本地冒烟已通过) -**协作焦点**: [.doc/ops/CURRENT.md](ops/CURRENT.md) -**Agent 手册**: [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md) - -> Codex 2026-09-12 再审计项与本轮回环证据见下表「Codex 再审计」区段。 - ---- - -## Phase A/B/C 原审计项 - -| ID | 审计描述 | 状态 | 证据 | 计划动作 | -|---|---|---|---|---| -| BUG-01 | 完成后 lifecycle 未更新 | PASS | `stage_remediation_test.go`;`scripts/fix-completed-instance-lifecycle.sql`;dev 执行 UPDATE 47 | 已完成 | -| BUG-02 | 推进强制批文档 | PASS | `AdvanceStage` 无 doc UPDATE | 已完成 | -| BUG-03 | 无 skipped_disabled | PASS | memStore `skipped_disabled` | 已完成 | -| BUG-04 | 对话走旧 bizdev | PASS | `engine.go` live 门控 | 已完成 | -| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 | -| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 | -| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 | -| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` | -| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 | -| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 | -| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 | -| BUG-12 | 前端名称硬编码 | PASS | catalog API | 已完成 | -| MISSING-01 | 上下文快照 | PASS | `ctxmgr.CollectProjectDialogue` | 已完成 | -| MISSING-02 | 终止 | PASS | `GetTerminationPreview` | 已完成 | -| MISSING-04 | E2E | PASS | 三正式工作流 PG+PI E2E | 已完成 | - ---- - -## Codex 2026-09-12 再审计 - -| ID | 描述 | 状态 | 证据 | -|---|---|---|---| -| AUTH-TASK-RUN | `/tasks/run` 缺项目鉴权 | PASS | `handlers.go` RequireProjectAccess;`task_run_authz_pg_test.go` | -| AUTH-TASK-SSE | `/tasks/run/stream` 鉴权在 Flush 前 | PASS | `sse.go`;同上测试 | -| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval | -| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 | -| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 | -| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` | -| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 | -| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 | -| TEST-EMBEDDING-GATE | 默认打真实 embedding | PASS | `kb/integration_test.go` Short + `RUN_KB_INTEGRATION=1` | -| HEALTH-SCHEMA-CACHE | health schema 启动缓存 | PASS | `LiveSchemaVersion` + health 实时读 | -| GO-VET-ASSET | asset handler resp before err | PASS | `asset_handlers_test.go` err-first | -| ENV-TEST-STALE | test 旧镜像/schema 漂移 | PASS | rebuild app;health schema_version=25 | -| ENV-DEV-STALE | dev 二进制/schema 漂移 | PASS | docker app 重启;schema_version=25 | -| ENV-MAIN-MISSING | main 未部署验收 | PASS | docker 创建 `data/main`;compose 注入 ADMIN/KB 密码;health/ready schema 25 | -| DOC-SSOT | 文档叙事漂移 | PASS | 本矩阵 + superseded 标记 + ops | -| OPS-AGENTS | 多 Agent 协作规范 | PASS | `AGENTS.md` / `PROJECT.md` / `.doc/ops` | - ---- - -## 发布门禁(test → main) - -``` -☑ go vet ./... 全绿 -☑ go test -short ./... 全绿 -□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI) -□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token) -☑ lifecycle fix SQL 已在 dev 执行 -☑ test/dev health schema_version=25 -☑ main 环境部署冒烟(本地 8000 health/ready schema 25) -□ 前端:版本冲突刷新、终止 preview 人工抽检 -``` - -**结论**: P0 授权、冷启动序列、Go 门禁、三环境本地冒烟已闭环。**发布 blocker 剩余 CI 真实 PI E2E 与前端人工抽检**。 +本文档已迁至 [remediation/gap-matrix.md](remediation/gap-matrix.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md b/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md index 05388cce..804b3db4 100644 --- a/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md +++ b/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md @@ -1,1179 +1,3 @@ -# 整改实施拆分与验收清单 +# 已迁移 -> **工作手册(非 live status)** — 任务说明与验收框;勾选状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/checklists/](./ops/checklists/) 为准。 - -**日期**: 2026-09-12 -**格式**: 可执行的任务分解与逐项验收标准 -**用途**: 开发、QA 与产品对齐 - ---- - -## 第一部分:关键缺陷修复(Phase A) - -### Task A1: 项目完成后生命周期转换 - -**目标**: 完成最后阶段后,项目立即进入可配置下一工作流的状态 - -**修改文件**: -- `internal/projectinstance/stage_store.go` (AdvanceStage 事务) -- `internal/projectinstance/service.go` (逻辑校验) -- 相关测试 - -**具体修改**: - -**文件**: `internal/projectinstance/stage_store.go` -```go -// 现有代码(伪代码) -func (s *pgStore) AdvanceStage(...) (*InstanceDetail, error) { - // ... 获取实例与阶段定义 - - // 🔴 当前:只更新实例,不更新项目 - stmt := "UPDATE project_workflow_instances SET active_stage_key = ?, status = ? WHERE id = ?" - - // ✅ 修改后:检查是否最后阶段,若是同时更新项目 - isLastStage := checkLastStageInDefinition(...) - if isLastStage { - // 同事务操作 - stmtProject := "UPDATE projects SET lifecycle_status = ?, current_workflow_instance_id = NULL WHERE id = ?" - // 写审计 - auditStmt := "INSERT INTO workflow_events ..." - } -} -``` - -**测试用例**: -```go -// 新增测试 -func TestAdvanceStage_CompletesProjectAfterLastStage(t *testing.T) { - // 1. 创建并激活工作流 - // 2. 推进到最后一个启用阶段 - // 3. 所有文档批准后确认推进 - // 4. 验证: - // - workflow_instance.status = "completed" - // - projects.lifecycle_status = "planning" - // - projects.current_workflow_instance_id = NULL - // - 审计事件已记录 -} - -func TestAdvanceStage_DoesNotChangeProjectOnNonLastStage(t *testing.T) { - // 验证:非最后阶段的推进不改变项目状态 -} -``` - -**验收标准**: -- [ ] 单元测试 PASS -- [ ] 完成最后阶段后项目 `lifecycle_status` 变为 `planning` -- [ ] 前端 /projects/{id}/settings 立即显示"配置下一工作流"按钮 -- [ ] 审计日志记录 `ProjectWorkflowCompleted` 事件 - -**预计工作量**: 2h - ---- - -### Task A2: 推进事务不强制更新文档审批状态 - -**目标**: 验证并删除推进时强制批准文档的逻辑 - -**步骤**: -1. 搜索 `AdvanceStage` 中是否存在 UPDATE 文档状态的 SQL -2. 若存在,删除该逻辑 -3. 补充负例测试 - -**搜索命令**: -```bash -grep -n "UPDATE.*doc.*approved\|UPDATE.*approval.*approved" \ - internal/projectinstance/stage_store.go -``` - -**如果存在修改**: -```go -// 🔴 删除以下逻辑(如果存在) -stmt := `UPDATE project_doc_task_instances - SET status = 'approved' - WHERE instance_id = ? AND enabled = true` - -// ✅ 替换为:什么都不改,只改阶段状态 -stmt := `UPDATE project_workflow_instances - SET active_stage_key = ? WHERE id = ?` -``` - -**测试**: -```go -func TestAdvanceStage_DoesNotModifyDocumentApprovalStatus(t *testing.T) { - // 1. 创建、激活、推进到阶段就绪 - // 2. 记录所有文档的当前 approval_status - // 3. 执行 AdvanceStage - // 4. 验证:所有文档 approval_status 未变 -} -``` - -**验收标准**: -- [ ] 单元测试 PASS -- [ ] 推进前后文档状态一致 -- [ ] 阶段状态改变,文档状态不改变 - -**预计工作量**: 1h - ---- - -### Task A3: 禁用文档状态标记为 skipped_disabled - -**目标**: 禁用文档在数据库中有明确的 `skipped_disabled` 状态记录 - -**数据库迁移** (`00025_2026-09-12-disabled-doc-status.sql`): -```sql --- 新增迁移 -ALTER TABLE project_doc_task_instances -ADD COLUMN status_reason VARCHAR(50) DEFAULT NULL; - --- 补充约束:disabled 时 duties 必须为空 -ALTER TABLE project_doc_task_instances -ADD CONSTRAINT chk_disabled_no_duties -CHECK (status != 'skipped_disabled' OR - (author_user_id IS NULL AND - reviewer_user_id IS NULL AND - approver_user_id IS NULL)); -``` - -**代码修改** (`internal/projectinstance/store.go`): -```go -func (s *pgStore) SaveWorkflowPlan(...) error { - // 激活时为所有文档创建记录 - for _, stage := range plan.Stages { - for _, doc := range stage.DocTasks { - if doc.Enabled { - // 写启用文档 - stmt := `INSERT INTO project_doc_task_instances - (instance_id, task_key, status, author_user_id, ...) - VALUES (?, ?, 'awaiting_edit', ?, ...)` - } else { - // ✅ 新增:写禁用文档 - stmt := `INSERT INTO project_doc_task_instances - (instance_id, task_key, status, status_reason) - VALUES (?, ?, 'skipped_disabled', 'creator_disabled')` - } - } - } -} -``` - -**测试**: -```go -func TestDisabledDocumentPersistence(t *testing.T) { - // 1. 创建计划,禁用某文档 - // 2. 激活 - // 3. 验证: - // - 禁用文档在 project_doc_task_instances 中存在 - // - status = 'skipped_disabled' - // - 无职责行 -} - -func TestDisabledDocumentRejectionAllEntries(t *testing.T) { - // 针对不同入口测试禁用文档拒绝 - // - API 启动:409 DOC_TASK_DISABLED - // - 提交/审核/批准:403 DOC_DUTY_FORBIDDEN -} -``` - -**验收标准**: -- [ ] 数据库迁移成功应用 -- [ ] 禁用文档在 project_doc_task_instances 中有记录 -- [ ] 禁用文档的所有操作返回 409 或 403 -- [ ] 审计查询显示哪些文档被禁用 - -**预计工作量**: 3h - ---- - -### Task A4: 对话推进切换到新实例服务 - -**目标**: 对话中的"推进阶段"调用新的实例服务,而非旧的商务执行器 - -**修改文件**: `internal/coordinator/engine.go:672-811` - -**原代码**: -```go -func (e *CoordinatorEngine) handleAdvanceStage(...) { - // ...识别成功后 - - // 🔴 旧逻辑:调用商务服务 - result, err := e.bizdevSvc.ExecuteStage(ctx, projectID, ...) -} -``` - -**新代码**: -```go -func (e *CoordinatorEngine) handleAdvanceStage(...) { - // ...识别成功后 - - // ✅ 新逻辑:调用实例服务 - - // 1. 从项目或上文获取 workflow_instance_id - instanceID, err := extractWorkflowInstanceID(ctx, projectID, ...) - if err != nil { - return rejectResponse("Cannot determine active workflow instance") - } - - // 2. 调用新服务 - result, err := e.instSvc.AdvanceStage( - ctx, instanceID, userID, isCreator, - projectinstance.AdvanceStageInput{ - StageKey: stageKey, - ExpectedConfigRevision: configRev, - }, - ) - if err != nil { - return rejectResponse(err.Error()) - } - - // 3. 返回成功响应 - return confirmResponse("Stage advanced successfully", result) -} -``` - -**辅助函数**: -```go -func (e *CoordinatorEngine) extractWorkflowInstanceID( - ctx context.Context, - projectID int64, - dialogueContext map[string]any, -) (int64, error) { - // 优先级: - // 1. 上下文中显式提供 - if id, ok := dialogueContext["workflow_instance_id"].(int64); ok && id > 0 { - return id, nil - } - - // 2. 从项目设置查询 live instance - settings, err := e.instSvc.GetSettings(ctx, projectID, userID, true) - if err != nil || settings.LiveInstance == nil { - return 0, fmt.Errorf("no active workflow instance") - } - return settings.LiveInstance.ID, nil -} -``` - -**测试**: -```go -func TestDialogueAdvanceStage_UsesNewService(t *testing.T) { - // 1. 激活工作流实例 - // 2. 对话说"推进到下一阶段" - // 3. 验证: - // - 调用 instSvc.AdvanceStage 而非 bizdevSvc.ExecuteStage - // - 返回新格式响应 - // - 实例状态正确更新 -} -``` - -**验收标准**: -- [ ] 对话推进测试 PASS -- [ ] 新实例服务被调用(可通过 mock 验证) -- [ ] 权限检查一致(仅创建者可推进) -- [ ] 旧商务服务逻辑不再触发 - -**预计工作量**: 2h - ---- - -### Task A5: 禁用文档拒绝逻辑一致性(DocumentAccessDecider) - -**目标**: 统一所有入口对禁用文档的拒绝决策 - -**新增文件**: `internal/projectinstance/document_access.go` - -```go -package projectinstance - -import "context" - -type DocumentAccessDecider interface { - // CanAccess 判断用户是否可访问指定文档任务 - // action: "edit", "submit", "review", "approve", "view" - CanAccess( - ctx context.Context, - docTaskInstID int64, - action string, - userID int64, - ) (bool, error) - - // GetAccessDenialReason 返回具体的拒绝原因 - GetAccessDenialReason( - ctx context.Context, - docTaskInstID int64, - userID int64, - ) (code string, message string) -} - -type defaultAccessDecider struct { - store Store - docs DocumentReadinessChecker -} - -func (d *defaultAccessDecider) CanAccess( - ctx context.Context, - docTaskInstID int64, - action string, - userID int64, -) (bool, error) { - // 1. 查询 doc_task_instance - docTask, err := d.store.GetDocTaskInstance(ctx, docTaskInstID) - if err != nil { - return false, err - } - - // 2. 检查状态 - if docTask.Status == "skipped_disabled" { - return false, nil // 禁用文档,拒绝所有操作 - } - - // 3. 获取实例详情 - instance, err := d.store.GetInstanceByID(ctx, docTask.InstanceID) - if err != nil { - return false, err - } - - // 4. 检查实例状态 - if instance.Instance.Status != InstanceActive && - instance.Instance.Status != InstanceAwaiting { - return false, nil // 实例非运行状态 - } - - // 5. 检查当前阶段 - if !stageContainsTask(instance, docTask.StageKey, docTaskInstID) { - return false, nil // 不在当前阶段 - } - - // 6. 检查职责匹配 - if !userHasRole(docTask, userID, action) { - return false, nil // 用户非对应职责人 - } - - return true, nil -} -``` - -**集成点**: -- API 路由: `POST /api/v1/doc-task-instances/{id}/runs` -- SSE 推送: 过滤禁用/非当前阶段的文档更新 -- 异步任务: 启动前校验 -- Agent tool: 文档访问 wrapper - -**测试**: -```go -func TestDocumentAccessDecider_DisabledDocumentRejected(t *testing.T) { - // 禁用文档的所有操作被拒绝 -} - -func TestDocumentAccessDecider_NonCurrentStageRejected(t *testing.T) { - // 不在当前阶段的文档被拒绝 -} - -func TestDocumentAccessDecider_NonResponsibleUserRejected(t *testing.T) { - // 非职责人的操作被拒绝 -} - -func TestDocumentAccessDecider_ValidAccessAllowed(t *testing.T) { - // 满足所有条件时允许 -} -``` - -**验收标准**: -- [ ] 所有入口(API、SSE、异步任务、Agent tool)使用同一决策器 -- [ ] 禁用文档全拒绝 -- [ ] 非职责人拒绝 -- [ ] 非当前阶段拒绝 - -**预计工作量**: 4h - ---- - -### Task A6: 激活 Token 安全处理 - -**目标**: Token 改为 one-time、hash 存储、原子消费 - -**修改流程**: - -**步骤 1**: 修改激活预览 API -```go -// 旧:返回 activation_token -GET /api/v1/projects/{id}/activation-preview -→ { token: "xyz123", ... } - -// ✅ 新:返回 challenge 和 nonce -GET /api/v1/projects/{id}/activation-preview -→ { challenge_id: "ch_abc", nonce: "n123", ... } -``` - -**步骤 2**: 修改激活 API -```go -// 旧:明文 token -POST /api/v1/projects/{id}/workflow-instances/activate -{ token: "xyz123" } - -// ✅ 新:挑战响应 -POST /api/v1/projects/{id}/workflow-instances/activate -{ - challenge_id: "ch_abc", - token: "at_oneTimeXyz123" // 由服务端生成 -} -``` - -**步骤 3**: 数据库变更 -```sql --- 激活挑战表 -CREATE TABLE activation_challenges ( - id BIGSERIAL PRIMARY KEY, - project_id BIGINT NOT NULL, - created_by BIGINT NOT NULL, - challenge_id VARCHAR(32) UNIQUE, - nonce VARCHAR(32), - config_hash VARCHAR(64), -- 冻结内容的 hash - created_at TIMESTAMP DEFAULT NOW(), - expires_at TIMESTAMP, - consumed_at TIMESTAMP, - FOREIGN KEY (project_id) REFERENCES projects(id) -); - --- 一次性 token 表 -CREATE TABLE one_time_tokens ( - id BIGSERIAL PRIMARY KEY, - challenge_id VARCHAR(32), - token_hash VARCHAR(255), -- bcrypt hash - created_at TIMESTAMP, - expires_at TIMESTAMP, - consumed_at TIMESTAMP -); -``` - -**激活逻辑**: -```go -func (s *Service) ActivateWorkflow( - ctx context.Context, - projectID int64, - userID int64, - challengeID string, - token string, -) (*ActivateResult, error) { - return s.store.ActivateInTx(ctx, func(tx Tx) error { - // 1. 查询 challenge(5 分钟未过期) - challenge, err := tx.GetChallenge(ctx, challengeID) - if err != nil || challenge.ExpiresAt < now { - return ErrChallengeExpired - } - - // 2. 验证 token hash - if err := bcrypt.CompareHashAndPassword(challenge.TokenHash, token); err != nil { - return ErrInvalidToken - } - - // 3. 检查 token 未消费 - if challenge.ConsumedAt != nil { - return ErrTokenAlreadyConsumed - } - - // 4. 在同一事务内激活实例 - instance, err := tx.ActivateInstance(ctx, projectID, ...) - if err != nil { - return err - } - - // 5. 标记 challenge 和 token 已消费 - tx.MarkChallengeConsumed(ctx, challengeID) - - return nil - }) -} -``` - -**测试**: -```go -func TestActivationTokenSecurity_OneTimeUse(t *testing.T) { - // 同一 token 不能消费两次 -} - -func TestActivationTokenSecurity_Expiration(t *testing.T) { - // 5 分钟后 token 过期 -} - -func TestActivationTokenSecurity_InvalidTokenRejected(t *testing.T) { - // 错误 token 被拒绝 -} - -func TestActivationTokenSecurity_AtomicConsumption(t *testing.T) { - // token 消费与实例激活在同一事务内 -} -``` - -**验收标准**: -- [ ] Token 为 one-time,消费后不可重用 -- [ ] Token 5 分钟过期 -- [ ] Token hash 存储,明文不保存 -- [ ] 激活原子性(token 消费与实例激活同事务) -- [ ] 中间故障时 token 仍有效(可重试) - -**预计工作量**: 3h - ---- - -## 第二部分:高优先级新功能(Phase B) - -### Task B1: 受控终止工作流 API - -**目标**: 工作流实例可被创建者受控终止,写入原因并审计 - -**新增文件**: `internal/projectinstance/terminate.go` - -```go -package projectinstance - -import "context" - -type TerminationPreviewInput struct { - InstanceID int64 `json:"instance_id"` -} - -type TerminationPreviewResult struct { - InstanceID int64 `json:"instance_id"` - PendingDocuments []DocTaskSummary `json:"pending_documents"` - PendingNotifications []string `json:"pending_notifications"` - InProgressRunTasks []string `json:"in_progress_run_tasks"` - CanTerminate bool `json:"can_terminate"` - Impact string `json:"impact,omitempty"` -} - -type TerminateInput struct { - InstanceID int64 `json:"instance_id"` - Reason string `json:"reason"` // 必填,最多 500 字 - Confirm bool `json:"confirm"` // 二次确认 -} - -type TerminateResult struct { - InstanceID int64 `json:"instance_id"` - Status string `json:"status"` // "terminated" - TerminatedAt time.Time `json:"terminated_at"` - TerminatedBy int64 `json:"terminated_by"` - Reason string `json:"reason"` -} - -func (s *Service) GetTerminationPreview( - ctx context.Context, - instanceID int64, -) (*TerminationPreviewResult, error) { - instance, err := s.store.GetInstanceByID(ctx, instanceID) - if err != nil { - return nil, err - } - - // 收集影响项 - pending := []DocTaskSummary{} - notifs := []string{} - tasks := []string{} - - // ...查询待审批文档、待发送通知、在途任务... - - return &TerminationPreviewResult{ - InstanceID: instanceID, - PendingDocuments: pending, - PendingNotifications: notifs, - InProgressRunTasks: tasks, - CanTerminate: true, - Impact: fmt.Sprintf( - "%d pending docs, %d notifications, %d task runs will be cancelled", - len(pending), len(notifs), len(tasks), - ), - }, nil -} - -func (s *Service) TerminateWorkflow( - ctx context.Context, - instanceID int64, - userID int64, - isCreator bool, - input TerminateInput, -) (*TerminateResult, error) { - if !isCreator { - return nil, ErrForbiddenNotCreator - } - if !input.Confirm { - return nil, ErrTerminationNotConfirmed - } - if len(strings.TrimSpace(input.Reason)) == 0 { - return nil, ErrTerminationReasonRequired - } - - result, err := s.store.TerminateInTx(ctx, func(tx Tx) error { - // 1. 获取实例 - instance, err := tx.GetInstanceByID(ctx, instanceID) - if err != nil { - return err - } - - // 2. 检查状态可终止 - if instance.Instance.Status != InstanceActive && - instance.Instance.Status != InstanceAwaiting { - return ErrCannotTerminateInstance - } - - // 3. 标记实例为 terminated - if err := tx.UpdateInstance(ctx, instanceID, map[string]any{ - "status": "terminated", - "terminated_at": now, - "terminated_by": userID, - "termination_reason": input.Reason, - }); err != nil { - return err - } - - // 4. 取消在途任务 - if err := tx.CancelPendingTaskRuns(ctx, instanceID); err != nil { - return err - } - - // 5. 项目改为 planning - if err := tx.UpdateProject(ctx, instance.Instance.ProjectID, map[string]any{ - "lifecycle_status": "planning", - "current_workflow_instance_id": nil, - }); err != nil { - return err - } - - // 6. 写审计 - if err := tx.LogEvent(ctx, "WorkflowTerminated", map[string]any{ - "instance_id": instanceID, - "reason": input.Reason, - "by": userID, - }); err != nil { - return err - } - - return nil - }) - - return &TerminateResult{ - InstanceID: instanceID, - Status: "terminated", - TerminatedAt: now, - TerminatedBy: userID, - Reason: input.Reason, - }, err -} -``` - -**API 路由**: -```go -// server.go -mux.HandleFunc("GET /api/v1/workflow-instances/{id}/termination-preview", - s.handleTerminationPreview) -mux.HandleFunc("POST /api/v1/workflow-instances/{id}/terminate", - s.handleTerminate) -``` - -**测试**: -```go -func TestTerminationPreview_ShowsImpact(t *testing.T) { - // 显示待审批文档、通知、任务清单 -} - -func TestTerminate_RequiresCreator(t *testing.T) { - // 非创建者被拒绝 -} - -func TestTerminate_RequiresConfirmation(t *testing.T) { - // confirm = false 时被拒绝 -} - -func TestTerminate_UpdatesProjectLifecycle(t *testing.T) { - // 终止后项目可配置下一工作流 -} - -func TestTerminate_CancelsPendingTasks(t *testing.T) { - // 在途任务被取消 -} -``` - -**验收标准**: -- [ ] 预览 API 显示完整影响 -- [ ] 仅创建者可终止 -- [ ] 需二次确认和原因 -- [ ] 终止后项目立即可选择下一流程 -- [ ] 审计记录终止原因 - -**预计工作量**: 6h - ---- - -### Task B2: 真实 E2E 测试(PostgreSQL + PI Agent) - -**目标**: 使用真实数据库和 PI Agent 验证三个工作流完整链路 - -**新增文件**: `internal/server/e2e_workflow_integration_test.go` - -**框架**: -```go -package server - -import ( - "context" - "testing" - - "github.com/jackc/pgx/v5/pgxpool" -) - -func setupE2ETestDB(t *testing.T) *pgxpool.Pool { - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - t.Skip("TEST_DATABASE_URL not set, skipping E2E tests") - } - - pool, err := pgxpool.New(context.Background(), dbURL) - if err != nil { - t.Fatalf("Failed to connect to E2E test DB: %v", err) - } - - // 创建隔离 schema - schema := "e2e_test_" + randomID() - _, err = pool.Exec(context.Background(), "CREATE SCHEMA "+schema) - if err != nil { - t.Fatalf("Failed to create schema: %v", err) - } - - // 运行所有迁移 - if err := runMigrations(t, pool, schema); err != nil { - t.Fatalf("Failed to run migrations: %v", err) - } - - t.Cleanup(func() { - pool.Exec(context.Background(), "DROP SCHEMA "+schema+" CASCADE") - pool.Close() - }) - - return pool -} - -func TestE2E_BizdevWorkflow_Complete(t *testing.T) { - pool := setupE2ETestDB(t) - ctx := context.Background() - - // 1. 创建项目 - projectID := createProject(t, ctx, pool, "Project-Bizdev", "weichen") - - // 2. 获取三工作流目录 - workflows := listWorkflows(t, ctx, pool) - if len(workflows) != 3 { - t.Fatalf("Expected 3 workflows, got %d", len(workflows)) - } - - // 3. 选择商务对接流程 - bizdevWF := findWorkflow(workflows, "main") - plan := createPlan(t, ctx, pool, projectID, bizdevWF.Key) - - // 4. 激活 - instance := activateWorkflow(t, ctx, pool, projectID, plan) - if instance.Status != "active" { - t.Fatalf("Expected instance.status=active, got %s", instance.Status) - } - - // 5. 逐个批准 7 个文档 - docKeys := []string{ - "intake", "research", "feasibility_dev", "feasibility_reg", - "user_requirements", "prelim_design", "cdo_quote", - } - for i, docKey := range docKeys { - approveDocument(t, ctx, pool, instance.ID, docKey) - - // 检查门禁 - readiness := getStageReadiness(t, ctx, pool, instance.ID, "stage_v01") - if i < len(docKeys)-1 { - if readiness.Ready { - t.Fatalf("Stage should not be ready with %d/%d docs approved", - i+1, len(docKeys)) - } - } else { - if !readiness.Ready { - t.Fatalf("Stage should be ready after all docs approved") - } - } - } - - // 6. 推进各阶段 - advanceStage(t, ctx, pool, instance.ID, "stage_v01", 0) - advanceStage(t, ctx, pool, instance.ID, "stage_v05", 0) - - // 7. 完成最后阶段 - result := advanceStage(t, ctx, pool, instance.ID, "stage_v10", 0) - if result.CompletedAt == nil { - t.Fatal("Expected instance.completed_at to be set") - } - - // 8. 验证项目已返回 planning - settings := getProjectSettings(t, ctx, pool, projectID) - if settings.LifecycleStatus != "planning" { - t.Fatalf("Expected project lifecycle=planning, got %s", - settings.LifecycleStatus) - } - - // 9. 可配置下一个工作流 - workflows2 := listWorkflows(t, ctx, pool) - if len(workflows2) != 3 { - t.Fatalf("Cannot select next workflow") - } - - t.Logf("✅ Bizdev workflow complete chain PASSED") -} - -func TestE2E_ProductManagerWorkflow_Standalone(t *testing.T) { - pool := setupE2ETestDB(t) - ctx := context.Background() - - projectID := createProject(t, ctx, pool, "Project-PM", "weichen") - - // 选择产品经理流程(未运行商务流程) - pmWF := findWorkflow(listWorkflows(t, ctx, pool), "product_manager") - plan := createPlan(t, ctx, pool, projectID, pmWF.Key) - instance := activateWorkflow(t, ctx, pool, projectID, plan) - - // 批准 SRS 文档 - approveDocument(t, ctx, pool, instance.ID, "system_reqs") - - // 推进 - advanceStage(t, ctx, pool, instance.ID, "stage_pm", 0) - - // 完成 - result := advanceStage(t, ctx, pool, instance.ID, "stage_pm", 0) - if result.CompletedAt == nil { - t.Fatal("PM workflow should complete") - } - - t.Logf("✅ ProductManager workflow standalone PASSED") -} - -func TestE2E_TestEngineerWorkflow_WithoutSRS(t *testing.T) { - pool := setupE2ETestDB(t) - ctx := context.Background() - - projectID := createProject(t, ctx, pool, "Project-TE", "weichen") - - // 直接选择测试工程师流程,不需要先运行产品经理 - teWF := findWorkflow(listWorkflows(t, ctx, pool), "test_manager") - plan := createPlan(t, ctx, pool, projectID, teWF.Key) - instance := activateWorkflow(t, ctx, pool, projectID, plan) - - // PI Agent 生成测试方案(集成或 mock) - // ... - - // 批准测试方案 - approveDocument(t, ctx, pool, instance.ID, "test_manager") - - // 推进完成 - result := advanceStage(t, ctx, pool, instance.ID, "stage_te", 0) - if result.CompletedAt == nil { - t.Fatal("TE workflow should complete") - } - - t.Logf("✅ TestEngineer workflow without SRS PASSED") -} -``` - -**验收标准**: -- [ ] 商务流程 7 文档全流程完成 -- [ ] 产品流程独立运行无前置依赖 -- [ ] 测试流程无 SRS 也能运行 -- [ ] 每个完成流程后项目可配置下一个 -- [ ] 所有 E2E 测试 PASS -- [ ] 真实 PG + PI Agent 完整链路验证 - -**预计工作量**: 8h - ---- - -### Task B3: 项目上下文快照服务(ProjectContextSnapshot) - -**目标**: 为产品/测试流程提供统一、可复现的项目上下文 - -**新增文件**: `internal/projectcontext/service.go` - -**核心结构**: -```go -package projectcontext - -import "context" - -type ContextSnapshot struct { - ID int64 `json:"id"` - ProjectID int64 `json:"project_id"` - TaskID int64 `json:"task_id"` // 引用的任务(可选) - SnapshotHash string `json:"snapshot_hash"` - CreatedAt time.Time `json:"created_at"` - CreatedBy int64 `json:"created_by"` - - // 五层内容 - ProjectFacts ProjectFacts `json:"project_facts"` - ProjectDecisions ProjectDecisions `json:"project_decisions"` - ProjectDocuments ProjectDocuments `json:"project_documents"` - ProjectDialogue []DialogueEntry `json:"project_dialogue"` - HistoryOutputs []HistoryOutput `json:"history_outputs"` - KnowledgeHits []KnowledgeRef `json:"knowledge_hits"` - - // 血缘 - Sources []SourceManifest `json:"sources"` - ExcludedPrivate int `json:"excluded_private_count"` - ExcludedNoAccess int `json:"excluded_no_access_count"` -} - -type SourceManifest struct { - SourceType string // "project_fact", "document", "dialogue", etc. - SourceID int64 - SourceVersion int - SourceHash string - AuthorityLevel string // "confirmed", "approved", "reference", "evidence" - Permission string // "all_members", "shared_to_project", "private" - WasReferenced bool // 是否实际被输出引用 -} - -// Service 构建和查询项目上下文快照 -type Service struct { - store Store - projectStore projectworkflow.Store - docStore DocumentStore - dialogueStore DialogueStore -} - -func (s *Service) BuildContextSnapshot( - ctx context.Context, - projectID int64, - taskID int64, // 可选,用于任务的输入 -) (*ContextSnapshot, error) { - // 1. 收集五层源 - facts, err := s.gatherProjectFacts(ctx, projectID) - if err != nil { - return nil, err - } - - decisions, err := s.gatherProjectDecisions(ctx, projectID) - if err != nil { - return nil, err - } - - docs, sources, err := s.gatherProjectDocuments(ctx, projectID) - if err != nil { - return nil, err - } - - dialogue, excluded, err := s.gatherProjectDialogue(ctx, projectID) - if err != nil { - return nil, err - } - - history, err := s.gatherHistoryOutputs(ctx, projectID) - if err != nil { - return nil, err - } - - knowledge, err := s.gatherKnowledgeHits(ctx, projectID) - if err != nil { - return nil, err - } - - // 2. 冲突合并 - merged := s.mergeConflicts(facts, decisions, docs, dialogue, history) - - // 3. 计算 hash - hash := computeContentHash(merged) - - // 4. 保存快照 - snapshot := &ContextSnapshot{ - ProjectID: projectID, - TaskID: taskID, - SnapshotHash: hash, - CreatedAt: now, - CreatedBy: userID, - ProjectFacts: facts, - ProjectDecisions: decisions, - ProjectDocuments: docs, - ProjectDialogue: dialogue, - HistoryOutputs: history, - KnowledgeHits: knowledge, - Sources: sources, - ExcludedPrivate: excluded.PrivateCount, - ExcludedNoAccess: excluded.NoAccessCount, - } - - if err := s.store.SaveSnapshot(ctx, snapshot); err != nil { - return nil, err - } - - return snapshot, nil -} - -func (s *Service) gatherProjectFacts( - ctx context.Context, - projectID int64, -) (ProjectFacts, error) { - // 查询 projects 表和结构化事实黑板 - project, err := s.projectStore.GetProject(ctx, projectID) - if err != nil { - return ProjectFacts{}, err - } - - return ProjectFacts{ - ProjectName: project.Name, - CustomerName: project.Customer, - ProductType: project.ProductType, - IntendedUse: project.IntendedUse, - TargetMarket: project.TargetMarket, - StructuredFacts: project.StructuredFacts, - AuthorityLevel: "confirmed", // 项目元数据最权威 - }, nil -} - -func (s *Service) gatherProjectDocuments( - ctx context.Context, - projectID int64, -) (ProjectDocuments, []SourceManifest, error) { - // 查询当前有效版本的受控文档、共享文档、上传材料 - docs, err := s.docStore.ListProjectDocuments(ctx, projectID) - if err != nil { - return ProjectDocuments{}, nil, err - } - - sources := make([]SourceManifest, 0) - for _, doc := range docs { - sources = append(sources, SourceManifest{ - SourceType: "document", - SourceID: doc.ID, - SourceVersion: doc.LatestApprovedVersion, - SourceHash: doc.ContentHash, - AuthorityLevel: "approved", // 已批准文档 - Permission: "all_members", - WasReferenced: false, // 待填充 - }) - } - - return ProjectDocuments{ - ControlledDocs: docs, - AuthorityLevel: "approved", - }, sources, nil -} - -func (s *Service) gatherProjectDialogue( - ctx context.Context, - projectID int64, -) ([]DialogueEntry, ExcludedCounts, error) { - // 查询所有进入项目知识边界的对话 - // 过滤:私人草稿、个人私聊(未共享)不纳入 - - dialogue, excluded, err := s.dialogueStore.ListProjectDialogue( - ctx, projectID, true, // 仅已共享 - ) - - return dialogue, excluded, err -} - -// 冲突优先级: -// 确认事实/决策 > 已批准文档 > 上传材料 > 里程碑 > 普通对话 > 总结 -func (s *Service) mergeConflicts( - facts ProjectFacts, - decisions ProjectDecisions, - docs ProjectDocuments, - dialogue []DialogueEntry, - history []HistoryOutput, -) MergedContext { - // 若多个来源对同一概念有不同看法,按优先级择一 - // 例:需求既在 SRS 中又在对话中,选 SRS - - return MergedContext{ - // ... - } -} -``` - -**与现有系统集成**: -- 产品经理:调用 `ctxSvc.BuildContextSnapshot` 取数代替现有部分逻辑 -- 测试工程师:同样使用新快照,而非硬查 SRS -- 血缘追溯:输出文档内包含 source manifest 和追溯表 - -**测试**: -```go -func TestProjectContextSnapshot_ConsistentForSameInput(t *testing.T) { - // 同一项目在同一时刻的快照 hash 相同 -} - -func TestProjectContextSnapshot_ChangeWhenSourceUpdated(t *testing.T) { - // 新批准文档后快照 hash 改变 -} - -func TestProjectContextSnapshot_ExcludesPrivateContent(t *testing.T) { - // 私人草稿和未共享对话不纳入 -} - -func TestProjectContextSnapshot_LineageComplete(t *testing.T) { - // 输出包含所有被引用来源的 manifest -} -``` - -**验收标准**: -- [ ] 快照服务实现完整 -- [ ] 产品/测试工程师都使用新服务 -- [ ] 快照可复现(同输入 → 同快照) -- [ ] 血缘追溯表完整 - -**预计工作量**: 12h - ---- - -## 第三部分:验收与发布(Phase C) - -### Task C1-C7: 见前面 Phase C 表 - -**总体验收检查表**: - -``` -□ 单元测试覆盖 - □ 所有 bug fix 有负例测试 - □ 新功能覆盖率 > 50% - □ 关键路径覆盖率 = 100% - -□ 集成测试 - □ PG 集成测试全 PASS - □ 并发测试 PASS - □ 数据库迁移向前向后兼容 - -□ 真实 E2E(PostgreSQL + PI Agent) - □ 商务流程 PASS - □ 产品流程 PASS - □ 测试流程 PASS - □ 项目完成后切换 PASS - □ 受控终止 PASS - -□ 验收标准(见 7.1-7.5) - □ 目录仅三项 - □ 禁用文档全拒绝 - □ 推进不改文档状态 - □ 完成后可配置下一流程 - □ 安全与审计完整 - -□ 文档与发布 - □ API 文档更新 - □ 发布说明完成 - □ 迁移脚本与回滚 - □ 用户指南 - -□ 生产就绪检查 - □ 性能基准测试 - □ 压力测试 - □ 故障场景演练 - □ 审计日志覆盖 -``` - ---- - -**完整拆分总结**: -- **Phase A** (Day 1): 15 小时 - 关键缺陷修复 -- **Phase B** (Day 2-3): 26 小时 - 新功能开发 -- **Phase C** (Day 4-5): 20 小时 - 完善与发布 - -**总计**: ~61 小时 - ---- - -**下一步**: 选择一项任务开始实施,或全队并行进行。 +本文档已迁至 [remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md](remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-three-workflows-strict-governance-remediation.md b/.doc/2026-09-12-three-workflows-strict-governance-remediation.md index 8018467f..33871a97 100644 --- a/.doc/2026-09-12-three-workflows-strict-governance-remediation.md +++ b/.doc/2026-09-12-three-workflows-strict-governance-remediation.md @@ -1,525 +1,3 @@ -# 三工作流严格治理与现有系统融合整改方案 +# 已迁移 -- 日期:2026-09-12 -- 状态:核心业务决策已确认 / 可进入实施拆分 -- 范围:工作流定义、项目实例、阶段门禁、文档三权、通知与对话推进、运行时授权、数据迁移和验收 -- 本文性质:当前代码与开发数据库的只读核验结论及整改设计;本轮未修改业务代码 - -## 1. 结论先行 - -系统面向项目创建者和项目成员时,只应存在以下 **3 个可选择工作流**: - -1. **商务对接流程**:7 个文档,3 个阶段; -2. **智能产品经理流程**:1 个输出文档,1 个阶段; -3. **智能测试工程师流程**:1 个输出文档,1 个阶段。 - -商务对接流程的文档数量可以定案为 **7 个,不是 6 个**。前端模板工厂和测试固定断言了 7 个任务键,后端标准任务目录也包含同一组 7 个商务文档,历史专项测试报告同样把它们定义为标准全生命周期交付物。[^biz-seven-test][^biz-seven-backend][^biz-seven-report] - -当前系统尚未满足这一目标,且不是简单改几个显示名称即可解决: - -- 启动代码实际发布 5 个默认工作流,除目标三项外还包含“医疗器械研发”和“非医疗纯软件”;[^bootstrap-five] -- 当前开发库已有 92 个工作流定义,其中大量为测试定义;三个目标工作流仍都是单阶段的 schema v1; -- 仓库虽然有三个 schema v2 清单,但商务清单只有 5 个文档,漏了 `feasibility_dev` 和 `user_requirements`;[^main-v2-missing] -- 三个 v2 清单仅被嵌入和登记,没有进入启动发布链;已有发布版又会让 seed 逻辑直接退出,因此现有库不会自动升级;[^manifest-loader][^seed-no-upgrade] -- 旧运行入口会把多阶段版本压成“第一个阶段的第一个任务”,与项目实例运行时并存,形成双轨权威;[^catalog-flatten] -- 配置页面允许勾选关闭文档,但后端校验禁止关闭所有 `required/blocking` 文档;当前清单又把所有文档都标成这两类,因此界面能力实际上不可用;[^plan-disable-conflict] -- 智能测试工程师当前被 manifest、执行服务和前端提示硬绑定到产品经理/SRS,与已确认的两个智能工作流独立运行原则冲突;[^test-upstream][^test-hard-dependency] -- 阶段推进虽然先检查批准状态,但事务内会把所有启用任务强制写成 `approved`,并且最后阶段完成后没有把项目恢复到可选择下一工作流的状态;[^advance-forces-approved][^project-lifecycle-gap] -- 对话中的“推进阶段”仍调用旧商务成熟度执行器,并没有调用项目工作流实例的阶段推进服务;[^dialogue-old-advance] - -因此本次整改的核心是:**以已激活项目工作流实例的冻结快照作为唯一运行时权威**。工作流目录、项目配置、文档三权、任务启动、审批、阶段门禁、通知和对话都必须围绕同一个实例标识运行,旧的直接切换和扁平执行入口退出生产路径。 - -## 2. 已确认的业务基线 - -### 2.1 唯一允许对项目展示和选择的工作流 - -| 稳定内部 key | 对外名称 | 阶段数 | 输出文档数 | 说明 | -|---|---|---:|---:|---| -| `main` | 商务对接流程 | 3 | 7 | 保留现有 key 以避免破坏历史数据,只改正式名称 | -| `product_manager` | 智能产品经理流程 | 1 | 1 | 输出《系统需求规格书》 | -| `test_manager` | 智能测试工程师流程 | 1 | 1 | 保留现有 key,只把“测试经理”统一更名为“测试工程师” | - -“系统只需要三个流程”的含义应同时落实到三个层面: - -- 项目设置 API 只返回这 3 个可选项; -- 前端任何入口只展示这 3 个可选项; -- 服务端只允许为这 3 个正式、已发布版本创建项目工作流实例。 - -后台可以保留历史定义和草稿以满足审计,但必须标记为 `retired` 或 `project_selectable=false`,不能继续出现在项目目录中。不能仅靠前端白名单隐藏,因为当前设置服务会枚举数据库里全部有发布版本的定义。[^settings-all-definitions] - -### 2.2 商务对接流程:7 个文档,3 个阶段 - -沿用系统已经形成的 V0.1 / V0.5 / V1.0 业务阶段和模板归属,目标定义如下。当前模板工厂已按 `1 + 5 + 1` 归档这 7 个文档。[^template-stage-map] - -| 阶段 | 顺序 | task key | 正式文档名 | 默认状态 | 阶段门禁 | -|---|---:|---|---|---|---| -| V0.1 需求摸底 | 10 | `intake` | 用户初始需求收集表 | 启用 | 启用时必须批准 | -| V0.5 方案与可行性 | 20 | `research` | 调研报告 | 启用 | 启用时必须批准 | -| V0.5 方案与可行性 | 21 | `feasibility_dev` | 设计开发可行性评估报告 | 启用 | 启用时必须批准 | -| V0.5 方案与可行性 | 22 | `feasibility_reg` | 注册路径可行性评估报告 | 启用 | 启用时必须批准 | -| V0.5 方案与可行性 | 23 | `user_requirements` | 用户需求表 | 启用 | 启用时必须批准 | -| V0.5 方案与可行性 | 24 | `prelim_design` | 系统初步设计方案 | 启用 | 启用时必须批准 | -| V1.0 商务报价 | 30 | `cdo_quote` | CDO 报价单 | 启用 | 启用时必须批准 | - -当前后端商务阶段只执行 `intake`、`research`、`feasibility_reg`、`prelim_design`、`cdo_quote` 五项,正好缺少另外两项,必须同步补齐阶段执行映射和 executor 注册。[^biz-stage-five][^executor-missing] - -### 2.3 智能产品经理流程 - -| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 | -|---|---|---|---|---| -| 系统需求基线 | `system_reqs` | 系统需求规格书 | 启用 | 文档批准后,创建者确认完成工作流 | - -### 2.4 智能测试工程师流程 - -| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 | -|---|---|---|---|---| -| 系统验证策划 | `test_manager` | 系统验证方案及计划 | 启用 | 文档批准后,创建者确认完成工作流 | - -**智能产品经理流程和智能测试工程师流程相互解耦。** 智能测试工程师流程不再要求项目曾运行智能产品经理流程,也不再要求必须存在该流程输出的《系统需求规格书》。它直接从当前项目可用于工作流的对话、文档、上传材料、项目事实和决策记录中提取需求及验证依据,独立生成《系统验证方案及计划》。 - -如果项目中恰好存在已批准的《系统需求规格书》,它只是项目输入集合中的一项高权威来源,不是启动前置条件,也不产生流程级耦合。当前 manifest、执行服务、血缘逻辑和前端提示仍硬编码了这一依赖,整改时必须一起删除。[^test-upstream][^test-hard-dependency] - -### 2.5 两个智能工作流的统一项目上下文输入 - -智能产品经理和智能测试工程师使用同一个“项目上下文快照服务”,但采用不同的分析目标和输出模板: - -| 输入类别 | 纳入内容 | 建议权威等级 | -|---|---|---| -| 项目事实 | 项目名称、客户、产品类型、预期用途、目标市场、结构化事实黑板 | 已确认事实 | -| 项目决策 | 创建者确认事项、里程碑决策、已关闭的待确认项 | 已确认决策 | -| 项目文档 | 当前有效版本的受控文档、项目共享文档、上传材料 | 按批准状态和来源分级 | -| 项目对话 | 所有已进入项目共享知识边界的成员对话及其附件 | 原始沟通证据 | -| 历史输出 | 商务、产品、测试或自由任务形成的项目交付物 | 按状态和版本分级 | -| 知识依据 | 系统检索到的法规、标准和内部知识库命中 | 外部参考依据 | - -这里的“所有”是指 **当前项目知识边界内全部有资格被工作流使用的内容**,不是把数据库中所有原文无差别拼接到一次模型调用中。建议遵循以下规则: - -1. 只纳入当前项目,绝不跨项目召回; -2. 私人草稿、个人私聊只有在明确“共享到项目”后才进入项目级工作流输入,避免流程执行扩大原有可见范围; -3. 任务启动时生成不可变 `project_context_snapshot`,记录截止时间、来源 ID、版本、内容 hash、权限判定和引用位置; -4. 全量来源先建立清单,再按任务目标检索相关片段;已确认事实和已批准文档必须进入固定核心上下文,普通对话按相关性分批读取; -5. 冲突时不静默覆盖,优先级建议为:创建者确认事实/决策 > 当前已批准文档 > 用户上传原始材料 > 里程碑记录 > 普通项目对话 > 智能体历史总结; -6. 输出必须带 source manifest。智能测试工程师需在唯一输出文档内部生成“需求/风险—测试项—来源”追溯表,不额外创建第二个受控输出文档; -7. 任务运行后项目来源发生变化时,依据被引用来源的 hash 判断 `input_changed/stale`,而不是只监听《系统需求规格书》。未被本次输出引用的无关对话变化不应把文档误标为 stale。 - -现有 Squad 工作区已经支持 project context、materials、prior docs、knowledge hits 等输入槽位,也会建立带权威等级的 context 索引;产品经理还已有从项目事实和里程碑生成输入材料的局部实现。因此应把这些能力上移为通用项目上下文快照服务,而不是为测试流程继续维护单一 SRS 特例。[^context-input-foundation] - -## 3. 不可违反的业务规则 - -### 3.1 选择、启动和切换 - -1. 只有项目创建者可以选择、配置、激活、推进或受控终止项目工作流。 -2. 一个项目同一时刻最多只能有一个 live 实例。 -3. 在 `active`、`awaiting_stage_confirmation` 或 `termination_requested` 状态下,不允许选择或切换工作流。 -4. “切换工作流”不是修改当前实例的 `workflow_key`,而是当前实例 `completed` 或 `terminated` 后创建一个新的 planning 实例。 -5. 激活时冻结工作流版本、阶段、文档开关、模板版本、执行器、质量门禁和三权责任人。运行中不可静默修改。 -6. 管理员不因系统身份自动替代项目创建者执行推进;如以后引入 break-glass,必须单独设计理由、再认证和审计,且不能代替文档签署人。 - -目标状态机: - -```mermaid -stateDiagram-v2 - [*] --> planning: 创建者选择并配置 - planning --> active: 预览后确认激活 - active --> awaiting_stage_confirmation: 当前阶段所有启用文档已批准 - awaiting_stage_confirmation --> active: 创建者确认进入下一阶段 - awaiting_stage_confirmation --> completed: 创建者确认完成最后阶段 - active --> termination_requested: 创建者申请终止 - termination_requested --> terminated: 二次确认并记录原因 - completed --> planning: 创建下一工作流实例 - terminated --> planning: 创建下一工作流实例 -``` - -数据库已经为一个 planning 实例和一个 live 实例设置了部分唯一索引,也预留了 `awaiting_stage_confirmation`、`terminated` 等状态,适合沿此模型完善,不必另造一套表。[^instance-schema] - -### 3.2 文档启用与禁用 - -项目创建者可以在 planning 状态逐文档启用或禁用。严格语义如下: - -| 文档状态 | 三权配置 | 可创建/启动编制 | 可提交审核 | 可审核 | 可批准 | 是否计入阶段门禁 | -|---|---|---:|---:|---:|---:|---:| -| enabled | 作者、审核人、批准人均必填且互斥 | 是,仅作者或明确执行人 | 是,仅作者 | 是,仅审核人 | 是,仅批准人 | 是 | -| disabled | 必须为空 | 否 | 否 | 否 | 否 | 否 | - -关键约束: - -- `default_enabled` 只表示默认值,不表示不可关闭; -- `blocking_when_enabled=true` 表示文档一旦启用,未批准就阻断阶段; -- 新增明确字段 `creator_configurable=true/false`,不要继续混用现有 `required`、`blocking`、`default_enabled` 三个布尔值表达四种含义; -- 禁用后实例状态写为 `skipped_disabled`,不创建 DocGov 文档、不生成三权行,也不允许通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动; -- 对禁用文档发起动作时统一返回 `409 DOC_TASK_DISABLED`;对启用文档但责任人不匹配返回 `403 DOC_DUTY_FORBIDDEN`; -- 激活计划必须至少包含一个启用文档。这样一文档流程仍可在配置时关闭唯一文档,但关闭后不能激活一个没有产出的空工作流。 - -现有数据结构已经能表达 `enabled` 和三权,且持久化时会跳过禁用文档的职责写入;可复用这部分。问题在于定义校验把 required/blocking 文档一律视为不可关闭,需要先修正语义。[^plan-structure][^duty-write-enabled-only] - -### 3.3 阶段完成和推进 - -阶段就绪的唯一业务判定应为: - -```text -stage_ready = 当前阶段处于 active - AND 当前阶段至少有一个 enabled 文档 - AND 每个 enabled 文档的当前受控版本都为 approved - AND 没有正在执行、待审核、待批准或 stale 的同任务实例 -``` - -推进动作必须满足: - -- 服务端在同一数据库事务中锁定 workflow instance 和 stage instance; -- 重新计算门禁,不能只信几秒前的 readiness 响应; -- 校验操作者仍是项目创建者; -- 校验 `expected_config_revision` 和幂等键; -- 只改变阶段和实例状态,绝不把文档“补写”为 approved; -- 进入下一启用阶段;若没有下一阶段,则把实例标为 completed,并把项目切回“可配置下一个工作流”的状态; -- 同事务关闭对应 `stage_advance_request`,写审计和 outbox 事件。 - -当前 readiness 已经忽略禁用任务、检查启用必需文档是否批准,并限制创建者推进,这一骨架可以保留;但它按 `project_id + task_key` 汇总文档状态,仍需升级到 `doc_task_instance_id + document_version_id`,避免跨阶段或重复实例串线。[^readiness-current][^approval-key-too-wide] - -### 3.4 主动提醒和对话推进 - -系统在 readiness 从 false 变为 true 时生成一次 `stage.ready_to_advance` 事件,并只通知项目创建者。已有 outbox、站内通知、去重键以及 24 小时再次提醒机制可以复用。[^notify-ready][^notify-reminder] - -建议闭环: - -1. 最后一份启用文档批准; -2. 事务后事件处理器重新计算 readiness; -3. 实例进入 `awaiting_stage_confirmation`; -4. 创建者收到站内消息和可操作确认卡:阶段名、启用/已批准文档清单、下一阶段或“完成工作流”; -5. 创建者点击按钮,或在项目对话中说“推进到下一阶段 / 确认推进”; -6. 两种入口都调用同一个 `AdvanceStage` 应用服务; -7. 成功后通知状态改为 acted,推进请求改为 confirmed;若条件在确认前失效,则返回最新阻断项并把旧请求标为 superseded。 - -当前前端已经每 15 秒拉取通知并显示“确认推进”按钮,但对话入口仍走旧的 `bizdev.ExecuteStage`,所以需要把自然语言意图解析与执行彻底分开:识别器只产生命令,实例服务才拥有推进权。[^stage-banner][^dialogue-old-advance] - -## 4. 当前系统与目标的差距 - -### 4.1 定义和目录 - -| 编号 | 当前事实 | 风险 | 整改 | -|---|---|---|---| -| WF-CAT-01 | Bootstrap 发布 5 个工作流 | 项目会看到目标外流程 | 只发布三项;其余退役且不可选 | -| WF-CAT-02 | 设置服务返回所有有发布版的定义 | 测试/历史流程进入项目 | 增加 `project_selectable`,查询端白名单 + 状态双重校验 | -| WF-CAT-03 | 开发库有 92 个定义,88 个 key 为 `pg_*` 或 `test_*` | 测试污染业务目录 | 测试强制独立数据库/schema,fixture 必须清理 | -| WF-DEF-01 | 三个正式 key 当前均为 schema v1 单阶段 | 实际运行不是目标结构 | 以新版本发布 schema v2/v3,禁止覆盖旧版本 | -| WF-DEF-02 | `main.v2.json` 只有 5 个文档 | 商务流程缺 2 个输出 | 补齐 7 个并增加 executor、模板和质量门禁校验 | -| WF-DEF-03 | v2 manifest 未进入 bootstrap | 仓库文件与运行数据库不一致 | 建立 manifest 迁移器,按 hash 创建并发布新版本 | -| WF-DEF-04 | seed 发现任何 published 就跳过 | 永远停留旧版本 | 按内容 hash 和目标版本升级,写版本迁移审计 | -| WF-DEF-05 | DBCatalog 压扁完整定义 | 多阶段配置不能驱动运行 | 删除生产 flatten 路径,运行只读取冻结实例 | -| WF-DEF-06 | 测试流程声明 product_manager 上游,执行服务又硬查 approved SRS | 两个智能工作流不能独立运行 | 删除流程级依赖;改用统一项目上下文快照和多来源血缘 | - -### 4.2 项目实例和生命周期 - -| 编号 | 当前事实 | 风险 | 整改 | -|---|---|---|---| -| WF-INS-01 | planning / active 和唯一 live 骨架已存在 | 可复用但未闭环 | 扩展 awaiting/completed/terminated 完整转换 | -| WF-INS-02 | 完成最后阶段只更新实例 | 项目仍为 active,无法配置下一流程 | 同事务更新项目可选择状态并清空 current live 指针 | -| WF-INS-03 | 无受控终止 API | 异常流程永久锁死或只能改库 | 增加申请、影响预览、创建者二次确认和终止原因 | -| WF-INS-04 | 激活 token 明文保存,消费与激活分事务 | 失败后 token 已失效或可泄露 | 只存 hash,并在激活事务内锁定、消费 | -| WF-INS-05 | 冻结子任务只写 key/enabled/status | executor、模板、质量门禁仍依赖可变定义 | 激活时把完整运行元数据写入实例表并以实例表为权威 | - -数据库已添加 executor/template/quality gate 列,但当前实例写入 SQL 仍只插入 task key、enabled 和 status,证明冻结快照尚未真正成为执行权威。[^instance-runtime-metadata] - -### 4.3 文档、三权和运行时授权 - -| 编号 | 当前事实 | 风险 | 整改 | -|---|---|---|---| -| WF-DOC-01 | 启用文档要求三权且互斥 | 基础规则正确 | 再校验三人均为 active 项目成员且账户有效 | -| WF-DOC-02 | 禁用文档不会写三权 | 基础持久化正确 | 增加 `skipped_disabled` 和全入口拒绝 | -| WF-DOC-03 | 访问过滤按 task key 判断 | 同 key 重复实例可能串权 | 所有动作使用 `doc_task_instance_id` | -| WF-DOC-04 | 无 live 实例时访问过滤默认不限制 | 完成后旧任务入口可能恢复可用 | 正式项目按治理模式 fail closed;legacy 仅限显式迁移标记 | -| WF-DOC-05 | 运行入口仍接受 task key 并查扁平目录 | 可能绕过阶段和冻结绑定 | 请求只传 doc task instance id,服务端解析 executor/template/duty | -| WF-DOC-06 | DocGov 状态机可验证具体审核/批准人 | 可复用 | 文档必须外键绑定 doc task instance 和版本 | - -现有阶段访问代码确实会从 live 快照中排除禁用任务,这是可保留的基础;但当没有 live 实例或实例 completed 时会返回 unrestricted,因此不能把它视为禁用文档全生命周期的完整保障。[^stage-access] - -### 4.4 前端、通知和对话 - -| 编号 | 当前事实 | 风险 | 整改 | -|---|---|---|---| -| WF-UI-01 | 旧切换器硬编码三项,但名称不一致 | 用户认知混乱 | 统一为三个正式名称,数据来自服务端目录 | -| WF-UI-02 | 新治理 API 失败时回退旧直接切换 UI | 可重新打开不合规路径 | 删除回退;治理不可用时只读并明确报错 | -| WF-UI-03 | 旧切换在版本冲突后自动重试 | 可能覆盖用户最新选择 | 展示冲突并要求重新确认,不自动提交高风险操作 | -| WF-UI-04 | 项目设置只显示 stage/task key | 不利于业务确认 | 显示正式阶段名、文档名、启用状态、三权和影响摘要 | -| WF-UI-05 | live 配置缺少完整只读审计视图 | 创建者不清楚冻结内容 | 展示版本、hash、激活人/时间、所有 enabled/disabled 和职责 | -| WF-NOTIFY-01 | readiness 通知和 24h 提醒已存在 | 基础可复用 | 增加状态转换、已读/已处理、失效和重算 | -| WF-DLG-01 | 对话推进旧商务阶段 | 可越过新实例门禁 | 对话调用同一实例 AdvanceStage command | -| WF-CTX-01 | 产品经理仅在无材料时拼装部分项目事实;测试工程师只注入 SRS | “全部项目内容”没有统一、可复现的输入语义 | 建立项目上下文快照、来源清单、权限过滤、冲突优先级和 hash 血缘 | - -旧前端切换器在治理不可用时仍调用 `/active-workflow`,并在冲突后自动取新版本再次切换;这两个行为都应删除。[^legacy-switch-ui] 旧服务端路由在迁移完成后应返回 `410 WORKFLOW_SWITCH_API_RETIRED`,而不是继续作为备用入口。[^legacy-route] - -### 4.5 开发数据库现场快照 - -2026-09-12 对当前 `shuimu-context-pg-dev / agent_system_dev` 做只读查询得到: - -```text -workflow_definitions = 92 -published workflow versions = 92 -main = version 1, schema 1, 1 stage -product_manager = version 1, schema 1, 1 stage -test_manager = version 1, schema 1, 1 stage -project_workflow_instances: active 32, completed 47 -projects.lifecycle_status: active 97, planning 51 -completed 实例已存在、无 live 实例但项目仍为 active:47 个 -测试命名定义(pg_* / test_*):88 个 -``` - -这些数字主要反映当前开发环境和集成测试污染,不能直接当成生产数据;但它们证明目录查询没有隔离正式定义与测试定义,也直接复现了“实例已完成而项目仍 active”的生命周期断点。PG 测试在未设置 `TEST_DATABASE_URL` 时默认连接开发库,部分定义发布测试又没有清理工作流定义,因此必须纳入整改。[^test-db-default][^test-definition-no-cleanup] - -## 5. 目标技术模型 - -### 5.1 单一运行权威 - -```text -Published Workflow Version - │ 创建 planning plan - ▼ -Project Workflow Instance + immutable config snapshot - │ 激活时物化 - ├── Stage Instances - │ └── Doc Task Instances - │ ├── frozen executor/template/quality gate - │ ├── duty assignments - │ ├── controlled document versions - │ └── task runs - ├── Stage Advance Requests / Notifications - └── Audit / Outbox Events -``` - -激活后,任何运行请求不得再从“最新发布定义”、前端 task key 或 legacy catalog 推导行为。最新定义只用于创建未来实例;已运行实例永远引用自己的冻结数据。 - -### 5.2 定义 schema 建议 - -文档任务应至少明确以下字段: - -```json -{ - "key": "research", - "title": "调研报告", - "default_enabled": true, - "creator_configurable": true, - "blocking_when_enabled": true, - "executor_key": "bizdev.research.v1", - "quality_gate_key": "quality.generic.v1", - "template": {"asset_key": "research", "version": 1}, - "output_doc_type": "research", - "output_doc_title": "调研报告" -} -``` - -发布校验必须增加: - -- workflow key 属于三个正式 key 之一,且对外名称准确; -- 阶段 key、position、任务 key 均唯一且非空; -- 每个阶段至少一个文档任务; -- executor、quality gate 和 ready 模板版本全部存在; -- 三个正式流程精确满足 7 / 1 / 1 文档清单; -- 三个正式工作流均不声明流程级 `required_upstream_workflow`; -- 项目上下文输入策略、来源权限和冲突优先级完整; -- 禁用策略、完成策略和参与策略完整; -- 发布后版本不可原地修改。 - -当前 v2 校验只检查 schema 版本、阶段位置、executor/quality gate 注册和输出类型,尚不足以守住上述业务契约。[^validator-v2] - -### 5.3 数据结构增量 - -优先扩展现有表,不重复建模: - -- `workflow_definitions`:增加 `project_selectable`、`catalog_order`、`official_code`; -- `workflow_versions.definition_json`:采用新禁用语义并保留版本 hash; -- `project_workflow_instances`:增加 `completed_at/by`、`terminated_at/by/reason`、`previous_instance_id`; -- `project_stage_instances`:增加 `ready_at`、`completed_at/by`; -- `project_doc_task_instances`:持久化 `executor_key`、`quality_gate_key`、模板 asset/version、output type/title;禁用任务状态为 `skipped_disabled`; -- `documents`:增加 `doc_task_instance_id`,受控文档版本唯一绑定; -- `project_context_snapshots`:记录项目、任务、截止时间、汇总 hash、创建人和冻结状态; -- `project_context_snapshot_sources`:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用; -- `task_runs`:增加 `workflow_instance_id`、`stage_instance_id`、`doc_task_instance_id`、`context_snapshot_id`; -- `document_lineages`:从单一“上游 SRS”扩展为多来源 lineage,允许对话、材料、事实、决策和文档版本作为来源; -- `stage_advance_requests`:保留 readiness revision,补 `idempotency_key`、`superseded_at`; -- 审计事件:至少记录 plan saved、activated、document disabled/enabled、duty assigned、stage ready、stage advanced、workflow completed/terminated。 - -### 5.4 API 收敛 - -建议正式接口: - -| 方法与路径 | 用途 | 关键约束 | -|---|---|---| -| `GET /api/v1/workflows/catalog` | 返回严格三项正式目录 | 只含 project_selectable + published | -| `GET /api/v1/projects/{id}/settings` | 规划或冻结配置视图 | 项目访问控制 | -| `PUT /api/v1/projects/{id}/workflow-plan` | 选择流程、开关文档、设置三权 | 仅创建者、仅 planning、乐观锁 | -| `POST /api/v1/projects/{id}/activation-preview` | 完整影响与校验 | 无空流程、三权和上下文策略通过 | -| `POST /api/v1/projects/{id}/workflow-instances/activate` | 冻结并激活 | 创建者二次确认、原子 token | -| `GET /api/v1/workflow-instances/{id}` | 运行和历史详情 | 项目 + 阶段可见性 | -| `GET /api/v1/workflow-instances/{id}/stages/{key}/readiness` | 门禁详情 | 返回所有启用文档状态 | -| `POST /api/v1/workflow-instances/{id}/stages/{key}/advance` | 创建者推进或完成 | 事务内重算、幂等 | -| `POST /api/v1/workflow-instances/{id}/termination-preview` | 终止影响 | 未决任务、文档和通知清单 | -| `POST /api/v1/workflow-instances/{id}/terminate` | 受控终止 | 创建者、原因、二次确认 | -| `POST /api/v1/doc-task-instances/{id}/runs` | 启动编制 | enabled + active stage + duty | - -旧 `/projects/{id}/active-workflow` 和依赖扁平 workflow key 的 run 接口先记录迁移告警,完成客户端切换后返回 410。 - -## 6. 实施顺序 - -### Phase 0:冻结错误扩散和数据盘点 - -1. 给项目目录增加服务端正式白名单,立即只暴露三个目标 key。 -2. 禁止测试默认连接开发库;CI 必须显式提供隔离的 `TEST_DATABASE_URL`。 -3. 备份并分类 92 个定义及其引用:正式、历史、测试、被实例引用。 -4. 未被任何实例引用的测试定义在开发环境清理;被引用定义只退役,不物理删除。 -5. 修复开发环境中 completed instance 与 project lifecycle 不一致的数据,但先输出 dry-run 清单。 - -### Phase 1:发布三个唯一正式定义 - -1. 修订三个 manifest 的正式名称与 schema;商务流程补齐 7 个文档。 -2. 为 `feasibility_dev` 和 `user_requirements` 注册专用 executor,或明确映射到通用任务 executor;禁止使用含混的法规 executor 代替。 -3. 从 `test_manager` manifest、默认目录和校验模型中删除 `required_upstream_workflow=product_manager`,使三个流程在流程级完全独立。 -4. 增加严格发布校验和 7 / 1 / 1 契约测试。 -5. 实现 hash 驱动的版本升级:已有 v1 时创建 v2/v3,而不是退出或覆盖。 -6. `medical_device_development`、`non_medical_software` 及其他定义全部 `project_selectable=false` 并退役。 - -### Phase 2:补齐实例状态机和禁用语义 - -1. 重构 plan validator:creator-configurable 文档可关闭;启用文档三权必填;空工作流不可激活。 -2. 校验三权人员为有效项目成员、账户有效且三权互斥。 -3. 激活时完整物化运行元数据,以实例为唯一权威。 -4. 阶段推进事务内重算门禁,删除“推进时强制批准文档”的 SQL。 -5. 完成最后阶段时同步更新项目状态,使其可创建下一 planning 实例。 -6. 实现受控终止,保证 live 实例不会永久锁住项目。 - -### Phase 3:运行、文档治理和权限合流 - -1. 建立通用项目上下文快照服务,覆盖项目事实、项目级对话、文档、材料、决策、历史输出和知识命中。 -2. 产品经理和测试工程师分别从同一快照服务取数;删除测试任务中“查找已批准 system_reqs,否则拒绝”的特例。 -3. 所有任务启动改用 `doc_task_instance_id`;服务端解析 task/executor/template/stage/duty/context snapshot。 -4. 文档创建、查看、编辑、提交、审核、批准均校验同一 doc task instance。 -5. disabled、非当前阶段、非责任人、实例非 live 均 fail closed。 -6. SSE、异步 task run、恢复/取消、RAG 检索、Agent tools 使用同一策略决策。 -7. 审批回调按具体文档版本更新具体 doc task instance,不再按项目 + task key 批量更新。 -8. 把 SRS 单来源 lineage 改成 source manifest 多来源血缘;只在实际引用来源变化时标记输出待复核。 - -### Phase 4:通知、对话和前端闭环 - -1. readiness 边沿触发状态和通知,补 read/acted/dismissed API。 -2. 把对话“推进/完成工作流”绑定到项目实例 command;保留明确确认卡。 -3. 项目设置只显示三项,按正式名称显示阶段和文档。 -4. active/awaiting 时显示冻结只读视图,隐藏所有切换动作。 -5. completed/terminated 后显示“配置下一个工作流”,而不是修改旧实例。 -6. 删除旧切换回退、冲突自动重试和 `WorkflowPrerequisiteBanner` 的产品经理前置提示。 -7. 在运行预览中展示项目上下文截止时间、来源数量、被排除的私有/无权内容和冲突项。 - -### Phase 5:迁移和发布 - -1. 新项目只允许使用新的三个正式版本。 -2. 尚未激活的 planning v1 计划自动重建为新版本草稿,并要求创建者重新确认三权。 -3. 已激活 v1 实例不静默改写:真实业务实例由创建者选择继续兼容完成或受控终止后重建;开发/测试垃圾实例按确认后的清理脚本处理。 -4. 先 shadow 计算新旧 readiness 差异,再开启新推进服务。 -5. 通过全套验收后关闭 legacy route 和 flatten catalog。 - -## 7. 验收标准 - -### 7.1 目录和定义 - -- 任意项目、任意普通用户或管理员在项目选择页都只能看到 3 个工作流。 -- 正式名称精确为“商务对接流程 / 智能产品经理流程 / 智能测试工程师流程”。 -- 定义快照精确为 7 / 1 / 1;缺一、多一、重复 key、模板未 ready 或 executor 未注册均无法发布。 -- 三个正式定义均没有流程级上游依赖;产品经理和测试工程师可被分别独立选择和运行。 -- 服务重启、数据库迁移和旧数据存在时,目录结果仍稳定为三项。 - -### 7.2 选择和冻结 - -- 只有项目创建者可保存、激活和推进;普通成员、系统管理员默认均被拒绝。 -- live 实例存在时,UI、API 和对话三个入口均不能切换。 -- 工作流完成或受控终止后,创建者可以配置下一实例;旧实例保持只读可追溯。 -- 两个浏览器同时配置或推进时只有一个成功,另一个收到版本冲突并重新确认。 - -### 7.3 文档开关和三权 - -- 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活。 -- 禁用文档没有职责行、没有受控文档、没有运行按钮,也不能通过手工 API、SSE 或对话启动。 -- 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED`。 -- 再启用只允许发生在 planning;激活后不能原地改变。 - -### 7.4 阶段门禁和提醒 - -- 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断并返回清单。 -- 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒。 -- readiness 后文档被驳回或标 stale 时,旧推进请求失效,确认动作不能成功。 -- 推进事务不会修改任何文档审批状态。 -- 最后一阶段确认后实例为 completed,项目立即可配置下一流程。 - -### 7.5 安全、恢复和真实链路 - -- 跨项目、非成员、非职责人、未来阶段成员、已退出成员全部有服务端负例。 -- API、SSE、异步任务、断线恢复、搜索、导出、RAG 和 Agent tool 的判定一致。 -- 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求。 -- 使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路。 -- 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案;输出包含逐项来源追溯和待确认清单。 -- 项目已有 SRS 时,该文档被当作高权威来源纳入,但移除它不会导致工作流定义级依赖错误;是否需要重新生成由本次 source manifest 判断。 -- 项目私聊/个人草稿未共享时不进入上下文;共享后可被新快照发现。跨项目内容在检索和快照层都有负例。 -- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致,输出目标和模板不同。 -- 测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义或测试项目。 - -## 8. 已确认的业务决策及实施解释 - -2026-09-12 已确认以下决策,后续实现和验收以此为准: - -1. **允许关闭单文档流程的唯一文档,但空工作流不能激活。** 配置可以保存,激活预览必须明确阻断并提示重新启用文档或选择其他工作流。 -2. **智能产品经理和智能测试工程师解耦。** 两者都直接使用当前项目知识边界内的对话、文档、材料、事实和决策。任何一方的产出都不是另一方的启动前置;已有 SRS 仅作为高权威输入来源。 -3. **开放项目创建者受控终止工作流。** 必须二次确认、填写原因、处理或取消在途任务并形成审计;completed 和 terminated 都允许创建下一工作流实例,但历史含义必须区分。 - -这些决策合理且彼此一致。第 2 项的实施建议是“流程解耦、数据可组合、来源可追溯”,而不是取消质量控制:测试工程师必须自己从项目上下文抽取需求和风险,生成文档内追溯矩阵,并将缺少判据的内容列为待确认,不能因为没有 SRS 就编造需求。 - -商务流程按 7 个文档落地、系统只暴露三个正式流程、运行中不可切换、阶段推进必须由创建者确认、禁用文档不得参与任何编审批动作,也均为已确认要求。 - -## 9. 建议的实施交付拆分 - -建议按以下 8 个可独立评审的变更集提交,避免一次大改难以回滚: - -1. 正式目录隔离与测试数据库隔离; -2. 三个正式 manifest、严格 validator 和版本升级器; -3. planning 配置、文档开关和成员/三权校验; -4. 激活冻结与完整实例物化; -5. doc task instance 驱动的执行、DocGov 和统一授权; -6. 原子 readiness / advance / complete / terminate 状态机; -7. 通知、对话命令与前端只读/下一流程体验; -8. 数据迁移、兼容退出、真实 PG/PI Agent E2E 和发布门禁。 - -每个变更集都应包含正向测试、越权负例、并发负例和重启恢复验证。只有第 8 项完成后,才应删除旧兼容路径并宣布三工作流治理正式生效。 - -## 10. 来源与证据 - -[^biz-seven-test]: `web/src/engine/templateFactory.test.ts:8-33`,测试精确断言 7 个任务键;读取于 2026-09-12。 -[^biz-seven-backend]: `internal/squad/service.go:128-138`,后端标准任务目录包含 7 个商务任务及产品、测试任务;读取于 2026-09-12。 -[^biz-seven-report]: `.doc/test-reports/2026-09-08-project-init-template-cloning-test-report.md:12-25,51-60`,历史专项测试把商务全生命周期固定为 7 个受控交付物;读取于 2026-09-12。 -[^bootstrap-five]: `internal/workflowdef/bootstrap.go:63-74,78-115`,启动种子包含三个旧流程及两个额外行业流程;读取于 2026-09-12。 -[^main-v2-missing]: `internal/workflowdef/manifests/main.v2.json:1-50`,清单只定义 intake、research、feasibility_reg、prelim_design、cdo_quote;读取于 2026-09-12。 -[^manifest-loader]: `internal/workflowdef/manifest_loader.go:9-32` 仅提供嵌入读取和文件名映射;仓库检索未发现 `V2ManifestFiles` 的运行时调用;读取于 2026-09-12。 -[^seed-no-upgrade]: `internal/workflowdef/store.go:364-372`,已有任意 latest published version 时直接返回;读取于 2026-09-12。 -[^catalog-flatten]: `internal/workflowdef/catalog.go:27-41,50-82`,数据库目录将版本压为首阶段首任务;读取于 2026-09-12。 -[^plan-disable-conflict]: `internal/projectinstance/validator.go:37-90,105-139`,required 或 blocking 任务关闭时校验失败;读取于 2026-09-12。 -[^advance-forces-approved]: `internal/projectinstance/stage_store.go:71-158`,推进事务把启用任务状态强制更新为 approved;读取于 2026-09-12。 -[^project-lifecycle-gap]: `internal/projectinstance/stage_store.go:128-158` 只完成实例,`internal/projectinstance/service.go:119-135` 又只允许 planning 项目保存下一计划;读取于 2026-09-12。 -[^dialogue-old-advance]: `internal/coordinator/engine.go:672-811`,对话推进调用 `bizdevSvc.ExecuteStage` 并直接改变旧成熟度上下文;读取于 2026-09-12。 -[^settings-all-definitions]: `internal/projectinstance/service.go:94-113`,项目设置枚举全部有 latest published version 的定义;读取于 2026-09-12。 -[^template-stage-map]: `web/src/engine/templateFactory.ts:37-39,87-89,158-160,228-230,286-288,331-333,392-394`,7 个商务模板当前归属为 V0.1 一项、V0.5 五项、V1.0 一项;读取于 2026-09-12。 -[^biz-stage-five]: `internal/bizdev/service.go:204-223`,旧商务阶段仅映射 1 + 3 + 1 个任务;读取于 2026-09-12。 -[^executor-missing]: `internal/workflow/registry.go:5-15`,商务 executor 缺少 feasibility_dev 和 user_requirements;读取于 2026-09-12。 -[^test-upstream]: `internal/workflowdef/manifests/test_manager.v2.json:1-23`,测试流程声明 product_manager 前置依赖;读取于 2026-09-12。 -[^test-hard-dependency]: `internal/bizdev/service.go:349-380,673-687`,测试任务硬查同项目 approved SRS、自动注入并记录单一 SRS 血缘;读取于 2026-09-12。 -[^context-input-foundation]: `internal/squad/service.go:35-55`、`internal/squad/workspace.go:262-408` 和 `internal/bizdev/service.go:250-294`,现有运行参数及工作区已支持项目、材料、前序文档、知识和部分项目事实输入;读取于 2026-09-12。 -[^instance-schema]: `deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql:13-52`,实例状态和 one planning/one live 唯一索引;读取于 2026-09-12。 -[^plan-structure]: `internal/projectinstance/types.go:21-48`,计划已包含文档 enabled 和三权;读取于 2026-09-12。 -[^duty-write-enabled-only]: `internal/projectinstance/store.go:244-280`,禁用文档不会写职责行;读取于 2026-09-12。 -[^readiness-current]: `internal/projectinstance/gate.go:5-53` 和 `internal/projectinstance/stage_service.go:15-63`,现有门禁忽略禁用任务并限制创建者;读取于 2026-09-12。 -[^approval-key-too-wide]: `internal/projectinstance/stage_store.go:176-191`,批准同步按 project_id + task_key 更新;读取于 2026-09-12。 -[^notify-ready]: `internal/server/workflow_approval_hook.go:17-44` 和 `internal/notification/service.go:38-107`,批准回调、推进请求、outbox 与创建者通知;读取于 2026-09-12。 -[^notify-reminder]: `internal/notification/reminder.go:35-91,94-171`,24 小时提醒和 confirmed 状态;读取于 2026-09-12。 -[^stage-banner]: `web/src/components/workflow/StageAdvanceBanner.tsx:29-95,111-151`,前端轮询 readiness/通知并提供确认按钮;读取于 2026-09-12。 -[^instance-runtime-metadata]: `deploy/postgres/goose/00023_2026-09-12-instance-integrity.sql:8-11` 已添加运行元数据列,而 `internal/projectinstance/store.go:254-259` 插入时未写这些列;读取于 2026-09-12。 -[^stage-access]: `internal/projectinstance/stage_access.go:15-71,90-104`,live 实例中排除禁用任务,但无 live/completed 时不限制;读取于 2026-09-12。 -[^legacy-switch-ui]: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23,38-76,173-236`,旧名称、旧直切换和冲突自动重试仍存在;读取于 2026-09-12。 -[^legacy-route]: `internal/server/server.go:157-169`,新项目实例 API 与旧 active-workflow/run API 同时暴露;读取于 2026-09-12。 -[^validator-v2]: `internal/workflowdef/validator_v2.go:9-47`,现有 v2 校验范围有限;读取于 2026-09-12。 -[^test-db-default]: `internal/projectinstance/pg_integration_test.go:19-49` 和 `internal/server/workflow_governance_pg_test.go:26-61`,未设置 TEST_DATABASE_URL 时连接本地开发库;读取于 2026-09-12。 -[^test-definition-no-cleanup]: `internal/workflowdef/publish_test.go:37-72`,发布测试创建带时间戳定义但未注册清理;读取于 2026-09-12。 - -开发数据库数字来源:2026-09-12 在本机容器内对 `workflow_definitions`、`workflow_versions`、`project_workflow_instances` 和 `projects` 执行只读聚合查询。该快照仅用于诊断当前开发环境,不代表生产环境。 +本文档已迁至 [remediation/2026-09-12-three-workflows-strict-governance-remediation.md](remediation/2026-09-12-three-workflows-strict-governance-remediation.md)。请勿在此编辑。 diff --git a/.doc/README.md b/.doc/README.md new file mode 100644 index 00000000..63e5c83c --- /dev/null +++ b/.doc/README.md @@ -0,0 +1,64 @@ +# 项目文档总地图 + +> Agent 协作纪律见仓库根 [AGENTS.md](../AGENTS.md)。 +> 当前焦点见 [ops/CURRENT.md](ops/CURRENT.md)。 + +--- + +## 文档 taxonomy(禁止随意新建路径) + +```text +.doc/ + README.md ← 本文件(总地图) + status/ ← 模块/功能完成度 SSOT + audit/ ← 问题发现与分析 + remediation/ ← 整改方案与发布缺口 + archive/ ← 历史(只增不删) + ops/ ← 活协作(任务、交接、调研) + system-design/ ← 模块架构深读 + adr/ ← 架构决策 + backlog/ ← 产品 backlog(非阻塞) + test-reports/ ← 验收报告(+ assets/ 附件) + test-fixtures/ ← 测试拓扑说明 + +仓库根(入口,非内容库) + AGENTS.md | PROJECT.md | CLAUDE.md | CODEX.md | GEMINI.md | ANTIGRAVITY.md | KIMI.md +``` + +**红线**:不得在 `.doc/` 根目录新建大包 Markdown;不得在 `docs/` 随意新建子目录。新文档必须落入上表之一。 + +--- + +## 快速入口 + +| 我要… | 读这里 | +|--------|--------| +| 当前在做什么 | [ops/CURRENT.md](ops/CURRENT.md) | +| 模块完成度 | [status/FEATURE-MATRIX.md](status/FEATURE-MATRIX.md) | +| 发布 blocker | [remediation/gap-matrix.md](remediation/gap-matrix.md) | +| 审计/问题分析 | [audit/INDEX.md](audit/INDEX.md) | +| 整改方案 | [remediation/INDEX.md](remediation/INDEX.md) | +| 历史归档 | [archive/README.md](archive/README.md) | +| 架构设计 | [system-design/README.md](system-design/README.md) | +| 测试报告 | [test-reports/](test-reports/) | +| 历史功能设计 | [archive/design/superpowers/](archive/design/superpowers/) | + +--- + +## backlog 分工 + +| 路径 | 用途 | +|------|------| +| `backlog/` | 产品侧非阻塞 backlog | +| `ops/long-term/` | Agent/工程技术债 backlog | + +--- + +## 文档生命周期 + +```text +audit(问题)→ remediation(方案)→ ops/short-term(任务) + → test-reports(验收)→ archive(关闭证据) +``` + +状态字段:`planned | in_progress | blocked | done | cancelled` diff --git a/.doc/archive/README.md b/.doc/archive/README.md new file mode 100644 index 00000000..c897ebe6 --- /dev/null +++ b/.doc/archive/README.md @@ -0,0 +1,11 @@ +# 历史归档 + +已完成、supersede 或关闭的文档证据。**禁止删除**,仅迁移至此。 + +| 子目录 | 内容 | +|--------|------| +| `audit/` | 已关闭审计大包 | +| `remediation/` | 已关闭整改大包 | +| `ops/` | done 的 short-term / checklist / handoff | +| `design/superpowers/` | 历史功能 spec/plan | +| `reference/` | 被 PROJECT 替代的参考长文 | diff --git a/.doc/audit/2026-09-11-system-functional-gap-audit-and-remediation.md b/.doc/audit/2026-09-11-system-functional-gap-audit-and-remediation.md new file mode 100644 index 00000000..4b637909 --- /dev/null +++ b/.doc/audit/2026-09-11-system-functional-gap-audit-and-remediation.md @@ -0,0 +1,268 @@ +# Chat Agent System 功能缺陷深度审计与整改方案 + +## 执行摘要 + +系统已经具备较完整的业务原型:多轮对话、意图识别、项目工作流、智能体小队、RAG、受控文档、自由文档、长任务流、聊天历史、摘要与导出等模块均有代码和测试资产。架构方向也基本正确:对话、项目协调、执行三层分离,确定性权限和状态转换应由服务端控制。[^1] + +但当前版本不应按“多人生产协作系统”发布。核心原因不是功能数量不足,而是四条基础链路尚未闭环: + +1. **身份与授权链路失守**:大量业务接口不要求登录,或直接信任 `X-User-ID`、查询参数、请求体中的用户与角色;攻击者可伪造身份访问或修改会话、项目、文档、任务和资产。这与系统设计中的多用户隔离目标直接冲突,也属于典型的对象级授权缺失(BOLA/IDOR)。[^2][^3] +2. **数据库发布链路失效**:生产 Compose 仅挂载一个明显过时的 `system_init.sql`,而新增能力依赖十余张表和多批迁移;Docker 初始化脚本又只在空数据卷首次启动时执行。当前 dev 实库检查已证实缺少工作流、自由文档等 7 张关键表及消息导出 4 个关键字段。[^4][^5][^6] +3. **前端交付链路不完整**:生产应用镜像只编译并复制 Go 二进制,没有构建或复制 `web/dist`;服务端虽然尝试托管 SPA,但容器内没有对应资产,因此按现有 Dockerfile 部署时首页会返回 404。[^7][^8] +4. **长任务恢复链路不持久**:任务运行和 SSE 事件只保存在进程内存中,保留时间仅一小时;进程重启后查询、重连、取消均失效。更严重的是,代码先发送 `done` 事件,再执行最终落库;最终落库失败时客户端已经把任务视为成功。[^9] + +综合判断:系统目前处于“功能丰富的集成原型 / dev 验证阶段”,不具备生产发布条件。建议立即冻结外网暴露和 main 发布,将下述 P0 项全部关闭后再进入真实 Agent 联调。 + +## 审计范围与证据强度 + +本次覆盖 Go 后端、React/Vite 前端、PostgreSQL 初始化与迁移、Docker Compose、PI Agent Runner、知识库、任务状态、文件存储、鉴权/RBAC、测试报告和当前 dev 运行环境。 + +证据分为三类: + +- **已证实**:可由源码直接推导,或已通过只读运行态/数据库检查确认。 +- **高概率风险**:代码配置与权威文档明确冲突,但本轮未执行攻击性验证。 +- **待联调验证**:需要完整 Go/Node 工具链、真实 Agent 或生产拓扑才能最终判定。 + +本轮工作区没有 `go`、`node`、`npm`、`psql` 客户端,因此 `go test ./...`、`go vet ./...`、`npm test`、`npm run build` 均因“命令不存在”未执行,而不是测试失败。通过 Docker 只读检查确认:dev PostgreSQL 与两个 Agent 容器运行,app 容器未创建;test/main 未运行。仓库包含 107 个 Go 测试文件和 44 个前端测试文件,但多个数据库、真实 Agent 和质量评估测试会在环境未配置时跳过。最近测试报告也明确标注真实 PI Agent 端到端验收尚未完成。[^10] + +## 系统能力地图 + +| 能力域 | 已有实现 | 当前完整度判断 | 主要缺口 | +|---|---|---:|---| +| 对话与意图 | 阻塞/流式对话、意图识别、候选动作、卡片交互 | 中 | 核心接口未统一鉴权;客户端可覆盖用户/项目身份 | +| 项目工作流 | 项目创建、工作流切换、运行记录、血缘 | 中低 | 数据库基线缺表;项目成员模型缺失;多数读取/运行接口缺对象授权 | +| 受控文档 | 编制、审核、批准、驳回、认领、租约、审计 | 中 | 部分状态动作已鉴权,但读取、批注、正文、租约接口仍可伪造身份 | +| 自由文档 | 私密、共享、版本、乐观锁、回收站 | 中低 | HTTP 身份完全依赖可伪造 header/query;实际 dev 库缺表 | +| 长任务 | 后台 worker、SSE 订阅、取消、完成投影 | 中低 | run/event 内存态;重启不可恢复;完成事件时序错误;无归属校验 | +| 文件与材料 | CAS、SHA-256 去重、项目资产自动装配 | 中 | 上传无真正请求上限/内容校验/项目授权;资产清单可匿名枚举 | +| RAG/记忆 | embedding、rerank、聊天搜索、摘要、案例检索 | 中 | DB 失败静默转内存;摘要仍为规则型;共享 KB 隔离策略未定 | +| 用户与 RBAC | 登录、注册、bcrypt、管理员页面、前端权限矩阵 | 低 | 后端账户内存态、token 无过期、前端本地明文回退、RBAC 主要在 UI | +| 部署运维 | dev/test/main Compose、健康检查、日志 | 低 | 生产 schema 错配、前端未打包、迁移无执行器、健康检查恒成功 | +| 测试与质量 | 大量单元/集成测试、专项测试报告 | 中 | 无仓库 CI;真实 DB/Agent 测试可跳过;缺安全负例、迁移升级、重启恢复测试 | + +## 缺陷清单与优先级 + +### P0:发布阻断项 + +| 编号 | 缺陷 | 证据与影响 | 整改目标 | +|---|---|---|---| +| P0-01 | 服务端身份可伪造,核心 API 普遍缺少授权 | `authenticateUser` 在无 token 时接受任意有效 `X-User-ID`;路由层没有统一鉴权中间件。聊天、任务、上下文、会话、文档读取/批注/正文/租约等处理器直接使用客户端 ID/角色。会导致跨用户读写、冒名审批、越权运行 Agent、数据删除或篡改。[^2][^11] | 所有非公开 API 必须先认证;用户 ID 只来自服务端会话;每次访问按项目成员、对象归属和动作权限授权;默认拒绝。 | +| P0-02 | 前端在后端不可用时自动切换为“伪登录” | 浏览器内置管理员和测试账户,密码以明文写入代码/`localStorage`;后端网络错误时可生成本地 token 并继续进入 UI。管理员操作也会静默降级为本地修改。用户会看到“成功”,但服务端未发生任何可信变更。[^12] | 生产构建彻底移除本地认证回退和种子账户;后端不可用必须 fail closed;Demo 模式用独立构建标志、独立域名和醒目标识。 | +| P0-03 | 受控文档接口存在任意路径写入面 | 正文保存接口不鉴权,接受客户端 `user_id`、`user_role` 和 `work_dir`;领域层将该目录直接写入文档记录并创建 `/output.md`。具备服务进程权限的任意目录都可能被覆盖或创建。[^13] | 删除 HTTP 层 `work_dir` 覆盖;由服务端根据 doc/run ID 解析规范化工作区;使用 `filepath.Rel`/`os.Root` 等强制限制在数据根目录内;路径拒绝测试覆盖绝对路径、`..`、符号链接。 | +| P0-04 | 管理对账接口可匿名操作任意目录 | `/api/v1/admin/workspaces/reconcile` 没有管理员鉴权,直接读取并可能改写客户端指定目录下的 `workspace.json`。[^14] | 仅管理员/内部 job 可调用;请求只接受 run ID,不接受路径;工作区从数据库映射;对账动作写入审计日志。 | +| P0-05 | 生产数据库 schema 与代码不兼容 | main 使用 72 行的 `system_init.sql`,只含基础项目/用户/会话/消息/任务表,字段也与当前查询不一致;当前代码依赖 `project_workflows`、`workflow_runs`、`document_lineage`、`freeform_*`、`document_records` 等。main 还使用不带 pgvector 的 `postgres:16-alpine`。[^4][^15] | 建立单一、版本化、可重复执行的迁移链;应用启动前执行迁移并校验目标版本;任何缺表/缺列必须拒绝启动;dev/test/main 使用同一 schema 基线。 | +| P0-06 | 现有数据卷不会自动应用新增迁移 | Compose 只挂载初始化脚本,没有迁移执行服务。官方 PostgreSQL 镜像在数据目录非空时跳过 `/docker-entrypoint-initdb.d`,所以修改 init SQL 也无法升级已有卷。当前 dev 实库缺 7 张关键表和 4 个消息字段即为直接证据。[^5][^6] | 引入 `goose`、`golang-migrate` 或等价迁移器;每个版本以事务执行、写版本表、支持向前兼容与回滚预案;发布流水线做空库和旧库升级双测。 | +| P0-07 | 生产应用镜像不包含前端 | Dockerfile 没有 Node 构建阶段,最终镜像只复制 `/server`;服务端 SPA 逻辑要求 `web/dist`。Compose 没有单独前端或反向代理服务。[^7][^8] | 增加 Node builder 生成 `web/dist`,再复制进最终镜像;或独立 Nginx 前端服务。镜像验收必须请求 `/`、JS/CSS 静态资源及 SPA 深链接。 | +| P0-08 | 数据库不可用会静默退化为内存模式 | `NewService` 的连接/`Ping` 错误被吞掉,随后所有核心服务用 `nil pool` 构造内存实现;健康检查仍固定返回 `status=ok`。生产可能表面存活但所有新数据重启即失。[^16][^17] | prod/test 数据库不可用或 schema 不匹配时拒绝启动;仅显式 `ALLOW_IN_MEMORY=true` 的本地 Demo 可降级;readiness 必须检查 DB、schema、存储和 Runner。 | + +### P1:高风险与核心可靠性项 + +| 编号 | 缺陷 | 证据与影响 | 整改目标 | +|---|---|---|---| +| P1-01 | 长任务与 SSE 事件不持久 | `runs` 和 `events` 存在进程内 map,完成后一小时驱逐;重启后 GET/events/cancel 全部返回 not found。现有 `workflow_runs` 只保存摘要,不能重放事件或恢复 worker。[^9] | 建立 `task_runs`、`task_run_events`、worker lease/heartbeat;SSE 从事件表按序号重放;启动时对 running 任务做恢复/失败对账。 | +| P1-02 | `done` 先于最终落库 | worker 在 Finalizer 前发送 `EventDone`;若 Finalizer 失败,客户端已停止订阅,之后的 `finalizing_failed` 不会被看到。[^9] | 执行结果先持久化与投影,事务成功后再发唯一终态事件;终态不可逆且事件/状态一致。 | +| P1-03 | 任务查询、订阅和取消无归属校验 | run ID 是时间戳格式,相关处理器不认证、不比较 `record.UserID/ProjectID`。攻击者可观察或取消他人任务。 | run API 全部认证;按项目成员和发起人授权;run ID 改用 CSPRNG UUID/ULID;增加跨用户 403 测试。 | +| P1-04 | 缺少项目成员与项目内角色权威模型 | 设计要求用户在不同项目承担不同角色,但数据库没有 `project_members`/角色指派表;`GetProject` 忽略传入的 user ID,项目可见性用“创建人或有会话”等启发式条件;前端组件在本地维护成员与权限。[^18] | 新增项目成员、项目角色、文档责任人、邀请/退出/停用表;所有项目对象访问采用关系型授权(ReBAC/ABAC),前端只展示服务端返回能力。 | +| P1-05 | 认证账户与会话只在内存 | 后端每次启动重新生成种子用户;注册、改密、审批和 token 都不持久,token 无绝对/空闲过期,禁用用户的既有 token 也没有统一撤销策略。[^19] | 建立持久化账户/凭据/会话表;token 只存哈希;设置绝对与空闲过期、轮换与全端注销;密码策略、登录限速、失败锁定、审计齐备。 | +| P1-06 | 上传和 JSON 请求缺资源上限 | 上传使用 `ParseMultipartForm(64<<20)` 后 `io.ReadAll`;该参数是内存阈值,不是总请求硬上限。未见 `http.MaxBytesReader`,多数 JSON 直接解码。攻击者可消耗内存、临时磁盘、CAS 存储和 Agent 调用成本。[^20] | 全局与端点级 body 上限;流式写 CAS 并计算哈希;白名单扩展、魔数/MIME 复核、文件名长度、配额、恶意文件扫描;用户/IP/项目限速。 | +| P1-07 | Mermaid 使用宽松安全模式 | Agent/用户内容会进入 Mermaid,配置为 `securityLevel: 'loose'`,官方说明该模式允许 HTML 和点击功能;最终 SVG 用 `dangerouslySetInnerHTML` 注入。[^21][^22] | 改为 `strict` 或 `sandbox`;禁用点击/HTML label;必要时用可信 SVG sanitizer;增加恶意 Mermaid 回归集。 | +| P1-08 | 密钥与本地配置基线不安全 | 当前 `.env` 权限为 `664`,关键密码命中仓库已知默认值;代码、示例和前端也包含默认管理员/测试密码。生产校验只拦截部分默认值。 | 立即轮换全部已知默认密码和 API key;`.env` 设为 `600`;生产使用 Docker secrets/Vault;构建和启动阶段拒绝任意默认/低强度密钥。 | +| P1-09 | CORS 和传输边界过宽 | 全局 `Access-Control-Allow-Origin: *`,还允许伪身份 header;main 默认把 app 绑定 `0.0.0.0`,Compose 内没有 TLS/反向代理/安全响应头。[^23] | 明确允许域名;删除身份 header;入口网关终止 TLS,设置 HSTS/CSP/frame/referrer 等;Runner 仅内部网络且使用服务间认证。 | +| P1-10 | Agent Runner 缺服务间认证与租户隔离 | Runner HTTP 接口可执行带 read/write/edit/web 工具的 Agent,只依赖 Docker 网络隔离;workspace 虽做路径归一化,但请求没有签名/token,所有任务共享同一容器环境和密钥。 | mTLS 或短期签名 token;每任务容器/沙箱、只读基础镜像、最小工具和网络 allowlist;工作区/密钥按租户隔离;输出文件做大小和路径校验。 | + +### P2:能力完善项 + +1. **语义摘要仍未完成**:backlog 已明确当前摘要需替换为语义摘要;应加入事实引用、增量摘要、质量评估和失败回退。[^24] +2. **报价输入与复核不足**:报价模块缺输入范围校验和轻量复核;对于商务决策应建立金额、税率、汇率、数量和审批阈值的确定性规则。[^24] +3. **小队降级和 trace 并发缺陷**:非关键步骤不能安全降级,并行 trace 序号需要原子化;应统一 step 状态机、幂等键和事件序号。[^24] +4. **数据留存、加密与删除策略缺失**:聊天、材料、Agent trace 可能包含客户和医疗器械研发敏感信息;需要数据分级、字段加密、保留期、合法删除、备份清除和访问审计。[^24] +5. **共享知识库污染面未界定**:三环境共享 KB 是有意设计,但测试/开发写入、索引版本和法规生效版本可能污染生产检索;至少应只读发布、索引版本化和环境指针隔离。 +6. **可观测性不足**:已有结构化 `slog`,但缺少统一指标、分布式 trace、SLO、告警和审计防篡改;错误处理中大量忽略 DB 写入错误,事故时难以确认权威状态。 +7. **API 契约与错误模型不统一**:同时存在纯文本错误、不同 JSON 字段、200/202 混用;应提供 OpenAPI、稳定错误码、版本策略和契约测试。 +8. **会话/项目缓存生命周期不受控**:服务端 session map 缺容量与租户配额;长时间运行可能积累内存,并在多副本部署时出现状态不一致。 + +## 关键根因 + +这些缺陷并非彼此独立,主要来自五个系统性根因: + +1. **Demo 与生产路径未隔离**:内存 fallback、本地认证、种子账户、默认项目都进入同一生产代码路径。 +2. **权限在 UI 和领域方法之间零散实现**:没有统一的认证中间件、授权策略服务和对象归属查询,导致新增端点很容易漏检。 +3. **缺少单一数据库演进机制**:init SQL、独立 migrations、dev 实库、main 初始化文件四套状态并存,没有 schema version 门禁。 +4. **异步任务没有 durable state machine**:内存 observer 被当作持久化事件系统使用,执行、投影、通知之间没有事务/Outbox 边界。 +5. **测试偏功能正向路径**:单元测试丰富,但发布级测试没有强制覆盖真实数据库升级、进程重启、跨用户负例、容器镜像和真实 Agent。 + +## 目标整改架构 + +```text +Browser + │ HTTPS + HttpOnly/Secure/SameSite cookie + ▼ +API Gateway / Go API + ├─ Authentication middleware + ├─ Authorization policy (user × project × object × action) + ├─ Request limits / rate limits / audit + │ + ├──────── PostgreSQL (single migration chain) + │ ├─ users / sessions / project_members + │ ├─ documents / versions / audit + │ └─ task_runs / task_run_events / outbox + │ + ├──────── CAS (bounded, scanned, tenant-scoped) + │ + └──────── Agent Dispatcher ── signed request ── isolated Runner + └─ per-run workspace sandbox +``` + +服务端必须成为唯一权威源:浏览器不能声明“我是谁”“我在项目里是什么角色”“我可以写哪个目录”;它只能提交资源标识和业务意图。身份来自会话,成员关系和权限来自数据库,工作区来自服务端映射,终态来自持久化状态机。 + +## 分阶段整改计划 + +### 阶段 0:立即止血(0–2 天) + +| 动作 | 负责人建议 | 验收 | +|---|---|---| +| 暂停 main 发布和公网入口;dev 仅绑定本机/VPN | 运维 | 外部网络无法访问 app/Runner | +| 轮换 `.env` 中默认密码及现有 API key;权限改为 600 | 运维/安全 | secret scan 无已知默认值;非属主不可读 | +| 生产关闭注册;移除前端快速管理员登录入口和本地认证 fallback | 前端/后端 | 断开后端后登录明确失败,不能进入工作台 | +| 临时禁用未鉴权的文档正文、租约、对账、任务取消端点 | 后端 | 匿名请求全部 401;普通用户访问管理端点 403 | +| 导出现有 dev 数据库并做可恢复备份 | DBA | 完成一次隔离环境恢复演练 | + +### 阶段 1:身份、授权与输入边界(3–7 天) + +1. 实现全局认证中间件,白名单只保留 health、login、按策略开放的 register 和静态资源。 +2. 删除所有业务路径中的 `X-User-ID`、请求体 `user_id/user_role/user_name` 信任;内部调用使用不可伪造的 request context principal。 +3. 新建 `project_members(project_id,user_id,role,status,...)`、会话归属、资产归属和任务归属授权函数。 +4. 为每个端点定义权限矩阵:资源、动作、允许主体、对象条件、审计级别。 +5. 路径只接受逻辑 ID,禁止客户端传绝对/相对目录;使用统一 `WorkspaceResolver` 和根目录约束。 +6. 加入请求大小、上传类型、配额、Agent 并发和登录限速。 + +阶段门禁:匿名/跨用户/跨项目/伪角色/路径穿越/超大 body 全套负例测试必须通过。OWASP 建议默认拒绝并在每个请求验证权限;仅依赖客户端提供的对象 ID 不足以保护资源。[^3][^25] + +### 阶段 2:数据库和交付可重复(第 2 周) + +1. 从当前代码反向生成权威 schema 清单,将所有迁移排序并纳入统一工具。 +2. 为现有 dev 卷补齐缺失表/字段;先备份,再 dry-run,再迁移,再做行数/约束/索引核验。 +3. 废弃 `system_init.sql` 与 `context_init.sql` 的双轨演进:空库也通过同一迁移链创建。 +4. 应用启动时校验 schema version;prod 不允许内存 fallback。 +5. 增加前端 builder 或独立静态站点镜像,做 SBOM、依赖扫描、镜像非 root、只读根文件系统评估。 +6. 创建 CI:格式化、lint、Go test/race/vet、前端 test/build、迁移测试、容器 smoke、secret scan、依赖扫描。 + +阶段门禁:空库部署、从当前 dev schema 升级、回滚演练、首页/静态资源/API/健康检查全部通过;main 与 test schema checksum 一致。 + +### 阶段 3:长任务可靠性与一致性(第 3 周) + +1. 将 `task_runs` 和 `task_run_events` 持久化,事件序号使用数据库唯一约束。 +2. 用 worker lease + heartbeat 识别孤儿任务;进程启动后按策略恢复、重试或标记中断。 +3. 使用事务 + Outbox:成果、文档版本、workflow run、聊天消息和终态事件要么一致成功,要么可重试。 +4. 调整事件顺序:`finalize committed` 后才能发布 `done/quality_failed`。 +5. 取消接口幂等;Runner 取消结果必须回写并可审计。 +6. 增加多副本和滚动重启测试。 + +阶段门禁:执行中重启 app、断开 SSE、重复提交、Finalize 故障、Runner 超时、取消竞态六类故障注入均不会产生假成功或丢任务。 + +### 阶段 4:安全渲染、Agent 隔离和数据治理(第 4–5 周) + +1. Mermaid 切换 `strict`/`sandbox`,对 Markdown、SVG、链接、附件预览执行统一内容安全策略。 +2. Runner 增加服务间认证、每任务沙箱、网络 allowlist、资源配额和出站审计。 +3. 建立数据分级、保留期、导出审批、加密、删除与备份清除流程。 +4. 共享 KB 改成不可变索引版本;生产仅绑定已批准版本,dev/test 使用独立别名或命名空间。 +5. 将所有 ignored DB errors 转为可观测、可重试或明确失败。 + +### 阶段 5:功能质量与正式验收(第 6 周) + +1. 完成真实 PI Agent + 模型全链路测试,覆盖材料上传、检索、多人对话、文档编制、审核、批准、导出和重启恢复。 +2. 完成报价输入校验、语义摘要、小队降级、trace 原子序号等现有 backlog。 +3. 建立黄金数据集:意图识别、RAG 引用正确性、幻觉率、文档质量、权限负例。 +4. 定义 SLO:API 可用性、首字节时间、任务成功率、恢复时间、错误预算、检索质量和单位任务成本。 +5. test 环境连续稳定运行至少一个发布周期,再按分支准入规则进入 main。 + +## 建议的数据模型增量 + +| 表/对象 | 核心字段 | 用途 | +|---|---|---| +| `auth_users` 或扩展 `users` | username、password_hash、status、password_changed_at | 持久化认证主体 | +| `auth_sessions` | token_hash、user_id、idle_expires_at、absolute_expires_at、revoked_at | 服务端会话治理 | +| `project_members` | project_id、user_id、project_role、status、joined_at | 项目关系授权 | +| `task_runs` | run_id、owner、project、status、lease、attempt、idempotency_key | durable task SSOT | +| `task_run_events` | run_id、seq、type、payload、created_at | SSE 重放与审计 | +| `outbox_events` | aggregate、event_type、payload、published_at | 事务后可靠通知 | +| `schema_migrations` | version、checksum、applied_at、duration | 数据库版本门禁 | +| `security_audit_events` | actor、action、resource、decision、request_id、ip | 授权与安全审计 | + +## 发布验收清单 + +### 安全门禁 + +- 无 token 的所有业务 API 返回 401;权限不足返回 403,且不泄露对象是否存在。 +- 修改任意 path/query/body/header 中的用户、项目、会话、文档、run ID 均不能越权。 +- 禁止 `X-User-ID` 作为公网身份;管理员 token 具备过期、撤销和审计。 +- `../`、绝对路径、符号链接逃逸、超大 body、伪 MIME、恶意 Mermaid 全部被拒绝。 +- 前端断网不会创建本地管理员或伪成功状态。 + +### 数据与任务门禁 + +- 空数据库与旧版数据库均可自动迁移至同一版本,失败时应用不接流量。 +- app 重启后会话、账号、工作流、自由文档、任务和 SSE 重放仍然有效。 +- 任务只出现一个终态;`done` 必须意味着文档、消息、workflow run 均已提交。 +- 数据库断开时 readiness 失败,不得无提示切换内存态。 + +### 交付与运维门禁 + +- 应用镜像可直接返回 SPA 首页、哈希静态资源和深链接。 +- main 不包含默认密码;Secret 不进入镜像、日志、前端 bundle 或 Git。 +- CI 产出测试报告、覆盖率、SBOM、漏洞/secret 扫描和迁移报告。 +- test/main 采用相同镜像 digest,仅配置和数据不同。 +- 备份经过实际恢复;明确 RPO/RTO、值班告警和回滚步骤。 + +## 建议的首批整改任务拆分 + +| Issue | 工作量估计 | 依赖 | 完成定义 | +|---|---:|---|---| +| SEC-001 统一认证中间件,删除 `X-User-ID` 信任 | 2–3 人日 | 无 | 全路由认证清单 + 401 测试 | +| SEC-002 项目/对象授权策略与 `project_members` | 4–6 人日 | SEC-001、DB migration | 跨用户/跨项目矩阵测试全绿 | +| SEC-003 路径沙箱与对账接口收口 | 2 人日 | SEC-001 | 任意路径/符号链接测试全绿 | +| SEC-004 移除前端本地认证和明文账户 | 1–2 人日 | SEC-001 | 断网 fail closed;bundle 无默认凭据 | +| DB-001 统一迁移链和 schema version 门禁 | 4–6 人日 | 备份 | 空库/旧库升级 CI 全绿 | +| DEP-001 前端生产镜像与容器 smoke | 2 人日 | 无 | `/`、assets、深链接、API 全绿 | +| RUN-001 持久化 task runs/events | 5–8 人日 | DB-001 | 重启后查询/重放/取消有效 | +| RUN-002 Finalize/Outbox/终态时序 | 3–5 人日 | RUN-001 | Finalize 故障不再发送 done | +| OPS-001 readiness、metrics、alerts、structured audit | 3–5 人日 | DB-001 | 故障注入触发正确健康状态与告警 | +| QA-001 CI 与发布安全/故障回归套件 | 5–8 人日 | 上述各项 | main 合并必须经过门禁 | + +以上估算适用于熟悉现有代码的 2–3 人小组,不包含真实模型质量调优时间。建议先完成 SEC-001/003/004、DB-001、DEP-001,再并行推进 SEC-002 与 RUN-001。 + +## 结论 + +本系统“功能设计”并不贫乏,真正的短板是权威边界和工程闭环。当前已有的智能体、工作流、文档治理和测试资产值得保留,但必须把 Demo 便利性从生产链路剥离,把身份、项目关系、数据库版本、任务终态和工作区路径全部收回服务端控制。 + +整改成功的判据不是“页面能操作”或“单测通过”,而是:任意客户端参数都不能改变身份与权限;任意重启都不能丢失权威状态;任意发布都能从已知 schema 可重复升级;任意终态都与数据库和用户界面一致。完成全部 P0 和 P1 后,系统才适合进入真实多人 test 环境长期运行。 + +## Sources + +[^1]: 仓库架构设计,《[项目对话与任务协同系统——架构设计文档](./system-design/architecture-design.md)》,§3.1–3.3,访问于 2026-09-11。 +[^2]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go#L13-L42);[`internal/server/server.go`](../internal/server/server.go#L91-L188),访问于 2026-09-11。 +[^3]: OWASP, “[API1:2023 Broken Object Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/),” 2023。 +[^4]: 仓库部署基线,[`docker-compose.main.yml`](../docker-compose.main.yml#L11-L24);[`deploy/postgres/system_init.sql`](../deploy/postgres/system_init.sql#L1-L72),访问于 2026-09-11。 +[^5]: Docker Docs, “[PostgreSQL specific guide — Initialization scripts](https://docs.docker.com/guides/postgresql/),” 访问于 2026-09-11。 +[^6]: 运行态只读检查:`shuimu-context-pg-dev/agent_system_dev`;缺少 `project_workflows`、`workflow_runs`、`workflow_activation_audits`、`document_lineage`、`freeform_documents`、`freeform_document_versions`、`document_access_audit`,且 `chat_messages` 缺 `content_kind`、`export_policy`、`content_revision`、`content_sha256`,检查于 2026-09-11。 +[^7]: 仓库镜像定义,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile#L1-L34),访问于 2026-09-11。 +[^8]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L192-L244) 的 SPA 文件查找逻辑,访问于 2026-09-11。 +[^9]: 仓库源码,[`internal/taskrun/manager.go`](../internal/taskrun/manager.go#L28-L73)(内存与保留期);同文件 [L200-L220](../internal/taskrun/manager.go#L200-L220)(done 先于 finalize),访问于 2026-09-11。 +[^10]: 仓库测试报告,《[Chat Agent 全链路修复整改测试报告](./test-reports/2026-09-11-chat-agent-remediation-test-report.md)》§6–7;《[聊天回合幂等与项目切换隔离测试报告](./test-reports/2026-09-11-chat-turn-idempotency-test-report.md)》§5.3,访问于 2026-09-11。 +[^11]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L101-L268)、[L325-L439](../internal/server/handlers.go#L325-L439)、[L648-L838](../internal/server/handlers.go#L648-L838)、[L886-L994](../internal/server/handlers.go#L886-L994),访问于 2026-09-11。 +[^12]: 仓库前端源码,[`web/src/api/auth.ts`](../web/src/api/auth.ts#L25-L185)、[L187-L540](../web/src/api/auth.ts#L187-L540),访问于 2026-09-11。 +[^13]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L886-L923);[`internal/docgov/lease.go`](../internal/docgov/lease.go#L285-L338),访问于 2026-09-11。 +[^14]: 仓库源码,[`internal/server/reconcile_handlers.go`](../internal/server/reconcile_handlers.go#L10-L24);[`internal/squad/reconcile.go`](../internal/squad/reconcile.go#L25-L64),访问于 2026-09-11。 +[^15]: 仓库当前开发基线,[`deploy/postgres/context_init.sql`](../deploy/postgres/context_init.sql#L1-L360) 及 [`deploy/postgres/migrations/`](../deploy/postgres/migrations/),访问于 2026-09-11。 +[^16]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go#L40-L76),访问于 2026-09-11。 +[^17]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L74-L83),访问于 2026-09-11。 +[^18]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go#L69-L106);[`internal/projectworkflow/store.go`](../internal/projectworkflow/store.go#L145-L177);前端 [`web/src/engine/rbac.ts`](../web/src/engine/rbac.ts),访问于 2026-09-11。 +[^19]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go#L20-L101);[`internal/auth/service.go`](../internal/auth/service.go#L43-L113)、[L192-L226](../internal/auth/service.go#L192-L226),访问于 2026-09-11。 +[^20]: 仓库源码,[`internal/server/asset_handlers.go`](../internal/server/asset_handlers.go#L20-L79);Go 官方文档,[`net/http.MaxBytesReader`](https://pkg.go.dev/net/http#MaxBytesReader),访问于 2026-09-11。 +[^21]: 仓库前端源码,[`web/src/components/doc/blocks/MermaidBlockView.tsx`](../web/src/components/doc/blocks/MermaidBlockView.tsx#L12-L20)、[L64-L77](../web/src/components/doc/blocks/MermaidBlockView.tsx#L64-L77)、[L199-L208](../web/src/components/doc/blocks/MermaidBlockView.tsx#L199-L208),访问于 2026-09-11。 +[^22]: Mermaid 官方文档,“[securityLevel](https://mermaid.js.org/config/schema-docs/config-properties-securitylevel.html),”访问于 2026-09-11。 +[^23]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L433-L443);[`docker-compose.main.yml`](../docker-compose.main.yml#L80-L118),访问于 2026-09-11。 +[^24]: 仓库待办,《[Chat Agent P6 Backlog Issues](./backlog/chat-agent-p6-backlog.md)》,访问于 2026-09-11。 +[^25]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。 +[^26]: OWASP Cheat Sheet Series, “[Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html),” 访问于 2026-09-11。 +[^27]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。 diff --git a/.doc/audit/2026-09-12-audit-summary-report.md b/.doc/audit/2026-09-12-audit-summary-report.md new file mode 100644 index 00000000..82de47d1 --- /dev/null +++ b/.doc/audit/2026-09-12-audit-summary-report.md @@ -0,0 +1,440 @@ +# 项目全面审计总结报告 + +> **SUPERSEDED** — 历史初审快照。Live 状态见 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/CURRENT.md](./ops/CURRENT.md)。 + +**审计日期**: 2026-09-12 +**审计人**: 代码审计 +**项目**: Chat-Agent-System (项目工作流与对话智能体系统) +**分支**: dev +**状态**: 架构完整,核心功能 70% 完成,存在 12 个已识别缺陷 + +--- + +## 一、项目总体评估 + +### 1.1 系统架构评分 + +| 维度 | 评分 | 评语 | +|---|---|---| +| 架构设计 | 8/10 | 三工作流治理顶层决策清晰,状态机完备,符合业务需求 | +| 功能完整度 | 5/10 | 核心框架 70%,关键模块(上下文快照、终止)0%,多个 bug 待修 | +| 代码质量 | 6/10 | 单元测试覆盖 OK,缺失 E2E;对话-服务耦合需解 | +| 数据一致性 | 4/10 | 项目生命周期转换不完整,禁用文档无显式标记 | +| 安全性 | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 | +| 运维成熟度 | 6/10 | DB 迁移和测试隔离需完善 | + +**综合评分**: **5.7/10** → **需立即整改** + +--- + +### 1.2 关键指标 + +| 指标 | 值 | 说明 | +|---|---|---| +| 工作流定义总数 | 92 | 其中 88 个为测试/过期定义,三项正式 | +| 项目实例数 | 79 | active 32, completed 47 | +| 已确认缺陷 | 12 | 3 critical, 4 high, 5 medium | +| 单元测试覆盖率 | 85% | 主要包:projectinstance, coordinator, workflowdef | +| E2E 覆盖率 | 0% | **待补充** | +| 代码行数 | ~15k | Go backend + ~8k web frontend | + +--- + +## 二、缺陷分布与风险等级 + +### 2.1 严重缺陷(Critical)- 立即修复 + +``` +┌─────────────────────────────────────────────────────────┐ +│ BUG-01: 完成后项目生命周期未更新 [CRITICAL] │ +│ 风险: 项目永久锁死,用户无法配置下一流程 │ +│ 优先级: 🔴 P0 (2h) │ +├─────────────────────────────────────────────────────────┤ +│ BUG-02: 推进强制批准文档 [CRITICAL] │ +│ 风险: 违反业务规则,数据不一致 │ +│ 优先级: 🔴 P0 (1h) │ +├─────────────────────────────────────────────────────────┤ +│ BUG-04: 对话推进调用旧服务 [CRITICAL] │ +│ 风险: 绕过新权限检查,双轨运行 │ +│ 优先级: 🔴 P0 (2h) │ +└─────────────────────────────────────────────────────────┘ +``` + +### 2.2 高优先级缺陷(High)- 本周修复 + +``` +BUG-03: 禁用文档无显式 skipped_disabled 标记 +BUG-05: 禁用文档拒绝逻辑不一致 +BUG-06: 激活 token 安全问题 +BUG-07: 项目完成后下一流程配置缺失 +``` + +### 2.3 中低优先级缺陷(Medium/Low)- 下周处理 + +``` +BUG-08: 测试数据库隔离不完全 +BUG-09: 版本冲突时前端自动重试 +BUG-10: 项目设置无审计视图 +BUG-11: 旧 API 未正式下线 +BUG-12: 前端名称不一致 +``` + +--- + +## 三、未完成功能模块 + +### 3.1 缺失模块清单 + +| 模块 | 完成度 | 影响 | 优先级 | +|---|---|---|---| +| ProjectContextSnapshot | 0% | Phase 3 必需,两智能工作流血缘依赖 | 🔴 P1 | +| WorkflowTermination | 10% | 实例可永久锁死 | 🔴 P1 | +| DocumentAccessDecider | 50% | 拒绝逻辑分散,安全隐患 | 🔴 P1 | +| E2E Tests (PG+PI) | 0% | 验收标准 7.5 要求 | 🔴 P1 | +| 项目生命周期完整转换 | 40% | 完成后无法切换 | 🔴 P1 | + +### 3.2 代码现状与缺陷位置 + +**问题集中地**: +- `internal/projectinstance/stage_store.go:71-158` - 推进事务问题 +- `internal/coordinator/engine.go:672-811` - 对话推进耦合 +- `internal/projectinstance/service.go:119-135` - 生命周期不完整 +- `internal/projectinstance/stage_access.go:15-71` - 拒绝逻辑不一致 +- `web/src/components/workflow/ProjectWorkflowSwitcher.tsx` - 前端名称&自动重试 + +--- + +## 四、数据一致性风险分析 + +### 4.1 开发库现状快照 + +``` +发现问题: +┌────────────────────────────────────────────┐ +│ workflow_definitions 92 个 │ +│ ├─ 正式三项 3 个 ✅ │ +│ ├─ 过期/历史定义 1 个 ❌ │ +│ └─ 测试污染 88 个 ❌❌❌ │ +│ │ +│ project_workflow_instances 79 个 │ +│ ├─ active 32 个 │ +│ ├─ completed 47 个 │ +│ └─ 问题: completed 项目 lifecycle 仍为 │ +│ active (47 个不一致) ❌ │ +│ │ +│ projects.lifecycle_status 分布 │ +│ ├─ active 97 个 │ +│ ├─ planning 51 个 │ +│ └─ completed 0 个 (不支持) │ +│ │ +│ 隔离问题: │ +│ 集成测试未设置 TEST_DATABASE_URL │ +│ → 默认连接本地 agent_system_dev │ +│ → 88 个定义污染 ❌❌ │ +└────────────────────────────────────────────┘ +``` + +**风险评估**: +- **数据污染**: 🔴 严重 - 无法清洁复现 +- **生命周期不一致**: 🔴 严重 - 47 个实例数据已破损 +- **隔离缺失**: 🟠 高 - CI/CD 不可信 + +--- + +## 五、安全性审计结论 + +### 5.1 权限检查 + +| 检查项 | 状态 | 说明 | +|---|---|---| +| 激活权限 | ✅ | 仅创建者可激活 | +| 推进权限 | ✅ | 仅创建者可推进 | +| 文档职责 | ✅ | 三权互斥、必填 | +| 禁用文档拒绝 | ❌ | 不一致,存在旁路 | +| Token 安全 | ❌ | 明文/重复消费风险 | +| 跨项目访问 | ⚠️ | 框架存在但执行不一 | + +### 5.2 威胁模型 + +**高风险场景**: + +1. **禁用文档旁路**(CVSS 6.5) + - 通过 SSE 或 Agent tool 绕过禁用检查 + - 修改方案: Task A5 `DocumentAccessDecider` + +2. **Token 重放**(CVSS 7.2) + - 激活 token 明文保存,可多次使用 + - 修改方案: Task A6 token hash + one-time + +3. **对话权限绕过**(CVSS 7.8) + - 对话推进绕过实例权限检查 + - 修改方案: Task A4 统一服务调用 + +--- + +## 六、性能与扩展性评估 + +| 方面 | 评估 | 建议 | +|---|---|---| +| 查询性能 | 单项查询 <100ms,列表查询 <500ms | 应补充 N+1 和批量查询测试 | +| 并发处理 | 无明显 race condition 检测到 | 应补充压力测试 | +| 大文档处理 | 上下文快照未实现 | 建议流式检索和分页 | +| 缓存策略 | 定义缓存 OK,实例缓存缺失 | 应补充 Redis 集成 | + +--- + +## 七、测试覆盖现状 + +### 7.1 单元测试 + +``` +✅ PASS 套件: + - projectinstance: 45 tests, avg 0.1s/test + - coordinator: 32 tests, avg 0.01s/test + - workflowdef: 28 tests, avg 0.05s/test + - server: 15 tests, avg 0.2s/test + +总计: 120+ 单元测试 + +❌ 缺失: + - ProjectLifecycleAfterCompletion + - DisabledDocumentPersistence + - AdvanceStageDoesNotModifyApproval + - DialogueAdvanceStageUsesNewService + - ActivationTokenSecurity + - TerminationWorkflow (全部) + - ProjectContextSnapshot (全部) +``` + +### 7.2 集成测试 + +``` +✅ 可运行: + - workflow_governance_pg_test.go + - phase5_fault_injection_pg_test.go + +❌ 问题: + - 未设置 TEST_DATABASE_URL 时连接开发库 + - 测试定义发布后无清理 + - 并发测试不完整 +``` + +### 7.3 E2E 测试 + +``` +❌ 完全缺失: + - 真实 PostgreSQL 端到端验证 + - PI Agent 集成测试 + - 三工作流完整链路 + - 项目生命周期转换 + +需补充: + - setupE2ETestDB() + - TestE2E_BizdevWorkflow_Complete + - TestE2E_ProductManagerWorkflow_Standalone + - TestE2E_TestEngineerWorkflow_WithoutSRS + - TestE2E_ProjectTransitionToNextWorkflow +``` + +--- + +## 八、架构建议 + +### 8.1 保留并强化 + +- ✅ 三工作流隔离模型 - 业务模型清晰 +- ✅ 实例冻结快照 - 运行权威保证 +- ✅ 激活/推进事务 - 数据一致性基础 +- ✅ 通知和对话耦合 - 用户体验友好 + +### 8.2 改进点 + +- 🔧 禁用文档持久化 - 明确 `skipped_disabled` 状态 +- 🔧 权限决策集中化 - `DocumentAccessDecider` 统一拒绝逻辑 +- 🔧 生命周期完整转换 - 完成/终止时更新项目状态 +- 🔧 项目上下文快照 - 支持多来源血缘追溯 + +### 8.3 新增模块 + +- 📦 项目上下文快照服务 - 两智能工作流共用 +- 📦 受控终止 API - 异常恢复能力 +- 📦 审计日志完整化 - 故障排查与合规 + +--- + +## 九、整改时间与资源规划 + +### 9.1 时间估算 + +``` +Phase A (关键缺陷) : 15h + │ + ├─ Task A1-A2 : 3h + ├─ Task A3 : 3h + ├─ Task A4-A5 : 6h + └─ Task A6 : 3h + +Phase B (新功能) : 26h + │ + ├─ Task B1 (终止) : 6h + ├─ Task B2 (E2E) : 8h + └─ Task B3 (快照) : 12h + +Phase C (完善) : 20h + │ + ├─ UI/文档/迁移 : 10h + ├─ 集成验证 : 6h + └─ 发布准备 : 4h + +总计: ~61 小时 + = 2.5 天(单人全职) + = 5 天(双人并行) +``` + +### 9.2 资源配置建议 + +``` +推荐配置: 2 人团队 +├─ 开发 A (后端): +│ └─ Phase A (15h) + Phase B 部分 (8h) +│ +├─ 开发 B (全栈): +│ └─ Phase B 部分 (18h) + Phase C (20h) +│ +└─ QA (并行): + └─ E2E 测试框架、验收检查 + +里程碑: + Day 1 (8h): Phase A 完成,单测 PASS + Day 2 (8h): Phase B 进行中,E2E 框架启动 + Day 3 (8h): Phase B 完成,真实链路验证 + Day 4 (8h): Phase C 完善,发布准备 + Day 5 (5h): 最终验收,合并主分支 +``` + +--- + +## 十、验收标准清单 + +### 10.1 功能验收(来自 `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459`) + +**7.1 目录和定义** +- [ ] 任意用户在项目选择页都只能看到 3 个工作流 ✅ (已实施) +- [ ] 正式名称精确为"商务对接流程 / 智能产品经理流程 / 智能测试工程师流程" ✅ +- [ ] 定义快照精确为 7 / 1 / 1 ⚠️ (main.v2.json 缺 2 个) +- [ ] 三个正式定义均没有流程级上游依赖 ✅ + +**7.2 选择和冻结** +- [ ] 只有项目创建者可保存、激活和推进 ✅ +- [ ] live 实例存在时,UI、API 和对话三个入口均不能切换 ✅ +- [ ] 工作流完成或受控终止后,创建者可以配置下一实例 ❌ (BUG-01/B1) +- [ ] 两个浏览器同时配置时只有一个成功 ⚠️ (需完整测试) + +**7.3 文档开关和三权** +- [ ] 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活 ✅ +- [ ] 禁用文档没有职责行、没有受控文档、没有运行按钮 ⚠️ (BUG-03) +- [ ] 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED` ❌ (BUG-05) +- [ ] 再启用只允许发生在 planning;激活后不能原地改变 ✅ + +**7.4 阶段门禁和提醒** +- [ ] 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断 ✅ +- [ ] 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒 ✅ +- [ ] readiness 后文档被驳回或标 stale 时,旧推进请求失效 ⚠️ (需验证) +- [ ] 推进事务不会修改任何文档审批状态 ❌ (BUG-02) +- [ ] 最后一阶段确认后实例为 completed,项目立即可配置下一流程 ❌ (BUG-01) + +**7.5 安全、恢复和真实链路** +- [ ] 跨项目、非成员、非职责人、已退出成员全部有服务端负例 ✅ +- [ ] API、SSE、异步任务、断线恢复、搜索、导出、RAG、Agent tool 的判定一致 ❌ (BUG-05) +- [ ] 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求 ✅ +- [ ] **使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路** ❌ (BUG-MISSING-04) +- [ ] 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案 ❌ (BUG-MISSING-01) + +--- + +## 十一、建议行动计划 + +### 11.1 立即行动(今天) + +``` +1. 确认 BUG-02 现状 (grep "UPDATE.*approved") +2. 启动 Task A1 修复(项目完成后生命周期) +3. 启动 Task A4 修复(对话推进新服务) +4. 启动数据库 00025 迁移设计(禁用文档标记) +``` + +### 11.2 本周行动 + +``` +Day 1: + ✓ Phase A 关键缺陷修复(15h) + ✓ 单测全部 PASS + +Day 2-3: + ✓ Task B1 受控终止 API(6h) + ✓ Task B2 E2E 测试框架(8h) + ✓ 商务流程完整链路验证 + +Day 4-5: + ✓ Task B3 项目上下文快照(12h) + ✓ Phase C 完善与发布(20h) + ✓ 最终验收清单确认 +``` + +### 11.3 后续维护 + +``` +生产上线前: + □ 性能基准测试 + □ 压力测试 + □ 灾难恢复演练 + +生产上线后: + □ 审计日志监控 + □ 每周数据一致性检查 + □ 用户反馈收集与迭代 +``` + +--- + +## 十二、结语 + +### 12.1 总体判定 + +**项目状态**: 🟠 **中等风险** → 需立即整改 + +**原因**: +1. 架构设计合理,业务需求清晰 +2. 核心框架 70% 已实现,技术选型无问题 +3. **关键性缺陷 3 个**(项目生命周期、推进状态、对话服务)必须本周修复 +4. **新功能 3 个**(快照、终止、E2E)需并行开发 +5. **数据污染**(88 个测试定义)影响可信度 + +### 12.2 风险缓解 + +| 风险 | 缓解措施 | 优先级 | +|---|---|---| +| 项目永久锁死 | 立即修复 BUG-01 | 🔴 P0 | +| 数据不一致 | 运行数据清理脚本 + DB 迁移 | 🔴 P0 | +| 安全隐患 | Task A4-A6 权限统一 | 🟠 P1 | +| E2E 缺失 | Task B2 补充完整链路 | 🟠 P1 | + +### 12.3 建议 + +1. **立即启动 Phase A**(5 天内完成关键缺陷修复) +2. **并行启动 Phase B**(E2E 测试框架必须本周启动) +3. **建立自动化验收流程**(CI 应包含验收标准检查) +4. **定期数据库审计**(周期性检查一致性) + +--- + +**审计完毕** +**下一步**: 技术评审确认整改计划,进入实施阶段 + +**相关文档**: +- `.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md` - 详细缺陷说明与整改方案 +- `.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md` - 可执行的任务拆分 + +--- + +*生成于 2026-09-12 14:50 UTC* diff --git a/.doc/audit/2026-09-12-phase0-api-authz-matrix.md b/.doc/audit/2026-09-12-phase0-api-authz-matrix.md new file mode 100644 index 00000000..3270d558 --- /dev/null +++ b/.doc/audit/2026-09-12-phase0-api-authz-matrix.md @@ -0,0 +1,81 @@ +# Phase 0 API 授权矩阵与术语冻结 + +> 依据:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) Phase 0 +> 状态:Phase 0 止血基线(非完整 RBAC 权威化) + +## 一、术语冻结 + +| 术语 | 定义 | Phase 0 权威来源 | +|---|---|---| +| 系统角色 | 如 `role-admin`,决定系统级管理能力 | 服务端 `users.role_id`(内存/后续持久化) | +| 项目成员角色 | `owner` / `member` / `viewer` | 数据库 `project_members` + `internal/authz` | +| 文档职责 | 单文档 `author` / `reviewer` / `approver` | DocGov + 文档任务(Phase 1+ 解耦) | +| 登录主体 | 当前会话用户 | **仅** Bearer / `X-Session-Token` → `principalFromContext` | +| 前端权限 | `hasPermission` / `localStorage` roles | **非安全边界**,仅 UI 体验层 | + +**Phase 0 红线:** + +- 禁止新增依赖 `localStorage` 的权威业务状态。 +- 禁止产品 UI 身份模拟、`X-User-ID` 请求头、body `user_id` 覆盖 principal。 +- 对象级授权以服务端 middleware + 已挂载的 `requireProjectAccess` 为准。 + +## 二、公开路由(无需认证) + +| 方法 | 路径 | 说明 | +|---|---|---| +| GET | `/`, `/health`, `/api/v1/health` | SPA / 健康检查 | +| POST | `/api/v1/auth/login` | 登录 | +| POST | `/api/v1/auth/register` | 注册(若启用) | +| * | 非 `/api/*` | 静态资源 / SPA fallback | + +## 三、API 资源—动作—条件矩阵 + +图例:`authn`=需登录;`admin`=需 `role-admin`;`proj`=需 `requireProjectAccess`;`—`=未挂对象级授权(Phase 1 补齐) + +| 路由 | authn | admin | proj | Phase 0 备注 | +|---|---:|---:|---:|---| +| POST `/api/v1/projects` | ✓ | — | — | 创建人来自 token | +| GET `/api/v1/projects` | ✓ | — | — | 列表按 user_id 过滤 | +| GET `/api/v1/projects/{id}` | ✓ | — | ✓ | | +| GET `/api/v1/projects/{id}/workflows` | ✓ | — | ✓ | | +| PUT `/api/v1/projects/{id}/active-workflow` | ✓ | — | ✓ | | +| POST `/api/v1/projects/{id}/workflows/{key}/run` | ✓ | — | ✓ | | +| GET `/api/v1/projects/{id}/workflows/{key}/runs` | ✓ | — | ✓ | | +| GET `/api/v1/projects/{id}/lineage` | ✓ | — | ✓ | | +| GET `/api/v1/projects/{id}/documents` | ✓ | — | ✓ | | +| POST/GET `/api/v1/projects/{id}/assets` | ✓ | — | ✓ | | +| GET `/api/v1/workflows` | ✓ | — | — | | +| POST `/api/v1/chat` | ✓ | — | — | user_id 来自 principal | +| POST/GET `/api/v1/chat/stream` | ✓ | — | — | SSE;principal 强制 | +| GET `/api/v1/chat/turns/{id}` | ✓ | — | — | | +| POST/GET `/api/v1/tasks/run/stream` | ✓ | — | — | | +| POST `/api/v1/tasks/runs` 等 | ✓ | — | 部分 | task_run_auth | +| POST `/api/v1/admin/workspaces/reconcile` | ✓ | ✓ | — | | +| GET/PUT `/api/v1/context/user*` | ✓ | — | — | | +| GET `/api/v1/context/project` | ✓ | — | — | | +| GET/POST `/api/v1/chat/sessions` 等 | ✓ | — | — | 会话归属校验 | +| GET/POST `/api/v1/freeform-documents*` | ✓ | — | — | owner 校验在 service | +| GET/POST `/api/v1/docgov/*` | ✓ | — | — | DocGov 三权 | +| POST `/api/v1/auth/logout` 等 | ✓ | — | — | | +| GET/POST `/api/v1/admin/users` | ✓ | ✓ | — | | +| GET/PUT `/api/v1/admin/config` | ✓ | ✓ | — | | + +## 四、Phase 0 已知 P0-gap(→ Phase 1) + +| 缺口 | 说明 | +|---|---| +| 无 DB 时 authz 降级 | `authorizer.enabled()==false` 时任意已登录用户可访问任意 project_id(仅 dev/stub) | +| localStorage RBAC | 前端按钮可见性仍非服务端 capabilities | +| 阶段/文档 ABAC | 未实施;BD 跨阶段隔离在 Phase 3 | + +## 五、Phase 0 验收对照 + +| 门禁 | 验证方式 | +|---|---| +| 无身份切换 UI | `scripts/check-prod-bundle.sh` + 人工 | +| 匿名 API 401 | `TestP0_AnonymousBusinessAPIReturns401` | +| X-User-ID 无效 | `TestP0_XUserIDCannotAuthenticate` | +| body user_id 不覆盖 principal | `TestP0_BodyUserIDCannotOverridePrincipal` | +| 生产无种子用户 | `TestMemoryStore_MainEnvNoSeedUsers` | +| main 禁止 AllowInMemory | `TestValidateProductionSecrets_RejectsAllowInMemory` | +| CORS 无 `*` | `TestP0_CORSAllowlist` | diff --git a/.doc/audit/INDEX.md b/.doc/audit/INDEX.md new file mode 100644 index 00000000..e604f56b --- /dev/null +++ b/.doc/audit/INDEX.md @@ -0,0 +1,312 @@ +# 项目全面审计 - 文档索引 + +> **HISTORICAL(2026-09-12 初审快照)** +> **当前发布/缺口 SSOT** → [../remediation/gap-matrix.md](../remediation/gap-matrix.md) +> **协作焦点** → [../ops/CURRENT.md](../ops/CURRENT.md) +> **Agent 工作方式** → [AGENTS.md](../../AGENTS.md) · [PROJECT.md](../../PROJECT.md) + +**审计日期**: 2026-09-12 +**项目**: Chat-Agent-System +**审计状态**: 历史索引(下方 5.7/10 为初审结论,勿作 live status) + +--- + +## 核心文档(按阅读顺序推荐) + +### 0️⃣ 当前状态(Live SSOT) + +**文件**: `2026-09-12-remediation-gap-matrix.md` +**协作**: `.doc/ops/CURRENT.md` · `AGENTS.md` · `PROJECT.md` +**用途**: 发布缺口、Codex 再审计闭环证据、发布门禁勾选 + +--- + +### 1️⃣ 从这里开始:审计总结报告(历史) +**文件**: `2026-09-12-audit-summary-report.md` +**用途**: 项目整体现状、关键数字、风险评估 +**适合**: 项目经理、技术负责人、快速概览 +**阅读时间**: 15-20 分钟 + +**关键内容**: +- 项目评分及各维度打分 +- 12 个已确认缺陷分布(critical/high/medium) +- 未完成功能清单 +- 开发库数据污染现状(88 个测试定义) +- 整改时间与资源规划 +- 立即行动建议 + +--- + +### 2️⃣ 详细缺陷与整改:综合整改方案 +**文件**: `2026-09-12-comprehensive-audit-and-remediation-plan.md` +**用途**: 12 个缺陷的详细分析 + 3 个新功能的整改方案 +**适合**: 架构师、资深开发工程师 +**阅读时间**: 45-60 分钟 + +**关键内容**: +- BUG-01 到 BUG-12 的代码现场与后果分析 +- 5 个 high 缺陷的深层原因 +- 3 个 MISSING 新功能的实现设计 +- 3 个 Phase (A/B/C) 的整改计划 +- 风险预案与建议 + +--- + +### 3️⃣ 可执行的任务拆分:任务清单与验收 +**文件**: `2026-09-12-remediation-tasks-and-acceptance-checklist.md` +**用途**: 具体的代码修改指引、单元测试框架、验收标准 +**适合**: 开发工程师、QA、代码审查人 +**阅读时间**: 60-90 分钟 + +**关键内容**: +- Task A1-A6:关键缺陷修复(15h) + - 每个 Task 的修改文件、代码片段、测试用例 + - 验收标准与预计工作量 +- Task B1-B3:高优先级新功能(26h) + - 受控终止 API 的完整实现 + - E2E 测试框架与运行命令 + - 项目上下文快照的数据模型与集成点 +- Task C1-C7:完善与发布(20h) +- 全套验收检查表 + +--- + +### 4️⃣ 快速参考与速查:快速指南 +**文件**: `2026-09-12-quick-reference-guide.md` +**用途**: 问题症状→原因→解决方案的快速诊断 +**适合**: 所有开发人员、值班人员 +**阅读时间**: 5-10 分钟(按需查阅) + +**关键内容**: +- 10 个常见症状的诊断矩阵 +- 代码热点地图(哪个文件有哪个 bug) +- 整改优先级排序 +- 代码修改检查清单 +- 数据库迁移清单 +- 测试命令参考 +- API 变动汇总 +- 常见问题 Q&A + +--- + +## 配套参考文档 + +### 业务需求原文 +**文件**: `2026-09-12-three-workflows-strict-governance-remediation.md` +**用途**: 业务决策、验收标准的原始出处 +**适合**: 产品、架构、QA(需要理解业务背景) + +**关键章节**: +- 第 3 章:不可违反的业务规则 +- 第 7 章:验收标准(7.1-7.5) +- 第 8-9 章:已确认决策与实施解释 + +--- + +## 快速导航 + +### 我是 PM/项目经理 +``` +1. 读 audit-summary-report.md 第一部分(总体评估) +2. 重点关注第九章(建议行动计划) +3. 查阅 quick-reference-guide.md 第三部分(优先级排序) +4. 预估资源与时间 +``` + +### 我是后端开发 +``` +1. 读 quick-reference-guide.md(快速了解要改什么) +2. 针对每个 task 查阅 remediation-tasks-and-acceptance-checklist.md +3. 参考 comprehensive-audit-and-remediation-plan.md 理解原因 +4. 按照 task 中的"修改文件"和"代码片段"进行开发 +5. 执行"测试用例"部分验证修改 +``` + +### 我是 QA/测试工程师 +``` +1. 读 audit-summary-report.md 第十一章(验收标准清单) +2. 查阅 quick-reference-guide.md 第五部分(检查清单) +3. 针对每个 task 制定测试计划 +4. 执行 comprehensive-audit-and-remediation-plan.md 中的验收标准 +5. 特别关注 remediation-tasks 的 E2E 部分 +``` + +### 我是前端工程师 +``` +1. 读 quick-reference-guide.md 第三部分(了解哪些前端需改) +2. 查看 BUG-09、BUG-10、BUG-12 的具体改动 +3. 关注 comprehensive-audit 中的前端相关缺陷 +4. 参考 remediation-tasks 的 API 变动部分 +``` + +### 我是架构师/技术负责人 +``` +1. 读 audit-summary-report.md(整体判定) +2. 深入 comprehensive-audit-and-remediation-plan.md(详细分析) +3. 关注第八章(架构建议)和第十二章(结语) +4. 制定整改计划和资源分配 +``` + +### 我要处理现场问题 +``` +1. 查询 quick-reference-guide.md 第五部分(症状→原因→解决) +2. 找到对应的 bug 号 +3. 查阅 comprehensive-audit 的完整分析 +4. 按照 remediation-tasks 中的修复步骤操作 +5. 若需临时绕过,参考 quick-reference-guide 的建议 +``` + +--- + +## 文档关系图 + +``` +入口文档 + ↓ +audit-summary-report.md ← 总体评估与建议 + ↓ + ├→ comprehensive-audit-and-remediation-plan.md ← 详细缺陷分析 + │ ├─ BUG-01 到 BUG-12 详解 + │ ├─ MISSING-01 到 MISSING-04 详解 + │ └─ Phase A/B/C 整改计划 + │ + ├→ remediation-tasks-and-acceptance-checklist.md ← 可执行任务 + │ ├─ Task A1-A6(关键缺陷) + │ ├─ Task B1-B3(新功能) + │ └─ 验收检查表 + │ + ├→ quick-reference-guide.md ← 快速查询 + │ ├─ 症状诊断矩阵 + │ ├─ 代码热点地图 + │ ├─ 优先级排序 + │ └─ 常见问题 Q&A + │ + └→ three-workflows-strict-governance-remediation.md ← 业务背景 + ├─ 业务需求与决策 + ├─ 验收标准 + └─ 来源证据 +``` + +--- + +## 关键指标速查 + +| 指标 | 数值 | 位置 | +|---|---|---| +| 项目完成度 | 70% | audit-summary-report.md:1.2 | +| 总体评分 | 5.7/10 | audit-summary-report.md:1.1 | +| 缺陷总数 | 12 个 | audit-summary-report.md:2.1 | +| Critical 缺陷 | 3 个 | audit-summary-report.md:2.1 | +| 整改工作量 | 61h | audit-summary-report.md:9.1 | +| 单元测试覆盖率 | 85% | audit-summary-report.md:1.2 | +| E2E 覆盖率 | 0% | audit-summary-report.md:1.2 | +| 开发库污染定义 | 88 个 | audit-summary-report.md:4.1 | + +--- + +## 立即行动清单 + +**今天需要做的事**(第一天): + +``` +[ ] 技术负责人读 audit-summary-report.md(20 分钟) +[ ] 架构师读 comprehensive-audit-and-remediation-plan.md(60 分钟) +[ ] 后端 A 开发师启动 Task A1(2h)- 项目生命周期修复 +[ ] 后端 A 开发师启动 Task A4(2h)- 对话推进新服务 +[ ] QA 准备 E2E 测试框架(同步进行) +[ ] 全队讨论确认整改计划(30 分钟) +``` + +**本周目标**(5 天): + +``` +Day 1: 完成 Phase A 关键缺陷修复(15h) +Day 2-3: 启动 Phase B 新功能开发并行(26h) +Day 4-5: Phase C 完善与发布准备(20h) + + 每晚运行完整测试套件验证 +``` + +--- + +## 常见路径快查 + +**"完成工作流后项目仍然是 active"** +→ quick-reference-guide.md 第二部分 症状 1 +→ comprehensive-audit 第二部分 BUG-01 +→ remediation-tasks 的 Task A1 + +**"对话推进不起作用"** +→ quick-reference-guide.md 第二部分 症状 3 +→ comprehensive-audit 第二部分 BUG-04 +→ remediation-tasks 的 Task A4 + +**"禁用文档仍能被打开"** +→ quick-reference-guide.md 第二部分 症状 2 +→ comprehensive-audit 第二部分 BUG-05 +→ remediation-tasks 的 Task A5 + +**"激活 token 可能被重复使用"** +→ quick-reference-guide.md 第二部分 症状 6 +→ comprehensive-audit 第二部分 BUG-06 +→ remediation-tasks 的 Task A6 + +**"无法运行测试流程"** +→ quick-reference-guide.md 第二部分 症状 7 +→ comprehensive-audit 第三部分 MISSING-06 +→ remediation-tasks 的 Phase B 开始 + +**"需要完整 E2E 验证"** +→ comprehensive-audit 第三部分 MISSING-04 +→ remediation-tasks 的 Task B2 + +--- + +## 发布检查清单 + +**上线前必须确认**: + +``` +整改完成度: + □ Phase A 全部 PASS + □ Phase B 全部 PASS + □ Phase C 全部 PASS + +测试覆盖: + □ 单元测试覆盖率 ≥ 85% + □ E2E 测试三工作流完整链路 + □ 并发测试通过 + □ 数据库迁移兼容性验证 + +业务验收: + □ 验收标准 7.1-7.5 全部满足 + □ 不存在 critical 缺陷 + □ 安全性审计通过 + +运维就绪: + □ 数据库备份与恢复方案 + □ 审计日志完整 + □ 监控告警配置 + □ 性能基准测试 +``` + +--- + +## 文档维护 + +这套审计文档为 v1.0,应定期更新: + +- **每完成一个 task**: 更新对应 task 的状态 +- **每发现新缺陷**: 补充到 comprehensive-audit-and-remediation-plan.md +- **每月**: 做一次整体进度评估和文档更新 + +--- + +**审计完毕** + +**下一步**: 确认整改计划,进入实施阶段 + +**总体建议**: 立即启动 Phase A(关键缺陷),并行启动 E2E 测试框架,一周内完成所有整改。 + +--- + +*本索引最后更新于 2026-09-12 15:05 UTC* diff --git a/.doc/audit/README.md b/.doc/audit/README.md new file mode 100644 index 00000000..f1b51e3a --- /dev/null +++ b/.doc/audit/README.md @@ -0,0 +1,5 @@ +# 问题发现与分析 + +审计、根因分析、授权基线与矩阵。**不含**具体改码步骤(链到 `../remediation/`)。 + +索引:[INDEX.md](./INDEX.md) diff --git a/.doc/audit/authorization-baseline-2026-09-12.md b/.doc/audit/authorization-baseline-2026-09-12.md new file mode 100644 index 00000000..0ed74bb3 --- /dev/null +++ b/.doc/audit/authorization-baseline-2026-09-12.md @@ -0,0 +1,35 @@ +# 授权实施基线快照(Phase 0) + +- **分支**:`dev` +- **Commit SHA**:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3` +- **Goose schema**:`00020`(`00020_2026-09-12-task-run-worker-lease.sql`) +- **规格文档**:`.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md` + +## 环境矩阵 + +| 环境 | 分支 | Compose | HTTP | DB | 数据路径 | +|---|---|---|---|---|---| +| 开发 | dev | agent-dev | 8080 | 5433 | data/dev | +| 测试 | test | agent-test | 8081 | 5434 | data/test | +| 生产 | main | agent-main | 8000 | 5435 | data/main | +| 共享 KB | — | agent-infra | — | 5432 | data/shared/kb | + +## 工作流 v1 种子(published) + +| workflow_key | 说明 | 备注 | +|---|---|---| +| `main` | 商务对接 v1 单阶段包装 | 真实阶段仍在 bizdev 硬编码 | +| `product_manager` | 产品经理 v1 单阶段 | 未驱动 squad 五步 | +| `test_manager` | 测试经理 v1 单阶段 | 未驱动结构化 coverage | + +v2 将以新 version 发布,不覆盖 v1 hash。 + +## 验证命令(基线通过) + +```bash +go test -short -timeout 8m \ + ./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \ + ./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/... + +cd web && npm test && npm run build +``` diff --git a/.doc/audit/authorization-matrix-v2.md b/.doc/audit/authorization-matrix-v2.md new file mode 100644 index 00000000..8c44adc7 --- /dev/null +++ b/.doc/audit/authorization-matrix-v2.md @@ -0,0 +1,23 @@ +# API 授权矩阵 v2(Phase 0 基线) + +> 基线 commit:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3` +> 策略:默认拒绝;未知路由拒绝;跨项目 403/404 统一。 + +| 路由 | Resource | Action | Owner | 负例(未授权) | +|---|---|---|---|---| +| POST /api/v1/auth/login | session | create | auth | 匿名可访问(公开) | +| GET /api/v1/auth/me | user | read_self | auth | 401 无 token | +| GET /api/v1/projects | project | list | projectworkflow | 401 匿名 | +| POST /api/v1/projects | project | create | projectworkflow | 401;403 无 project:create | +| GET /api/v1/projects/{id} | project | read | authz | 403 非成员 | +| GET /api/v1/projects/{id}/lineage | lineage | read | projectworkflow | 403 跨项目 | +| GET /api/v1/projects/{id}/workflows/{key}/runs | workflow_run | list | projectworkflow | 403 跨项目 | +| POST /api/v1/projects/{id}/workflows/{key}/run | task | run | bizdev+stage | 403 错 task/stage | +| GET /api/v1/tasks/runs/{id} | task_run | view | taskrun | 403 非 owner/非 owner 成员 | +| POST /api/v1/tasks/runs/{id}/cancel | task_run | cancel | taskrun | 403 取消他人 | +| POST /api/v1/chat/stream | chat | send | chat+stage | 403 无阶段权限 | +| GET /api/v1/docgov/* | document | * | docgov+duty | 403 非职责人 | +| GET /api/v1/admin/* | admin | * | authz RBAC | 403 非 admin/细粒度 perm | +| GET /health, /api/v1/health | system | health | server | 公开 | + +完整路由枚举见 `internal/server/server.go` Routes();Phase 1 起每个项目子资源必须经 `requireProjectAccess`。 diff --git a/.doc/authorization-baseline-2026-09-12.md b/.doc/authorization-baseline-2026-09-12.md index 0ed74bb3..1a203a38 100644 --- a/.doc/authorization-baseline-2026-09-12.md +++ b/.doc/authorization-baseline-2026-09-12.md @@ -1,35 +1,3 @@ -# 授权实施基线快照(Phase 0) +# 已迁移 -- **分支**:`dev` -- **Commit SHA**:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3` -- **Goose schema**:`00020`(`00020_2026-09-12-task-run-worker-lease.sql`) -- **规格文档**:`.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md` - -## 环境矩阵 - -| 环境 | 分支 | Compose | HTTP | DB | 数据路径 | -|---|---|---|---|---|---| -| 开发 | dev | agent-dev | 8080 | 5433 | data/dev | -| 测试 | test | agent-test | 8081 | 5434 | data/test | -| 生产 | main | agent-main | 8000 | 5435 | data/main | -| 共享 KB | — | agent-infra | — | 5432 | data/shared/kb | - -## 工作流 v1 种子(published) - -| workflow_key | 说明 | 备注 | -|---|---|---| -| `main` | 商务对接 v1 单阶段包装 | 真实阶段仍在 bizdev 硬编码 | -| `product_manager` | 产品经理 v1 单阶段 | 未驱动 squad 五步 | -| `test_manager` | 测试经理 v1 单阶段 | 未驱动结构化 coverage | - -v2 将以新 version 发布,不覆盖 v1 hash。 - -## 验证命令(基线通过) - -```bash -go test -short -timeout 8m \ - ./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \ - ./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/... - -cd web && npm test && npm run build -``` +本文档已迁至 [audit/authorization-baseline-2026-09-12.md](audit/authorization-baseline-2026-09-12.md)。请勿在此编辑。 diff --git a/.doc/authorization-matrix-v2.md b/.doc/authorization-matrix-v2.md index 8c44adc7..1e3c9dd2 100644 --- a/.doc/authorization-matrix-v2.md +++ b/.doc/authorization-matrix-v2.md @@ -1,23 +1,3 @@ -# API 授权矩阵 v2(Phase 0 基线) +# 已迁移 -> 基线 commit:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3` -> 策略:默认拒绝;未知路由拒绝;跨项目 403/404 统一。 - -| 路由 | Resource | Action | Owner | 负例(未授权) | -|---|---|---|---|---| -| POST /api/v1/auth/login | session | create | auth | 匿名可访问(公开) | -| GET /api/v1/auth/me | user | read_self | auth | 401 无 token | -| GET /api/v1/projects | project | list | projectworkflow | 401 匿名 | -| POST /api/v1/projects | project | create | projectworkflow | 401;403 无 project:create | -| GET /api/v1/projects/{id} | project | read | authz | 403 非成员 | -| GET /api/v1/projects/{id}/lineage | lineage | read | projectworkflow | 403 跨项目 | -| GET /api/v1/projects/{id}/workflows/{key}/runs | workflow_run | list | projectworkflow | 403 跨项目 | -| POST /api/v1/projects/{id}/workflows/{key}/run | task | run | bizdev+stage | 403 错 task/stage | -| GET /api/v1/tasks/runs/{id} | task_run | view | taskrun | 403 非 owner/非 owner 成员 | -| POST /api/v1/tasks/runs/{id}/cancel | task_run | cancel | taskrun | 403 取消他人 | -| POST /api/v1/chat/stream | chat | send | chat+stage | 403 无阶段权限 | -| GET /api/v1/docgov/* | document | * | docgov+duty | 403 非职责人 | -| GET /api/v1/admin/* | admin | * | authz RBAC | 403 非 admin/细粒度 perm | -| GET /health, /api/v1/health | system | health | server | 公开 | - -完整路由枚举见 `internal/server/server.go` Routes();Phase 1 起每个项目子资源必须经 `requireProjectAccess`。 +本文档已迁至 [audit/authorization-matrix-v2.md](audit/authorization-matrix-v2.md)。请勿在此编辑。 diff --git a/.doc/remediation/2026-09-11-production-ready-workflow-governance-plan.md b/.doc/remediation/2026-09-11-production-ready-workflow-governance-plan.md new file mode 100644 index 00000000..7796d773 --- /dev/null +++ b/.doc/remediation/2026-09-11-production-ready-workflow-governance-plan.md @@ -0,0 +1,684 @@ +# Chat Agent System 发布级账户、权限与工作流治理改进方案 + +## 1. 执行摘要 + +当前系统已经具备良好的业务原型基础:登录/注册、项目、项目成员表、受控文档三权流转、工作流运行、文档血缘、系统设置弹窗和用户设置弹窗均已有不同程度的实现;近期还补上了统一 API 登录中间件、Goose 数据库迁移、生产镜像中的前端构建,以及数据库不可用时的生产失败关闭。这些能力应保留并演进,而不是推倒重来。[^1][^2][^3] + +系统目前仍不适合直接作为多人生产协作产品发布。关键问题已经从“有没有功能”转变为“谁是权威、配置何时生效、运行状态能否被绕过”: + +- 用户、密码、登录令牌和认证配置仍保存在 Go 进程内存中,重启即变化,令牌没有持久化、过期、轮换和全端撤销闭环。[^4] +- 角色定义、权限矩阵、人员扩展资料、项目成员编辑与大量交付物状态仍由浏览器 `localStorage` 保存;当前后端管理员判断仍硬编码为 `role-admin`。[^5][^6] +- 工作流目录是 Go 代码中的三个固定定义,每个定义只有一个 `stage_key/task_key`,还不是管理员可编辑、可发布、多阶段、多文档的工作流模型。[^7] +- 新项目默认立即激活 `main`;现有工作流控件会直接切换 active 指针,甚至在版本冲突后自动刷新重试,没有“配置—预览—二次确认—冻结—结束”的完整生命周期。[^8][^9] +- 项目成员角色当前混用了“创建人、编制人、审核人、批准人、查阅者”。编制/审核/批准本质上是每份文档的职责,不应作为一个人在整个项目中的单一角色。[^10] +- 项目类型仍主要是自由文本 `device_type`,前端阶段键固定为 `V0.1/V0.5/V1.0`,无法自然表达非医疗纯软件项目或其他生命周期。[^11] + +建议把目标系统定义为一个“受控的项目工作流平台”,核心由五层组成: + +```text +账户主体 ── 组织/系统角色 ── 项目成员关系 + │ + ▼ +不可变工作流版本 ──> 项目工作流实例 ──> 阶段实例 ──> 文档任务实例 + │ │ + ├─ 对话参与策略 └─ 编制/审核/批准职责 + ├─ 文档可见策略 + └─ 阶段推进门禁 + 审计 + 通知 +``` + +最重要的产品决策是: + +1. **取消任意身份切换**:生产包中删除 `DevRoleSwitcher` 和“模拟账号切换”;登录身份只能来自服务端会话。测试身份切换只保留在不随产品发布的测试夹具中。 +2. **角色不等于文档职责**:角色回答“这个人通常能做什么”;项目成员关系回答“这个人是否属于这个项目”;文档职责回答“这个人在这份文档中是编制、审核还是批准”。三者必须分表、分权限、分审计。 +3. **工作流采用版本化模板**:管理员编辑的是草稿版本,发布后不可原地修改。项目激活时复制一个完整快照,后续修改全局模板不得改变正在运行的项目。 +4. **同一项目最多一个运行中的工作流**:不能“切换”正在运行的工作流,只能在其完成或受控终止后选择新的工作流。 +5. **激活即冻结**:阶段开关、文档任务开关、模板版本、文档三权与参与策略在激活前配置;激活后普通路径不可修改。确需变更时走“受控变更单”,而不是直接改字段。 +6. **阶段不自动推进**:所有启用且必需的文档任务完成批准、无阻断性 stale/开放变更后,系统生成一次去重的“可推进”建议,主动通知项目创建者;由创建者确认后才原子进入下一阶段。 +7. **项目分类与合规范围分离**:不要只设 `is_medical=true/false`。至少拆为“产品域”和“合规配置”。纯软件可能是非医疗软件,也可能是医疗器械软件;两者不能由“是不是软件”推断。 + +## 2. 需求重述与边界 + +### 2.1 三类设置 + +系统应形成三个边界清晰的设置入口: + +| 入口 | 可进入者 | 管理对象 | 不应包含 | +|---|---|---|---| +| 用户设置 | 当前登录用户 | 本人资料、安全、通知、界面偏好、活动会话 | 角色提升、项目权限、他人账号 | +| 项目设置 | 项目创建者 | 项目成员、待激活工作流、阶段/文档开关、文档三权、激活/结束、通知 | 全局角色、全局模板原件、系统安全策略 | +| 系统设置 | 具备相应系统管理权限者 | 账户、角色、权限、工作流设计、模板库、项目类型/合规配置、审计和安全策略 | 以管理员身份直接替项目创建者完成日常业务决策 | + +“系统管理员能看一切”不应成为默认业务规则。管理员需要处理平台配置,但项目私密资料和个人私密文档应遵守独立的数据访问策略。必要的运维介入应使用带理由、再认证、限时和全量审计的 break-glass 流程。 + +### 2.2 关键术语 + +| 术语 | 建议定义 | +|---|---| +| 账户 | 唯一自然人的登录主体,不可在前端任意切换 | +| 角色 | 一组可复用权限,可以是系统范围或项目范围 | +| 项目成员 | 用户与项目之间的关系,含状态和项目角色绑定 | +| 文档职责 | 某个用户对某个文档任务实例承担 author/reviewer/approver | +| 工作流定义 | 管理员维护的逻辑标识,如 `medical_device_development` | +| 工作流版本 | 已发布且不可变的完整流程快照,如 `v3` | +| 项目工作流实例 | 某项目基于某个已发布版本创建的实际运行实例 | +| 阶段实例 | 项目工作流中的一个可推进单元 | +| 文档任务实例 | 阶段中的具体交付任务,连接模板、文档记录与三权职责 | + +## 3. 当前实现评估 + +### 3.1 值得保留的基础 + +| 现有能力 | 评价 | 后续用法 | +|---|---|---| +| 统一 API 认证中间件 | 已覆盖非公开 `/api` 路由,方向正确 | 改接持久化会话,继续作为统一入口 | +| `project_members` | 已有项目成员关系和 owner 回填 | 扩展角色绑定、成员管理 API 和成员状态 | +| `document_records` | 已有状态、锁定、版本、三权和审计字段 | 关联 `document_task_instance`,逐步去除冗余姓名字段 | +| DocGov 状态机 | 已有编制、审核、批准、驳回基础 | 增加职责分离、电子签名/再认证和阶段门禁事件 | +| `project_workflows/workflow_runs` | 已有项目工作流、运行和激活审计雏形 | 升级为定义版本 + 项目实例 + 阶段实例模型 | +| 文档血缘/stale | 已能表达上下游版本变化 | 纳入阶段完成条件和变更影响评估 | +| Goose 迁移与前端生产构建 | 近期已补齐基本链路 | 加迁移兼容测试、回滚预案和镜像验收 | +| 互动卡片/提醒类型 | 前端已有确认与提醒数据结构 | 用于“阶段可推进”和“工作流激活确认” | + +### 3.2 必须纠正的结构性问题 + +第一,当前 RBAC 主要在前端执行。`DEFAULT_ROLES` 和 `hasPermission` 用于隐藏按钮、过滤文档,但服务端没有同构的角色/权限表和统一策略决策。浏览器过滤只能改善体验,不能构成安全边界。OWASP 建议默认拒绝,并在每个请求上重新验证用户对具体资源和动作的权限。[^12] + +第二,现有 `ProjectWorkflowSwitcher` 的语义是“切换当前焦点”,而目标语义是“运行中的流程互斥”。当前控件点击后直接调用激活 API,遇到乐观锁冲突还会自动用最新版本重试;对高影响业务操作,这会掩盖“另一个操作者刚刚改变了项目”的事实。冲突应该展示差异并要求用户重新确认,而不是静默覆盖。[^9] + +第三,现有项目工作流唯一约束是 `(project_id, workflow_key)`,无法表示同一项目先后运行同一流程两次,也没有数据库约束保证“每个项目最多一个 active”。应保留历史实例,以 `instance_no` 或独立实例 ID 区分,并用部分唯一索引约束活动态。 + +第四,现有文档记录已支持三权,但项目成员 UI 又把成员角色设成 author/reviewer/approver,导致一个人加入项目时就被迫成为所有文档的某一职责。这会阻碍不同文档采用不同责任人,也无法表达 QA 同时参与多个文档但只批准其中一份。 + +## 4. 目标权限模型 + +### 4.1 RBAC + 项目关系 + 工作流属性 + +只用 RBAC 无法表达“BD 在商务阶段可对话,进入研发阶段后不可对话且不可看研发文档”。建议采用组合策略: + +```text +允许 = 已认证 + AND 账户有效 + AND 具备基础动作权限 + AND 是该项目的有效成员(或合规的系统级例外) + AND 当前工作流/阶段允许其项目角色参与 + AND 目标文档可见策略允许 + AND 当前状态允许该动作 + AND 未违反职责分离约束 +``` + +任一条件未知或没有匹配规则时拒绝。RBAC 适合降低组织权限管理成本,但阶段、对象归属、文档责任人和状态属于属性/关系条件,需要与 ABAC/ReBAC 组合。NIST 的 RBAC 模型明确区分用户、角色、权限、操作和对象,也支持职责分离约束;NIST 对 RBAC 加属性的研究同样说明二者结合更适合动态条件。[^13][^14] + +### 4.2 角色分层 + +| 层级 | 示例 | 作用域 | 建议 | +|---|---|---|---| +| 系统角色 | 系统管理员、用户管理员、工作流管理员、安全审计员 | 全系统 | 内置角色至少保留一个不可删除的超级管理员,但可编辑角色不得靠前端标志保护 | +| 业务/项目角色 | BD、产品经理、研发、测试、法规、QA、项目观察者 | 某项目 | 用户可在不同项目承担不同角色;可从组织默认角色复制后由项目创建者调整 | +| 文档职责 | 编制、审核、批准 | 单个文档任务实例 | 必须指派到具体用户,不等于项目角色 | + +建议允许一个用户绑定多个角色,但权限计算不是简单无条件求并集。若两个角色触发静态或动态职责分离冲突,应阻止绑定或阻止同一会话中的冲突动作。例如,同一文档默认不得由同一人同时编制和批准;如小团队必须例外,工作流版本需显式允许,并要求理由和额外审计。 + +### 4.3 权限键建议 + +权限键使用稳定动作,不把具体角色名编码进代码: + +| 权限域 | 建议权限 | +|---|---| +| 系统 | `system.settings.view`、`system.audit.view`、`system.security.manage` | +| 用户 | `users.view`、`users.create`、`users.edit`、`users.disable`、`users.reset_password` | +| 角色 | `roles.view`、`roles.create`、`roles.edit`、`roles.delete`、`roles.assign` | +| 工作流模板 | `workflow_defs.view`、`workflow_defs.create`、`workflow_defs.edit_draft`、`workflow_defs.publish`、`workflow_defs.retire` | +| 项目 | `projects.create`、`projects.view`、`projects.edit`、`projects.members.manage`、`projects.workflow.configure`、`projects.workflow.activate`、`projects.workflow.terminate`、`projects.stage.advance` | +| 工作流参与 | `workflow.chat.send`、`workflow.chat.view`、`workflow.task.run`、`workflow.progress.view` | +| 文档 | `documents.view`、`documents.edit`、`documents.submit_review`、`documents.review`、`documents.approve`、`documents.export`、`documents.visibility.manage` | +| 模板文件 | `templates.upload`、`templates.download`、`templates.publish`、`templates.retire` | + +项目创建者的专属能力不应仅靠一个通用 permission。服务端应同时校验 `projects.creator_user_id == principal.user_id`。系统管理员若需替代操作,只能走单独的 break-glass API,不能复用普通项目设置接口。 + +### 4.4 阶段策略示例 + +| 角色 | 商务阶段对话 | 商务文档 | 研发阶段对话 | 研发文档 | 审批动作 | +|---|---:|---:|---:|---:|---:| +| 项目创建者 | 是 | 是 | 是 | 是 | 仅被指派时;阶段推进始终由其确认 | +| BD | 是 | 按文档规则 | 否 | 否 | 仅商务文档且被指派时 | +| 产品经理 | 可选 | 按规则 | 是 | 需求类与被授权文档 | 被指派时 | +| 研发 | 否/可选 | 默认否 | 是 | 是 | 被指派时 | +| 测试 | 否 | 默认否 | 是 | 测试及依赖文档 | 被指派时 | +| 法规/QA | 可选 | 合规文档 | 是 | 合规与质量文档 | 被指派时 | +| 审计员 | 否 | 只读 | 否 | 只读 | 否 | + +“否”必须在服务端同时作用于列表、详情、搜索、导出、附件下载、SSE、对话发送、RAG 上下文组装和 Agent 工具读取,不能只隐藏 UI。 + +## 5. 账户与身份治理 + +### 5.1 去掉任意身份切换 + +发布版本应: + +- 删除 `DevRoleSwitcher` 的产品入口; +- 删除 `UserProjectRightsModal` 中的快速模拟账号切换; +- 删除前端本地认证 fallback、内置明文测试账户和 `X-User-ID` 发送逻辑; +- CI 检查生产 bundle 不包含种子密码、测试用户列表、`allowDevSwitch` 或模拟切换文案; +- E2E 测试通过独立测试登录接口、数据库 fixture 或浏览器多上下文完成,不在产品 UI 留后门。 + +如果未来确实需要客服“代用户查看”,应作为独立的 impersonation/break-glass 功能:管理员再认证、填写工单与理由、限时、只读优先、页面持续红色提示、用户可见审计、禁止电子签名和批准。首个可发布版本建议不做。 + +### 5.2 持久化账户与会话 + +建议新增: + +| 表 | 关键字段 | +|---|---| +| `users` | username、display_name、email、status、department、employee_id、locale、timezone、created_at、updated_at | +| `user_credentials` | user_id、password_hash、password_changed_at、failed_count、locked_until、mfa_state | +| `auth_sessions` | id、token_hash、user_id、created_at、last_seen_at、idle_expires_at、absolute_expires_at、revoked_at、ip_hash、user_agent | +| `password_reset_tokens` | token_hash、user_id、expires_at、used_at | +| `user_role_bindings` | user_id、role_id、scope_type、scope_id、valid_from、valid_until、assigned_by | + +令牌仅以哈希形式持久化。浏览器优先使用 `HttpOnly + Secure + SameSite` Cookie;如果继续使用 Bearer token,也必须有短期访问令牌、刷新/轮换、撤销和 XSS 风险控制。NIST 已在 2025 年发布 SP 800-63B-4,替代旧版数字身份认证指南;账户安全设计应以新版为基线,而不是继续依赖永久内存 token。[^15] + +### 5.3 用户设置 + +用户设置建议分为四页: + +1. **个人资料**:头像、姓名展示、邮箱、电话、语言、时区;员工号、部门和职位为组织受控字段,只读或需管理员审批。 +2. **安全**:修改密码、MFA、已登录设备、注销其他设备、最近登录与安全事件。 +3. **通知**:待审核、待批准、阶段可推进、文档 stale、任务失败的站内/邮件策略及免打扰时间。 +4. **偏好**:主题、默认输出格式、沟通风格、自定义指令;明确哪些偏好会进入 Agent 上下文。 + +高风险变更如密码、MFA、主邮箱和电子批准应要求近期认证。账号被禁用、密码重置或角色收回时,相关会话立即撤销并使权限缓存失效。 + +## 6. 系统设置的信息架构 + +系统设置不宜继续放在单个 980px 模态框内。建议改为有独立路由和权限保护的管理中心:`/admin/*`。 + +| 页面 | 核心能力 | +|---|---| +| 概览 | 服务健康、待审批用户、失败工作流、存储/队列、近期安全事件 | +| 用户与账户 | 创建、编辑、启停、邀请、重置密码、撤销会话、批量导入、角色绑定 | +| 角色与权限 | 角色增删改、权限矩阵、作用域、职责分离、受影响用户预览 | +| 工作流设计器 | 草稿创建、阶段排序、文档任务、参与策略、门禁、校验、测试、发布、退役 | +| 模板库 | 上传、预览、变量、版本、哈希、扫描状态、被哪些工作流引用 | +| 项目类型与合规 | 产品域、合规配置、字段 schema、可用工作流、默认策略 | +| 通知与自动化 | 事件模板、渠道、提醒频率、升级规则、去重规则 | +| 审计日志 | 用户/权限/工作流/模板/项目变更查询与导出 | +| 安全与会话 | 注册策略、密码/MFA、会话时限、CORS、上传上限、保留期 | + +角色删除必须先做影响分析。若仍有用户或工作流策略引用,默认不允许删除,只允许停用/归档或迁移绑定。内置超级管理员角色不可删除、不可清空关键权限;系统必须始终至少有一个有效超级管理员账户。 + +## 7. 工作流定义与版本管理 + +### 7.1 定义结构 + +```text +WorkflowDefinition (稳定业务标识) + └─ WorkflowVersion (draft | published | retired,发布后不可变) + ├─ StageDefinition [有序] + │ ├─ DocumentTaskDefinition [0..N] + │ │ ├─ TemplateVersion + │ │ ├─ default duties / eligible roles + │ │ └─ visibility / participation policy + │ └─ entry/exit gate + └─ workflow-level participation / completion policy +``` + +首期建议只支持线性阶段,拖拽排序即可。不要一开始引入任意 DAG、循环和复杂表达式;但表结构可以预留 `transition_rules`。线性模型已经满足“本阶段文档全部批准后,由创建者确认进入下一阶段”。 + +### 7.2 工作流版本状态 + +| 状态 | 可编辑 | 可用于新项目 | 可影响已激活项目 | +|---|---:|---:|---:| +| draft | 是 | 否 | 否 | +| published | 否 | 是 | 否,项目只引用固定版本 | +| retired | 否 | 否 | 已运行实例继续按原快照执行 | + +编辑已发布版本时实际执行“复制为新草稿”。发布前执行确定性校验:键唯一、阶段顺序连续、至少一个启用阶段、阶段至少有文档任务或显式人工门禁、模板均为可用版本、变量 schema 完整、权限策略有兜底、三权候选角色存在、无不可达节点、无角色死锁。 + +### 7.3 文档模板 + +模板不是直接覆盖文件,而是版本化资产: + +- 上传后生成 CAS blob、SHA-256、MIME/扩展名、大小、上传人和扫描状态; +- 只允许业务所需格式,如 DOCX、XLSX、PPTX、Markdown;宏文档默认拒绝; +- 经过扩展名、MIME、文件签名、大小、解压后大小、恶意文件扫描/隔离后才能标记 `ready`; +- 发布的工作流只能引用 `ready` 模板版本; +- 模板更新创建新版本,不改变历史项目实例; +- 变量采用白名单 schema,如 `project.name`、`project.owner.name`,未知变量阻止发布。 + +OWASP 对上传的建议包括扩展名白名单、不要信任客户端 Content-Type、应用生成存储名、限制大小、仅授权用户上传、放在 Web 根目录外并进行恶意文件扫描;模板上传应按此设计。[^16] + +## 8. 项目类型与合规配置 + +### 8.1 不使用单一“医疗/非医疗”开关 + +建议拆为两个维度: + +| 维度 | 示例 | 用途 | +|---|---|---| +| `product_domain` | `medical_device`、`non_medical_software`、`hardware_general`、`service` | 决定项目字段、推荐工作流和术语 | +| `compliance_profile` | `nmpa_device`、`eu_mdr`、`fda_qmsr`、`internal_qms`、`none` | 决定法规步骤、必需文档、签名和审计强度 | + +“纯软件”不能自动等同“无需法规”。非医疗 SaaS 可以选择 `none`;SaMD 则仍属于医疗器械域并选择对应市场合规配置。创建项目时以向导明确询问产品用途、目标市场和是否用于诊断/治疗等,由用户确认分类及理由,系统只提供建议。 + +FDA 的 QMSR 已于 2026 年 2 月 2 日生效,并将 ISO 13485:2016 纳入美国医疗器械质量体系框架;因此医疗项目的默认工作流与合规配置应可版本化,不应把旧法规口径写死在 Agent prompt 中。[^17] ISO 官方也说明 ISO 13485 面向医疗器械质量管理,并强调法规要求和风险管理;它不适合无差别施加给所有非医疗软件项目。[^18] + +### 8.2 首批项目类型建议 + +**医疗器械研发**建议阶段:商务摸底 → 需求与法规策划 → 设计开发 → 设计验证/确认 → 设计转移/发布。文档清单由所选市场、器械类型与组织 QMS 决定。 + +**非医疗纯软件**建议阶段:机会与范围 → 产品需求 → 架构与计划 → 实现 → 测试与验收 → 发布复盘。默认无法规检索步骤,可包含 SRS、架构设计、测试计划、发布清单、用户文档;若选择 `internal_qms`,仍可要求评审、批准和审计。 + +项目类型只负责推荐和约束可选工作流,不直接生成项目实例。这样未来可增加科研、咨询、硬件或组合产品,而无需修改 `projects` 表的大量专用字段。 + +## 9. 项目设置与激活冻结 + +### 9.1 项目设置页面 + +仅项目创建者可进入普通项目设置。页面建议分为: + +1. **基本信息**:名称、编号、产品域、合规配置、目标市场;工作流激活后影响流程的字段冻结,修改需受控变更。 +2. **成员与项目角色**:邀请、移出、项目角色绑定;不能在这里把成员设为全项目 author/reviewer/approver。 +3. **工作流配置**:从与项目类型兼容的已发布版本中选择一个待激活工作流。 +4. **阶段与文档**:激活前开关可选阶段/文档,查看依赖和影响;必需节点不可关闭。 +5. **责任分配**:逐文档指派编制/审核/批准,实时验证角色资格与职责分离。 +6. **激活与结束**:预览快照、风险提示、二次确认;运行中只展示状态和受控操作。 +7. **项目审计**:成员、配置、激活、推进、终止和职责变更记录。 + +### 9.2 激活流程 + +新项目不应默认激活 `main`,而应处于 `planning`。推荐交互: + +```text +选择工作流版本 + → 配置阶段/文档开关 + → 指派每份启用文档的三权 + → 系统校验 + → 生成只读预览与 plan_hash + → 用户二次确认 + → 单事务创建实例/快照/首阶段/文档任务/审计 +``` + +激活确认弹窗应明确展示:工作流名称和版本、启用阶段数、启用/关闭文档数、三权缺口、激活后哪些配置会冻结、当前参与者权限将如何变化。用户勾选“我理解激活后不能直接修改”并再次点击确认。 + +服务端不能只信任 `confirmed=true`。建议 `POST /activation-preview` 返回短期 `confirmation_token + plan_hash + expected_project_version`;真正激活时必须三者一致。若期间成员、责任人、模板或项目配置变化,返回 409 和差异摘要,要求重新预览确认。 + +### 9.3 工作流实例状态机 + +```text +planning ──activate──> active + │ ├─> awaiting_stage_confirmation ──advance──> active + │ ├─> completed + │ └─> termination_requested ──confirm──> terminated + └─delete draft +``` + +数据库增加部分唯一约束:一个项目在 `active/awaiting_stage_confirmation/termination_requested` 中最多有一个实例。新的工作流只有在前一个实例为 `completed` 或 `terminated` 后才能选择和激活。 + +正常“结束”与异常“终止”必须区分: + +- `completed`:所有启用阶段按门禁完成; +- `terminated`:创建者因范围取消等原因提前结束,必须填写原因,保留已有文档和历史; +- `paused` 可作为后续版本能力,首期不建议增加以免模糊“是否仍占用 active 槽位”。 + +### 9.4 配置冻结与受控变更 + +激活后以下内容冻结:工作流版本、阶段和文档启用状态、模板版本、基线参与策略、文档三权。首期可严格禁止修改。 + +第二阶段再提供 `workflow_change_requests`:创建者提出变更 → 系统分析影响 → 相关批准人确认 → 创建新配置 revision → 使受影响下游文档 stale。即使通过变更单,也不应回写全局工作流版本。 + +## 10. 阶段、文档与主动推进 + +### 10.1 阶段状态机 + +```text +pending → active → ready_to_advance → completed + │ │ + └─ blocked <───┘ +``` + +阶段进入 `ready_to_advance` 的确定性条件: + +- 所有 `enabled=true && required=true` 的文档任务均为 `approved`; +- 没有运行中的 Agent/task run; +- 没有阻断性开放批注、变更提案或 stale 文档; +- 阶段专用 exit gate 通过; +- 下一阶段至少有一个有效参与者,避免推进后无人能工作。 + +可选文档如果启用,也建议默认纳入阶段门禁;工作流管理员可以把某文档配置为 `blocking=false`,但发布时需要解释用途。阶段开关关闭时,其文档节点自动关闭并记录在项目快照中。启用阶段若关闭全部文档,必须有 `manual_gate=true`,否则激活校验失败。 + +### 10.2 文档任务状态 + +文档任务实例与文档正文分离:任务状态负责“是否启用、负责人是谁、是否完成”,`document_records` 继续负责正文版本和受控生命周期。 + +```text +disabled(仅激活前可选) +enabled: template → drafting → reviewing → approving → approved + ↑ │ │ + └─ rejected┴────────────┘ +approved --upstream changed--> stale(阻止阶段推进,直到评估或新版本批准) +``` + +三权规则: + +- 编制人可编辑并提交审核,不能批准自己的版本; +- 审核人只能在 `reviewing` 决定通过/驳回; +- 批准人只能在审核通过的固定内容哈希上批准; +- 审核或批准动作记录 user、role binding、时间、内容哈希、意见和认证上下文; +- 责任人被禁用/移出项目时,任务进入 `assignment_blocked`,不能继续流转; +- 更换责任人属于受控事件,不覆盖历史签署信息。 + +若系统承载受法规要求约束的电子记录/签名,应先做适用性评估。21 CFR 11.10 对闭合系统强调授权访问、按许可顺序执行、权限检查、记录保护和带时间戳审计轨迹;因此这里推荐的服务端状态机、不可覆盖审计和固定内容哈希不仅是产品体验要求,也是更稳妥的合规架构基础。[^19] 这不等于仅靠实现这些功能就自动达到 Part 11 合规,仍需结合组织程序、验证、培训、留存和适用法规完成独立评估。FDA 指南也建议基于对产品质量、安全和记录完整性的风险评估确定控制强度。[^20] + +### 10.3 主动询问创建者 + +当状态首次满足推进条件时,由事务 Outbox 写入 `stage.ready_to_advance` 事件。通知服务创建一条去重的待办和互动卡片: + +> “研发输入阶段的 4/4 个必需文档已批准,没有阻断项。是否进入‘设计开发’阶段?推进后 BD 将失去本工作流对话与研发文档访问权限。” + +卡片提供:查看完成清单、查看权限变化、暂不推进、确认推进。确认接口再次实时校验条件和 `expected_stage_version`;若已有文档被撤回、stale 或成员发生变化,拒绝推进并列出差异。 + +提醒去重键可为 `(stage_instance_id, readiness_revision)`。首次立即站内提醒,24 小时未处理再次提醒,超过组织配置阈值可升级给项目创建者本人或指定项目监督人,但绝不自动推进。 + +### 10.4 阶段切换时的权限变化 + +阶段推进和权限生效在同一数据库事务中完成。以 BD 为例: + +- 事务提交前仍按商务阶段策略工作; +- 提交后新的对话发送、文档列表、详情、下载、搜索、引用和 Agent 上下文读取立即按研发阶段策略拒绝; +- 已打开页面下一次 API/SSE 校验时收到权限变化事件并转为只读/关闭; +- 是否还能查看历史商务阶段记录由工作流策略单独配置,不与研发文档权限混在一起; +- 默认建议允许 BD 查看自己参与的已结束商务阶段记录,但不能查看研发阶段消息和文档。 + +为此,聊天会话/消息必须绑定 `workflow_instance_id` 和 `stage_instance_id`。否则只有项目级 session,系统无法安全区分同一项目中商务与研发阶段的对话可见性。 + +## 11. 推荐数据模型 + +### 11.1 核心表 + +| 表 | 关键字段与说明 | +|---|---| +| `roles` | id、code、name、scope_type、status、is_system、version | +| `permissions` | key、resource_type、action、risk_level | +| `role_permissions` | role_id、permission_id、effect;首期只支持 allow,未匹配即 deny | +| `role_bindings` | user_id、role_id、scope_type、scope_id、有效期、assigned_by | +| `role_constraints` | SoD、互斥角色、作用域限制 | +| `workflow_definitions` | id、key、name、status、latest_published_version | +| `workflow_versions` | workflow_id、version、status、schema_version、published_by/at、definition_hash | +| `workflow_stage_defs` | workflow_version_id、key、name、position、optional、manual_gate、entry/exit_rule | +| `workflow_doc_task_defs` | stage_def_id、key、title、template_version_id、required、blocking、default_enabled | +| `workflow_access_policies` | target_type/id、project_role_id、action、effect | +| `template_assets` | logical key、name、status | +| `template_versions` | asset_id、version、blob_sha256、mime、size、scan_status、variable_schema | +| `project_types` | key、name、product_domain、field_schema、status | +| `compliance_profiles` | key、name、ruleset_version、status | +| `project_type_workflows` | project_type_id、workflow_id、compliance_profile_id、recommended/allowed | +| `project_workflow_instances` | project_id、workflow_version_id、instance_no、status、config_revision、created_by | +| `project_stage_instances` | workflow_instance_id、stage_def_id、position、enabled、status、version | +| `project_doc_task_instances` | stage_instance_id、doc_task_def_id、enabled、blocking、status、document_id | +| `document_duty_assignments` | doc_task_instance_id、duty、user_id、assigned_by、valid_from/to | +| `stage_advance_requests` | stage_instance_id、readiness_revision、status、requested_at、decided_by/at、reason | +| `workflow_change_requests` | instance_id、from_revision、patch、impact、status、decisions | +| `notifications` | user_id、event_id、type、status、dedupe_key、read_at、acted_at | +| `audit_events` | actor、action、resource、before/after hash、reason、request_id、occurred_at | + +### 11.2 关键约束 + +```sql +CREATE UNIQUE INDEX uq_one_live_workflow_per_project +ON project_workflow_instances(project_id) +WHERE status IN ('active', 'awaiting_stage_confirmation', 'termination_requested'); + +CREATE UNIQUE INDEX uq_doc_duty_once +ON document_duty_assignments(doc_task_instance_id, duty) +WHERE valid_to IS NULL; + +CREATE UNIQUE INDEX uq_stage_advance_revision +ON stage_advance_requests(stage_instance_id, readiness_revision); +``` + +此外应使用外键和 CHECK/触发器或领域事务确保:已发布版本不可更新;激活实例至少有一个启用阶段;一个实例最多一个 active stage;文档任务只能引用本实例阶段;批准动作绑定的内容哈希等于当前待批准版本。 + +### 11.3 现有表迁移映射 + +| 现有对象 | 迁移方式 | +|---|---| +| `projects.active_workflow_key` | 过渡期作为缓存字段,最终由 live instance 派生;不再作为唯一事实源 | +| `project_workflows` | 回填成 `project_workflow_instances`;已有 active 记录生成 legacy snapshot | +| `workflow_runs` | 增加 instance/stage/task 外键,保留 run_id 与 input manifest | +| `document_records.task_key/stage` | 回填关联 `project_doc_task_instances`;保留只读兼容字段一版 | +| `document_records.author/reviewer/approver` | 回填 `document_duty_assignments`;姓名字段只用于历史展示,不再鉴权 | +| `project_members.project_role` | 从单字符串迁移到 `role_bindings`;owner 单独保留创建人关系 | +| 前端 `localStorage` roles/projects/deliverables | 首次升级只读取并提示导入;服务端确认成功后停止作为权威源 | + +## 12. API 与领域服务 + +### 12.1 建议领域服务 + +- `IdentityService`:账户、凭据、会话、MFA、撤销; +- `AuthorizationService`:集中计算 `Decision{allowed, reason_code, policy_version}`; +- `RoleService`:角色版本、绑定、影响分析和职责分离; +- `WorkflowDefinitionService`:草稿、校验、发布、退役; +- `ProjectWorkflowService`:配置预览、激活、推进、完成、终止、受控变更; +- `DocumentTaskService`:任务实例、三权指派、DocGov 联动; +- `NotificationService`:Outbox 消费、去重、提醒与升级; +- `AuditService`:不可覆盖审计事件、查询、导出和留存。 + +### 12.2 主要 API + +```text +GET/POST/PATCH /api/v1/admin/users +POST /api/v1/admin/users/{id}/revoke-sessions +GET/POST/PATCH/DELETE /api/v1/admin/roles +GET/POST /api/v1/admin/workflows +POST /api/v1/admin/workflows/{id}/versions/{v}/validate +POST /api/v1/admin/workflows/{id}/versions/{v}/publish +POST /api/v1/admin/templates +GET/POST/PATCH /api/v1/admin/project-types + +GET/PATCH /api/v1/me +POST /api/v1/me/password +GET/DELETE /api/v1/me/sessions +PATCH /api/v1/me/preferences + +GET /api/v1/projects/{id}/settings +PUT /api/v1/projects/{id}/workflow-plan +POST /api/v1/projects/{id}/activation-preview +POST /api/v1/projects/{id}/workflow-instances/activate +POST /api/v1/workflow-instances/{id}/stages/{stage}/advance +POST /api/v1/workflow-instances/{id}/complete +POST /api/v1/workflow-instances/{id}/terminate-preview +POST /api/v1/workflow-instances/{id}/terminate +PUT /api/v1/document-tasks/{id}/duties +``` + +所有写操作带 `Idempotency-Key` 和 `expected_version`。错误使用稳定代码,如 `WORKFLOW_ALREADY_ACTIVE`、`PLAN_CHANGED_RECONFIRM`、`STAGE_GATE_NOT_READY`、`ROLE_NOT_ELIGIBLE`、`SEPARATION_OF_DUTY_VIOLATION`、`WORKFLOW_ACCESS_DENIED`。 + +### 12.3 服务端授权位置 + +路由中间件只解决“是否登录”;对象级授权必须在领域入口再做。所有项目、会话、消息、文档、附件、搜索、导出、任务和 SSE API 都调用同一个 `AuthorizationService`。不允许 handler 自行散落 `if role == ...`,也不允许相信请求体中的 user/role/project ownership。 + +## 13. UI 交互方案 + +### 13.1 主工作台 + +- 顶部展示固定登录用户,不提供身份下拉切换; +- 项目标题旁显示当前工作流、阶段和状态,不再展示可随点随切的三个按钮; +- 有权限且无运行中工作流时显示“配置工作流”;运行中显示“查看流程”; +- 对当前阶段无参与权的用户,输入框禁用并说明原因;不能仅靠禁用,发送接口也返回 403; +- 右栏只加载服务端已授权的文档,避免先取全量再在浏览器过滤; +- 创建者看到“待我确认”角标和阶段推进卡片。 + +### 13.2 工作流设计器 + +建议三栏布局:左侧阶段树,中间阶段/文档配置,右侧属性和权限策略。顶部固定展示 `草稿/已发布/已退役`、版本号、校验结果和发布按钮。发布操作弹出变更摘要:新增/删除阶段、模板变化、角色访问变化、与上一版本兼容性。 + +### 13.3 项目工作流配置器 + +采用向导而不是大表单:选择 → 裁剪阶段 → 裁剪文档 → 指派职责 → 权限影响 → 校验 → 激活确认。所有关闭项显示影响,例如“关闭《法规路径评估》会使 FDA QMSR 合规配置不完整”,对合规配置定义的必需项则直接禁止关闭。 + +## 14. 生产发布基线 + +本方案的业务功能不能脱离发布工程。近期代码已补上统一认证中间件、数据库迁移调用和前端多阶段镜像,但仍至少需要完成以下发布阻断项: + +1. **持久化认证**:替换 `MemoryStore` 和进程内 token;生产不创建固定密码种子用户。 +2. **服务端 RBAC/ABAC**:把角色、权限、策略和项目成员修改迁入数据库/API,前端只消费 `capabilities`。 +3. **会话安全**:过期、轮换、撤销、登录限速、失败锁定、MFA、敏感动作再认证。 +4. **上传安全**:请求硬上限、配额、类型/签名检查、扫描、隔离、Web 根外存储。 +5. **审计完整性**:用户/角色/策略/模板/工作流/阶段/签署/导出都进入只追加审计;日志访问也审计。OWASP 建议记录用户管理、权限变更、管理操作、导入导出和文件上传,并保护日志不被未授权修改或删除。[^21] +6. **网络安全**:移除 `Access-Control-Allow-Origin: *`,使用允许域名;TLS、HSTS、CSP、frame/referrer 等由网关和应用共同设置。[^22] +7. **持久异步任务**:task run/event、worker lease、重启恢复、Outbox;只能在文档与事件落库成功后发布终态。 +8. **机密管理**:生产拒绝默认密码,密钥不进入镜像/前端/日志,使用 Secret 管理并轮换。 +9. **备份与恢复**:数据库、CAS、审计、模板版本一致性备份;实际演练 RPO/RTO。 +10. **验证与发布证据**:需求—设计—测试追溯、迁移报告、权限负例、性能、安全扫描、SBOM、部署/回滚记录。 + +## 15. 分阶段实施路线 + +### Phase 0:决策冻结与安全止血(3–5 天) + +- 冻结新的本地状态功能;明确服务端为唯一权威; +- 从生产 UI 删除任意身份切换和模拟入口; +- 定稿角色、权限、项目成员、文档职责术语; +- 关闭生产默认账号/密码、宽 CORS 和本地认证 fallback; +- 编制所有现有 API 的资源—动作—条件矩阵。 + +完成门禁:生产 bundle 不含切换入口/种子密码;匿名 API 401;跨项目、跨阶段、跨文档负例 403。 + +### Phase 1:账户与授权权威化(2 周) + +- 持久化 users/credentials/sessions/roles/permissions/bindings; +- 实现统一 `AuthorizationService`; +- 把系统设置中的用户和角色操作改成真实 API; +- 建立项目成员 CRUD 与项目角色绑定; +- 前端不再从 localStorage 判定权限,后端返回 capabilities。 + +完成门禁:重启后账户、角色、会话策略仍在;禁用账户立即失效;每个资源动作均有允许/拒绝测试。 + +### Phase 2:工作流设计器与模板库(2–3 周) + +- 建立工作流定义/版本/阶段/文档/策略表; +- 管理端完成草稿、校验、发布、退役; +- 模板上传、扫描、版本和预览; +- 建立医疗器械与非医疗纯软件两套首批工作流; +- 旧静态 catalog 作为 bootstrap seed,运行时改读数据库缓存。 + +完成门禁:已发布版本不可变;旧项目不受新版本影响;非法/死锁工作流不能发布。 + +### Phase 3:项目配置、冻结和阶段门禁(2–3 周) + +- 项目设置独立页面; +- planning、activation preview、二次确认、单活动实例约束; +- 阶段/文档开关和三权分配; +- 文档批准驱动 readiness,创建者确认推进; +- 阶段级聊天、文档、搜索和 Agent 上下文权限。 + +完成门禁:运行中不能选择其他工作流;激活后不能直接改开关/职责;BD 进入研发阶段后无法通过任何接口访问研发内容。 + +### Phase 4:可靠任务、审计与通知(2 周) + +- 持久化任务和事件、重连/重启恢复; +- Outbox 通知、推进卡片、去重和升级; +- 审计日志防篡改、查询和导出; +- stale、责任人失效和配置变更成为正式阻断项。 + +### Phase 5:生产验收与灰度(2 周) + +- 空库/旧库升级双测,备份恢复演练; +- 完整权限矩阵、并发、幂等、故障注入、上传和渗透测试; +- 医疗/非医疗两套黄金项目 E2E; +- test 环境稳定运行一个发布周期,随后灰度 main。 + +按熟悉现有代码的 3–4 人团队估算,发布级闭环约 8–12 周。若只有 1–2 人,应先交付 Phase 0–1 的安全账户/RBAC,再做工作流设计器,不建议把所有能力压缩进一次大改。 + +## 16. 验收测试矩阵 + +### 16.1 身份与权限 + +- 用户不能在 UI、请求头、请求体或 localStorage 中更换自己的身份; +- 修改 URL 中 project/workflow/stage/doc/run ID 不会越权; +- 角色权限变更后旧会话在下一请求即使用新策略; +- 角色删除前能列出用户、项目和工作流策略引用; +- 至少一个超级管理员保护有效,普通管理员不能删除最后一个; +- 同一文档的 author 与 approver 默认不能为同一用户。 + +### 16.2 工作流定义 + +- 草稿可编辑,已发布版本任何更新均被拒绝; +- 模板新版本不改变已激活项目的哈希; +- 零阶段、重复键、无模板、未知角色、无可参与人员、不可达阶段无法发布; +- 退役版本不能用于新项目,但旧实例可继续。 + +### 16.3 项目实例 + +- 新项目初始无 active 工作流; +- 两个并发激活请求最多一个成功; +- 激活预览后配置变化会要求重新确认; +- active 工作流存在时,选择另一个返回 409; +- completed/terminated 后可新建下一实例; +- 激活后关闭阶段/文档、替换模板或直接换责任人均被拒绝。 + +### 16.4 阶段与文档 + +- 任一必需文档未批准、stale、有阻断提案或任务运行中时不能推进; +- 最后一份必需文档批准只产生一个推进待办; +- 创建者确认时条件已变化则不推进; +- 推进事务失败时阶段和权限均保持旧状态; +- BD 在研发阶段的对话、列表、详情、搜索、下载、导出、SSE 和 Agent 工具读取均为拒绝; +- 文档批准绑定内容哈希,批准后内容变化会产生新版本并重新走审核。 + +### 16.5 发布与恢复 + +- 应用/worker/数据库短暂故障不会产生两个终态或丢失推进通知; +- 数据库和 CAS 能从备份恢复到一致点; +- 审计可重建用户、权限、模板、工作流、阶段和签署变更顺序; +- 医疗项目启用所选合规配置的必需节点,非医疗软件不被强制加载法规步骤; +- 生产镜像、配置和数据库没有默认密码或测试身份入口。 + +## 17. 建议优先创建的研发 Epic + +| Epic | 目标 | 依赖 | 优先级 | +|---|---|---|---:| +| IAM-01 持久化账户与会话 | 替换内存用户/token,支持撤销与过期 | DB | P0 | +| AUTHZ-01 权限策略服务 | 服务端 RBAC + 项目/阶段/文档条件 | IAM-01 | P0 | +| UI-01 移除身份模拟与本地权威状态 | 生产 fail closed,权限来自服务端 | IAM-01/AUTHZ-01 | P0 | +| ROLE-01 角色与权限管理 API | 管理端真实持久化、影响分析、绑定 | AUTHZ-01 | P0 | +| WFDEF-01 工作流版本模型 | 定义、阶段、文档、策略、发布 | ROLE-01 | P1 | +| TMPL-01 安全模板库 | 上传、扫描、版本、变量 schema | WFDEF-01 | P1 | +| PTYPE-01 项目类型/合规配置 | 医疗与非医疗首批模型 | WFDEF-01 | P1 | +| WFINST-01 项目配置与激活冻结 | planning、preview、单活、快照 | WFDEF-01/TMPL-01 | P1 | +| DOC-01 文档任务与三权解耦 | 文档任务实例、职责分离、DocGov 接入 | WFINST-01 | P1 | +| STAGE-01 阶段门禁与推进 | readiness、创建者确认、权限原子变化 | DOC-01/AUTHZ-01 | P1 | +| NOTIFY-01 主动提醒 | Outbox、待办、互动卡片、去重升级 | STAGE-01 | P1 | +| RELEASE-01 发布验收 | CI、迁移、恢复、安全、灰度 | 全部 | P0/P1 | + +## 18. 最终建议 + +这次改造不应被理解为“给现有设置弹窗再加几个 Tab”。真正需要建立的是一条不可绕过的权威链:**固定登录主体 → 服务端角色与项目关系 → 已发布工作流版本 → 项目冻结快照 → 阶段与文档状态机 → 责任人签署 → 创建者推进 → 全程审计**。 + +建议先完成账户和授权权威化,再建设工作流设计器。否则管理员即使能在页面上创建角色和流程,服务端仍无法可靠执行这些策略,功能越丰富,越权和状态不一致的风险越大。工作流首期采用线性阶段、单活动实例、激活后严格冻结,是在可用性、实现复杂度和受控性之间最稳妥的平衡。 + +对医疗器械项目,应通过合规配置逐步提高控制强度,并保留适用性评估、版本、审计和签署证据;对非医疗纯软件项目,应复用同一工作流引擎,但允许选择 `compliance_profile=none`,避免把法规流程硬编码进产品域。这样系统才能从当前的医疗器械业务原型,演进为可发布、可扩展、可审计的通用项目工作流平台。 + +## Sources + +[^1]: 仓库源码,[`internal/server/auth_middleware.go`](../internal/server/auth_middleware.go),统一保护非公开 API;[`internal/db/migrate.go`](../internal/db/migrate.go),Goose 迁移执行,访问于 2026-09-11。 +[^2]: 仓库源码,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile),包含 Node 前端构建与 `web/dist` 复制,访问于 2026-09-11。 +[^3]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go),数据库连接、迁移及生产失败关闭逻辑,访问于 2026-09-11。 +[^4]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go) 与 [`internal/auth/service.go`](../internal/auth/service.go),内存用户存储与进程内 token,访问于 2026-09-11。 +[^5]: 仓库源码,[`web/src/App.tsx`](../web/src/App.tsx) 与 [`web/src/data/storage.ts`](../web/src/data/storage.ts),角色、人员、项目和交付物的浏览器持久化,访问于 2026-09-11。 +[^6]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go),管理员接口以 `role-admin` 硬编码判断;[`web/src/components/admin/AdminSettingsModal.tsx`](../web/src/components/admin/AdminSettingsModal.tsx),角色权限编辑主要调用前端状态,访问于 2026-09-11。 +[^7]: 仓库源码,[`internal/projectworkflow/catalog.go`](../internal/projectworkflow/catalog.go),三个静态工作流及单一 stage/task 定义,访问于 2026-09-11。 +[^8]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go) 与 [`deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql`](../deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql),新项目默认 `main` 及当前切换模型,访问于 2026-09-11。 +[^9]: 仓库源码,[`web/src/components/workflow/ProjectWorkflowSwitcher.tsx`](../web/src/components/workflow/ProjectWorkflowSwitcher.tsx),直接切换及冲突后自动重试行为,访问于 2026-09-11。 +[^10]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`web/src/components/project/ProjectMembersModal.tsx`](../web/src/components/project/ProjectMembersModal.tsx),项目成员角色与文档职责混用,访问于 2026-09-11。 +[^11]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`internal/projectworkflow/types.go`](../internal/projectworkflow/types.go),固定阶段枚举和自由文本设备类型,访问于 2026-09-11。 +[^12]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。 +[^13]: NIST, “[Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control),” 含 INCITS 359 RBAC 模型说明,更新于 2026-03-04。 +[^14]: NIST, Kuhn, Coyne, Weil, “[Adding Attributes to Role-Based Access Control](https://csrc.nist.gov/files/pubs/journal/2010/06/adding-attributes-to-rolebased-access-control/final/docs/kuhn-coyne-weil-10.pdf),” 2010。 +[^15]: NIST, “[SP 800-63B-4: Digital Identity Guidelines — Authentication and Authenticator Management](https://csrc.nist.gov/pubs/sp/800/63/B/4/final),” 2025-07。 +[^16]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。 +[^17]: U.S. FDA, “[Quality Management System Regulation (QMSR)](https://www.fda.gov/medical-devices/postmarket-requirements-devices/quality-management-system-regulation-qmsr),” 更新于 2026-02-02。 +[^18]: ISO, “[ISO 13485:2016 — Medical devices — Quality management systems — Requirements for regulatory purposes](https://www.iso.org/standard/59752.html),” 2016,2025 年复审确认。 +[^19]: Electronic Code of Federal Regulations, “[21 CFR § 11.10 — Controls for closed systems](https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-11/subpart-B/section-11.10),” 访问于 2026-09-11。 +[^20]: U.S. FDA, “[Part 11, Electronic Records; Electronic Signatures — Scope and Application](https://www.fda.gov/regulatory-information/search-fda-guidance-documents/part-11-electronic-records-electronic-signatures-scope-and-application),” 2003-09,访问于 2026-09-11。 +[^21]: OWASP Cheat Sheet Series, “[Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html),” 访问于 2026-09-11。 +[^22]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go),当前 CORS 允许任意来源,访问于 2026-09-11。 diff --git a/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md b/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md new file mode 100644 index 00000000..34b343c3 --- /dev/null +++ b/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md @@ -0,0 +1,680 @@ +# 项目全面审计与整改方案 + +> **HISTORICAL** — 缺陷详解与 Phase 设计档案。执行状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 为准。 + +**日期**:2026-09-12 +**编制**:代码审计 +**状态**:待执行 +**范围**:功能完整性、实现缺陷、潜在bug 及整改优先级 + +--- + +## 一、执行现状总结 + +### 1.1 已完成的工作 + +| 项目 | 完成度 | 说明 | +|---|---|---| +| 业务决策文档 | ✅ 100% | `.doc/2026-09-12-three-workflows-strict-governance-remediation.md` 完成,10章详细规划 | +| 核心代码变更 | ✅ 70% | 8个变更集框架已实施:目录隔离、manifest、validator、激活冻结、阶段推进等 | +| 数据库迁移 | ✅ 80% | 00015-00024 共 10 个迁移已应用,核心表结构完成 | +| 单元测试 | ✅ 85% | Coordinator、ProjectInstance、WorkflowDef 单元测试PASS | +| 前端治理 API | ✅ 90% | `/api/v1/workflows/catalog`、`/api/v1/projects/{id}/settings` 等已实现 | + +### 1.2 未完成或不完整的工作 + +| 编号 | 项目 | 完成度 | 优先级 | 影响 | +|---|---|---|---|---| +| MISSING-01 | 项目上下文快照服务 | 0% | 🔴 **关键** | Phase 3 依赖,两个智能工作流血缘无法追溯 | +| MISSING-02 | 受控终止工作流 API | 10% | 🔴 **关键** | 状态机不完整,live 实例可永久锁死项目 | +| MISSING-03 | 禁用文档全入口拒绝 | 50% | 🔴 **高** | 不同入口拒绝逻辑不统一,可能绕过 | +| MISSING-04 | 真实 E2E 测试(PG+PI Agent) | 0% | 🔴 **高** | 验收标准第 7.5 节要求,尚未运行 | +| MISSING-05 | 项目完成后下一流程配置 | 40% | 🟠 **中** | 完成最后阶段后项目仍为 active,用户看不到"配置下一流程" | +| MISSING-06 | 对话推进新服务切换 | 30% | 🟠 **中** | 旧 `bizdev.ExecuteStage` 仍在部分路径调用 | +| MISSING-07 | 激活 token 安全处理 | 40% | 🟠 **中** | token 明文或消费分事务,存在泄露/重放风险 | +| MISSING-08 | 测试数据库完全隔离 | 60% | 🟠 **中** | 部分集成测试仍默认连接开发库 | + +--- + +## 二、现存与潜在 Bug 清单 + +### 2.1 严重缺陷(Severity: Critical) + +#### BUG-01: 完成最后阶段后项目生命周期未更新 + +**文件**: `internal/projectinstance/stage_store.go:128-158`, `internal/projectinstance/service.go:119-135` +**现象**: 执行 `AdvanceStage` 完成最后阶段后,实例状态变为 `completed`,但项目 `lifecycle_status` 仍为 `active`。 + +**代码现场**: +```go +// stage_store.go:AdvanceStage +after, err := s.store.AdvanceStage(ctx, instanceID, in.StageKey, in.ExpectedConfigRevision) +// ... 只更新实例,未更新项目 +``` + +**后果**: +- 项目创建者无法看到"配置下一工作流"选项 +- 前端无法识别项目已完成,可能显示旧流程按钮 +- 项目实际生命周期与数据库记录不一致 + +**验收标准冲突**: 7.4 "最后一阶段确认后实例为 completed,项目立即可配置下一流程" + +**整改方案**: +1. `AdvanceStage` 在同一事务中检查是否为最后阶段 +2. 若是最后阶段,同时更新 `projects.lifecycle_status` 为 `planning` +3. 清空 `projects.current_workflow_instance_id`(可选,视数据模型) +4. 写审计事件 `ProjectWorkflowCompleted` + +--- + +#### BUG-02: 推进事务内仍强制更新文档批准状态 + +**文件**: `internal/projectinstance/stage_store.go:71-158` +**现象**: 执行阶段推进时,SQL 语句中有类似逻辑将启用任务的文档强制设置为 `approved`。 + +**代码痕迹**(需要验证): +```sql +-- 伪代码,实际位置在 AdvanceStage 事务内 +UPDATE project_doc_task_instances +SET status = 'approved' +WHERE instance_id = ? AND task_key = ? AND enabled = true; +``` + +**后果**: +- 违反业务规则 3.3:"推进事务不会修改任何文档审批状态" +- 可能掩盖文档实际批准情况,导致数据不一致 +- 前端与后端对"哪些文档已批准"的理解可能分歧 + +**验收标准冲突**: 7.4 "推进事务不会修改任何文档审批状态" + +**整改方案**: +1. 确认 `stage_store.go:AdvanceStage` 中是否存在此 UPDATE 逻辑 +2. 若存在,删除该 UPDATE 语句 +3. `AdvanceStage` 只改变阶段状态和实例状态,不触及文档 +4. 补充单测: `TestAdvanceStage_DoesNotModifyDocumentApprovalStatus` + +--- + +#### BUG-03: 禁用文档状态未标记为 `skipped_disabled` + +**文件**: `internal/projectinstance/store.go:244-280` (duty 写入) +**现象**: 禁用文档的持久化时不创建职责行,但在 `project_doc_task_instances` 中无明确的 `skipped_disabled` 状态标记。 + +**代码现场**: +```go +// store.go:SaveWorkflowPlan 或类似 +for _, doc := range docs { + if !doc.Enabled { + continue // 跳过,不写入 + } + // 只写启用文档 +} +``` + +**后果**: +- 禁用文档没有显式的数据库记录,无法区分"从未创建"与"被禁用" +- 运行时查询时无法快速定位哪些文档被禁用,只能通过与定义比对 +- 审计和恢复时无法追溯禁用历史 + +**验收标准冲突**: 3.2 "禁用后实例状态写为 `skipped_disabled`" + +**整改方案**: +1. `project_doc_task_instances` 表添加状态枚举支持 `skipped_disabled` +2. 激活时为禁用文档创建记录,状态明确设为 `skipped_disabled` +3. 查询、拒绝等所有入口统一检查此状态 +4. 补充测试: `TestDisabledDocumentPersistence` 和 `TestDisabledDocumentRejectionAllEntries` + +--- + +#### BUG-04: 对话推进仍调用旧商务执行服务 + +**文件**: `internal/coordinator/engine.go:672-811` +**现象**: 对话识别 `ADVANCE_STAGE` 意图后,调用 `bizdevSvc.ExecuteStage` 而非新的 `projectinstance.Service.AdvanceStage`。 + +**代码现场**: +```go +// engine.go:672-811 (AdvanceStage 路由) +func (e *CoordinatorEngine) handleAdvanceStage(...) { + // ... + result, err := e.bizdevSvc.ExecuteStage(ctx, ...) // ❌ 旧服务 + // 应该调用 e.instSvc.AdvanceStage(...) +} +``` + +**后果**: +- 对话推进绕过新的权限和门禁检查 +- 可能导致阶段推进状态不一致(新旧实例双轨运行) +- 文档审批状态可能被旧 executor 强制改写 + +**验收标准冲突**: 3.4 "两种入口都调用同一个 `AdvanceStage` 应用服务" + +**整改方案**: +1. 修改 `CoordinatorEngine.handleAdvanceStage` 以调用新服务 +2. 删除对 `bizdevSvc.ExecuteStage` 的依赖(或标记 deprecated) +3. 对话推进需要提取 `workflow_instance_id`(可从项目或上文获取) +4. 补充端到端测试: `TestDialogueAdvanceStage_UsesNewService` + +--- + +### 2.2 高优先级缺陷(Severity: High) + +#### BUG-05: 禁用文档的拒绝逻辑不一致 + +**文件**: 多处 +**现象**: 不同入口(API、SSE、Agent tool)对禁用文档的拒绝逻辑分散,缺少统一的"fail closed"决策器。 + +**问题点**: +- `stage_access.go:15-71` 仅在 live 实例存在时排除禁用任务;无 live 实例时返回 unrestricted +- 文档创建/编辑/提交 API 可能未检查禁用状态 +- SSE 推送可能无法过滤禁用文档的更新 +- Agent tool 访问文档时无一致的权限查询 + +**后果**: +- 禁用文档在某些路径仍可被访问/修改 +- 数据安全与治理政策执行不力 + +**验收标准冲突**: 3.2 "禁用后…不能通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动" + +**整改方案**: +1. 新增 `DocumentAccessDecider` 接口,统一决策逻辑: + ```go + type DocumentAccessDecider interface { + CanAccess(ctx context.Context, docTaskInstID int64, action string, userID int64) (bool, error) + } + ``` +2. 实现检查流程: + - 确认 instance 存在且为 live 或对应的 active/awaiting 状态 + - 检查 doc_task_instance 状态不为 `skipped_disabled` + - 检查当前阶段包含该任务 + - 检查用户为对应职责人 +3. 在所有入口(API、SSE、异步任务、搜索、导出、RAG、Agent tool)使用此决策器 +4. 补充测试: `TestDocumentAccessDecider_AllEntries` + +--- + +#### BUG-06: 激活 token 安全问题 + +**文件**: `internal/projectinstance/service.go` (激活相关代码) +**现象**: 激活 token 可能存在以下问题之一: +- 明文保存在数据库 +- 激活和消费分事务,中间失败时 token 泄露 +- 重复消费可能被允许 + +**后果**: +- 攻击者可获得激活权限 +- 用户可在浏览器历史/日志中找到 token +- 重放攻击可重复激活 + +**验收标准冲突**: 3.1 "激活时冻结…运行中不可静默修改" 的先决条件是原子激活 + +**整改方案**: +1. 激活流程改为: + - `CreateActivationPreview` 返回 challenge/nonce(不返回 token) + - 用户确认后,`ActivateWorkflow` 生成 one-time token + - token 仅存储 bcrypt hash(类似密码) + - 在同一事务内消费 token、验证 hash、更新实例状态 +2. token 过期时间设为 5 分钟 +3. 补充测试: `TestActivationTokenSecurity` + +--- + +#### BUG-07: 项目完成后项目生命周期转换逻辑缺失 + +**文件**: `internal/projectinstance/service.go`, `internal/projectworkflow/service.go` +**现象**: 完成一个工作流后,项目无法自动进入可选择下一工作流的状态。 + +**代码现场**: +```go +// projectinstance/service.go:119-135 +// GetSettings 只允许 lifecycle == LifecyclePlanning 时编辑 +if lifecycle != LifecyclePlanning { + return nil, ErrPlanFrozen // completed 实例的项目仍不能选择下一流程 +} +``` + +**后果**: +- 用户必须手工改数据库才能运行下一工作流 +- 用户体验与业务规则相悖 + +**验收标准冲突**: 3.1 "完成或受控终止后创建下一工作流实例" + +**整改方案**: +1. 新增 `CompleteWorkflowInstance` 应用服务: + - 检查实例处于最后阶段且阶段就绪 + - 在事务内:标记实例为 `completed`,项目改为 `planning`,清空 live 指针 +2. `AdvanceStage` 检查当前阶段是否为最后阶段,是则调用此服务 +3. 补充测试: `TestProjectLifecycleAfterCompletion` + +--- + +### 2.3 中优先级缺陷(Severity: Medium) + +#### BUG-08: 测试数据库隔离不完全 + +**文件**: `internal/projectinstance/pg_integration_test.go:19-49`,`internal/server/workflow_governance_pg_test.go:26-61` +**现象**: 集成测试未设置 `TEST_DATABASE_URL` 时默认连接本地开发库,导致测试数据污染。 + +**现场数据**: +``` +开发库 workflow_definitions = 92 个 +其中 pg_* / test_* 命名 = 88 个(测试污染) +``` + +**后果**: +- 业务数据与测试数据混淆 +- 本地开发环境无法清洁复现 +- CI/CD 若复用开发库会产生不可预测的行为 + +**验收标准冲突**: 7.5 "测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义" + +**整改方案**: +1. 所有 `*_test.go` 中强制要求 `TEST_DATABASE_URL`;未设置时 skip 或 fatal +2. 测试前创建隔离 schema 或独立库,测试后清理 +3. CI 配置中显式设置 `TEST_DATABASE_URL` 指向临时数据库 +4. 补充 CI 脚本检查:测试结束后确认开发库中无 `pg_*`、`test_*` 定义 + +--- + +#### BUG-09: 版本冲突时前端自动重试 + +**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:38-76,173-236` +**现象**: 当两个浏览器同时切换工作流时,第一个返回版本冲突,但前端自动取新版本再次提交,无需用户确认。 + +**代码现场**: +```typescript +// ProjectWorkflowSwitcher.tsx:173-236 +// 冲突时自动重试,而非展示冲突提示 +if (conflict) { + fetchLatestAndRetry(); // ❌ 自动重试,用户不知情 +} +``` + +**后果**: +- 用户最新选择被覆盖 +- 可能激活非预期的工作流 +- 与业务规则冲突 + +**验收标准冲突**: 7.2 "两个浏览器同时配置或推进时…另一个收到版本冲突并重新确认" + +**整改方案**: +1. 冲突时展示弹窗:"您的选择与其他编辑冲突,请重新确认" +2. 显示当前版本、冲突版本和新版本内容 +3. 用户确认后重新提交,而非自动重试 +4. 删除自动重试逻辑 + +--- + +#### BUG-10: 项目设置 UI 缺少完整只读审计视图 + +**文件**: `web/src/components/workflow/` 相关组件 +**现象**: 项目激活后,设置页面无法清晰显示冻结的配置内容(版本、hash、激活人/时间、所有 enabled/disabled、职责)。 + +**后果**: +- 创建者不知道实际冻结的是什么 +- 无法自助诊断权限问题 +- 审计信息不可见 + +**验收标准冲突**: 7.2 "live 配置缺少完整只读审计视图" + +**整改方案**: +1. 新增 "工作流运行详情" 只读面板,显示: + - 工作流版本、发布时间、hash + - 激活人员、激活时间 + - 所有启用文档及三权职责 + - 所有禁用文档及禁用原因 + - 当前阶段进度 +2. 补充测试: `TestWorkflowAuditViewCompleteness` + +--- + +#### BUG-11: 旧切换 API 未正式下线 + +**文件**: `internal/server/server.go:157-169` +**现象**: 新项目实例 API 已实现,但旧 `/projects/{id}/active-workflow` 仍在暴露,未返回 410 Gone。 + +**代码现场**: +```go +// server.go:157-169 +mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ❌ 仍暴露 +``` + +**后次**: +- 旧客户端可绕过新治理 +- 不能区分"不支持"与"已下线" + +**验收标准冲突**: 5 "旧服务端路由…应返回 `410 WORKFLOW_SWITCH_API_RETIRED`" + +**整改方案**: +1. 将 `/projects/{id}/active-workflow` 路由改为返回 410 Gone 和迁移指引 +2. 添加 deprecation 日志 +3. 补充测试: `TestLegacyAPIReturns410` + +--- + +### 2.4 低优先级缺陷(Severity: Low) + +#### BUG-12: 前端名称不一致 + +**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23` +**现象**: 前端硬编码的三个工作流名称与后端正式名称不一致。 + +**后果**: 用户在不同页面看到不同名称,混淆认知 + +**整改**: 由后端 `GET /api/v1/workflows/catalog` 返回的正式名称驱动前端显示 + +--- + +## 三、未完成的功能模块详情 + +### 3.1 项目上下文快照服务(ProjectContextSnapshot) + +**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:82-105` +**当前状态**: 规划完整,实现 0% +**关键要求**: + +1. **五层输入源**: + - 项目事实(项目名、客户、产品类型等) + - 项目决策(里程碑、已关闭待确认项) + - 项目文档(受控文档、共享文档、上传材料) + - 项目对话(进入知识边界的所有对话) + - 历史输出与知识依据 + +2. **不可变快照**: + - `project_context_snapshots` 表:记录项目、任务、截止时间、汇总 hash、创建人、冻结状态 + - `project_context_snapshot_sources` 表:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用 + +3. **冲突优先级**: + - 创建者确认事实/决策 > 已批准文档 > 上传材料 > 里程碑记录 > 普通对话 > 智能体总结 + +4. **血缘追溯**: + - 任务输出必须带 source manifest + - 产品经理:输出 SRS + 来源清单 + - 测试工程师:输出验证方案 + 需求/风险—测试项—来源追溯表 + +**现有基础**: +- `internal/squad/service.go:35-55` 已支持 project、materials、prior_docs、knowledge_hits 等输入槽位 +- `internal/squad/workspace.go:262-408` 已有 context 索引建立能力 +- `internal/bizdev/service.go:250-294` 已有部分项目事实输入逻辑 + +**整改方案**: +1. 新增 `internal/projectcontext/service.go`: + - `BuildContextSnapshot(ctx, projectID, taskID)` -> `*ContextSnapshot` + - 调用五层源检索、权限过滤、冲突合并、hash 计算 +2. 新增数据库表与迁移 +3. 产品经理与测试工程师都改用此服务 +4. 补充集成测试 + +**验收标准**: 7.5 +- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致 +- 产品经理/测试工程师输出中包含完整 source manifest 和被排除内容说明 + +--- + +### 3.2 受控终止工作流(WorkflowTermination) + +**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:109-131` (状态机) +**当前状态**: 状态表存在,API 和逻辑 0% +**关键要求**: + +1. **状态转换**: + ``` + active → termination_requested → terminated + ``` + +2. **操作约束**: + - 仅创建者可申请 + - 需二次确认 + - 需填写原因 + - 处理或取消在途任务 + - 生成审计 + +3. **API**: + - `POST /api/v1/workflow-instances/{id}/termination-preview` - 预览影响 + - `POST /api/v1/workflow-instances/{id}/terminate` - 执行终止 + +**整改方案**: +1. 新增 `internal/projectinstance/terminate.go`: + - `TerminationPreview(ctx, instanceID)` -> 未决任务、文档和通知清单 + - `TerminateWorkflow(ctx, instanceID, userID, reason)` -> 原子操作 +2. 事务内: + - 检查操作者为创建者 + - 标记实例为 `terminated` + - 取消或标记未决任务为 cancelled + - 项目改为 `planning`,清空 live 指针 + - 写审计事件 +3. 补充 API 路由和端到端测试 + +**验收标准**: 7.3 +- 创建者可以选择"受控终止"而非永久锁死 +- terminated 状态的项目可创建下一实例 +- 审计记录包含终止原因 + +--- + +### 3.3 真实 E2E 测试(PostgreSQL + PI Agent) + +**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459` (验收标准) +**当前状态**: 单元测试 PASS,E2E 0% +**要求**: + +1. 使用真实 PostgreSQL(不是内存 mock) +2. 使用真实 PI Agent 容器 +3. 完整链路: + - 创建项目 → 选择工作流 → 激活 → 推进各阶段 → 完成 → 配置下一工作流 +4. 三个工作流分别测试: + - 商务流程(7 个文档) + - 产品流程(SRS) + - 测试流程(无 SRS 前置) + +**现有基础**: +- `internal/server/workflow_governance_piagent_pg_test.go` 已有 PG 集成框架 +- PI Agent 容器已在 `docker-compose.yml` 中定义 + +**整改方案**: +1. 新增 `internal/server/e2e_workflow_test.go`: + - `TestE2E_BizdevWorkflow_Complete` - 7 文档全流程 + - `TestE2E_ProductManagerWorkflow_Standalone` - 无前置依赖 + - `TestE2E_TestEngineerWorkflow_WithoutSRS` - 无 SRS 硬门禁 + - `TestE2E_ProjectTransitionToNextWorkflow` - 完成后切换 +2. 设置 `TEST_DATABASE_URL` 指向隔离库 +3. 启动 PI Agent 容器(或 mock 其接口) +4. 逐步执行,记录结果 + +**验收标准**: 7.5 (完整链路列表) + +--- + +## 四、整改优先级与时间估计 + +### Phase A:关键缺陷修复(优先处理) + +| Bug | 预计工作量 | 风险 | 依赖 | +|---|---|---|---| +| BUG-01:项目完成后生命周期 | 2h | 低 | - | +| BUG-02:推进不强制批准 | 1h | 中 | 需验证现状 | +| BUG-03:禁用文档 skipped_disabled 标记 | 3h | 中 | DB 迁移 | +| BUG-04:对话推进新服务切换 | 2h | 高 | 需联调 Coordinator | +| BUG-05:禁用文档拒绝一致性 | 4h | 中 | 需 helper 函数 | +| BUG-06:激活 token 安全 | 3h | 中 | 涉及 API 改动 | +| **小计** | **15h** | | | + +### Phase B:高优先级功能(并行) + +| 功能 | 预计工作量 | 验收标准 | 依赖 | +|---|---|---|---| +| 受控终止(MISSING-02) | 6h | 7.3 | BUG-01 | +| 真实 E2E 测试(MISSING-04) | 8h | 7.5 | Phase A + 容器 | +| 项目上下文快照(MISSING-01) | 12h | 7.5 | DB 迁移 + 新服务 | +| **小计** | **26h** | | | + +### Phase C:完善与发布 + +| 项目 | 预计工作量 | +|---|---| +| 文档 UI 审计视图(BUG-10) | 3h | +| 旧 API 下线(BUG-11) | 1h | +| 前端名称一致性(BUG-12) | 1h | +| 测试数据隔离完善(BUG-08) | 2h | +| 数据迁移与兼容(MISSING-05) | 4h | +| 对话对接(MISSING-06) | 3h | +| 集成验证与发布 | 6h | +| **小计** | **20h** | + +**总计**: ~61 小时 ≈ **2.5 天(单人全职)**或 **5 天(双人)** + +--- + +## 五、整改执行计划 + +### 5.1 Day 1: 关键缺陷修复 + +**Morning (4h)**: +1. BUG-01 修复:AdvanceStage → 同事务更新项目生命周期 + - 修改 `stage_store.go` 和 `service.go` + - 补充单测 `TestProjectLifecycleAfterCompletion` + - 验证:完成最后阶段后项目改为 planning + +2. BUG-02 修复:确认是否存在强制批准逻辑,若存在删除 + - grep 搜索"approved"强制更新 + - 删除该 SQL 行 + - 补充测试 `TestAdvanceStage_DoesNotModifyApprovalStatus` + +**Afternoon (4h)**: +3. BUG-04 修复:对话推进切换到新服务 + - 修改 `coordinator/engine.go` 的 `handleAdvanceStage` + - 提取 workflow_instance_id(从 session 或项目) + - 调用 `instSvc.AdvanceStage` 替代 `bizdevSvc.ExecuteStage` + - 补充对话测试 + +4. BUG-06 开始:激活 token 安全重构 + - 设计 one-time token 与 hash 方案 + - 修改激活预览与激活 API + +### 5.2 Day 2: 继续缺陷修复 + 开始新功能 + +**Morning (4h)**: +5. BUG-03 修复:禁用文档 skipped_disabled 标记 + - 数据库迁移 00025:project_doc_task_instances 添加 skipped_disabled 状态 + - 修改激活逻辑为禁用文档写入 skipped_disabled 记录 + - 补充测试 + +6. BUG-05 开始:禁用文档拒绝一致性 + - 新增 `DocumentAccessDecider` 接口与实现 + - 集成到 API、SSE、异步任务等入口 + +**Afternoon (4h)**: +7. 受控终止开发(MISSING-02) + - 新增 `terminate.go` 服务 + - 实现终止预览和执行 API + - 补充测试 + +### 5.3 Day 3: 新功能开发与集成测试 + +**Full Day (8h)**: +8. 项目上下文快照初版(MISSING-01) + - 新增 `projectcontext/service.go` + - 实现快照构建与来源清单 + - 产品/测试工程师改用新服务 + +9. 真实 E2E 测试启动(MISSING-04) + - 编写 E2E 测试框架 + - 三个工作流链路验证 + - 文档与验证报告 + +--- + +## 六、质量保证与验收检查表 + +### 6.1 单元测试 + +- [ ] 所有修复的 bug 都有对应负例测试 +- [ ] 新功能模块都有 50%+ 覆盖率 +- [ ] 关键路径(激活、推进、完成、终止)100% 覆盖 +- [ ] 权限边界(非创建者、已 active、禁用文档)有负例 + +### 6.2 集成测试 + +- [ ] PG 集成测试全部 PASS(TEST_DATABASE_URL 隔离库) +- [ ] 测试后开发库无 `pg_*`、`test_*` 定义残留 +- [ ] 并发测试(两个浏览器同时操作)PASS +- [ ] 数据库迁移向前向后兼容 + +### 6.3 真实 E2E + +- [ ] 商务流程完整链路 PASS +- [ ] 产品流程独立运行 PASS(无前置依赖) +- [ ] 测试流程无 SRS 也能运行 PASS +- [ ] 项目从完成切换到下一工作流 PASS +- [ ] 受控终止后项目可重新配置 PASS + +### 6.4 验收标准 + +- [ ] 目录仅暴露三项正式工作流 +- [ ] 禁用文档全入口(API、对话、SSE、Agent tool)拒绝 +- [ ] 推进事务不改文档审批状态 +- [ ] 项目完成后立即可配置下一工作流 +- [ ] 对话推进使用新实例服务 +- [ ] 激活 token 原子且安全 +- [ ] 旧 API 返回 410 Gone + +--- + +## 七、风险预案 + +### Risk-1: 激活 token 改动影响现有流程 + +**应对**: 先保留双通道(新旧),shadow 运行,验证一致后下线旧通道 + +### Risk-2: 数据库迁移引入兼容性问题 + +**应对**: 新增迁移前备份数据库;迁移脚本包含回滚逻辑;测试向后兼容 + +### Risk-3: 对话推进改动影响用户体验 + +**应对**: 对话测试覆盖完整,先内测验证;保留原意图识别,改调用目标 + +--- + +## 八、文档与交付物清单 + +| 交付物 | 格式 | 目标受众 | +|---|---|---| +| 整改方案(本文档) | Markdown | 开发、QA、产品 | +| 单元测试新增用例 | Go test | 开发 | +| E2E 测试报告 | Markdown + 日志 | QA、产品 | +| 数据库迁移脚本 | SQL | DBA、开发 | +| API 文档更新 | OpenAPI / Markdown | 前端、集成方 | +| 项目上下文快照设计文档 | Markdown | 架构评审 | +| 发布说明 | Markdown | 用户、销售 | + +--- + +## 九、总结与建议 + +### 当前项目整体评估 + +| 方面 | 评分 | 说明 | +|---|---|---| +| **架构与设计** | 8/10 | 三工作流治理顶层决策清晰,状态机设计合理 | +| **实现完整度** | 5/10 | 核心框架 70%,关键功能(快照、终止)缺失,多个 bug | +| **代码质量** | 6/10 | 单元测试 OK,缺失 E2E;对话-服务耦合待解 | +| **数据一致性** | 4/10 | 项目生命周期转换不完整,禁用文档没有显式标记 | +| **安全性** | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 | +| **运维成熟度** | 6/10 | DB 迁移和测试隔离需完善 | + +### 建议 + +1. **优先完成 Phase A 缺陷修复**(2 天)以稳定当前功能 +2. **并行开发 Phase B 新功能**(3 天),特别是 E2E 测试以验证整体逻辑 +3. **建立自动化验收流程**:CI 应包括所有验收标准的检查 +4. **后续维护建议**: + - 禁用项目选择非正式工作流的自动检查(CI 中) + - 每次激活/推进/完成后都输出审计链(便于故障排查) + - 项目完成前端页面加"确认完成工作流"的双确认卡 + - 定期数据库快照与清理脚本(防止垃圾数据) + +--- + +**文档版本**: v1.0 +**最后更新**: 2026-09-12 14:45 UTC +**下一步**: 待产品&技术评审确认,进入实施阶段 diff --git a/.doc/remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md b/.doc/remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md new file mode 100644 index 00000000..92b1fd41 --- /dev/null +++ b/.doc/remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md @@ -0,0 +1,706 @@ +# Agent System 权限、设置与三类工作流完整实施方案 + +## 1. 执行结论 + +当前系统已经完成了从原型向受控工作流平台演进所需的多数“结构件”:数据库账户与会话、系统角色/权限表、项目成员、工作流定义及版本、模板版本、项目工作流实例、阶段实例、文档任务实例、三权职责、激活确认、阶段推进请求、通知 Outbox、任务运行持久化和文档血缘均已存在。现有 Go 短测、前端测试和生产构建也能通过。因此,本轮不应推倒重做,而应完成最后一段也是最关键的一段:**统一授权权威、把设置真正落到服务端、让已发布工作流版本成为运行时唯一事实源,并将商务对接、智能产品经理、智能测试经理发布为可配置、可冻结、可执行、可审计的正式工作流。**[^1][^2][^3] + +但截至本次审计,系统还不能宣称“权限和设置已做全”,三个工作流也还不能按当前治理设计直接投入多人生产使用。核心原因如下: + +1. **权限表存在,但策略执行不完整。** 部分项目查询、工作流历史和血缘查询缺少对象级授权;创建项目只校验登录,不校验 `project:create`;工作流管理 API 仍统一要求超级管理员,未使用已入库的细粒度权限;系统权限计算还忽略绑定作用域、角色状态和 `valid_from`。[^4][^5][^6] +2. **阶段权限存在高风险放行路径。** 解析 live 实例发生数据库错误时会回退为“不限制”,多个列表、聊天、RAG/上下文过滤辅助函数也在错误时放行;拥有当前阶段任一文档职责的用户会获得该阶段全部文档任务权限,任务执行门禁还允许其运行任意 `task_key`。[^7][^8] +3. **设置界面与服务端权威尚未闭环。** 浏览器仍把 Bearer token 和会话对象放入 `localStorage`,登出只删除本地状态;个人资料保存、个人偏好和部分权限画像仍是前端本地数据,已有活动会话 API 未在用户设置中形成闭环。[^9][^10] +4. **三个工作流只是“登记过”,不是“完整接入”。** `main`、`product_manager`、`test_manager` 已作为发布种子存在,但都是单阶段包装;运行目录会把任意已发布版本压扁为第一阶段的第一个任务。商务对接真实的 V0.1/V0.5/V1.0 阶段仍硬编码在 BizDev 执行器中;产品经理和测试经理的五步 Agent 流程存在,但没有由版本化定义驱动。[^11][^12][^13] +5. **项目实例与文档治理还未成为同一条链。** 规划校验没有检查必需阶段/必需任务是否被整个遗漏,也没有校验三权人员是否为有效项目成员;实例持久化把所有阶段 `position` 写成 0;执行器又会在请求未传三权时回退到固定用户 2/3,并把文档阶段固定为 `V0.5_feasibility`,没有消费冻结实例中的职责和活动阶段。[^14][^15] + +因此建议把工作拆为三道发布闸门: + +- **闸门 A:授权止血。** 先关闭跨项目读取、错误放行、任意任务键、身份/会话本地权威等 P0;完成全部 API/数据通路的策略矩阵。 +- **闸门 B:配置与运行时合流。** 扩展工作流 schema,建立 `executor_key` 注册表和全阶段解释器,让项目实例、DocGov、任务运行、对话/RAG、文档血缘都从同一冻结快照取值。 +- **闸门 C:发布三个正式版本。** 以新版本而不是覆盖旧数据的方式发布三个工作流,完成迁移、真实 PostgreSQL、跨用户负例和真实 PI Agent E2E 后再开放生产选择。 + +本方案遵循当前系统已经确定的治理原则:生产身份只来自服务端会话;系统角色、项目角色和单文档三权职责分离;已发布版本不可原地修改;项目激活时冻结完整快照;同一项目只允许一个 live 工作流;当前流程完成或受控终止后才能选择下一个;门禁满足只发提醒,阶段推进必须由项目创建人明确确认。[^1] + +## 2. 本次研究范围与验证边界 + +### 2.1 已审阅范围 + +| 层 | 已审阅内容 | +|---|---| +| 数据库 | Goose `00014`–`00020`:成员、IAM、工作流/模板、项目实例、通知、任务运行 | +| 后端 | `internal/auth`、`authz`、`workflowdef`、`projectinstance`、`projectworkflow`、`bizdev`、`squad`、`server` | +| 前端 | 登录会话、RBAC 类型、用户设置、系统设置、项目设置、工作流切换/展示 | +| 业务执行 | 商务对接真实阶段;产品经理/测试经理 Agent 角色、步骤、模板、质量门禁、前置依赖和血缘 | +| 既有文档 | 2026-09-11 治理总方案、Phase 1/2 实施计划、当前 PG/CI/Soak/E2E 报告 | + +### 2.2 本轮已执行验证 + +```text +go test -short -timeout 8m \ + ./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \ + ./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/... +结果:全部通过 + +cd web && npm test +结果:170 项 Node tests + 22 项 Vitest tests 全部通过 + +cd web && npm run build +结果:TypeScript + Vite 构建通过;存在主 bundle 过大的非阻断警告 +``` + +这些结果证明当前分支能编译且现有回归未破坏,不证明跨租户授权、真实 PostgreSQL 事务、重启恢复和真实 PI Agent 长链路已满足本方案的发布门禁。当前测试报告中 PI Agent 全生命周期仍记录了 `/v1/run` 超时,且报告结尾又写“仍在运行”,应先修正文档状态,再以一次新的、带 commit SHA 和环境指纹的运行作为验收证据。[^16] + +### 2.3 外部设计基线 + +授权采用“默认拒绝、每次请求验证、对象标识不可猜测越权、失败安全退出、记录审计”的基线;动态项目、阶段和文档条件用 RBAC + ReBAC + ABAC 组合,而不是只靠全局角色。OWASP 明确建议默认拒绝并对每次请求执行权限判断;NIST RBAC 模型把用户、角色、权限、操作和对象建模为独立关系,并支持职责分离约束。[^17][^18] + +浏览器会话不再把认证 token 放在 `localStorage`。OWASP 指出 Web Storage 可被同源 JavaScript 读取,建议会话使用 `HttpOnly; Secure; SameSite` Cookie;Cookie 模式下同时补齐 CSRF 防护。[^19] + +## 3. 当前系统能力盘点 + +### 3.1 可以直接保留并扩展的能力 + +| 能力 | 当前状态 | 本方案处理 | +|---|---|---| +| 统一 API 认证中间件 | 已存在 | 保留;切换到安全 Cookie/CSRF,并在授权失败时统一错误模型 | +| 数据库账户、密码哈希、会话哈希 | 已存在 | 保留;增加密码/MFA/重置策略、会话前端闭环和安全事件 | +| 系统角色/权限/绑定 | 已存在 | 纠正多角色、作用域、有效期、状态和管理审计语义 | +| `project_members` | 已存在 | 增加 FK、项目业务角色多绑定、成员状态和职责候选资格 | +| 工作流草稿/发布/退役 | 后端基础存在 | 增加复制草稿、完整 schema、细粒度授权、发布影响预览和 UI | +| 模板 CAS/版本/扫描状态 | 基础存在 | 增加扫描 worker、隔离区、预览、发布/退役和引用影响分析 | +| 项目规划/预览/确认/冻结 | 基础存在 | 修复完整性校验、原子 token、阶段顺序、受控变更和下一个工作流 | +| 文档三权状态机 | 已存在 | 由实例职责驱动;加职责资格、再认证/签署策略和阶段门禁映射 | +| Outbox/通知/阶段推进请求 | 已存在 | 完成用户偏好、渠道、升级、去重和创建人确认体验 | +| 任务运行持久化/lease | 已存在 | 把任务与实例/阶段/任务定义绑定;细分 read/cancel/resume 权限 | +| 文档血缘/stale | 已存在 | stale 成为阶段退出阻断条件,提供影响分析和重新基线闭环 | + +### 3.2 当前成熟度判定 + +| 领域 | 代码骨架 | 服务端权威 | 前端闭环 | 生产验收 | 判定 | +|---|---:|---:|---:|---:|---| +| 认证与会话 | 高 | 中 | 低 | 中 | 需整改 | +| 系统 RBAC | 中 | 低 | 中 | 低 | 发布阻断 | +| 项目 ReBAC | 中 | 中 | 中 | 低 | 发布阻断 | +| 阶段/文档 ABAC | 中 | 低 | 中 | 低 | 发布阻断 | +| 用户设置 | 中 | 低 | 中 | 低 | 未做全 | +| 系统设置 | 中 | 中 | 中 | 低 | 未做全 | +| 项目设置 | 中高 | 中 | 中 | 低 | 关键断点 | +| 工作流设计/版本 | 中高 | 中 | 低 | 低 | 关键断点 | +| 三工作流执行器 | 高 | 低 | 中 | 低 | 尚未正式接入 | +| 审计与通知 | 中 | 中 | 低 | 低 | 尚未闭环 | + +## 4. 必须优先修复的问题清单 + +### 4.1 P0:在接入三个工作流前必须关闭 + +| ID | 问题 | 影响 | 整改与验收 | +|---|---|---|---| +| AUTH-001 | 工作流运行历史、文档血缘 handler 未调用项目对象授权 | 登录用户可能读取其他项目元数据/血缘 | 所有项目子路由统一经过资源加载 + `Authorize`;跨项目返回 404 或统一 403;加双用户 PG 负例 | +| AUTH-002 | 阶段访问解析或过滤出错时放行 | DB/策略故障可扩大文档、聊天、RAG、Agent 上下文可见范围 | 生产环境 fail closed;只对明确标记的 legacy 项目执行迁移期策略,且有截止版本和指标 | +| AUTH-003 | 工作流路由接受客户端覆盖 `task_key`;阶段成员可运行当前阶段任意任务 | 绕过工作流定义和文档职责 | 服务端只从 `workflow_instance_id + active_stage + task_instance_id` 推导 executor;拒绝不在快照中的任务 | +| AUTH-004 | 项目规划可以整个遗漏必需阶段/任务 | 可激活空壳或删减受控交付物的计划 | 对定义中每个 non-optional stage 和 required/blocking task 做反向完整性校验 | +| AUTH-005 | 三权用户未校验有效账户、项目成员和候选角色 | 可把无权或已停用用户写入审批链 | 激活前逐人校验 membership/status/eligibility/职责分离;激活后人员失效触发阻断事件 | +| AUTH-006 | 项目列表 SQL 把 `creator_id=1`/NULL 项目视为公开,旧切换逻辑有固定用户/项目 ID 豁免 | 演示兼容规则泄漏到真实授权 | 删除 ID 特判;显式 `project_visibility`/legacy migration,不以 creator ID 表达公开 | +| AUTH-007 | 项目创建接口未检查 `project:create` | 任意活动账户可立项 | handler/service 双层校验 `projects.create`,前端按钮仅作体验控制 | +| AUTH-008 | 项目成员可读取/取消其他成员任务运行,未区分动作 | 破坏他人运行和审计归属 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` 分权;取消他人任务须负责人或创建人 | +| AUTH-009 | 本地 token、仅本地 logout、失效 `/me` 后仍保留登录态 | XSS/撤销后前端假登录 | 改安全 Cookie;服务端 logout;`/me` 401 立即清空主体和缓存;权限加载失败敏感动作 fail closed | +| WF-001 | DBCatalog 将完整版本压扁为第一阶段第一任务 | 发布多阶段定义也不会按定义运行 | 移除 flatten 执行路径,新增实例编排器逐阶段/任务读取冻结快照 | +| WF-002 | DocGov 三权和阶段来自请求/固定默认值,不来自实例 | 配置的责任人和活动阶段不生效 | 由 `doc_task_instance_id` 解析 author/reviewer/approver/stage;禁止生产请求传入身份覆盖 | + +### 4.2 P1:首次正式发布必须完成 + +| ID | 问题 | 整改 | +|---|---|---| +| IAM-101 | `ListCapabilities` 忽略 `scope_type/scope_id`、角色状态和 `valid_from` | 引入带资源上下文的 PDP;系统能力只取 `scope_type=system, scope_id=0`,校验角色/账户/有效期 | +| IAM-102 | `users.role_id` 与 `user_role_bindings` 双权威,更新角色会删除其他绑定 | `user_role_bindings` 为唯一权威;`users.role_id` 只作迁移兼容后移除;支持多角色 | +| IAM-103 | `assigned_by` 被写成目标用户本身,角色+状态更新非原子且忽略角色更新错误 | 从 principal 传 actor;单事务变更;写不可变审计事件;失败整体回滚 | +| IAM-104 | `role-admin` 字符串直接赋予管理员身份,`perm:manage` 又作为所有权限通配 | 显式 `system.superadmin`;普通 `permissions.manage` 不再通配业务数据;至少两名受控管理员防死锁 | +| IAM-105 | 前端权限键只有最早 7 项,后端迁移已有更多权限 | 后端暴露 permission catalog;前端由 API 渲染,不维护硬编码联合类型作为事实源 | +| SET-101 | 用户资料保存只改 React state;偏好仅组件本地;活动会话 UI 缺失 | 增加 `/me/profile`、`/me/preferences`、`/me/notification-preferences` 和会话管理 UI | +| SET-102 | 管理中心工作流页只能列出/校验/发布,不能完整建模 | 增加创建、复制草稿、阶段排序、任务/职责/参与策略、模板选择、diff、发布、退役 | +| SET-103 | Office 模板进入 `pending` 后缺少扫描完成链 | 隔离上传 + scanner worker + 状态回调/轮询;只有 `ready` 可发布 | +| SET-104 | UI 宣称符合 21 CFR Part 11,但未实现电子签名控制 | 删除不实文案;如需合规,另立 e-sign scope(再认证、签署含义、签名绑定、审计、防篡改) | +| WF-101 | 所有阶段实例 `position=0` | 从定义快照持久化真实 position;增加唯一性与连续性校验 | +| WF-102 | 激活 token 明文保存且消费、激活非同一事务 | 仅存 token hash;`SELECT FOR UPDATE` 后在同一事务验证、消费和激活 | +| WF-103 | 推进会把全部启用任务强制标成 approved | 推进只允许已满足门禁的状态,不修正业务状态;不一致即事务失败 | +| WF-104 | stale 未纳入阶段门禁 | required upstream/downstream lineage 有 stale 时禁止推进,重新批准后清除 stale 并留痕 | +| WF-105 | 完成后缺少“选择下一工作流”与受控终止/变更 API | 实现 `completed/termination_requested/terminated` 全状态机及下一实例创建 | +| WF-106 | bootstrap 发现已有 published 版本就退出 | 种子升级采用显式版本 manifest;内容 hash 变化创建 v2 draft,经校验批准后发布 | + +### 4.3 P2:可在首发后持续增强 + +- 管理员 break-glass:理由、近期认证、限时、醒目标识、禁止代签、完整审计。 +- MFA/WebAuthn、企业 SSO/SCIM、组织层级和角色层级。 +- 策略模拟器、权限差异比较、定期访问复核和孤儿权限报告。 +- 工作流可视化 DAG;首版仍建议坚持线性阶段,减少编排复杂度。 +- 审计日志防篡改、WORM/外部归档和监管报表。 + +## 5. 目标授权架构 + +### 5.1 五层判定模型 + +每个敏感动作统一调用一个服务端策略决策点(PDP),判定表达式为: + +```text +ALLOW = authenticated(principal) + AND account.active + AND session.active + AND permission_allows(action, resource_type, scope) + AND project_relationship_allows(principal, project) + AND workflow_snapshot_policy_allows(principal, active_instance, stage) + AND document_policy_allows(principal, doc_task, document) + AND state_machine_allows(action, current_state) + AND separation_of_duty_allows(principal, action) + +unknown / missing policy / dependency error => DENY +``` + +| 层 | 回答的问题 | 数据权威 | +|---|---|---| +| 认证 | 这个请求是谁,账号/会话是否有效 | `users`、`auth_sessions` | +| 系统 RBAC | 是否具备创建、管理、发布、审计等平台动作 | role/permission/binding 表 | +| 项目 ReBAC | 是否属于该项目,承担哪些项目业务角色 | `project_members` + `project_role_bindings` | +| 工作流/阶段 ABAC | 当前实例、阶段、参与策略是否允许 | 冻结 `config_snapshot` + 实例状态 | +| 文档职责/状态 | 是否为该文档的编制/审核/批准人,当前状态能否执行动作 | `document_duty_assignments` + DocGov | + +### 5.2 角色分层 + +系统角色不再表达具体项目里的业务职责,项目角色也不再等同于某一份文档的三权。 + +| 范围 | 建议内置角色 | 用途 | +|---|---|---| +| 系统 | 超级管理员、安全管理员、用户管理员、工作流管理员、模板管理员、安全审计员、普通用户 | 平台配置和治理;业务项目数据不因管理员身份默认全开 | +| 项目 | 项目创建人、项目经理、商务 BD、产品经理、系统/研发工程师、测试、法规、QA、观察者 | 阶段参与、项目资料范围和业务动作候选资格 | +| 文档 | author、reviewer、approver | 绑定单个文档任务实例;必须是具体用户,默认互斥 | + +一个用户可以在同一项目绑定多个业务角色;角色绑定和文档职责均必须有 `valid_from/valid_until/status/assigned_by/reason`。静态职责分离在配置时阻止冲突,动态职责分离在动作时阻止同一主体对同一版本自审自批。 + +### 5.3 权限目录 + +权限键统一采用 `resource.action`,旧键通过一版兼容映射迁移,之后删除。建议首发目录: + +| 域 | 权限 | +|---|---| +| 系统 | `system.settings.view/manage`、`system.security.manage`、`system.audit.view/export` | +| 用户 | `users.view/create/edit/disable/reset_password`、`users.sessions.revoke` | +| 角色 | `roles.view/create/edit/retire/assign/review` | +| 工作流 | `workflow_defs.view/create/edit_draft/publish/retire`、`workflow_defs.impact_view` | +| 模板 | `templates.view/upload/download/publish/retire` | +| 项目 | `projects.create/view/edit/archive`、`projects.members.view/manage` | +| 项目流程 | `projects.workflow.view/configure/activate/terminate`、`projects.stage.advance` | +| 参与 | `workflow.chat.view/send`、`workflow.task.run`、`workflow.progress.view` | +| 任务运行 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` | +| 文档 | `documents.view/edit/submit/review/approve/export`、`documents.visibility.manage` | +| 通知 | `notifications.view/update`、`notification_policies.manage` | + +### 5.4 服务端执行点 + +不要在每个 handler 手写角色判断。建立: + +```go +Decision Authorize(ctx, Principal, Action, ResourceRef, Attributes) + +Decision { + Allowed bool + ReasonCode string + PolicyVersion string + Obligations []string // redact, require_recent_auth, audit_reason, etc. +} +``` + +- 路由中间件负责身份和粗粒度权限。 +- service 层在事务内重新验证对象关系和当前状态,防止 TOCTOU。 +- repository 查询默认带可见范围,不先查全量再在浏览器过滤。 +- SSE、附件下载、搜索、导出、RAG、Agent tools 使用同一个 `ResourceRef`/Decision。 +- 禁止把 `user_id`、`role`、`stage`、`work_dir` 或 duty 作为客户端可信授权输入。 +- 403/404 策略统一;审计记录 actor、resource、action、decision、reason、request_id、policy_version。 + +### 5.5 核心动作矩阵 + +| 动作 | 普通成员 | 项目业务角色 | 项目创建人 | 系统管理角色 | 文档三权 | +|---|---|---|---|---|---| +| 创建项目 | 需 `projects.create` | 同左 | 同左 | 不默认拥有,按绑定 | 无关 | +| 查看项目 | active membership | active membership | 是 | 仅 break-glass 或显式审计权限 | 无关 | +| 管理成员 | 否 | 项目经理可选 | 是 | break-glass | 无关 | +| 配置待激活流程 | 否 | 可提议 | 是 | 工作流管理员不能代替业务确认 | 无关 | +| 激活/终止流程 | 否 | 可申请 | 是 + 再确认 | 只可 break-glass | 无关 | +| 运行任务 | 否 | 阶段策略允许 + 对应 task permission | 同策略,不绕过 | 不默认 | author 或显式执行人 | +| 查看文档 | 文档策略允许 | 阶段/角色策略允许 | 仍受私密/合规策略 | 不默认 | 当前职责人允许 | +| 提交审核 | 否 | 否 | 不默认 | 不默认 | author | +| 审核 | 否 | 否 | 不默认 | 不默认 | reviewer 且非 author | +| 批准 | 否 | 否 | 不默认 | 不默认 | approver 且非 author/reviewer | +| 推进阶段 | 否 | 只能申请/接收提醒 | 明确确认 | 不替代业务确认 | 无关 | +| 发布工作流版本 | 否 | 否 | 无关 | 工作流发布权限 + 双人复核可选 | 无关 | + +## 6. 设置体系完整方案 + +### 6.1 用户设置 `/settings` + +| 页面 | 服务端能力 | 验收 | +|---|---|---| +| 个人资料 | `GET/PATCH /api/v1/me/profile`;姓名、邮箱、语言、时区;部门/工号受控只读 | 刷新、换设备仍一致;审计敏感字段变更 | +| 安全 | 修改密码、MFA 状态、活动会话、撤销其他会话、最近登录 | 修改密码撤销其他会话;撤销后下一请求 401 | +| 通知 | 站内/邮件渠道、事件类型、免打扰、升级策略 | Outbox 读取服务端偏好;关键审批提醒不可被完全关闭 | +| 偏好 | 主题、默认导出、语言、默认项目页、Agent 显示偏好 | 落库并有 schema 版本;不再只存在组件 state | +| 我的权限 | 服务端返回生效角色、作用域、有效期和权限来源 | 不由前端本地 role 推导;支持“为何有/无此权限” | + +安全会话改造:登录响应通过 `Set-Cookie: __Host-agent_session=...; Secure; HttpOnly; SameSite=Lax|Strict; Path=/` 建立会话;状态变更使用 CSRF token/origin 验证;logout 调服务端撤销当前会话。测试环境可通过独立 fixture 获取 Cookie,不在产品包保留任意身份切换。 + +### 6.2 项目设置 `/projects/{id}/settings` + +| 页面 | planning | active/awaiting | completed/terminated | +|---|---|---|---| +| 基本信息 | 创建人编辑 | 受控字段变更单 | 只读/归档 | +| 成员与业务角色 | 增删改,校验职责候选 | 变更需影响分析;不能留下无人职责 | 历史只读,可为下个实例配置 | +| 工作流选择 | 选已发布版本 | 冻结只读 | 可创建下一个 planning 实例 | +| 阶段/任务 | 配置 optional/default,required 不可关闭 | 冻结;仅受控变更 | 快照只读 | +| 模板版本 | 从 ready 版本选择 | 冻结 | 快照只读 | +| 三权职责 | 必填、互斥、成员/资格校验 | 变更单 + 未决审批处理 | 历史只读 | +| 参与/可见策略 | 从版本默认值继承,可按允许范围收紧 | 冻结;紧急收紧可走安全变更 | 历史只读 | +| 预览与激活 | diff + 门禁 + 二次确认 | 不显示“重新激活” | 显示下一流程入口 | +| 推进/终止 | 无 | 门禁满足后创建人确认;终止需原因/影响 | 展示完整审计 | + +项目创建人不是系统超级管理员。项目设置的“独占确认权”和系统权限的“是否允许操作接口”同时成立:例如可由项目经理编辑草案,但最终激活和阶段推进仍由创建人确认。 + +### 6.3 系统管理中心 `/admin/*` + +| 页面 | 必做功能 | +|---|---| +| 概览 | 服务/DB/Runner/Outbox/worker 健康、失败任务、待审批、策略版本 | +| 用户 | 创建、审批、启停、资料、重置密码、撤销会话、多角色绑定、批量导入 | +| 角色权限 | 权限目录、多角色、作用域、有效期、职责分离、影响预览、角色退役 | +| 工作流设计器 | 创建/复制草稿、阶段排序、任务、执行器、模板、输入输出、门禁、职责候选、参与/可见策略、校验、diff、发布、退役 | +| 模板库 | 隔离上传、扫描、预览、变量 schema、版本、发布/退役、引用关系 | +| 项目类型与合规 | `product_domain` 与 `compliance_profile` 分离;可用流程、必需文档和签署强度 | +| 通知自动化 | 事件、渠道、模板、频率、升级和去重 | +| 审计 | 按 actor/action/resource/result/request_id 查询和导出;高风险变更对比 | +| 安全 | 注册、审批、密码、MFA、会话时限、CSRF/CORS、上传限制、保留期、break-glass | + +管理端不能继续依赖硬编码权限清单。`GET /api/v1/admin/permissions` 返回目录和风险等级;每个页面使用服务端 capabilities 控制入口,但最终仍由 API 决策。 + +## 7. 工作流定义 Schema v2 + +现有 schema 只有阶段、位置、人工门禁和文档任务基本字段,无法表达运行绑定、参与策略、职责资格、输入输出和确定性质量门禁。建议新增 `schema_version: 2`: + +```json +{ + "schema_version": 2, + "workflow_key": "product_manager", + "product_domains": ["medical_device", "non_medical_software"], + "required_upstream": [], + "participation_policy": {}, + "completion_policy": {}, + "stages": [{ + "key": "requirements_baseline", + "name": "系统需求基线", + "position": 10, + "optional": false, + "entry_gate": {}, + "exit_gate": {}, + "participation_policy": {}, + "doc_tasks": [{ + "key": "system_reqs", + "executor_key": "squad.system_reqs.v1", + "required": true, + "blocking": true, + "template": {"asset_key": "system_reqs", "version": 2}, + "input_contract": {}, + "output_contract": {}, + "quality_gate_key": "quality.system_reqs.v2", + "eligible_project_roles": {}, + "visibility_policy": {}, + "retry_policy": {}, + "timeout_seconds": 3600 + }] + }] +} +``` + +发布校验必须至少验证: + +- key 格式和全局唯一;stage position 唯一且严格递增;必需阶段/任务不可缺失; +- `executor_key` 已注册且声明支持相应输入/输出;不再把未知任务落入 generic runner; +- template version 存在且 `scan_status=ready`,变量 schema 与 input contract 一致; +- 三权候选角色存在,且不会造成项目无人可配;author/reviewer/approver 默认互斥; +- 上游工作流和文档依赖无环、能解析到已发布版本; +- 每个 required/blocking task 有确定性质量门禁; +- 可见/参与策略有明确默认值,未知即拒绝; +- 发布后 definition JSON/hash 和所有引用版本不可变;编辑从已发布版本复制新 draft。 + +## 8. 三个工作流的正式定义 + +### 8.1 兼容性决定 + +当前项目和代码广泛使用 `main` 代表商务主线。首轮迁移**保留稳定 key `main`**,显示名统一为“商务对接”,避免破坏存量项目、任务记录和文档 ID;停止在新代码里把它解释成“任意默认流程”。`product_manager` 和 `test_manager` 保持现有 key。若未来希望改为 `business_engagement`,新增显式 alias 表,不直接改历史 key。 + +三个正式版本均以 v2 draft 创建和发布;不得修改已有 published v1,也不得依赖当前 `UpsertPublishedSeed` 自动覆盖。已 active 的 v1 项目继续使用原快照;planning 项目由创建人查看 diff 后主动升级。 + +### 8.2 商务对接 `main` v2 + +当前真实执行器已有以下阶段和任务,本方案将其搬入版本定义,执行器只保留能力注册,不再保留另一套阶段事实源。[^13] + +| 顺序 | 阶段 | 文档任务 | 必需/阻断 | 建议三权候选 | 退出门禁 | +|---:|---|---|---|---|---| +| 10 | `V0.1_triage` 闪电摸底与盲区探测 | `intake` 客户需求采集/初始需求表 | 是/是 | author: BD/PM;reviewer: 项目经理;approver: 创建人或商务负责人 | intake approved;关键项无缺失;无运行任务 | +| 20 | `V0.5_feasibility` 方案成型与法规对齐 | `research` 竞品调研;`feasibility_reg` 法规可行性;`prelim_design` 初步设计 | 全部是/是 | 按文档分别指派 BD、法规、研发;审核/批准分离 | 三文档 approved;无 stale/open change;entry inputs 已基线化 | +| 30 | `V1.0_quoting` 工程拆解与商业锁定 | `cdo_quote` CDO 报价与核算 | 是/是 | author: 商务/项目经理;reviewer: 技术/财务;approver: 创建人/授权商务负责人 | 正文和核算 XLSX hash 一致、approved;报价关键字段完整 | + +参与策略默认值: + +- BD 可参与 V0.1/V0.5 的 `intake/research`,不因“是项目成员”自动获得 `prelim_design` 或报价批准权。 +- 法规只访问被授权的法规任务及其显式上游;研发只访问初步设计及显式上游。 +- 创建人可看项目进度并确认推进,但不会自动获得某份文档的审核/批准动作。 +- 阶段完成只产生 `ready_to_advance` 通知;创建人确认后原子进入下一阶段。 + +### 8.3 智能产品经理 `product_manager` v2 + +项目层保持一个受控阶段,阶段内的五个 Agent step 是 executor 内部步骤,不把内部 agent step 误建成五个需要人工推进的项目阶段。现有代码已经定义需求梳理、系统工程、法规、成文、终审五角色和五步执行链,可直接注册为 `squad.system_reqs.v1`。[^20] + +| 项 | 正式配置 | +|---|---| +| 阶段 | `requirements_baseline` 系统需求基线,position=10,required/blocking | +| 文档任务 | `system_reqs`,输出受控《系统需求规格书》 | +| 执行器 | `squad.system_reqs.v1` | +| 模板 | `system_reqs` ready version;发布时固定版本 | +| 必需输入 | 项目五要素;已批准/显式基线化的客户需求或上游商务文档;项目材料清单 | +| 结构化输出 | `output.md`、`artifacts/requirements.json`、manifest/hash、质量报告 | +| 三权候选 | author: PM/系统工程;reviewer: 技术负责人/法规;approver: 创建人授权的批准人/QA | +| 质量门禁 v2 | 每条需求唯一 ID;来源、理由、优先级、可验证准则、验证方法齐全;无未替换占位;JSON 与正文一致;重复/冲突/孤儿需求为 0 | +| 完成门禁 | executor 成功 + deterministic gate 通过 + 文档 approved + 无 stale/open change/running task | + +当前质量门禁只检查正文中是否出现 `REQ-` 和宽泛的“测试/分析/审查”等词,达不到“需求集合完整、唯一、可追溯、可测”的正式门禁。v2 必须解析 `requirements.json`,以结构化集合为准,并把校验报告与文档版本绑定。[^21] + +### 8.4 智能测试经理 `test_manager` v2 + +| 项 | 正式配置 | +|---|---| +| 阶段 | `system_verification_planning` 系统验证策划,position=10,required/blocking | +| 文档任务 | `test_manager`,输出受控《系统验证方案及计划》 | +| 执行器 | `squad.test_manager.v1` | +| 上游条件 | 同项目最近一次已批准且非 stale 的 `system_reqs`;记录上游 doc/version/hash | +| 模板 | `test_manager` ready version;发布时固定版本 | +| 结构化输出 | `output.md`、必需的 `artifacts/test_cases.json`、coverage report、manifest/hash | +| 三权候选 | author: 测试;reviewer: 系统/法规;approver: 测试负责人/QA,三者互斥 | +| 质量门禁 v2 | 上游需求全集解析成功;每条 requirement 至少一条有效 case;case ID 唯一;步骤、预期、判据、环境、方法完整;覆盖率 100%;无孤儿引用 | +| stale 策略 | 上游 SR hash 变化立即将下游标为 stale,禁止提交/批准/阶段完成,完成影响分析与重新基线后解除 | + +现有 executor 已要求上游 SR approved 并建立血缘,也定义了 100% 覆盖的 Agent 目标;但当前确定性门禁只检查 `TC-/TEST-`、`REQ-` 字符串,并且 `test_cases.json` 仅在文件存在时校验 JSON,文件不存在不会失败。v2 必须把结构化用例文件和覆盖率报告设为必需产物。[^21][^22] + +### 8.5 三个工作流的串联语义 + +系统当前设计是“一项目最多一个 live 工作流”,不是三条流程同时 active: + +```text +商务对接 completed/受控 terminated + -> 创建人选择并配置 product_manager v2 + -> 产品经理流程 completed,系统需求 approved + -> 创建人选择并配置 test_manager v2 + -> 测试经理流程完成 +``` + +系统可以在前一流程门禁满足时推荐下一个流程并通知创建人,但绝不自动激活。上游依赖解析按文档类型 + workflow instance + approved version 查询,不依赖固定文件路径或仅由字符串拼出的 doc ID。 + +## 9. 配置到运行时的唯一权威链 + +必须建立以下单向链,禁止旁路: + +```text +published workflow version + ready template versions + ↓ creator configures / preview / confirms +immutable project workflow snapshot + ↓ creates ordered stage/task instances + duty assignments +active stage + authorized doc task instance + ↓ resolves executor, template, inputs, actor obligations +task run + DocGov document version + lineage + audit + ↓ deterministic gate + three-duty approval + no stale/open work +ready_to_advance notification + ↓ creator explicit confirmation +next stage OR workflow completed +``` + +具体约束: + +1. `POST task-runs` 接收 `doc_task_instance_id` 和业务输入,不接收可信 `user_id/role/stage/work_dir/reviewer_id/approver_id`。 +2. 服务端锁定实例和 task instance,验证 active stage、actor、executor、模板和当前状态。 +3. WorkDir 由服务端按 project/instance/task_run 生成并做路径约束。 +4. DocGov 从 duty assignment 创建/校验文档责任人,stage 来自 stage instance。 +5. 任务结果写入与运行终态、文档版本、manifest、lineage、outbox 使用事务/可恢复 saga,避免“显示完成但产物未落稳”。 +6. 列表、详情、导出、附件、搜索、SSE、RAG 和 Agent tool read 都使用同一资源授权上下文。 + +## 10. 数据库迁移方案 + +迁移号以合并时最新 Goose 版本为准,下表暂按 `00021+` 表示。 + +| 迁移 | 主要变更 | 兼容/回填 | +|---|---|---| +| 00021 IAM hardening | project_members.user_id FK;role/binding 状态、reason;审计 actor;权限键 alias | 校验孤儿成员后加 FK;旧 `users.role_id` 双读一版、停止写入 | +| 00022 project roles | `project_roles`、`project_role_permissions`、`project_user_role_bindings` | owner/member/viewer 映射为 owner/contributor/observer;原表保留 membership 状态 | +| 00023 settings | user preferences、notification preferences、security policy versions | 把可识别的 local preferences 一次性导入需用户确认;其余使用服务端默认 | +| 00024 workflow schema v2 | executor registry/version、schema fields、policy JSON schema/version | 不修改 v1 JSON;validator 按 schema_version 路由 | +| 00025 instance integrity | stage position、task executor/template/output snapshot、duty eligibility、change requests | 修正现有 position;对 active 数据先报告后修复,不静默重排 | +| 00026 authorization audit | `authorization_audit_events` 或统一 audit_event 扩展、policy version、request ID | 明确保留期和敏感字段脱敏 | +| 00027 workflow v2 manifests | 创建三个 v2 draft/版本 manifest | 只在 hash 匹配预期时创建;不覆盖用户自定义版本 | + +数据库约束建议: + +- live instance 部分唯一索引继续保留;增加 planning 与 live 状态转换约束测试。 +- `project_stage_instances(workflow_instance_id, position)` unique,position > 0。 +- task instance 保存 `executor_key/template_version/output_doc_type/quality_gate_key` 的冻结副本。 +- duty assignment 引用 active project membership;跨表动态条件用事务 trigger 或 service + deferred validation 实现。 +- activation token 只存 hash;高风险一次性 token 使用短 TTL、actor/project/plan hash 绑定。 +- published definition/template 通过数据库权限或 trigger 阻止 UPDATE/DELETE,不只依赖 Go service。 + +## 11. API 调整 + +### 11.1 身份与设置 + +```text +POST /api/v1/auth/login -> Set-Cookie +POST /api/v1/auth/logout -> revoke current session +GET /api/v1/me +PATCH /api/v1/me/profile +GET/PUT /api/v1/me/preferences +GET/PUT /api/v1/me/notification-preferences +GET /api/v1/me/sessions +DELETE /api/v1/me/sessions/{id} +POST /api/v1/me/password/change +``` + +### 11.2 权限与管理 + +```text +GET /api/v1/admin/permissions +GET/POST/PATCH /api/v1/admin/roles... +GET/POST/DELETE /api/v1/admin/role-bindings... +POST /api/v1/admin/authorization/simulate +GET /api/v1/admin/audit-events +POST /api/v1/admin/users/{id}/reset-password +POST /api/v1/admin/users/{id}/sessions/revoke +``` + +每个 admin endpoint 绑定独立 permission,不再通过 `requireSystemAdmin` 全包。 + +### 11.3 工作流与项目实例 + +```text +POST /api/v1/admin/workflows/{id}/versions/{v}/copy-draft +PATCH /api/v1/admin/workflows/{id}/versions/{v} +POST /api/v1/admin/workflows/{id}/versions/{v}/validate +GET /api/v1/admin/workflows/{id}/versions/{v}/impact +POST /api/v1/admin/workflows/{id}/versions/{v}/publish +POST /api/v1/admin/workflows/{id}/versions/{v}/retire + +GET/PUT /api/v1/projects/{id}/workflow-plan +POST /api/v1/projects/{id}/workflow-plan/preview +POST /api/v1/projects/{id}/workflow-plan/activate +POST /api/v1/projects/{id}/workflow-instances/{iid}/termination-requests +POST /api/v1/projects/{id}/workflow-instances/{iid}/terminate +POST /api/v1/projects/{id}/workflow-instances/{iid}/change-requests +POST /api/v1/projects/{id}/workflow-instances/{iid}/stages/{stage}/advance +POST /api/v1/projects/{id}/doc-tasks/{taskInstanceId}/runs +``` + +所有资源路径先验证 path 中 project/instance/stage/task/document 的归属一致性,避免用合法项目权限访问另一个项目的子资源。 + +## 12. 前端实施方案 + +1. **认证壳**:不从 `localStorage` 恢复 principal/token;启动时只调用 `/me`。401 清空全部敏感状态并跳转登录。 +2. **权限 Provider**:从 `/me` 获取 capabilities + scoped grants;按钮、菜单和路由只做 UX 控制,错误统一展示服务端 reason code。 +3. **用户设置**:现有 modal 拆到真实 API;接入活动会话;资料/偏好保存失败不更新本地成功态。 +4. **系统管理中心**:从单一大 modal 演进为路由页面;权限矩阵来自 catalog;高风险变更提供 diff、影响人数和二次确认。 +5. **工作流设计器**:线性阶段排序、每阶段多任务、executor 只从注册表下拉、模板版本选择、职责候选、参与/可见策略、JSON 高级视图、发布校验报告。 +6. **项目设置**:明确 planning/live/history 三态;live 快照只读;门禁列表展示每个阻断项;下一工作流必须由创建人确认。 +7. **工作台**:根据服务端返回的 allowed actions 渲染,不在前端用姓名/本地角色重新计算业务授权。 +8. **删除演练入口**:`UserProjectRightsModal` 的测试角色切换、旧 `SettingsModal`、本地模拟分支和生产 bundle 中的测试身份文案移出产品代码。 + +## 13. 分阶段交付计划 + +估时为单个熟悉代码库的小组工作日,安全修复与工作流建模可并行开发,但发布必须按闸门顺序。 + +### Phase 0:基线冻结与权限清单(1–2 天) + +- 固定 commit、DB schema、环境和三个 workflow v1 hash。 +- 自动导出全部 `/api/v1` 路由,建立 resource/action/owner/negative test 矩阵。 +- 修正当前 E2E 报告状态矛盾;归档一次干净的 short test 和 build 结果。 +- 输出:`authorization-matrix-v2.md`、migration preflight SQL、测试数据拓扑。 + +门禁:每个非公开路由都有责任 owner、策略和至少一个未授权负例;未知路由默认为拒绝。 + +### Phase 1:P0 授权止血(3–5 天) + +- 修复 AUTH-001–009、WF-001/002 的越权入口。 +- 建立统一 `Authorize`/ResourceRef 和 server-side allowed actions。 +- 删除固定管理员/演示项目 ID 豁免;生产禁用 permissive fallback。 +- Cookie/CSRF/logout/401 前端失效闭环。 + +门禁:匿名、跨用户、跨项目、跨阶段、错 task、错 child resource、DB authz fault 全部负例通过;SSE/RAG/Agent tool 同样验证。 + +### Phase 2:IAM 与设置权威化(4–6 天) + +- 完成 IAM-101–105 和用户/项目/系统设置 API。 +- 角色多绑定、作用域/有效期、permission catalog、原子用户变更和审计。 +- 用户资料、偏好、通知、活动会话 UI;管理中心权限拆分。 + +门禁:重启/换浏览器数据一致;权限收回和账号停用下一请求生效;至少两名管理员防锁死演练通过。 + +### Phase 3:工作流 Schema v2 与运行时合流(5–8 天) + +- 实现 schema v2、executor/quality gate registry、完整 validator。 +- 移除 `flattenVersion` 作为执行路径;编排器只读实例快照。 +- 修复 position、token 原子性、DocGov duty/stage 绑定、stale 门禁。 +- 完成受控终止、变更单和下一个工作流生命周期。 + +门禁:修改全局 published/latest 不影响 active 实例;请求伪造 stage/task/duty 无效;故障恢复后实例位置和职责不漂移。 + +### Phase 4:发布三个 v2 工作流(4–6 天) + +- 按 §8 创建 `main`、`product_manager`、`test_manager` v2 draft。 +- 绑定 ready 模板和 executor;补齐结构化门禁。 +- 对 planning v1 项目生成可读 diff,由创建人选择是否升级;active v1 不迁移。 +- 完成三个流程的串联推荐,但保持人工选择/激活。 + +门禁:三个版本通过静态校验、dry-run、单流程 PG E2E 和串联 PG E2E。 + +### Phase 5:管理端/项目端完整体验(4–6 天) + +- 工作流设计器、模板库、项目规划、门禁详情、影响预览、下一流程、终止/变更 UI。 +- 删除旧本地/演示权威路径和不实合规文案。 +- 可访问性、错误恢复、并发 diff/reconfirm。 + +门禁:产品经理无需改代码即可复制 v2 为 v3 草案、换模板/职责候选、校验并由有权者发布;普通管理员无法越权发布。 + +### Phase 6:发布验证与灰度(5–8 天) + +- 全量 Go/前端、race、PG、迁移升级/回滚、重启、worker 故障注入。 +- 真实 PI Agent 三工作流 E2E;长任务超时/恢复/取消;跨用户负例。 +- 备份恢复、日志脱敏、监控告警、容量和 bundle 分包。 +- 灰度一个内部项目,再扩到新项目;旧项目只读兼容指标归零后删除 fallback。 + +门禁:§14 全部完成;P0/P1 为 0;可恢复演练和回滚演练均有报告。 + +总体建议:**21–35 个小组工作日**。如多人并行,最短日历时间约 4–5 周;不应通过跳过负例、迁移和真实 Runner 验证压缩关键路径。 + +## 14. 测试与验收矩阵 + +### 14.1 授权负例 + +| 场景 | 预期 | +|---|---| +| 未登录访问任意非公开 API/SSE/附件 | 401,不泄漏资源存在性 | +| A 项目成员读 B 项目、run history、lineage、搜索、导出 | 403/404,审计 deny | +| 当前阶段 BD 请求研发 task key | 403;不创建 task_run/workdir/doc | +| 非职责人提交/审核/批准 | 403;状态、版本、审计不变 | +| author 尝试审核或批准同一版本 | 409/403 SoD violation | +| authz DB/策略加载故障 | 敏感路径拒绝,健康状态 degraded,触发告警 | +| 权限撤销后复用旧页面/旧 SSE/旧 Cookie | 下一次鉴权失败;流关闭或重新鉴权 | +| 猜测 task/document/template/blob ID | 不能跨项目读取 | +| 客户端伪造 user/role/stage/workdir/duty | 服务端忽略或 400;不得改变判定 | + +### 14.2 工作流配置与冻结 + +- v2 required stage/task 被遗漏、禁用、重复或错序时校验失败。 +- executor 未注册、模板非 ready、变量 schema 不匹配时禁止发布。 +- published version UPDATE/DELETE 在 service 和 DB 层均失败。 +- 激活 token 重放、过期、跨 actor、跨 project、plan hash 不同均失败。 +- 并发保存/激活/推进只成功一个;另一方收到 diff/reconfirm,不自动重试。 +- 修改 v3 不影响使用 v2 的 active 项目;历史 hash 可复算。 +- 流程未完成/未终止时不能创建第二个 live;完成后可配置下一个 planning。 + +### 14.3 三工作流 E2E + +**商务对接:** 按 V0.1 → V0.5 三任务 → V1.0 运行;每阶段文档分别走三权;未全部 approved 不产生 ready;满足后产生一次去重提醒;只有创建人确认推进。 + +**智能产品经理:** 从批准的输入基线生成 `requirements.json` 和正文;随机抽取、重复 ID、缺验证准则、正文/JSON 不一致均被确定性门禁拒绝;批准后可作为下游输入。 + +**智能测试经理:** 没有 approved SR、SR stale、hash 不匹配时拒绝启动;生成必需 `test_cases.json`;需求全集覆盖率必须 100%;上游更新后下游立即 stale 且不能完成。 + +**串联:** `main` 完成后只推荐 PM;创建人配置并激活;PM 完成后只推荐 Test;每个实例版本、模板、职责、输入 hash、输出 hash 和审计链可追溯。 + +### 14.4 运行与灾难恢复 + +- 应用、worker、PostgreSQL、PI Runner 分别重启,验证会话/任务/实例/Outbox 恢复。 +- PI Runner 超时后 task 可恢复或明确失败,不重复生成审批版本。 +- Outbox 重投不重复发阶段提醒;消费者幂等。 +- 迁移从 v20 的生产快照升级;备份恢复后 hash/权限/实例一致。 +- `go test -race`、前端测试、生产 build、依赖/镜像扫描、长期 soak。 + +## 15. 发布完成定义(Definition of Done) + +只有同时满足以下条件,才能宣布“权限、设置和三个工作流已按当前设计做全”: + +- [ ] 生产产品不存在任意身份切换、本地认证 fallback 或客户端身份权威。 +- [ ] 每个 API/SSE/RAG/Agent tool/附件通路都有服务端授权和跨用户负例。 +- [ ] 授权失败或依赖异常默认拒绝;不存在固定用户 ID、项目 ID 特权。 +- [ ] 系统角色、项目业务角色、文档三权分离且可审计;三权职责分离生效。 +- [ ] 用户、项目、系统三类设置均由服务端持久化,刷新/重启/换端一致。 +- [ ] 工作流、模板、权限管理使用各自细粒度 permission,而不是全员超级管理员。 +- [ ] 已发布工作流/模板不可变;项目激活冻结版本、模板、阶段、任务、策略和职责。 +- [ ] 同一项目最多一个 live;完成/受控终止后由创建人选择下一个。 +- [ ] 门禁满足只通知,不自动推进;创建人确认与推进在事务中完成。 +- [ ] `main` v2 完整执行 V0.1/V0.5/V1.0,不再由硬编码目录另行决定。 +- [ ] `product_manager` v2 结构化需求门禁通过;`test_manager` v2 实现 100% 需求覆盖和 stale 阻断。 +- [ ] DocGov 的 stage 和三权全部来自冻结实例,客户端不能覆盖。 +- [ ] PG、真实 PI Agent、重启恢复、故障注入、跨项目/跨阶段负例均有可复现报告。 +- [ ] P0/P1 缺陷归零,灰度/回滚/监控/告警和审计查询可用。 + +## 16. 风险与控制 + +| 风险 | 概率/影响 | 控制 | +|---|---|---| +| v1/v2 双执行权威并存 | 高/高 | feature flag 只选一个 orchestrator;记录每次 run 的 schema/executor/version;不静默 fallback | +| 存量项目职责/成员数据不完整 | 高/中 | preflight 报告;active 不强迁;planning 由创建人补全并确认 | +| 权限收紧影响现有演示项目 | 高/中 | 显式 legacy visibility 数据迁移;不保留 ID 豁免;灰度观察 deny 指标 | +| Cookie 改造引入 CSRF | 中/高 | SameSite + CSRF token + Origin/Referer 校验;状态变更不用 GET | +| 长 Agent 运行与 HTTP 超时 | 高/高 | 异步 task + lease/heartbeat + resumable worker;客户端订阅状态,不持有超长请求 | +| 结构化质量门禁误报 | 中/中 | schema version、明确错误定位、golden corpus、允许修复重跑但不可人工静默跳过 | +| 角色配置锁死管理员 | 中/高 | 双管理员、关键权限不可清空、变更影响预览、break-glass 离线流程 | +| 模板恶意文件/解析炸弹 | 中/高 | 隔离、扩展/MIME/签名、大小/解压限制、扫描、Web root 外 CAS;仅 ready 可引用 | + +## 17. 建议的首个迭代任务包 + +第一周不要先画完整工作流设计器,先完成以下可独立验收的任务: + +1. `AUTH-001`:给 run history/lineage 及所有项目子资源补统一对象授权和双用户 PG 负例。 +2. `AUTH-002`:阶段访问错误全部 fail closed,加入数据库故障注入测试。 +3. `AUTH-003`:workflow run/task run 改从 task instance 推导 task/stage/executor,客户端覆盖返回 400。 +4. `AUTH-004/005`:补必需项反向校验和 duty member/status/role eligibility 校验。 +5. `AUTH-006/007`:删除 ID 特判,项目列表改用 `ListVisibleProjectIDs`/membership join,创建项目校验 permission。 +6. `AUTH-009`:服务端 logout + `/me` 失效清理;设计 Cookie/CSRF 兼容迁移。 +7. `WF-001/002`:提交 schema v2 ADR 和 runtime authority contract,阻止新增旁路。 + +首周验收物应是:代码、迁移 preflight、授权矩阵、负例测试、更新后的安全报告。只有该闸门通过,才开始发布三个 v2 draft。 + +## 18. 交付物清单 + +- 本实施方案。 +- API 授权矩阵 v2(路由、动作、资源、策略、负例、owner)。 +- Schema v2 JSON Schema + executor/quality gate registry ADR。 +- Goose 00021+ 迁移和 preflight/rollback SQL。 +- 三个工作流 v2 manifest、模板版本清单和 golden fixtures。 +- 用户/项目/系统设置产品规格与 API contract。 +- 授权负例、PG、真实 PI Agent、迁移、恢复、soak 测试报告。 +- 灰度清单、监控面板、告警规则、回滚 runbook。 + +## 资料来源 + +[^1]: 当前治理原则与目标模型见 [2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md)。 +[^2]: IAM、工作流定义、项目实例、通知和任务持久化分别见 [00015 IAM](../deploy/postgres/goose/00015_2026-09-12-iam-core.sql)、[00016 workflow definitions](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql)、[00017 project instances](../deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql)、[00018 outbox](../deploy/postgres/goose/00018_2026-09-12-outbox-notifications-stage-advance.sql)、[00019 task runs](../deploy/postgres/goose/00019_2026-09-12-task-runs-events.sql) 和 [00020 worker lease](../deploy/postgres/goose/00020_2026-09-12-task-run-worker-lease.sql)。 +[^3]: 本轮验证命令与结果记录在本方案 §2.2;当前历史测试状态见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。 +[^4]: 系统能力查询没有限定 binding scope/role status/valid_from,且 role-admin 字符串直接判 admin,见 [internal/authz/service.go](../internal/authz/service.go#L26-L99)。 +[^5]: 创建项目只验证身份,见 [project_handlers.go](../internal/server/project_handlers.go#L16-L46);运行历史和血缘查询未做项目访问判断,见同文件 [run history/lineage](../internal/server/project_handlers.go#L221-L274)。 +[^6]: 工作流管理统一走 `requireSystemAdmin`,没有使用已经入库的 `workflow_defs.*`,见 [admin_workflow_handlers.go](../internal/server/admin_workflow_handlers.go#L13-L23);权限种子见 [00016](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql#L67-L82)。 +[^7]: `ResolveStageAccess` 在 live 查询错误时返回 unrestricted,且一个阶段任一职责会放开该阶段全部任务,见 [stage_access.go](../internal/projectinstance/stage_access.go#L15-L68);服务器过滤辅助函数也在错误时放行,见 [stage_access_helpers.go](../internal/server/stage_access_helpers.go#L23-L47)。 +[^8]: 任务门禁在 actor 能访问 active stage 时放过不匹配 task,见 [bizdev_stage_gate.go](../internal/server/bizdev_stage_gate.go#L40-L54);workflow run 接收客户端 task override,见 [project_handlers.go](../internal/server/project_handlers.go#L205-L218)。 +[^9]: token/session 存 localStorage 且 logout 只删除本地键,见 [web/src/api/auth.ts](../web/src/api/auth.ts#L306-L330);恢复 session 后 `/me` 失败被吞掉,见 [web/src/App.tsx](../web/src/App.tsx#L690-L703)。 +[^10]: 用户设置把偏好描述为浏览器本地并从前端角色推导权限,见 [UserSettingsModal.tsx](../web/src/components/user/UserSettingsModal.tsx#L68-L77) 与 [同文件](../web/src/components/user/UserSettingsModal.tsx#L673-L779);后端已有活动会话 API,见 [auth_handlers.go](../internal/server/auth_handlers.go#L162-L204)。 +[^11]: 三个单阶段种子见 [workflowdef/bootstrap.go](../internal/workflowdef/bootstrap.go#L63-L74);seed 遇到已有发布版本直接退出,见 [workflowdef/store.go](../internal/workflowdef/store.go#L364-L372)。 +[^12]: DBCatalog 只取首阶段/首任务,见 [workflowdef/catalog.go](../internal/workflowdef/catalog.go#L50-L82);现有 schema 能表达的字段见 [workflowdef/types.go](../internal/workflowdef/types.go#L15-L43)。 +[^13]: 商务流程真实阶段和任务仍由 [internal/bizdev/service.go](../internal/bizdev/service.go#L202-L223) 硬编码。 +[^14]: 规划 validator 只遍历客户端提交项,没有反向验证必需定义项是否缺失,见 [projectinstance/validator.go](../internal/projectinstance/validator.go#L37-L105);三权只校验非空和互斥,见 [同文件](../internal/projectinstance/validator.go#L108-L144)。 +[^15]: 阶段实例 position 固定写 0,见 [projectinstance/store.go](../internal/projectinstance/store.go#L244-L249);执行器默认 reviewer=2、approver=3 并固定阶段,见 [bizdev/service.go](../internal/bizdev/service.go#L383-L418)。 +[^16]: 当前报告的真实 PI Agent E2E 记录 `/v1/run` 超时,同时结论仍称“进行中”,见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。 +[^17]: [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)。 +[^18]: [NIST Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control) 与 [NIST SP 800-162 ABAC](https://csrc.nist.gov/pubs/sp/800/162/upd2/final)。 +[^19]: [OWASP Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)。 +[^20]: 产品经理和测试经理的 Agent 角色及职责见 [squad/workspace.go](../internal/squad/workspace.go#L648-L743),内部步骤见 [同文件](../internal/squad/workspace.go#L940-L1073)。 +[^21]: 当前产品/测试质量门禁见 [squad/quality_gate.go](../internal/squad/quality_gate.go#L108-L146)。 +[^22]: 测试经理对 approved SR 的前置校验和材料注入见 [bizdev/service.go](../internal/bizdev/service.go#L365-L381),stale 传播见 [projectworkflow/service.go](../internal/projectworkflow/service.go#L237-L265)。 diff --git a/.doc/remediation/2026-09-12-phase1-iam-authz-implementation-plan.md b/.doc/remediation/2026-09-12-phase1-iam-authz-implementation-plan.md new file mode 100644 index 00000000..b491f3fd --- /dev/null +++ b/.doc/remediation/2026-09-12-phase1-iam-authz-implementation-plan.md @@ -0,0 +1,99 @@ +# Phase 1:账户与授权权威化 Implementation Plan + +> **依据**:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) §5.2、§4、§12、Phase 1 +> **前置**:Phase 0 已合并(5 commits on `dev`,`8341168`) + +**Goal:** 登录、角色、权限、项目成员关系全部以数据库 + 服务端策略为唯一权威;前端只消费 `capabilities`;重启后会话/账户策略仍有效;禁用账户下一请求失效。 + +**Architecture:** Goose 迁移新增 IAM 表 → `PostgresAuthStore` 替换 `MemoryStore`(dev 可 feature flag 回退)→ `AuthorizationService` 统一 RBAC + `project_members` + admin 判定 → `/api/v1/auth/me` 返回 capabilities → 管理端用户/角色 API 持久化 → 前端移除 localStorage 权限权威。 + +**Tech Stack:** Goose、pgx、现有 `internal/auth`、`internal/authz`、React/Vite。 + +**明确不在本阶段:** 工作流版本模型、阶段 ABAC、capabilities 到每个 DocGov 动作的全覆盖(先系统 + 项目 + 已挂 authz 路由)。 + +--- + +## 完成门禁 + +| 门禁 | 判定 | +|---|---| +| 持久化账户 | 重启后 users/roles 仍在 DB | +| 持久化会话 | token 存哈希;logout/禁用立即失效 | +| 无 localStorage RBAC 权威 | `AdminSettingsModal` 读写 API;`hasPermission` 仅 UI 兜底并标注 deprecated | +| 项目成员 CRUD | 创建者可增删改成员;API 测试 | +| 负例 | 禁用用户 token → 401;跨项目已挂 authz → 403 | + +--- + +## 任务分解 + +### Task 1 — IAM 数据库迁移(`feat(db)`) + +新建 `deploy/postgres/goose/00015_iam_core.sql`: + +- `users`(id, username, display_name, email, status, department, employee_id, locale, timezone, created_at, updated_at) +- `user_credentials`(user_id, password_hash, password_changed_at, failed_count, locked_until) +- `auth_sessions`(id, token_hash, user_id, created_at, last_seen_at, idle_expires_at, absolute_expires_at, revoked_at, ip_hash, user_agent) +- `roles` / `permissions` / `role_permissions` / `user_role_bindings` +- seed:`role-admin` + 核心 permissions + 从 MemoryStore dev 用户回填(仅 dev/test 迁移脚本) + +约束:username unique;token_hash unique;至少一个 super-admin binding。 + +### Task 2 — PostgresAuthStore(`feat(auth)`) + +- `internal/auth/pg_store.go` 实现 `AuthStore` +- 会话:Login 写 `auth_sessions`(只存 SHA256(token));ValidateToken 查库 + 更新 last_seen +- Logout/RevokeAll 标记 revoked_at +- `server.go`:有 `ContextDbHost` 时用 PgStore,否则 dev 仍 MemoryStore + +### Task 3 — AuthorizationService(`feat(authz)`) + +- `internal/authz/service.go`:`Capabilities(ctx, userID) []string` +- `HasPermission(ctx, userID, perm, scope)` 组合系统 role_bindings + `project_members` +- 替换 scattered `role-admin` 硬编码 → `HasSystemPermission(..., "system.admin")` 或保留 admin role_id 映射 +- `requireAdmin` / `requireProjectAccess` 改调用 Authorizer + AuthzService + +### Task 4 — Auth API 扩展(`feat(api)`) + +- `GET /api/v1/auth/me` 增加 `capabilities: string[]` +- 会话列表/撤销(用户设置 Phase 1 最小版):`GET/DELETE /api/v1/auth/sessions` +- Admin users/roles CRUD 对齐 DB(现有 handler 改接 PgStore) + +### Task 5 — 项目成员 API(`feat(api)`) + +- `GET/POST/PUT/DELETE /api/v1/projects/{id}/members` +- 仅 owner/creator + `projects.members.manage` 可写 +- 与 `project_members` 表对齐;禁止把 author/reviewer/approver 写入成员 role + +### Task 6 — 前端 capabilities(`feat(web)`) + +- `authClient.me()` 缓存 capabilities +- `engine/rbac.ts`:`hasPermission` 优先读 capabilities;localStorage roles 只读迁移提示 +- `AdminSettingsModal` / `UserProjectRightsModal` 成员编辑走 API +- 移除 `loadRoles(DEFAULT_ROLES)` 作为权威初始化(保留 demo 数据只读展示直至导入完成) + +### Task 7 — 测试与报告(`test` / `docs(test)`) + +- `internal/auth/pg_store_test.go`(testcontainers 或 stub pg) +- `internal/authz/service_test.go` +- 扩展 `security_p0_test` + 跨项目 403(需 DB fixture) +- `.doc/test-reports/2026-09-12-phase1-iam-authz-test-report.md` + +--- + +## 建议提交节奏 + +1. `feat(db):` IAM goose migration + seed +2. `feat(auth):` PostgresAuthStore + session persistence +3. `feat(authz):` AuthorizationService + admin gate +4. `feat(api):` members CRUD + auth/me capabilities +5. `feat(web):` frontend capabilities consumer +6. `test(docs):` Phase 1 report + +--- + +## 风险 + +- **双写期**:MemoryStore 与 PG 并存时须单一 Store 注入,避免混用。 +- **ID 对齐**:现有 `projects.creator_user_id` / memory user id 与 PG users.id 迁移需一次性回填脚本。 +- **前端降级**:capabilities 未加载前 fail closed(禁用敏感按钮,不默认 allow)。 diff --git a/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md b/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md new file mode 100644 index 00000000..8d8db223 --- /dev/null +++ b/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md @@ -0,0 +1,23 @@ +# Phase 2:工作流设计器与模板库 Implementation Plan + +> **依据**:`.doc/2026-09-11-production-ready-workflow-governance-plan.md` §7、§15 Phase 2 + +**Goal:** 工作流定义版本化入库;模板 CAS 资产库;Admin 草稿/校验/发布/退役;静态 catalog bootstrap;运行时 DBCatalog。 + +**不在本阶段:** 项目激活冻结、instance 快照、阶段 ABAC(Phase 3)。 + +## 完成门禁 + +| 门禁 | 判定 | +|---|---| +| 已发布版本不可变 | Publish 后 UpdateDraft 拒绝 | +| 非法工作流不能发布 | Validate 失败 → 422 | +| 旧 catalog bootstrap | BootstrapSeeds 幂等写入 5 套 published v1 | +| 运行时读 DB | NewCatalog 优先 DBCatalog | + +## 已交付模块 + +- `deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql` +- `internal/workflowdef/` — store, service, validator, catalog, bootstrap +- `internal/server/admin_workflow_handlers.go`, `admin_template_handlers.go` +- `web/src/api/workflowAdmin.ts` + AdminSettingsModal workflows Tab diff --git a/.doc/remediation/2026-09-12-quick-reference-guide.md b/.doc/remediation/2026-09-12-quick-reference-guide.md new file mode 100644 index 00000000..6816a20a --- /dev/null +++ b/.doc/remediation/2026-09-12-quick-reference-guide.md @@ -0,0 +1,461 @@ +# 项目审计快速参考指南 + +**用途**: 开发/QA 快速定位问题、理解整改方向 +**格式**: 结构化索引,支持搜索和导航 + +--- + +## 一、关键数字一览 + +| 指标 | 数值 | 说明 | +|---|---|---| +| 项目完成度 | 70% | 架构完整,核心功能大部分实现,缺新功能和 bug 修复 | +| 已确认缺陷 | 12 个 | 3 个 critical,4 个 high,5 个 medium | +| 未完成功能 | 3 个 | 项目上下文快照、受控终止、E2E 测试 | +| 整改工作量 | 61h | 单人 2.5 天,双人 5 天 | +| 单元测试 | 120+ | 85% 覆盖主要包 | +| E2E 测试 | 0% | **需补充** | +| 数据污染 | 88 个定义 | 测试定义混入开发库 | + +--- + +## 二、快速诊断矩阵 + +### 症状 → 原因 → 解决方案 + +``` +症状 1: 完成工作流后项目仍显示为"正在运行",无法配置下一个工作流 +├─ 原因: BUG-01 - AdvanceStage 完成最后阶段时未更新项目 lifecycle +├─ 代码位置: internal/projectinstance/stage_store.go:128-158 +├─ 优先级: 🔴 P0 CRITICAL +└─ 解决: Task A1(2h) + └─ 同事务更新 projects.lifecycle_status = 'planning' + +症状 2: 禁用的文档仍然可以在某些页面被启动/编辑 +├─ 原因: BUG-05 - 拒绝逻辑分散,不同入口检查不一致 +├─ 代码位置: stage_access.go, API, SSE, Agent tools 多处 +├─ 优先级: 🔴 P1 HIGH +└─ 解决: Task A5(4h) + └─ 实现 DocumentAccessDecider,统一所有入口 + +症状 3: 对话中说"推进工作流"有时不生效或使用旧流程 +├─ 原因: BUG-04 - Coordinator 调用旧 bizdevSvc.ExecuteStage +├─ 代码位置: internal/coordinator/engine.go:672-811 +├─ 优先级: 🔴 P0 CRITICAL +└─ 解决: Task A4(2h) + └─ 改为调用 instSvc.AdvanceStage + +症状 4: 阶段推进后发现文档被强制标记为"已批准",但用户未操作 +├─ 原因: BUG-02 - AdvanceStage SQL 中有强制更新批准状态的逻辑 +├─ 代码位置: internal/projectinstance/stage_store.go(需 grep 验证) +├─ 优先级: 🔴 P0 CRITICAL +└─ 解决: Task A2(1h) + └─ 删除 UPDATE 批准状态的 SQL 行 + +症状 5: 测试在开发环境运行后,88 个奇怪的 pg_* 定义出现在工作流目录 +├─ 原因: BUG-08 - 集成测试未设置 TEST_DATABASE_URL,默认连接开发库 +├─ 代码位置: internal/projectinstance/pg_integration_test.go +├─ 优先级: 🟠 P1 MEDIUM +└─ 解决: Task BUG-08(2h) + └─ 强制要求 TEST_DATABASE_URL;测试后清理 + +症状 6: 激活工作流时 token 可能在浏览器历史中看到,或被重复使用 +├─ 原因: BUG-06 - Token 明文保存,消费分事务,不是 one-time +├─ 代码位置: internal/projectinstance/service.go(激活相关) +├─ 优先级: 🟠 P1 HIGH +└─ 解决: Task A6(3h) + └─ Token → hash + one-time,同事务消费 + +症状 7: 产品经理流程不运行,测试工程师流程无法启动,提示"需先运行产品流程" +├─ 原因: MISSING-06 - test_manager manifest 中仍有 upstream 依赖 +├─ 代码位置: internal/workflowdef/manifests/test_manager.v2.json +├─ 优先级: 🟠 P1 HIGH +└─ 解决: Task B3(需先删除测试流程的上游依赖) + └─ 修改 manifest,删除 required_upstream_workflow + +症状 8: 选择工作流时前端显示"商务流程",但服务返回的名称不一致 +├─ 原因: BUG-12 - 前端硬编码名称 vs 后端正式名称不同步 +├─ 代码位置: web/src/components/workflow/ProjectWorkflowSwitcher.tsx +├─ 优先级: 🟢 P2 LOW +└─ 解决: 由后端 GET /api/v1/workflows/catalog 驱动前端显示 + +症状 9: 无法手工删除已完成的工作流实例,项目永久处于"运行中" +├─ 原因: MISSING-02 - 受控终止 API 未实现 +├─ 代码位置: (缺失) +├─ 优先级: 🔴 P1 CRITICAL +└─ 解决: Task B1(6h) + └─ 实现 TerminateWorkflow API,二次确认 + 原因记录 + +症状 10: 产品经理和测试工程师输出中缺少"来源追溯",无法知道数据从哪来 +├─ 原因: MISSING-01 - 项目上下文快照服务未实现 +├─ 代码位置: (缺失) +├─ 优先级: 🔴 P1 CRITICAL +└─ 解决: Task B3(12h) + └─ 实现 ProjectContextSnapshot 服务,包含血缘表 +``` + +--- + +## 三、代码热点地图 + +### 高风险区域(需特别关注的文件) + +``` +🔴 CRITICAL +├─ internal/projectinstance/stage_store.go +│ ├─ BUG-01: AdvanceStage 不更新项目生命周期 +│ ├─ BUG-02: 推进强制批准文档(需验证) +│ └─ 位置: 第 71-158 行 +│ +├─ internal/coordinator/engine.go +│ ├─ BUG-04: 对话推进调用旧服务 +│ └─ 位置: 第 672-811 行(handleAdvanceStage) +│ +├─ internal/projectinstance/service.go +│ ├─ BUG-01: 完成后生命周期(同上) +│ └─ 位置: 第 119-135 行(SaveWorkflowPlan) + +🟠 HIGH +├─ internal/projectinstance/stage_access.go +│ ├─ BUG-05: 禁用文档拒绝逻辑不一致 +│ └─ 位置: 第 15-71, 90-104 行 +│ +├─ web/src/components/workflow/ProjectWorkflowSwitcher.tsx +│ ├─ BUG-09: 版本冲突自动重试 +│ ├─ BUG-12: 硬编码名称 +│ └─ 位置: 第 16-23, 38-76, 173-236 行 + +🟡 MEDIUM +├─ internal/projectinstance/pg_integration_test.go +│ ├─ BUG-08: 未设置 TEST_DATABASE_URL +│ └─ 位置: 第 19-49 行 +│ +├─ internal/workflowdef/manifests/test_manager.v2.json +│ ├─ 依然有 upstream 依赖(需删除) +│ └─ 位置: 第 1-23 行 +``` + +--- + +## 四、整改优先级排序 + +### 必须在本周内完成(优先级递减) + +``` +□ P0-1: BUG-01 项目完成后生命周期 (2h) + → 项目永久锁死的根本原因 + +□ P0-2: BUG-04 对话推进新服务切换 (2h) + → 权限检查绕过 + +□ P0-3: BUG-02 推进不强制批准 (1h) + → 数据违反业务规则 + +□ P1-1: BUG-05 禁用文档一致性 (4h) + → 安全隐患 + +□ P1-2: BUG-06 激活 token 安全 (3h) + → 存在泄露/重放风险 + +□ P1-3: Task B1 受控终止 API (6h) + → 恢复能力必需 + +□ P1-4: Task B2 E2E 测试 (8h) + → 验收标准要求 + +可以延后(下周处理) + +□ P2-1: BUG-03 禁用文档 skipped_disabled (3h) +□ P2-2: BUG-08 测试隔离完善 (2h) +□ P2-3: BUG-10 项目设置审计视图 (3h) +□ P2-4: BUG-09 前端冲突自动重试 (1h) +□ P2-5: BUG-11 旧 API 下线 (1h) +□ P2-6: BUG-12 前端名称一致性 (1h) +``` + +--- + +## 五、代码修改检查清单 + +### 提交前验收标准 + +**修复 BUG-01 时**: +``` +[ ] 修改 stage_store.go 的 AdvanceStage 函数 + - 检查是否最后阶段 + - 若是,同事务更新 projects.lifecycle_status + - 清空 current_workflow_instance_id + - 写审计事件 +[ ] 新增测试: TestAdvanceStage_CompletesProjectAfterLastStage +[ ] 新增测试: TestAdvanceStage_DoesNotChangeProjectOnNonLastStage +[ ] 本地测试通过 (go test ./internal/projectinstance -v) +[ ] 前端检查:/projects/{id}/settings 显示"配置下一工作流" +``` + +**修复 BUG-04 时**: +``` +[ ] 修改 coordinator/engine.go 的 handleAdvanceStage + - 提取 workflow_instance_id + - 改调 instSvc.AdvanceStage 替代 bizdevSvc.ExecuteStage + - 调整返回格式 +[ ] 新增测试: TestDialogueAdvanceStage_UsesNewService +[ ] 新增测试: TestDialogueAdvanceStage_PermissionCheck +[ ] 本地测试通过 (go test ./internal/coordinator -v) +[ ] 对话测试通过 (go test ./internal/server -run Dialogue -v) +``` + +**创建 Task B2 E2E 框架时**: +``` +[ ] 确保 TEST_DATABASE_URL 已设置 +[ ] 创建 setupE2ETestDB() 函数 + - 创建隔离 schema + - 运行所有迁移 + - 清理逻辑 +[ ] 编写 TestE2E_BizdevWorkflow_Complete + - 7 文档完整流程 + - 每个阶段验证门禁 + - 完成后验证项目状态 +[ ] 编写 TestE2E_ProductManagerWorkflow_Standalone + - 无前置依赖 + - 独立运行成功 +[ ] 编写 TestE2E_TestEngineerWorkflow_WithoutSRS + - 无 SRS 输入仍能运行 + - 输出包含来源清单 +[ ] 全部 E2E 测试通过 +[ ] 验收标准 7.5 完全满足 +``` + +--- + +## 六、数据库迁移清单 + +### 需要新增的迁移脚本 + +``` +00025_2026-09-12-disabled-doc-status.sql +├─ 添加 project_doc_task_instances.status_reason +├─ 添加约束:disabled 时 duties 为空 +└─ 编写回滚脚本 + +00026_2026-09-12-workflow-termination.sql +├─ 添加 project_workflow_instances.terminated_at/by/reason +├─ 添加 termination_reason 列 +└─ 编写回滚脚本 + +00027_2026-09-12-context-snapshots.sql +├─ 创建 project_context_snapshots 表 +├─ 创建 project_context_snapshot_sources 表 +└─ 编写回滚脚本 + +00028_2026-09-12-activation-challenges.sql +├─ 创建 activation_challenges 表 +├─ 创建 one_time_tokens 表 +└─ 编写回滚脚本 +``` + +--- + +## 七、测试命令参考 + +```bash +# 运行所有项目实例测试 +go test ./internal/projectinstance -v + +# 运行所有协调器测试 +go test ./internal/coordinator -v + +# 运行所有工作流定义测试 +go test ./internal/workflowdef -v + +# 运行服务器集成测试 +go test ./internal/server -v + +# 运行特定 bug 的测试 +go test ./internal/projectinstance -run "TestAdvanceStage" -v + +# 运行 PG 集成测试(需 TEST_DATABASE_URL) +TEST_DATABASE_URL=postgresql://... go test ./internal/server -run PG -v + +# 运行 E2E 测试 +TEST_DATABASE_URL=postgresql://... go test ./internal/server -run E2E -v + +# 代码覆盖率分析 +go test ./internal/projectinstance ./internal/coordinator ./internal/workflowdef \ + -coverprofile=coverage.out && go tool cover -html=coverage.out + +# 静态检查 +go vet ./internal/... +golangci-lint run ./internal/... +``` + +--- + +## 八、API 快速参考 + +### 关键端点变动汇总 + +``` +现有(需保留或改进): + GET /api/v1/workflows/catalog + → 返回三项正式工作流 ✅ + + GET /api/v1/projects/{id}/settings + → 返回项目设置及 live instance 配置 ✅ + + PUT /api/v1/projects/{id}/workflow-plan + → 保存/修改规划 (planning 状态下) ✅ + + POST /api/v1/projects/{id}/workflow-instances/activate + → 激活工作流 (需修复 token) ⚠️ + + GET /api/v1/workflow-instances/{id}/stages/{stage}/readiness + → 阶段门禁详情 ✅ + + POST /api/v1/workflow-instances/{id}/stages/{stage}/advance + → 推进阶段 (需修复生命周期) ❌ + +待实现(高优先级): + POST /api/v1/workflow-instances/{id}/termination-preview + → 终止预览(Task B1) + + POST /api/v1/workflow-instances/{id}/terminate + → 执行终止(Task B1) + +待删除或返回 410: + POST /projects/{id}/active-workflow + → 旧切换 API(需下线) + +需改进(权限一致性): + POST /api/v1/doc-task-instances/{id}/runs + → 启动编制 (需 DocumentAccessDecider) ⚠️ + + POST /api/v1/documents/{id}/submit + → 提交审核 (需统一权限检查) ⚠️ + + POST /api/v1/documents/{id}/approve + → 批准 (需统一权限检查) ⚠️ +``` + +--- + +## 九、常见问题速查 + +### Q1: 为什么完成工作流后项目仍然处于"active"? +**A**: BUG-01 - `AdvanceStage` 完成最后阶段时未同事务更新项目 `lifecycle_status`。 +**修复**: Task A1(2h) +**临时绕过**: 手动执行 SQL `UPDATE projects SET lifecycle_status='planning' WHERE id=?` + +### Q2: 禁用的文档仍然能被某些用户操作? +**A**: BUG-05 - 不同入口对禁用文档的检查不一致。 +**修复**: Task A5(4h) - 实现 `DocumentAccessDecider` +**临时绕过**: 在关键入口前添加 `if doc.status == 'skipped_disabled' { return 409 }` + +### Q3: 激活 token 可能被重复使用? +**A**: BUG-06 - Token 明文保存,消费分事务。 +**修复**: Task A6(3h) +**临时保护**: 限制 token 有效期为 5 分钟;记录消费日志;审计异常 token 使用 + +### Q4: 对话推进工作流不起作用? +**A**: BUG-04 - Coordinator 调用旧商务服务而非实例服务。 +**修复**: Task A4(2h) +**临时检查**: 查看 `internal/coordinator/engine.go:672-811` 是否仍调用 `bizdevSvc` + +### Q5: 为什么 E2E 测试一直 fail? +**A**: 可能多个原因: + 1. TEST_DATABASE_URL 未设置 → 连接开发库(88 个污染定义) + 2. E2E 框架缺失 → 需实现 setupE2ETestDB() + 3. 实例生命周期 bug → BUG-01 导致测试逻辑不对 + +**修复**: 检查 TEST_DATABASE_URL;运行 Task B2 + +### Q6: 生产数据库中有 47 个"已完成但项目仍为 active"的不一致数据? +**A**: BUG-01 导致。数据本身可恢复。 +**恢复方案**: + 1. 查询 `SELECT * FROM project_workflow_instances WHERE status='completed'` + 2. 对每个 completed 实例: + ```sql + UPDATE projects SET lifecycle_status='planning', current_workflow_instance_id=NULL + WHERE id=(SELECT project_id FROM project_workflow_instances WHERE id=?) + ``` + 3. 补写审计日志 + +--- + +## 十、参考文档导航 + +| 文档 | 用途 | 适合人员 | +|---|---|---| +| [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) | **当前缺口 SSOT** | 全体 | +| [ops/CURRENT.md](./ops/CURRENT.md) | 协作焦点 | Agent / 开发 | +| [comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 详细缺陷分析与整改方案(历史) | 架构师、资深开发 | +| [remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 可执行的任务拆分与验收 | 开发、QA | +| [audit-summary-report.md](./2026-09-12-audit-summary-report.md) | 审计总结与建议(历史) | 项目经理、技术负责人 | +| **[本文件]** | 快速参考与索引 | 全体团队 | +| [three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 业务需求原始规划 | 产品、架构 | + +--- + +## 十一、快速评分表 + +### 修复每个 bug 后的自检清单 + +``` +BUG-01 ✓ 完成 + □ stage_store.go 修改 + □ 新增单元测试 ×2 + □ 本地 go test PASS + □ 前端验证项目状态改变 + → 接受标准: 完成最后阶段后项目 lifecycle='planning' + +BUG-02 ✓ 完成 + □ grep 确认强制批准逻辑存在 + □ 删除 UPDATE 批准状态的 SQL + □ 新增单元测试 + □ 本地 go test PASS + → 接受标准: 推进前后文档状态不变 + +BUG-04 ✓ 完成 + □ engine.go handleAdvanceStage 改为调用新服务 + □ 新增单元测试 + □ 本地 go test PASS + □ 对话测试 PASS + → 接受标准: 对话推进使用 instSvc + +BUG-05 ✓ 完成 + □ 实现 DocumentAccessDecider 接口 + □ 集成到 API、SSE、异步任务、Agent tools + □ 新增综合测试 + □ 本地 go test PASS + → 接受标准: 禁用文档全拒绝,返回 409/403 + +BUG-06 ✓ 完成 + □ 数据库迁移 00028 + □ API 改为 challenge_id + one_time_token + □ Token hash + 原子消费 + □ 新增安全测试 ×4 + □ 本地 go test PASS + → 接受标准: Token one-time、hash 存储、5 分钟过期 + +Task B1 ✓ 完成 + □ 新增 terminate.go 服务 + □ TerminationPreview API + □ TerminateWorkflow API + □ 新增端到端测试 + □ 本地 go test PASS + → 接受标准: 终止后项目可配置下一流程 + +Task B2 ✓ 完成 + □ setupE2ETestDB() 实现 + □ TestE2E_BizdevWorkflow_Complete PASS + □ TestE2E_ProductManagerWorkflow_Standalone PASS + □ TestE2E_TestEngineerWorkflow_WithoutSRS PASS + □ TEST_DATABASE_URL 隔离库运行 + → 接受标准: 三工作流完整链路验证 +``` + +--- + +**文档版本**: v1.0 快速参考 +**适用对象**: 项目全体 +**更新频率**: 同步更新主审计文档 + diff --git a/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md b/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md new file mode 100644 index 00000000..05388cce --- /dev/null +++ b/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md @@ -0,0 +1,1179 @@ +# 整改实施拆分与验收清单 + +> **工作手册(非 live status)** — 任务说明与验收框;勾选状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/checklists/](./ops/checklists/) 为准。 + +**日期**: 2026-09-12 +**格式**: 可执行的任务分解与逐项验收标准 +**用途**: 开发、QA 与产品对齐 + +--- + +## 第一部分:关键缺陷修复(Phase A) + +### Task A1: 项目完成后生命周期转换 + +**目标**: 完成最后阶段后,项目立即进入可配置下一工作流的状态 + +**修改文件**: +- `internal/projectinstance/stage_store.go` (AdvanceStage 事务) +- `internal/projectinstance/service.go` (逻辑校验) +- 相关测试 + +**具体修改**: + +**文件**: `internal/projectinstance/stage_store.go` +```go +// 现有代码(伪代码) +func (s *pgStore) AdvanceStage(...) (*InstanceDetail, error) { + // ... 获取实例与阶段定义 + + // 🔴 当前:只更新实例,不更新项目 + stmt := "UPDATE project_workflow_instances SET active_stage_key = ?, status = ? WHERE id = ?" + + // ✅ 修改后:检查是否最后阶段,若是同时更新项目 + isLastStage := checkLastStageInDefinition(...) + if isLastStage { + // 同事务操作 + stmtProject := "UPDATE projects SET lifecycle_status = ?, current_workflow_instance_id = NULL WHERE id = ?" + // 写审计 + auditStmt := "INSERT INTO workflow_events ..." + } +} +``` + +**测试用例**: +```go +// 新增测试 +func TestAdvanceStage_CompletesProjectAfterLastStage(t *testing.T) { + // 1. 创建并激活工作流 + // 2. 推进到最后一个启用阶段 + // 3. 所有文档批准后确认推进 + // 4. 验证: + // - workflow_instance.status = "completed" + // - projects.lifecycle_status = "planning" + // - projects.current_workflow_instance_id = NULL + // - 审计事件已记录 +} + +func TestAdvanceStage_DoesNotChangeProjectOnNonLastStage(t *testing.T) { + // 验证:非最后阶段的推进不改变项目状态 +} +``` + +**验收标准**: +- [ ] 单元测试 PASS +- [ ] 完成最后阶段后项目 `lifecycle_status` 变为 `planning` +- [ ] 前端 /projects/{id}/settings 立即显示"配置下一工作流"按钮 +- [ ] 审计日志记录 `ProjectWorkflowCompleted` 事件 + +**预计工作量**: 2h + +--- + +### Task A2: 推进事务不强制更新文档审批状态 + +**目标**: 验证并删除推进时强制批准文档的逻辑 + +**步骤**: +1. 搜索 `AdvanceStage` 中是否存在 UPDATE 文档状态的 SQL +2. 若存在,删除该逻辑 +3. 补充负例测试 + +**搜索命令**: +```bash +grep -n "UPDATE.*doc.*approved\|UPDATE.*approval.*approved" \ + internal/projectinstance/stage_store.go +``` + +**如果存在修改**: +```go +// 🔴 删除以下逻辑(如果存在) +stmt := `UPDATE project_doc_task_instances + SET status = 'approved' + WHERE instance_id = ? AND enabled = true` + +// ✅ 替换为:什么都不改,只改阶段状态 +stmt := `UPDATE project_workflow_instances + SET active_stage_key = ? WHERE id = ?` +``` + +**测试**: +```go +func TestAdvanceStage_DoesNotModifyDocumentApprovalStatus(t *testing.T) { + // 1. 创建、激活、推进到阶段就绪 + // 2. 记录所有文档的当前 approval_status + // 3. 执行 AdvanceStage + // 4. 验证:所有文档 approval_status 未变 +} +``` + +**验收标准**: +- [ ] 单元测试 PASS +- [ ] 推进前后文档状态一致 +- [ ] 阶段状态改变,文档状态不改变 + +**预计工作量**: 1h + +--- + +### Task A3: 禁用文档状态标记为 skipped_disabled + +**目标**: 禁用文档在数据库中有明确的 `skipped_disabled` 状态记录 + +**数据库迁移** (`00025_2026-09-12-disabled-doc-status.sql`): +```sql +-- 新增迁移 +ALTER TABLE project_doc_task_instances +ADD COLUMN status_reason VARCHAR(50) DEFAULT NULL; + +-- 补充约束:disabled 时 duties 必须为空 +ALTER TABLE project_doc_task_instances +ADD CONSTRAINT chk_disabled_no_duties +CHECK (status != 'skipped_disabled' OR + (author_user_id IS NULL AND + reviewer_user_id IS NULL AND + approver_user_id IS NULL)); +``` + +**代码修改** (`internal/projectinstance/store.go`): +```go +func (s *pgStore) SaveWorkflowPlan(...) error { + // 激活时为所有文档创建记录 + for _, stage := range plan.Stages { + for _, doc := range stage.DocTasks { + if doc.Enabled { + // 写启用文档 + stmt := `INSERT INTO project_doc_task_instances + (instance_id, task_key, status, author_user_id, ...) + VALUES (?, ?, 'awaiting_edit', ?, ...)` + } else { + // ✅ 新增:写禁用文档 + stmt := `INSERT INTO project_doc_task_instances + (instance_id, task_key, status, status_reason) + VALUES (?, ?, 'skipped_disabled', 'creator_disabled')` + } + } + } +} +``` + +**测试**: +```go +func TestDisabledDocumentPersistence(t *testing.T) { + // 1. 创建计划,禁用某文档 + // 2. 激活 + // 3. 验证: + // - 禁用文档在 project_doc_task_instances 中存在 + // - status = 'skipped_disabled' + // - 无职责行 +} + +func TestDisabledDocumentRejectionAllEntries(t *testing.T) { + // 针对不同入口测试禁用文档拒绝 + // - API 启动:409 DOC_TASK_DISABLED + // - 提交/审核/批准:403 DOC_DUTY_FORBIDDEN +} +``` + +**验收标准**: +- [ ] 数据库迁移成功应用 +- [ ] 禁用文档在 project_doc_task_instances 中有记录 +- [ ] 禁用文档的所有操作返回 409 或 403 +- [ ] 审计查询显示哪些文档被禁用 + +**预计工作量**: 3h + +--- + +### Task A4: 对话推进切换到新实例服务 + +**目标**: 对话中的"推进阶段"调用新的实例服务,而非旧的商务执行器 + +**修改文件**: `internal/coordinator/engine.go:672-811` + +**原代码**: +```go +func (e *CoordinatorEngine) handleAdvanceStage(...) { + // ...识别成功后 + + // 🔴 旧逻辑:调用商务服务 + result, err := e.bizdevSvc.ExecuteStage(ctx, projectID, ...) +} +``` + +**新代码**: +```go +func (e *CoordinatorEngine) handleAdvanceStage(...) { + // ...识别成功后 + + // ✅ 新逻辑:调用实例服务 + + // 1. 从项目或上文获取 workflow_instance_id + instanceID, err := extractWorkflowInstanceID(ctx, projectID, ...) + if err != nil { + return rejectResponse("Cannot determine active workflow instance") + } + + // 2. 调用新服务 + result, err := e.instSvc.AdvanceStage( + ctx, instanceID, userID, isCreator, + projectinstance.AdvanceStageInput{ + StageKey: stageKey, + ExpectedConfigRevision: configRev, + }, + ) + if err != nil { + return rejectResponse(err.Error()) + } + + // 3. 返回成功响应 + return confirmResponse("Stage advanced successfully", result) +} +``` + +**辅助函数**: +```go +func (e *CoordinatorEngine) extractWorkflowInstanceID( + ctx context.Context, + projectID int64, + dialogueContext map[string]any, +) (int64, error) { + // 优先级: + // 1. 上下文中显式提供 + if id, ok := dialogueContext["workflow_instance_id"].(int64); ok && id > 0 { + return id, nil + } + + // 2. 从项目设置查询 live instance + settings, err := e.instSvc.GetSettings(ctx, projectID, userID, true) + if err != nil || settings.LiveInstance == nil { + return 0, fmt.Errorf("no active workflow instance") + } + return settings.LiveInstance.ID, nil +} +``` + +**测试**: +```go +func TestDialogueAdvanceStage_UsesNewService(t *testing.T) { + // 1. 激活工作流实例 + // 2. 对话说"推进到下一阶段" + // 3. 验证: + // - 调用 instSvc.AdvanceStage 而非 bizdevSvc.ExecuteStage + // - 返回新格式响应 + // - 实例状态正确更新 +} +``` + +**验收标准**: +- [ ] 对话推进测试 PASS +- [ ] 新实例服务被调用(可通过 mock 验证) +- [ ] 权限检查一致(仅创建者可推进) +- [ ] 旧商务服务逻辑不再触发 + +**预计工作量**: 2h + +--- + +### Task A5: 禁用文档拒绝逻辑一致性(DocumentAccessDecider) + +**目标**: 统一所有入口对禁用文档的拒绝决策 + +**新增文件**: `internal/projectinstance/document_access.go` + +```go +package projectinstance + +import "context" + +type DocumentAccessDecider interface { + // CanAccess 判断用户是否可访问指定文档任务 + // action: "edit", "submit", "review", "approve", "view" + CanAccess( + ctx context.Context, + docTaskInstID int64, + action string, + userID int64, + ) (bool, error) + + // GetAccessDenialReason 返回具体的拒绝原因 + GetAccessDenialReason( + ctx context.Context, + docTaskInstID int64, + userID int64, + ) (code string, message string) +} + +type defaultAccessDecider struct { + store Store + docs DocumentReadinessChecker +} + +func (d *defaultAccessDecider) CanAccess( + ctx context.Context, + docTaskInstID int64, + action string, + userID int64, +) (bool, error) { + // 1. 查询 doc_task_instance + docTask, err := d.store.GetDocTaskInstance(ctx, docTaskInstID) + if err != nil { + return false, err + } + + // 2. 检查状态 + if docTask.Status == "skipped_disabled" { + return false, nil // 禁用文档,拒绝所有操作 + } + + // 3. 获取实例详情 + instance, err := d.store.GetInstanceByID(ctx, docTask.InstanceID) + if err != nil { + return false, err + } + + // 4. 检查实例状态 + if instance.Instance.Status != InstanceActive && + instance.Instance.Status != InstanceAwaiting { + return false, nil // 实例非运行状态 + } + + // 5. 检查当前阶段 + if !stageContainsTask(instance, docTask.StageKey, docTaskInstID) { + return false, nil // 不在当前阶段 + } + + // 6. 检查职责匹配 + if !userHasRole(docTask, userID, action) { + return false, nil // 用户非对应职责人 + } + + return true, nil +} +``` + +**集成点**: +- API 路由: `POST /api/v1/doc-task-instances/{id}/runs` +- SSE 推送: 过滤禁用/非当前阶段的文档更新 +- 异步任务: 启动前校验 +- Agent tool: 文档访问 wrapper + +**测试**: +```go +func TestDocumentAccessDecider_DisabledDocumentRejected(t *testing.T) { + // 禁用文档的所有操作被拒绝 +} + +func TestDocumentAccessDecider_NonCurrentStageRejected(t *testing.T) { + // 不在当前阶段的文档被拒绝 +} + +func TestDocumentAccessDecider_NonResponsibleUserRejected(t *testing.T) { + // 非职责人的操作被拒绝 +} + +func TestDocumentAccessDecider_ValidAccessAllowed(t *testing.T) { + // 满足所有条件时允许 +} +``` + +**验收标准**: +- [ ] 所有入口(API、SSE、异步任务、Agent tool)使用同一决策器 +- [ ] 禁用文档全拒绝 +- [ ] 非职责人拒绝 +- [ ] 非当前阶段拒绝 + +**预计工作量**: 4h + +--- + +### Task A6: 激活 Token 安全处理 + +**目标**: Token 改为 one-time、hash 存储、原子消费 + +**修改流程**: + +**步骤 1**: 修改激活预览 API +```go +// 旧:返回 activation_token +GET /api/v1/projects/{id}/activation-preview +→ { token: "xyz123", ... } + +// ✅ 新:返回 challenge 和 nonce +GET /api/v1/projects/{id}/activation-preview +→ { challenge_id: "ch_abc", nonce: "n123", ... } +``` + +**步骤 2**: 修改激活 API +```go +// 旧:明文 token +POST /api/v1/projects/{id}/workflow-instances/activate +{ token: "xyz123" } + +// ✅ 新:挑战响应 +POST /api/v1/projects/{id}/workflow-instances/activate +{ + challenge_id: "ch_abc", + token: "at_oneTimeXyz123" // 由服务端生成 +} +``` + +**步骤 3**: 数据库变更 +```sql +-- 激活挑战表 +CREATE TABLE activation_challenges ( + id BIGSERIAL PRIMARY KEY, + project_id BIGINT NOT NULL, + created_by BIGINT NOT NULL, + challenge_id VARCHAR(32) UNIQUE, + nonce VARCHAR(32), + config_hash VARCHAR(64), -- 冻结内容的 hash + created_at TIMESTAMP DEFAULT NOW(), + expires_at TIMESTAMP, + consumed_at TIMESTAMP, + FOREIGN KEY (project_id) REFERENCES projects(id) +); + +-- 一次性 token 表 +CREATE TABLE one_time_tokens ( + id BIGSERIAL PRIMARY KEY, + challenge_id VARCHAR(32), + token_hash VARCHAR(255), -- bcrypt hash + created_at TIMESTAMP, + expires_at TIMESTAMP, + consumed_at TIMESTAMP +); +``` + +**激活逻辑**: +```go +func (s *Service) ActivateWorkflow( + ctx context.Context, + projectID int64, + userID int64, + challengeID string, + token string, +) (*ActivateResult, error) { + return s.store.ActivateInTx(ctx, func(tx Tx) error { + // 1. 查询 challenge(5 分钟未过期) + challenge, err := tx.GetChallenge(ctx, challengeID) + if err != nil || challenge.ExpiresAt < now { + return ErrChallengeExpired + } + + // 2. 验证 token hash + if err := bcrypt.CompareHashAndPassword(challenge.TokenHash, token); err != nil { + return ErrInvalidToken + } + + // 3. 检查 token 未消费 + if challenge.ConsumedAt != nil { + return ErrTokenAlreadyConsumed + } + + // 4. 在同一事务内激活实例 + instance, err := tx.ActivateInstance(ctx, projectID, ...) + if err != nil { + return err + } + + // 5. 标记 challenge 和 token 已消费 + tx.MarkChallengeConsumed(ctx, challengeID) + + return nil + }) +} +``` + +**测试**: +```go +func TestActivationTokenSecurity_OneTimeUse(t *testing.T) { + // 同一 token 不能消费两次 +} + +func TestActivationTokenSecurity_Expiration(t *testing.T) { + // 5 分钟后 token 过期 +} + +func TestActivationTokenSecurity_InvalidTokenRejected(t *testing.T) { + // 错误 token 被拒绝 +} + +func TestActivationTokenSecurity_AtomicConsumption(t *testing.T) { + // token 消费与实例激活在同一事务内 +} +``` + +**验收标准**: +- [ ] Token 为 one-time,消费后不可重用 +- [ ] Token 5 分钟过期 +- [ ] Token hash 存储,明文不保存 +- [ ] 激活原子性(token 消费与实例激活同事务) +- [ ] 中间故障时 token 仍有效(可重试) + +**预计工作量**: 3h + +--- + +## 第二部分:高优先级新功能(Phase B) + +### Task B1: 受控终止工作流 API + +**目标**: 工作流实例可被创建者受控终止,写入原因并审计 + +**新增文件**: `internal/projectinstance/terminate.go` + +```go +package projectinstance + +import "context" + +type TerminationPreviewInput struct { + InstanceID int64 `json:"instance_id"` +} + +type TerminationPreviewResult struct { + InstanceID int64 `json:"instance_id"` + PendingDocuments []DocTaskSummary `json:"pending_documents"` + PendingNotifications []string `json:"pending_notifications"` + InProgressRunTasks []string `json:"in_progress_run_tasks"` + CanTerminate bool `json:"can_terminate"` + Impact string `json:"impact,omitempty"` +} + +type TerminateInput struct { + InstanceID int64 `json:"instance_id"` + Reason string `json:"reason"` // 必填,最多 500 字 + Confirm bool `json:"confirm"` // 二次确认 +} + +type TerminateResult struct { + InstanceID int64 `json:"instance_id"` + Status string `json:"status"` // "terminated" + TerminatedAt time.Time `json:"terminated_at"` + TerminatedBy int64 `json:"terminated_by"` + Reason string `json:"reason"` +} + +func (s *Service) GetTerminationPreview( + ctx context.Context, + instanceID int64, +) (*TerminationPreviewResult, error) { + instance, err := s.store.GetInstanceByID(ctx, instanceID) + if err != nil { + return nil, err + } + + // 收集影响项 + pending := []DocTaskSummary{} + notifs := []string{} + tasks := []string{} + + // ...查询待审批文档、待发送通知、在途任务... + + return &TerminationPreviewResult{ + InstanceID: instanceID, + PendingDocuments: pending, + PendingNotifications: notifs, + InProgressRunTasks: tasks, + CanTerminate: true, + Impact: fmt.Sprintf( + "%d pending docs, %d notifications, %d task runs will be cancelled", + len(pending), len(notifs), len(tasks), + ), + }, nil +} + +func (s *Service) TerminateWorkflow( + ctx context.Context, + instanceID int64, + userID int64, + isCreator bool, + input TerminateInput, +) (*TerminateResult, error) { + if !isCreator { + return nil, ErrForbiddenNotCreator + } + if !input.Confirm { + return nil, ErrTerminationNotConfirmed + } + if len(strings.TrimSpace(input.Reason)) == 0 { + return nil, ErrTerminationReasonRequired + } + + result, err := s.store.TerminateInTx(ctx, func(tx Tx) error { + // 1. 获取实例 + instance, err := tx.GetInstanceByID(ctx, instanceID) + if err != nil { + return err + } + + // 2. 检查状态可终止 + if instance.Instance.Status != InstanceActive && + instance.Instance.Status != InstanceAwaiting { + return ErrCannotTerminateInstance + } + + // 3. 标记实例为 terminated + if err := tx.UpdateInstance(ctx, instanceID, map[string]any{ + "status": "terminated", + "terminated_at": now, + "terminated_by": userID, + "termination_reason": input.Reason, + }); err != nil { + return err + } + + // 4. 取消在途任务 + if err := tx.CancelPendingTaskRuns(ctx, instanceID); err != nil { + return err + } + + // 5. 项目改为 planning + if err := tx.UpdateProject(ctx, instance.Instance.ProjectID, map[string]any{ + "lifecycle_status": "planning", + "current_workflow_instance_id": nil, + }); err != nil { + return err + } + + // 6. 写审计 + if err := tx.LogEvent(ctx, "WorkflowTerminated", map[string]any{ + "instance_id": instanceID, + "reason": input.Reason, + "by": userID, + }); err != nil { + return err + } + + return nil + }) + + return &TerminateResult{ + InstanceID: instanceID, + Status: "terminated", + TerminatedAt: now, + TerminatedBy: userID, + Reason: input.Reason, + }, err +} +``` + +**API 路由**: +```go +// server.go +mux.HandleFunc("GET /api/v1/workflow-instances/{id}/termination-preview", + s.handleTerminationPreview) +mux.HandleFunc("POST /api/v1/workflow-instances/{id}/terminate", + s.handleTerminate) +``` + +**测试**: +```go +func TestTerminationPreview_ShowsImpact(t *testing.T) { + // 显示待审批文档、通知、任务清单 +} + +func TestTerminate_RequiresCreator(t *testing.T) { + // 非创建者被拒绝 +} + +func TestTerminate_RequiresConfirmation(t *testing.T) { + // confirm = false 时被拒绝 +} + +func TestTerminate_UpdatesProjectLifecycle(t *testing.T) { + // 终止后项目可配置下一工作流 +} + +func TestTerminate_CancelsPendingTasks(t *testing.T) { + // 在途任务被取消 +} +``` + +**验收标准**: +- [ ] 预览 API 显示完整影响 +- [ ] 仅创建者可终止 +- [ ] 需二次确认和原因 +- [ ] 终止后项目立即可选择下一流程 +- [ ] 审计记录终止原因 + +**预计工作量**: 6h + +--- + +### Task B2: 真实 E2E 测试(PostgreSQL + PI Agent) + +**目标**: 使用真实数据库和 PI Agent 验证三个工作流完整链路 + +**新增文件**: `internal/server/e2e_workflow_integration_test.go` + +**框架**: +```go +package server + +import ( + "context" + "testing" + + "github.com/jackc/pgx/v5/pgxpool" +) + +func setupE2ETestDB(t *testing.T) *pgxpool.Pool { + dbURL := os.Getenv("TEST_DATABASE_URL") + if dbURL == "" { + t.Skip("TEST_DATABASE_URL not set, skipping E2E tests") + } + + pool, err := pgxpool.New(context.Background(), dbURL) + if err != nil { + t.Fatalf("Failed to connect to E2E test DB: %v", err) + } + + // 创建隔离 schema + schema := "e2e_test_" + randomID() + _, err = pool.Exec(context.Background(), "CREATE SCHEMA "+schema) + if err != nil { + t.Fatalf("Failed to create schema: %v", err) + } + + // 运行所有迁移 + if err := runMigrations(t, pool, schema); err != nil { + t.Fatalf("Failed to run migrations: %v", err) + } + + t.Cleanup(func() { + pool.Exec(context.Background(), "DROP SCHEMA "+schema+" CASCADE") + pool.Close() + }) + + return pool +} + +func TestE2E_BizdevWorkflow_Complete(t *testing.T) { + pool := setupE2ETestDB(t) + ctx := context.Background() + + // 1. 创建项目 + projectID := createProject(t, ctx, pool, "Project-Bizdev", "weichen") + + // 2. 获取三工作流目录 + workflows := listWorkflows(t, ctx, pool) + if len(workflows) != 3 { + t.Fatalf("Expected 3 workflows, got %d", len(workflows)) + } + + // 3. 选择商务对接流程 + bizdevWF := findWorkflow(workflows, "main") + plan := createPlan(t, ctx, pool, projectID, bizdevWF.Key) + + // 4. 激活 + instance := activateWorkflow(t, ctx, pool, projectID, plan) + if instance.Status != "active" { + t.Fatalf("Expected instance.status=active, got %s", instance.Status) + } + + // 5. 逐个批准 7 个文档 + docKeys := []string{ + "intake", "research", "feasibility_dev", "feasibility_reg", + "user_requirements", "prelim_design", "cdo_quote", + } + for i, docKey := range docKeys { + approveDocument(t, ctx, pool, instance.ID, docKey) + + // 检查门禁 + readiness := getStageReadiness(t, ctx, pool, instance.ID, "stage_v01") + if i < len(docKeys)-1 { + if readiness.Ready { + t.Fatalf("Stage should not be ready with %d/%d docs approved", + i+1, len(docKeys)) + } + } else { + if !readiness.Ready { + t.Fatalf("Stage should be ready after all docs approved") + } + } + } + + // 6. 推进各阶段 + advanceStage(t, ctx, pool, instance.ID, "stage_v01", 0) + advanceStage(t, ctx, pool, instance.ID, "stage_v05", 0) + + // 7. 完成最后阶段 + result := advanceStage(t, ctx, pool, instance.ID, "stage_v10", 0) + if result.CompletedAt == nil { + t.Fatal("Expected instance.completed_at to be set") + } + + // 8. 验证项目已返回 planning + settings := getProjectSettings(t, ctx, pool, projectID) + if settings.LifecycleStatus != "planning" { + t.Fatalf("Expected project lifecycle=planning, got %s", + settings.LifecycleStatus) + } + + // 9. 可配置下一个工作流 + workflows2 := listWorkflows(t, ctx, pool) + if len(workflows2) != 3 { + t.Fatalf("Cannot select next workflow") + } + + t.Logf("✅ Bizdev workflow complete chain PASSED") +} + +func TestE2E_ProductManagerWorkflow_Standalone(t *testing.T) { + pool := setupE2ETestDB(t) + ctx := context.Background() + + projectID := createProject(t, ctx, pool, "Project-PM", "weichen") + + // 选择产品经理流程(未运行商务流程) + pmWF := findWorkflow(listWorkflows(t, ctx, pool), "product_manager") + plan := createPlan(t, ctx, pool, projectID, pmWF.Key) + instance := activateWorkflow(t, ctx, pool, projectID, plan) + + // 批准 SRS 文档 + approveDocument(t, ctx, pool, instance.ID, "system_reqs") + + // 推进 + advanceStage(t, ctx, pool, instance.ID, "stage_pm", 0) + + // 完成 + result := advanceStage(t, ctx, pool, instance.ID, "stage_pm", 0) + if result.CompletedAt == nil { + t.Fatal("PM workflow should complete") + } + + t.Logf("✅ ProductManager workflow standalone PASSED") +} + +func TestE2E_TestEngineerWorkflow_WithoutSRS(t *testing.T) { + pool := setupE2ETestDB(t) + ctx := context.Background() + + projectID := createProject(t, ctx, pool, "Project-TE", "weichen") + + // 直接选择测试工程师流程,不需要先运行产品经理 + teWF := findWorkflow(listWorkflows(t, ctx, pool), "test_manager") + plan := createPlan(t, ctx, pool, projectID, teWF.Key) + instance := activateWorkflow(t, ctx, pool, projectID, plan) + + // PI Agent 生成测试方案(集成或 mock) + // ... + + // 批准测试方案 + approveDocument(t, ctx, pool, instance.ID, "test_manager") + + // 推进完成 + result := advanceStage(t, ctx, pool, instance.ID, "stage_te", 0) + if result.CompletedAt == nil { + t.Fatal("TE workflow should complete") + } + + t.Logf("✅ TestEngineer workflow without SRS PASSED") +} +``` + +**验收标准**: +- [ ] 商务流程 7 文档全流程完成 +- [ ] 产品流程独立运行无前置依赖 +- [ ] 测试流程无 SRS 也能运行 +- [ ] 每个完成流程后项目可配置下一个 +- [ ] 所有 E2E 测试 PASS +- [ ] 真实 PG + PI Agent 完整链路验证 + +**预计工作量**: 8h + +--- + +### Task B3: 项目上下文快照服务(ProjectContextSnapshot) + +**目标**: 为产品/测试流程提供统一、可复现的项目上下文 + +**新增文件**: `internal/projectcontext/service.go` + +**核心结构**: +```go +package projectcontext + +import "context" + +type ContextSnapshot struct { + ID int64 `json:"id"` + ProjectID int64 `json:"project_id"` + TaskID int64 `json:"task_id"` // 引用的任务(可选) + SnapshotHash string `json:"snapshot_hash"` + CreatedAt time.Time `json:"created_at"` + CreatedBy int64 `json:"created_by"` + + // 五层内容 + ProjectFacts ProjectFacts `json:"project_facts"` + ProjectDecisions ProjectDecisions `json:"project_decisions"` + ProjectDocuments ProjectDocuments `json:"project_documents"` + ProjectDialogue []DialogueEntry `json:"project_dialogue"` + HistoryOutputs []HistoryOutput `json:"history_outputs"` + KnowledgeHits []KnowledgeRef `json:"knowledge_hits"` + + // 血缘 + Sources []SourceManifest `json:"sources"` + ExcludedPrivate int `json:"excluded_private_count"` + ExcludedNoAccess int `json:"excluded_no_access_count"` +} + +type SourceManifest struct { + SourceType string // "project_fact", "document", "dialogue", etc. + SourceID int64 + SourceVersion int + SourceHash string + AuthorityLevel string // "confirmed", "approved", "reference", "evidence" + Permission string // "all_members", "shared_to_project", "private" + WasReferenced bool // 是否实际被输出引用 +} + +// Service 构建和查询项目上下文快照 +type Service struct { + store Store + projectStore projectworkflow.Store + docStore DocumentStore + dialogueStore DialogueStore +} + +func (s *Service) BuildContextSnapshot( + ctx context.Context, + projectID int64, + taskID int64, // 可选,用于任务的输入 +) (*ContextSnapshot, error) { + // 1. 收集五层源 + facts, err := s.gatherProjectFacts(ctx, projectID) + if err != nil { + return nil, err + } + + decisions, err := s.gatherProjectDecisions(ctx, projectID) + if err != nil { + return nil, err + } + + docs, sources, err := s.gatherProjectDocuments(ctx, projectID) + if err != nil { + return nil, err + } + + dialogue, excluded, err := s.gatherProjectDialogue(ctx, projectID) + if err != nil { + return nil, err + } + + history, err := s.gatherHistoryOutputs(ctx, projectID) + if err != nil { + return nil, err + } + + knowledge, err := s.gatherKnowledgeHits(ctx, projectID) + if err != nil { + return nil, err + } + + // 2. 冲突合并 + merged := s.mergeConflicts(facts, decisions, docs, dialogue, history) + + // 3. 计算 hash + hash := computeContentHash(merged) + + // 4. 保存快照 + snapshot := &ContextSnapshot{ + ProjectID: projectID, + TaskID: taskID, + SnapshotHash: hash, + CreatedAt: now, + CreatedBy: userID, + ProjectFacts: facts, + ProjectDecisions: decisions, + ProjectDocuments: docs, + ProjectDialogue: dialogue, + HistoryOutputs: history, + KnowledgeHits: knowledge, + Sources: sources, + ExcludedPrivate: excluded.PrivateCount, + ExcludedNoAccess: excluded.NoAccessCount, + } + + if err := s.store.SaveSnapshot(ctx, snapshot); err != nil { + return nil, err + } + + return snapshot, nil +} + +func (s *Service) gatherProjectFacts( + ctx context.Context, + projectID int64, +) (ProjectFacts, error) { + // 查询 projects 表和结构化事实黑板 + project, err := s.projectStore.GetProject(ctx, projectID) + if err != nil { + return ProjectFacts{}, err + } + + return ProjectFacts{ + ProjectName: project.Name, + CustomerName: project.Customer, + ProductType: project.ProductType, + IntendedUse: project.IntendedUse, + TargetMarket: project.TargetMarket, + StructuredFacts: project.StructuredFacts, + AuthorityLevel: "confirmed", // 项目元数据最权威 + }, nil +} + +func (s *Service) gatherProjectDocuments( + ctx context.Context, + projectID int64, +) (ProjectDocuments, []SourceManifest, error) { + // 查询当前有效版本的受控文档、共享文档、上传材料 + docs, err := s.docStore.ListProjectDocuments(ctx, projectID) + if err != nil { + return ProjectDocuments{}, nil, err + } + + sources := make([]SourceManifest, 0) + for _, doc := range docs { + sources = append(sources, SourceManifest{ + SourceType: "document", + SourceID: doc.ID, + SourceVersion: doc.LatestApprovedVersion, + SourceHash: doc.ContentHash, + AuthorityLevel: "approved", // 已批准文档 + Permission: "all_members", + WasReferenced: false, // 待填充 + }) + } + + return ProjectDocuments{ + ControlledDocs: docs, + AuthorityLevel: "approved", + }, sources, nil +} + +func (s *Service) gatherProjectDialogue( + ctx context.Context, + projectID int64, +) ([]DialogueEntry, ExcludedCounts, error) { + // 查询所有进入项目知识边界的对话 + // 过滤:私人草稿、个人私聊(未共享)不纳入 + + dialogue, excluded, err := s.dialogueStore.ListProjectDialogue( + ctx, projectID, true, // 仅已共享 + ) + + return dialogue, excluded, err +} + +// 冲突优先级: +// 确认事实/决策 > 已批准文档 > 上传材料 > 里程碑 > 普通对话 > 总结 +func (s *Service) mergeConflicts( + facts ProjectFacts, + decisions ProjectDecisions, + docs ProjectDocuments, + dialogue []DialogueEntry, + history []HistoryOutput, +) MergedContext { + // 若多个来源对同一概念有不同看法,按优先级择一 + // 例:需求既在 SRS 中又在对话中,选 SRS + + return MergedContext{ + // ... + } +} +``` + +**与现有系统集成**: +- 产品经理:调用 `ctxSvc.BuildContextSnapshot` 取数代替现有部分逻辑 +- 测试工程师:同样使用新快照,而非硬查 SRS +- 血缘追溯:输出文档内包含 source manifest 和追溯表 + +**测试**: +```go +func TestProjectContextSnapshot_ConsistentForSameInput(t *testing.T) { + // 同一项目在同一时刻的快照 hash 相同 +} + +func TestProjectContextSnapshot_ChangeWhenSourceUpdated(t *testing.T) { + // 新批准文档后快照 hash 改变 +} + +func TestProjectContextSnapshot_ExcludesPrivateContent(t *testing.T) { + // 私人草稿和未共享对话不纳入 +} + +func TestProjectContextSnapshot_LineageComplete(t *testing.T) { + // 输出包含所有被引用来源的 manifest +} +``` + +**验收标准**: +- [ ] 快照服务实现完整 +- [ ] 产品/测试工程师都使用新服务 +- [ ] 快照可复现(同输入 → 同快照) +- [ ] 血缘追溯表完整 + +**预计工作量**: 12h + +--- + +## 第三部分:验收与发布(Phase C) + +### Task C1-C7: 见前面 Phase C 表 + +**总体验收检查表**: + +``` +□ 单元测试覆盖 + □ 所有 bug fix 有负例测试 + □ 新功能覆盖率 > 50% + □ 关键路径覆盖率 = 100% + +□ 集成测试 + □ PG 集成测试全 PASS + □ 并发测试 PASS + □ 数据库迁移向前向后兼容 + +□ 真实 E2E(PostgreSQL + PI Agent) + □ 商务流程 PASS + □ 产品流程 PASS + □ 测试流程 PASS + □ 项目完成后切换 PASS + □ 受控终止 PASS + +□ 验收标准(见 7.1-7.5) + □ 目录仅三项 + □ 禁用文档全拒绝 + □ 推进不改文档状态 + □ 完成后可配置下一流程 + □ 安全与审计完整 + +□ 文档与发布 + □ API 文档更新 + □ 发布说明完成 + □ 迁移脚本与回滚 + □ 用户指南 + +□ 生产就绪检查 + □ 性能基准测试 + □ 压力测试 + □ 故障场景演练 + □ 审计日志覆盖 +``` + +--- + +**完整拆分总结**: +- **Phase A** (Day 1): 15 小时 - 关键缺陷修复 +- **Phase B** (Day 2-3): 26 小时 - 新功能开发 +- **Phase C** (Day 4-5): 20 小时 - 完善与发布 + +**总计**: ~61 小时 + +--- + +**下一步**: 选择一项任务开始实施,或全队并行进行。 diff --git a/.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md b/.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md new file mode 100644 index 00000000..8018467f --- /dev/null +++ b/.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md @@ -0,0 +1,525 @@ +# 三工作流严格治理与现有系统融合整改方案 + +- 日期:2026-09-12 +- 状态:核心业务决策已确认 / 可进入实施拆分 +- 范围:工作流定义、项目实例、阶段门禁、文档三权、通知与对话推进、运行时授权、数据迁移和验收 +- 本文性质:当前代码与开发数据库的只读核验结论及整改设计;本轮未修改业务代码 + +## 1. 结论先行 + +系统面向项目创建者和项目成员时,只应存在以下 **3 个可选择工作流**: + +1. **商务对接流程**:7 个文档,3 个阶段; +2. **智能产品经理流程**:1 个输出文档,1 个阶段; +3. **智能测试工程师流程**:1 个输出文档,1 个阶段。 + +商务对接流程的文档数量可以定案为 **7 个,不是 6 个**。前端模板工厂和测试固定断言了 7 个任务键,后端标准任务目录也包含同一组 7 个商务文档,历史专项测试报告同样把它们定义为标准全生命周期交付物。[^biz-seven-test][^biz-seven-backend][^biz-seven-report] + +当前系统尚未满足这一目标,且不是简单改几个显示名称即可解决: + +- 启动代码实际发布 5 个默认工作流,除目标三项外还包含“医疗器械研发”和“非医疗纯软件”;[^bootstrap-five] +- 当前开发库已有 92 个工作流定义,其中大量为测试定义;三个目标工作流仍都是单阶段的 schema v1; +- 仓库虽然有三个 schema v2 清单,但商务清单只有 5 个文档,漏了 `feasibility_dev` 和 `user_requirements`;[^main-v2-missing] +- 三个 v2 清单仅被嵌入和登记,没有进入启动发布链;已有发布版又会让 seed 逻辑直接退出,因此现有库不会自动升级;[^manifest-loader][^seed-no-upgrade] +- 旧运行入口会把多阶段版本压成“第一个阶段的第一个任务”,与项目实例运行时并存,形成双轨权威;[^catalog-flatten] +- 配置页面允许勾选关闭文档,但后端校验禁止关闭所有 `required/blocking` 文档;当前清单又把所有文档都标成这两类,因此界面能力实际上不可用;[^plan-disable-conflict] +- 智能测试工程师当前被 manifest、执行服务和前端提示硬绑定到产品经理/SRS,与已确认的两个智能工作流独立运行原则冲突;[^test-upstream][^test-hard-dependency] +- 阶段推进虽然先检查批准状态,但事务内会把所有启用任务强制写成 `approved`,并且最后阶段完成后没有把项目恢复到可选择下一工作流的状态;[^advance-forces-approved][^project-lifecycle-gap] +- 对话中的“推进阶段”仍调用旧商务成熟度执行器,并没有调用项目工作流实例的阶段推进服务;[^dialogue-old-advance] + +因此本次整改的核心是:**以已激活项目工作流实例的冻结快照作为唯一运行时权威**。工作流目录、项目配置、文档三权、任务启动、审批、阶段门禁、通知和对话都必须围绕同一个实例标识运行,旧的直接切换和扁平执行入口退出生产路径。 + +## 2. 已确认的业务基线 + +### 2.1 唯一允许对项目展示和选择的工作流 + +| 稳定内部 key | 对外名称 | 阶段数 | 输出文档数 | 说明 | +|---|---|---:|---:|---| +| `main` | 商务对接流程 | 3 | 7 | 保留现有 key 以避免破坏历史数据,只改正式名称 | +| `product_manager` | 智能产品经理流程 | 1 | 1 | 输出《系统需求规格书》 | +| `test_manager` | 智能测试工程师流程 | 1 | 1 | 保留现有 key,只把“测试经理”统一更名为“测试工程师” | + +“系统只需要三个流程”的含义应同时落实到三个层面: + +- 项目设置 API 只返回这 3 个可选项; +- 前端任何入口只展示这 3 个可选项; +- 服务端只允许为这 3 个正式、已发布版本创建项目工作流实例。 + +后台可以保留历史定义和草稿以满足审计,但必须标记为 `retired` 或 `project_selectable=false`,不能继续出现在项目目录中。不能仅靠前端白名单隐藏,因为当前设置服务会枚举数据库里全部有发布版本的定义。[^settings-all-definitions] + +### 2.2 商务对接流程:7 个文档,3 个阶段 + +沿用系统已经形成的 V0.1 / V0.5 / V1.0 业务阶段和模板归属,目标定义如下。当前模板工厂已按 `1 + 5 + 1` 归档这 7 个文档。[^template-stage-map] + +| 阶段 | 顺序 | task key | 正式文档名 | 默认状态 | 阶段门禁 | +|---|---:|---|---|---|---| +| V0.1 需求摸底 | 10 | `intake` | 用户初始需求收集表 | 启用 | 启用时必须批准 | +| V0.5 方案与可行性 | 20 | `research` | 调研报告 | 启用 | 启用时必须批准 | +| V0.5 方案与可行性 | 21 | `feasibility_dev` | 设计开发可行性评估报告 | 启用 | 启用时必须批准 | +| V0.5 方案与可行性 | 22 | `feasibility_reg` | 注册路径可行性评估报告 | 启用 | 启用时必须批准 | +| V0.5 方案与可行性 | 23 | `user_requirements` | 用户需求表 | 启用 | 启用时必须批准 | +| V0.5 方案与可行性 | 24 | `prelim_design` | 系统初步设计方案 | 启用 | 启用时必须批准 | +| V1.0 商务报价 | 30 | `cdo_quote` | CDO 报价单 | 启用 | 启用时必须批准 | + +当前后端商务阶段只执行 `intake`、`research`、`feasibility_reg`、`prelim_design`、`cdo_quote` 五项,正好缺少另外两项,必须同步补齐阶段执行映射和 executor 注册。[^biz-stage-five][^executor-missing] + +### 2.3 智能产品经理流程 + +| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 | +|---|---|---|---|---| +| 系统需求基线 | `system_reqs` | 系统需求规格书 | 启用 | 文档批准后,创建者确认完成工作流 | + +### 2.4 智能测试工程师流程 + +| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 | +|---|---|---|---|---| +| 系统验证策划 | `test_manager` | 系统验证方案及计划 | 启用 | 文档批准后,创建者确认完成工作流 | + +**智能产品经理流程和智能测试工程师流程相互解耦。** 智能测试工程师流程不再要求项目曾运行智能产品经理流程,也不再要求必须存在该流程输出的《系统需求规格书》。它直接从当前项目可用于工作流的对话、文档、上传材料、项目事实和决策记录中提取需求及验证依据,独立生成《系统验证方案及计划》。 + +如果项目中恰好存在已批准的《系统需求规格书》,它只是项目输入集合中的一项高权威来源,不是启动前置条件,也不产生流程级耦合。当前 manifest、执行服务、血缘逻辑和前端提示仍硬编码了这一依赖,整改时必须一起删除。[^test-upstream][^test-hard-dependency] + +### 2.5 两个智能工作流的统一项目上下文输入 + +智能产品经理和智能测试工程师使用同一个“项目上下文快照服务”,但采用不同的分析目标和输出模板: + +| 输入类别 | 纳入内容 | 建议权威等级 | +|---|---|---| +| 项目事实 | 项目名称、客户、产品类型、预期用途、目标市场、结构化事实黑板 | 已确认事实 | +| 项目决策 | 创建者确认事项、里程碑决策、已关闭的待确认项 | 已确认决策 | +| 项目文档 | 当前有效版本的受控文档、项目共享文档、上传材料 | 按批准状态和来源分级 | +| 项目对话 | 所有已进入项目共享知识边界的成员对话及其附件 | 原始沟通证据 | +| 历史输出 | 商务、产品、测试或自由任务形成的项目交付物 | 按状态和版本分级 | +| 知识依据 | 系统检索到的法规、标准和内部知识库命中 | 外部参考依据 | + +这里的“所有”是指 **当前项目知识边界内全部有资格被工作流使用的内容**,不是把数据库中所有原文无差别拼接到一次模型调用中。建议遵循以下规则: + +1. 只纳入当前项目,绝不跨项目召回; +2. 私人草稿、个人私聊只有在明确“共享到项目”后才进入项目级工作流输入,避免流程执行扩大原有可见范围; +3. 任务启动时生成不可变 `project_context_snapshot`,记录截止时间、来源 ID、版本、内容 hash、权限判定和引用位置; +4. 全量来源先建立清单,再按任务目标检索相关片段;已确认事实和已批准文档必须进入固定核心上下文,普通对话按相关性分批读取; +5. 冲突时不静默覆盖,优先级建议为:创建者确认事实/决策 > 当前已批准文档 > 用户上传原始材料 > 里程碑记录 > 普通项目对话 > 智能体历史总结; +6. 输出必须带 source manifest。智能测试工程师需在唯一输出文档内部生成“需求/风险—测试项—来源”追溯表,不额外创建第二个受控输出文档; +7. 任务运行后项目来源发生变化时,依据被引用来源的 hash 判断 `input_changed/stale`,而不是只监听《系统需求规格书》。未被本次输出引用的无关对话变化不应把文档误标为 stale。 + +现有 Squad 工作区已经支持 project context、materials、prior docs、knowledge hits 等输入槽位,也会建立带权威等级的 context 索引;产品经理还已有从项目事实和里程碑生成输入材料的局部实现。因此应把这些能力上移为通用项目上下文快照服务,而不是为测试流程继续维护单一 SRS 特例。[^context-input-foundation] + +## 3. 不可违反的业务规则 + +### 3.1 选择、启动和切换 + +1. 只有项目创建者可以选择、配置、激活、推进或受控终止项目工作流。 +2. 一个项目同一时刻最多只能有一个 live 实例。 +3. 在 `active`、`awaiting_stage_confirmation` 或 `termination_requested` 状态下,不允许选择或切换工作流。 +4. “切换工作流”不是修改当前实例的 `workflow_key`,而是当前实例 `completed` 或 `terminated` 后创建一个新的 planning 实例。 +5. 激活时冻结工作流版本、阶段、文档开关、模板版本、执行器、质量门禁和三权责任人。运行中不可静默修改。 +6. 管理员不因系统身份自动替代项目创建者执行推进;如以后引入 break-glass,必须单独设计理由、再认证和审计,且不能代替文档签署人。 + +目标状态机: + +```mermaid +stateDiagram-v2 + [*] --> planning: 创建者选择并配置 + planning --> active: 预览后确认激活 + active --> awaiting_stage_confirmation: 当前阶段所有启用文档已批准 + awaiting_stage_confirmation --> active: 创建者确认进入下一阶段 + awaiting_stage_confirmation --> completed: 创建者确认完成最后阶段 + active --> termination_requested: 创建者申请终止 + termination_requested --> terminated: 二次确认并记录原因 + completed --> planning: 创建下一工作流实例 + terminated --> planning: 创建下一工作流实例 +``` + +数据库已经为一个 planning 实例和一个 live 实例设置了部分唯一索引,也预留了 `awaiting_stage_confirmation`、`terminated` 等状态,适合沿此模型完善,不必另造一套表。[^instance-schema] + +### 3.2 文档启用与禁用 + +项目创建者可以在 planning 状态逐文档启用或禁用。严格语义如下: + +| 文档状态 | 三权配置 | 可创建/启动编制 | 可提交审核 | 可审核 | 可批准 | 是否计入阶段门禁 | +|---|---|---:|---:|---:|---:|---:| +| enabled | 作者、审核人、批准人均必填且互斥 | 是,仅作者或明确执行人 | 是,仅作者 | 是,仅审核人 | 是,仅批准人 | 是 | +| disabled | 必须为空 | 否 | 否 | 否 | 否 | 否 | + +关键约束: + +- `default_enabled` 只表示默认值,不表示不可关闭; +- `blocking_when_enabled=true` 表示文档一旦启用,未批准就阻断阶段; +- 新增明确字段 `creator_configurable=true/false`,不要继续混用现有 `required`、`blocking`、`default_enabled` 三个布尔值表达四种含义; +- 禁用后实例状态写为 `skipped_disabled`,不创建 DocGov 文档、不生成三权行,也不允许通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动; +- 对禁用文档发起动作时统一返回 `409 DOC_TASK_DISABLED`;对启用文档但责任人不匹配返回 `403 DOC_DUTY_FORBIDDEN`; +- 激活计划必须至少包含一个启用文档。这样一文档流程仍可在配置时关闭唯一文档,但关闭后不能激活一个没有产出的空工作流。 + +现有数据结构已经能表达 `enabled` 和三权,且持久化时会跳过禁用文档的职责写入;可复用这部分。问题在于定义校验把 required/blocking 文档一律视为不可关闭,需要先修正语义。[^plan-structure][^duty-write-enabled-only] + +### 3.3 阶段完成和推进 + +阶段就绪的唯一业务判定应为: + +```text +stage_ready = 当前阶段处于 active + AND 当前阶段至少有一个 enabled 文档 + AND 每个 enabled 文档的当前受控版本都为 approved + AND 没有正在执行、待审核、待批准或 stale 的同任务实例 +``` + +推进动作必须满足: + +- 服务端在同一数据库事务中锁定 workflow instance 和 stage instance; +- 重新计算门禁,不能只信几秒前的 readiness 响应; +- 校验操作者仍是项目创建者; +- 校验 `expected_config_revision` 和幂等键; +- 只改变阶段和实例状态,绝不把文档“补写”为 approved; +- 进入下一启用阶段;若没有下一阶段,则把实例标为 completed,并把项目切回“可配置下一个工作流”的状态; +- 同事务关闭对应 `stage_advance_request`,写审计和 outbox 事件。 + +当前 readiness 已经忽略禁用任务、检查启用必需文档是否批准,并限制创建者推进,这一骨架可以保留;但它按 `project_id + task_key` 汇总文档状态,仍需升级到 `doc_task_instance_id + document_version_id`,避免跨阶段或重复实例串线。[^readiness-current][^approval-key-too-wide] + +### 3.4 主动提醒和对话推进 + +系统在 readiness 从 false 变为 true 时生成一次 `stage.ready_to_advance` 事件,并只通知项目创建者。已有 outbox、站内通知、去重键以及 24 小时再次提醒机制可以复用。[^notify-ready][^notify-reminder] + +建议闭环: + +1. 最后一份启用文档批准; +2. 事务后事件处理器重新计算 readiness; +3. 实例进入 `awaiting_stage_confirmation`; +4. 创建者收到站内消息和可操作确认卡:阶段名、启用/已批准文档清单、下一阶段或“完成工作流”; +5. 创建者点击按钮,或在项目对话中说“推进到下一阶段 / 确认推进”; +6. 两种入口都调用同一个 `AdvanceStage` 应用服务; +7. 成功后通知状态改为 acted,推进请求改为 confirmed;若条件在确认前失效,则返回最新阻断项并把旧请求标为 superseded。 + +当前前端已经每 15 秒拉取通知并显示“确认推进”按钮,但对话入口仍走旧的 `bizdev.ExecuteStage`,所以需要把自然语言意图解析与执行彻底分开:识别器只产生命令,实例服务才拥有推进权。[^stage-banner][^dialogue-old-advance] + +## 4. 当前系统与目标的差距 + +### 4.1 定义和目录 + +| 编号 | 当前事实 | 风险 | 整改 | +|---|---|---|---| +| WF-CAT-01 | Bootstrap 发布 5 个工作流 | 项目会看到目标外流程 | 只发布三项;其余退役且不可选 | +| WF-CAT-02 | 设置服务返回所有有发布版的定义 | 测试/历史流程进入项目 | 增加 `project_selectable`,查询端白名单 + 状态双重校验 | +| WF-CAT-03 | 开发库有 92 个定义,88 个 key 为 `pg_*` 或 `test_*` | 测试污染业务目录 | 测试强制独立数据库/schema,fixture 必须清理 | +| WF-DEF-01 | 三个正式 key 当前均为 schema v1 单阶段 | 实际运行不是目标结构 | 以新版本发布 schema v2/v3,禁止覆盖旧版本 | +| WF-DEF-02 | `main.v2.json` 只有 5 个文档 | 商务流程缺 2 个输出 | 补齐 7 个并增加 executor、模板和质量门禁校验 | +| WF-DEF-03 | v2 manifest 未进入 bootstrap | 仓库文件与运行数据库不一致 | 建立 manifest 迁移器,按 hash 创建并发布新版本 | +| WF-DEF-04 | seed 发现任何 published 就跳过 | 永远停留旧版本 | 按内容 hash 和目标版本升级,写版本迁移审计 | +| WF-DEF-05 | DBCatalog 压扁完整定义 | 多阶段配置不能驱动运行 | 删除生产 flatten 路径,运行只读取冻结实例 | +| WF-DEF-06 | 测试流程声明 product_manager 上游,执行服务又硬查 approved SRS | 两个智能工作流不能独立运行 | 删除流程级依赖;改用统一项目上下文快照和多来源血缘 | + +### 4.2 项目实例和生命周期 + +| 编号 | 当前事实 | 风险 | 整改 | +|---|---|---|---| +| WF-INS-01 | planning / active 和唯一 live 骨架已存在 | 可复用但未闭环 | 扩展 awaiting/completed/terminated 完整转换 | +| WF-INS-02 | 完成最后阶段只更新实例 | 项目仍为 active,无法配置下一流程 | 同事务更新项目可选择状态并清空 current live 指针 | +| WF-INS-03 | 无受控终止 API | 异常流程永久锁死或只能改库 | 增加申请、影响预览、创建者二次确认和终止原因 | +| WF-INS-04 | 激活 token 明文保存,消费与激活分事务 | 失败后 token 已失效或可泄露 | 只存 hash,并在激活事务内锁定、消费 | +| WF-INS-05 | 冻结子任务只写 key/enabled/status | executor、模板、质量门禁仍依赖可变定义 | 激活时把完整运行元数据写入实例表并以实例表为权威 | + +数据库已添加 executor/template/quality gate 列,但当前实例写入 SQL 仍只插入 task key、enabled 和 status,证明冻结快照尚未真正成为执行权威。[^instance-runtime-metadata] + +### 4.3 文档、三权和运行时授权 + +| 编号 | 当前事实 | 风险 | 整改 | +|---|---|---|---| +| WF-DOC-01 | 启用文档要求三权且互斥 | 基础规则正确 | 再校验三人均为 active 项目成员且账户有效 | +| WF-DOC-02 | 禁用文档不会写三权 | 基础持久化正确 | 增加 `skipped_disabled` 和全入口拒绝 | +| WF-DOC-03 | 访问过滤按 task key 判断 | 同 key 重复实例可能串权 | 所有动作使用 `doc_task_instance_id` | +| WF-DOC-04 | 无 live 实例时访问过滤默认不限制 | 完成后旧任务入口可能恢复可用 | 正式项目按治理模式 fail closed;legacy 仅限显式迁移标记 | +| WF-DOC-05 | 运行入口仍接受 task key 并查扁平目录 | 可能绕过阶段和冻结绑定 | 请求只传 doc task instance id,服务端解析 executor/template/duty | +| WF-DOC-06 | DocGov 状态机可验证具体审核/批准人 | 可复用 | 文档必须外键绑定 doc task instance 和版本 | + +现有阶段访问代码确实会从 live 快照中排除禁用任务,这是可保留的基础;但当没有 live 实例或实例 completed 时会返回 unrestricted,因此不能把它视为禁用文档全生命周期的完整保障。[^stage-access] + +### 4.4 前端、通知和对话 + +| 编号 | 当前事实 | 风险 | 整改 | +|---|---|---|---| +| WF-UI-01 | 旧切换器硬编码三项,但名称不一致 | 用户认知混乱 | 统一为三个正式名称,数据来自服务端目录 | +| WF-UI-02 | 新治理 API 失败时回退旧直接切换 UI | 可重新打开不合规路径 | 删除回退;治理不可用时只读并明确报错 | +| WF-UI-03 | 旧切换在版本冲突后自动重试 | 可能覆盖用户最新选择 | 展示冲突并要求重新确认,不自动提交高风险操作 | +| WF-UI-04 | 项目设置只显示 stage/task key | 不利于业务确认 | 显示正式阶段名、文档名、启用状态、三权和影响摘要 | +| WF-UI-05 | live 配置缺少完整只读审计视图 | 创建者不清楚冻结内容 | 展示版本、hash、激活人/时间、所有 enabled/disabled 和职责 | +| WF-NOTIFY-01 | readiness 通知和 24h 提醒已存在 | 基础可复用 | 增加状态转换、已读/已处理、失效和重算 | +| WF-DLG-01 | 对话推进旧商务阶段 | 可越过新实例门禁 | 对话调用同一实例 AdvanceStage command | +| WF-CTX-01 | 产品经理仅在无材料时拼装部分项目事实;测试工程师只注入 SRS | “全部项目内容”没有统一、可复现的输入语义 | 建立项目上下文快照、来源清单、权限过滤、冲突优先级和 hash 血缘 | + +旧前端切换器在治理不可用时仍调用 `/active-workflow`,并在冲突后自动取新版本再次切换;这两个行为都应删除。[^legacy-switch-ui] 旧服务端路由在迁移完成后应返回 `410 WORKFLOW_SWITCH_API_RETIRED`,而不是继续作为备用入口。[^legacy-route] + +### 4.5 开发数据库现场快照 + +2026-09-12 对当前 `shuimu-context-pg-dev / agent_system_dev` 做只读查询得到: + +```text +workflow_definitions = 92 +published workflow versions = 92 +main = version 1, schema 1, 1 stage +product_manager = version 1, schema 1, 1 stage +test_manager = version 1, schema 1, 1 stage +project_workflow_instances: active 32, completed 47 +projects.lifecycle_status: active 97, planning 51 +completed 实例已存在、无 live 实例但项目仍为 active:47 个 +测试命名定义(pg_* / test_*):88 个 +``` + +这些数字主要反映当前开发环境和集成测试污染,不能直接当成生产数据;但它们证明目录查询没有隔离正式定义与测试定义,也直接复现了“实例已完成而项目仍 active”的生命周期断点。PG 测试在未设置 `TEST_DATABASE_URL` 时默认连接开发库,部分定义发布测试又没有清理工作流定义,因此必须纳入整改。[^test-db-default][^test-definition-no-cleanup] + +## 5. 目标技术模型 + +### 5.1 单一运行权威 + +```text +Published Workflow Version + │ 创建 planning plan + ▼ +Project Workflow Instance + immutable config snapshot + │ 激活时物化 + ├── Stage Instances + │ └── Doc Task Instances + │ ├── frozen executor/template/quality gate + │ ├── duty assignments + │ ├── controlled document versions + │ └── task runs + ├── Stage Advance Requests / Notifications + └── Audit / Outbox Events +``` + +激活后,任何运行请求不得再从“最新发布定义”、前端 task key 或 legacy catalog 推导行为。最新定义只用于创建未来实例;已运行实例永远引用自己的冻结数据。 + +### 5.2 定义 schema 建议 + +文档任务应至少明确以下字段: + +```json +{ + "key": "research", + "title": "调研报告", + "default_enabled": true, + "creator_configurable": true, + "blocking_when_enabled": true, + "executor_key": "bizdev.research.v1", + "quality_gate_key": "quality.generic.v1", + "template": {"asset_key": "research", "version": 1}, + "output_doc_type": "research", + "output_doc_title": "调研报告" +} +``` + +发布校验必须增加: + +- workflow key 属于三个正式 key 之一,且对外名称准确; +- 阶段 key、position、任务 key 均唯一且非空; +- 每个阶段至少一个文档任务; +- executor、quality gate 和 ready 模板版本全部存在; +- 三个正式流程精确满足 7 / 1 / 1 文档清单; +- 三个正式工作流均不声明流程级 `required_upstream_workflow`; +- 项目上下文输入策略、来源权限和冲突优先级完整; +- 禁用策略、完成策略和参与策略完整; +- 发布后版本不可原地修改。 + +当前 v2 校验只检查 schema 版本、阶段位置、executor/quality gate 注册和输出类型,尚不足以守住上述业务契约。[^validator-v2] + +### 5.3 数据结构增量 + +优先扩展现有表,不重复建模: + +- `workflow_definitions`:增加 `project_selectable`、`catalog_order`、`official_code`; +- `workflow_versions.definition_json`:采用新禁用语义并保留版本 hash; +- `project_workflow_instances`:增加 `completed_at/by`、`terminated_at/by/reason`、`previous_instance_id`; +- `project_stage_instances`:增加 `ready_at`、`completed_at/by`; +- `project_doc_task_instances`:持久化 `executor_key`、`quality_gate_key`、模板 asset/version、output type/title;禁用任务状态为 `skipped_disabled`; +- `documents`:增加 `doc_task_instance_id`,受控文档版本唯一绑定; +- `project_context_snapshots`:记录项目、任务、截止时间、汇总 hash、创建人和冻结状态; +- `project_context_snapshot_sources`:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用; +- `task_runs`:增加 `workflow_instance_id`、`stage_instance_id`、`doc_task_instance_id`、`context_snapshot_id`; +- `document_lineages`:从单一“上游 SRS”扩展为多来源 lineage,允许对话、材料、事实、决策和文档版本作为来源; +- `stage_advance_requests`:保留 readiness revision,补 `idempotency_key`、`superseded_at`; +- 审计事件:至少记录 plan saved、activated、document disabled/enabled、duty assigned、stage ready、stage advanced、workflow completed/terminated。 + +### 5.4 API 收敛 + +建议正式接口: + +| 方法与路径 | 用途 | 关键约束 | +|---|---|---| +| `GET /api/v1/workflows/catalog` | 返回严格三项正式目录 | 只含 project_selectable + published | +| `GET /api/v1/projects/{id}/settings` | 规划或冻结配置视图 | 项目访问控制 | +| `PUT /api/v1/projects/{id}/workflow-plan` | 选择流程、开关文档、设置三权 | 仅创建者、仅 planning、乐观锁 | +| `POST /api/v1/projects/{id}/activation-preview` | 完整影响与校验 | 无空流程、三权和上下文策略通过 | +| `POST /api/v1/projects/{id}/workflow-instances/activate` | 冻结并激活 | 创建者二次确认、原子 token | +| `GET /api/v1/workflow-instances/{id}` | 运行和历史详情 | 项目 + 阶段可见性 | +| `GET /api/v1/workflow-instances/{id}/stages/{key}/readiness` | 门禁详情 | 返回所有启用文档状态 | +| `POST /api/v1/workflow-instances/{id}/stages/{key}/advance` | 创建者推进或完成 | 事务内重算、幂等 | +| `POST /api/v1/workflow-instances/{id}/termination-preview` | 终止影响 | 未决任务、文档和通知清单 | +| `POST /api/v1/workflow-instances/{id}/terminate` | 受控终止 | 创建者、原因、二次确认 | +| `POST /api/v1/doc-task-instances/{id}/runs` | 启动编制 | enabled + active stage + duty | + +旧 `/projects/{id}/active-workflow` 和依赖扁平 workflow key 的 run 接口先记录迁移告警,完成客户端切换后返回 410。 + +## 6. 实施顺序 + +### Phase 0:冻结错误扩散和数据盘点 + +1. 给项目目录增加服务端正式白名单,立即只暴露三个目标 key。 +2. 禁止测试默认连接开发库;CI 必须显式提供隔离的 `TEST_DATABASE_URL`。 +3. 备份并分类 92 个定义及其引用:正式、历史、测试、被实例引用。 +4. 未被任何实例引用的测试定义在开发环境清理;被引用定义只退役,不物理删除。 +5. 修复开发环境中 completed instance 与 project lifecycle 不一致的数据,但先输出 dry-run 清单。 + +### Phase 1:发布三个唯一正式定义 + +1. 修订三个 manifest 的正式名称与 schema;商务流程补齐 7 个文档。 +2. 为 `feasibility_dev` 和 `user_requirements` 注册专用 executor,或明确映射到通用任务 executor;禁止使用含混的法规 executor 代替。 +3. 从 `test_manager` manifest、默认目录和校验模型中删除 `required_upstream_workflow=product_manager`,使三个流程在流程级完全独立。 +4. 增加严格发布校验和 7 / 1 / 1 契约测试。 +5. 实现 hash 驱动的版本升级:已有 v1 时创建 v2/v3,而不是退出或覆盖。 +6. `medical_device_development`、`non_medical_software` 及其他定义全部 `project_selectable=false` 并退役。 + +### Phase 2:补齐实例状态机和禁用语义 + +1. 重构 plan validator:creator-configurable 文档可关闭;启用文档三权必填;空工作流不可激活。 +2. 校验三权人员为有效项目成员、账户有效且三权互斥。 +3. 激活时完整物化运行元数据,以实例为唯一权威。 +4. 阶段推进事务内重算门禁,删除“推进时强制批准文档”的 SQL。 +5. 完成最后阶段时同步更新项目状态,使其可创建下一 planning 实例。 +6. 实现受控终止,保证 live 实例不会永久锁住项目。 + +### Phase 3:运行、文档治理和权限合流 + +1. 建立通用项目上下文快照服务,覆盖项目事实、项目级对话、文档、材料、决策、历史输出和知识命中。 +2. 产品经理和测试工程师分别从同一快照服务取数;删除测试任务中“查找已批准 system_reqs,否则拒绝”的特例。 +3. 所有任务启动改用 `doc_task_instance_id`;服务端解析 task/executor/template/stage/duty/context snapshot。 +4. 文档创建、查看、编辑、提交、审核、批准均校验同一 doc task instance。 +5. disabled、非当前阶段、非责任人、实例非 live 均 fail closed。 +6. SSE、异步 task run、恢复/取消、RAG 检索、Agent tools 使用同一策略决策。 +7. 审批回调按具体文档版本更新具体 doc task instance,不再按项目 + task key 批量更新。 +8. 把 SRS 单来源 lineage 改成 source manifest 多来源血缘;只在实际引用来源变化时标记输出待复核。 + +### Phase 4:通知、对话和前端闭环 + +1. readiness 边沿触发状态和通知,补 read/acted/dismissed API。 +2. 把对话“推进/完成工作流”绑定到项目实例 command;保留明确确认卡。 +3. 项目设置只显示三项,按正式名称显示阶段和文档。 +4. active/awaiting 时显示冻结只读视图,隐藏所有切换动作。 +5. completed/terminated 后显示“配置下一个工作流”,而不是修改旧实例。 +6. 删除旧切换回退、冲突自动重试和 `WorkflowPrerequisiteBanner` 的产品经理前置提示。 +7. 在运行预览中展示项目上下文截止时间、来源数量、被排除的私有/无权内容和冲突项。 + +### Phase 5:迁移和发布 + +1. 新项目只允许使用新的三个正式版本。 +2. 尚未激活的 planning v1 计划自动重建为新版本草稿,并要求创建者重新确认三权。 +3. 已激活 v1 实例不静默改写:真实业务实例由创建者选择继续兼容完成或受控终止后重建;开发/测试垃圾实例按确认后的清理脚本处理。 +4. 先 shadow 计算新旧 readiness 差异,再开启新推进服务。 +5. 通过全套验收后关闭 legacy route 和 flatten catalog。 + +## 7. 验收标准 + +### 7.1 目录和定义 + +- 任意项目、任意普通用户或管理员在项目选择页都只能看到 3 个工作流。 +- 正式名称精确为“商务对接流程 / 智能产品经理流程 / 智能测试工程师流程”。 +- 定义快照精确为 7 / 1 / 1;缺一、多一、重复 key、模板未 ready 或 executor 未注册均无法发布。 +- 三个正式定义均没有流程级上游依赖;产品经理和测试工程师可被分别独立选择和运行。 +- 服务重启、数据库迁移和旧数据存在时,目录结果仍稳定为三项。 + +### 7.2 选择和冻结 + +- 只有项目创建者可保存、激活和推进;普通成员、系统管理员默认均被拒绝。 +- live 实例存在时,UI、API 和对话三个入口均不能切换。 +- 工作流完成或受控终止后,创建者可以配置下一实例;旧实例保持只读可追溯。 +- 两个浏览器同时配置或推进时只有一个成功,另一个收到版本冲突并重新确认。 + +### 7.3 文档开关和三权 + +- 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活。 +- 禁用文档没有职责行、没有受控文档、没有运行按钮,也不能通过手工 API、SSE 或对话启动。 +- 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED`。 +- 再启用只允许发生在 planning;激活后不能原地改变。 + +### 7.4 阶段门禁和提醒 + +- 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断并返回清单。 +- 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒。 +- readiness 后文档被驳回或标 stale 时,旧推进请求失效,确认动作不能成功。 +- 推进事务不会修改任何文档审批状态。 +- 最后一阶段确认后实例为 completed,项目立即可配置下一流程。 + +### 7.5 安全、恢复和真实链路 + +- 跨项目、非成员、非职责人、未来阶段成员、已退出成员全部有服务端负例。 +- API、SSE、异步任务、断线恢复、搜索、导出、RAG 和 Agent tool 的判定一致。 +- 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求。 +- 使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路。 +- 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案;输出包含逐项来源追溯和待确认清单。 +- 项目已有 SRS 时,该文档被当作高权威来源纳入,但移除它不会导致工作流定义级依赖错误;是否需要重新生成由本次 source manifest 判断。 +- 项目私聊/个人草稿未共享时不进入上下文;共享后可被新快照发现。跨项目内容在检索和快照层都有负例。 +- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致,输出目标和模板不同。 +- 测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义或测试项目。 + +## 8. 已确认的业务决策及实施解释 + +2026-09-12 已确认以下决策,后续实现和验收以此为准: + +1. **允许关闭单文档流程的唯一文档,但空工作流不能激活。** 配置可以保存,激活预览必须明确阻断并提示重新启用文档或选择其他工作流。 +2. **智能产品经理和智能测试工程师解耦。** 两者都直接使用当前项目知识边界内的对话、文档、材料、事实和决策。任何一方的产出都不是另一方的启动前置;已有 SRS 仅作为高权威输入来源。 +3. **开放项目创建者受控终止工作流。** 必须二次确认、填写原因、处理或取消在途任务并形成审计;completed 和 terminated 都允许创建下一工作流实例,但历史含义必须区分。 + +这些决策合理且彼此一致。第 2 项的实施建议是“流程解耦、数据可组合、来源可追溯”,而不是取消质量控制:测试工程师必须自己从项目上下文抽取需求和风险,生成文档内追溯矩阵,并将缺少判据的内容列为待确认,不能因为没有 SRS 就编造需求。 + +商务流程按 7 个文档落地、系统只暴露三个正式流程、运行中不可切换、阶段推进必须由创建者确认、禁用文档不得参与任何编审批动作,也均为已确认要求。 + +## 9. 建议的实施交付拆分 + +建议按以下 8 个可独立评审的变更集提交,避免一次大改难以回滚: + +1. 正式目录隔离与测试数据库隔离; +2. 三个正式 manifest、严格 validator 和版本升级器; +3. planning 配置、文档开关和成员/三权校验; +4. 激活冻结与完整实例物化; +5. doc task instance 驱动的执行、DocGov 和统一授权; +6. 原子 readiness / advance / complete / terminate 状态机; +7. 通知、对话命令与前端只读/下一流程体验; +8. 数据迁移、兼容退出、真实 PG/PI Agent E2E 和发布门禁。 + +每个变更集都应包含正向测试、越权负例、并发负例和重启恢复验证。只有第 8 项完成后,才应删除旧兼容路径并宣布三工作流治理正式生效。 + +## 10. 来源与证据 + +[^biz-seven-test]: `web/src/engine/templateFactory.test.ts:8-33`,测试精确断言 7 个任务键;读取于 2026-09-12。 +[^biz-seven-backend]: `internal/squad/service.go:128-138`,后端标准任务目录包含 7 个商务任务及产品、测试任务;读取于 2026-09-12。 +[^biz-seven-report]: `.doc/test-reports/2026-09-08-project-init-template-cloning-test-report.md:12-25,51-60`,历史专项测试把商务全生命周期固定为 7 个受控交付物;读取于 2026-09-12。 +[^bootstrap-five]: `internal/workflowdef/bootstrap.go:63-74,78-115`,启动种子包含三个旧流程及两个额外行业流程;读取于 2026-09-12。 +[^main-v2-missing]: `internal/workflowdef/manifests/main.v2.json:1-50`,清单只定义 intake、research、feasibility_reg、prelim_design、cdo_quote;读取于 2026-09-12。 +[^manifest-loader]: `internal/workflowdef/manifest_loader.go:9-32` 仅提供嵌入读取和文件名映射;仓库检索未发现 `V2ManifestFiles` 的运行时调用;读取于 2026-09-12。 +[^seed-no-upgrade]: `internal/workflowdef/store.go:364-372`,已有任意 latest published version 时直接返回;读取于 2026-09-12。 +[^catalog-flatten]: `internal/workflowdef/catalog.go:27-41,50-82`,数据库目录将版本压为首阶段首任务;读取于 2026-09-12。 +[^plan-disable-conflict]: `internal/projectinstance/validator.go:37-90,105-139`,required 或 blocking 任务关闭时校验失败;读取于 2026-09-12。 +[^advance-forces-approved]: `internal/projectinstance/stage_store.go:71-158`,推进事务把启用任务状态强制更新为 approved;读取于 2026-09-12。 +[^project-lifecycle-gap]: `internal/projectinstance/stage_store.go:128-158` 只完成实例,`internal/projectinstance/service.go:119-135` 又只允许 planning 项目保存下一计划;读取于 2026-09-12。 +[^dialogue-old-advance]: `internal/coordinator/engine.go:672-811`,对话推进调用 `bizdevSvc.ExecuteStage` 并直接改变旧成熟度上下文;读取于 2026-09-12。 +[^settings-all-definitions]: `internal/projectinstance/service.go:94-113`,项目设置枚举全部有 latest published version 的定义;读取于 2026-09-12。 +[^template-stage-map]: `web/src/engine/templateFactory.ts:37-39,87-89,158-160,228-230,286-288,331-333,392-394`,7 个商务模板当前归属为 V0.1 一项、V0.5 五项、V1.0 一项;读取于 2026-09-12。 +[^biz-stage-five]: `internal/bizdev/service.go:204-223`,旧商务阶段仅映射 1 + 3 + 1 个任务;读取于 2026-09-12。 +[^executor-missing]: `internal/workflow/registry.go:5-15`,商务 executor 缺少 feasibility_dev 和 user_requirements;读取于 2026-09-12。 +[^test-upstream]: `internal/workflowdef/manifests/test_manager.v2.json:1-23`,测试流程声明 product_manager 前置依赖;读取于 2026-09-12。 +[^test-hard-dependency]: `internal/bizdev/service.go:349-380,673-687`,测试任务硬查同项目 approved SRS、自动注入并记录单一 SRS 血缘;读取于 2026-09-12。 +[^context-input-foundation]: `internal/squad/service.go:35-55`、`internal/squad/workspace.go:262-408` 和 `internal/bizdev/service.go:250-294`,现有运行参数及工作区已支持项目、材料、前序文档、知识和部分项目事实输入;读取于 2026-09-12。 +[^instance-schema]: `deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql:13-52`,实例状态和 one planning/one live 唯一索引;读取于 2026-09-12。 +[^plan-structure]: `internal/projectinstance/types.go:21-48`,计划已包含文档 enabled 和三权;读取于 2026-09-12。 +[^duty-write-enabled-only]: `internal/projectinstance/store.go:244-280`,禁用文档不会写职责行;读取于 2026-09-12。 +[^readiness-current]: `internal/projectinstance/gate.go:5-53` 和 `internal/projectinstance/stage_service.go:15-63`,现有门禁忽略禁用任务并限制创建者;读取于 2026-09-12。 +[^approval-key-too-wide]: `internal/projectinstance/stage_store.go:176-191`,批准同步按 project_id + task_key 更新;读取于 2026-09-12。 +[^notify-ready]: `internal/server/workflow_approval_hook.go:17-44` 和 `internal/notification/service.go:38-107`,批准回调、推进请求、outbox 与创建者通知;读取于 2026-09-12。 +[^notify-reminder]: `internal/notification/reminder.go:35-91,94-171`,24 小时提醒和 confirmed 状态;读取于 2026-09-12。 +[^stage-banner]: `web/src/components/workflow/StageAdvanceBanner.tsx:29-95,111-151`,前端轮询 readiness/通知并提供确认按钮;读取于 2026-09-12。 +[^instance-runtime-metadata]: `deploy/postgres/goose/00023_2026-09-12-instance-integrity.sql:8-11` 已添加运行元数据列,而 `internal/projectinstance/store.go:254-259` 插入时未写这些列;读取于 2026-09-12。 +[^stage-access]: `internal/projectinstance/stage_access.go:15-71,90-104`,live 实例中排除禁用任务,但无 live/completed 时不限制;读取于 2026-09-12。 +[^legacy-switch-ui]: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23,38-76,173-236`,旧名称、旧直切换和冲突自动重试仍存在;读取于 2026-09-12。 +[^legacy-route]: `internal/server/server.go:157-169`,新项目实例 API 与旧 active-workflow/run API 同时暴露;读取于 2026-09-12。 +[^validator-v2]: `internal/workflowdef/validator_v2.go:9-47`,现有 v2 校验范围有限;读取于 2026-09-12。 +[^test-db-default]: `internal/projectinstance/pg_integration_test.go:19-49` 和 `internal/server/workflow_governance_pg_test.go:26-61`,未设置 TEST_DATABASE_URL 时连接本地开发库;读取于 2026-09-12。 +[^test-definition-no-cleanup]: `internal/workflowdef/publish_test.go:37-72`,发布测试创建带时间戳定义但未注册清理;读取于 2026-09-12。 + +开发数据库数字来源:2026-09-12 在本机容器内对 `workflow_definitions`、`workflow_versions`、`project_workflow_instances` 和 `projects` 执行只读聚合查询。该快照仅用于诊断当前开发环境,不代表生产环境。 diff --git a/.doc/remediation/INDEX.md b/.doc/remediation/INDEX.md new file mode 100644 index 00000000..8de77927 --- /dev/null +++ b/.doc/remediation/INDEX.md @@ -0,0 +1,15 @@ +# 整改方案索引 + +| 文档 | 说明 | +|------|------| +| [gap-matrix.md](./gap-matrix.md) | 发布缺口 SSOT | +| [2026-09-12-comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 综合缺陷与整改 | +| [2026-09-12-remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 任务拆分与验收 | +| [2026-09-12-quick-reference-guide.md](./2026-09-12-quick-reference-guide.md) | 症状→原因→方案速查 | +| [2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) | 生产就绪治理 | +| [2026-09-12-permissions-settings-three-workflows-implementation-plan.md](./2026-09-12-permissions-settings-three-workflows-implementation-plan.md) | 权限+三工作流 | +| [2026-09-12-phase1-iam-authz-implementation-plan.md](./2026-09-12-phase1-iam-authz-implementation-plan.md) | Phase1 IAM | +| [2026-09-12-phase2-workflow-designer-implementation-plan.md](./2026-09-12-phase2-workflow-designer-implementation-plan.md) | Phase2 设计器 | +| [2026-09-12-three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 三工作流严格治理 | + +审计入口:[../audit/INDEX.md](../audit/INDEX.md) diff --git a/.doc/remediation/README.md b/.doc/remediation/README.md new file mode 100644 index 00000000..cf5ba5cf --- /dev/null +++ b/.doc/remediation/README.md @@ -0,0 +1,8 @@ +# 整改方案 + +实施方案、分波次计划、发布缺口 SSOT。 + +| 文档 | 说明 | +|------|------| +| [gap-matrix.md](./gap-matrix.md) | 发布 blocker SSOT | +| [INDEX.md](./INDEX.md) | 方案索引 | diff --git a/.doc/remediation/gap-matrix.md b/.doc/remediation/gap-matrix.md new file mode 100644 index 00000000..14d67063 --- /dev/null +++ b/.doc/remediation/gap-matrix.md @@ -0,0 +1,71 @@ +# 整改缺口复核矩阵(SSOT) + +**更新**: 2026-09-13 +**分支**: dev +**production_ready**: no(CI 真实 PI E2E / 前端人工抽检未完成;main 本地冒烟已通过) +**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md) +**Agent 手册**: [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md) + +> Codex 2026-09-12 再审计项与本轮回环证据见下表「Codex 再审计」区段。 + +--- + +## Phase A/B/C 原审计项 + +| ID | 审计描述 | 状态 | 证据 | 计划动作 | +|---|---|---|---|---| +| BUG-01 | 完成后 lifecycle 未更新 | PASS | `stage_remediation_test.go`;`scripts/fix-completed-instance-lifecycle.sql`;dev 执行 UPDATE 47 | 已完成 | +| BUG-02 | 推进强制批文档 | PASS | `AdvanceStage` 无 doc UPDATE | 已完成 | +| BUG-03 | 无 skipped_disabled | PASS | memStore `skipped_disabled` | 已完成 | +| BUG-04 | 对话走旧 bizdev | PASS | `engine.go` live 门控 | 已完成 | +| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 | +| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 | +| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 | +| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` | +| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 | +| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 | +| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 | +| BUG-12 | 前端名称硬编码 | PASS | catalog API | 已完成 | +| MISSING-01 | 上下文快照 | PASS | `ctxmgr.CollectProjectDialogue` | 已完成 | +| MISSING-02 | 终止 | PASS | `GetTerminationPreview` | 已完成 | +| MISSING-04 | E2E | PASS | 三正式工作流 PG+PI E2E | 已完成 | + +--- + +## Codex 2026-09-12 再审计 + +| ID | 描述 | 状态 | 证据 | +|---|---|---|---| +| AUTH-TASK-RUN | `/tasks/run` 缺项目鉴权 | PASS | `handlers.go` RequireProjectAccess;`task_run_authz_pg_test.go` | +| AUTH-TASK-SSE | `/tasks/run/stream` 鉴权在 Flush 前 | PASS | `sse.go`;同上测试 | +| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval | +| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 | +| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 | +| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` | +| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 | +| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 | +| TEST-EMBEDDING-GATE | 默认打真实 embedding | PASS | `kb/integration_test.go` Short + `RUN_KB_INTEGRATION=1` | +| HEALTH-SCHEMA-CACHE | health schema 启动缓存 | PASS | `LiveSchemaVersion` + health 实时读 | +| GO-VET-ASSET | asset handler resp before err | PASS | `asset_handlers_test.go` err-first | +| ENV-TEST-STALE | test 旧镜像/schema 漂移 | PASS | rebuild app;health schema_version=25 | +| ENV-DEV-STALE | dev 二进制/schema 漂移 | PASS | docker app 重启;schema_version=25 | +| ENV-MAIN-MISSING | main 未部署验收 | PASS | docker 创建 `data/main`;compose 注入 ADMIN/KB 密码;health/ready schema 25 | +| DOC-SSOT | 文档叙事漂移 | PASS | 本矩阵 + superseded 标记 + ops | +| OPS-AGENTS | 多 Agent 协作规范 | PASS | `AGENTS.md` / `PROJECT.md` / `.doc/ops` | + +--- + +## 发布门禁(test → main) + +``` +☑ go vet ./... 全绿 +☑ go test -short ./... 全绿 +□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI) +□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token) +☑ lifecycle fix SQL 已在 dev 执行 +☑ test/dev health schema_version=25 +☑ main 环境部署冒烟(本地 8000 health/ready schema 25) +□ 前端:版本冲突刷新、终止 preview 人工抽检 +``` + +**结论**: P0 授权、冷启动序列、Go 门禁、三环境本地冒烟已闭环。**发布 blocker 剩余 CI 真实 PI E2E 与前端人工抽检**。 diff --git a/.doc/status/FEATURE-MATRIX.md b/.doc/status/FEATURE-MATRIX.md new file mode 100644 index 00000000..6222f84f --- /dev/null +++ b/.doc/status/FEATURE-MATRIX.md @@ -0,0 +1,35 @@ +# 模块与功能完成度(SSOT) + +**更新**: 2026-09-13 +**production_ready**: no +**发布缺口**: [../remediation/gap-matrix.md](../remediation/gap-matrix.md) +**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md) + +> 本表描述**能力地图**;上线 blocker 见 gap-matrix,二者互相链接、不合并。 + +**状态枚举**: `done` | `partial` | `planned` | `deferred` | `blocked` + +--- + +## 完成度矩阵 + +| 模块 | 能力 | 状态 | 证据 | 缺口/后续 | mutex | +|------|------|------|------|-----------|-------| +| 意图识别 L1 | 18 类 Intent + 三分支消解 | done | [system-design/intent-recognition](../system-design/intent-recognition/);[test-report 2026-09-07](../test-reports/2026-09-07-three-branch-intent-framework-test-report.md) | — | `intent` | +| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);P0 断链已修 | 语义摘要(D5 backlog);长任务治理 | `chat` | +| 智能体小队 | 角色-任务-工作区-黑板 | done | [system-design/agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6 backlog) | `squad` | +| 工作流治理 | 三正式工作流 + 阶段门禁 | done | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md) | Phase2 设计器 partial | `workflow` | +| IAM / 鉴权 | 项目级 API 鉴权 + RBAC | done | [audit/authorization](../audit/authorization-matrix-v2.md);[test phase1](../test-reports/2026-09-12-phase1-iam-authz-test-report.md) | 旧 API 410 标注(BUG-11 partial) | `authz` | +| 文档治理 | 法定文档生命周期 + 租约 | done | [test docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md) | — | `docgov` | +| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md) | 人工抽检待完成 | `web` | +| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md) | — | `pi-agent` | +| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` | +| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md) | CI `TEST_DATABASE_URL` + 真实 PI E2E 实录 | `ci` | + +--- + +## 更新规则 + +1. 模块状态变化时同步更新本表与 [gap-matrix](../remediation/gap-matrix.md)(若涉及 blocker) +2. 同一 `mutex` 同时仅一个 Agent `in_progress`(见 CURRENT 并行认领表) +3. 新能力行:复制模板 [../ops/templates/feature-matrix-row.md](../ops/templates/feature-matrix-row.md) diff --git a/.doc/status/README.md b/.doc/status/README.md new file mode 100644 index 00000000..db0d5364 --- /dev/null +++ b/.doc/status/README.md @@ -0,0 +1,5 @@ +# 模块完成度 + +**SSOT**:[FEATURE-MATRIX.md](./FEATURE-MATRIX.md) + +与 [remediation/gap-matrix.md](../remediation/gap-matrix.md)(发布 blocker)分离:本目录描述**能力地图**,gap-matrix 描述**上线缺口**。 diff --git a/.gitignore b/.gitignore index 011f0d1b..d249f82d 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ logs/ # Workspaces & Cache workspaces/ +.worktrees/ .cache/ tmp/ temp/ From 20f52d025b808be158d5c41850ad0e1d1eb9b144 Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 02:31:27 +0000 Subject: [PATCH 2/5] docs(agents): multi-agent rules, templates, and tool entrypoints Rewrite AGENTS.md with taxonomy, worktree, and integration slot rules; add FEATURE-MATRIX-driven CURRENT; tool stubs; session-close checklist. Co-authored-by: Cursor --- .cursor/rules/agent-collaboration-docs.mdc | 13 +- .cursor/rules/test-reports-standard.mdc | 4 +- .doc/ops/CURRENT.md | 34 ++- .doc/ops/README.md | 21 +- .../2026-09-13-codex-audit-p0-remediation.md | 47 ---- .../2026-09-13-container-env-configuration.md | 54 ++++ ...09-13-container-env-configuration-audit.md | 33 +++ .doc/ops/research/2026-09-13-doc-inventory.md | 38 +++ .../2026-09-13-codex-audit-p0-remediation.md | 44 ---- ...2026-09-13-fix-piagent-provider-minimax.md | 50 ---- .doc/ops/templates/audit-note.md | 33 +++ .doc/ops/templates/feature-matrix-row.md | 1 + .doc/ops/templates/handoff.md | 11 + .doc/ops/templates/remediation-plan.md | 32 +++ .doc/ops/templates/session-close-checklist.md | 27 ++ .doc/ops/templates/short-term-task.md | 3 + .doc/system-design/README.md | 12 +- AGENTS.md | 243 +++++++++++------- ANTIGRAVITY.md | 9 + CLAUDE.md | 2 +- CODEX.md | 9 + GEMINI.md | 9 + KIMI.md | 9 + PROJECT.md | 12 +- README.md | 4 +- scripts/agent-worktree.sh | 76 ++++++ 26 files changed, 555 insertions(+), 275 deletions(-) delete mode 100644 .doc/ops/checklists/2026-09-13-codex-audit-p0-remediation.md create mode 100644 .doc/ops/handoffs/2026-09-13-container-env-configuration.md create mode 100644 .doc/ops/research/2026-09-13-container-env-configuration-audit.md create mode 100644 .doc/ops/research/2026-09-13-doc-inventory.md delete mode 100644 .doc/ops/short-term/2026-09-13-codex-audit-p0-remediation.md delete mode 100644 .doc/ops/short-term/2026-09-13-fix-piagent-provider-minimax.md create mode 100644 .doc/ops/templates/audit-note.md create mode 100644 .doc/ops/templates/feature-matrix-row.md create mode 100644 .doc/ops/templates/remediation-plan.md create mode 100644 .doc/ops/templates/session-close-checklist.md create mode 100644 ANTIGRAVITY.md create mode 100644 CODEX.md create mode 100644 GEMINI.md create mode 100644 KIMI.md create mode 100755 scripts/agent-worktree.sh diff --git a/.cursor/rules/agent-collaboration-docs.mdc b/.cursor/rules/agent-collaboration-docs.mdc index 279d0adf..35758745 100644 --- a/.cursor/rules/agent-collaboration-docs.mdc +++ b/.cursor/rules/agent-collaboration-docs.mdc @@ -9,15 +9,16 @@ alwaysApply: true ## 开场必读 -1. `AGENTS.md` → `PROJECT.md` → `.doc/ops/CURRENT.md` → 相关 short-term / handoff +1. `AGENTS.md` → `PROJECT.md` → `.doc/README.md` → `.doc/ops/CURRENT.md` → `FEATURE-MATRIX` → short-term / handoff ## 红线 -- 任何任务/调研/审计/修复/运维:**开始前**建或更新 `.doc/ops/short-term/` 或 `long-term/`(复制 templates) -- **禁止**只改代码、真相只留在聊天 -- 里程碑更新 `CURRENT.md`;会话结束写 `handoffs/` -- 验收报告进 `.doc/test-reports/` 并回链 checklist -- 文档与代码同批或紧随 `docs(...)` 提交 +- 任务开始前:short-term/long-term + CURRENT 并行认领(mutex) +- 合 dev + 容器测:占用 CURRENT 集成槽位;他人 queue 等待 +- 多 Agent 并行:worktree(`.worktrees/`);禁止 worktree 内 env-service start +- 禁止只改代码;done 任务 → `archive/ops/` +- 验收报告 → `.doc/test-reports/`;运行产物 → `test-reports/assets/` +- 禁止在 `.doc/` 根或 `docs/` 随意新建文档 ## 状态 diff --git a/.cursor/rules/test-reports-standard.mdc b/.cursor/rules/test-reports-standard.mdc index 3d23706c..8eb00670 100644 --- a/.cursor/rules/test-reports-standard.mdc +++ b/.cursor/rules/test-reports-standard.mdc @@ -13,7 +13,7 @@ alwaysApply: true - **统一目录**:所有测试报告必须统一存放于 `.doc/test-reports/` 目录下。 - **命名规范**:遵循 `YYYY-MM-DD-<模块/功能/版本>-test-report.md` 命名格式。 - 例如:`.doc/test-reports/2026-09-07-three-branch-intent-framework-test-report.md` - - 例如:`.doc/test-reports/2026-09-07-bizdev-workflow-integration-test-report.md` +- **证据附件**:运行产物(json/jsonl、workspace 快照、截图)放 `.doc/test-reports/assets//`,**不得**与 `*-test-report.md` 混放在同一层级目录。 --- @@ -58,7 +58,7 @@ alwaysApply: true 1. **真实 Agent 交付铁律(红线)**: - **开发实现阶段**:可以快速使用 `stub` 验证状态机、协议分流、数据落盘与逻辑契约,加速反馈; - - **交付前验收与测试报告生成**:**必须切回真实环境与真实 Agent(`pi-agent` + 实际运行的 `MiniMax-M3` 容器)进行全链路端到端实测**; + - **交付前验收与测试报告生成**:**必须切回真实环境与真实 Agent(`pi-agent` + 实际运行的 `MiniMax-M2.7-highspeed` 容器)进行全链路端到端实测**; - **严禁**使用 stub 的测试输出作为最终交付报告的验收数据。 2. **严禁散落存放**:测试报告统一归档至 `.doc/test-reports/` 目录下,禁止散落在根目录或临时沙箱中。 3. **真实控制台取样**:测试报告中的输入、输出、耗时与判定必须取自实际环境运行的真实控制台输出与日志。 diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index 05326424..8f7c46d7 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -5,13 +5,27 @@ ## 焦点 -1. **已修复**:dev pi-agent provider 误为 `cc-switch-kimi-for-coding` → 已对齐 `.env` 的 `minimax` + `MiniMax-M2.7-highspeed`(见 short-term) -2. Codex 审计 P0 整改 **Wave 0–D 已全部完成**;main 本地冒烟已通过 - -## 剩余(非 P0) - 1. **CI**: `TEST_DATABASE_URL` + 真实 PI E2E 实录 -2. **BACKLOG**: session cookie / bundle 拆分 / 容量治理 +2. **前端**: 版本冲突刷新、终止 preview 人工抽检 +3. **BACKLOG**: session cookie / bundle 拆分 / 容量治理(见 [backlog](../backlog/chat-agent-p6-backlog.md)) + +## 并行认领 + +| owner | task | branch | worktree | mutex | status | +|-------|------|--------|----------|-------|--------| +| — | — | — | — | — | — | + +> 新任务开始前登记。同一 `mutex` 同时仅一个 `in_progress`。 + +## 集成槽位 + +| holder | phase | since | scope | queue | +|--------|-------|-------|-------|-------| +| idle | - | - | - | - | + +**phase**: `idle` | `merging` | `smoke` | `e2e` + +> 合入 `dev` + 共享容器验证必须串行。详见 [AGENTS.md](../../AGENTS.md) §6.3。 ## 环境快照 @@ -19,12 +33,14 @@ |------|------|--------|------| | dev | 8080 | 25 | healthy | | test | 8081 | 25 | healthy | -| main | 8000 | 25 | healthy(本地冒烟) | +| main | 8000 | 25 | healthy(app + runner + DB) | ## SSOT | 类型 | 路径 | |------|------| -| 发布缺口 | [gap-matrix](../2026-09-12-remediation-gap-matrix.md) | -| 测试报告 | [test-report](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md) | +| 文档总地图 | [../README.md](../README.md) | +| 模块完成度 | [FEATURE-MATRIX](../status/FEATURE-MATRIX.md) | +| 发布缺口 | [gap-matrix](../remediation/gap-matrix.md) | +| 测试报告 | [test-reports/](../test-reports/) | | Agent 手册 | [AGENTS.md](../../AGENTS.md) | diff --git a/.doc/ops/README.md b/.doc/ops/README.md index 7ee08f40..5dceaaca 100644 --- a/.doc/ops/README.md +++ b/.doc/ops/README.md @@ -1,24 +1,25 @@ # 活协作区(.doc/ops) -Agent 会话级协作文档,与 Git 跟踪的审计/设计文档分离。 +Agent 会话级协作文档。完整 taxonomy 见 [../README.md](../README.md)。 ## 用法 -1. 会话开始读 [CURRENT.md](./CURRENT.md) +1. 会话开始读 [CURRENT.md](./CURRENT.md)(含并行认领 + 集成槽位) 2. 新任务复制 [templates/](./templates/) 到对应目录 -3. 完成或切换 Agent 时写 [handoffs/](./handoffs/) +3. 结束按 [session-close-checklist.md](./templates/session-close-checklist.md);换人写 [handoffs/](./handoffs/) ## 状态 -- **current**:进行中条目 + CURRENT.md -- **historical**:已完成条目保留,标 `done` 或移入归档 +- **current**:进行中 + CURRENT.md +- **historical**:标 `done` 并移入 [../archive/ops/](../archive/ops/) -## 与 SSOT 关系 +## SSOT 关系 -| 类型 | 位置 | +| 类型 | 路径 | |------|------| -| 协作焦点 | 本目录 CURRENT | -| 发布/审计缺口 | [gap-matrix](../2026-09-12-remediation-gap-matrix.md) | +| 协作焦点 | CURRENT | +| 模块完成度 | [FEATURE-MATRIX](../status/FEATURE-MATRIX.md) | +| 发布缺口 | [gap-matrix](../remediation/gap-matrix.md) | | 验收报告 | [test-reports](../test-reports/) | -通用纪律见仓库根 [AGENTS.md](../../AGENTS.md)。 +通用纪律见 [AGENTS.md](../../AGENTS.md)。 diff --git a/.doc/ops/checklists/2026-09-13-codex-audit-p0-remediation.md b/.doc/ops/checklists/2026-09-13-codex-audit-p0-remediation.md deleted file mode 100644 index 2def7995..00000000 --- a/.doc/ops/checklists/2026-09-13-codex-audit-p0-remediation.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -title: "Codex 审计 P0 整改 Checklist" -status: done -created: 2026-09-13 -updated: 2026-09-13 -related_task: short-term/2026-09-13-codex-audit-p0-remediation.md ---- - -# Codex 审计 P0 整改 Checklist - -## Wave 0 — Agent 文档 - -- [x] AGENTS.md / PROJECT.md / CLAUDE.md — commit 31fe607 -- [x] .cursor/rules — agent-collaboration + git-secrets -- [x] .doc/ops templates + CURRENT - -## Wave A — P0 - -- [x] AUTH tasks/run + stream — commit d82021e;`task_run_authz_pg_test.go` -- [x] DB 00025 — commit b13ced6;dev/test setval -- [x] DATA lifecycle — dev UPDATE 47 → 0 -- [x] DATA test wf — UPDATE 5 retired - -## Wave B — Go 门禁 - -- [x] go vet ./... PASS — commit 91985a2 -- [x] go test -short ./... PASS -- [x] AdvisorBrief / V0.5 / chat / kb / health / asset - -## Wave C — 环境 - -- [x] test rebuild schema 25 — health 8081 -- [x] dev docker app schema 25 — health 8080 -- [x] main 冒烟 — health/ready 8000 schema 25;restart 恢复 -- [x] HTTP 超时 + env status 只读 — commit 505c419 -- [x] .env.dev/.env.test chmod 600 - -## Wave D — 文档 - -- [x] gap-matrix Codex 项 -- [x] AUDIT-INDEX + superseded 横幅 -- [x] quick-ref 断链修复 -- [x] [test-report](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md) - -## 完成定义 - -- [x] P0/门禁项已闭环(main 除外,已记 OPEN) diff --git a/.doc/ops/handoffs/2026-09-13-container-env-configuration.md b/.doc/ops/handoffs/2026-09-13-container-env-configuration.md new file mode 100644 index 00000000..c071c378 --- /dev/null +++ b/.doc/ops/handoffs/2026-09-13-container-env-configuration.md @@ -0,0 +1,54 @@ +--- +title: "容器与 env 配置审计补密钥交接" +created: 2026-09-13 +from: codex +to: next-agent +status: done +--- + +# 交接:容器与 env 配置审计补密钥 + +## 目标(下一位 Agent 应完成什么) + +记录已完成的数据库密码轮换、容器重建与最终健康验证。 + +## 已完成 + +- 根 `.env` 与环境差异文件已分层,容器所需配置已透传。 +- 失效字段、重复项目名与 23GB 构建上下文问题已清理。 +- dev/test app + pi-agent 均已重建并健康;镜像实构建和 Go short 全量测试通过。 +- 用户已补齐两个密码;现有 PostgreSQL 用户已同步轮换。 +- shared/dev/test/main 均 healthy,三个 app ready 通过;独立 TCP/SCRAM 登录与 `SELECT 1` 通过。 + +## 未完成 + +- 无。 + +## 关键文件 + +| 路径 | 说明 | +|------|------| +| `.env` | 公共配置与共享 KB 密码(gitignored) | +| `configs/.env.main` | main 环境差异与 main DB 密码(gitignored) | +| `scripts/env-service.sh` | 根配置 + 环境差异分层加载 | +| `docker-compose.*.yml` | 必填校验和 app/runner 注入 | + +## 如何验证 + +```bash +docker compose -f docker-compose.shared.yml --env-file .env config -q +docker compose -f docker-compose.main.yml --env-file .env --env-file configs/.env.main config -q +go test -short ./... +./scripts/env-service.sh all status +curl -fsS http://127.0.0.1:8000/api/v1/ready +``` + +## 风险 / Blocker + +- 共享 KB 密码低于建议的 16 字符;建议后续维护窗口再次轮换。 + +## 相关链接 + +- CURRENT: [CURRENT.md](../CURRENT.md) +- Task: [audit-container-env-configuration](../short-term/2026-09-13-audit-container-env-configuration.md) +- Test report: [container-env-configuration-test-report](../../test-reports/2026-09-13-container-env-configuration-test-report.md) diff --git a/.doc/ops/research/2026-09-13-container-env-configuration-audit.md b/.doc/ops/research/2026-09-13-container-env-configuration-audit.md new file mode 100644 index 00000000..3338c708 --- /dev/null +++ b/.doc/ops/research/2026-09-13-container-env-configuration-audit.md @@ -0,0 +1,33 @@ +--- +title: "容器构建与环境变量配置链审计" +created: 2026-09-13 +status: done +confidence: high +--- + +# 调研:容器构建与环境变量配置链 + +## 结论 + +原配置链不完整:`env-service.sh` 未读取根 `.env`,app 容器未透传多项已配置能力,test/main 仍选择 `stub`,且 `COMPOSE_PROJECT_NAME` 会导致共享环境串到 dev。上述配置链均已修复。另发现的共享 KB 与 main 业务库示例弱密码也已由用户补值、在现有 PostgreSQL volume 内同步轮换并完成 TCP/SCRAM 复验。 + +## 证据 + +| 项 | 路径/命令 | 结果 | +|----|-----------|------| +| 根配置分层 | `scripts/env-service.sh` | `.env` 公共配置先加载,`configs/.env.` 后加载并只覆盖差异 | +| app 透传 | `docker-compose.{dev,test,main}.yml` | Agent 超时/并发、Embedding/Reranker、认证、CORS、缓存、意图开关均注入 | +| 真实 Agent | `configs/.env.{test,main}(.example)` | `AGENT_BACKEND=pi-agent`,main runner 端口补为 18867 | +| 串环境 | `./scripts/env-service.sh all status` | 删除 `COMPOSE_PROJECT_NAME` 后 shared 正确显示 `agent-infra` / `shuimu-kb-shared` | +| 构建上下文 | Docker build 输出、`.dockerignore` | `.regulations` 23GB 已排除;上下文从中止时 17.1GB 降至 12.7MB | +| 失效字段 | 全仓 `rg` | 移除 `EMBEDDING_PROVIDER`、`RERANKER_PROVIDER`、`ADMIN_TOKEN`、`ALLOW_INSECURE_ADMIN`、`AUX_FILE_DSN`、`KB_DATA_DIR` 与单 Key Tavily 透传 | +| 配置加载 | `internal/config/config.go` | 环境变量现在能覆盖 timeout、Cursor/Pi bridge 与检索模型;生产占位密码纳入拒绝列表 | +| secret 权限 | `stat -c '%a %n' ...` | 四个实际 env 文件均为 600 | + +## 开放问题 + +- 共享 KB 密码低于建议的 16 字符;当前不是已知示例值且已生效,建议后续维护窗口换成长随机值。 + +## 建议动作 + +- 后续轮换仍应保持两个数据库密码不同,并优先使用至少 16 字符的高强度随机值。 diff --git a/.doc/ops/research/2026-09-13-doc-inventory.md b/.doc/ops/research/2026-09-13-doc-inventory.md new file mode 100644 index 00000000..4f32f582 --- /dev/null +++ b/.doc/ops/research/2026-09-13-doc-inventory.md @@ -0,0 +1,38 @@ +--- +title: "全仓文档盘点" +status: done +created: 2026-09-13 +updated: 2026-09-13 +--- + +# 全仓文档盘点(2026-09-13) + +## 摘要 + +| 分类 | 路径 | 动作 | +|------|------|------| +| 审计/分析 | `.doc/audit/` | 自根目录迁入 | +| 整改方案 | `.doc/remediation/` | 自根目录迁入;gap-matrix SSOT | +| 活协作 | `.doc/ops/` | 保留;done → `archive/ops/` | +| 完成度 | `.doc/status/FEATURE-MATRIX.md` | 新建 | +| 历史设计 | `.doc/archive/design/superpowers/` | 自 `docs/superpowers/` 迁入 | +| 参考长文 | `.doc/archive/reference/` | workflow 规则归档 | +| 测试报告 | `.doc/test-reports/` | 主报告保留;workspace → `assets/` | +| 架构 | `.doc/system-design/` | 保留;修索引 | +| 遗留 stub | `.doc/` 根 15 stub | 跳转新路径 | +| 遗留 stub | `docs/superpowers/`、`docs/workflow/` | 跳转 archive / PROJECT | +| 产品模板 | `templates/docs/` | **不迁移** | +| Agent prompt | `configs/agents/` | **不迁移** | + +## 合法文档区(整理后) + +见 [AGENTS.md](../../AGENTS.md) §4 与 [.doc/README.md](../../README.md)。 + +## 禁止随意新建 + +- `.doc/` 根目录大包(仅 stub 例外) +- `docs/` 新子目录(仅 stub README) + +## 证据 + +整理执行 commit 见本任务 short-term 证据段。 diff --git a/.doc/ops/short-term/2026-09-13-codex-audit-p0-remediation.md b/.doc/ops/short-term/2026-09-13-codex-audit-p0-remediation.md deleted file mode 100644 index a2bb4d8b..00000000 --- a/.doc/ops/short-term/2026-09-13-codex-audit-p0-remediation.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -title: "Codex 审计 P0 整改" -status: done -created: 2026-09-13 -updated: 2026-09-13 -owner: agent ---- - -# Codex 审计 P0 整改 - -## 目标 - -闭环 Codex 2026-09-12 再审计 P0/门禁/环境项,并完成文档 SSOT 对齐。 - -## 范围 - -- Wave A: 任务鉴权、00025 序列、lifecycle 脏数据 -- Wave B: Go vet + short 全绿 -- Wave C: test 重建、main 冒烟 -- Wave D: gap-matrix、superseded、test-report - -## 非目标 - -- session cookie 重构 -- bundle 拆分 / 23GB 容量治理 - -## 步骤 - -1. [x] Wave 0: AGENTS.md / PROJECT.md / CLAUDE.md / ops / rules -2. [x] Wave A1: handleRunTask + SSE 鉴权 + 负例测试 -3. [x] Wave A2: goose 00025 -4. [x] Wave A3: lifecycle SQL + test 工作流退休 -5. [x] Wave B: AdvisorBrief / V0.5 / chat memory / kb gate / health -6. [x] Wave C: 环境一致性(main OPEN) -7. [x] Wave D: 文档对齐 - -## 验收标准 - -见 [checklist](../checklists/2026-09-13-codex-audit-p0-remediation.md) - -## 相关链接 - -- 调研: [research/2026-09-12-codex-reaudit-summary.md](../research/2026-09-12-codex-reaudit-summary.md) -- Gap matrix: [../../2026-09-12-remediation-gap-matrix.md](../../2026-09-12-remediation-gap-matrix.md) diff --git a/.doc/ops/short-term/2026-09-13-fix-piagent-provider-minimax.md b/.doc/ops/short-term/2026-09-13-fix-piagent-provider-minimax.md deleted file mode 100644 index fd492f8b..00000000 --- a/.doc/ops/short-term/2026-09-13-fix-piagent-provider-minimax.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: "修复 pi-agent Unknown provider cc-switch-kimi-for-coding" -status: done -created: 2026-09-13 -updated: 2026-09-13 -owner: agent ---- - -# 修复 pi-agent Unknown provider cc-switch-kimi-for-coding - -## 目标 - -任务 `run_1789263149536199173` / workspace `intake_1789263149571817685` 因错误 provider 中断;恢复为与根 `.env` 一致的 `minimax` + `MiniMax-M2.7-highspeed`。 - -## 范围 - -- 修正 `internal/config/config.go` 错误默认值 -- 同步 `configs/.env.dev` 与 compose 注入(不编造新密钥/新 endpoint) -- 对齐根 `.env` 中 `PI_AGENT_MODEL` 与 `MINIMAX_MODEL_ID` -- 重启 / 重建 dev 的 app / pi-agent 使配置生效 - -## 非目标 - -- 不改动 test/main 环境密钥 -- 不擅自更换 API endpoint / API key -- 不在本任务内重跑完整业务长任务(修复后由用户 continue/restart) - -## 步骤 - -1. [x] 根因定位:Go 默认 `cc-switch-kimi-for-coding`;app 容器无 `PI_AGENT_*` 覆盖 -2. [x] 修正代码默认值与 `.env` / `.env.dev` / compose -3. [x] force-recreate + rebuild;health 已显示 `MiniMax-M2.7-highspeed` -4. [x] 提交 `8f3aa0f` - -## 验收标准 - -- [x] `shuimu-pi-agent-dev` health 显示 `MiniMax-M2.7-highspeed` -- [x] app 进程生效 `PI_AGENT_PROVIDER=minimax`、`PI_AGENT_MODEL=MiniMax-M2.7-highspeed` -- [x] 配置链不再默认 `cc-switch-kimi-for-coding`(业务 continue/restart 由用户触发验证) - -## 相关链接 - -- 失败 workspace: `data/dev/workspaces/bizdev/intake_1789263149571817685` -- 根配置: `.env`(`MINIMAX_MODEL_ID=MiniMax-M2.7-highspeed`) - -## 证据 / 备注 - -- upstream: `step step_01_organize failed: Error: Unknown provider "cc-switch-kimi-for-coding"` -- blame: `abd0893e` 将默认从 anthropic 误改为 kimi -- 验证:`curl :18865/health` → `model_id=MiniMax-M2.7-highspeed`;app env 含 `PI_AGENT_PROVIDER=minimax` diff --git a/.doc/ops/templates/audit-note.md b/.doc/ops/templates/audit-note.md new file mode 100644 index 00000000..ef2adeef --- /dev/null +++ b/.doc/ops/templates/audit-note.md @@ -0,0 +1,33 @@ +--- +title: "<审计/分析标题>" +status: planned +created: YYYY-MM-DD +updated: YYYY-MM-DD +severity: medium +--- + +# <审计/分析标题> + +## 现象 + +(可观测症状) + +## 根因分析 + +(证据路径、代码引用) + +## 严重度 + +`critical` | `high` | `medium` | `low` + +## 关联整改 + +- Remediation: + +## 证据 + +(命令输出、日志、文件路径) + +## 开放问题 + +- diff --git a/.doc/ops/templates/feature-matrix-row.md b/.doc/ops/templates/feature-matrix-row.md new file mode 100644 index 00000000..886dc951 --- /dev/null +++ b/.doc/ops/templates/feature-matrix-row.md @@ -0,0 +1 @@ +| <模块名> | <能力描述> | planned | (设计/代码/test-report 链接) | (缺口) | `` | diff --git a/.doc/ops/templates/handoff.md b/.doc/ops/templates/handoff.md index ca475420..48d0bad8 100644 --- a/.doc/ops/templates/handoff.md +++ b/.doc/ops/templates/handoff.md @@ -18,6 +18,17 @@ status: open - +## 认领 / 槽位状态 + +| 项 | 值 | +|----|-----| +| mutex 已释放 | yes / no | +| 集成槽位 holder | idle / 需接管 | +| branch | | +| worktree | | + +> 若 mutex 未释放,下一位须先在 CURRENT 认领或写 blocker。 + ## 关键文件 | 路径 | 说明 | diff --git a/.doc/ops/templates/remediation-plan.md b/.doc/ops/templates/remediation-plan.md new file mode 100644 index 00000000..845b547b --- /dev/null +++ b/.doc/ops/templates/remediation-plan.md @@ -0,0 +1,32 @@ +--- +title: "<整改方案标题>" +status: planned +created: YYYY-MM-DD +updated: YYYY-MM-DD +--- + +# <整改方案标题> + +## 背景 + +(链到 audit/ 分析文档) + +## 目标 + +(可验证的整改结果) + +## 分波次计划 + +| 波次 | 内容 | 验收 | +|------|------|------| +| Wave 0 | | | + +## 验收标准 + +- [ ] + +## 相关链接 + +- Audit: +- Short-term: +- gap-matrix 行: diff --git a/.doc/ops/templates/session-close-checklist.md b/.doc/ops/templates/session-close-checklist.md new file mode 100644 index 00000000..7fe12942 --- /dev/null +++ b/.doc/ops/templates/session-close-checklist.md @@ -0,0 +1,27 @@ +# 会话结束清单 + +任务完成或切换 Agent 前逐项勾选: + +## 认领与集成 + +- [ ] CURRENT「并行认领」行 status 已更新(done 或移除) +- [ ] 若曾占集成槽位:smoke 已完成,holder=idle,queue 已通知 +- [ ] mutex 无遗留 in_progress(除明确 handoff 交接项) + +## 代码与分支 + +- [ ] 非 trivial 改动已 merge `--no-ff` 到 dev(或 handoff 说明未 merge 原因) +- [ ] 无未 push 的 dev 关键提交(若用户要求同步远端) + +## 文档 + +- [ ] [FEATURE-MATRIX.md](../../status/FEATURE-MATRIX.md) 已更新(若模块状态变) +- [ ] [gap-matrix.md](../../remediation/gap-matrix.md) 已更新(若 blocker 变) +- [ ] 任务 frontmatter status=done +- [ ] done 任务已 `git mv` 到 [archive/ops/](../../archive/ops/) +- [ ] [CURRENT.md](../CURRENT.md) 焦点 1–3 条已刷新 +- [ ] 若换人:已写 [handoffs/](../handoffs/) + +## 提交 + +- [ ] 文档与代码同批或紧随 `docs(...)` 提交 diff --git a/.doc/ops/templates/short-term-task.md b/.doc/ops/templates/short-term-task.md index b24ee85a..ac16f3ce 100644 --- a/.doc/ops/templates/short-term-task.md +++ b/.doc/ops/templates/short-term-task.md @@ -4,6 +4,9 @@ status: planned created: YYYY-MM-DD updated: YYYY-MM-DD owner: agent +branch: feature/ +worktree: "-" +mutex: --- # <任务标题> diff --git a/.doc/system-design/README.md b/.doc/system-design/README.md index 370f0af0..da71ad6c 100644 --- a/.doc/system-design/README.md +++ b/.doc/system-design/README.md @@ -11,7 +11,7 @@ | 项 | 链接 | |-----|------| -| 主报告 | [intention-recognition/01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md](intention-recognition/01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md) | +| 主报告 | [intent-recognition/01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md](intent-recognition/01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md) | | 中间分析 | [.tmp/intent-recognition/](../.tmp/intent-recognition/) | | 一句话总结 | 纯规则 + 四级漏斗 + 三分支消解的 L1 协作对话层 | @@ -121,8 +121,13 @@ │ └── 01-意图识别框架-设计-架构-实现-难点-解决方案-亮点与优势.md ├── agent-squad/ │ └── 02-智能体小队编排-设计-思路-架构-实现-难点-解决方案-亮点与优势.md -└── multi-turn-dialogue/ - └── 03-多轮对话优化-设计-架构-实现-难点-解决方案-亮点与优势.md +├── multi-turn-dialogue/ +│ └── 03-多轮对话优化-设计-架构-实现-难点-解决方案-亮点与优势.md +└── project-workflow/ + ├── 03-项目多工作流与智能产品经理-测试经理工作流-设计方案.md + ├── 04-项目多工作流与智能产品经理-测试经理工作流-实施计划.md + ├── 05-Phase0-基线确认与契约冻结.md + └── 06-Phase7-全链路验收与发布基线.md .tmp/ ← 中间分析文件 ├── intent-recognition/ @@ -147,3 +152,4 @@ - 架构总览:[.doc/system-design/architecture-design.md](../architecture-design.md)(已有的项目骨架设计文档) - 测试报告:[.doc/test-reports/](../test-reports/)(多轮多角色端到端测试报告) +- 历史功能设计:[.doc/archive/design/superpowers/](../archive/design/superpowers/) diff --git a/AGENTS.md b/AGENTS.md index 74b14f8a..8bfdada6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ ## 1. 目的与适用范围 -- 适用于在本仓库工作的所有编码 Agent(Cursor、Claude Code、Codex 等)。 +- 适用于在本仓库工作的所有编码 Agent(Cursor、Claude Code、Codex、Kimi、Antigravity 等)。 - **聊天记录易失**;Git 与活文档区才是可协作、可审计的真相来源。 - 任何任务、调研、审计、修复、运维操作均须同步落盘,禁止「只改代码 / 只留在对话」。 @@ -17,11 +17,13 @@ 每次会话开始,按顺序阅读: -1. **本文件** `AGENTS.md`(通用工作方式) +1. **本文件** `AGENTS.md` 2. **[PROJECT.md](./PROJECT.md)**(本仓库地图与约定) -3. **`.doc/ops/CURRENT.md`**(当前焦点、阻塞、下一步) -4. 相关 **short-term 任务** / **handoff**(若存在) -5. 发布/审计类任务:再读 PROJECT 指向的 gap-matrix 等 SSOT +3. **[`.doc/README.md`](./.doc/README.md)**(文档 taxonomy) +4. **[`.doc/ops/CURRENT.md`](./.doc/ops/CURRENT.md)**(焦点、并行认领、集成槽位) +5. **[`.doc/status/FEATURE-MATRIX.md`](./.doc/status/FEATURE-MATRIX.md)**(模块完成度) +6. 相关 **short-term** / **handoff** / **audit** / **remediation** +7. 发布/审计类任务:[`remediation/gap-matrix.md`](./.doc/remediation/gap-matrix.md) **未读完不得开始改代码**(紧急热修除外,事后必须在 24h 内补文档)。 @@ -32,167 +34,212 @@ | 时机 | 必须动作 | |------|----------| | 任务开始 | 在 `short-term/` 或 `long-term/` 新建或更新条目(复制 templates) | -| 里程碑 | 更新任务文 `status` 与 `CURRENT.md` | -| 调研/审计 | 写入 `research/` 或任务文「证据」段 | -| 验收 | 写 test-report(路径见 PROJECT),回链到 checklist | -| 会话结束/切换 Agent | 写或更新 `handoffs/` | +| 认领 | 在 CURRENT「并行认领」表登记 owner / branch / mutex | +| 合 dev + 容器测 | 占用 CURRENT「集成槽位」;他人排队 | +| 里程碑 | 更新任务文 `status`、FEATURE-MATRIX、CURRENT | +| 调研/审计 | 写入 `audit/` 或 `ops/research/` | +| 整改方案 | 写入 `remediation/` | +| 验收 | 写 test-report(路径见 PROJECT),回链 checklist | +| 会话结束/切换 Agent | 按 [session-close-checklist](./.doc/ops/templates/session-close-checklist.md) | | 提交 | 文档变更与代码同批或紧随 `docs(...)` 提交 | **状态字段**:`planned | in_progress | blocked | done | cancelled` -**current vs historical**:完成项标 `done` 或移入归档;不删除证据。 +**current vs historical**:完成项标 `done` 并移入 `archive/`;不删除证据。 --- -## 4. 活文档区约定 +## 4. 文档 taxonomy -默认路径:`.doc/ops/`(可由 PROJECT 覆盖) +默认路径:`.doc/`(详见 [`.doc/README.md`](./.doc/README.md)) ```text -.doc/ops/ - README.md # 本区用法 - CURRENT.md # 一页纸:当前焦点(会话必读) - short-term/ # 本迭代可关闭的任务 - long-term/ # 跨迭代 backlog - checklists/ # 可勾选验收清单 - handoffs/ # 会话交接 - research/ # 调研笔记实例 - templates/ # 新建条目时复制 +.doc/ + README.md # 总地图 + status/ # FEATURE-MATRIX(模块完成度 SSOT) + audit/ # 问题发现与分析 + remediation/ # 整改方案;gap-matrix(发布 blocker) + archive/ # 历史(只增不删) + ops/ # 活协作:CURRENT、short-term、handoffs… + system-design/ # 模块架构深读 + adr/ | backlog/ | test-reports/ | test-fixtures/ ``` +**红线**:禁止在 `.doc/` 根或 `docs/` 随意新建项目文档;新文档必须落入 taxonomy。 + **命名**:`YYYY-MM-DD-.md` --- ## 5. 文档类型与何时使用 -### 短期任务(short-term) - -- **何时**:本迭代可关闭的具体工作 -- **必含**:目标、范围、非目标、步骤、验收标准、相关链接 -- **模板**:`.doc/ops/templates/short-term-task.md` - -### 长期任务(long-term) - -- **何时**:跨迭代 backlog、架构债、未排期改进 -- **必含**:动机、成功标准、依赖、暂不启动原因 -- **模板**:`.doc/ops/templates/long-term-task.md` - -### Checklist(checklists) - -- **何时**:可勾选验收;与短任务 1:1 或 1:N -- **必含**:每项 `[ ]` / `[x]` + 证据链接(commit、报告、命令输出) -- **模板**:`.doc/ops/templates/checklist.md` - -### 调研笔记(research) - -- **何时**:只读调查、审计复核、根因分析 -- **必含**:结论、证据路径、开放问题、置信度 -- **模板**:`.doc/ops/templates/research-note.md` - -### 交接(handoffs) - -- **何时**:会话结束、切换 Agent、长时间阻塞 -- **必含**:目标、已完成、未完成、关键文件、如何验证、风险 -- **模板**:`.doc/ops/templates/handoff.md` - -### 报告(test-reports) - -- 路径由 **PROJECT.md** 指定(本仓为 `.doc/test-reports/`) -- **原则**:真实控制台/日志取样;禁止 stub 冒充最终验收 -- 在任务文与 `CURRENT.md` 中用相对链接引用 +| 类型 | 路径 | 模板 | +|------|------|------| +| 问题/分析 | `audit/` | [audit-note.md](./.doc/ops/templates/audit-note.md) | +| 整改方案 | `remediation/` | [remediation-plan.md](./.doc/ops/templates/remediation-plan.md) | +| 短期任务 | `ops/short-term/` | [short-term-task.md](./.doc/ops/templates/short-term-task.md) | +| 长期 backlog | `ops/long-term/` | [long-term-task.md](./.doc/ops/templates/long-term-task.md) | +| Checklist | `ops/checklists/` | [checklist.md](./.doc/ops/templates/checklist.md) | +| 交接 | `ops/handoffs/` | [handoff.md](./.doc/ops/templates/handoff.md) | +| 调研 | `ops/research/` | [research-note.md](./.doc/ops/templates/research-note.md) | +| 模块完成度 | `status/FEATURE-MATRIX.md` | [feature-matrix-row.md](./.doc/ops/templates/feature-matrix-row.md) | +| 验收报告 | `.doc/test-reports/` | 见 test-reports-standard | +| 历史 | `archive/**` | 关闭后迁入 | --- ## 6. 多 Agent 协作 -- **单一焦点**:`CURRENT.md` 只列 1–3 个当前焦点 -- **并行任务**:在 CURRENT 列出 owner/agent 标识与互斥资源(分支、文件、环境) -- **不覆盖**:不覆盖他人未合并工作区;发现冲突先写 handoff/blocker +### 6.1 并行认领(编码阶段) + +任务开始前在 CURRENT「并行认领」表登记: + +| 字段 | 说明 | +|------|------| +| owner | 工具 + 标识 | +| task | short-term 文件名 | +| branch | `feature/*` 或 `fix/*` | +| worktree | 路径或 `-` | +| mutex | 模块名(见 FEATURE-MATRIX) | +| status | `in_progress` / `blocked` / `done` | + +**同一 mutex 同时仅一个 `in_progress`**。冲突 → 写 handoff blocker,禁止覆盖他人未合并改动。 + +### 6.2 分支与 Worktree + +- 非 trivial 改动必须独立分支,禁止多人直推同一 dev 工作区抢改。 +- **多 Agent 并行时强制 worktree**:`.worktrees//`(已 gitignore) +- 脚本:`./scripts/agent-worktree.sh create|list|remove` + +| Worktree 允许 | Worktree 禁止 | +|---------------|---------------| +| 编码、`go test -short ./...` | `env-service.sh * start/stop/restart` | +| 连主仓已起服务 `:8080` | 各 worktree 各起 docker | + +### 6.3 集成槽位(合入 dev + 容器验证) + +> **编码与 worktree 单测可并行;合入 dev + 共享容器验证必须串行。** + +Agent A 占槽 merge + 冒烟期间,Agent B **不得** merge dev 或动共享 docker;B 可继续 worktree 编码,并写入 queue 等待。 + +CURRENT「集成槽位」:`holder` | `phase`(idle/merging/smoke/e2e)| `since` | `scope` | `queue` + +**释放**:冒烟 PASS(或 FAIL+handoff)+ 文档同步 + holder=idle。长 E2E 优先 smoke 释放,E2E 结果后补报告。 + +**默认冒烟(holder 在主仓执行)**: + +```bash +go vet ./... +go test -short ./... +./scripts/env-service.sh dev restart +curl -sf http://127.0.0.1:8080/health +``` + +### 6.4 共享文档 + +`CURRENT.md` / `FEATURE-MATRIX.md` 由认领方或合并者更新;冲突时保留双方认领行再收敛。 + +### 6.5 协作纪律 + +- **单一焦点**:CURRENT 只列 1–3 个焦点 +- **不覆盖**:发现冲突先 handoff/blocker - **交接优先**:口头转述不可代替 handoff 文件 --- -## 7. Git 与提交 +## 7. 文档生命周期 + +```text +audit(问题)→ remediation(方案)→ ops/short-term(任务) + → test-reports(验收)→ archive/(关闭证据) +``` + +会话结束:[session-close-checklist.md](./.doc/ops/templates/session-close-checklist.md) + +--- + +## 8. Git 与提交 - 遵循 **Conventional Commits**:`feat` / `fix` / `refactor` / `test` / `docs` / `chore` / `ci` -- **原子提交**:一个逻辑变更一批;便于 review 与回滚 -- **用户未要求**:不擅自 push、不 force push 保护分支 -- **用户已要求 push/同步远端**:必须自主完成,不得把「请你去点推送」推回用户 +- **原子提交**:一个逻辑变更一批 +- merge 回 dev 用 `--no-ff` +- **用户未要求**:不擅自 push +- **用户已要求 push/同步远端**:必须自主完成 - **禁止**:在 `git config` 写入 token;硬重置/强推/删库仅在用户明确授权时 --- -## 8. Secrets 与远端推送(自主,禁止索要) +## 9. Secrets 与远端推送(自主,禁止索要) ### 查找顺序 -1. `${HOME}/.secrets/` 下与远端相关的文件(如 `gitea`、`github`) -2. 本仓 **PROJECT.md** 与 **push 脚本**(如 `scripts/git-push-dev.sh`)中的字段说明 - -### 常见字段(格式因宿主而异) - -```text -- ACCESS_TOKEN= -- URL_PREFIX= -``` - -### 执行方式 - -- 优先调用本仓封装脚本(若存在) -- 或自行读取 secrets 文件构造 push URL(**不写入 git config**) +1. `${HOME}/.secrets/`(如 `gitea`) +2. **PROJECT.md** 与 **push 脚本**(`scripts/git-push-dev.sh`) ### 禁止 -- 向用户索要 token 或要求粘贴凭证 -- 在聊天、文档、commit message 中展示 secret +- 向用户索要 token +- 在聊天/文档/commit 中展示 secret - 把 token 写入仓库或 `.env` 并提交 ### 缺失时 -- 在 ops 任务/handoff 记录 **blocker**:文件路径 + 缺字段名 -- 提示用户在本机补齐该文件后重试 -- **仍不索要 secret 内容** +在 ops/handoff 记 blocker(路径 + 缺字段);**仍不索要 secret 内容**。 --- -## 9. 安全与合规红线 +## 10. 安全与合规红线 - 不提交 `.env`、密钥、凭证、生产数据倾倒 -- 不做未授权访问或攻击性利用(本地修复与加固除外) -- 破坏性命令(`git reset --hard`、`push --force`、DROP DATABASE)仅在用户明确授权时 +- 破坏性命令仅在用户明确授权时 - XSS/注入等修复优先于功能扩展 --- -## 10. 计划 / 实现 / 验证 +## 11. 计划 / 实现 / 验证 -1. **大改动**:先对齐计划或 short-term 范围;范围外记 long-term -2. **实现**:按 PROJECT 测试命令验证;失败信息写入任务/报告 -3. **完成定义**:写进 checklist;勾选须有证据链接(非口头「已完成」) +1. **大改动**:先 short-term 范围;范围外记 long-term +2. **实现**:按 PROJECT 测试命令验证 +3. **完成定义**:checklist 勾选须有证据链接 --- -## 11. 沟通 +## 12. 沟通 -- 对用户:**简洁、中文**(若 PROJECT 未另规定) -- 不复述长篇规则;指向文件路径 +- 对用户:**简洁、中文** +- 指向文件路径,不复述长篇规则 - 需要决策时 **一次只问 1–2 个关键问题** -- 长输出先给结论,再展开细节 --- -## 12. 模板索引 +## 13. 工具入口(薄转发) -新建任何 ops 条目前,先复制对应模板: +| 工具 | 入口 | +|------|------| +| Cursor | `.cursor/rules/*` + 本文件 | +| Claude Code | [CLAUDE.md](./CLAUDE.md) | +| Codex | [CODEX.md](./CODEX.md) | +| Gemini | [GEMINI.md](./GEMINI.md) | +| Antigravity | [ANTIGRAVITY.md](./ANTIGRAVITY.md) | +| Kimi | [KIMI.md](./KIMI.md) | -| 类型 | 模板路径 | -|------|----------| +均转发至本文件启动链。 + +--- + +## 14. 模板索引 + +| 类型 | 路径 | +|------|------| | 短期任务 | `.doc/ops/templates/short-term-task.md` | | 长期任务 | `.doc/ops/templates/long-term-task.md` | | Checklist | `.doc/ops/templates/checklist.md` | | 交接 | `.doc/ops/templates/handoff.md` | | 调研 | `.doc/ops/templates/research-note.md` | +| 审计笔记 | `.doc/ops/templates/audit-note.md` | +| 整改方案 | `.doc/ops/templates/remediation-plan.md` | +| 完成度行 | `.doc/ops/templates/feature-matrix-row.md` | +| 会话结束 | `.doc/ops/templates/session-close-checklist.md` | --- diff --git a/ANTIGRAVITY.md b/ANTIGRAVITY.md new file mode 100644 index 00000000..7a14766d --- /dev/null +++ b/ANTIGRAVITY.md @@ -0,0 +1,9 @@ +# Antigravity 入口 + +请先完整阅读并遵守 [AGENTS.md](./AGENTS.md)(通用 Agent 工作手册)。 + +再阅读 [PROJECT.md](./PROJECT.md)(本仓库地图与约定)。 + +然后阅读 [.doc/README.md](./.doc/README.md) 与 [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) 获取文档 taxonomy 与当前焦点。 + +勿向用户索要 Git token;按 AGENTS.md 自行从本机 `${HOME}/.secrets/` 路径读取。 diff --git a/CLAUDE.md b/CLAUDE.md index eb386745..d0ee9512 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,6 +4,6 @@ 再阅读 [PROJECT.md](./PROJECT.md)(本仓库地图与约定)。 -然后阅读 [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) 获取当前任务焦点。 +然后阅读 [.doc/README.md](./.doc/README.md) 与 [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) 获取文档 taxonomy 与当前焦点。 勿向用户索要 Git token;按 AGENTS.md 自行从本机 `${HOME}/.secrets/` 路径读取。 diff --git a/CODEX.md b/CODEX.md new file mode 100644 index 00000000..2a6fa50f --- /dev/null +++ b/CODEX.md @@ -0,0 +1,9 @@ +# Codex 入口 + +请先完整阅读并遵守 [AGENTS.md](./AGENTS.md)(通用 Agent 工作手册)。 + +再阅读 [PROJECT.md](./PROJECT.md)(本仓库地图与约定)。 + +然后阅读 [.doc/README.md](./.doc/README.md) 与 [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) 获取文档 taxonomy 与当前焦点。 + +勿向用户索要 Git token;按 AGENTS.md 自行从本机 `${HOME}/.secrets/` 路径读取。 diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 00000000..0f71fd32 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,9 @@ +# Gemini 入口 + +请先完整阅读并遵守 [AGENTS.md](./AGENTS.md)(通用 Agent 工作手册)。 + +再阅读 [PROJECT.md](./PROJECT.md)(本仓库地图与约定)。 + +然后阅读 [.doc/README.md](./.doc/README.md) 与 [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) 获取文档 taxonomy 与当前焦点。 + +勿向用户索要 Git token;按 AGENTS.md 自行从本机 `${HOME}/.secrets/` 路径读取。 diff --git a/KIMI.md b/KIMI.md new file mode 100644 index 00000000..a478bcff --- /dev/null +++ b/KIMI.md @@ -0,0 +1,9 @@ +# Kimi Code 入口 + +请先完整阅读并遵守 [AGENTS.md](./AGENTS.md)(通用 Agent 工作手册)。 + +再阅读 [PROJECT.md](./PROJECT.md)(本仓库地图与约定)。 + +然后阅读 [.doc/README.md](./.doc/README.md) 与 [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) 获取文档 taxonomy 与当前焦点。 + +勿向用户索要 Git token;按 AGENTS.md 自行从本机 `${HOME}/.secrets/` 路径读取。 diff --git a/PROJECT.md b/PROJECT.md index a9391728..88b4e005 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -58,10 +58,13 @@ | 用途 | 路径 | |------|------| +| 文档总地图 | [.doc/README.md](./.doc/README.md) | | 协作会话 / 当前焦点 | [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) | -| 发布/审计缺口状态 | [.doc/2026-09-12-remediation-gap-matrix.md](./.doc/2026-09-12-remediation-gap-matrix.md) | +| 模块完成度 | [.doc/status/FEATURE-MATRIX.md](./.doc/status/FEATURE-MATRIX.md) | +| 发布/审计缺口 | [.doc/remediation/gap-matrix.md](./.doc/remediation/gap-matrix.md) | +| 问题分析 | [.doc/audit/INDEX.md](./.doc/audit/INDEX.md) | +| 整改方案 | [.doc/remediation/INDEX.md](./.doc/remediation/INDEX.md) | | 测试报告归档 | [.doc/test-reports/](./.doc/test-reports/) | -| 历史审计索引 | [.doc/2026-09-12-AUDIT-INDEX.md](./.doc/2026-09-12-AUDIT-INDEX.md) | | 测试报告规范 | [.cursor/rules/test-reports-standard.mdc](./.cursor/rules/test-reports-standard.mdc) | --- @@ -108,7 +111,7 @@ cd web && npm test && npm run build ## 8. 测试与验收铁律 -- 开发可用 stub;**交付前验收**必须真实 PI Agent + MiniMax-M3 全链路 +- 开发可用 stub;**交付前验收**必须真实 PI Agent + MiniMax-M2.7-highspeed 全链路 - 报告必须归档至 `.doc/test-reports/`,遵循 test-reports-standard - 禁止 stub 输出冒充最终验收数据 @@ -118,7 +121,8 @@ cd web && npm test && npm run build 见 **[.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md)**。 -- 发布缺口 SSOT:[gap-matrix](./.doc/2026-09-12-remediation-gap-matrix.md) +- 发布缺口 SSOT:[gap-matrix](./.doc/remediation/gap-matrix.md) +- 模块完成度:[FEATURE-MATRIX](./.doc/status/FEATURE-MATRIX.md) - 最新测试报告:[2026-09-13-codex-audit-p0-remediation-test-report.md](./.doc/test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md) - **剩余 blocker**: CI 真实 PI E2E + 前端人工抽检(main 本地冒烟已通过) diff --git a/README.md b/README.md index b3965c3d..332380fd 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ 本项目是一个面向企业与团队的高可用对话智能体(Chat Agent)系统,结合了知识库检索增强(RAG)、自动化 Agent 执行能力与安全审计机制。 +> **Agent / 协作者必读**:[AGENTS.md](./AGENTS.md) → [PROJECT.md](./PROJECT.md) → [.doc/README.md](./.doc/README.md) → [.doc/ops/CURRENT.md](./.doc/ops/CURRENT.md) + --- ## 一、 仓库三分支结构说明 @@ -14,7 +16,7 @@ | **`test`** | **测试分支** | **准生产实测分支**。当 `dev` 积累了一定功能阶段后合并至此,建立发布候选节点(`rc-vX.Y.Z`),进行真实环境部署与长期集成测试与运维检验。 | | **`main`** | **主分支** | **生产发布分支**。严禁直接提交。仅在 `test` 分支经过真实运维和测试验证达到发布标准后,将对应节点合并回 `main` 并打正式版本 Tag(`vX.Y.Z`)。 | -完整的分支流转模型、热修复流程与提交规范请参阅:[docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md](docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md)。 +完整的分支流转模型、热修复流程与提交规范请参阅:[PROJECT.md](./PROJECT.md) §4(SSOT)。 --- diff --git a/scripts/agent-worktree.sh b/scripts/agent-worktree.sh new file mode 100755 index 00000000..3e6195a2 --- /dev/null +++ b/scripts/agent-worktree.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# Agent worktree helper — parallel coding only; do NOT start docker from worktrees. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +WORKTREES="${ROOT}/.worktrees" + +usage() { + cat < # git worktree add .worktrees/ -b + $0 list # git worktree list + $0 remove # remove worktree and optionally delete branch + +示例: + $0 create feature/my-task + $0 list + $0 remove feature/my-task +EOF + exit 1 +} + +ensure_ignored() { + if git -C "${ROOT}" check-ignore -q .worktrees/. 2>/dev/null; then + : + else + echo "[错误] .worktrees/ 未在 .gitignore 中,请先添加。" >&2 + exit 1 + fi + mkdir -p "${WORKTREES}" +} + +slug_from_branch() { + echo "$1" | tr '/' '-' +} + +cmd="${1:-}" +case "${cmd}" in + create) + [[ $# -eq 2 ]] || usage + branch="$2" + ensure_ignored + slug="$(slug_from_branch "${branch}")" + path="${WORKTREES}/${slug}" + if [[ -d "${path}" ]]; then + echo "[错误] 已存在: ${path}" >&2 + exit 1 + fi + git -C "${ROOT}" worktree add "${path}" -b "${branch}" + echo "Worktree: ${path} (branch ${branch})" + echo "禁止在此目录运行 env-service.sh start/stop/restart" + ;; + list) + git -C "${ROOT}" worktree list + ;; + remove) + [[ $# -ge 2 && $# -le 3 ]] || usage + branch="$2" + delete_branch="${3:-}" + slug="$(slug_from_branch "${branch}")" + path="${WORKTREES}/${slug}" + if [[ ! -d "${path}" ]]; then + echo "[错误] 不存在: ${path}" >&2 + exit 1 + fi + git -C "${ROOT}" worktree remove "${path}" --force + if [[ "${delete_branch}" == "--delete-branch" ]]; then + git -C "${ROOT}" branch -D "${branch}" 2>/dev/null || true + fi + echo "已移除 worktree ${path}" + ;; + *) + usage + ;; +esac From be9a6d4640c61a07b4df3b087e9305cef658ef24 Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 02:31:30 +0000 Subject: [PATCH 3/5] docs(archive): relocate superpowers, workflow, and test assets Move docs/superpowers to archive/design/superpowers with stubs; archive workflow rules to PROJECT SSOT; separate test-report assets. Update Go doc path references. Co-authored-by: Cursor --- .doc/archive/design/superpowers/INDEX.md | 10 + .../plans/2026-09-07-bizdev-squad.md | 0 .../2026-09-07-dynamic-squad-planning.md | 0 .../2026-09-07-multi-domain-knowledge-base.md | 0 .../2026-09-08-auth-and-dual-settings.md | 0 ...-driven-content-and-hierarchical-intent.md | 0 ...8-dynamic-roles-and-doc-visibility-rbac.md | 0 ...026-09-08-project-init-template-cloning.md | 0 ...emantic-chat-history-and-case-retrieval.md | 0 ...9-08-streaming-events-and-digestible-ux.md | 0 ...ree-column-workbench-and-block-document.md | 0 ...ee-tier-deliverable-privacy-and-sharing.md | 6 +- .../2026-09-09-chat-wait-error-retry-ux.md | 2 +- ...026-09-09-longtask-phase-live-resume-ux.md | 2 +- .../specs/2026-09-07-bizdev-squad-design.md | 0 ...026-09-07-dynamic-squad-planning-design.md | 0 ...9-07-multi-domain-knowledge-base-design.md | 0 ...026-09-08-auth-and-dual-settings-design.md | 0 ...-content-and-hierarchical-intent-design.md | 2 +- ...ic-roles-and-doc-visibility-rbac-design.md | 2 +- ...08-project-init-template-cloning-design.md | 2 +- ...-chat-history-and-case-retrieval-design.md | 0 ...reaming-events-and-digestible-ux-design.md | 0 ...umn-workbench-and-block-document-design.md | 2 +- ...-deliverable-privacy-and-sharing-design.md | 2 +- ...6-09-09-chat-wait-error-retry-ux-design.md | 2 +- ...urrency-mutex-and-doc-edit-lease-design.md | 2 +- ...09-dialogue-llm-casual-ambiguous-design.md | 2 +- ...task-governance-router-and-adhoc-design.md | 2 +- ...09-longtask-phase-live-resume-ux-design.md | 0 ...e-aware-interactive-card-options-design.md | 2 +- ...dock-anchors-and-unread-redesign-design.md | 4 +- ...hive-navigation-and-daily-digest-design.md | 8 +- ...-private-document-design-implementation.md | 2 +- ...dempotency-and-session-isolation-design.md | 0 .../ops/2026-09-13-agent-docs-system-reorg.md | 68 +++++ ...09-13-audit-container-env-configuration.md | 53 ++++ .../2026-09-13-codex-audit-p0-remediation.md | 44 +++ ...2026-09-13-fix-piagent-provider-minimax.md | 50 ++++ .../2026-09-13-codex-audit-p0-remediation.md | 47 ++++ .../reference/branch-and-environment-rules.md | 250 +++++++++++++++++ ...les-and-doc-visibility-rbac-test-report.md | 4 +- ...09-chat-wait-error-retry-ux-test-report.md | 2 +- ...container-env-configuration-test-report.md | 104 ++++++++ .../01-router-upgrade/adhoc_task_reply.md | 0 .../dialogue_first_answer.md | 0 .../workspace/blackboard.json | 0 .../workspace/gov_audit.jsonl | 0 .../01-router-upgrade/workspace/ledger.json | 0 .../01-router-upgrade/workspace/manifest.json | 0 .../01-router-upgrade/workspace/output.md | 0 .../workspace/tasks/01_organize/TASK.md | 0 .../workspace/tasks/01_organize/output.md | 0 .../tasks/01_organize/step_manifest.json | 0 .../workspace/tasks/02_engineer/TASK.md | 0 .../workspace/tasks/02_engineer/output.md | 0 .../tasks/02_engineer/step_manifest.json | 0 .../workspace/tasks/03_draft/TASK.md | 0 .../workspace/tasks/03_draft/output.md | 0 .../tasks/03_draft/step_manifest.json | 0 .../workspace/tasks/04_review/TASK.md | 0 .../workspace/tasks/04_review/output.md | 0 .../tasks/04_review/step_manifest.json | 0 .../workspace/tasks/dynamic_rf_emc/TASK.md | 0 .../workspace/tasks/dynamic_rf_emc/output.md | 0 .../tasks/dynamic_rf_emc/step_manifest.json | 0 .../workspace/tasks/repair_1/TASK.md | 0 .../workspace/tasks/repair_1/output.md | 0 .../workspace/tasks/repair_2/TASK.md | 0 .../workspace/tasks/repair_2/output.md | 0 .../01-router-upgrade/workspace/trace.jsonl | 0 .../01-router-upgrade/workspace/workflow.json | 0 .../workspace/workspace.json | 0 .../02-standard-research/task_summary.md | 0 .../workspace/blackboard.json | 0 .../workspace/gov_audit.jsonl | 0 .../workspace/ledger.json | 0 .../workspace/manifest.json | 0 .../02-standard-research/workspace/output.md | 0 .../workspace/tasks/01_search/TASK.md | 0 .../workspace/tasks/01_search/output.md | 0 .../tasks/01_search/step_manifest.json | 0 .../workspace/tasks/02_market/TASK.md | 0 .../workspace/tasks/02_market/output.md | 0 .../tasks/02_market/step_manifest.json | 0 .../workspace/tasks/03_regulatory/TASK.md | 0 .../workspace/tasks/03_regulatory/output.md | 0 .../tasks/03_regulatory/step_manifest.json | 0 .../workspace/tasks/04_plan/TASK.md | 0 .../tasks/04_plan/step_manifest.json | 0 .../workspace/tasks/05_review_plan/TASK.md | 0 .../tasks/05_review_plan/step_manifest.json | 0 .../workspace/tasks/06_draft/TASK.md | 0 .../workspace/tasks/06_draft/output.md | 0 .../tasks/06_draft/step_manifest.json | 0 .../workspace/tasks/07_review/TASK.md | 0 .../workspace/tasks/07_review/output.md | 0 .../tasks/07_review/step_manifest.json | 0 .../workspace/trace.jsonl | 0 .../workspace/workflow.json | 0 .../workspace/workspace.json | 0 .../REPORT.md | 2 +- docs/README.md | 10 + docs/superpowers/README.md | 7 + docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md | 251 +----------------- internal/chat/longtask_quality_e2e_test.go | 2 +- internal/squad/gov.go | 2 +- 107 files changed, 674 insertions(+), 276 deletions(-) create mode 100644 .doc/archive/design/superpowers/INDEX.md rename {docs => .doc/archive/design}/superpowers/plans/2026-09-07-bizdev-squad.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-07-dynamic-squad-planning.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-07-multi-domain-knowledge-base.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-auth-and-dual-settings.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-dialogue-driven-content-and-hierarchical-intent.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-project-init-template-cloning.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-semantic-chat-history-and-case-retrieval.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-streaming-events-and-digestible-ux.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-three-column-workbench-and-block-document.md (100%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md (88%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md (99%) rename {docs => .doc/archive/design}/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-07-bizdev-squad-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-07-dynamic-squad-planning-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-07-multi-domain-knowledge-base-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-auth-and-dual-settings-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-project-init-template-cloning-design.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md (98%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md (98%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md (96%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md (93%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md (100%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md (96%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md (98%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md (99%) rename {docs => .doc/archive/design}/superpowers/specs/2026-09-11-chat-turn-idempotency-and-session-isolation-design.md (100%) create mode 100644 .doc/archive/ops/2026-09-13-agent-docs-system-reorg.md create mode 100644 .doc/archive/ops/2026-09-13-audit-container-env-configuration.md create mode 100644 .doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md create mode 100644 .doc/archive/ops/2026-09-13-fix-piagent-provider-minimax.md create mode 100644 .doc/archive/ops/checklists/2026-09-13-codex-audit-p0-remediation.md create mode 100644 .doc/archive/reference/branch-and-environment-rules.md create mode 100644 .doc/test-reports/2026-09-13-container-env-configuration-test-report.md rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/adhoc_task_reply.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/dialogue_first_answer.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/blackboard.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/gov_audit.jsonl (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/ledger.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/trace.jsonl (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workflow.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workspace.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/task_summary.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/blackboard.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/gov_audit.jsonl (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/ledger.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/TASK.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/output.md (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/step_manifest.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/trace.jsonl (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workflow.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workspace.json (100%) rename .doc/test-reports/{ => assets/longtask-governance-quality}/2026-09-09-longtask-governance-quality/REPORT.md (95%) create mode 100644 docs/README.md create mode 100644 docs/superpowers/README.md diff --git a/.doc/archive/design/superpowers/INDEX.md b/.doc/archive/design/superpowers/INDEX.md new file mode 100644 index 00000000..98eb829b --- /dev/null +++ b/.doc/archive/design/superpowers/INDEX.md @@ -0,0 +1,10 @@ +# 历史功能设计(Superpowers) + +迭代期功能 spec/plan,自 `.doc/archive/design/superpowers/` 迁入。 + +| 子目录 | 内容 | +|--------|------| +| `specs/` | 设计规范 | +| `plans/` | 实施计划 | + +新功能设计请写入 `.doc/system-design/` 或 `.doc/remediation/`,**不再**使用 `.doc/archive/design/superpowers/`。 diff --git a/docs/superpowers/plans/2026-09-07-bizdev-squad.md b/.doc/archive/design/superpowers/plans/2026-09-07-bizdev-squad.md similarity index 100% rename from docs/superpowers/plans/2026-09-07-bizdev-squad.md rename to .doc/archive/design/superpowers/plans/2026-09-07-bizdev-squad.md diff --git a/docs/superpowers/plans/2026-09-07-dynamic-squad-planning.md b/.doc/archive/design/superpowers/plans/2026-09-07-dynamic-squad-planning.md similarity index 100% rename from docs/superpowers/plans/2026-09-07-dynamic-squad-planning.md rename to .doc/archive/design/superpowers/plans/2026-09-07-dynamic-squad-planning.md diff --git a/docs/superpowers/plans/2026-09-07-multi-domain-knowledge-base.md b/.doc/archive/design/superpowers/plans/2026-09-07-multi-domain-knowledge-base.md similarity index 100% rename from docs/superpowers/plans/2026-09-07-multi-domain-knowledge-base.md rename to .doc/archive/design/superpowers/plans/2026-09-07-multi-domain-knowledge-base.md diff --git a/docs/superpowers/plans/2026-09-08-auth-and-dual-settings.md b/.doc/archive/design/superpowers/plans/2026-09-08-auth-and-dual-settings.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-auth-and-dual-settings.md rename to .doc/archive/design/superpowers/plans/2026-09-08-auth-and-dual-settings.md diff --git a/docs/superpowers/plans/2026-09-08-dialogue-driven-content-and-hierarchical-intent.md b/.doc/archive/design/superpowers/plans/2026-09-08-dialogue-driven-content-and-hierarchical-intent.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-dialogue-driven-content-and-hierarchical-intent.md rename to .doc/archive/design/superpowers/plans/2026-09-08-dialogue-driven-content-and-hierarchical-intent.md diff --git a/docs/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md b/.doc/archive/design/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md rename to .doc/archive/design/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md diff --git a/docs/superpowers/plans/2026-09-08-project-init-template-cloning.md b/.doc/archive/design/superpowers/plans/2026-09-08-project-init-template-cloning.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-project-init-template-cloning.md rename to .doc/archive/design/superpowers/plans/2026-09-08-project-init-template-cloning.md diff --git a/docs/superpowers/plans/2026-09-08-semantic-chat-history-and-case-retrieval.md b/.doc/archive/design/superpowers/plans/2026-09-08-semantic-chat-history-and-case-retrieval.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-semantic-chat-history-and-case-retrieval.md rename to .doc/archive/design/superpowers/plans/2026-09-08-semantic-chat-history-and-case-retrieval.md diff --git a/docs/superpowers/plans/2026-09-08-streaming-events-and-digestible-ux.md b/.doc/archive/design/superpowers/plans/2026-09-08-streaming-events-and-digestible-ux.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-streaming-events-and-digestible-ux.md rename to .doc/archive/design/superpowers/plans/2026-09-08-streaming-events-and-digestible-ux.md diff --git a/docs/superpowers/plans/2026-09-08-three-column-workbench-and-block-document.md b/.doc/archive/design/superpowers/plans/2026-09-08-three-column-workbench-and-block-document.md similarity index 100% rename from docs/superpowers/plans/2026-09-08-three-column-workbench-and-block-document.md rename to .doc/archive/design/superpowers/plans/2026-09-08-three-column-workbench-and-block-document.md diff --git a/docs/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md b/.doc/archive/design/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md similarity index 88% rename from docs/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md rename to .doc/archive/design/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md index cec98e83..293861b2 100644 --- a/docs/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md +++ b/.doc/archive/design/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md @@ -2,7 +2,7 @@ # (Three-Tier Deliverable Governance, Privacy & Sharing Implementation Plan) - **编制日期**: 2026-09-08 -- **设计规范**: `docs/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md` +- **设计规范**: `.doc/archive/design/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md` - **执行分支**: `dev` --- @@ -12,8 +12,8 @@ ### 任务 1: 规范编制与架构契约归档 (Docs & Specs) - **目标**: 编制完整的架构规范与实施计划文档,明确三层分类、可见性规则与流转动作。 - **文件**: - - `docs/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md` - - `docs/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md` + - `.doc/archive/design/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md` + - `.doc/archive/design/superpowers/plans/2026-09-08-three-tier-deliverable-privacy-and-sharing.md` ### 任务 2: 升级前端数据模型与 Mock 数据 (Data Model & Initial Mocks) - **目标**: 扩展 `DeliverableItem`,增加 `category` (`workflow` | `shared` | `private`)、`creatorId`、`creatorName`、`sharedAt` 等字段,并补充初始模拟数据。 diff --git a/docs/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md b/.doc/archive/design/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md similarity index 99% rename from docs/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md rename to .doc/archive/design/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md index a1b4605c..45235c07 100644 --- a/docs/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md +++ b/.doc/archive/design/superpowers/plans/2026-09-09-chat-wait-error-retry-ux.md @@ -8,7 +8,7 @@ **Tech Stack:** Go 1.22+ (`net/http` SSE), React 19 + TypeScript + Vite, `node:test` / vitest for web unit tests, real `pi-agent` + MiniMax for E2E acceptance. -**Spec:** `docs/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md` +**Spec:** `.doc/archive/design/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md` ## Global Constraints diff --git a/docs/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md b/.doc/archive/design/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md similarity index 99% rename from docs/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md rename to .doc/archive/design/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md index 40a70c51..6a5f94ff 100644 --- a/docs/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md +++ b/.doc/archive/design/superpowers/plans/2026-09-09-longtask-phase-live-resume-ux.md @@ -8,7 +8,7 @@ **Tech Stack:** Go 1.22+ (`net/http` SSE), React 19 + TypeScript + Vite, `node:test` for web unit tests, real `pi-agent` + MiniMax for E2E acceptance. -**Spec:** `docs/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md` +**Spec:** `.doc/archive/design/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md` ## Global Constraints diff --git a/docs/superpowers/specs/2026-09-07-bizdev-squad-design.md b/.doc/archive/design/superpowers/specs/2026-09-07-bizdev-squad-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-07-bizdev-squad-design.md rename to .doc/archive/design/superpowers/specs/2026-09-07-bizdev-squad-design.md diff --git a/docs/superpowers/specs/2026-09-07-dynamic-squad-planning-design.md b/.doc/archive/design/superpowers/specs/2026-09-07-dynamic-squad-planning-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-07-dynamic-squad-planning-design.md rename to .doc/archive/design/superpowers/specs/2026-09-07-dynamic-squad-planning-design.md diff --git a/docs/superpowers/specs/2026-09-07-multi-domain-knowledge-base-design.md b/.doc/archive/design/superpowers/specs/2026-09-07-multi-domain-knowledge-base-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-07-multi-domain-knowledge-base-design.md rename to .doc/archive/design/superpowers/specs/2026-09-07-multi-domain-knowledge-base-design.md diff --git a/docs/superpowers/specs/2026-09-08-auth-and-dual-settings-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-auth-and-dual-settings-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-08-auth-and-dual-settings-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-auth-and-dual-settings-design.md diff --git a/docs/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md similarity index 99% rename from docs/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md index 512442df..dbe781e5 100644 --- a/docs/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md @@ -1,7 +1,7 @@ # 对话驱动受控内容产出、分级意图消解与交互卡片架构设计规范 # (Dialogue-Driven Content Synthesis, Hierarchical Intent Funnel & Interactive Cards Specification) -- **归档路径**: `docs/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md` - **编制日期**: 2026-09-08 - **当前状态**: 批准实施 (Approved) - **技术栈**: Go 后端 (L1 意图识别/L2 协调引擎/L3 底层服务) + React 19 / TypeScript 前端 + 医疗器械受控文档治理引擎 (`docgov`) diff --git a/docs/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md similarity index 99% rename from docs/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md index 6658e071..d41677ef 100644 --- a/docs/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md @@ -1,7 +1,7 @@ # 动态角色管理与单文档可见性覆盖权限系统架构设计规范 # (Dynamic Roles & Document-Level Visibility Override RBAC Specification) -- **归档路径**: `docs/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md` - **编制日期**: 2026-09-08 - **当前状态**: 批准实施 (Approved) - **技术栈**: React 19 + TypeScript + Vite + FlowMind Token 设计系统 + Go 后端规范兼容 diff --git a/docs/superpowers/specs/2026-09-08-project-init-template-cloning-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-project-init-template-cloning-design.md similarity index 99% rename from docs/superpowers/specs/2026-09-08-project-init-template-cloning-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-project-init-template-cloning-design.md index 114ae3d1..ee68a5b1 100644 --- a/docs/superpowers/specs/2026-09-08-project-init-template-cloning-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-08-project-init-template-cloning-design.md @@ -1,7 +1,7 @@ # 项目创建即时克隆全生命周期文档模板副本设计规范 # (Project-Init Template Cloning & Full-Lifecycle Workflow Visualization Spec) -- **归档路径**: `docs/superpowers/specs/2026-09-08-project-init-template-cloning-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-08-project-init-template-cloning-design.md` - **编制日期**: 2026-09-08 - **当前状态**: 待实施 (Draft / Pending Plan) - **技术栈**: React 19 + TypeScript + FlowMind Token 设计系统 + Vite + Go 协同服务 diff --git a/docs/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md diff --git a/docs/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md diff --git a/docs/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md similarity index 99% rename from docs/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md index feef4175..152bd170 100644 --- a/docs/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md @@ -1,7 +1,7 @@ # 水木东方现代三栏工作台与块状受控文档引擎设计规范 # (Three-Column Modern Workbench & Block-Based Document Engine Specification) -- **归档路径**: `docs/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-08-three-column-workbench-and-block-document-design.md` - **编制日期**: 2026-09-08 - **状态**: 批准实施 (Approved) - **技术栈**: React 19 + TypeScript + Vite + FlowMind Token 设计系统 + Go HTTP/SSE 后端 diff --git a/docs/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md b/.doc/archive/design/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md similarity index 98% rename from docs/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md rename to .doc/archive/design/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md index 2770f0ad..ee5e9c41 100644 --- a/docs/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md @@ -1,7 +1,7 @@ # 三层交付物治理与隐私/共享架构设计规范 # (Three-Tier Deliverable Governance, Privacy & Sharing Specification) -- **归档路径**: `docs/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-08-three-tier-deliverable-privacy-and-sharing-design.md` - **编制日期**: 2026-09-08 - **当前状态**: 批准实施 (Approved) - **技术栈**: React 19 + TypeScript + Vite + FlowMind Token 设计系统 + Go 后端 diff --git a/docs/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md b/.doc/archive/design/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md similarity index 98% rename from docs/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md rename to .doc/archive/design/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md index f256eccc..256e6391 100644 --- a/docs/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md @@ -222,7 +222,7 @@ pending → streaming_status → completed ## 七、与既有文档的关系 -- 继承并实现:`docs/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md` 中 Web 侧「进度条 + 对话呈现」缺口。 +- 继承并实现:`.doc/archive/design/superpowers/specs/2026-09-08-streaming-events-and-digestible-ux-design.md` 中 Web 侧「进度条 + 对话呈现」缺口。 - 不替代该文档的三层信息架构与事件类型定义;本文件专注 **Web 等待态、错误诊断、分型重试与自动重试策略**。 --- diff --git a/docs/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md b/.doc/archive/design/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md similarity index 96% rename from docs/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md rename to .doc/archive/design/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md index 81b39d85..7ade729a 100644 --- a/docs/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md @@ -1,6 +1,6 @@ # 对话/小队并发与文档编辑互斥设计规范 -- **归档路径**: `docs/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-09-concurrency-mutex-and-doc-edit-lease-design.md` - **编制日期**: 2026-09-09 - **当前状态**: 批准实施 (Approved) / 实现中 - **技术栈**: Go 后端 docgov/bizdev/chat/agent + React 工作台 diff --git a/docs/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md b/.doc/archive/design/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md similarity index 93% rename from docs/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md rename to .doc/archive/design/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md index 858f79eb..75271590 100644 --- a/docs/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md @@ -1,6 +1,6 @@ # 对话闲聊/模糊分支接入真实 LLM(Phase A)设计 -- **归档路径**: `docs/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md` - **编制日期**: 2026-09-09 - **状态**: 实施中(用户确认方案 A + 协调层内嵌 pi-agent) diff --git a/docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md b/.doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md similarity index 99% rename from docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md rename to .doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md index 9d7eb864..c4b8f7d9 100644 --- a/docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md @@ -1,6 +1,6 @@ # 长任务运行时治理、执行路由与自由任务体系设计(Task Runtime Governance & Router) -- **归档路径**: `docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md` - **编制日期**: 2026-09-09 - **当前状态**: 设计定稿待评审 (Draft for Review) - **关联模块**: `internal/squad` · `internal/agent` · `internal/intent` · `internal/coordinator` · `internal/ctxmgr` · `internal/kb` · pi-agent bridge · `web/src` diff --git a/docs/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md b/.doc/archive/design/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md rename to .doc/archive/design/superpowers/specs/2026-09-09-longtask-phase-live-resume-ux-design.md diff --git a/docs/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md b/.doc/archive/design/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md similarity index 96% rename from docs/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md rename to .doc/archive/design/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md index b4e50fd1..92ae4210 100644 --- a/docs/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md @@ -1,7 +1,7 @@ # 角色适配交互卡片选项设计补丁 # (Role-Aware Interactive Card Options) -- **归档路径**: `docs/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-09-role-aware-interactive-card-options-design.md` - **编制日期**: 2026-09-09 - **当前状态**: 批准实施 (Approved) - **关联规格**: `2026-09-08-dialogue-driven-content-and-hierarchical-intent-design.md` §5.x diff --git a/docs/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md b/.doc/archive/design/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md similarity index 99% rename from docs/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md rename to .doc/archive/design/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md index 04e1fc51..6f3fe29b 100644 --- a/docs/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md @@ -1,11 +1,11 @@ # 分类准确性治理、Dock 式锚点坞与未读体系重设计规范 -- **归档路径**: `docs/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-10-category-dock-anchors-and-unread-redesign-design.md` - **编制日期**: 2026-09-10 - **状态**: 待评审 (Draft for Review) - **性质**: 前序设计 `2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md` 落地后的**实施反馈修正版**(Fix-up Spec) - **关联文档**: - - `docs/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md`(P0-P3 已实施:窗口化、日历、搜索、摘要、导出、未读) + - `.doc/archive/design/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md`(P0-P3 已实施:窗口化、日历、搜索、摘要、导出、未读) - `internal/intent/types.go`(意图枚举单一事实源) - `internal/ctxmgr/category.go` / `deploy/postgres/migrations/2026-09-10-chat-messages-day-window.sql`(现存两套分类词表) diff --git a/docs/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md b/.doc/archive/design/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md similarity index 98% rename from docs/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md rename to .doc/archive/design/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md index 67459a24..603411f9 100644 --- a/docs/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md +++ b/.doc/archive/design/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md @@ -1,12 +1,12 @@ # 长对话历史时间轴归档、多级导航锚点与每日智能摘要设计规范 -- **归档路径**: `docs/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-10-chat-history-archive-navigation-and-daily-digest-design.md` - **编制日期**: 2026-09-10 - **状态**: 待评审 (Draft for Review) - **关联文档**: - - `docs/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md`(多轮会话持久化与标杆案例语义检索,本设计在其 `chat_sessions` / `chat_messages` / `context_memory_chunks` 基础上演进) - - `docs/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md`(SSE 气泡状态机与 `sourceUserMessageId`,本设计的消息 ID 稳定性协议与其衔接) - - `docs/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md`(pi-agent + MiniMax 真实 LLM 接入,本设计的每日摘要生成器复用该 Backend) + - `.doc/archive/design/superpowers/specs/2026-09-08-semantic-chat-history-and-case-retrieval-design.md`(多轮会话持久化与标杆案例语义检索,本设计在其 `chat_sessions` / `chat_messages` / `context_memory_chunks` 基础上演进) + - `.doc/archive/design/superpowers/specs/2026-09-09-chat-wait-error-retry-ux-design.md`(SSE 气泡状态机与 `sourceUserMessageId`,本设计的消息 ID 稳定性协议与其衔接) + - `.doc/archive/design/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md`(pi-agent + MiniMax 真实 LLM 接入,本设计的每日摘要生成器复用该 Backend) --- diff --git a/docs/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md b/.doc/archive/design/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md similarity index 99% rename from docs/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md rename to .doc/archive/design/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md index 16dc46a0..caca4a16 100644 --- a/docs/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md +++ b/.doc/archive/design/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md @@ -1,7 +1,7 @@ # 单次智能体回复导出、私密文档保存与隐私防泄露设计及实施规范 # (Single Assistant Reply Export, Private Document Save & Privacy Guard Design and Implementation Specification) -- **归档路径**: `docs/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md` +- **归档路径**: `.doc/archive/design/superpowers/specs/2026-09-10-single-assistant-reply-export-and-private-document-design-implementation.md` - **编制日期**: 2026-09-10 - **当前状态**: 评审稿 (Proposed) - **适用范围**: 项目工作台中单条智能体回复的复制、下载、保存为私密文档及后续项目级共享 diff --git a/docs/superpowers/specs/2026-09-11-chat-turn-idempotency-and-session-isolation-design.md b/.doc/archive/design/superpowers/specs/2026-09-11-chat-turn-idempotency-and-session-isolation-design.md similarity index 100% rename from docs/superpowers/specs/2026-09-11-chat-turn-idempotency-and-session-isolation-design.md rename to .doc/archive/design/superpowers/specs/2026-09-11-chat-turn-idempotency-and-session-isolation-design.md diff --git a/.doc/archive/ops/2026-09-13-agent-docs-system-reorg.md b/.doc/archive/ops/2026-09-13-agent-docs-system-reorg.md new file mode 100644 index 00000000..e10a66df --- /dev/null +++ b/.doc/archive/ops/2026-09-13-agent-docs-system-reorg.md @@ -0,0 +1,68 @@ +--- +title: "Agent 协作文档体系重组" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: cursor +branch: dev +worktree: "-" +mutex: docs +--- + +# Agent 协作文档体系重组 + +## 目标 + +建立跨工具(Cursor / Claude Code / Codex / Kimi / Antigravity)可协作的文档 taxonomy、多 Agent 并行规则与集成槽位,并完成 `.doc/` 结构性重组。 + +## 范围 + +- 新建 `audit/`、`remediation/`、`archive/`、`status/` 及 `.doc/README.md` +- 迁移根目录 15 份审计/整改文档;留 stub +- 编写 `FEATURE-MATRIX.md`;扩展 `AGENTS.md` +- CURRENT 增加并行认领表 + 集成槽位 +- 多工具薄入口 + `scripts/agent-worktree.sh` +- `.gitignore` 增加 `.worktrees/` + +## 非目标 + +- 每 worktree 独立 Docker 端口矩阵 +- 重写 system-design 长文 +- 删除历史证据 + +## 已锁定决策 + +| 项 | 选择 | +|----|------| +| 重组力度 | 结构性重组(迁目录) | +| 完成度 SSOT | `.doc/status/FEATURE-MATRIX.md` | +| 并行 | 认领 + 分支强制 + 并行时 worktree | +| Docker | 仅主工作区单实例 | +| 集成 | 合入 dev + 容器测串行(集成槽位) | + +## 步骤 + +1. [ ] P0:scaffold 目录 + `.gitignore` + `.doc/README.md` +2. [ ] P1:`git mv` 15 文件 + stubs + 更新 INDEX/全库链接 +3. [ ] P2:`FEATURE-MATRIX` + CURRENT 认领/槽位 + 已完成任务→archive +4. [ ] P3:模板 + 重写 `AGENTS.md` + PROJECT/薄入口/Cursor rule +5. [ ] P4:`agent-worktree.sh` + 链接抽检 + 分批提交 + +## 验收标准 + +- [ ] AGENTS 启动链完整(含 `.doc/README` + FEATURE-MATRIX) +- [ ] 根目录无散落审计/整改大包(仅 stub) +- [ ] CURRENT 含认领表与集成槽位段 +- [ ] 多工具薄入口齐全 +- [ ] worktree 脚本冒烟通过 + +## 相关链接 + +- 详细计划:Cursor plan `agent_docs_system_4d43ab63` +- Checklist: (本任务完成后自建) +- Handoff: +- Test report: N/A(纯文档任务) + +## 证据 / 备注 + +(执行过程中追加 commit hash 与命令输出) diff --git a/.doc/archive/ops/2026-09-13-audit-container-env-configuration.md b/.doc/archive/ops/2026-09-13-audit-container-env-configuration.md new file mode 100644 index 00000000..c49483b0 --- /dev/null +++ b/.doc/archive/ops/2026-09-13-audit-container-env-configuration.md @@ -0,0 +1,53 @@ +--- +title: "审计容器构建与环境变量配置链" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: codex +--- + +# 审计容器构建与环境变量配置链 + +## 目标 + +确认 Dockerfile、Compose、启动脚本与应用代码正确消费根 `.env` 的必要配置;补齐缺失字段并移除已废弃字段。 + +## 范围 + +- Dockerfile、所有 Compose 文件、容器启动与环境管理脚本 +- Go / React / PI Agent 的环境变量读取点及默认值 +- 根 `.env` 与 `.env.example` 的字段集合(不记录秘密值) +- 当前容器解析配置与运行时注入的静态/动态验证 + +## 非目标 + +- 不替用户编造或更换第三方密钥 +- 不修改与环境配置无关的业务逻辑 +- 不输出 `.env` 中的敏感值 + +## 步骤 + +1. [x] 建立代码、构建、Compose、脚本的环境变量清单 +2. [x] 对比 `.env`、`.env.example` 与各环境覆写,定位缺失/废弃/断链字段 +3. [x] 修正配置文件与必要的注入链路 +4. [x] 执行 Compose config、构建及运行时验证 +5. [x] 写入调研证据、测试报告、CURRENT 与 handoff + +## 验收标准 + +- [x] 必需字段在 `.env.example` 中有说明,在 `.env` 中有字段占位或现值 +- [x] 已移除配置不再残留在 `.env` / `.env.example` +- [x] Compose 构建与配置渲染能正确传递所需字段 +- [x] 验证结果有不泄露秘密的可复核报告 +- [x] 用户补齐两个数据库密码、同步轮换现有 DB,并恢复 main ready + +## 相关链接 + +- Research: `../research/2026-09-13-container-env-configuration-audit.md` +- Test report: `../../test-reports/2026-09-13-container-env-configuration-test-report.md` +- Handoff: `../handoffs/2026-09-13-container-env-configuration.md` + +## 证据 / 备注 + +- 审计中仅记录变量名、来源和是否非空,不记录敏感值。 +- 用户补值后已同步执行两个 PostgreSQL `ALTER ROLE`;独立容器 TCP/SCRAM 登录与 `SELECT 1` 均通过,main app 已恢复 healthy/ready。 diff --git a/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md b/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md new file mode 100644 index 00000000..a2bb4d8b --- /dev/null +++ b/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md @@ -0,0 +1,44 @@ +--- +title: "Codex 审计 P0 整改" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: agent +--- + +# Codex 审计 P0 整改 + +## 目标 + +闭环 Codex 2026-09-12 再审计 P0/门禁/环境项,并完成文档 SSOT 对齐。 + +## 范围 + +- Wave A: 任务鉴权、00025 序列、lifecycle 脏数据 +- Wave B: Go vet + short 全绿 +- Wave C: test 重建、main 冒烟 +- Wave D: gap-matrix、superseded、test-report + +## 非目标 + +- session cookie 重构 +- bundle 拆分 / 23GB 容量治理 + +## 步骤 + +1. [x] Wave 0: AGENTS.md / PROJECT.md / CLAUDE.md / ops / rules +2. [x] Wave A1: handleRunTask + SSE 鉴权 + 负例测试 +3. [x] Wave A2: goose 00025 +4. [x] Wave A3: lifecycle SQL + test 工作流退休 +5. [x] Wave B: AdvisorBrief / V0.5 / chat memory / kb gate / health +6. [x] Wave C: 环境一致性(main OPEN) +7. [x] Wave D: 文档对齐 + +## 验收标准 + +见 [checklist](../checklists/2026-09-13-codex-audit-p0-remediation.md) + +## 相关链接 + +- 调研: [research/2026-09-12-codex-reaudit-summary.md](../research/2026-09-12-codex-reaudit-summary.md) +- Gap matrix: [../../2026-09-12-remediation-gap-matrix.md](../../2026-09-12-remediation-gap-matrix.md) diff --git a/.doc/archive/ops/2026-09-13-fix-piagent-provider-minimax.md b/.doc/archive/ops/2026-09-13-fix-piagent-provider-minimax.md new file mode 100644 index 00000000..fd492f8b --- /dev/null +++ b/.doc/archive/ops/2026-09-13-fix-piagent-provider-minimax.md @@ -0,0 +1,50 @@ +--- +title: "修复 pi-agent Unknown provider cc-switch-kimi-for-coding" +status: done +created: 2026-09-13 +updated: 2026-09-13 +owner: agent +--- + +# 修复 pi-agent Unknown provider cc-switch-kimi-for-coding + +## 目标 + +任务 `run_1789263149536199173` / workspace `intake_1789263149571817685` 因错误 provider 中断;恢复为与根 `.env` 一致的 `minimax` + `MiniMax-M2.7-highspeed`。 + +## 范围 + +- 修正 `internal/config/config.go` 错误默认值 +- 同步 `configs/.env.dev` 与 compose 注入(不编造新密钥/新 endpoint) +- 对齐根 `.env` 中 `PI_AGENT_MODEL` 与 `MINIMAX_MODEL_ID` +- 重启 / 重建 dev 的 app / pi-agent 使配置生效 + +## 非目标 + +- 不改动 test/main 环境密钥 +- 不擅自更换 API endpoint / API key +- 不在本任务内重跑完整业务长任务(修复后由用户 continue/restart) + +## 步骤 + +1. [x] 根因定位:Go 默认 `cc-switch-kimi-for-coding`;app 容器无 `PI_AGENT_*` 覆盖 +2. [x] 修正代码默认值与 `.env` / `.env.dev` / compose +3. [x] force-recreate + rebuild;health 已显示 `MiniMax-M2.7-highspeed` +4. [x] 提交 `8f3aa0f` + +## 验收标准 + +- [x] `shuimu-pi-agent-dev` health 显示 `MiniMax-M2.7-highspeed` +- [x] app 进程生效 `PI_AGENT_PROVIDER=minimax`、`PI_AGENT_MODEL=MiniMax-M2.7-highspeed` +- [x] 配置链不再默认 `cc-switch-kimi-for-coding`(业务 continue/restart 由用户触发验证) + +## 相关链接 + +- 失败 workspace: `data/dev/workspaces/bizdev/intake_1789263149571817685` +- 根配置: `.env`(`MINIMAX_MODEL_ID=MiniMax-M2.7-highspeed`) + +## 证据 / 备注 + +- upstream: `step step_01_organize failed: Error: Unknown provider "cc-switch-kimi-for-coding"` +- blame: `abd0893e` 将默认从 anthropic 误改为 kimi +- 验证:`curl :18865/health` → `model_id=MiniMax-M2.7-highspeed`;app env 含 `PI_AGENT_PROVIDER=minimax` diff --git a/.doc/archive/ops/checklists/2026-09-13-codex-audit-p0-remediation.md b/.doc/archive/ops/checklists/2026-09-13-codex-audit-p0-remediation.md new file mode 100644 index 00000000..2def7995 --- /dev/null +++ b/.doc/archive/ops/checklists/2026-09-13-codex-audit-p0-remediation.md @@ -0,0 +1,47 @@ +--- +title: "Codex 审计 P0 整改 Checklist" +status: done +created: 2026-09-13 +updated: 2026-09-13 +related_task: short-term/2026-09-13-codex-audit-p0-remediation.md +--- + +# Codex 审计 P0 整改 Checklist + +## Wave 0 — Agent 文档 + +- [x] AGENTS.md / PROJECT.md / CLAUDE.md — commit 31fe607 +- [x] .cursor/rules — agent-collaboration + git-secrets +- [x] .doc/ops templates + CURRENT + +## Wave A — P0 + +- [x] AUTH tasks/run + stream — commit d82021e;`task_run_authz_pg_test.go` +- [x] DB 00025 — commit b13ced6;dev/test setval +- [x] DATA lifecycle — dev UPDATE 47 → 0 +- [x] DATA test wf — UPDATE 5 retired + +## Wave B — Go 门禁 + +- [x] go vet ./... PASS — commit 91985a2 +- [x] go test -short ./... PASS +- [x] AdvisorBrief / V0.5 / chat / kb / health / asset + +## Wave C — 环境 + +- [x] test rebuild schema 25 — health 8081 +- [x] dev docker app schema 25 — health 8080 +- [x] main 冒烟 — health/ready 8000 schema 25;restart 恢复 +- [x] HTTP 超时 + env status 只读 — commit 505c419 +- [x] .env.dev/.env.test chmod 600 + +## Wave D — 文档 + +- [x] gap-matrix Codex 项 +- [x] AUDIT-INDEX + superseded 横幅 +- [x] quick-ref 断链修复 +- [x] [test-report](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md) + +## 完成定义 + +- [x] P0/门禁项已闭环(main 除外,已记 OPEN) diff --git a/.doc/archive/reference/branch-and-environment-rules.md b/.doc/archive/reference/branch-and-environment-rules.md new file mode 100644 index 00000000..1bca88e0 --- /dev/null +++ b/.doc/archive/reference/branch-and-environment-rules.md @@ -0,0 +1,250 @@ +# 研发分支与多套独立环境运行规范 (Branch & Environment Rules) + +本规范为本系统代码仓库的强制性规范,涵盖 **Git 3 分支流转模型**、**任务功能拆分与渐进式提交**、**三套环境独立运行(知识库共享 + 对话与数据库隔离)** 以及 **运维操作指引**。 + +--- + +## 一、 Git 固定三分支体系与流转规范 + +本仓库严格固定维护 **3 个常驻分支**: + +``` + (Feature/Fix 子分支) + ┌─────────────┐ + │ feature/*** │ + └──────┬──────┘ + (创建/自测) │ (合回) + ▼ ▼ +┌─────────────────────────────────┐ +│ 开发分支: dev │ <-- 所有日常开发在此进行,功能逐步提交 +└────────────────┬────────────────┘ + │ (积累一定阶段功能,准备长期部署实测) + ▼ +┌─────────────────────────────────┐ +│ 测试分支: test │ <-- 部署到测试环境,进行真实环境长期运维与测试 +└────────────────┬────────────────┘ + │ (测试分支经过实际运维和测试验证,达到发布标准) + ▼ +┌─────────────────────────────────┐ +│ 主分支: main (Release) │ <-- 生产发布基线,对应线上生产环境 +└─────────────────────────────────┘ +``` + +### 1. 开发分支 (`dev`) +- **定位**:日常开发核心集成分支。 +- **职责**:所有新功能(Features)、常规缺陷修复(Bugfixes)、日常重构均在 `dev` 分支推进。 +- **子分支策略**: + - **简单任务**:可直接在 `dev` 分支上按功能拆分进行渐进式提交。 + - **中大型或独立功能**:必须从 `dev` 检出子分支,命名格式为: + - `feature/<功能简述>` (如 `feature/session-isolation`) + - `fix/<缺陷简述>` (如 `fix/llm-streaming-timeout`) + - **合回机制**:子分支在开发者本地或容器中完成自测、通过单元测试和代码审查后,合并回 `dev` 分支(推荐保留提交历史或使用半快进合并)。合并完成后应及时删除临时子分支。 + +### 2. 测试分支 (`test`) +- **定位**:长期实测与准生产验证分支(Staging / Pre-Release)。 +- **职责**:当 `dev` 分支积累了一定的业务功能或阶段里程碑,需要进行较长时间的真实环境部署、冒烟测试、压力测试、全链路联调以及运维验证时,将 `dev` 的对应阶段节点合并至 `test` 分支。 +- **节点打标**: + - 在 `test` 分支部署实测时,建议在该节点上打上候选版本 Tag(如 `rc-v1.1.0-beta.1`)。 + - 测试期间发现的缺陷,若属于该候选版本的严重阻断问题,可在 `test` 分支修复并验证,验证完毕后必须**同步回合(Cherry-pick 或 Merge)至 `dev` 分支**;非阻断问题统一在 `dev` 中继续排期推进。 + +### 3. 主分支 (`main`) +- **定位**:生产发布分支(Production / Release)。 +- **职责**:主分支的代码代表经过实际运维与测试检验、已达到生产可用标准的系统版本。 +- **发布准入标准**: + - 严禁任何未经 `test` 分支充分测试验证的代码直接提交或合入 `main`。 + - 必须由 `test` 分支上的验证通过节点,以合并的方式提交至 `main`。 +- **发布打标**: + - 每次合入 `main` 后,必须打上正式发布 Tag(语义化版本,如 `v1.0.0`, `v1.1.0`)。 +- **紧急热修复 (Hotfix)**: + - 遇到线上紧急故障且 `test` 分支已有新开发代码时,从 `main` 检出 `hotfix/` 分支。 + - 修复完成并在专门隔离环境测试后,先合回 `main` 打补丁 Tag(如 `v1.0.1`),同时合并回 `test` 和 `dev` 分支。 + +--- + +## 二、 任务拆分与渐进式提交规范 (Progressive Commits) + +为保证代码可追溯性、降低 Code Review 成本并利于排查回滚,**禁止将一个大任务的所有变更揉合成一个巨大的提交**。 + +### 1. 拆分原则 +一个完整的业务任务必须按功能层次、逻辑职责进行横向或纵向切分,并在开发过程中逐步提交: +1. **数据模型与存储层提交**:定义数据库 Schema、ORM 映射、迁移脚本或接口实体。 +2. **核心业务逻辑与 Agent 算法层提交**:实现核心业务处理、Agent 工具、会话逻辑。 +3. **API / 适配层提交**:暴露 HTTP/gRPC 端点、集成外部组件或中间件。 +4. **单元与集成测试提交**:补充对应模块的自动化测试用例。 +5. **文档与配置更新提交**:同步更新环境参数配置、README 或设计文档。 + +### 2. 提交信息规范 (Conventional Commits) +采用统一的 Git Commit 消息规范: +```text +(): + +[optional body] +``` +- **Type 类型**: + - `feat`: 新增功能(按功能拆分逐步提交) + - `fix`: 修复缺陷 + - `refactor`: 代码重构(无功能改变与 Bug 修复) + - `test`: 增加或修改测试用例 + - `docs`: 文档变动 + - `chore`: 构建工具、依赖库更新、脚手架配置等 + - `ci`: CI/CD 流程调整 +- **示例**: + - `feat(db): 增加会话与多租户数据库模型迁移脚本` + - `feat(agent): 实现知识库问答工具的多环境路由调用` + - `test(agent): 增加知识库共享与对话隔离测试用例` + - `chore(deploy): 配置 test 环境独立端口与 docker-compose` + +--- + +## 三、 三套环境独立运行架构规范 + +每个分支在部署时对应一套完整的启动服务。必须严格遵循 **“知识库共享,对话数据与数据库隔离”** 的核心原则。 + +``` + ┌──────────────────────────────────────────┐ + │ 共享基础设施: 知识库服务 │ + │ - pgvector / 向量检索 / 统一知识索引库 │ + │ - 共享数据卷: shared-kb-data │ + │ - 共享服务端口: 5432 (Internal) │ + └─────────────────────┬────────────────────┘ + │ (只读检索或统一管理通道) + ┌──────────────────────────────────┼──────────────────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ +│ 开发环境 (dev) │ │ 测试环境 (test) │ │ 主干环境 (main) │ +│ 容器组: agent-dev-* │ │ 容器组: agent-test-* │ │ 容器组: agent-main-* │ +├─────────────────────────┤ ├─────────────────────────┤ ├─────────────────────────┤ +│ • 专属数据库: │ │ • 专属数据库: │ │ • 专属数据库: │ +│ agent_dev (Port 5433) │ │ agent_test (Port 5434)│ │ agent_main (Port 5435)│ +│ • 专属会话与存储卷: │ │ • 专属会话与存储卷: │ │ • 专属会话与存储卷: │ +│ data/dev/workspace │ │ data/test/workspace │ │ data/main/workspace │ +│ data/dev/conversations│ │ data/test/conversations data/main/conversations│ +│ dev-system-pgdata │ │ test-system-pgdata │ │ main-system-pgdata │ +│ • 应用服务端口: │ │ • 应用服务端口: │ │ • 应用服务端口: │ +│ HTTP: 8080 │ │ HTTP: 8081 │ │ HTTP: 8000 (生产) │ +│ Agent-Runner: 18765 │ │ Agent-Runner: 18766 │ │ Agent-Runner: 18767 │ +│ • 独立日志/SQLite: │ │ • 独立日志/SQLite: │ │ • 独立日志/SQLite: │ +│ dev-aux-data │ │ test-aux-data │ │ main-aux-data │ +└─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ +``` + +### 1. 知识库共享规则 (Shared Knowledge Base) +- **共享内容**:法规条文、行业政策、静态向量索引、规章库、系统公共知识文档。 +- **访问控制**: + - 所有分支服务通过专用的 `POSTGRES_SHARED_KB_DSN` 连接同一个共享知识库容器(如 `shuimu-kb-shared`)。 + - 开发、测试与主分支服务在检索知识时,只读访问公共条目。 + - 知识库的结构升级或新增全量知识,统一由知识库迁移脚本维护,并提前通过版本兼容性测试。 + +### 2. 对话数据与业务数据库隔离规则 (Strict Data Isolation) +- **隔离内容**: + 1. **对话上下文与历史记录 (Chat History & Sessions)**:包括用户聊天记录、Agent 规划轨迹、思考日志等。 + 2. **业务数据库 (System DB)**:系统用户表、权限、配置状态、任务状态、审计表。 + 3. **外发信箱与日志 (Outbox & SQLite & Temp Logs)**。 + 4. **工作区目录 (Workspaces & Cache)**。 +- **隔离实现机制**: + - **Docker 容器名隔离**:通过 `COMPOSE_PROJECT_NAME` 前缀 (`agent-dev`, `agent-test`, `agent-main`),服务容器互不覆盖。 + - **网络与端口隔离**:每个环境占用独立的宿主机端口映射(详见下表),互不冲突,支持在同一台机器或多台机器并存启动。 + - **存储卷隔离**:Docker Named Volume 或宿主机本地目录均以环境后缀命名,严禁多环境挂载同一会话或 DB 目录。 + +### 3. 环境配置矩阵表 + +| 配置项 | 共享知识库 (Shared) | 开发环境 (Dev) | 测试环境 (Test) | 主分支生产环境 (Main) | +| :--- | :--- | :--- | :--- | :--- | +| **Compose 项目名** | `agent-infra` | `agent-dev` | `agent-test` | `agent-main` | +| **配置文件** | `configs/.env.shared` | `configs/.env.dev` | `configs/.env.test` | `configs/.env.main` | +| **系统 DB 名称** | `regulations` (KB) | `agent_system_dev` | `agent_system_test` | `agent_system_main` | +| **系统 DB 宿主端口** | `5432` | `5433` | `5434` | `5435` | +| **App 业务 HTTP 端口**| - | `8080` | `8081` | `8000` | +| **Agent Runner 端口** | - | `18765` | `18766` | `18767` | +| **持久化数据目录** | `data/shared/kb` | `data/dev/` | `data/test/` | `data/main/` | +| **系统 DB 数据卷** | `kb-shared-pgdata` | `dev-system-pgdata` | `test-system-pgdata` | `main-system-pgdata` | +| **审计/会话 SQLite** | - | `dev-aux-data` | `test-aux-data` | `main-aux-data` | + +--- + +## 四、 常用运维操作与脚本使用 + +项目在 `scripts/` 目录下提供了标准运维与管理脚本: + +### 1. 服务启停操作 +```bash +# 1. 启动共享知识库基础服务 (首次运行前必须启动) +./scripts/env-service.sh shared start + +# 2. 启动开发环境服务 +./scripts/env-service.sh dev start + +# 3. 启动测试环境服务 +./scripts/env-service.sh test start + +# 4. 启动主分支生产环境服务 +./scripts/env-service.sh main start + +# 5. 查看所有环境运行状态 +./scripts/env-service.sh all status + +# 6. 停止指定环境服务 (如停止 dev) +./scripts/env-service.sh dev stop +``` + +### 2. 分支流转标准流程示范 + +#### 流程 A:日常功能开发与逐步提交 +```bash +# 切换并同步开发分支 +git checkout dev +git pull origin dev + +# 若功能较独立,创建功能子分支 +git checkout -b feature/auth-multi-tenant + +# 功能拆分阶段 1:数据表与存储层 +git add internal/db/migrations/ +git commit -m "feat(db): 增加多租户隔离与字段迁移" + +# 功能拆分阶段 2:服务实现与路由 +git add internal/services/ +git commit -m "feat(auth): 实现多租户鉴权中间件与上下文传递" + +# 功能拆分阶段 3:测试用例 +git add internal/auth/auth_test.go +git commit -m "test(auth): 补充多租户鉴权单元与集成测试" + +# 自测通过后,合并回 dev +git checkout dev +git merge --no-ff feature/auth-multi-tenant -m "merge: 合并功能 feature/auth-multi-tenant 到开发分支" +git branch -d feature/auth-multi-tenant +``` + +#### 流程 B:功能阶段积累完成,进入测试分支实测 +```bash +# 切换到测试分支 +git checkout test +git pull origin test + +# 将 dev 分支当前稳定节点合并到 test +git merge --no-ff dev -m "release-candidate: 合并 dev 阶段功能至 test 分支进行长期实测" + +# 打上实测候选版本 Tag +git tag -a rc-v1.2.0-beta.1 -m "构建 1.2.0 测试候选版本 1,启动长期实测" + +# 启动或重启 test 环境服务进行运维实测 +./scripts/env-service.sh test restart +``` + +#### 流程 C:测试分支验证完成,发布到主分支 +```bash +# 切换到主分支 +git checkout main +git pull origin main + +# 将测试验证完毕的节点合并到 main +git merge --no-ff test -m "release: 经长期测试与运维验证,发布版本 1.2.0" + +# 打正式版本 Tag +git tag -a v1.2.0 -m "Release v1.2.0" + +# 部署/更新主分支生产服务 +./scripts/env-service.sh main restart +``` diff --git a/.doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md b/.doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md index e38457bc..4a62be6c 100644 --- a/.doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md +++ b/.doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md @@ -4,8 +4,8 @@ - **归档路径**: `.doc/test-reports/2026-09-08-dynamic-roles-and-doc-visibility-rbac-test-report.md` - **测试日期**: 2026-09-08 - **测试结果**: 全部通过 (PASS 100%) -- **关联设计规范**: `docs/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md` -- **关联实施计划**: `docs/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md` +- **关联设计规范**: `.doc/archive/design/superpowers/specs/2026-09-08-dynamic-roles-and-doc-visibility-rbac-design.md` +- **关联实施计划**: `.doc/archive/design/superpowers/plans/2026-09-08-dynamic-roles-and-doc-visibility-rbac.md` --- diff --git a/.doc/test-reports/2026-09-09-chat-wait-error-retry-ux-test-report.md b/.doc/test-reports/2026-09-09-chat-wait-error-retry-ux-test-report.md index 6557f460..b64bd012 100644 --- a/.doc/test-reports/2026-09-09-chat-wait-error-retry-ux-test-report.md +++ b/.doc/test-reports/2026-09-09-chat-wait-error-retry-ux-test-report.md @@ -142,7 +142,7 @@ $ curl -N -s -D - -X POST http://127.0.0.1:8080/api/v1/chat/stream \ **实际输出:** 收到完整 `phase`/`status`/`delta`/`done` 序列,**未出现 `event: error`**;`done.duration_ms=9`(毫秒级,非真实生成耗时),`delta` 内容是一段与"逆压电效应"无关的通用推进建议话术(V0.5 方案框架选项)。 -**根因排查:** 阅读 `internal/coordinator/dialogue_llm.go` 与 `docs/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md` 确认,这是**既有、独立的 Phase A 设计行为**(非本次 P1 引入的缺陷):`generateDialogueReply` 对 `CASUAL_CHAT`/`AMBIGUOUS_FALLBACK` 分支调用 pi-agent 失败时,按该设计文档第 26 行 "失败回退原模板,`ReplySource=template`" 的既定契约静默降级为规则模板,由 `internal/coordinator/engine.go:301/748` 处的 `ReplySourceTemplate` 兜底吸收,不会传播到 `sse.go` 的 `SendMessageStream` 错误返回路径,因此该场景**不产生** `error` 事件。这与 P1 设计"失败不得写入成功模板"的原则存在语义交叉,但适用范围不同:P1 该原则约束的是 `chat/stream` 层面的 transient/网络/超时错误(`ClassifyError`/`EmitError` 覆盖的路径,例如 `handleRunTaskStream`/`handleChatStream` 中 `sess.SendMessageStream` 返回非 nil error 时),而闲聊对话生成的模板兜底属于 2026-09-09 单独设计并验收通过的 Phase A 契约,两者不是同一交付边界,因此**不计为本次 P1 缺陷**,但记录为后续需澄清的边界(见第七节)。 +**根因排查:** 阅读 `internal/coordinator/dialogue_llm.go` 与 `.doc/archive/design/superpowers/specs/2026-09-09-dialogue-llm-casual-ambiguous-design.md` 确认,这是**既有、独立的 Phase A 设计行为**(非本次 P1 引入的缺陷):`generateDialogueReply` 对 `CASUAL_CHAT`/`AMBIGUOUS_FALLBACK` 分支调用 pi-agent 失败时,按该设计文档第 26 行 "失败回退原模板,`ReplySource=template`" 的既定契约静默降级为规则模板,由 `internal/coordinator/engine.go:301/748` 处的 `ReplySourceTemplate` 兜底吸收,不会传播到 `sse.go` 的 `SendMessageStream` 错误返回路径,因此该场景**不产生** `error` 事件。这与 P1 设计"失败不得写入成功模板"的原则存在语义交叉,但适用范围不同:P1 该原则约束的是 `chat/stream` 层面的 transient/网络/超时错误(`ClassifyError`/`EmitError` 覆盖的路径,例如 `handleRunTaskStream`/`handleChatStream` 中 `sess.SendMessageStream` 返回非 nil error 时),而闲聊对话生成的模板兜底属于 2026-09-09 单独设计并验收通过的 Phase A 契约,两者不是同一交付边界,因此**不计为本次 P1 缺陷**,但记录为后续需澄清的边界(见第七节)。 **尝试 2(文档要求的替代方案:死端口验证客户端网络失败分类):** diff --git a/.doc/test-reports/2026-09-13-container-env-configuration-test-report.md b/.doc/test-reports/2026-09-13-container-env-configuration-test-report.md new file mode 100644 index 00000000..a13d48c8 --- /dev/null +++ b/.doc/test-reports/2026-09-13-container-env-configuration-test-report.md @@ -0,0 +1,104 @@ +# 容器构建与环境变量配置链测试报告 + +## 一、 测试背景 (Background) + +审计根 `.env`、环境差异文件、四套 Compose、Dockerfile、启动脚本和应用配置加载器是否形成一致的配置链。 + +## 二、 测试目标 (Test Objectives) + +- 所有根配置键都有实际消费点,无已移除字段残留。 +- 四套 Compose 可解析,app/runner 模型与 provider 一致,必要密钥非空。 +- app 与 pi-agent 镜像能够真实构建,构建上下文不包含运行数据。 +- Go short 全量回归通过;运行中的容器状态有真实记录。 + +## 三、 测试方案与环境 (Test Plan & Environment) + +- OS: Linux;Docker Compose v5.5.1;Go 仓库当前 toolchain。 +- 层级:静态键覆盖、Compose 渲染、Docker 多阶段实构建、Go short 回归、容器健康与 HTTP ready。 +- 敏感字段只判定存在/非空,不记录值。 + +## 四、 预期结果 (Expected Results) + +| 用例 | 预期 | +|------|------| +| env 键覆盖 | 无未消费与重复键,无已废弃字段 | +| Compose | shared/dev/test/main 均可解析;缺必填密码时 fail-fast | +| Docker build | app/pi-agent 成功,`.regulations` 不进入上下文 | +| Go short | 全部 package PASS | +| runtime | shared/dev/test/main 全健康,数据库新密码可通过独立 TCP/SCRAM 登录 | + +## 五、 实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 配置渲染与键覆盖 + +**Input**: 四套 `docker compose ... config -q`;`rg` + `awk` 键集合审计。 + +**Actual Output**: + +```text +shared compose config ok with required KB placeholder +dev compose config ok with required KB placeholder +test compose config ok with required KB placeholder +main compose config ok with required KB placeholder +env key coverage and stale-key validation ok +``` + +移除临时验证值后,四套 Compose 均按预期拒绝空 `KB_DB_PASSWORD`。 + +**Verdict**: PASS(fail-fast 生效) + +### 5.2 Docker 实构建 + +**Input**: dev/test/main 的 `docker compose build app pi-agent`。 + +**Actual Output**: + +```text +Image agent-dev-app Built +Image shuimu-pi-agent:dev Built +Image agent-test-app Built +Image shuimu-pi-agent:test Built +Image agent-main-app Built +Image shuimu-pi-agent:main Built +app build context: 12.70MB +``` + +首次发现 `.regulations` 未忽略时,context 已传 17.10GB,立即中止;修复 `.dockerignore` 后为 12.70MB。 + +**Verdict**: PASS + +### 5.3 运行状态与 ready + +**Actual Output**: + +```text +shuimu-kb-shared healthy +shuimu-agent-app-dev healthy +shuimu-pi-agent-dev healthy +shuimu-agent-app-test healthy +shuimu-pi-agent-test healthy +shuimu-pi-agent-main healthy +shuimu-agent-app-main healthy +http://127.0.0.1:8080/api/v1/ready PASS +http://127.0.0.1:8081/api/v1/ready PASS +http://127.0.0.1:8000/api/v1/ready PASS +``` + +用户补值后,对 `shuimu-kb-shared` 与 `shuimu-system-pg-main` 执行 PostgreSQL 用户密码轮换;再从两个独立临时客户端通过 TCP/SCRAM 登录并执行 `SELECT 1`,均成功。三个 app 的 health 均返回 `database_ready=true`、`task_store_ready=true`、`schema_version=25`。 + +**Verdict**: PASS + +## 六、 自动化测试套件汇总 (Test Suite Execution) + +```text +go test -short ./... -> PASS(全部 package ok,internal/server 7.086s) +go test ./internal/config/... -> PASS +bash -n scripts/env-service.sh -> PASS +git diff --check -> PASS +``` + +## 七、 测试结论与后续优化建议 (Conclusion & Next Steps) + +- 配置链、镜像构建、数据库密码轮换与 shared/dev/test/main 运行验收通过。 +- 共享 KB 密码已生效但低于建议的 16 字符,建议后续维护窗口再次轮换为更长随机值。 +- 本报告未以 stub 结果冒充真实 Agent 验收;test/main 配置已切至 `pi-agent`,但未执行长任务真实模型 E2E。 diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/adhoc_task_reply.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/adhoc_task_reply.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/adhoc_task_reply.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/adhoc_task_reply.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/dialogue_first_answer.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/dialogue_first_answer.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/dialogue_first_answer.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/dialogue_first_answer.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/blackboard.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/blackboard.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/blackboard.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/blackboard.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/gov_audit.jsonl b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/gov_audit.jsonl similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/gov_audit.jsonl rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/gov_audit.jsonl diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/ledger.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/ledger.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/ledger.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/ledger.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/01_organize/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/02_engineer/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/03_draft/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/04_review/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/dynamic_rf_emc/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_1/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/tasks/repair_2/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/trace.jsonl b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/trace.jsonl similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/trace.jsonl rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/trace.jsonl diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workflow.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workflow.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workflow.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workflow.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workspace.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workspace.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workspace.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/01-router-upgrade/workspace/workspace.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/task_summary.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/task_summary.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/task_summary.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/task_summary.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/blackboard.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/blackboard.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/blackboard.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/blackboard.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/gov_audit.jsonl b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/gov_audit.jsonl similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/gov_audit.jsonl rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/gov_audit.jsonl diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/ledger.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/ledger.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/ledger.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/ledger.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/01_search/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/02_market/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/03_regulatory/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/04_plan/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/05_review_plan/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/06_draft/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/TASK.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/TASK.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/TASK.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/TASK.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/output.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/output.md similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/output.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/output.md diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/step_manifest.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/step_manifest.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/step_manifest.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/tasks/07_review/step_manifest.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/trace.jsonl b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/trace.jsonl similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/trace.jsonl rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/trace.jsonl diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workflow.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workflow.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workflow.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workflow.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workspace.json b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workspace.json similarity index 100% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workspace.json rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/02-standard-research/workspace/workspace.json diff --git a/.doc/test-reports/2026-09-09-longtask-governance-quality/REPORT.md b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/REPORT.md similarity index 95% rename from .doc/test-reports/2026-09-09-longtask-governance-quality/REPORT.md rename to .doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/REPORT.md index dee3a1ac..cb4556fb 100644 --- a/.doc/test-reports/2026-09-09-longtask-governance-quality/REPORT.md +++ b/.doc/test-reports/assets/longtask-governance-quality/2026-09-09-longtask-governance-quality/REPORT.md @@ -2,7 +2,7 @@ - **执行时间**: 2026-09-10 00:42:20 - **后端**: pi-agent (MiniMax-M3, 真实执行) -- **设计规范**: docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md +- **设计规范**: .doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md ## 场景 A:路由升级全链路(同题对比) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..de58fcb5 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,10 @@ +# docs/ 索引(遗留路径) + +本目录仅保留 **stub 跳转**。项目文档 SSOT 在 [`.doc/`](../.doc/README.md)。 + +| 原路径 | 现位置 | +|--------|--------| +| `superpowers/` | [`.doc/archive/design/superpowers/`](../.doc/archive/design/superpowers/) | +| `workflow/` | [PROJECT.md](../PROJECT.md) §4(SSOT) | + +**禁止**在此目录新建项目/Agent 文档。 diff --git a/docs/superpowers/README.md b/docs/superpowers/README.md new file mode 100644 index 00000000..10e903b5 --- /dev/null +++ b/docs/superpowers/README.md @@ -0,0 +1,7 @@ +# 已迁移 + +历史功能设计 spec/plan 已迁至 [`.doc/archive/design/superpowers/`](../../.doc/archive/design/superpowers/)。 + +索引:[INDEX.md](../../.doc/archive/design/superpowers/INDEX.md) + +请勿在此目录新建文档。新设计见 `.doc/system-design/` 或 `.doc/remediation/`。 diff --git a/docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md b/docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md index 1bca88e0..8d1ead80 100644 --- a/docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md +++ b/docs/workflow/BRANCH_AND_ENVIRONMENT_RULES.md @@ -1,250 +1,5 @@ -# 研发分支与多套独立环境运行规范 (Branch & Environment Rules) +# 已迁移 -本规范为本系统代码仓库的强制性规范,涵盖 **Git 3 分支流转模型**、**任务功能拆分与渐进式提交**、**三套环境独立运行(知识库共享 + 对话与数据库隔离)** 以及 **运维操作指引**。 +分支与环境规范 SSOT 见 [PROJECT.md](../../PROJECT.md) §4 与 [.cursor/rules/git-workflow-and-environments.mdc](../../.cursor/rules/git-workflow-and-environments.mdc)。 ---- - -## 一、 Git 固定三分支体系与流转规范 - -本仓库严格固定维护 **3 个常驻分支**: - -``` - (Feature/Fix 子分支) - ┌─────────────┐ - │ feature/*** │ - └──────┬──────┘ - (创建/自测) │ (合回) - ▼ ▼ -┌─────────────────────────────────┐ -│ 开发分支: dev │ <-- 所有日常开发在此进行,功能逐步提交 -└────────────────┬────────────────┘ - │ (积累一定阶段功能,准备长期部署实测) - ▼ -┌─────────────────────────────────┐ -│ 测试分支: test │ <-- 部署到测试环境,进行真实环境长期运维与测试 -└────────────────┬────────────────┘ - │ (测试分支经过实际运维和测试验证,达到发布标准) - ▼ -┌─────────────────────────────────┐ -│ 主分支: main (Release) │ <-- 生产发布基线,对应线上生产环境 -└─────────────────────────────────┘ -``` - -### 1. 开发分支 (`dev`) -- **定位**:日常开发核心集成分支。 -- **职责**:所有新功能(Features)、常规缺陷修复(Bugfixes)、日常重构均在 `dev` 分支推进。 -- **子分支策略**: - - **简单任务**:可直接在 `dev` 分支上按功能拆分进行渐进式提交。 - - **中大型或独立功能**:必须从 `dev` 检出子分支,命名格式为: - - `feature/<功能简述>` (如 `feature/session-isolation`) - - `fix/<缺陷简述>` (如 `fix/llm-streaming-timeout`) - - **合回机制**:子分支在开发者本地或容器中完成自测、通过单元测试和代码审查后,合并回 `dev` 分支(推荐保留提交历史或使用半快进合并)。合并完成后应及时删除临时子分支。 - -### 2. 测试分支 (`test`) -- **定位**:长期实测与准生产验证分支(Staging / Pre-Release)。 -- **职责**:当 `dev` 分支积累了一定的业务功能或阶段里程碑,需要进行较长时间的真实环境部署、冒烟测试、压力测试、全链路联调以及运维验证时,将 `dev` 的对应阶段节点合并至 `test` 分支。 -- **节点打标**: - - 在 `test` 分支部署实测时,建议在该节点上打上候选版本 Tag(如 `rc-v1.1.0-beta.1`)。 - - 测试期间发现的缺陷,若属于该候选版本的严重阻断问题,可在 `test` 分支修复并验证,验证完毕后必须**同步回合(Cherry-pick 或 Merge)至 `dev` 分支**;非阻断问题统一在 `dev` 中继续排期推进。 - -### 3. 主分支 (`main`) -- **定位**:生产发布分支(Production / Release)。 -- **职责**:主分支的代码代表经过实际运维与测试检验、已达到生产可用标准的系统版本。 -- **发布准入标准**: - - 严禁任何未经 `test` 分支充分测试验证的代码直接提交或合入 `main`。 - - 必须由 `test` 分支上的验证通过节点,以合并的方式提交至 `main`。 -- **发布打标**: - - 每次合入 `main` 后,必须打上正式发布 Tag(语义化版本,如 `v1.0.0`, `v1.1.0`)。 -- **紧急热修复 (Hotfix)**: - - 遇到线上紧急故障且 `test` 分支已有新开发代码时,从 `main` 检出 `hotfix/` 分支。 - - 修复完成并在专门隔离环境测试后,先合回 `main` 打补丁 Tag(如 `v1.0.1`),同时合并回 `test` 和 `dev` 分支。 - ---- - -## 二、 任务拆分与渐进式提交规范 (Progressive Commits) - -为保证代码可追溯性、降低 Code Review 成本并利于排查回滚,**禁止将一个大任务的所有变更揉合成一个巨大的提交**。 - -### 1. 拆分原则 -一个完整的业务任务必须按功能层次、逻辑职责进行横向或纵向切分,并在开发过程中逐步提交: -1. **数据模型与存储层提交**:定义数据库 Schema、ORM 映射、迁移脚本或接口实体。 -2. **核心业务逻辑与 Agent 算法层提交**:实现核心业务处理、Agent 工具、会话逻辑。 -3. **API / 适配层提交**:暴露 HTTP/gRPC 端点、集成外部组件或中间件。 -4. **单元与集成测试提交**:补充对应模块的自动化测试用例。 -5. **文档与配置更新提交**:同步更新环境参数配置、README 或设计文档。 - -### 2. 提交信息规范 (Conventional Commits) -采用统一的 Git Commit 消息规范: -```text -(): - -[optional body] -``` -- **Type 类型**: - - `feat`: 新增功能(按功能拆分逐步提交) - - `fix`: 修复缺陷 - - `refactor`: 代码重构(无功能改变与 Bug 修复) - - `test`: 增加或修改测试用例 - - `docs`: 文档变动 - - `chore`: 构建工具、依赖库更新、脚手架配置等 - - `ci`: CI/CD 流程调整 -- **示例**: - - `feat(db): 增加会话与多租户数据库模型迁移脚本` - - `feat(agent): 实现知识库问答工具的多环境路由调用` - - `test(agent): 增加知识库共享与对话隔离测试用例` - - `chore(deploy): 配置 test 环境独立端口与 docker-compose` - ---- - -## 三、 三套环境独立运行架构规范 - -每个分支在部署时对应一套完整的启动服务。必须严格遵循 **“知识库共享,对话数据与数据库隔离”** 的核心原则。 - -``` - ┌──────────────────────────────────────────┐ - │ 共享基础设施: 知识库服务 │ - │ - pgvector / 向量检索 / 统一知识索引库 │ - │ - 共享数据卷: shared-kb-data │ - │ - 共享服务端口: 5432 (Internal) │ - └─────────────────────┬────────────────────┘ - │ (只读检索或统一管理通道) - ┌──────────────────────────────────┼──────────────────────────────────┐ - │ │ │ - ▼ ▼ ▼ -┌─────────────────────────┐ ┌─────────────────────────┐ ┌─────────────────────────┐ -│ 开发环境 (dev) │ │ 测试环境 (test) │ │ 主干环境 (main) │ -│ 容器组: agent-dev-* │ │ 容器组: agent-test-* │ │ 容器组: agent-main-* │ -├─────────────────────────┤ ├─────────────────────────┤ ├─────────────────────────┤ -│ • 专属数据库: │ │ • 专属数据库: │ │ • 专属数据库: │ -│ agent_dev (Port 5433) │ │ agent_test (Port 5434)│ │ agent_main (Port 5435)│ -│ • 专属会话与存储卷: │ │ • 专属会话与存储卷: │ │ • 专属会话与存储卷: │ -│ data/dev/workspace │ │ data/test/workspace │ │ data/main/workspace │ -│ data/dev/conversations│ │ data/test/conversations data/main/conversations│ -│ dev-system-pgdata │ │ test-system-pgdata │ │ main-system-pgdata │ -│ • 应用服务端口: │ │ • 应用服务端口: │ │ • 应用服务端口: │ -│ HTTP: 8080 │ │ HTTP: 8081 │ │ HTTP: 8000 (生产) │ -│ Agent-Runner: 18765 │ │ Agent-Runner: 18766 │ │ Agent-Runner: 18767 │ -│ • 独立日志/SQLite: │ │ • 独立日志/SQLite: │ │ • 独立日志/SQLite: │ -│ dev-aux-data │ │ test-aux-data │ │ main-aux-data │ -└─────────────────────────┘ └─────────────────────────┘ └─────────────────────────┘ -``` - -### 1. 知识库共享规则 (Shared Knowledge Base) -- **共享内容**:法规条文、行业政策、静态向量索引、规章库、系统公共知识文档。 -- **访问控制**: - - 所有分支服务通过专用的 `POSTGRES_SHARED_KB_DSN` 连接同一个共享知识库容器(如 `shuimu-kb-shared`)。 - - 开发、测试与主分支服务在检索知识时,只读访问公共条目。 - - 知识库的结构升级或新增全量知识,统一由知识库迁移脚本维护,并提前通过版本兼容性测试。 - -### 2. 对话数据与业务数据库隔离规则 (Strict Data Isolation) -- **隔离内容**: - 1. **对话上下文与历史记录 (Chat History & Sessions)**:包括用户聊天记录、Agent 规划轨迹、思考日志等。 - 2. **业务数据库 (System DB)**:系统用户表、权限、配置状态、任务状态、审计表。 - 3. **外发信箱与日志 (Outbox & SQLite & Temp Logs)**。 - 4. **工作区目录 (Workspaces & Cache)**。 -- **隔离实现机制**: - - **Docker 容器名隔离**:通过 `COMPOSE_PROJECT_NAME` 前缀 (`agent-dev`, `agent-test`, `agent-main`),服务容器互不覆盖。 - - **网络与端口隔离**:每个环境占用独立的宿主机端口映射(详见下表),互不冲突,支持在同一台机器或多台机器并存启动。 - - **存储卷隔离**:Docker Named Volume 或宿主机本地目录均以环境后缀命名,严禁多环境挂载同一会话或 DB 目录。 - -### 3. 环境配置矩阵表 - -| 配置项 | 共享知识库 (Shared) | 开发环境 (Dev) | 测试环境 (Test) | 主分支生产环境 (Main) | -| :--- | :--- | :--- | :--- | :--- | -| **Compose 项目名** | `agent-infra` | `agent-dev` | `agent-test` | `agent-main` | -| **配置文件** | `configs/.env.shared` | `configs/.env.dev` | `configs/.env.test` | `configs/.env.main` | -| **系统 DB 名称** | `regulations` (KB) | `agent_system_dev` | `agent_system_test` | `agent_system_main` | -| **系统 DB 宿主端口** | `5432` | `5433` | `5434` | `5435` | -| **App 业务 HTTP 端口**| - | `8080` | `8081` | `8000` | -| **Agent Runner 端口** | - | `18765` | `18766` | `18767` | -| **持久化数据目录** | `data/shared/kb` | `data/dev/` | `data/test/` | `data/main/` | -| **系统 DB 数据卷** | `kb-shared-pgdata` | `dev-system-pgdata` | `test-system-pgdata` | `main-system-pgdata` | -| **审计/会话 SQLite** | - | `dev-aux-data` | `test-aux-data` | `main-aux-data` | - ---- - -## 四、 常用运维操作与脚本使用 - -项目在 `scripts/` 目录下提供了标准运维与管理脚本: - -### 1. 服务启停操作 -```bash -# 1. 启动共享知识库基础服务 (首次运行前必须启动) -./scripts/env-service.sh shared start - -# 2. 启动开发环境服务 -./scripts/env-service.sh dev start - -# 3. 启动测试环境服务 -./scripts/env-service.sh test start - -# 4. 启动主分支生产环境服务 -./scripts/env-service.sh main start - -# 5. 查看所有环境运行状态 -./scripts/env-service.sh all status - -# 6. 停止指定环境服务 (如停止 dev) -./scripts/env-service.sh dev stop -``` - -### 2. 分支流转标准流程示范 - -#### 流程 A:日常功能开发与逐步提交 -```bash -# 切换并同步开发分支 -git checkout dev -git pull origin dev - -# 若功能较独立,创建功能子分支 -git checkout -b feature/auth-multi-tenant - -# 功能拆分阶段 1:数据表与存储层 -git add internal/db/migrations/ -git commit -m "feat(db): 增加多租户隔离与字段迁移" - -# 功能拆分阶段 2:服务实现与路由 -git add internal/services/ -git commit -m "feat(auth): 实现多租户鉴权中间件与上下文传递" - -# 功能拆分阶段 3:测试用例 -git add internal/auth/auth_test.go -git commit -m "test(auth): 补充多租户鉴权单元与集成测试" - -# 自测通过后,合并回 dev -git checkout dev -git merge --no-ff feature/auth-multi-tenant -m "merge: 合并功能 feature/auth-multi-tenant 到开发分支" -git branch -d feature/auth-multi-tenant -``` - -#### 流程 B:功能阶段积累完成,进入测试分支实测 -```bash -# 切换到测试分支 -git checkout test -git pull origin test - -# 将 dev 分支当前稳定节点合并到 test -git merge --no-ff dev -m "release-candidate: 合并 dev 阶段功能至 test 分支进行长期实测" - -# 打上实测候选版本 Tag -git tag -a rc-v1.2.0-beta.1 -m "构建 1.2.0 测试候选版本 1,启动长期实测" - -# 启动或重启 test 环境服务进行运维实测 -./scripts/env-service.sh test restart -``` - -#### 流程 C:测试分支验证完成,发布到主分支 -```bash -# 切换到主分支 -git checkout main -git pull origin main - -# 将测试验证完毕的节点合并到 main -git merge --no-ff test -m "release: 经长期测试与运维验证,发布版本 1.2.0" - -# 打正式版本 Tag -git tag -a v1.2.0 -m "Release v1.2.0" - -# 部署/更新主分支生产服务 -./scripts/env-service.sh main restart -``` +历史长文归档:[branch-and-environment-rules.md](../../.doc/archive/reference/branch-and-environment-rules.md) diff --git a/internal/chat/longtask_quality_e2e_test.go b/internal/chat/longtask_quality_e2e_test.go index 8df3950b..8f02ab2c 100644 --- a/internal/chat/longtask_quality_e2e_test.go +++ b/internal/chat/longtask_quality_e2e_test.go @@ -221,7 +221,7 @@ func TestLongTaskGovernance_QualityE2E(t *testing.T) { - **执行时间**: %s - **后端**: pi-agent (MiniMax-M3, 真实执行) -- **设计规范**: docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md +- **设计规范**: .doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md ## 场景 A:路由升级全链路(同题对比) diff --git a/internal/squad/gov.go b/internal/squad/gov.go index f3ef71e8..28efe723 100644 --- a/internal/squad/gov.go +++ b/internal/squad/gov.go @@ -2,7 +2,7 @@ package squad // ============================================================================ // 长任务运行时治理内核 (TaskGov) -// 设计规范: docs/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md +// 设计规范: .doc/archive/design/superpowers/specs/2026-09-09-longtask-governance-router-and-adhoc-design.md // 覆盖: StepFSM 状态机 / BudgetLedger 预算账本 / Trace 执行轨迹 / // LoopDetector 重复识别 / StepManifest 归档锁定 // ============================================================================ From 81743dcb75443250eb04715f382eb09d339aa15e Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 02:36:23 +0000 Subject: [PATCH 4/5] docs(ops): remove .doc root stubs and archive completed research Delete 15 redirect stubs now that canonical paths exist under audit/ and remediation/. Move completed ops/research to archive, fix internal links, and remove untracked duplicate test-report workspace artifacts. Co-authored-by: Cursor --- ...-09-11-production-ready-workflow-governance-plan.md | 3 --- ...9-11-system-functional-gap-audit-and-remediation.md | 3 --- .doc/2026-09-12-AUDIT-INDEX.md | 3 --- .doc/2026-09-12-audit-summary-report.md | 3 --- ...6-09-12-comprehensive-audit-and-remediation-plan.md | 3 --- ...ons-settings-three-workflows-implementation-plan.md | 3 --- .doc/2026-09-12-phase0-api-authz-matrix.md | 3 --- .../2026-09-12-phase1-iam-authz-implementation-plan.md | 3 --- ...-12-phase2-workflow-designer-implementation-plan.md | 3 --- .doc/2026-09-12-quick-reference-guide.md | 3 --- .doc/2026-09-12-remediation-gap-matrix.md | 3 --- ...09-12-remediation-tasks-and-acceptance-checklist.md | 3 --- ...12-three-workflows-strict-governance-remediation.md | 3 --- .doc/archive/README.md | 1 + .../ops/2026-09-13-codex-audit-p0-remediation.md | 2 +- .../ops/research/2026-09-12-codex-reaudit-summary.md | 0 .../2026-09-13-container-env-configuration-audit.md | 0 .../ops/research/2026-09-13-doc-inventory.md | 0 .doc/audit/2026-09-12-audit-summary-report.md | 8 ++++---- .doc/audit/INDEX.md | 4 ++-- .doc/audit/authorization-baseline-2026-09-12.md | 2 +- .doc/authorization-baseline-2026-09-12.md | 3 --- .doc/authorization-matrix-v2.md | 3 --- .doc/ops/research/README.md | 5 +++++ ...6-09-12-comprehensive-audit-and-remediation-plan.md | 10 +++++----- ...-12-phase2-workflow-designer-implementation-plan.md | 2 +- .doc/remediation/2026-09-12-quick-reference-guide.md | 2 +- ...09-12-remediation-tasks-and-acceptance-checklist.md | 2 +- ...ree-workflows-governance-remediation-test-report.md | 2 +- 29 files changed, 23 insertions(+), 62 deletions(-) delete mode 100644 .doc/2026-09-11-production-ready-workflow-governance-plan.md delete mode 100644 .doc/2026-09-11-system-functional-gap-audit-and-remediation.md delete mode 100644 .doc/2026-09-12-AUDIT-INDEX.md delete mode 100644 .doc/2026-09-12-audit-summary-report.md delete mode 100644 .doc/2026-09-12-comprehensive-audit-and-remediation-plan.md delete mode 100644 .doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md delete mode 100644 .doc/2026-09-12-phase0-api-authz-matrix.md delete mode 100644 .doc/2026-09-12-phase1-iam-authz-implementation-plan.md delete mode 100644 .doc/2026-09-12-phase2-workflow-designer-implementation-plan.md delete mode 100644 .doc/2026-09-12-quick-reference-guide.md delete mode 100644 .doc/2026-09-12-remediation-gap-matrix.md delete mode 100644 .doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md delete mode 100644 .doc/2026-09-12-three-workflows-strict-governance-remediation.md rename .doc/{ => archive}/ops/research/2026-09-12-codex-reaudit-summary.md (100%) rename .doc/{ => archive}/ops/research/2026-09-13-container-env-configuration-audit.md (100%) rename .doc/{ => archive}/ops/research/2026-09-13-doc-inventory.md (100%) delete mode 100644 .doc/authorization-baseline-2026-09-12.md delete mode 100644 .doc/authorization-matrix-v2.md create mode 100644 .doc/ops/research/README.md diff --git a/.doc/2026-09-11-production-ready-workflow-governance-plan.md b/.doc/2026-09-11-production-ready-workflow-governance-plan.md deleted file mode 100644 index e536f685..00000000 --- a/.doc/2026-09-11-production-ready-workflow-governance-plan.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-11-production-ready-workflow-governance-plan.md](remediation/2026-09-11-production-ready-workflow-governance-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md b/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md deleted file mode 100644 index 36df7e69..00000000 --- a/.doc/2026-09-11-system-functional-gap-audit-and-remediation.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [audit/2026-09-11-system-functional-gap-audit-and-remediation.md](audit/2026-09-11-system-functional-gap-audit-and-remediation.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-AUDIT-INDEX.md b/.doc/2026-09-12-AUDIT-INDEX.md deleted file mode 100644 index 43f92920..00000000 --- a/.doc/2026-09-12-AUDIT-INDEX.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [audit/INDEX.md](audit/INDEX.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-audit-summary-report.md b/.doc/2026-09-12-audit-summary-report.md deleted file mode 100644 index 4468d8ce..00000000 --- a/.doc/2026-09-12-audit-summary-report.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [audit/2026-09-12-audit-summary-report.md](audit/2026-09-12-audit-summary-report.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md b/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md deleted file mode 100644 index 777ff2d9..00000000 --- a/.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md](remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md b/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md deleted file mode 100644 index aeb7f59c..00000000 --- a/.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md](remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-phase0-api-authz-matrix.md b/.doc/2026-09-12-phase0-api-authz-matrix.md deleted file mode 100644 index ad6d7dca..00000000 --- a/.doc/2026-09-12-phase0-api-authz-matrix.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [audit/2026-09-12-phase0-api-authz-matrix.md](audit/2026-09-12-phase0-api-authz-matrix.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md b/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md deleted file mode 100644 index 812d69e5..00000000 --- a/.doc/2026-09-12-phase1-iam-authz-implementation-plan.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-phase1-iam-authz-implementation-plan.md](remediation/2026-09-12-phase1-iam-authz-implementation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md b/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md deleted file mode 100644 index b8e74849..00000000 --- a/.doc/2026-09-12-phase2-workflow-designer-implementation-plan.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md](remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-quick-reference-guide.md b/.doc/2026-09-12-quick-reference-guide.md deleted file mode 100644 index b2a56520..00000000 --- a/.doc/2026-09-12-quick-reference-guide.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-quick-reference-guide.md](remediation/2026-09-12-quick-reference-guide.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-remediation-gap-matrix.md b/.doc/2026-09-12-remediation-gap-matrix.md deleted file mode 100644 index ab8d59df..00000000 --- a/.doc/2026-09-12-remediation-gap-matrix.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/gap-matrix.md](remediation/gap-matrix.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md b/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md deleted file mode 100644 index 804b3db4..00000000 --- a/.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md](remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md)。请勿在此编辑。 diff --git a/.doc/2026-09-12-three-workflows-strict-governance-remediation.md b/.doc/2026-09-12-three-workflows-strict-governance-remediation.md deleted file mode 100644 index 33871a97..00000000 --- a/.doc/2026-09-12-three-workflows-strict-governance-remediation.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [remediation/2026-09-12-three-workflows-strict-governance-remediation.md](remediation/2026-09-12-three-workflows-strict-governance-remediation.md)。请勿在此编辑。 diff --git a/.doc/archive/README.md b/.doc/archive/README.md index c897ebe6..4a812670 100644 --- a/.doc/archive/README.md +++ b/.doc/archive/README.md @@ -7,5 +7,6 @@ | `audit/` | 已关闭审计大包 | | `remediation/` | 已关闭整改大包 | | `ops/` | done 的 short-term / checklist / handoff | +| `ops/research/` | 已关闭调研(自 ops/research 迁入) | | `design/superpowers/` | 历史功能 spec/plan | | `reference/` | 被 PROJECT 替代的参考长文 | diff --git a/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md b/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md index a2bb4d8b..4332f153 100644 --- a/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md +++ b/.doc/archive/ops/2026-09-13-codex-audit-p0-remediation.md @@ -41,4 +41,4 @@ owner: agent ## 相关链接 - 调研: [research/2026-09-12-codex-reaudit-summary.md](../research/2026-09-12-codex-reaudit-summary.md) -- Gap matrix: [../../2026-09-12-remediation-gap-matrix.md](../../2026-09-12-remediation-gap-matrix.md) +- Gap matrix: [../../remediation/gap-matrix.md](../../remediation/gap-matrix.md) diff --git a/.doc/ops/research/2026-09-12-codex-reaudit-summary.md b/.doc/archive/ops/research/2026-09-12-codex-reaudit-summary.md similarity index 100% rename from .doc/ops/research/2026-09-12-codex-reaudit-summary.md rename to .doc/archive/ops/research/2026-09-12-codex-reaudit-summary.md diff --git a/.doc/ops/research/2026-09-13-container-env-configuration-audit.md b/.doc/archive/ops/research/2026-09-13-container-env-configuration-audit.md similarity index 100% rename from .doc/ops/research/2026-09-13-container-env-configuration-audit.md rename to .doc/archive/ops/research/2026-09-13-container-env-configuration-audit.md diff --git a/.doc/ops/research/2026-09-13-doc-inventory.md b/.doc/archive/ops/research/2026-09-13-doc-inventory.md similarity index 100% rename from .doc/ops/research/2026-09-13-doc-inventory.md rename to .doc/archive/ops/research/2026-09-13-doc-inventory.md diff --git a/.doc/audit/2026-09-12-audit-summary-report.md b/.doc/audit/2026-09-12-audit-summary-report.md index 82de47d1..b7221353 100644 --- a/.doc/audit/2026-09-12-audit-summary-report.md +++ b/.doc/audit/2026-09-12-audit-summary-report.md @@ -1,6 +1,6 @@ # 项目全面审计总结报告 -> **SUPERSEDED** — 历史初审快照。Live 状态见 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/CURRENT.md](./ops/CURRENT.md)。 +> **SUPERSEDED** — 历史初审快照。Live 状态见 [gap-matrix.md](../remediation/gap-matrix.md) 与 [CURRENT.md](../ops/CURRENT.md)。 **审计日期**: 2026-09-12 **审计人**: 代码审计 @@ -316,7 +316,7 @@ Phase C (完善) : 20h ## 十、验收标准清单 -### 10.1 功能验收(来自 `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459`) +### 10.1 功能验收(来自 `.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md:417-459`) **7.1 目录和定义** - [ ] 任意用户在项目选择页都只能看到 3 个工作流 ✅ (已实施) @@ -432,8 +432,8 @@ Day 4-5: **下一步**: 技术评审确认整改计划,进入实施阶段 **相关文档**: -- `.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md` - 详细缺陷说明与整改方案 -- `.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md` - 可执行的任务拆分 +- `.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md` - 详细缺陷说明与整改方案 +- `.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md` - 可执行的任务拆分 --- diff --git a/.doc/audit/INDEX.md b/.doc/audit/INDEX.md index e604f56b..103cf6cf 100644 --- a/.doc/audit/INDEX.md +++ b/.doc/audit/INDEX.md @@ -15,8 +15,8 @@ ### 0️⃣ 当前状态(Live SSOT) -**文件**: `2026-09-12-remediation-gap-matrix.md` -**协作**: `.doc/ops/CURRENT.md` · `AGENTS.md` · `PROJECT.md` +**文件**: [gap-matrix.md](../remediation/gap-matrix.md) +**协作**: [CURRENT.md](../ops/CURRENT.md) · [AGENTS.md](../../AGENTS.md) · [PROJECT.md](../../PROJECT.md) **用途**: 发布缺口、Codex 再审计闭环证据、发布门禁勾选 --- diff --git a/.doc/audit/authorization-baseline-2026-09-12.md b/.doc/audit/authorization-baseline-2026-09-12.md index 0ed74bb3..cce1f331 100644 --- a/.doc/audit/authorization-baseline-2026-09-12.md +++ b/.doc/audit/authorization-baseline-2026-09-12.md @@ -3,7 +3,7 @@ - **分支**:`dev` - **Commit SHA**:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3` - **Goose schema**:`00020`(`00020_2026-09-12-task-run-worker-lease.sql`) -- **规格文档**:`.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md` +- **规格文档**:`.doc/remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md` ## 环境矩阵 diff --git a/.doc/authorization-baseline-2026-09-12.md b/.doc/authorization-baseline-2026-09-12.md deleted file mode 100644 index 1a203a38..00000000 --- a/.doc/authorization-baseline-2026-09-12.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [audit/authorization-baseline-2026-09-12.md](audit/authorization-baseline-2026-09-12.md)。请勿在此编辑。 diff --git a/.doc/authorization-matrix-v2.md b/.doc/authorization-matrix-v2.md deleted file mode 100644 index 1e3c9dd2..00000000 --- a/.doc/authorization-matrix-v2.md +++ /dev/null @@ -1,3 +0,0 @@ -# 已迁移 - -本文档已迁至 [audit/authorization-matrix-v2.md](audit/authorization-matrix-v2.md)。请勿在此编辑。 diff --git a/.doc/ops/research/README.md b/.doc/ops/research/README.md new file mode 100644 index 00000000..9bd505e7 --- /dev/null +++ b/.doc/ops/research/README.md @@ -0,0 +1,5 @@ +# 调研笔记(活) + +进行中的只读调查放此目录。完成后迁入 [../archive/ops/research/](../archive/ops/research/)。 + +模板:[../templates/research-note.md](../templates/research-note.md) diff --git a/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md b/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md index 34b343c3..72e740f7 100644 --- a/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md +++ b/.doc/remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md @@ -1,6 +1,6 @@ # 项目全面审计与整改方案 -> **HISTORICAL** — 缺陷详解与 Phase 设计档案。执行状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 为准。 +> **HISTORICAL** — 缺陷详解与 Phase 设计档案。执行状态以 [remediation-gap-matrix.md](./gap-matrix.md) 为准。 **日期**:2026-09-12 **编制**:代码审计 @@ -15,7 +15,7 @@ | 项目 | 完成度 | 说明 | |---|---|---| -| 业务决策文档 | ✅ 100% | `.doc/2026-09-12-three-workflows-strict-governance-remediation.md` 完成,10章详细规划 | +| 业务决策文档 | ✅ 100% | `.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md` 完成,10章详细规划 | | 核心代码变更 | ✅ 70% | 8个变更集框架已实施:目录隔离、manifest、validator、激活冻结、阶段推进等 | | 数据库迁移 | ✅ 80% | 00015-00024 共 10 个迁移已应用,核心表结构完成 | | 单元测试 | ✅ 85% | Coordinator、ProjectInstance、WorkflowDef 单元测试PASS | @@ -368,7 +368,7 @@ mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ### 3.1 项目上下文快照服务(ProjectContextSnapshot) -**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:82-105` +**规划文档**: `.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md:82-105` **当前状态**: 规划完整,实现 0% **关键要求**: @@ -412,7 +412,7 @@ mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ### 3.2 受控终止工作流(WorkflowTermination) -**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:109-131` (状态机) +**规划文档**: `.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md:109-131` (状态机) **当前状态**: 状态表存在,API 和逻辑 0% **关键要求**: @@ -453,7 +453,7 @@ mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ### 3.3 真实 E2E 测试(PostgreSQL + PI Agent) -**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459` (验收标准) +**规划文档**: `.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md:417-459` (验收标准) **当前状态**: 单元测试 PASS,E2E 0% **要求**: diff --git a/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md b/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md index 8d8db223..497416de 100644 --- a/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md +++ b/.doc/remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md @@ -1,6 +1,6 @@ # Phase 2:工作流设计器与模板库 Implementation Plan -> **依据**:`.doc/2026-09-11-production-ready-workflow-governance-plan.md` §7、§15 Phase 2 +> **依据**:`.doc/remediation/2026-09-11-production-ready-workflow-governance-plan.md` §7、§15 Phase 2 **Goal:** 工作流定义版本化入库;模板 CAS 资产库;Admin 草稿/校验/发布/退役;静态 catalog bootstrap;运行时 DBCatalog。 diff --git a/.doc/remediation/2026-09-12-quick-reference-guide.md b/.doc/remediation/2026-09-12-quick-reference-guide.md index 6816a20a..0cb9bf4c 100644 --- a/.doc/remediation/2026-09-12-quick-reference-guide.md +++ b/.doc/remediation/2026-09-12-quick-reference-guide.md @@ -385,7 +385,7 @@ golangci-lint run ./internal/... | 文档 | 用途 | 适合人员 | |---|---|---| -| [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) | **当前缺口 SSOT** | 全体 | +| [remediation-gap-matrix.md](./gap-matrix.md) | **当前缺口 SSOT** | 全体 | | [ops/CURRENT.md](./ops/CURRENT.md) | 协作焦点 | Agent / 开发 | | [comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 详细缺陷分析与整改方案(历史) | 架构师、资深开发 | | [remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 可执行的任务拆分与验收 | 开发、QA | diff --git a/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md b/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md index 05388cce..01ef50be 100644 --- a/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md +++ b/.doc/remediation/2026-09-12-remediation-tasks-and-acceptance-checklist.md @@ -1,6 +1,6 @@ # 整改实施拆分与验收清单 -> **工作手册(非 live status)** — 任务说明与验收框;勾选状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/checklists/](./ops/checklists/) 为准。 +> **工作手册(非 live status)** — 任务说明与验收框;勾选状态以 [gap-matrix.md](./gap-matrix.md) 与 [archive/ops/checklists/](../archive/ops/checklists/) 为准。 **日期**: 2026-09-12 **格式**: 可执行的任务分解与逐项验收标准 diff --git a/.doc/test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md b/.doc/test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md index 76abc5d0..70d24e81 100644 --- a/.doc/test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md +++ b/.doc/test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md @@ -2,7 +2,7 @@ ## 一、 测试背景 (Background) -依据 `.doc/2026-09-12-three-workflows-strict-governance-remediation.md`,系统需收敛为 3 个正式工作流、实例唯一运行权威、PM/TE 解耦及项目上下文快照。 +依据 `.doc/remediation/2026-09-12-three-workflows-strict-governance-remediation.md`,系统需收敛为 3 个正式工作流、实例唯一运行权威、PM/TE 解耦及项目上下文快照。 ## 二、 测试目标 (Test Objectives) From f30886e44226f1d6e2db056ccc19005240e2ab5a Mon Sep 17 00:00:00 2001 From: weichen Date: Sun, 13 Sep 2026 02:44:39 +0000 Subject: [PATCH 5/5] docs(agents): require feature branches off dev for all work Align AGENTS, Cursor rule, PROJECT, README, templates, and CURRENT with strategy A: no direct commits on dev/test/main; all work branches from dev. Co-authored-by: Cursor --- .../rules/git-workflow-and-environments.mdc | 10 ++--- .../reference/branch-and-environment-rules.md | 2 + .doc/ops/CURRENT.md | 10 ++--- .doc/ops/templates/session-close-checklist.md | 6 ++- .doc/ops/templates/short-term-task.md | 2 +- AGENTS.md | 40 ++++++++++++++----- PROJECT.md | 6 ++- README.md | 6 +-- 8 files changed, 54 insertions(+), 28 deletions(-) diff --git a/.cursor/rules/git-workflow-and-environments.mdc b/.cursor/rules/git-workflow-and-environments.mdc index 18c58135..59d6d4d0 100644 --- a/.cursor/rules/git-workflow-and-environments.mdc +++ b/.cursor/rules/git-workflow-and-environments.mdc @@ -10,18 +10,18 @@ alwaysApply: true ## 一、 Git 固定三分支体系 1. **开发分支 (`dev`)**: - - 所有代码日常开发在此分支进行。 - - 细小变更直接在 `dev` 上分批逐步提交。 - - 独立大功能可从 `dev` 检出子分支 `feature/` 或 `fix/`,在本地测试完成后合并回 `dev`(`--no-ff`),并删除临时子分支。 + - **合入基线**,不是日常 commit 目标。 + - **禁止**在 `dev` 上直接开发提交(含 docs/chore)。 + - 一律从最新 `dev` 检出 `feature/` 或 `fix/`,在 feature 分支上渐进式提交;自测后占集成槽位,`--no-ff` 合回 `dev`,并删除临时子分支(见 [AGENTS.md](../../AGENTS.md) §6.2)。 2. **测试分支 (`test`)**: - 当 `dev` 积累了一定的功能阶段后,合并至 `test` 分支,创建阶段候选节点 Tag(如 `rc-vX.Y.Z-beta.1`)。 - 用于较长时间的真实环境部署、全链路集成测试、运维稳定性检验。 - - 严禁在 `test` 分支进行未经规划的大规模功能开发。 + - **严禁**在 `test` 分支进行开发或直接 commit。 3. **主分支 (`main`)**: - 生产发布分支(Release)。 - - 严禁直接在 `main` 上开发! + - **严禁**直接在 `main` 上开发或 commit! - 只有 `test` 分支的代码经过实际运维和测试充分验证达到发布标准后,方可将对应验证节点合并回 `main` 分支,并打正式发布 Tag(如 `v1.0.0`)。 --- diff --git a/.doc/archive/reference/branch-and-environment-rules.md b/.doc/archive/reference/branch-and-environment-rules.md index 1bca88e0..269800f2 100644 --- a/.doc/archive/reference/branch-and-environment-rules.md +++ b/.doc/archive/reference/branch-and-environment-rules.md @@ -1,5 +1,7 @@ # 研发分支与多套独立环境运行规范 (Branch & Environment Rules) +> **HISTORICAL**:日常开发分支策略已由 [AGENTS.md](../../../AGENTS.md) §6.2、[PROJECT.md](../../../PROJECT.md) §4 与 [`.cursor/rules/git-workflow-and-environments.mdc`](../../../.cursor/rules/git-workflow-and-environments.mdc) 取代为「一律从 `dev` 开 `feature/*` 或 `fix/*`,禁止在三大主干直接 commit」。本文档保留作环境矩阵与历史流程参考。 + 本规范为本系统代码仓库的强制性规范,涵盖 **Git 3 分支流转模型**、**任务功能拆分与渐进式提交**、**三套环境独立运行(知识库共享 + 对话与数据库隔离)** 以及 **运维操作指引**。 --- diff --git a/.doc/ops/CURRENT.md b/.doc/ops/CURRENT.md index 8f7c46d7..7b249fbf 100644 --- a/.doc/ops/CURRENT.md +++ b/.doc/ops/CURRENT.md @@ -1,13 +1,13 @@ # 当前焦点 **更新**: 2026-09-13 -**production_ready**: no(CI 真实 PI E2E + 前端人工抽检待完成) +**production_ready**: no(对话刷新恢复、CI 真实 PI E2E、前端人工抽检待完成) ## 焦点 -1. **CI**: `TEST_DATABASE_URL` + 真实 PI E2E 实录 -2. **前端**: 版本冲突刷新、终止 preview 人工抽检 -3. **BACKLOG**: session cookie / bundle 拆分 / 容量治理(见 [backlog](../backlog/chat-agent-p6-backlog.md)) +1. **CHAT**: [刷新恢复整改待实施](short-term/2026-09-13-chat-history-refresh-remediation.md)(发布 blocker) +2. **CI**: `TEST_DATABASE_URL` + 真实 PI E2E 实录 +3. **前端**: 版本冲突刷新、终止 preview 人工抽检 ## 并行认领 @@ -15,7 +15,7 @@ |-------|------|--------|----------|-------|--------| | — | — | — | — | — | — | -> 新任务开始前登记。同一 `mutex` 同时仅一个 `in_progress`。 +> 新任务开始前登记。`branch` 必须为 `feature/` 或 `fix/`,**禁止** `dev` / `test` / `main`。同一 `mutex` 同时仅一个 `in_progress`。 ## 集成槽位 diff --git a/.doc/ops/templates/session-close-checklist.md b/.doc/ops/templates/session-close-checklist.md index 7fe12942..ae2cb032 100644 --- a/.doc/ops/templates/session-close-checklist.md +++ b/.doc/ops/templates/session-close-checklist.md @@ -10,8 +10,10 @@ ## 代码与分支 -- [ ] 非 trivial 改动已 merge `--no-ff` 到 dev(或 handoff 说明未 merge 原因) -- [ ] 无未 push 的 dev 关键提交(若用户要求同步远端) +- [ ] 确认未在 `dev` / `test` / `main` 上直接 commit(工作均在 `feature/*` 或 `fix/*`) +- [ ] 已占集成槽位并 `merge --no-ff` 合回 `dev`(或 handoff 说明未 merge 原因) +- [ ] feature/fix 分支已删除或 worktree 已 remove(若已合入) +- [ ] 无未 push 的关键提交(若用户要求同步远端) ## 文档 diff --git a/.doc/ops/templates/short-term-task.md b/.doc/ops/templates/short-term-task.md index ac16f3ce..a1d7dbff 100644 --- a/.doc/ops/templates/short-term-task.md +++ b/.doc/ops/templates/short-term-task.md @@ -4,7 +4,7 @@ status: planned created: YYYY-MM-DD updated: YYYY-MM-DD owner: agent -branch: feature/ +branch: feature/ # 必填:feature/* 或 fix/*;禁止 dev / test / main worktree: "-" mutex: --- diff --git a/AGENTS.md b/AGENTS.md index 8bfdada6..e27aa717 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -105,17 +105,36 @@ **同一 mutex 同时仅一个 `in_progress`**。冲突 → 写 handoff blocker,禁止覆盖他人未合并改动。 -### 6.2 分支与 Worktree +### 6.2 分支与 Worktree(策略 A:一律从 dev 开分支) -- 非 trivial 改动必须独立分支,禁止多人直推同一 dev 工作区抢改。 -- **多 Agent 并行时强制 worktree**:`.worktrees//`(已 gitignore) -- 脚本:`./scripts/agent-worktree.sh create|list|remove` +> **禁止**在 `dev` / `test` / `main` 三大主干上直接 `git commit`(含代码、配置、文档)。 +> `dev` 仅作合入点;`test`/`main` 仅作环境晋升合入,禁止开发。 -| Worktree 允许 | Worktree 禁止 | -|---------------|---------------| -| 编码、`go test -short ./...` | `env-service.sh * start/stop/restart` | +**任务开始(先于改码):** + +1. 更新本地 `dev`:`git checkout dev && git pull`(若已配置远端) +2. 从 `dev` 创建分支:`feature/`(新能力)或 `fix/`(缺陷);slug 与 short-term 任务名对齐 +3. 多 Agent 并行:用 `./scripts/agent-worktree.sh create feature/`(worktree 内编码) +4. 单 Agent:可在主仓 `git checkout -b feature/`,**不得**留在 `dev` 上改码提交 + +**合回 dev(占集成槽位,见 §6.3):** + +```bash +git checkout dev +git merge --no-ff feature/ -m "merge: feature/" +# 冒烟通过后 +git branch -d feature/ # 或 agent-worktree.sh remove +``` + +| 允许 | 禁止 | +|------|------| +| 在 `feature/*` / `fix/*` 上 commit | 在 `dev` / `test` / `main` 上 commit | +| worktree 内 `go test -short ./...` | worktree 内 `env-service.sh * start/stop/restart` | +| 占槽后在主仓 merge 入 `dev` | 多人直推同一 `dev` 工作区抢改 | | 连主仓已起服务 `:8080` | 各 worktree 各起 docker | +脚本:`./scripts/agent-worktree.sh create|list|remove` + ### 6.3 集成槽位(合入 dev + 容器验证) > **编码与 worktree 单测可并行;合入 dev + 共享容器验证必须串行。** @@ -161,11 +180,12 @@ audit(问题)→ remediation(方案)→ ops/short-term(任务) ## 8. Git 与提交 - 遵循 **Conventional Commits**:`feat` / `fix` / `refactor` / `test` / `docs` / `chore` / `ci` -- **原子提交**:一个逻辑变更一批 -- merge 回 dev 用 `--no-ff` +- **原子提交**:一个逻辑变更一批;提交发生在 `feature/*` 或 `fix/*` 上,不在三大主干 +- **合回 dev**:占集成槽位后 `merge --no-ff`(见 §6.2、§6.3) +- **晋升**:`dev` → `test`(rc tag)→ `main`(release tag);仅在规划的环境合并时动 `test`/`main` - **用户未要求**:不擅自 push - **用户已要求 push/同步远端**:必须自主完成 -- **禁止**:在 `git config` 写入 token;硬重置/强推/删库仅在用户明确授权时 +- **禁止**:在 `dev`/`test`/`main` 上直接开发 commit;在 `git config` 写入 token;硬重置/强推/删库仅在用户明确授权时 --- diff --git a/PROJECT.md b/PROJECT.md index 88b4e005..5c840aa0 100644 --- a/PROJECT.md +++ b/PROJECT.md @@ -52,6 +52,8 @@ **红线**:知识库共享;对话与业务 DB **严格隔离**,禁止跨环境读写。 +**分支红线**:三大主干(`dev`/`test`/`main`)禁止直接开发 commit;一律从 `dev` 开 `feature/*` 或 `fix/*`,合回 `dev` 须占集成槽位(见 [AGENTS.md](./AGENTS.md) §6)。 + --- ## 5. 文档地图(SSOT) @@ -124,11 +126,11 @@ cd web && npm test && npm run build - 发布缺口 SSOT:[gap-matrix](./.doc/remediation/gap-matrix.md) - 模块完成度:[FEATURE-MATRIX](./.doc/status/FEATURE-MATRIX.md) - 最新测试报告:[2026-09-13-codex-audit-p0-remediation-test-report.md](./.doc/test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md) -- **剩余 blocker**: CI 真实 PI E2E + 前端人工抽检(main 本地冒烟已通过) +- **剩余 blocker**: 对话刷新恢复与历史读取授权一致性 + CI 真实 PI E2E + 前端人工抽检(main 本地冒烟已通过) --- ## 10. 语言与提交 - 对用户:**简体中文** -- 提交:Conventional Commits;在 `dev` 上渐进式分批提交 +- 提交:Conventional Commits;在 `feature/*` 或 `fix/*` 上渐进式分批提交,合回 `dev` 用 `--no-ff`(禁止在三大主干直接 commit) diff --git a/README.md b/README.md index 332380fd..6c45a01f 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ | 分支名 | 定位 | 职责与准入规则 | | :--- | :--- | :--- | -| **`dev`** | **开发分支** | **日常开发基线**。所有代码开发均在此分支或其衍生子分支(`feature/*`, `fix/*`)进行,子分支自测后合并回 `dev`。支持一个任务按功能拆解并逐步渐进式提交。 | -| **`test`** | **测试分支** | **准生产实测分支**。当 `dev` 积累了一定功能阶段后合并至此,建立发布候选节点(`rc-vX.Y.Z`),进行真实环境部署与长期集成测试与运维检验。 | -| **`main`** | **主分支** | **生产发布分支**。严禁直接提交。仅在 `test` 分支经过真实运维和测试验证达到发布标准后,将对应节点合并回 `main` 并打正式版本 Tag(`vX.Y.Z`)。 | +| **`dev`** | **开发合入基线** | 禁止直接 commit。从最新 `dev` 开 `feature/*` 或 `fix/*` 开发,自测后占集成槽位 `--no-ff` 合回 `dev`。 | +| **`test`** | **测试分支** | 准生产实测;`dev` 阶段合并 + rc tag。**严禁**在此分支开发或 commit。 | +| **`main`** | **主分支** | 生产发布;仅 `test` 验证通过后合并。**严禁**直接开发或 commit。 | 完整的分支流转模型、热修复流程与提交规范请参阅:[PROJECT.md](./PROJECT.md) §4(SSOT)。