# PMFlow OS Product Contract 版本日期:2026-04-26 本文档是 PMFlow OS 从本地高保真主链走向真实数据闭环的产品级合同。它锁定对象真源、读写边界、状态流转和后续开发接口,避免 `frontend/src/features/pmflow-os/` 继续围绕 mock store 扩散。A3 已完成真实只读 projection,Phase B 已完成 Project Launch 创建链,Phase C1 已完成 Change Review 数据底座与审查状态机;Phase C2 backend 已按 atomic commit 合同实现,后续前端接入不得再自行改变 API shape。 产品方向真源仍以 `docs/PMFLOW_PRODUCT_BLUEPRINT.md` 为准;UI 行为与状态标签以 `docs/PMFLOW_UI_CONTRACT.md` 为准;推进节奏以 `docs/PMFLOW_PRODUCT_DELIVERY_STANDARD.md` 为准。 ## 1. 合同结论 PMFlow OS V1 的主链是: ```text Project Thread -> Structured Extraction -> ChangeSet Review -> Project Memory / Work Graph commit -> Execution Bridge -> Release / Growth feedback ``` 当前复用边界: - `Requirement / Decision / Risk / Release` 优先从 `truth_nodes` 投影,不新建另一套正式业务对象表。 - `Task` 复用 `tasks`,并通过 `truth_node_id` 绑定需求/宪章/项目真相节点。 - `Project Memory` 由 `truth_nodes + semantic_facts` 聚合投影;`semantic_facts` 是 read model,不是人工确认记录本身。 - `ModelDecision / PromptPackage / ReleaseValidation / Feedback / Revenue / ROI / Compliance` 复用 `ai_project_control` 模型与 `sstc_api/model_control.py` 现有接口。 - `ExecutionContext` 复用 `prompt_packages + repo_bindings + task_code_links + progress_events + dev_sync summary`;运行端接入凭据复用 `ai_project_control` 域新增的 `pmflow_execution_runtime_credentials`,只保存短期签名回流合同,不保存明文 secret。 - `Thread / ThreadMessage` 已由 Phase B 落到 `pmflow_threads / pmflow_thread_messages`。 - `ChangeSet / ChangeItem / Approval / EvidenceLink` 已由 Phase C1 落到 `pmflow_change_sets / pmflow_change_items / pmflow_approvals / pmflow_evidence_links`。 PMFlow OS 专属表: ```text pmflow_threads pmflow_thread_messages pmflow_change_sets pmflow_change_items pmflow_approvals pmflow_evidence_links ``` `/commit` 后端代码与前端真实模式接入已实现;真实模式下 `promoteAcceptedToGraph` 必须调用后端 `POST /pmflow-os/change-sets/{change_set_id}/commit`,不得用本地 mutation 冒充正式 Project Memory 写入。 ## 2. 对象映射表 | 前端对象 | 后端来源 | 是否新增表 | 读 API | 写 API | 状态流转 | 证据/审计 | 风险点 | | --- | --- | --- | --- | --- | --- | --- | --- | | `ProjectTruthState` | 聚合投影:`projects`、`truth_nodes`、`tasks`、`semantic_facts`、PMFlow OS 专属 review 表、`ai_project_control`、`dev_sync` | 不直接建总表 | `GET /pmflow-os/projects/{project_id}/truth-state` | 由各子对象 API 写入 | `loopStage` 由最近线程、提取和审查状态计算 | 返回 customer-safe 状态,不暴露内部 raw label | 需要 projection service,不能由前端拼多个旧接口冒充 | | `Thread` | `pmflow_threads`;绑定 `project_id`、默认目标、当前阶段 | 是,Phase B 已建 | `truth-state` 内返回 | 创建项目时初始化,或 C1 `messages` 首次写入时懒创建 | `idle -> loading -> ready` 仅表示提取状态 | 线程本身是后续 ChangeSet 证据源 | 不能复用飞书 thread/session 作为唯一项目线程 | | `Message` | `pmflow_thread_messages`;可引用 Feishu/QA/message 来源 | 是,Phase B 已建 | `truth-state` 内返回 | `POST /pmflow-os/projects/{project_id}/threads/{thread_id}/messages` | C1 先写 `sent`,后续可扩 `analyzing/resolved/failed` | message id 可被 `EvidenceLink` 引用 | 写 message 不等于写项目真相层 | | `ChangeSet` | `pmflow_change_sets` | 是,Phase C1 已建 | `GET /pmflow-os/projects/{project_id}/change-sets/{change_set_id}` | `POST /pmflow-os/projects/{project_id}/extractions` 生成;C2 才实现 `commit` | C1:`open -> reviewed`;C2:`committed / partially_committed` | 记录生成来源、routing_meta、LLM call id、actor | 不能用 `truth_nodes` 直接模拟 ChangeSet;ChangeSet 是待确认变更包 | | `ChangeItem` | `pmflow_change_items` | 是,Phase C1 已建 | ChangeSet detail | C1:`accept / edit / defer`;C2:`commit` 后写正式对象 | C1:`pending_review -> accepted / edited / deferred`;C2:`committed / skipped` | 每项必须绑定 evidence ids 与 risk level | `accept` 只改审查状态,不得静默落库 | | `Evidence` | `pmflow_evidence_links` 投影,来源可为 message、truth_node、task、progress_event、release_validation、feedback、metric | 是,Phase C1 已建 link 表 | `truth-state`、ChangeSet detail | C1 随 extraction 创建 thread message evidence;C2 随 commit、execution/growth 回写扩展 | 证据不走业务状态,只可 active/archived | 必须记录 `source_type/source_id/excerpt/display_label` | `ai_project_control.EvidencePack` 只适合发布/合规证据包,不能替代通用证据链 | | `Approval` | `pmflow_approvals` | 是,Phase C1 已建 | `truth-state`、ChangeSet detail | C1:`accept / edit / defer` 写入;C2:commit gate 扩展 | `approved / edited / deferred / rejected` | 记录 actor、role、decision、before/after | 高风险变更必须有 approval 记录;C1 只记录,C2 才强制 gate | | `Requirement` | `truth_nodes.node_type in ('charter','requirement')` 投影;V1 可从 charter content 中拆分 requirement block | 否 | `truth-state` | `commit` accepted ChangeItem 后创建/更新 `truth_nodes` | `draft/proposed -> confirmed -> archived`,前端映射到 `draft/confirmed/done` | commit 时绑定 ChangeItem/EvidenceLink;semantic facts hook 后台抽取 | 当前 `TruthNode.node_type` 历史值不统一,需在 projection 层做白名单映射 | | `Decision` | `truth_nodes.node_type='decision'` 或 charter/review content 决策块投影 | 否 | `truth-state` | `commit` 写 `truth_nodes` | `draft/proposed -> confirmed` | 必须保留来源 ChangeItem 和 owner | 若历史没有 decision node,先从 charter content 投影,不新增前端-only 决策 | | `Task` | `tasks` + `truth_nodes` | 否 | `truth-state`;后续可复用 SSTC task board | `commit` 创建/更新 `tasks`;执行进度走 dev-sync | `draft -> in_progress -> blocked/done` | 任务来源 ChangeItem、验收标准、assignee 建议进入审计 | `tasks.status` 与前端状态枚举需 projection 映射 | | `Risk` | `truth_nodes.node_type='risk'` 或 charter/release/check content 风险块投影 | 否 | `truth-state` | `commit` 写 `truth_nodes` | `draft/proposed -> confirmed -> archived` | 高风险必须绑定 approval 与 mitigation | `ReleaseValidationRun.risk_items` 是发布检查结果,不等于正式风险对象 | | `ModelDecision` | `project_model_bindings`、`model_recommendation_snapshots`、`model_eval_runs` 投影 | 否 | `truth-state` 可聚合;细节复用 `/projects/{project_id}/model-recommendations`、`/model-usage` | `/model-binding` | `recommended -> active -> archived` 映射到前端 `confirmed/released` | selection_reason、snapshot_input、eval summary 作为证据 | 不做独立模型市场页,必须嵌入项目主链 | | `TestRun` | `model_eval_runs`、`release_validation_runs`、`progress_events(event_type=test*)` 投影 | 否 | `truth-state`、`execution-summary` | dev-sync progress event 或 release validation | `pending/running -> passed/failed/blocked` | 测试日志和 PR/commit 可作为 evidence | 当前没有通用 test_runs 表,V1 先按投影聚合 | | `Release` | `truth_nodes.node_type='release'` + `release_validation_runs` | 否 | `truth-state`;SSTC release APIs | SSTC release 创建;`run_release_validation` | `check_pending -> ready -> shipping -> live/watch` | release gate、rollback_plan、validation_summary | 发布对象和发布验证结果需要在 projection 中分清 | | `MetricSignal` | `feedback_ingests.metrics`、`revenue_events`、`roi_snapshots`、增长埋点结果投影 | 否 | `truth-state`;`/roi-snapshots` | `feedback-ingest`、`revenue-events` | `draft/proposed -> confirmed` | 指标来源和采样窗口必须展示 | 只做轻量反馈,不引入完整财务系统 | | `ExecutionContext` | `prompt_packages`、`repo_bindings`、`task_code_links`、`progress_events`、`pmflow_execution_runtime_credentials`、`dev_sessions` | 否 | `GET /pmflow-os/projects/{project_id}/execution-summary` 聚合 `GET /projects/{project_id}/dev-sync/summary` | `POST /pmflow-os/projects/{project_id}/execution-handoffs` 生成/复用 `PromptPackage` 并创建 `ProgressEvent` 起点;`POST /pmflow-os/projects/{project_id}/execution-handoffs/{prompt_package_id}/runtime-credential` 生成短期签名回流凭据;`POST /pmflow-os/runtime/execution-results` 或登录态 `POST /execution-progress-events` 写入 `execution_result_protocol_v1` 执行结果;repo 绑定仍走 dev-sync/GitHub App | `queued -> pushed -> coding -> pr_open -> testing -> synced/failed` | progress events、deliveries、credential use count、repo/PR/commit/test/blocker 是执行证据 | 不得重造 dev-sync;PMFlow OS 只做项目内执行投影、handoff 与签名 result contract,不直接执行本机命令,不保存运行端明文 secret | | `TeamFeed / TeamInbox` | `pmflow_change_sets`、`pmflow_approvals`、`progress_events`、release/feedback 事件聚合 | 暂不新增专表,先 projection | `truth-state` | 由各业务动作写入源表 | feed item 不承载主状态 | 必须能追溯到源对象 | Phase F 才补 Role Inbox/Decision Desk 的真实模型 | ## 3. ProjectTruthState 后端投影 `GET /pmflow-os/projects/{project_id}/truth-state` 返回前端兼容结构,但数据必须由后端 projection service 组装: ```text project: projects + latest confirmed truth_nodes thread/messages: pmflow_threads + pmflow_thread_messages changeSets/changeItems/evidence/approvals: PMFlow OS 专属 review 表 requirements/decisions/risks/releases: truth_nodes 投影 tasks: tasks + related truth_nodes modelDecisions: model_recommendation_snapshots + project_model_bindings + model_eval_runs testRuns: release_validation_runs + model_eval_runs + progress_events(test) metricSignals: feedback_ingests + revenue_events + roi_snapshots feed/teamInbox: review/actions/progress/release/growth 事件聚合 execution: dev-sync summary + prompt_packages + recent progress_events ``` 投影规则: - `AI 已生成` 对应 `ChangeSet.open` 和 `ChangeItem.pending_review`,不得进入正式对象列表。 - `待你确认` 对应 `ChangeItem.pending_review` 或高风险 `Approval.requested`。 - `已确认` 对应 `ChangeItem.accepted/edited`,但尚未必然写入 Project Memory。 - `已写入项目记忆` 只能在 `ChangeSet.commit` 成功写入 `truth_nodes / tasks / semantic_facts` 后出现。 - `semantic_facts` 只用于 read-side facts-first 查询与 Project Memory projection,不作为人工确认动作记录。 审查与写入顺序: - `Structured Extraction` 只生成 `ChangeSet / ChangeItem / EvidenceLink`,不得写正式对象。 - `ChangeReviewPage` 是正式审查动作的唯一主入口;`accept / edit / defer / reject / review decision` 都只写审查状态、approval 和审计,不写 `truth_nodes / tasks / semantic_facts`。 - `TeamLayerPage` 只消费 `reviewerRouting / reviewDecision / approvalState` 做责任路由、角色收件箱、决策台和阻塞解释;团队层不得直接执行 `commit`,也不得成为第二套 Change Review。 - `reviewerRouting` 只是建议与状态投影;除非用户显式 `request_review` 或后续合同定义自动分派,否则不得把建议 reviewer 当成已分派任务。 - 高风险、跨角色、缺证据或需要专业判断的 item 必须先满足 required reviewer / approval gate,再允许 `commit`。 - `commit` 是 Project Memory 写入唯一边界;成功后才允许正式对象进入 Work Graph,并成为 Execution Bridge 的可执行候选。 项目级副驾投影合同: - 前端当前由 `ProjectTruthState + execution summary + reviewer routing + release signals + ai readiness` 派生 `CopilotContextPacket`,只作为客户可见解释、建议、跳转和受限动作投影。 - `ProjectCopilotPanel` 可以显示当前对象、阶段、风险、证据、待确认、AI readiness 和下一步动作,但不得自行写 `ChangeSet / Project Memory / ProgressEvent / ReleaseValidationRun / FeedbackIngest`。 - 副驾里的 `Commit` 类动作必须跳回或调用 Change Review 的正式提交链路;`Execute` 类动作必须跳回或调用 Execution Bridge 的正式 handoff / progress / memory writeback 链路;发布增长动作只能进入 release validation 或 recommendation -> ChangeSet draft。 - 在后端补齐项目级 `ask/action` 合同前,副驾输入只能作为页面回调或受控 ask 入口,不得让自由 QA 绕过 `Query Route Gateway`、Project Memory commit、reviewer gate 或 Execution Bridge。 - 客户可见副驾只能展示中文化业务标签、证据摘要和下一步动作;不得暴露 provider、model、trace、prompt body、raw source label 或内部 agent 编排。 ## 4. API 合同草案 所有接口统一返回: ```json { "code": 0, "message": "success", "data": {} } ``` 错误仍走项目现有失败包络与 HTTP 状态;客户可见错误必须明确失败原因,不得用 mock 或默认句冒充成功。 ### 4.1 获取项目真相投影 ```text GET /pmflow-os/projects/{project_id}/truth-state ``` Response `data`: ```json { "loopStage": "extraction_ready", "lastWritebackAt": "2026-04-25T10:00:00+08:00", "project": {}, "thread": {}, "messages": [], "changeSets": [], "changeItems": [], "evidence": [], "requirements": [], "decisions": [], "tasks": [], "risks": [], "modelDecisions": [], "testRuns": [], "releases": [], "metricSignals": [], "approvals": [], "feed": [], "teamInbox": {}, "activeChangeSetId": null, "selectedTaskId": null, "execution": {} } ``` 失败语义: - `404 project_not_found`:项目不存在或不属于当前租户。 - `403 forbidden`:当前用户不是项目成员或管理角色。 - `409 projection_incomplete`:核心合同对象缺失,不能拼装可信 ProjectTruthState。 ### 4.2 写入线程消息 ```text POST /pmflow-os/projects/{project_id}/threads/{thread_id}/messages ``` Request: ```json { "content": "用户输入", "source": "web", "attachments": [] } ``` 行为: - 只写 `pmflow_thread_messages`。 - 可触发异步 extraction job,但不能直接写 `truth_nodes / tasks`。 - 返回 message 和可选 `extraction_job_id`。 ### 4.3 创建结构化提取 ```text POST /pmflow-os/projects/{project_id}/extractions ``` Request: ```json { "thread_id": "thread_123", "message_id": "msg_123", "scope": "latest_message", "proposed_items": [ { "group": "new_object", "object_type": "Requirement", "title": "待审变更标题", "summary": "待审变更摘要", "payload": {}, "confidence": 0.82, "risk_level": "medium" } ] } ``` 行为: - C1 采用 `proposed_items` 最小闭环,不默认调用 LLM;后续 AI 结构化提取应在上游生成 proposed items 后调用该接口。 - 生成 `pmflow_change_sets` 与 `pmflow_change_items`。 - ChangeSet 默认 `open`,ChangeItem 默认 `pending_review`。 - 生成 `pmflow_evidence_links`,至少绑定触发消息。 - 不写 `truth_nodes / tasks / semantic_facts`。 失败语义: - `422 invalid_proposed_items`:未提供可审查 proposed items,不生成 ChangeSet。 - `404 message_not_found`:message 不属于当前 tenant/project/thread。 ### 4.4 获取 ChangeSet ```text GET /pmflow-os/projects/{project_id}/change-sets/{change_set_id} ``` Response `data`: ```json { "changeSet": {}, "items": [], "evidence": [], "approvals": [] } ``` ### 4.5 审查 ChangeItem ```text POST /pmflow-os/change-items/{change_item_id}/accept POST /pmflow-os/change-items/{change_item_id}/edit POST /pmflow-os/change-items/{change_item_id}/defer ``` `edit` Request: ```json { "summary": "修改后的摘要", "diff": "修改后的业务 diff", "payload_patch": {} } ``` 行为: - `accept`:仅将 ChangeItem 置为 `accepted`,写 `pmflow_approvals`,不写正式对象。 - `edit`:保存人工修改后的 payload,状态为 `edited`,写 `pmflow_approvals`。 - `defer`:状态为 `deferred`,不进入项目真相层,但保留审计。 产品动作语义: - `接受` 只能表示当前 actor 认可候选变更进入待写入集合;不得显示为“已写入”或触发执行桥。 - `修改` 必须生成可审计 before/after,不得覆盖原始 AI proposal 和 evidence。 - `暂不落库` 对应 `deferred`,用于当前不写入但保留后续恢复空间;它不是 reject。 - `拒绝` 若前端或后端提供,必须作为 terminal discard / rejected 审计处理,不得被批量 commit 重新捞回;在未实现 reject API 前,UI 不得用 `defer` 冒充拒绝。 - `稍后处理` 是队列提醒 / 排序动作,不应调用本节三个审查 API;它不得改变 ChangeItem 状态。 - `批量接受` 只能调用一组满足低风险、证据充分、无需 required reviewer gate、对象类型受支持的 item;包含任一不满足项时必须 fail-closed 或拆分处理。 失败语义: - `409 changeset_not_open`:ChangeSet 非 open,不能继续审查。 - `409 item_already_reviewed`:ChangeItem 已被接受、编辑、暂缓、提交或跳过,不重复写 approval。 - `422 invalid_change_payload`:修改后的 payload 不满足对象合同。 ### 4.6 提交 ChangeSet Phase C2 必须按此合同实现,后端与前端不得自行发明其它请求或响应形状。 ```text POST /pmflow-os/change-sets/{change_set_id}/commit ``` Auth: - 当前用户必须是项目成员、`OWNER` 或 `REVIEWER`。 - `tenant_id` 必须来自当前 JWT,不得从请求体传入。 Request: ```json { "item_ids": ["12", "13"], "mode": "atomic", "note": "确认写入项目记忆" } ``` 字段规则: - `item_ids` 可选;为空时提交该 ChangeSet 下全部 `accepted / edited` 项。 - `mode` C2 V1 只允许 `atomic`;未来若支持部分提交,必须先更新本文档。 - `note` 可选,仅进入审计,不参与业务字段生成。 行为: - 只处理 `accepted / edited` 的 ChangeItem。 - `pending_review / deferred / committed / skipped` 不写正式对象,只进入 `skippedItems` 明细。 - C2 V1 使用单事务原子提交:任一 eligible item 写入失败时,整个 commit 回滚,不允许出现半写入 Project Memory。 - 按 `objectType` 写入正式对象: - `Requirement / Decision / Risk / Release` -> `truth_nodes` - `Task` -> `truth_nodes(node_type='task')` + `tasks.truth_node_id` - `ModelDecision` -> `project_model_bindings` 或绑定选择记录 - `MetricSignal` -> 反馈/收入/ROI 相关记录,或生成下一轮 recommendation 草案 - 创建或更新 `pmflow_evidence_links`。 - 提交成功后触发 semantic facts 抽取/刷新。 - 全部 eligible item 成功后 ChangeSet 进入 `committed`。 - `partially_committed` 是未来扩展状态,C2 V1 不应写出该状态。 Response `data`: ```json { "changeSet": { "id": "10", "status": "committed", "rawStatus": "committed", "committedAt": "2026-04-26T10:00:00+08:00", "committedItemIds": ["12"], "skippedItemIds": ["14"], "failedItemIds": [] }, "committedItems": [ { "changeItemId": "12", "objectType": "Requirement", "targetType": "truth_node", "targetId": "301", "status": "committed", "evidenceIds": ["44"], "semanticFactStatus": "queued" } ], "skippedItems": [ { "changeItemId": "14", "objectType": "Task", "status": "deferred", "reason": "item_not_accepted_or_edited" } ], "failedItems": [], "projectTruthState": {} } ``` 响应规则: - `projectTruthState` 可选;若返回,必须是 commit 后的后端真实 projection,不得由前端本地拼装。 - `committedItems[].targetId` 必须是正式对象 id,如 `truth_nodes.id`、`tasks.id`、`project_model_bindings.id`。 - `semanticFactStatus` 取值:`queued / seeded / skipped / failed`;失败不能影响已完成的正式对象写入,但必须进入审计或 failed detail。 失败语义: - `404 changeset_not_found`:ChangeSet 不存在或不属于当前 tenant/project。 - `409 changeset_not_reviewed`:仍存在 `pending_review` 项且请求未显式只提交 `item_ids`。 - `409 changeset_already_committed`:ChangeSet 已经提交,不能重复提交。 - `409 no_accepted_items`:没有 `accepted / edited` 可提交项。 - `409 high_risk_approval_required`:高风险项缺少 required approval。 - `422 invalid_commit_item_ids`:`item_ids` 不属于该 ChangeSet 或包含不可提交状态。 - `422 unsupported_object_type`:`objectType` 不在 C2 白名单。 - `422 invalid_change_payload`:有效 payload 不满足正式对象必填字段。 - `500 commit_failed`:写入正式对象失败;C2 V1 必须回滚整个事务,并返回 `failedItems` 明细,不得冒充部分成功。 ### 4.7 获取执行桥摘要 ```text GET /pmflow-os/projects/{project_id}/execution-summary ``` 行为: - 优先调用或复用 `GET /projects/{project_id}/dev-sync/summary`。 - 额外补齐最近 Prompt Package、活动 repo、PR/commit/test progress event。 - 返回前端 `ExecutionContext` 兼容结构、详细 dev task 列表、`qualityContract`、`acceptance`、`deliveryArtifacts`、`artifactCompleteness` 与 `artifactReview`。`qualityContract` 表达必测层级、阻塞发布的测试项、测试环境、真实/可 mock 数据边界和证据要求;`acceptance` 表达 `waiting_execution / waiting_test_evidence / pending_user_acceptance / pending_technical_review / technical_review_approved / accepted / changes_requested / rejected / execution_blocked` 等状态与 `canEnterReleaseGate`;`artifactCompleteness` 表达结构化交付证据 `empty / incomplete / blocked / ready`;`artifactReview` 把缺证据/失败证据转成补截图、补测试输出、修 failed command、补 review checklist 等返工审查项。 ### 4.8 创建执行交接 ```text POST /pmflow-os/projects/{project_id}/execution-handoffs ``` 请求: ```json { "task_id": "123", "repo_binding_id": "456", "runtime_target": "local_bridge", "note": "可选交接备注" } ``` 行为: - 先复用项目成员/OWNER/REVIEWER 权限边界,再校验 `task_id` 必须属于当前 tenant/project。 - `repo_binding_id` 可选;传入时必须属于当前 tenant/project 且为 active。未传入时允许创建 handoff draft,但 response 的 `warnings` 必须继续暴露 `repo_bindings_empty` 或等价缺口。 - 若当前任务已有 active `PromptPackage`,复用该包并写入 latest handoff metadata;否则从真实 `Project / Task / Project Memory / RepoBinding` 生成 deterministic `PromptPackage(package_kind='execution_handoff')`,禁止硬编码 demo 文案。PromptPackage 必须包含 `Quality Contract` 章节,列出单元测试、合同测试、冒烟测试、联调测试、必要技术审查、测试环境和证据返回格式。 - 创建 `ProgressEvent(event_type='handoff_created', source='pmflow_os')` 作为可追踪起点,payload 记录 `runtime_target / prompt_package_id / repo_binding_id / boundary`。 - 返回最新 `ExecutionSummaryProjection`:`execution / qualityContract / acceptance / releaseGate / promptPackage / repoBindings / activeDevTasks / recentProgressEvents / recentDeliveries / warnings`。 错误: - `404 task_not_found`:任务不存在、跨 project 或跨 tenant。 - `422 repo_binding_not_found`:传入的 repo binding 不存在、跨 project/tenant 或不是 active。 边界: - PMFlow backend 只创建 handoff 合同、PromptPackage 与 progress event,不直接执行本机命令。 - 本地 `stdio`、宿主机配置写入和真实执行必须经过 Local Bridge、Codex、GitHub agent 或兼容 MCP host;PMFlow 后端不得写 `~/.codex/config.toml`。 ### 4.9 写回执行结果 ```text POST /pmflow-os/projects/{project_id}/execution-progress-events ``` 请求: ```json { "task_id": "123", "repo_binding_id": "456", "event_type": "pr_opened", "source": "codex", "branch_name": "codex/execution-result-protocol-p1", "commit_sha": "abc123def456", "pr_number": 77, "test_summary": "pytest 与 typecheck 通过", "blocker_summary": null, "execution_status": "pr_open", "delivery_artifacts": { "changed_files": [ {"path": "frontend/src/features/pmflow-os/pages/ExecutionBridgePage.tsx", "change_type": "modified", "summary": "展示交付证据包"} ], "commands_run": [ {"command": "npm run build", "status": "passed", "summary": "前端构建通过"} ], "test_outputs": [ {"name": "frontend build", "status": "passed", "summary": "构建与类型检查通过"} ], "screenshots": [ {"label": "Execution Bridge desktop", "artifact_ref": "artifact://execution-bridge-d11.png", "summary": "UI 改动截图证据"} ] } } ``` 行为: - 只记录 Codex / IDE / Local Bridge / GitHub agent 已产生的执行结果,不执行本机命令、不推送、不发布。 - 写入 `ProgressEvent` 时同时保留兼容 flat payload 与协议 envelope:`protocol_version='execution_result_protocol_v1'`、`execution_result={eventType, source, status, branchName, commitSha, prNumber, testSummary, blockerSummary, repositoryFullName, delivery_artifacts}`。 - 返回最新 `ExecutionSummaryProjection`,其中 `execution` 展示 branch/commit/PR/test/status,`qualityContract` 按测试证据计算必测项状态,`acceptance` 计算用户验收/技术审查门禁,`deliveryArtifacts / artifactCompleteness` 聚合 changed files、commands run、test outputs、screenshots、logs、risk notes、review checklist,`releaseGate` 基于 passed/failed/blocked/checks 事件、`acceptance.canEnterReleaseGate` 与 `artifactCompleteness` 推导 `ready / blocked / needs_confirmation / empty`,`truth-state.feed` 后续只读展示执行进展。 - `blocker_summary` 优先作为 failed/blocked 事件的客户可见阻塞原因;`test_summary` 优先作为测试类事件摘要。 - `delivery_artifacts` 只允许保存结构化摘要或外部 artifact ref,不保存无限长日志、二进制截图、secret、token 或宿主机文件内容。 边界: - 该接口是执行结果回写协议,不是任务创建、发布执行或命令代理;缺证据时只能返回 pending/needs_confirmation/blocked,不得伪造测试或发布成功。 ### 4.9a 记录交付证据审查动作 ```text POST /pmflow-os/projects/{project_id}/execution-artifact-review-actions ``` 请求: ```json { "task_id": "123", "action": "request_fix", "review_item_ids": ["missing_ui_screenshots", "failed_command_0"], "note": "请补 UI 截图并修复 build 失败后重新回写 delivery_artifacts。" } ``` 行为: - 读取当前 `ExecutionSummaryProjection.artifactReview.items`,校验传入审查项必须来自当前 task/project 的投影。 - 写入 `ProgressEvent(payload.protocol_version='artifact_review_action_v1')`,事件类型为 `artifact_review_requested / artifact_fix_recorded / artifact_recheck_ready`。 - 返回最新 `ExecutionSummaryProjection`,`artifactReview.actionHistory` 展示审查动作历史。 边界: - 该接口只记录交付证据审查/返工意图,不执行命令、不创建分支、不推送、不开 PR、不合并、不部署、不发布、不创建正式 Task、不写 Project Memory。 ### 4.9b 生成交付证据返工执行包 ```text POST /pmflow-os/projects/{project_id}/execution-artifact-rework-packages ``` 请求: ```json { "task_id": "123", "repo_binding_id": "456", "runtime_target": "codex", "review_item_ids": ["missing_ui_screenshots", "failed_command_0"], "note": "根据交付证据审查项生成返工执行包。" } ``` 行为: - 从当前 `artifactReview.items` 选择待返工项,生成新的 `PromptPackage(package_kind='execution_handoff', package_payload.handoff_type='artifact_rework')`。 - 返工包内必须包含 `rework_contract`:审查项、预期证据、上一轮 `delivery_artifacts`、当前 `artifactCompleteness` 和 callback 要求。 - 写入 `ProgressEvent(event_type='artifact_rework_package_created', payload.protocol_version='artifact_rework_package_v1')`。 - 运行端继续用 D9/D10 的运行端凭据和签名 `POST /pmflow-os/runtime/execution-packages` 领取;拉包响应返回 `package.reworkContract`。 边界: - 返工包仍只是上下文包,不执行命令、不创建分支、不推送、不开 PR、不合并、不部署、不发布、不创建正式 Task、不写 Project Memory。 - 普通 handoff 不得复用 `handoff_type='artifact_rework'` 的 PromptPackage,避免返工上下文污染新一轮普通执行。 ### 4.9c 返工结果关闭与 UI 证据验收 行为: - 运行端基于 `artifact_rework` 包重新回写 `/runtime/execution-results` 时,必须继续携带同一个 `prompt_package_id`。 - `ExecutionSummaryProjection.artifactReview.closure` 从 `artifact_rework_package_created / execution_package_pulled / execution_result_protocol_v1` 事件生成返工闭环,返回: - `items[].status = resolved | open` - `items[].evidenceRefs`:覆盖该审查项的 passed command/test、screenshot artifact ref、changed file 或 review checklist。 - `timeline[]`:`package_created / package_pulled / result_returned` 审计线。 - command/test/review checklist 的阻塞状态按同名最新证据优先计算;新 `passed` 证据可以覆盖旧 `failed/blocked` 证据,但旧事件仍保留在审计时间线和原始 `deliveryArtifacts.events` 中。 - Execution Bridge 与 Release Growth 必须展示同源 closure 和 UI screenshot artifact ref,避免只显示“证据完整”的笼统结论。 边界: - closure 只表示返工审查项被当前交付证据覆盖,不等于用户验收、技术审查通过、Project Memory 写回、合并、部署或发布。 ### 4.9d 发布门禁复检与执行写回证据链 行为: - `ExecutionSummaryProjection.releaseGate.releaseReadinessProof` 必须消费同一份 `artifactCompleteness / artifactReview.closure / acceptance / execution_memory_writeback`: - `status=awaiting_acceptance`:测试和交付证据已满足复检输入,但还未完成验收或技术审查。 - `status=awaiting_memory_writeback`:验收已完成,但执行结果还未写回 Project Memory。 - `status=ready`:测试、返工关闭、验收和 Project Memory 写回均已形成证据。 - `status=blocked`:仍有未关闭失败或阻塞证据。 - `acceptance.evidenceProof` 与 `releaseGate.releaseReadinessProof` 必须使用同一套未关闭失败证据判断;当 `artifactCompleteness.status=ready` 且 `artifactReview.closure.status=all_resolved/none` 时,历史 delivery artifact 里的 failed command/test/checklist 不得继续阻塞。 - 显式 `failed / blocked / test_failed` progress event 仍然 fail-closed,不能被 closure 自动覆盖。 - `execution_memory_writeback_v1` 必须把 `writeback_proof / release_readiness_proof / artifact_review / artifact_completeness` 写入 payload 与 Project Memory writeback metadata。 边界: - `releaseReadinessProof.status=ready` 只表示发布复检输入完整,不自动执行发布、不自动合并、不自动部署、不绕过最终人工确认。 ### 4.9e 创建运行端凭据与签名回流 ```text POST /pmflow-os/projects/{project_id}/execution-handoffs/{prompt_package_id}/runtime-credential POST /pmflow-os/runtime/execution-packages POST /pmflow-os/runtime/execution-results ``` 行为: - 登录态凭据创建接口只允许项目成员、`OWNER` 或 `REVIEWER` 对当前项目的 `execution_handoff` PromptPackage 生成短期运行端凭据。 - 凭据绑定 `tenant_id / project_id / task_id / prompt_package_id / repo_binding_id / runtime_target / allowed_sources / expires_at`;响应只返回一次 raw `secret`,数据库仅保存 `secret_hash`。 - 运行端拉取执行包和回流结果接口都不吃 JWT,必须提供 `X-PMFlow-Key-Id / X-PMFlow-Timestamp / X-PMFlow-Signature`,签名基串为 `"{timestamp}.{raw_body}"`,算法为 HMAC-SHA256。 - 执行包拉取请求体必须携带 `prompt_package_id / task_id / source / delivery_id / event_source_id`,成功后返回机器可读 `Project / Task / RepoBinding / PromptPackage / Project Memory context / Quality Contract / callback contract / forbiddenActions`,并写入 `ProgressEvent(event_type='execution_package_pulled', payload.protocol_version='runtime_execution_package_pull_v1')`;重复 delivery/source id 必须幂等复用。 - 回流请求体必须携带 `prompt_package_id`,并继续使用 `execution_result_protocol_v1` 的 `task_id / event_type / source / branch / commit / PR / test / blocker / delivery_id / event_source_id / delivery_artifacts` 元数据。 - 后端按凭据精确校验 handoff、任务、repo、source allowlist、过期时间和签名;通过后复用登录态执行结果写入服务,继续按 `delivery_id / event_source_id` 幂等。 - 前端 `/execution-bridge` 的执行源包区域只展示运行端接入包、示例 header、拉包 payload 和回写 payload,帮助 Codex / Local Bridge / GitHub agent 领取上下文并回传事实;它不是“开始执行”按钮,也不代表 PMFlow 后端获得宿主机命令执行权。 边界: - 运行端凭据不是长期 API token,不保存明文 secret,不可跨 handoff、跨 task、跨 repo 或跨 tenant 使用。 - 签名拉包只返回执行上下文,签名回流只接收执行结果 metadata;不得执行本机命令、写宿主机配置、创建分支、推送、开 PR、合并、部署、发布或写 Project Memory。 - 签名错误、source 不在 allowlist、handoff 不匹配、凭据过期或缺少 key 时必须显式失败,不得降级为匿名写入。 执行责任与分派边界: - 执行交接只能针对已属于当前 project / tenant 的正式 `Task`,不得针对 `pending_review` ChangeItem 直接创建 handoff。 - `Execution Capability Graph` 在 handoff 前产出执行模式建议:`ai_direct / ai_with_user_acceptance / ai_with_technical_review / needs_human_judgement / blocked`。 - 人类或 agent 的执行责任在 handoff 创建前后形成;在 ChangeSet 阶段最多展示建议 owner / reviewer / agent,不得写成正式 assignment。 - `ai_with_technical_review` 必须绑定 reviewer 或返回 warning / blocked,不得把 agent 执行结果直接视为完成。 - 缺 repo binding、runtime target、PromptPackage、测试命令、权限、回写证据或 reviewer 时,允许创建 draft handoff 或 blocked projection,但不得展示为已开始开发。 ### 4.10 记录执行验收 / 技术审查决策 ```text POST /pmflow-os/projects/{project_id}/execution-acceptance-decisions ``` 请求: ```json { "task_id": "123", "decision": "accept", "note": "测试证据和业务验收均通过", "evidence_event_ids": ["progress-event-id"] } ``` 行为: - 支持 `accept / request_changes / reject / request_technical_review / approve_technical_review`。 - `accept` 与 `approve_technical_review` 必须先存在 `test_passed` 或 `checks_passed` 证据;缺失时返回 `acceptance_test_evidence_required`。 - 若质量合同要求技术审查,`accept` 必须在 `technical_review_approved` 之后发生;否则返回 `technical_review_required`。 - 写入 `ProgressEvent(payload.protocol_version='execution_acceptance_decision_v1')`,记录决策、备注、证据 event id 与质量合同 id。 - 返回最新 `ExecutionSummaryProjection`,供 `/execution-bridge`、`/space` 和 `/release-growth` 消费。 边界: - 该接口只记录人工验收/技术审查决策,不执行 merge、deploy、release,也不写 Project Memory。 - `accepted / technical_review_approved` 不是 Project Memory commit;执行结果写回必须走 `execution_memory_writeback_v1` 明确动作。 ### 4.11 记录执行结果写回项目记忆 ```text POST /pmflow-os/projects/{project_id}/execution-memory-writebacks ``` 请求: ```json { "task_id": "123", "progress_event_ids": ["progress-event-id"], "result": "completed", "note": "验收通过后写回项目记忆" } ``` 行为: - 只允许当前 project / tenant 下的正式 `Task` 写回,不允许 pending ChangeItem 或候选任务写回。 - 必须已经完成用户验收:`acceptance.status=accepted` 且 `userAccepted=true`;仅技术审查通过不能代替用户验收。 - 必须存在 branch / commit / PR / test / checks / merged / failed / blocked 等执行结果证据;`accepted` 验收事件本身不算执行证据。 - 写入 `ProgressEvent(event_type='execution_memory_writeback', payload.protocol_version='execution_memory_writeback_v1')`,记录 result、note、task_status、evidence_event_ids、acceptance 与 quality_contract_id。 - `result=completed` 时将 Task 稳定状态更新为 `done` 并写 `completed_at`;`blocked / changes_requested` 写为 `blocked`。 - `Project Memory writebacks` 读模型会把该 ProgressEvent 投影为 `sourceType=execution_memory_writeback` 的写回记录。 - `releaseGate` 只有在测试证据、验收通过和执行写回三者都满足后才允许 `ready`;验收后未写回必须保持 `needs_confirmation / 等待写回项目记忆`。 错误: - `404 task_not_found` - `409 execution_acceptance_required` - `409 execution_evidence_required` - `409 writeback_already_exists` - `409 unresolved_blocker_exists` - `422 invalid_progress_event_ids` 边界: - 该接口只把已验收的执行事实写入 PMFlow 项目记忆读模型;不执行 merge、deploy、release、本机命令、外部推送或 ChangeSet commit。 - Space 只能消费该写回状态派生下一步提醒,不得直接调用写接口。 ## 5. ChangeSet 写入正式对象规则 `ChangeItem.objectType` 的提交规则: 有效 payload 生成规则: - `edited` 项优先使用 `edited_payload`,否则使用 `payload`。 - `PMFlowChangeItem.title / summary / diff` 是展示与审计主字段;payload 中同名字段只能补充,不能覆盖人工 edit 后的主字段。 - 每个正式对象 content/payload 必须写入:`source=pmflow_change_set_commit`、`change_set_id`、`change_item_id`、`evidence_ids`、`confidence`、`risk_level`、`committed_by`、`committed_at`。 - 所有正式写入必须带 `tenant_id` 查询边界;`truth_nodes` 历史模型若无显式 `tenant_id` 字段,必须通过所属 `project_id` 的 tenant 校验间接保证租户边界。 | objectType | 正式写入目标 | 必填字段 | 写入后前端状态 | | --- | --- | --- | --- | | `Requirement` | `truth_nodes(node_type='requirement')` | `title`、`summary`、`stage`、证据 | `confirmed` | | `Decision` | `truth_nodes(node_type='decision')` | `title`、`summary`、`owner`、证据 | `confirmed` | | `Task` | `truth_nodes(node_type='task')` + `tasks` | `title`、`description/summary`、`priority`、`acceptanceCriteria` | `draft` | | `Risk` | `truth_nodes(node_type='risk')` | `title`、`summary`、`riskLevel`、`mitigation`、证据 | `confirmed` | | `ModelDecision` | `project_model_bindings` 或 `model_recommendation_snapshots` 引用 | `catalog_item_id` 或推荐快照引用 | `confirmed` | | `Release` | `truth_nodes(node_type='release')` + release validation 引用 | `title`、`summary`、gate items | `check_pending/ready` | | `MetricSignal` | `feedback_ingests`、`revenue_events`、`roi_snapshots` 投影或 recommendation 草案 | source、value、window | `confirmed` | C2 V1 白名单: - 必须实现:`Requirement / Decision / Task / Risk`。 - 可实现但不阻塞 C2:`Release`。 - 暂缓实现:`ModelDecision / MetricSignal`,若收到这两类 item,必须返回 `422 unsupported_object_type`,不得假成功。 禁止规则: - 禁止 `accept` 时直接写正式对象。 - 禁止没有 evidence 的高风险项进入 `commit`。 - 禁止把 AI 生成内容直接投影为 `Project Memory` confirmed facts。 - 禁止让前端用本地 `promoteAcceptedToGraph` 代替后端 commit。 - 禁止 commit 后仍让 `activeChangeSetId` 指向已 committed 的 ChangeSet;projection 应选择最近 open/reviewed ChangeSet,或返回 `null`。 高风险 approval gate: - `risk_level=high` 的 item 必须存在同 item 的 `pmflow_approvals` 记录,且 `decision in ('approved','edited')`、`after_status in ('accepted','edited')`。 - 高风险 item 必须能解析到至少一个 evidence link;ChangeSet 级 evidence 可以继承给 item,但 response 里必须显式返回 `evidenceIds`。 - gate 失败时整个 commit 不写入正式对象。 ## 6. Execution Bridge 复用合同 PMFlow OS 不重造开发执行系统。执行桥复用: - `PromptPackage`:开发上下文包,创建接口为 `POST /projects/{project_id}/charters/{charter_id}/prompt-packages`。 - `RepoBinding / GitHubAppInstallation / GitHubAppRepository`:仓库与 GitHub App 授权状态。 - `TaskCodeLink`:任务与 branch/PR/commit 绑定。 - `ProgressEvent`:branch、commit、PR、test、blocker、manual progress 的统一回写事件;PMFlow OS 写入 `execution_result_protocol_v1` envelope,保留执行状态和外部执行证据。 - `ProgressEvent` 也承载 `execution_acceptance_decision_v1` 验收审计事件:只表达验收/技术审查决策,不表达合并、发布或项目记忆写入。 - `DevSession`:开发活跃会话。 - `GET /projects/{project_id}/dev-sync/summary`:当前执行桥最小真实读路径。 `ExecutionContext` 字段映射: | 前端字段 | 后端来源 | | --- | --- | | `taskId` | active dev task id | | `status` | `ProgressEvent.derived_task_status` + `Task.status` projection | | `prompt` | latest `PromptPackage.package_text` | | `commitLog` | recent `ProgressEvent.summary` / payload commit fields | | `prStatus` | `TaskCodeLink.pr_number` + progress event | | `testSummary` | test progress event / release validation summary | | `writebackStatus` | latest progress event workflow state | | `qualityContract` | latest execution PromptPackage payload 或正式 Task fallback 生成的测试合同 | | `acceptance` | progress event 中的测试、失败、技术审查、用户验收事件推导 | ## 7. 后续实施顺序 1. A3 最小真实读路径:已实现 `pmflow_os_api` read-only projection,提供 `truth-state` 与 `execution-summary`。 2. Phase B:已把 `/project-launch` 的草案确认接入真实项目创建和初始 Project Memory 写入。 3. Phase C1:已实现 ChangeSet/ChangeItem/Approval/EvidenceLink 表与 `accept / edit / defer` 审查 API。 4. Phase C2 backend:已实现 ChangeSet atomic commit,把 `accepted / edited` 写入 `truth_nodes / tasks / semantic_facts` 并补齐高风险 approval gate。 5. Phase C2 frontend:已把真实模式下的 `promoteAcceptedToGraph` 接到 `POST /pmflow-os/change-sets/{change_set_id}/commit`,commit 后 refetch truth-state。 6. Phase D:把 `ExecutionBridgePage` 切到 `execution-summary` 和 dev-sync 真实数据。 7. Phase D.2:通过 `POST /pmflow-os/projects/{project_id}/execution-handoffs` 创建执行交接合同,生成/复用 PromptPackage 并记录 `handoff_created` progress event 起点。 8. Phase D.6:通过 `POST /pmflow-os/projects/{project_id}/execution-memory-writebacks` 把已验收执行事实写回 Project Memory / Work Graph 读模型,并把 release gate 的 `ready` 前置条件收紧为测试证据 + 验收 + 执行写回。 9. Phase D.10:通过 handoff-bound runtime credential 支持 `POST /pmflow-os/runtime/execution-packages` 机器可读执行包领取,并继续用 `POST /pmflow-os/runtime/execution-results` 回写执行事实。 10. Phase D.11:`execution_result_protocol_v1` 新增 `delivery_artifacts`,`ExecutionSummaryProjection.deliveryArtifacts / artifactCompleteness` 成为 Execution Bridge、Release Gate、Project Memory writeback 与 `/space` next action 的同源交付证据;缺 changed files、commands run、test outputs、UI 截图或存在 failed artifact 时 fail-closed。 11. Phase D.12:新增 `ExecutionSummaryProjection.artifactReview` 与 `POST /execution-artifact-review-actions`,把交付证据缺口/失败项转为同源审查项,并记录 request_fix / record_fix / mark_recheck_ready 历史;该动作只记录返工意图,不执行命令或写 Project Memory。 12. Phase D.13:新增 `POST /execution-artifact-rework-packages`,把 artifact review items 重新包装为可被签名 `/runtime/execution-packages` 领取的 rework handoff package;运行端拉包响应带 `reworkContract`,但仍只生成上下文,不执行命令或写 Project Memory。 13. Phase D.14:`artifactReview.closure` 把 rework package、package pull 和 runtime result 串成返工闭环;新 passed command/test/checklist 可覆盖同名旧 failed evidence,Execution Bridge / Release Growth 展示 closure、timeline 与 UI screenshot artifact ref,但 closure 不自动验收、不写 Project Memory、不发布。 14. Phase D.15:`releaseGate.releaseReadinessProof / acceptance.evidenceProof / execution_memory_writeback_v1.writeback_proof` 共用返工闭环后的复检证据链;closure resolved 且 artifacts ready 时旧 failed artifact 不再阻塞,显式 failed/blocked/test_failed 事件仍 fail-closed;proof ready 不自动发布。 10. Phase E:把 Release/Growth 投影接入 release validation、feedback、revenue、ROI、compliance。 本文档若与后续实现不一致,必须先更新合同再改代码。