workspace-cli AINative 研发平台技术实现方案

本文描述 AI Native Core CLI、daemon、MCP 和 Worker 实现;后续 Web 服务、内嵌 SPA、认证、REST/SSE 和主 Agent Web Chat 见 AI Native Web 技术实现方案。

1. 技术目标

AINative 研发平台在现有 workspace-cli 架构上增量实现。底层仍使用 Go、Cobra、SQLite、Git worktree 和本机 provider CLI;新增本地 daemon、SQLite job queue、Agent provider runner、MCP server、artifact 管理和更细的 workflow 状态。

当前交付和验收覆盖 Codex 与 Claude Code provider。两者使用同一 job/run/MCP 状态边界,并分别验证命令协议、主 Agent 会话和 Worker 输出解析;真实 smoke 按本机 CLI 可用性执行。

核心原则:

2. 总体架构

flowchart TD
  User["用户"] --> MainAgent["主 Agent\nCodex CLI 交互会话"]
  MainAgent --> MCP["workspace mcp serve\n结构化控制面"]
  MCP --> Service["workspace service 层"]
  CLI["workspace CLI"] --> Service
  Daemon["workspace agent daemon"] --> Queue["SQLite job queue"]
  Daemon --> CoordLane["Coordinator lane\nmain Agent non-interactive"]
  Daemon --> WorkerA["Analysis Worker"]
  Daemon --> WorkerC["Coding Worker"]
  Daemon --> WorkerT["Testing Worker"]
  CoordLane --> ProviderM["Codex provider"]
  WorkerA --> ProviderA["Codex provider"]
  WorkerC --> ProviderC["Codex provider"]
  WorkerT --> ProviderT["Codex provider"]
  ProviderM --> MCP
  ProviderA --> MCP
  ProviderC --> MCP
  ProviderT --> MCP
  Service --> DB["workspace.db"]
  Service --> Artifacts["work/artifacts"]
  Service --> Git["bare repos + worktrees"]

本地进程分工:

3. 运行目录

现有目录保持不变,新增 artifacts 和 runtime 目录:

~/.workspace-cli/
  config.yaml
  workspace.db
  work/
    repos/
      <repo>.git
    requirements/
      <req-slug>/
        <repo>/
    releases/
      <release-slug>/
        <repo>/
        .publish/
          <repo>/
    artifacts/
      requirements/
        <req-slug>/
          analysis/
          development/
          testing/
          bugs/
      releases/
        <release-slug>/
          test-runs/
            <test-run-id>/
    runtime/
      mcp/
      jobs/
      logs/

artifact 文件使用 Markdown 或 JSON:

4. 配置结构

扩展 config.Config:

type Config struct {
    Home       string
    DBPath     string
    WorkDir    string
    ReposDir   string
    ReqDir     string
    ReleaseDir string
    ArtifactDir string
    RuntimeDir  string
    Tools      Tools
    Agent      AgentConfig
}

type AgentConfig struct {
    DefaultReviewPolicy string
    DefaultMainAgent string
    DefaultTestCommand string
    CoordinatorWatchIntervalMs int
}

config.yaml 新增:

artifacts_dir: "~/.workspace-cli/work/artifacts"
runtime_dir: "~/.workspace-cli/work/runtime"
agent_default_review_policy: "no_high_risk"
agent_default_main_agent: "main-codex"
agent_default_test_command: ""
agent_coordinator_watch_interval_ms: 2000

已有简单 YAML parser 只能解析平铺 key。为控制变更范围,V1 继续使用平铺 key,不引入嵌套 agent: 配置。

5. SQLite 迁移

AINative 基础表使用 migration 0003_ai_native_workflow;后续兼容迁移依次为 0004_ai_native_atomic_hardening 和 0005_ai_native_hardening。0005 为 requirements 增加 acceptance_criteria、priority、analysis_review_policy_id、development_review_policy_id,旧记录使用 priority 100,策略为空时回退到全局默认策略。

5.1 扩展 requirements

新增列:

manual_active 表示旧命令创建的需求,不进入 AINative 自动流程。通过 req submit 创建的需求默认 pending_acceptance。

SQLite 不能可靠地通过 ALTER TABLE ADD COLUMN 为旧表新增外键约束;这些新增 ID 字段由 service 层校验引用存在、角色匹配和状态转换合法性,并新增普通索引用于查询。

5.2 扩展 releases

新增列:

这些新增 ID 字段同样由 service 层校验;旧 release 默认 manual_release,不自动进入 AINative 测试/发布状态机。AINative release 的 workflow_status 取值为 pending_testing、testing、testing_completed、pending_release、releasing、released、stale、publish_in_progress。default_test_command 来自 workspace release create --test-command,可为空。

5.3 新表 agents

CREATE TABLE agents (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  provider TEXT NOT NULL,
  role TEXT NOT NULL,
  model TEXT,
  system_prompt TEXT,
  system_prompt_path TEXT,
  command TEXT,
  sandbox TEXT,
  approval_policy TEXT,
  enabled INTEGER NOT NULL DEFAULT 1,
  health_status TEXT NOT NULL DEFAULT 'unknown',
  health_message TEXT,
  metadata_json TEXT,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Provider 取值:codex、claude。Role 取值:coordinator、analysis、coding、testing。

5.4 新表 worker_pools

CREATE TABLE worker_pools (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  role TEXT NOT NULL,
  agent_id INTEGER NOT NULL,
  parallelism INTEGER NOT NULL DEFAULT 1,
  max_workers INTEGER NOT NULL DEFAULT 1,
  poll_interval_ms INTEGER NOT NULL DEFAULT 2000,
  lease_seconds INTEGER NOT NULL DEFAULT 300,
  enabled INTEGER NOT NULL DEFAULT 1,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(agent_id) REFERENCES agents(id)
);

5.5 新表 worker_instances

CREATE TABLE worker_instances (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  pool_id INTEGER NOT NULL,
  worker_key TEXT NOT NULL UNIQUE,
  pid INTEGER,
  status TEXT NOT NULL,
  current_job_id INTEGER,
  heartbeat_at TIMESTAMP,
  started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  stopped_at TIMESTAMP,
  message TEXT,
  FOREIGN KEY(pool_id) REFERENCES worker_pools(id)
);

worker_instances.status 取值为 starting、idle、running、stopping、stopped、lost。parallelism 限制同一 pool 同时处于 leased/running 的 job 数;max_workers 限制同一 pool 存活 worker instance 数,存活状态包括 starting、idle、running、stopping。daemon 每轮调度先清理过期 heartbeat 的 instance 为 lost,再按 min(parallelism - active_jobs, max_workers - live_instances) 计算可启动槽位。

一次调度先串行完成 capacity、worker 和 job claim,随后为每个 claimed worker slot 启动独立 goroutine 并发运行 provider,等待本轮全部 outcome 后再生成 RunOnceResult。SQLite 状态读写使用单一共享连接串行短事务,provider 进程和文件系统工作仍并行执行,不能让数据库 transaction 跨越 provider 运行时间。claim query 对带 requirement_id 的 job 排除相同 requirement 的 leased/running job;只有不带 requirement 的 release-workspace job 才按 release_id 互斥。这样可以保护同一 workspace,同时允许同一 release 内不同 requirement 的 bugfix 并行。

5.6 新表 review_policies

CREATE TABLE review_policies (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL UNIQUE,
  stage TEXT NOT NULL,
  max_review_rounds INTEGER NOT NULL,
  pass_condition TEXT NOT NULL,
  max_allowed_severity TEXT NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

默认插入:

5.7 新表 artifacts

CREATE TABLE artifacts (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  entity_type TEXT NOT NULL,
  entity_id INTEGER NOT NULL,
  job_id INTEGER,
  run_id INTEGER,
  artifact_type TEXT NOT NULL,
  stage TEXT NOT NULL,
  version INTEGER NOT NULL,
  title TEXT NOT NULL,
  path TEXT NOT NULL,
  sha256 TEXT NOT NULL,
  is_final INTEGER NOT NULL DEFAULT 0,
  created_by TEXT NOT NULL,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);

entity_type 取值为 requirement、release、release_test_run,entity_id 按类型指向对应业务对象。需求设计、技术方案、开发报告和 bugfix 报告使用 entity_type=requirement;release 级说明使用 entity_type=release;测试报告使用 entity_type=release_test_run。job_id、run_id 指向 Agent 执行记录;多态 entity、artifact、job、run 的归属由 service 层校验,并在查询侧建立普通索引。

索引:

CREATE UNIQUE INDEX artifacts_version_unique
  ON artifacts(entity_type, entity_id, artifact_type, version);

CREATE UNIQUE INDEX artifacts_one_final
  ON artifacts(entity_type, entity_id, artifact_type)
  WHERE is_final = 1;

5.8 新表 requirement_status_events

CREATE TABLE requirement_status_events (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  requirement_id INTEGER NOT NULL,
  old_status TEXT,
  new_status TEXT NOT NULL,
  actor TEXT NOT NULL,
  reason TEXT,
  job_id INTEGER,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(requirement_id) REFERENCES requirements(id)
);

5.8.1 新表 release_status_events

CREATE TABLE release_status_events (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  release_id INTEGER NOT NULL,
  old_status TEXT,
  new_status TEXT NOT NULL,
  actor TEXT NOT NULL,
  reason TEXT,
  test_run_id INTEGER,
  job_id INTEGER,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(release_id) REFERENCES releases(id)
);

test_run_id 和 job_id 由 service 层校验归属。release test start、test pass/fail、scope stale、publish confirmation reject、publish start、publish-in-progress 和 publish success 都必须写入该表,供 release watch、release status 和主 Agent 展示。

所有改变 AINative workflow 的 production store API 必须把状态更新和 status event 放在同一个 transaction 中。requirement submit 还要把 requirement row、repo bindings 和初始 event 一起提交;Agent assignment 与状态推进、analysis final -> pending development、daemon requirement/release transitions 都使用带 actor、reason、job/test-run scope 的 transactional operation。测试专用 raw setter 不进入 production 调用路径。

5.9 新表 agent_jobs

CREATE TABLE agent_jobs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  job_key TEXT NOT NULL UNIQUE,
  role TEXT NOT NULL,
  job_type TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'queued',
  priority INTEGER NOT NULL DEFAULT 100,
  requirement_id INTEGER,
  release_id INTEGER,
  bug_id INTEGER,
  agent_id INTEGER,
  worker_pool_id INTEGER,
  input_json TEXT NOT NULL,
  result_json TEXT,
  attempts INTEGER NOT NULL DEFAULT 0,
  max_attempts INTEGER NOT NULL DEFAULT 3,
  lease_owner TEXT,
  lease_expires_at TIMESTAMP,
  not_before TIMESTAMP,
  started_at TIMESTAMP,
  completed_at TIMESTAMP,
  failed_at TIMESTAMP,
  last_error TEXT,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(requirement_id) REFERENCES requirements(id),
  FOREIGN KEY(release_id) REFERENCES releases(id),
  FOREIGN KEY(agent_id) REFERENCES agents(id),
  FOREIGN KEY(worker_pool_id) REFERENCES worker_pools(id)
);

状态:queued、leased、running、succeeded、failed、blocked、waiting_user_input、cancelled。

bug_id 指向 requirement_bugs.id,由 service 层校验;只有 job_type=bugfix 的 job 可以设置。

5.10 新表 agent_runs

CREATE TABLE agent_runs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  job_id INTEGER NOT NULL,
  attempt INTEGER NOT NULL,
  provider TEXT NOT NULL,
  agent_id INTEGER NOT NULL,
  worker_key TEXT,
  command TEXT NOT NULL,
  cwd TEXT NOT NULL,
  stdout_path TEXT,
  stderr_path TEXT,
  output_json_path TEXT,
  exit_code INTEGER,
  status TEXT NOT NULL,
  started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  completed_at TIMESTAMP,
  error TEXT,
  FOREIGN KEY(job_id) REFERENCES agent_jobs(id),
  FOREIGN KEY(agent_id) REFERENCES agents(id)
);

5.11 新表 agent_run_events

CREATE TABLE agent_run_events (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  run_id INTEGER NOT NULL,
  job_id INTEGER NOT NULL,
  requirement_id INTEGER,
  release_id INTEGER,
  event_seq INTEGER NOT NULL,
  event_type TEXT NOT NULL,
  visibility TEXT NOT NULL DEFAULT 'user',
  severity TEXT NOT NULL DEFAULT 'info',
  message TEXT NOT NULL,
  payload_json TEXT,
  artifact_id INTEGER,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(run_id) REFERENCES agent_runs(id),
  FOREIGN KEY(job_id) REFERENCES agent_jobs(id),
  FOREIGN KEY(requirement_id) REFERENCES requirements(id),
  FOREIGN KEY(release_id) REFERENCES releases(id)
);

索引:

CREATE UNIQUE INDEX agent_run_events_seq_unique
  ON agent_run_events(run_id, event_seq);

CREATE INDEX agent_run_events_job_created
  ON agent_run_events(job_id, created_at, id);

事件类型至少包含:run_started、provider_output、tool_call、artifact_created、review_result、test_output、approval_requested、blocked、run_completed。visibility=debug 的事件只在 --verbose 或显式 tail 时展示;token、API key、环境变量 secret 不写入事件。

event_seq 只能由 AppendAgentRunEvent service 方法生成,调用方不传入序号。该方法使用 BEGIN IMMEDIATE 或等价写锁事务读取同一 run_id 当前最大 event_seq,插入 max + 1,并返回插入后的事件;runner 的 stdout、stderr、tool call 和 approval 事件必须串行经过这个方法,避免并发写入重复序号。artifact_id 如果不为空,service 必须校验 artifact 存在且属于同一 requirement/release/test-run 上下文;V1 不增加 DB 外键,保持和 artifacts.job_id/run_id 一致的 service 校验策略。

5.12 新表 human_approval_requests

CREATE TABLE human_approval_requests (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  approval_key TEXT NOT NULL UNIQUE,
  requirement_id INTEGER,
  release_id INTEGER,
  release_test_run_id INTEGER,
  job_id INTEGER,
  run_id INTEGER,
  approval_type TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'pending',
  title TEXT NOT NULL,
  prompt TEXT NOT NULL,
  payload_json TEXT,
  options_json TEXT,
  default_option TEXT,
  response_json TEXT,
  requested_by TEXT NOT NULL,
  responded_by TEXT,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  responded_at TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(requirement_id) REFERENCES requirements(id),
  FOREIGN KEY(release_id) REFERENCES releases(id),
  FOREIGN KEY(release_test_run_id) REFERENCES release_test_runs(id),
  FOREIGN KEY(job_id) REFERENCES agent_jobs(id),
  FOREIGN KEY(run_id) REFERENCES agent_runs(id)
);

状态:pending、approved、rejected、cancelled。类型至少包含:requirement_clarification、artifact_finalization、implementation_blocker、test_command_missing、publish_confirmation、provider_permission。

同一业务 scope 内,同一 approval_type 只能存在一个 pending request;重复触发时更新原 request 的 updated_at 和提示摘要,不创建重复确认项。scope 按类型固定:需求澄清、方案定稿和实现阻塞使用 requirement_id,测试命令缺失使用 release_test_run_id,发布确认使用 release_id + release_test_run_id,provider 权限使用 job_id/run_id。如果 scope 字段缺失,service 必须拒绝创建 approval。

payload_json 和 response_json 必须按 approval_type 使用稳定结构:

5.12.1 新表 provider_permission_grants

CREATE TABLE provider_permission_grants (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  approval_id INTEGER NOT NULL,
  job_id INTEGER NOT NULL,
  run_id INTEGER,
  scope TEXT NOT NULL,
  sandbox TEXT NOT NULL,
  approval_policy TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'active',
  expires_at TIMESTAMP NOT NULL,
  used_at TIMESTAMP,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(approval_id) REFERENCES human_approval_requests(id),
  FOREIGN KEY(job_id) REFERENCES agent_jobs(id)
);

状态:active、used、expired、revoked。用户 approve provider_permission 后,service 创建 grant,把关联 job 恢复为 queued;grant 必须保存非空 sandbox 和 approval_policy,且二者来自用户 response。下一次 runner 启动前读取同一 job 的 active grant,校验未过期、scope 覆盖本次请求、sandbox 和 approval_policy 都存在后,才把 grant 应用到 provider 命令。grant 使用后写 used_at/status=used;过期 grant 或缺少授权参数时不得继续使用。用户 reject 时不创建 grant,job 保持 blocked 或标记 failed。

5.13 新表 requirement_bugs

CREATE TABLE requirement_bugs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  requirement_id INTEGER NOT NULL,
  release_id INTEGER,
  test_run_id INTEGER,
  title TEXT NOT NULL,
  description TEXT NOT NULL,
  severity TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'open',
  repo_id INTEGER,
  file_path TEXT,
  reproduction TEXT,
  created_by_job_id INTEGER,
  fixed_by_job_id INTEGER,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  closed_at TIMESTAMP,
  FOREIGN KEY(requirement_id) REFERENCES requirements(id),
  FOREIGN KEY(release_id) REFERENCES releases(id),
  FOREIGN KEY(repo_id) REFERENCES repos(id)
);

test_run_id、created_by_job_id、fixed_by_job_id 由 service 层校验存在性和归属,避免循环外键让 migration 顺序变脆。

5.14 新表 release_test_runs

CREATE TABLE release_test_runs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  release_id INTEGER NOT NULL,
  test_agent_id INTEGER,
  status TEXT NOT NULL DEFAULT 'queued',
  test_command TEXT,
  test_command_source TEXT NOT NULL DEFAULT 'explicit',
  working_dir TEXT,
  summary_artifact_id INTEGER,
  started_at TIMESTAMP,
  completed_at TIMESTAMP,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(release_id) REFERENCES releases(id),
  FOREIGN KEY(test_agent_id) REFERENCES agents(id)
);

summary_artifact_id 指向 entity_type=release_test_run、entity_id=<release_test_run_id>、artifact_type=test_report 的 artifact,由 service 层校验。release_test_runs.status 取值为 queued、running、waiting_user_input、passed、failed、blocked、cancelled;waiting_user_input 只用于等待 test_command_missing 等人工确认,用户补充命令后回到 queued,用户选择 block 后进入 blocked。

test_command_source 由 service 层校验稳定取值,V1 不加 DB CHECK 约束:

5.15 新表 release_test_run_requirements

CREATE TABLE release_test_run_requirements (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  release_test_run_id INTEGER NOT NULL,
  release_id INTEGER NOT NULL,
  requirement_id INTEGER NOT NULL,
  repo_id INTEGER,
  repo_name TEXT NOT NULL,
  requirement_workflow_status TEXT NOT NULL,
  feature_branch TEXT,
  feature_commit_sha TEXT,
  release_commit_sha TEXT,
  included_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY(release_test_run_id) REFERENCES release_test_runs(id),
  FOREIGN KEY(release_id) REFERENCES releases(id),
  FOREIGN KEY(requirement_id) REFERENCES requirements(id),
  FOREIGN KEY(repo_id) REFERENCES repos(id)
);

CREATE UNIQUE INDEX release_test_run_requirements_unique
  ON release_test_run_requirements(release_test_run_id, requirement_id, repo_name);

创建 test run 时,service 必须把当前 active release scope 按 requirement + repo 写入快照;同一需求覆盖多个 repo 时写多行。repo_id 可为空以兼容尚未落库的 repo 绑定或历史测试数据,repo_name 必填并参与唯一约束。feature_commit_sha 记录该需求在该 repo 的 feature 分支提交,release_commit_sha 记录 release worktree 中该 repo 的集成提交,二者都不是需求全局字段。发布前必须比较当前 active release 的 requirement 集合、repo 集合和每个 requirement + repo 的 feature/release commit 与当前 passed test run 快照;任一集合或提交不一致时,旧 test run 失效,release 进入 stale 或 pending_testing,并要求重新 integrate/test。

6. Go 包边界

新增或扩展包:

7. Provider runner

7.1 Interface

type ProviderRunner interface {
    Health(ctx context.Context, agent store.Agent) agent.HealthResult
    Run(ctx context.Context, run agent.RunRequest) agent.RunResult
}

type RunRequest struct {
    WorkspaceHome string
    RuntimeDir string
    JobKey string
    JobID int64
    JobToken string
    Attempt int
    Provider string
    Model string
    AgentID int64
    WorkerKey string
    CWD string
    Prompt string
    PermissionScope string
    Sandbox string
    ApprovalPolicy string
    MCPServerCommand string
}

ToolConfigPath 表示 provider 专用工具配置文件:Codex 生成 job/session scoped 的 config.toml 作为审计和等价配置来源,同时通过 -c mcp_servers.workspace_cli.* 注入当前进程,避免覆盖用户已有 CODEX_HOME 中的登录态;Claude 使用 --mcp-config 指向的 JSON 文件。CodexHome 在实现中表示 Codex runtime 配置目录,不应强制写入 provider 环境变量。

7.2 Codex 默认命令

codex exec
  --model <configured-model-if-present>
  --json
  --cd <cwd>
  --skip-git-repo-check
  --sandbox workspace-write
  -c approval_policy="never"
  -c mcp_servers.workspace_cli.command="<workspace-binary>"
  -c mcp_servers.workspace_cli.args=["mcp", "serve", "--home", "<workspace-home>", "--capability-token", "<job-token>"]
  --output-last-message <job-runtime>/output.json
  <prompt>

Codex runner 在启动前必须创建 work/runtime/mcp/<job-key>/codex/config.toml,配置内容只暴露一个 stdio MCP server:

[mcp_servers.workspace_cli]
command = "<workspace-binary>"
args = ["mcp", "serve", "--home", "<workspace-home>", "--capability-token", "<job-token>"]

不要为 Codex 使用 --mcp-config;该参数属于 Claude Code。Codex Worker 和主 Agent 都不应把 CODEX_HOME 改到临时目录,否则真实 Codex 会丢失用户登录态并出现 401。实际启动命令使用 -c mcp_servers.workspace_cli.command=... 和 -c mcp_servers.workspace_cli.args=[...] 注入同一 MCP server;生成的 config.toml 用于审计、session 记录和排障。主 Agent 的交互式 Codex 会话沿用用户默认 CODEX_HOME,通过 -c 注入 coordinator token,并保留 --ask-for-approval on-request。

如果 job 只读,例如分析或测试 Review,可以使用 --sandbox read-only,但分析阶段需要写 artifact 时由 MCP 工具写入,不要求文件系统写权限。

daemon 构造 worker RunRequest 时读取绑定 Agent 配置。model 非空时分别传给 Codex/Claude 的 --model。内联 system_prompt 和 system_prompt_path 文件内容按此顺序拼接,再以 Agent system instructions 与 Job input 两段组成最终 prompt;两者都为空时保持原始 job input,兼容既有作业。prompt 文件读取失败时在 provider 进程启动前终止本次执行,不能静默忽略配置;worker/coordinator job 使用相同 retry/max-attempts 状态机保存 path-specific error,普通 worker instance 返回 idle,达到最大次数的 pre-run failure 必须显式进入 failed。终态写入成功后 scheduler 将该 job 视为已处理,不把原错误上抛为 daemon fatal error。

provider 工作目录与控制面 home 必须分离。带 workspace_path 的 Coding/testing job 使用该路径作为 CWD,并在启动前校验 workspace 和 artifact 目录存在且为目录;不带 workspace_path 的 analysis/coordinator job 使用 work/runtime/agent-workspaces/job-<id>/attempt-<n>。交互式主 Agent 使用 work/runtime/main-agent/<agent>/<session>/workspace。MCP config 和 WORKSPACE_CLI_HOME 仍指向真实 workspace home,但 Codex --cd、CommandSpec.Dir 和 Claude process CWD 不得指向包含 workspace.db 的 home 根目录。

如果 job 曾因权限不足创建 provider_permission approval,runner 重试前必须读取同一 job 的 active provider_permission_grants。只有 grant 未过期、scope 覆盖本次请求、且规范化 workspace_policy 和 approval_policy 都存在时,才能扩大当前登记代码 worktree 内的权限;原始 sandbox 只用于审计,不能直接决定执行参数。否则继续保持 job blocked 或重新请求用户确认。

7.3 Claude 默认命令

claude -p
  --model <configured-model-if-present>
  --output-format stream-json
  --mcp-config <mcp-config.json>
  --permission-mode acceptEdits
  --system-prompt-file <prompt-file>
  <prompt>

Claude provider 的 --mcp-config 使用 job-scoped 配置文件,只暴露 workspace-cli MCP server。

7.4 输出采集

每次 run 写入:

work/runtime/jobs/<job-key>/<attempt>/
  prompt.md
  stdout.jsonl
  stderr.log
  result.json

runner 必须边读取 provider stdout/stderr 边写 agent_run_events,让 job watch 和主 Agent 可以实时展示执行过程。原始输出仍写入 stdout.jsonl 和 stderr.log;DB event 保存摘要、事件类型、关联对象和输出文件路径/offset,摘要写入前必须做 secret redaction。单条 provider output 超过摘要上限时,DB 只保存“输出已省略”的摘要、原始字节数和 raw 文件路径,完整内容只能从 runtime 文件读取。runner 完成后解析 provider 最后一条 assistant 消息,写入 agent_runs,并把结构化 artifact 创建交给 MCP 工具或 service 层。

当 provider 输出表示需要用户澄清或确认时,runner 不继续猜测:通过 service 创建 human_approval_requests,写入 approval_requested event,并把 job 标记为 waiting_user_input。

8. Job 调度

8.1 Claim 规则

daemon 对每个 enabled worker pool 执行事务,worker pool 只处理 analysis、coding、testing 三类 job。claim 前必须计算当前 pool 的 active job 数和 live worker instance 数;当 active job 数已达到 parallelism,或 live worker instance 数已达到 max_workers 且没有 idle instance 可复用时,本轮不得 claim 新 job:

UPDATE agent_jobs
SET status = 'leased',
    lease_owner = ?,
    lease_expires_at = datetime('now', '+' || ? || ' seconds'),
    attempts = attempts + 1,
    updated_at = CURRENT_TIMESTAMP
WHERE id = (
  SELECT id FROM agent_jobs
  WHERE status = 'queued'
    AND role = ?
    AND (not_before IS NULL OR not_before <= CURRENT_TIMESTAMP)
    AND attempts < max_attempts
  ORDER BY priority ASC, created_at ASC, id ASC
  LIMIT 1
)
RETURNING *;

如果 SQLite driver 不支持 RETURNING 的目标环境出现问题,改成 BEGIN IMMEDIATE、SELECT、UPDATE、COMMIT。

claim 成功后,daemon 优先复用该 pool 的 idle instance;没有 idle instance 且 live instance 数小于 max_workers 时创建 starting instance 并启动 provider runner;runner 开始执行时 instance 变为 running 并写 current_job_id,job 完成后 instance 回到 idle 或在 daemon 停止时进入 stopping/stopped。任何路径都不得让 live instance 数超过 max_workers,也不得让 active job 数超过 parallelism。

daemon-generated worker key 使用 <lease-owner>-pool-<pool-id>-<sequence>,sequence 必须跳过该 pool 所有 retained worker rows,不按 live count 回退。若另一 daemon 在 create 窗口抢先占用候选 key,当前 daemon 识别已存在 key 并尝试下一 sequence;单 daemon lost/stopped replacement 绝不能触发 unique constraint。

同一轮 claim 完成后,各 worker slot 的 provider runner 必须并发启动;RunOnce 等待本轮所有 runner 完成并汇总 completed/failed/retried 计数。带 requirement 的 job 以 requirement workspace 为互斥 scope;release-only job 以 release workspace 为互斥 scope。相同 scope 的 queued job 必须等待当前 leased/running job 退出 active 状态后才能 claim。

role=coordinator 的 job 不由 worker pool claim。daemon 使用 agent_default_main_agent 建立固定并行度为 1 的 coordinator lane,复用同样的 lease、run 记录和 retry 逻辑,避免多个主 Agent 同时为同一需求做相互冲突的分配决策。

8.2 Heartbeat

Worker instance 每 10 秒更新:

daemon 启动时把过期的 leased 或 running job 恢复为 queued,除非 attempts >= max_attempts,这种情况标记为 failed。

8.3 Retry

provider 退出非零时:

8.4 Workflow watch loop

daemon 每 agent_coordinator_watch_interval_ms 扫描 workflow 状态,并用幂等 service 方法补齐缺失 job:

8.5 实时 watch 和人工确认流程

实时 watch 使用 SQLite 事件流,不引入远程服务:

人工确认流程:

  1. Agent、daemon 或 service 发现需要用户判断,调用 CreateHumanApprovalRequest。
  2. service 写 human_approval_requests,同时写 agent_run_events.event_type=approval_requested 和 requirement/release 状态事件,保证 watch 能立即显示。
  3. 关联 job 进入 waiting_user_input 或 blocked;业务 workflow_status 保持当前阶段。
  4. 用户通过主 Agent 或 CLI respond。
  5. service 写响应、关闭 approval,并根据响应把 job 恢复为 queued、取消 job,或创建新的 coordinator/analysis/coding/testing job。
  6. artifact_finalization 被 approve 时,service 在关闭 approval 的同一事务中 finalize 需求设计和技术方案两类 artifact;任一 artifact 不存在、类型不匹配或不属于该需求时拒绝响应并保持 approval pending。
  7. publish_confirmation 被 reject 时,service 保持 release pending_release 并写 release_status_events next action;被 approve 且 confirm=true 时,只记录确认。publish 由后续 release_publish 单独触发,且仍要重新检查 dirty guard、external commit、release test run 的 requirement+repo+commit 快照和测试状态。
  8. provider_permission 被 approve 时,service 校验 response 包含 scope、expires_at、sandbox 和 approval_policy,再创建 provider_permission_grants 并把 job 恢复为 queued;被 reject 时保持 blocked 或标记 failed。
  9. 每次响应都写 requirement/release status event 和 run event,保证审计可追踪。

9. 状态机

需求状态只允许通过 service 方法推进。

允许转换:

pending_acceptance -> pending_analysis
pending_analysis -> analyzing
analyzing -> analysis_completed
analysis_completed -> pending_development
pending_development -> developing
developing -> development_completed
development_completed -> pending_testing
pending_testing -> testing
testing -> pending_development   # bugfix reopen
testing -> testing_completed
testing_completed -> pending_release
pending_release -> releasing
releasing -> released

特殊规则:

每次需求转换写入 requirement_status_events。

release 状态只允许通过 service 方法推进。允许转换:

manual_release -> pending_testing
pending_testing -> testing
testing -> testing_completed
testing -> stale
stale -> pending_testing
testing_completed -> pending_release
testing_completed -> stale
pending_release -> stale
pending_release -> releasing
releasing -> publish_in_progress
publish_in_progress -> released
releasing -> released

特殊规则:

每次 release 转换写入 release_status_events。

9.1 PrepareRequirementWorkspace

新增 service 方法:

func (s *Service) PrepareRequirementWorkspace(ctx context.Context, keyOrSlug string) (PrepareRequirementWorkspaceResult, error)

语义:

10. Artifact 管理

artifact 类型:

版本规则:

文件命名:

<artifact-type>-v<version>.md
<artifact-type>-final-v<version>.md

用户编辑 artifact 时创建新版本,created_by=user。 CLI 入口为 workspace req artifact create <req> --type <artifact-type> --content-file <path>,也支持 --content <text>;新版本创建后默认不自动 final,用户需要通过 req artifact finalize 或 artifact_finalization approval 选择终稿。

11. MCP server

11.1 Transport

V1 实现 stdio MCP:

workspace mcp serve --home <home> --capability-token <token>

主 Agent 可以用长期 coordinator token;Worker 使用 job-scoped token。

本地健康检查使用:

workspace mcp health --home <home>

health command 生成短期 coordinator capability,通过同一个 Server.Serve stdio JSON-RPC 边界发送 tools/list,要求无 RPC error 且 tools 非空。输出 status=available、transport=stdio、tool count 和 tool names;它不复用用户或 job token,也不执行任何业务 tool call。

stdio scanner 必须设置明确的有界 request limit。V1 上限为 4 MiB,覆盖 artifact/approval 等结构化 payload,同时避免无界内存增长;超过上限时返回 scanner error,不进入 tool dispatch。

11.2 Tool 权限

权限矩阵:

Tool coordinator analysis coding testing
req_submit yes no no no
req_list / req_show yes scoped scoped scoped
req_watch yes scoped scoped scoped
req_assign_agents yes no no no
req_update_workflow_status yes scoped scoped scoped
req_prepare_workspace yes no scoped no
artifact_create yes scoped entity scoped entity scoped entity
artifact_list / artifact_show yes scoped entity scoped entity scoped entity
artifact_finalize yes no no no
job_create yes scoped review scoped fix scoped bug
job_list / job_show yes scoped scoped scoped
job_update yes no no no
job_watch / run_tail yes scoped scoped scoped
approval_list / approval_show yes scoped scoped scoped
approval_respond yes no no no
bug_create yes no no scoped
bug_list / bug_update yes no no scoped
release_create yes no no no
release_test_start / release_test_status yes no no scoped
release_status / release_watch yes scoped scoped scoped
release_integrate yes no no scoped
release_publish yes with confirmation no no no

approval_respond 的 MCP 权限只给 coordinator,worker token 不能代表用户确认。CLI workspace approval respond 不走 MCP 权限矩阵,直接以本地用户身份调用 service;主 Agent 通过 MCP respond 时必须传入“用户在聊天中明确选择”的 structured response,service 将审计字段写成 coordinator relay,而不是 worker 自动决策。

job_update 是 coordinator 管理工具,worker token 不允许自行修改 job 状态,只能通过 runner/service 的受控完成、失败、阻塞和等待用户输入路径推进。bug_update 是 MCP/service 工具,用于测试 Agent 或 coordinator 在 scoped release/requirement 范围内关闭或更新测试 bug;V1 CLI 只提供 workspace req bugs list 和 workspace release bugs list 查询入口,不新增通用 workspace bug update 命令。

release_test_start 对应 CLI workspace release test start <release> [--agent <name>] [--test-command <cmd>],负责通过同一 service 方法创建或排队 release test run。release_test_status 对应 CLI workspace release test status <release>,返回当前或最近 test run、status、test_report artifact id/path、test_command_source 和 pending approval 摘要。release_status 保持 release workflow 总览,不替代 release test 专用状态。

11.3 Tool 输入输出

所有 MCP tools 返回 JSON object,包含:

工具失败不 panic,返回可读错误并写 operation log 或 job error。

Artifact tools 使用同一套多态 entity schema:artifact_create、artifact_list、artifact_show、artifact_finalize 的输入必须包含 entity_type=requirement|release|release_test_run 和 entity_id;artifact_show 还必须包含 artifact_id,并校验 artifact 的 entity 与输入一致。Capability token 不只校验 tool 名,还必须按 entity_type 校验 scope:analysis/coding token 只能访问本需求 artifact,testing token 只能访问 scoped requirement、release 或 release_test_run artifact,coordinator token 可以访问所有 entity。testing token 访问 requirement artifact 时,release_test_run_id scope 优先使用 immutable test snapshot membership;没有 test-run scope 时才使用 active release membership。testing token 访问 entity_type=release_test_run 的 artifact、watch 或 status 时,必须校验 token 的 release_test_run_id 匹配,或该 test run 属于 token 的 release_id。输出至少包含 artifact_id、entity_type、entity_id、artifact_type、version、path、sha256、is_final 和 created_by。workspace req artifact ... 只是 entity_type=requirement 的便捷包装,底层仍调用通用 artifact service。

bug_create 在 MCP 和 service 两层校验 requirement membership。带 test-run scope 时 requirement 必须在 release_test_run_requirements snapshot 中;只有 release scope 时 requirement 必须是 active release_requirements membership。相同优先级用于 bug_list、bug_update 和 bug-scoped job_create:只要 token 有 release_test_run_id,bug 的 test_run_id 和 requirement snapshot 都必须匹配,不能先用 release_id 放宽。MCP 省略 test_run_id 时把 capability release_test_run_id 写入请求,显式指定不同 run 时在 service 之前拒绝;同 release 不能替代同 test-run。MCP 未显式提供 created_by_job_id 时使用 capability job_id,service 接受 requirement-scoped job,或 release 和 input release_test_run_id 都匹配的 release_test job,并把该 job id 写入 bug 和 requirement status event。

release-test daemon 解析 provider bug 输出时也必须先做 snapshot resolution:显式 requirement ID/key 与 repo ID/name 均只能解析到当前 release_test_run_requirements 行,不能直接信任正整数 ID,也不能在名称未命中时回退到唯一需求。service 再执行相同 membership guard 作为写入边界。store 在一个 transaction 中创建 bug、推进 requirement workflow、写 requirement status event,并在提供 run ID 时校验 run/job 关系后写 bug_created run event。

当 capability 带 release_test_run_id 时,MCP auth helper 使用 test-run-first 规则:requirement 以 immutable snapshot 判定;job 以 input release_test_run_id 或 bound bug 判定;approval 以 approval test-run 或 scoped job 判定;release-test artifact 只接受 exact run。job_create 对 input scope 执行 default-and-reject。requirement/release watch 在返回前过滤其他周期的 jobs、approvals、bugs、events、test runs 和 active membership;run-scoped token 的 release_test_start 与 release_integrate 被拒绝。只有不带 test-run scope 的 release capability 才能使用 active release fallback。

job_create 的空 input 先规范化为 JSON {},再注入 test-run scope。requirement_status_events V1 没有 test_run_id 列,因此 MCP run-scoped view 通过 event job_id -> agent_jobs.input_json.release_test_run_id/bound bug 归属过滤;不能证明归属的 event fail closed。该过滤同时应用于 req list、show 和 watch,不影响 coordinator 完整审计。

publish_confirmation response 由 service 先规范化和校验:choice=confirm 生成 approved + confirm=true,其他 approved response 必须从最终 response JSON 读到 true confirmation,否则保持 pending。store transaction 再更新 approval,并在 commit 前写 release status event;approval 带 run scope 时同时写 approval_responded run event。approve/cancel 使用标准 <approval_type> approval <status> reason,reject 保留 release 当前状态与 next action 的专用诊断。任何 event insert 失败都回滚 approval response。

缺测试命令的新 test cycle 使用 CreateReleaseTestRunAwaitingCommand:同一 transaction 写 release_test_runs、从 active release scope 复制 release_test_run_requirements、创建 scoped test_command_missing approval,并写 approval-request release status event。daemon 不再先创建 run 后补 approval;对历史 waiting_user_input run 仍幂等执行 approval ensure 以自愈旧数据。

有测试命令的新 cycle 使用 CreateReleaseTestRunWithSnapshots,并与 awaiting-command 路径共享 createReleaseTestRunWithSnapshotsTx。daemon 在 queued/waiting run 上比较 snapshot 的 requirement/repo 集合、repo name、feature branch/SHA 和 release SHA;缺失、部分或不匹配时通过 test-run/status-event transaction 阻塞旧 cycle,不能创建 provider job。

invalid failed-output 使用 BlockInvalidReleaseTestOutput transaction,同时写 blocked test run、release_test_output_blocked run event、failed agent run、blocked job 和 release status diagnostic。service CreateBug 对 test-run scope 的空 repo 执行唯一 repo resolution,因此 daemon 和 MCP 共用同一个 concrete repo invariant。publish-confirmation specialized store responder重复校验 approved response JSON,generic responder 检测该 approval type 后委托 specialized path。

CreateHumanApprovalRequest 对 publish_confirmation 强制 initial status 为 pending,封闭 create-time terminal bypass。MCP test-run bug_create 通过 GetRunningAgentRunForJob 取得 capability job 的 active attempt,并把 run ID 传入 CreateRequirementBug transaction;没有 active run 时 fail closed。release worktree dirty 与 invalid-output 最终都调用 BlockReleaseTestExecution:它原子写 test-run block、可选 run event/run failure、job block 和 release event,适配 provider 启动前无 run 与结束后有 run 两种时序。

test-run-scoped MCP bug_create 先把 created-by job 绑定为 capability job,显式不同值 forbidden;canAccessBugCreate 重复校验。service 要求 TestRunID 同时携带 job/run 并验证归属,store 在 transaction 前重复 required-field guard。completeReleaseTest 对 parseReleaseTestOutput 的所有错误统一调用 BlockInvalidReleaseTestOutput,不再把 malformed output 送入普通 post-run retry。

release test completion 只接受 workflow_status=testing 且该 release 最新的 passed test run;同一 testing_completed + active_test_run_id 调用直接返回且不写重复 event。release scope、requirement reopen、feature/base/release branch 或 snapshot 变化进入 stale 时,AINative 路径在同一事务写 legacy status、workflow status 和 release event,manual release 继续保留 legacy workflow。stale 写入失败必须原样传播,不能只返回语义 stale error。bugfix 后的 re-integrate/retest 扫描 workflow_status=stale,并兼容历史 workflow_status=testing + status=stale 数据。

12. CLI 命令面

新增命令:

workspace agent add <name> --provider codex|claude --role coordinator|analysis|coding|testing
workspace agent list
workspace agent show <name>
workspace agent update <name>
workspace agent health <name>
workspace agent remove <name>

workspace worker add <name> --role analysis|coding|testing --agent <agent>
workspace worker list
workspace worker update <name> --parallelism <n> --max-workers <n>
workspace worker enable <name>
workspace worker disable <name>

workspace ai start [--agent <name>]
workspace agent daemon start
workspace agent daemon status
workspace agent daemon stop

workspace mcp serve

workspace job list [--status queued|running|failed|waiting_user_input|blocked]
workspace job show <job-key>
workspace job watch <job-key> [--follow]
workspace job retry <job-key>
workspace job cancel <job-key>
workspace run tail <run-id> [--follow] [--raw] [--unsafe-unredacted]

workspace req submit <title> [--description <text>] [--repo <name>]
workspace req watch <req> [--follow]
workspace req assign-agents <req> --analysis-agent <name> --coding-agent <name> --test-agent <name>
workspace req prepare-workspace <req>
workspace req artifact create <req> --type <artifact-type> [--stage analysis] [--title <title>] [--content <text>|--content-file <path>]
workspace req artifact list <req>
workspace req artifact show <req> <artifact-id>
workspace req artifact finalize <req> <artifact-id>
workspace req advance <req> <workflow-status>
workspace req bugs list <req> [--status open|fixed]

workspace artifact list --entity-type <requirement|release|release_test_run> --entity-id <id>
workspace artifact show <artifact-id>

workspace release create <title> --req <key> [--req <key>] [--key <slug>] [--test-command <cmd>]
workspace release test start <release> [--agent <name>] [--test-command <cmd>]
workspace release test status <release>
workspace release status <release>
workspace release watch <release> [--follow]
workspace release bugs list <release> [--status open|fixed]

workspace approval list [--status pending]
workspace approval show <approval-key>
workspace approval respond <approval-key> --choice <choice> [--message <text>] [--response-json <json>]
workspace approval respond <approval-key> --choice approve --final-requirement-design-artifact <id> --final-technical-design-artifact <id>
workspace approval respond <approval-key> --choice approve --test-command <cmd>
workspace approval respond <approval-key> --choice approve --confirm
workspace approval respond <approval-key> --choice approve --scope <scope> --expires-at <time> --sandbox <mode> --approval-policy <policy>

旧命令继续可用。README 和帮助文本必须明确 AINative 命令是高级协作模式。

13. 阶段 Loop 算法

13.1 分析 Loop

create analysis_generate job
for round in 1..max_review_rounds:
  analysis agent writes requirement_design and technical_design artifacts
  create analysis_review job
  review result = read review artifact
  if policy passes:
    mark analysis_completed
    stop
  create analysis_revise job with review artifact as input
mark blocked if max rounds exhausted

13.2 开发 Loop

ensure final requirement_design and technical_design exist
call PrepareRequirementWorkspace
mark developing
derive development cycle from final technical_design artifact
create implementation_plan job for the cycle
for each step:
  create cycle-scoped implementation_step job
  run coding agent in requirement workspace
  if result contains implementation_blocker.reason:
    create implementation_blocker artifact
    atomically create continue/replan/block approval and block source job
    stop the development loop pending user decision
  create cycle-scoped implementation_step_review job
  if review passes:
    continue
  create cycle-scoped implementation_step_fix job
after all steps:
  create implementation_report job from current-cycle steps and reviews only
  call FinishRequirement
  if requirement stage ready:
    mark development_completed

首个开发周期保留既有不带 cycle suffix 的 job key;后续周期的 plan key 绑定新的终稿 technical_design artifact,step、Review、fix 和 report key 使用新 implementation_plan artifact ID 作为 suffix。Review 轮次和报告聚合都必须按 implementation_plan_artifact_id 过滤,旧周期作业无论成功、失败或仍排队,都不能影响当前周期。

调度器在 queued stale job 清理、claim 后、provider 启动前和 provider 运行期间执行 current-cycle check。运行中的 development provider 使用可取消 context;requirement 离开 pending_development|developing,或 source plan job 绑定的 technical design 不再是当前终稿时,daemon 取消 provider 和 job,恢复 worker idle,并且不进入失败重试或 success post-processing。

implementation_step 和 implementation_step_fix job input 的 result_contract.blocked 声明 implementation_blocker 对象,至少要求非空 reason,可选 title、Markdown content 和用户决策 prompt。同一次 run 的 post-processing retry 复用同一个 blocker artifact 和 pending approval;新的 run 再次阻塞时创建新 artifact version 和 run-scoped approval key。同一 requirement 的不同 source job 不能复用 pending blocker approval。approval、approval_requested 实时事件和 source job blocked 状态在同一 SQLite 事务内提交。

13.3 测试和 bugfix Loop

release integrate
create release_test_run with resolved test_command
verify every release repo worktree is clean
if any worktree is dirty:
  block release_test job and test run
  write release diagnostic event
  stop before provider starts
run testing agent in release workspace
verify every release repo worktree is still clean
if testing agent changed a worktree:
  reject provider result
  mark provider run failed
  block release_test job and test run
  write release_workspace_modified run/release events
  wait for explicit cleanup and retry
if no command can run:
  create test_command_missing approval
  mark test_run waiting_user_input
  if user provides test_command:
    save supplied command
    mark test_run queued
    return to release test claim
  if user chooses block:
    mark test_run blocked
    stop
if bugs found:
  for each bug:
    in one store transaction:
      create requirement_bug
      set requirement pending_development
      append requirement status event with actor/reason/source job
    rollback bug and workflow if event write fails
    create bugfix job for coding agent
    req reopen
    coding agent fixes feature branch
    req finish
  release integrate again
  rerun test
else:
  mark requirements testing_completed
  mark release testing_completed with active_test_run_id
  create publish_confirmation approval for active_test_run_id
  mark release pending_release
  mark requirements pending_release

14. 安全与恢复

15. 测试策略

16. Review 加固实现