03-C-控制与接口.md 28.6 KB

03-C-控制与接口

接口分三层:项目层接口(第 13 节新增,对应控制台的项目创建/人工交互)、Org Graph 层接口(对两个后端一视同仁,架构文档 7.2 节)、Work Graph 层接口(MVP 阶段以 Claude Code 原生动态工作流为准,架构文档 10.1 节方案 A)。所有接口默认 auth: system_internal(MVP 单用户,无外部开放 API)。

3.-1 c_pick_folder(架构文档 13.1 节决策 5)

  • method + path:POST /api/system/pick-folder
  • 语义:控制台前端是本地 Web 应用,无法直接调用 OS 原生文件夹选择对话框;此接口由本机常驻的后端进程代为拉起系统对话框(macOS osascript、Windows/Linux 对应平台方案),返回用户选中的真实绝对路径
  • input_contract:{}(无需参数,对话框本身是模态的,由后端进程所在操作系统渲染)
  • output_contract:成功 { selected_path: string };用户取消对话框 { selected_path: null }(不算错误)
  • idempotent:否(每次调用弹出新的对话框交互)
  • errors:
    • DIALOG_UNAVAILABLE(不可重试):后端所在环境不支持拉起原生对话框(如无图形界面的纯服务器环境),控制台应提示改用手动路径输入作为兜底
  • owner_team:control-plane

3.0 c_project_create

  • method + path:POST /api/projects
  • input_contract:{ target_folder_path: string(required), name: string(optional), init_git_if_missing: boolean(required) }
  • output_contract:成功 { project_id, has_git_repo, graphlemon_subdir_initialized }
  • idempotent:是——同一 target_folder_path 重复调用直接返回已有 project 记录(见 01-M 1.0 幂等约束)
  • side_effects:若 has_git_repo=false 且 init_git_if_missing=true,执行 git init;创建 <target_folder_path>/.graphlemon/ 子目录
  • errors:
    • PATH_NOT_FOUND(不可重试):文件夹不存在
    • PATH_NOT_WRITABLE(不可重试):无写权限
    • GIT_INIT_DECLINED(不可重试):非 Git 仓库且用户未确认初始化
  • owner_team:control-plane

3.0.1 c_project_get / c_project_list

  • GET /api/projects/:project_id、GET /api/projects
  • idempotent:是
  • 说明:MVP 控制台 UI 不强制暴露完整项目列表交互(架构文档 13.1 节决策 2),但接口按多项目设计,供未来扩展

3.1 c_task_create

  • method + path:POST /api/tasks
  • input_contract:{ project_id: string(required), goal_text: string(required), task_type: enum('goal'), created_via: enum('api','human_console', default='api') }
  • output_contract:成功 { task_id, status: 'queued' };失败见 errors
  • idempotent:否(每次调用创建新任务)
  • transaction:单表插入 + 一条 execution_event(event_type=task_status_changed),需同一事务
  • side_effects:写入 task 表;若 org_concurrency_config.max_concurrent_goals 已达上限,任务落 queued 但不触发调度;写入 execution_event 供看板实时推送
  • errors:
    • INVALID_PARAM(不可重试):goal_text 为空或 project_id 不存在
  • audit_trace:trace_id、actor=system|human、business_id=task_id
  • owner_team:graph-engine

3.1.1 c_bug_report_create

  • method + path:POST /api/bug-reports
  • 语义:控制台人工反馈 bug 的入口,区别于 Validator 自动生成的 c_bug_record_create(3.10 节),复用同一张 bug_record 表但 source=human
  • input_contract:{ project_id: string(required), description: string(required), repro_steps: string(optional), related_task_id: string(optional) }(project_id 是 2026-07-31 订正新增——原文遗漏了它,但 execution_event.project_id 是 NOT NULL(01-M 1.9),bug_record 表自己没有 project_id 列,related_task_id 留空时("视为新发现的独立问题")没有任何字段能推导出 project_id,写 execution_event 会失败;U-023 实现时发现,按 c_task_create 同款处理方式把它变成必填)
  • output_contract:成功 { bug_id, status: 'open' }
  • idempotent:否
  • side_effects:写入 bug_record(source=human, status=open);写入 execution_event(event_type=bug_recorded);异步触发 Validator 认领该 bug 进行 triage(复用 04-P p_validator_root_cause_trace,见该节新增的人工接入分支)
  • errors:
    • INVALID_PARAM(不可重试):description 为空;project_id/related_task_id 不存在

3.2 c_task_list / c_task_get

  • GET /api/tasks?project_id=&status=&org_node=&keyword=(project_id 必填,2026-07-31 订正补上——原文漏写,控制台单项目 MVP 下仍需要用它按项目过滤)、GET /api/tasks/:task_id
  • output_contract:c_task_list 返回分页数组;c_task_get 返回单条 task + 关联 artifact 列表 + 关联 bug_record 列表 + 关联 work_graph_run 列表(各自带解析后的 graph_manifest 和 work_node_execution 列表,2026-07-31 订正补上——v_task_detail 的 to-do 树(02-V §2.6)需要这份数据,原 output_contract 没写全)
  • idempotent:是
  • errors:NOT_FOUND(不可重试,仅 c_task_get);INVALID_INPUT(不可重试,仅 c_task_list):缺少 project_id

3.3 c_org_node_trigger

  • POST /api/org-nodes/:org_node/trigger
  • input_contract:{ task_id: string(required) }
  • 语义:Org Graph 调度器将 task.assigned_org_node 指向的 Org Agent 唤起,Org Agent 内部先调用 c_work_graph_plan 再调用 c_work_graph_execute
  • 实现契约(架构文档 7.2 节决策,2026-07-29):底层是子进程调用 claude --agent <planner|coder|validator> -p "...",让整个会话以目标项目 .claude/agents/<org_node>.md 定义的 subagent 身份运行。三个 Org Agent 的身份(对应 SOUL.md)、memory、skills、tools、model 全部由这个 subagent 定义文件承载,c_org_node_trigger 本身只负责拼装任务上下文 prompt 和解析返回结果,不需要额外的角色隔离逻辑
  • idempotent:否(每次触发可能生成新的 work_graph_run)
  • errors:
    • TASK_NOT_READY(可重试):上游依赖 Artifact 未就绪
    • CONCURRENCY_LIMIT_REACHED(可重试):超过 max_concurrent_goals
    • USAGE_LIMIT_REACHED(新增,2026-07-29):语义同 3.6 节,Org Agent 级别的调用同样可能撞到 plan 额度,处理方式一致(等待重试,不转人工介入)
  • owner_team:graph-engine

3.4 c_work_graph_plan

  • POST /api/work-graph/plan
  • 语义:对应 Org Agent 的 Planning Skill 调用——输入任务上下文,输出结构化 graph_manifest(节点、边、fan-out/fan-in 分组、loop 规则),不执行,只规划
  • input_contract:{ task_id, org_node }
  • output_contract:{ run_id, graph_manifest }
  • idempotent:否
  • errors:PLANNING_FAILED(可重试,重试上限由调用方控制)
  • 约束(继承 10 节课程映射):graph_manifest 中每条边必须标注是否为"零 token 边"(纯代码聚合,如 flatten/dedupe)还是"需要 Agent 判断的边",规划阶段就要做这个区分,不能等执行时才发现

3.5 c_work_graph_execute

  • POST /api/work-graph/:run_id/execute
  • 语义:直接调用 Claude Code 原生动态工作流能力执行 graph_manifest 对应的编排脚本(agent()/parallel()/pipeline()),编排本身不消耗模型 token(MVP 阶段唯一执行后端,见架构文档 7.2 节 2026-07-29 决策——不再考虑 Hermes CLI 后端,此前的后端不对等声明已作废)
  • input_contract:{ run_id }
  • output_contract:{ status, result_artifact_refs }
  • idempotent:否
  • errors:
    • NODE_CONTRACT_VIOLATION(可重试,触发对应 work_node_execution 重试):某节点输出未通过 output_schema_ref 校验
    • BUDGET_EXCEEDED(不可重试,需人工介入):执行中触发 c_budget_check 拦截
    • CLASSIFIER_BLOCKED(不可重试,需人工介入):见下方权限模式说明——auto mode 分类器连续拦截 3 次或累计 20 次,-p 下无人可确认,进程中止

Claude Code ACP 后端的实现契约(A-1 已通过 spike 实测确认,见 spikes/a1-dynamic-workflows/,2026-07-29):

调用是 prompt-mediated 的,不是对 Claude Code 的直接函数调用。c_work_graph_execute 的具体实现步骤:

  1. 将 graph_manifest 对应的编排脚本写入/更新目标项目仓库的 .claude/workflows/<run_id>.js(随目标项目自身 git 历史版本化,而非 graphlemon 平台仓库)
  2. 以子进程方式调用: claude -p 'Run /<run_id> with args {...}' \ --output-format json \ --json-schema <output_schema_ref 对应的 JSON Schema> \ --permission-mode auto 不加 --bare:实测 --bare 会跳过凭据/登录态发现(报 Not logged in,与是否有 workflow 无关,是 --bare 本身的限制),必须用不带 --bare 的完整冷启动 权限模式选定为 auto,而非 bypassPermissions/--dangerously-skip-permissions(决策,2026-07-29):官方文档明确要求 bypassPermissions 只应在隔离容器/VM+无网络访问环境下使用,且"对 prompt injection 和意外操作零防护";graphlemon 当前的节点隔离手段是 git worktree(同机目录级隔离,非容器/VM 级),达不到这个前提。auto mode 用一个分类器对每个动作实时把关,默认拦截一批高危操作(curl|bash、密钥外泄、生产部署、force push、批量删除、IAM 变更等),同样能在 -p 下零 prompt 跑完,且和架构已有的预算护栏/人工升级理念一致。约束:auto mode 要求会话模型是 Claude Sonnet 5 / Opus 4.7+ / Fable 5(Anthropic API 上);架构文档 10 节"按节点分层选模型"给便宜/有界重复节点选模型时,需要在这个集合内选,不能选更早/更小的模型
  3. 解析返回 JSON 的 structured_output 字段作为 output_contract 的 result_artifact_refs 来源
  4. 用返回 JSON 的 total_cost_usd / usage 字段回填 budget_guardrail_config.current_usage(对应 c_budget_check)
  5. 子进程需以无 stdin 方式启动(< /dev/null 或等效),避免任何交互式提示导致挂起;实测确认无 stdin 时不会挂起、不会插入确认提示
  6. 若返回结果表明本轮运行被分类器连续拦截 3 次或累计 20 次(-p 下无人可确认,官方文档称此时 auto mode 会中止会话),映射为 CLASSIFIER_BLOCKED 错误,对应 04-P 状态机路由到 blocked_pending_human,blocked_reason='classifier_blocked',并把分类器拦截的动作摘要写入 v_task_detail,供人工判断是补 permissions.allow/白名单信任规则还是这确实是个危险操作

3.6 c_work_node_run

  • 内部接口(不对外暴露 HTTP,供 c_work_graph_execute 调用),语义对应课程"给每个节点一个契约"
  • input_contract:{ node_exec_id, input_payload, input_schema_ref } —— 校验失败直接拒绝,不进入执行
  • output_contract:{ output_payload } —— 必须通过 output_schema_ref 校验才算成功
  • idempotent:否
  • errors:
    • SCHEMA_VALIDATION_FAILED(可重试,重试即重新调用 Subagent,非幂等回放)
    • USAGE_LIMIT_REACHED(新增,2026-07-29,可重试但不是立即重试,见下方等待重试语义)
  • 约束:并行写代码的节点必须先申请 git_worktree_ref(见 01-M work_node_execution.git_worktree_ref),执行完成后清理 worktree 并合并回主分支
  • self-target 特例(新增,2026-07-30,见 05 节 §5.8):task.project_id 对应的 project.target_folder_path == graphlemon 平台自身安装路径 时,无论并行还是串行,一律强制申请 git_worktree_ref,不适用"仅并行时才强制"的一般规则;Coder/Validator 的自测/复核全部在 worktree 副本里跑,不碰主 checkout
  • 新增约束(架构文档 13.1 节决策 4):节点开始执行时必须先创建对应的 execution_log_file 记录(status=active),执行期间将 Claude Code ACP 的会话输出流式追加写入该文件,每次追加同时写一条 execution_event(event_type=log_appended);节点执行结束(成功或失败)后将 execution_log_file.status 置为 closed

Claude Code plan 额度耗尽的等待重试语义(架构文档 7.5 节决策,2026-07-29):

claude -p 的账号/plan 用量是一个会自然恢复的资源(5 小时滚动窗口 / 7 天窗口 / Opus 专属限额),耗尽时官方 CLI 直接终止请求并在文本里带上人类可读的恢复时间,例如 You've hit your session limit · resets 3:45pm、You've hit your weekly limit · resets Mon 12:00am。这类错误不应该路由到 blocked_pending_human(那是给需要人工判断的情况用的),而是自动等待+重试:

  1. 检测:claude -p 返回 is_error=true 且 result 文本匹配 /hit your (session|weekly|Opus) limit/i 时,判定为 USAGE_LIMIT_REACHED,从匹配的关键词提取 quota_limit_type(session|weekly|opus),写入 work_node_execution.quota_limit_type
  2. 状态转移:work_node_execution.status → waiting_for_quota,记录 quota_wait_started_at;不冒泡到 task.status,调度器继续跑队列里其他不依赖这个节点的工作(同 04-P budget_exceeded 的"跳过而非全局阻塞"模式)
  3. 退避轮询:不解析"resets 3:45pm"这种脆弱的人类可读文本(没有日期/时区锚点,跨天跨周边界容易解析错),改用容量更简单可靠的退避重试——等待间隔从 5 分钟起步,每次翻倍,上限 30 分钟(5/10/20/30/30/... 分钟),每次到点直接重新发起原本要跑的那次 claude -p 调用本身作为探测,成功即转入正常执行
    • 例外:quota_limit_type=opus 时不用等待退避——按官方建议直接把该节点这次调用降级到非 Opus 模型重试(需符合 03-C 3.5 节 auto mode 的模型约束:Sonnet 5 / Opus 4.7+ / Fable 5)
  4. 超时兜底(防止真正的账号/计费问题被无限期静默等待掩盖):quota_limit_type=session 累计等待超过 8 小时、或 quota_limit_type=weekly 累计等待超过 9 天仍未恢复,转 blocked_pending_human,blocked_reason='usage_limit_wait_timeout'
  5. 可见性:进入 waiting_for_quota 时写一条 execution_event(event_type=quota_wait_started),v_dashboard/v_graph_visualizer 用信息性样式(非告警)展示,见 02-V 2.2/2.7 节——这是自愈型等待,不需要人工介入,但应该在控制台可见

3.6.1 c_execution_log_get

  • GET /api/work-nodes/:node_exec_id/log
  • 语义:获取指定 Work Node 的原始执行日志(静态模式,用于已结束节点或首次加载)
  • input_contract:{ path: { node_exec_id }, query: { offset: int(optional), limit: int(optional), download: boolean(optional) } } —— 支持分页避免大文件一次性传输
  • output_contract:{ content: string, format, total_size_bytes, status };download=true 时返回文件流
  • idempotent:是
  • errors:
    • LOG_NOT_FOUND(不可重试):node_exec_id 不存在对应日志记录
    • LOG_PURGED(不可重试):日志已被定时清理任务删除,v_log_viewer 据此展示对应异常态

3.6.2 c_ws_log_tail(实时日志订阅)

  • protocol:WebSocket,WS /api/ws/work-nodes/:node_exec_id/log
  • 语义:订阅指定 Work Node 的实时日志追加事件,用于运行中节点的滚动查看
  • input_contract:{ path: { node_exec_id } }
  • output_contract(推送消息体):{ node_exec_id, appended_content: string, created_at }
  • idempotent:不适用(长连接)
  • errors:NODE_EXEC_NOT_FOUND(不可重试):连接建立时校验
  • 说明:节点执行结束后(work_node_execution.status 转为终态)服务端主动关闭该连接,前端应据此切换到 c_execution_log_get 的静态模式

3.7 c_artifact_write

  • POST /api/artifacts
  • input_contract:{ artifact_type, task_id, produced_by_run_id, file_path, content, depends_on_artifact_ids }
  • output_contract:{ artifact_id, git_commit_sha }
  • idempotent:否(artifact 不可变更,见 01-M 迁移约束)
  • side_effects:写文件 + Git commit(commit message 包含 task_id 与 artifact_type)
  • errors:GIT_COMMIT_FAILED(可重试)

3.7.1 c_artifact_get / c_artifact_list(2026-07-31 订正:c_artifact_get 此前只存在于机器可读的 sdd-mvcp-contract.json,正文一直没写;c_artifact_list 连 MVCP JSON 里都没有,v_artifact_browser 自己的过滤字段倒逼补上)

  • GET /api/artifacts/:artifact_id(c_artifact_get)、GET /api/artifacts?project_id=&task_id=&artifact_type=(c_artifact_list,project_id 必填)
  • output_contract:c_artifact_list 返回裸数组;c_artifact_get 返回单条 artifact 全部字段 + content(现读磁盘文件,artifact 表本身无 content 列)+ lineage(按 depends_on_artifact_ids 回溯的血缘链,oldest-first,含自身)
  • idempotent:是
  • errors:NOT_FOUND(不可重试,仅 c_artifact_get);INVALID_INPUT(不可重试,仅 c_artifact_list):缺少 project_id

3.8 c_skill_update

  • POST /api/skills/:skill_id/update
  • 语义:Skill 自主迭代的落地接口(架构文档 8 节决策 1)——允许 Validator 触发的自动改写立即生效,但必须产生独立 Git 提交
  • input_contract:{ skill_id, triggered_by_bug_id(required), new_content, change_summary(required) }
  • output_contract:{ iteration_id, after_git_commit_sha }
  • idempotent:否
  • transaction:文件写入 + Git commit 需原子完成(commit 失败则整体回滚,不留半成品 Skill 文件)
  • errors:MISSING_TRIGGER_REF(不可重试):triggered_by_bug_id 缺失时直接拒绝——不允许无来源的 Skill 变更

3.9 c_skill_rollback

  • POST /api/skills/:skill_id/rollback
  • input_contract:{ iteration_id(required) } —— 回滚到该次迭代之前的版本
  • output_contract:{ new_iteration_id }(回滚本身也生成一条新的 skill_iteration 记录)
  • idempotent:否
  • errors:ITERATION_NOT_FOUND(不可重试)

3.9.1 c_skill_diff / c_skill_list / c_skill_get(2026-07-31 订正:c_skill_diff 此前只存在于机器可读的 sdd-mvcp-contract.json,正文一直没写;c_skill_list/c_skill_get 连 MVCP JSON 里都没有,v_skill_library/v_skill_audit_log 自己的展示需求倒逼补上)

  • GET /api/skills/diff?before=&after=(c_skill_diff)、GET /api/skills(c_skill_list)、GET /api/skills/:skill_id/audit(c_skill_get 的落地形态——直接返回该 Skill 的 skill_iteration 列表,供 v_skill_audit_log 消费,不是单条 skill 记录)
  • output_contract:c_skill_diff 返回 { diff_text: string }(git diff <before> <after>,在 graphlemon 自身仓库执行——见 05 §5.4.1.4);c_skill_list 返回裸数组;c_skill_get 返回 skill_iteration 数组,按 applied_at 升序
  • idempotent:是
  • errors:NOT_FOUND(不可重试,仅 c_skill_get):skill_id 不存在;INVALID_INPUT(不可重试,仅 c_skill_diff):before/after 缺失

3.10 c_bug_record_create

  • POST /api/bug-records
  • input_contract:{ task_id, description, repro_steps, root_cause_category(required, enum), root_cause_detail(required), related_artifact_ids, suggested_route(required) }
  • output_contract:{ bug_id }
  • idempotent:否
  • errors:INVALID_ROOT_CAUSE_CATEGORY(不可重试):未落在 planning|coder|skill_defect|core_engine(新增,2026-07-30,见 01-M 1.6/05 节 §5.8)四类之一
  • 约束:root_cause_category=skill_defect 时必须同时创建 skill_iteration_suggestion,否则视为字段缺失(见 08 反模式门禁:不允许"空目标"式的归因);root_cause_category=core_engine 时不要求人工评审即可提交(用户明确否决"比照 org_graph_definition 强制人工 PR 评审"的原提案),但 c_org_loop_route 会将其路由到蓝绿部署+监控流程而非常规 fast_lane(见 3.11 节)

3.11 c_org_loop_route

  • POST /api/tasks/:task_id/route
  • 语义:Org-level Loop 的路由决策落地——Validator 判定结果驱动任务回到 Planner(full_replan)或直达 Coder(fast_lane),决策本身由 Agent 判断(Validator 分类),路由本身是确定性代码(架构文档 10 节课程映射:判断用 Agent,路由用代码)
  • input_contract:{ task_id, decided_route: enum('fast_lane','full_replan','manual_resume') }
  • output_contract:{ task_id, new_status, new_assigned_org_node }
  • idempotent:否
  • errors:
    • LOOP_LIMIT_REACHED(不可重试):task.loop_round 已达上限(3 轮),强制转 blocked_pending_human,不接受常规路由请求,只接受 manual_resume
  • core_engine 路由分支(新增,2026-07-30,见 05 节 §5.8):关联 bug_record.root_cause_category=core_engine 的任务,无论 Validator 给出的 decided_route 是 fast_lane 还是 full_replan,c_org_loop_route 都不直接按常规路由处理,而是在 Coder 完成修复、Validator PASS、worktree 分支 merge 回 graphlemon 自身仓库主分支之后,转交 p_deploy_supervisor_blue_green 流程(04-P)——即触发 Deploy Supervisor 的蓝绿部署与自动回滚机制,不是"合并即生效"

3.12 c_budget_check

  • 内部接口,c_work_graph_execute 执行前/中调用
  • input_contract:{ scope, estimated_usage }
  • output_contract:{ allowed: boolean, remaining_quota }
  • idempotent:是
  • errors:BUDGET_EXCEEDED(不可重试):触发后对应任务转 blocked_pending_human,并记录 blocked_reason='budget_exceeded'

3.13 c_concurrency_config_update / c_budget_config_update

  • PUT /api/settings/concurrency、PUT /api/settings/budget
  • input_contract:对应 01-M org_concurrency_config / budget_guardrail_config 的可写字段
  • output_contract:更新后的完整配置对象
  • idempotent:是
  • errors:INVALID_PARAM(不可重试):数值超出校验范围

3.13.1 c_log_retention_config_update

  • PUT /api/settings/log-retention
  • input_contract:{ retention_days: int(required, >0), max_total_size_mb: int(optional) }
  • output_contract:更新后的完整配置对象
  • idempotent:是
  • errors:INVALID_PARAM(不可重试):retention_days <= 0

3.14 c_ws_subscribe(实时事件订阅,架构文档 13.1 节决策 3)

  • protocol:WebSocket,WS /api/ws/projects/:project_id
  • 语义:控制台建立连接后订阅指定 project_id 下的全部 execution_event;服务端在 execution_event 写入的同一事务提交后立即推送给已订阅的连接
  • input_contract(连接建立时的订阅参数,query string):{ project_id: string(required), task_id: string(optional) } —— 传 task_id 时可选做服务端过滤,减少推送量
  • output_contract(服务端推送的消息体):{ event_id, event_type, task_id, run_id, node_exec_id, payload, created_at },字段与 execution_event 实体一一对应
  • idempotent:不适用(长连接)
  • errors:
    • PROJECT_NOT_FOUND(不可重试):连接建立时校验 project_id 不存在,直接拒绝连接
  • 断线重连约束:客户端重连后需带上 last_event_id 查询自该事件之后的遗漏事件(通过 c_task_get 系接口的时间线字段补齐,而非 WebSocket 层做消息重放缓冲,MVP 阶段简化处理)
  • owner_team:control-plane

3.15 Deploy Supervisor 控制操作(PH5 新增,2026-07-30,见 docs/supervisor-auto-rollback-design.md)

以下五个操作均由 Deploy Supervisor 进程调用,不是控制台前端直接调用的 HTTP API(Deploy Supervisor 是独立于 Graph Engine 之外的确定性 Python 进程,见 01-M 1.15 节),标记为内部接口。所有决策逻辑均为确定性代码,不接入任何 LLM 判断。触发前提:task 关联的 project.target_folder_path == graphlemon 平台自身安装路径 且 Validator 判定 PASS 后,worktree 分支已 merge 回主分支(见 3.11 节 core_engine 路由分支)。

c_deploy_supervisor_stage

  • 内部接口,语义:拉取合并后的主分支到全新目录(非原地 git pull),生成 deployment 记录
  • input_contract:{ git_commit_hash }
  • output_contract:{ deployment_id, status: 'staged' }
  • idempotent:否
  • side_effects:复制 PROD_DB_PATH 到一次性 candidate_db_path;用 supervisor/isolation/isolated_workspace.py 同款隔离原则拉起候选进程(subprocess.Popen,shell=False),监听临时 candidate_port
  • errors:CHECKOUT_FAILED(不可重试,转 blocked_pending_human):全新目录 checkout 失败(如磁盘空间不足)

c_deploy_supervisor_health_check

  • 内部接口,语义:对候选实例执行 process_alive/http_health/canary_task 三项 pre-cutover 检查(见 supervisor-auto-rollback-design.md §6)
  • input_contract:{ deployment_id }
  • output_contract:{ status: 'health_check_passed' | 'health_check_failed', signals: deploy_health_signal[] }
  • idempotent:是(可重复查询当前检查状态,但不重新触发候选进程重启)
  • errors:HEALTH_CHECK_TIMEOUT(不可重试,直接判定该项 fail,进入回滚路径 A,不重试——重试属于"给坏版本第二次机会",不符合 fail-closed 原则)
  • 约束:任一检查项 fail 立即整体判定 health_check_failed,不等待其余检查项跑完

c_deploy_supervisor_cutover

  • 内部接口,语义:蓝绿切换本体——仅在 c_deploy_supervisor_health_check 返回 health_check_passed 后才允许调用
  • input_contract:{ deployment_id }
  • output_contract:{ status: 'live', cutover_at }
  • idempotent:否
  • side_effects:Live 停止接受新的 c_org_node_trigger 调用(在途 work_node_execution 允许走到可安全中断的检查点,依赖既有持久化恢复机制,不强求优雅排空)→ Live 进程退出 → 候选进程改连 PROD_DB_PATH、改绑 LIVE_PORT → 候选成为新 Live;原 Live checkout 目录保留为 previous_instance_dir,不删除
  • errors:CUTOVER_FAILED(不可重试,转 blocked_pending_human):切换过程中候选进程未能正确绑定生产端口/生产库

c_deploy_supervisor_monitor

  • 内部接口,语义:post-cutover 监控窗口内周期性采样四类信号(见 supervisor-auto-rollback-design.md §6),窗口时长/任务数上限见 05 节 §5.9
  • input_contract:{ deployment_id }(由 Deploy Supervisor 自身的调度循环周期性调用,不是一次性调用)
  • output_contract:{ status: 'monitoring' | 'anomaly_detected' | 'monitoring_window_clean', latest_signal: deploy_health_signal }
  • idempotent:是
  • 约束:validator_approval_rate 信号从 execution_event/work_node_execution 按滚动窗口统计 Validator 节点 approved 占比,与该 deployment 之前的历史基线做纯算术比较,偏离 VALIDATOR_RATE_DEVIATION_THRESHOLD(05 节 §5.9)即判定 anomaly_detected——这是"改坏了的 validator"场景的核心检测点,判断全程不需要另一个 LLM 参与

c_deploy_supervisor_rollback

  • 内部接口,语义:回滚路径 A(pre-cutover,健康检查未过)与路径 B(post-cutover,监控期 anomaly_detected)的统一入口,具体步骤见 supervisor-auto-rollback-design.md §7
  • input_contract:{ deployment_id, rollback_reason }
  • output_contract:{ status: 'rolled_back' | 'health_check_failed' | 'rollback_failed' }
  • idempotent:否
  • side_effects:路径 A——终止候选进程、删除一次性 DB 副本、git revert 本次合并 commit、创建 bug_record(root_cause_category=core_engine);路径 B——用 previous_instance_dir 重新拉起旧版本、绑定 LIVE_PORT+PROD_DB_PATH、对复活的旧版本重跑一遍 pre-cutover 健康检查确认无误、git revert、创建 bug_record
  • errors:
    • ROLLBACK_FAILED(不可重试,转 blocked_pending_human,blocked_reason='rollback_failed'):连 previous_instance_dir 也起不来,或 git revert 冲突(见 supervisor-auto-rollback-design.md §10 开放问题 3)——这是本机制唯一保留的人工介入点,触发条件严格限定为"自动恢复机制本身失效",不是"代码判断谁对谁错"
  • owner_team:deploy-supervisor(独立于 graph-engine,进程边界见 01-M 1.15 节)