# 04-P-流程与状态流转 ## 4.1 流程:`p_org_task_lifecycle`(顶层任务生命周期) - `start_state`:`queued` - `end_state`:`done` | `blocked_pending_human`(终态之一,需人工介入才能继续) | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `queued` | `planning_brd_prd_sdd` | `c_org_node_trigger(planner)` | `c_work_graph_plan` + `c_work_graph_execute` | `max_concurrent_goals` 未超限 | `blocked_pending_human` | 0 | | `planning_brd_prd_sdd` | `coding` | `planner_work_graph_done` | `c_org_node_trigger(coder)` | 四类 Artifact(BRD/PRD/SDD/Benchmark)通过一致性/覆盖率校验 | `planning_failed` | 2 | | `planning_failed` | `planning_brd_prd_sdd` | `retry` | 重新触发 Planner Work Graph | `retry_count < 2` | `blocked_pending_human` | - | | `coding` | `validating` | `coder_work_graph_done` | `c_org_node_trigger(validator)` | Coder 自测(unit+integration test)通过 | `coding_failed` | 2 | | `coding_failed` | `coding` | `retry` | 重新触发 Coder Work Graph | `retry_count < 2` | `blocked_pending_human` | - | | `validating` | `done` | `validator_pass` | 关闭任务 | 全部 Benchmark/测试用例通过 | - | 0 | | `validating` | `routed_fast_lane` | `validator_fail` | `c_bug_record_create` + `c_org_loop_route(fast_lane)` | `bug_record.suggested_route=fast_lane` 且 `task.loop_round < 3` | `blocked_pending_human` | - | | `validating` | `routed_full_replan` | `validator_fail` | `c_bug_record_create` + `c_org_loop_route(full_replan)` | `bug_record.suggested_route=full_replan` 且 `task.loop_round < 3` | `blocked_pending_human` | - | | `routed_fast_lane` | `coding` | `route_applied` | `task.loop_round += 1`,直达 Coder | - | - | - | | `routed_full_replan` | `planning_brd_prd_sdd` | `route_applied` | `task.loop_round += 1`,回到 Planner | - | - | - | | `*`(任意态) | `blocked_pending_human` | `loop_round >= 3` OR `budget_exceeded` | 记录 `blocked_reason`,调度器跳过该任务、执行队列中其他可并行任务(架构文档 4.3/7.4 节) | - | - | - | | `blocked_pending_human` | 恢复到触发前状态 | `c_org_loop_route(manual_resume)` | 人工在 `v_task_detail` 点击"人工干预" | 需人工在管理后台确认 | - | - | 补充说明:`loop_round >= 3` 的判定复用架构文档第 10 节课程映射里 `loop-until-dry` 的思路作为**未来优化候选**——MVP 先用固定 3 轮上限(更简单、可预测),若后续 Validator 承担"未知规模缺陷扫描"类任务,再评估切换为连续 K 轮无新发现即停止的收敛判定(见 06 节验收锚点会标注为已知简化项,非本期强制要求)。 ## 4.2 流程:`p_work_graph_execution`(单次 Work Graph 执行生命周期) - `start_state`:`planning` - `end_state`:`done` | `failed` | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `planning` | `running` | `c_work_graph_plan` 完成 | 落 `graph_manifest`,调用 `c_work_graph_execute` | `graph_manifest` 通过反模式门禁(见 08 节) | `failed` | 0 | | `running` | `merging` | 全部 fan-out 节点 `done` 或 `filter(Boolean)` 后集合非空 | 执行 fan-in 边(零 token 代码边或 Agent 裁决边) | - | `failed` | 0 | | `merging` | `verifying` | fan-in 完成 | 触发本节点自身的验证规则(第 5.3 节生命周期"Merge/Verify"步骤) | - | `failed` | 0 | | `verifying` | `done` | 验证通过 | `c_artifact_write` 落最终产物 | - | - | - | | `verifying` | `reflecting` | 验证不通过 | 记录差距,决定重试路径 | `retry_count < node_level_max` | `failed` | 由具体 Work Node 定义 | | `reflecting` | `running` | reflection 决定重跑 | 回到受影响的最小子图(非整图重跑,对应课程 SDD 生成器"回灌策略:只回灌受影响子图") | - | - | - | | `running` | `blocked` | 节点失败且 `.filter(Boolean)` 后集合为空(全部并行分支失败) | 冒泡到 `p_org_task_lifecycle` 的 `*_failed` 态 | - | - | - | ## 4.3 流程:`p_validator_root_cause_trace`(Validator 根因溯源) - `start_state`:`test_failed` \| `human_reported`(新增第二个起点,架构文档第 13 节人工反馈 bug 诉求) - `end_state`:`bug_recorded` | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `human_reported` | `tracing_lineage` | `c_bug_report_create` 产生 `bug_record(source=human, status=open)` | Validator 认领该记录(`status: open→triaging`),若 `related_task_id` 为空则先反查最近相关 task | - | `tracing_failed` | 1 | | `test_failed` | `tracing_lineage` | 某功能点测试/benchmark 不通过 | 读取对应 SDD/PRD/BRD 版本 + Coder 实现记录(血缘追溯) | - | `tracing_failed` | 1 | | `tracing_lineage` | `judging_root_cause` | 血缘读取完成 | 多视角校验:正确性视角 / 需求完整性视角 / Skill 系统性缺陷视角(对应课程"多视角差异化校验") | 至少 2/3 视角一致才定案,否则升级人工 | `inconclusive_escalate` | - | | `judging_root_cause` | `bug_recorded` | 归因定案(`planning`\|`coder`\|`skill_defect` 三选一) | `c_bug_record_create` | `root_cause_category` 非空且有 `root_cause_detail` | - | - | | `judging_root_cause` | `inconclusive_escalate` | 多视角判断不一致 | 标记 `blocked_pending_human`,附带三视角原始判断供人工裁决 | - | - | - | | `bug_recorded` | `skill_iteration_triggered` | `root_cause_category=skill_defect` | `c_skill_update` | 必须提供 `triggered_by_bug_id` | `skill_update_failed` | 1 | 补充说明:`judging_root_cause→bug_recorded` 的动作在两条起点路径下语义略有差异——`test_failed` 起点是全新创建 `bug_record`(`c_bug_record_create`);`human_reported` 起点是对已存在的 `bug_record` 做字段补全式更新(`root_cause_category`/`root_cause_detail`/`suggested_route` 从 null 补齐,`status: triaging→routed`),不产生重复记录。 ## 4.4 流程:`p_budget_guardrail`(预算护栏) - `start_state`:`monitoring` - `end_state`:`paused` | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `monitoring` | `monitoring` | 每次 `c_work_node_run` 前调用 `c_budget_check` | 累加 `current_usage` | `current_usage < limit_value` | - | - | | `monitoring` | `paused` | `c_budget_check` 返回 `allowed=false` | 对应 `task` 转 `blocked_pending_human`,`blocked_reason='budget_exceeded'` | - | - | - | | `paused` | `monitoring` | 人工在 `v_budget_settings` 调高额度或人工 `manual_resume` | 恢复调度 | - | - | - | 补充:预算护栏和"平台层限额"(架构文档 7.5 节)是两条不同的路径,处理逻辑不同,不要合并成同一个 `blocked_reason`—— - **`budget_guardrail_config` 触发**(本节表格):这是人工主动配置的预算上限,超出后需要人工判断要不要提额,走 `blocked_pending_human`、`blocked_reason='budget_exceeded'` - **Claude Code plan 额度耗尽**(新增子流程 `p_usage_limit_wait`,见下方):这是账号/plan 自身的用量上限,会在固定时间窗口后自然恢复,不需要人工判断,走等待+自动重试,只有等待超时才升级到 `blocked_pending_human` ### 4.4.1 子流程:`p_usage_limit_wait`(Claude Code plan 额度等待重试,架构文档 7.5 节决策,2026-07-29) - `start_state`:`running` - `end_state`:`done`(恢复正常执行)或 `blocked_pending_human`(超时兜底) | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `running` | `waiting_for_quota` | `c_work_node_run`/`c_org_node_trigger` 返回 `USAGE_LIMIT_REACHED` | 记录 `quota_wait_started_at`/`quota_limit_type`,写 `execution_event(event_type=quota_wait_started)` | - | - | - | | `waiting_for_quota` | `waiting_for_quota` | 退避轮询到点(5→10→20→30 分钟,上限 30 分钟) | 重新发起原调用作为探测 | 距 `quota_wait_started_at` 未超时(`session`\|8h,`weekly`\|9d) | - | 不计入 `retry_count` | | `waiting_for_quota` | `running` | 探测调用成功 | 恢复正常执行流程 | - | - | - | | `waiting_for_quota` | `blocked_pending_human` | 距 `quota_wait_started_at` 超过对应超时上限 | `blocked_reason='usage_limit_wait_timeout'` | - | - | - | 补充:`quota_limit_type=opus` 不走上面的退避轮询——直接把该节点这次调用降级到非 Opus 模型重试(见 03-C 3.6 节),因为 Opus 专属限额和会话/周额度是独立的资源池,切模型能立即恢复工作,没必要等待。 `waiting_for_quota` 期间调度器不阻塞整体流水线,继续执行队列中其他不依赖该节点的工作,和 `budget_exceeded` 的"跳过而非全局阻塞"是同一模式(见 7.4 节)。 补充:`c_work_graph_execute` 使用 `auto` 权限模式(03-C 3.5 节决策,2026-07-29)时,若返回 `CLASSIFIER_BLOCKED` 错误(分类器连续拦截 3 次或累计 20 次,`-p` 下无人可确认导致会话中止),同样路由到 `blocked_pending_human`,`blocked_reason='classifier_blocked'`,与 `budget_exceeded`/`platform_quota_exhausted` 在 `v_task_detail` 分别展示,避免人工误判为同一类问题;此类阻塞的恢复路径是人工复核分类器拦截的具体动作,判断是补充信任规则(架构文档需补充"受信任基础设施"配置项,MVP 阶段留空,先走人工 `manual_resume`)还是这确实是个应该被拦下的危险操作。 ## 4.5 流程:`p_log_retention_cleanup`(日志定时清理,架构文档 13.1 节决策 4) - `start_state`:`idle` - `end_state`:`idle`(周期性流程,非一次性终结) | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `idle` | `scanning` | 定时触发(默认每日一次,具体周期由平台调度配置,非用户可配) | 扫描 `execution_log_file WHERE status='closed'` | - | `scan_failed` | 1 | | `scanning` | `purging` | 扫描完成,得到候选集合 | 按 `log_retention_config.retention_days` 过滤过期项;若配置了 `max_total_size_mb` 且总量超限,追加按 `created_at` 最旧优先的候选,直到总量回落到上限内 | - | - | - | | `purging` | `idle` | 逐条删除候选的物理文件 | 删除成功则 `execution_log_file.status→purged`,`purged_at=now()`,写入 `execution_event`(可选,非高优先级事件,用于审计不用于实时推送) | - | `purge_partial_failed` | 0 | | `purge_partial_failed` | `idle` | 部分文件删除失败(如文件被占用) | 记录失败项,保留 `status=closed` 待下次周期重试,不阻塞其余成功项 | - | - | - | 约束:清理过程只删除物理文件和更新 `execution_log_file` 状态,不删除 `execution_log_file` 记录本身、不删除任何 `execution_event`/`task`/`artifact` 等业务数据,保证"日志曾经存在过"这件事可审计(对应 01-M 1.13 节约束)。 ## 4.6 流程:`p_deploy_supervisor_blue_green`(PH5 新增,2026-07-30,见 `docs/supervisor-auto-rollback-design.md`) - `start_state`:`staged` - `end_state`:`finalized`(安全终态)| `blocked_pending_human`(唯一需人工介入的终态,触发条件严格限定为"自动回滚机制本身失败",不是"代码写得不好") 由 Deploy Supervisor(独立于 Graph Engine 之外的进程,见 01-M 1.15 节命名说明)驱动,触发前提:`bug_record.root_cause_category=core_engine` 的任务经 Coder 修复、Validator PASS、worktree 分支已 merge 回 graphlemon 自身仓库主分支(见 03-C 3.11 节 `core_engine` 路由分支)。全部状态转移均为确定性判断,不接入任何 LLM 判断。 | from | to | trigger | action | guard | error_state | retry_max | |---|---|---|---|---|---|---| | `staged` | `candidate_starting` | `c_deploy_supervisor_stage` 完成 | 全新目录 checkout(非原地 `git pull`),复制一次性 `candidate_db_path`,拉起候选进程 | - | `blocked_pending_human`(`CHECKOUT_FAILED`) | 0 | | `candidate_starting` | `health_check_running` | 候选进程启动完成 | 调用 `c_deploy_supervisor_health_check` | - | - | - | | `health_check_running` | `health_check_failed` | `process_alive`/`http_health`/`canary_task` 任一 fail 或超时 | 触发回滚路径 A(见下方) | - | - | 0(不重试,重试属于"给坏版本第二次机会",要重试整个自我修改需回到 Planner 重新出一版) | | `health_check_running` | `health_check_passed` | 三项检查全部通过 | 进入 cutover | - | - | - | | `health_check_passed` | `cutover_in_progress` | `c_deploy_supervisor_cutover` 调用 | Live 停止接受新 `c_org_node_trigger`,在途节点走到可恢复检查点 | - | `blocked_pending_human`(`CUTOVER_FAILED`) | 0 | | `cutover_in_progress` | `live` | Live 进程退出,候选切换到生产端口/生产库 | `cutover_at=now`,原 Live checkout 保留为 `previous_instance_dir` | - | - | - | | `live` | `monitoring` | cutover 完成 | `c_deploy_supervisor_monitor` 周期性采样四类信号 | - | - | - | | `monitoring` | `anomaly_detected` | 任一信号超出 05 节 §5.9 阈值(含 `validator_approval_rate` 偏离基线) | 记录信号快照到 `deployment.rollback_reason` | - | - | - | | `monitoring` | `monitoring_window_clean` | 监控窗口(`MONITORING_WINDOW_HOURS`/`MONITORING_MIN_TASK_COUNT` 先到者)内无 anomaly | - | - | - | - | | `monitoring_window_clean` | `finalized` | - | `previous_instance_dir` 可清理 | - | - | - | | `anomaly_detected` | `rollback_in_progress` | - | 触发回滚路径 B(见下方) | - | - | - | | `rollback_in_progress` | `rolled_back` | `previous_instance_dir` 重新拉起并通过健康检查 | 绑定 `LIVE_PORT`+`PROD_DB_PATH`,`git revert` 本次合并 commit,创建 `bug_record(root_cause_category=core_engine)` | - | - | - | | `rollback_in_progress` | `rollback_failed` | 旧版本也起不来,或 `git revert` 冲突 | - | - | `blocked_pending_human`(`blocked_reason='rollback_failed'`) | 0 | | `health_check_failed` | `rolled_back` | 回滚路径 A 执行完成 | 终止候选进程、删除一次性 DB 副本、`git revert`、创建 `bug_record(root_cause_category=core_engine)` | - | - | - | 补充说明(回滚路径 A vs B,见 `supervisor-auto-rollback-design.md` §7): - **路径 A(`health_check_failed → rolled_back`)**:Live 从未被动过,回滚成本最低——终止候选、删除一次性 DB 副本、`git revert`、发 `bug_record`。整个过程 Live 全程未受影响,调度立即可以继续处理下一个任务。 - **路径 B(`anomaly_detected → rollback_in_progress → rolled_back`)**:Live 已经是候选版本,需要真正"换回去"——用 `previous_instance_dir` 重新拉起旧版本,绑定生产端口/生产库(生产库全程未被替换,只是换了跑在它前面的代码进程,数据不受影响),对复活的旧版本重跑一遍 pre-cutover 健康检查确认无误,才判定 `rolled_back`。 - **`rollback_failed → blocked_pending_human` 是本流程唯一保留的人工介入点**,且明确限定触发条件仅为"自动恢复机制本身失效"(旧版本也起不来、DB 不可写等基础设施问题),不是"代码判断谁对谁错"——这一区分需要在 `v_task_detail`/控制台清楚展示,避免用户误以为又回到了"需要人工评审代码改得好不好"的模式(该模式已被用户明确否决,见 05 节 §5.8)。