Wave 7:最小化 Root-Orchestrator 架构计划(冻结 D1-D13 落地)

August 25, 2026 · View on GitHub

0. 定稿决策

  • Root Agent 是唯一 Orchestrator,"信息是否足够"由 Root 的 system prompt 判断,TypeScript 不做 criteria engine。
  • 6 概念模型:Project / PentestRun / Stage / AgentProfile / Delegation / Deliverable(File)。
  • Delegation 取代 Task + AgentRun:一次委托 = 一个 DSH child session;task_prompt 为不可变 snapshot。
  • Deliverable = 文件(workspace/stages/<NN>-<stage>/delegations/D-00N/ 目录),删除全部 store/journal 实体。
  • PTAP 整套删除;Worker 禁止 delegate,编排树永远只有 Root → Workers 一层。
  • One Workspace = One Primary Target = One PentestRun = One Git 仓库 = One active timeline = One Toolbox 容器 = Many Workers。

Root 工具面(4 个)pentester_delegate / pentester_cancel_delegation / pentester_advance_stage / pentester_rollback_stage。Root 不能使用 pentester_container_exec:per-Root-agent tools.restrict deny 只隐藏这一条 (deny 必须落在 Root 自己的 layer:官方 subagent child 会 join 父 preset, mount 级 deny 会把 container_exec 也挡给 Worker;且 tools.restrict 对未知名字 整体拒绝,不能把别的 preset 才注册的工具名加进来)。通用 subagent/job/bash/fs 工具由组合排除:本 deployment 把它们作为 per-preset 行(standard 等 preset 自带),pentester preset 组合不带 → Root 天然看不到。工具注册在 preset scope: 宿主不向 global registry 注册 pentester 工具(standard Session 完全看不到), preset 行 run-state.mjs 经宿主 pentester service 注册。

Worker 工具面(1 个)pentester_container_exec。不增加 fs/complete/submit/ status/sync/git 工具。

Bootstrap 位置(定稿)Pre-engagement 不创建 Worker —— 由 User + Root + ask_user_question 完成(targets / scope / RoE / language)。 首次初始化在 pentester_advance_stage:无 run.json 时, pentester_advance_stage({run, summary}) 承担 bootstrap —— 创建 workspace 骨架、 run.json、target 文件,git init + 初始 commit,然后同一调用完成 pre-engagement checkpoint 并激活 intelligence-gathering。pentester_delegate 不 bootstrap: 无 Run 时明确报错(先完成 pre-engagement 并调用 advance_stage 初始化)。

Root 每次推理前注入的 compact state 包含 Available AgentProfiles:当前 stage 的合法 AgentProfile 列表由 STAGE_DEFINITIONS.agentIds ∩ AgentProfile registry 生成(插件 apply 时写成 preset 目录 stage-profiles.json,run-state.mjs 同目录 读取),不硬编码第二套映射。Root 只从该列表选 agent id。

全 Workspace git 跟踪(Owner 要求完整回溯):不忽略 work/traffic/*.pcap*.mitm.gitignore 只保留 tmp/ cache/ *.log

远程阶段边界(§24):advance 时先 remote → local 同步 Worker 数据(本地 bind 下 no-op),再 promotion / summary / transition / git checkpoint / local → remote。

Worker 执行 = DeepSeek Harness 官方 Subagent seam(定稿): 不再维护自定义 ctx.agents.create() / agent.inject() / agent.followup() / agent.whenIdle() Worker lifecycle。Worker 走: ctx.subagents(Service,dsh-base 已挂载)→ provider spawn@deepseek-ai/dsh-subagent-spawn-in-process,dsh-base 已注册)→ durable continuable child(startContinuable / followup / interrupt;跨 Activation 持续,FIFO inbox,官方管理 cold resume)。无 ctx.jobs、无 one-shot SubagentRun.result/dispose。基础设施缺失(ctx.subagents / provider 不存在) fail loud,禁止 fallback 回自定义 lifecycle。Root 不获得通用 subagent/job/bash/fs 工具(组合排除 + per-Root deny,见 §0),只通过 pentester_* 领域工具编排。Worker prompt 拆分:persona = WORKER_BASELINE + AgentProfile.systemPrompt(官方 persona 模板);prompt = standalone task context(Delegation ID / Stage / Target / RoE / 目录 / 完成契约 / task_prompt)—— spawn child 不继承 parent transcript,所以 task_prompt 必须自包含。 worker toolFilter = { deny: [4 个 pentester Root 工具 + ask_user_question] }。Delegation ↔ childSessionId 绑定:startContinuable 发布后宿主立即把 childId 写入 Delegation.sessionIdpentester_container_exec 据此解析 worker work 目录并校验调用者身份)。

Pre-engagement 固定问卷(定稿):Pre-engagement 由 User + Root + 原生 ask_user_question 完成,使用固定结构问卷(五问一次调用): target_confirm / scope_confirm / exclusions_confirm / roe_confirm / language_confirm。不封装 pentester_ask_user,不临时加问。

1. 目标架构

User ⇄ DSH Root Session(pentester persona preset)
         │  Root 工具面 4 个(见上)

   Delegation(并行、可多个)── 每个对应一个 DSH child session
         │  Worker prompt = baseline + AgentProfile.systemPrompt
         │                 + host 注入 trusted metadata + task_prompt

   pentester_container_exec(dockerode;Root 不可见)

   workspace/stages/<NN>-<stage>/delegations/D-00N/   ← Deliverable 就是文件

   Worker 是 durable continuable child:写/更新 result.md 作为当前可交付结果,
   可接收 Root 的 send_message 后续;Root 自行判断再派 / advance / rollback

Root 每次 reasoning 前,宿主从 run.json 注入 compact state (target / branch / run 状态 / current stage / stage 状态 / delegations 摘要), 经 preset systemPrompt.context(text 函数每次 assembly 求值)实现;不注入 完整 run.json,不提供 status 工具。

1b. Workspace + Git Checkpoint

  • 交付树 = workspace/(= 容器 /workspace)。固定骨架每次 run 一致: .git/ .dsh-pentester/(run.json/workspace.json/events.jsonl) target/(target.json scope.md roe.md inputs/)stages/<NN>-<stage>/ {summary.md, delegations/D-00N/{input,work,artifacts,evidence,result.md}} findings/ report/ traffic/
  • run.json 位于 workspace git 树内workspace/.dsh-pentester/run.json): 阶段 checkpoint 的 commit 记录 transition 后的机器状态,rollback checkout 后 状态随 git 还原。这是"commit 里 current completed / next active"(T16)与 rollback 恢复(§31)的前提。
  • Workspace 挂载:本地 Docker → host workspace/ bind mount(无复制版); 远程 Docker → 共享 named volume,阶段边界才 full sync。
  • 同步(仅远程)为 mirror 语义:create/update/delete 都反映;pull 排除 .git/.dsh-pentester/(Host 控制态,防止 stale remote 覆盖宿主 run.json)。
  • Stage 生命周期 pending → active → reviewing → completed
  • advance = mechanical validation(无 running/starting delegation)→ 远程先 remote→local sync(§24)→ promotion → 写 summary.md(Root 提供)→ run transition → saveRun → git checkpoint(ptes(<NN>-<stage>): complete + tag)→ push。首次 advance(无 run.json)额外承担 bootstrap(见 §0)。
  • result.md = 当前正式可交付结果:Worker 写/更新 result.md 作为当前产出 (不是 Session 终止标志)。continuable child 跨轮持续;宿主不自动 settle/完成 检测,不自动生成。
  • delivery receipt(result.md + artifacts/evidence 文件清单)宿主可按需读取, 只存在于运行时响应,不持久化 INDEX/registry。
  • 不需要:STATUS.md、INDEX.*、manifest.json、logs/、Deliverable Registry、 全局 assets.json。
  • git 仓库宿主侧管理(workspace/.git),Worker 容器内无 .git;输出语言: 宿主生成文件用 run.language,Worker 文件跟随 task_prompt 语言,工具原始输出 保持原样。

2. 源码布局

src/
├── index.ts        # cordis 入口:apply/Config/inject;preset 发布;ctx.provide('pentester') 发布工具实现 + Settings RPC
├── model.ts        # 6 概念类型 + Delegation status + StageDefinition + StageStatus
├── stages.ts       # 7 个 PTES StageDefinition
├── profiles.ts     # AgentProfile 注册表(agents/*/profile.yml 加载校验)
├── store.ts        # run.json 读写(workspace/.dsh-pentester/run.json;原子写、schemaVersion)
├── workspace.ts    # 工作区骨架/target 落盘/events.jsonl/summary/promotion
├── git.ts          # GitCheckpointService(init/checkpoint/rollback timeline,injectable runner)
├── dsh.ts          # DSH seam:spawn child、cancel、完成捕获、followup 唤醒、trusted caller
├── delegations.ts  # Delegation 生命周期 + task_prompt snapshot + 目录骨架 + result.md 契约 + receipt + childSessionId 绑定
├── tools.ts        # 4 个 Root 工具(注册经 pentester service,preset scope)+ caller=root 校验 + advance + rollback
├── worker-tools.ts # container_exec(注册经 pentester service,preset scope)+ caller=worker-only 校验 + 默认 cwd=work/
├── docker/
│   ├── host.ts       # docker host 解析 + 连接探测 + 引擎构造
│   ├── connection.ts # Settings 测试连接(TLS/SSH)
│   ├── images.ts     # Toolbox 白名单
│   └── runtime.ts    # 硬化、容器/卷生命周期、exec、bind/volume、mirror sync、recovery
├── rpc.ts / settings-store.ts  # Settings UI 的 Typert RPC 与全局设置
└── ui/client/     # 仅 Settings(Docker Engine Tab),无数据面板
presets/pentester/  # persona + ask_user + run-state.mjs(preset scope 工具注册 + per-Root deny + 动态状态注入)

3. 关键设计

  • Delegation 生命周期:starting → active → interrupted/closed/failed; resultSummary 由 Root 在 cancel 时提供(reason)。 task_prompt/objective 持久化为不可变 snapshot;后续 steer/followup 不改写。
  • 完成信号:continuable 模式下无 host 自动 settle —— Worker 是 durable child,写/更新 result.md 作为当前可交付结果;Root 自行判断 advance / cancel / 再派;Worker 经 report 工具主动上报重要发现(Worker lifecycle 属 DSH, 宿主只管 PTES 领域状态)。
  • 并行:delegate 批量 assignments,内部 Promise.allSettled。
  • 目录:每 Delegation 独立 workspace/stages/<NN>-<stage>/delegations/D-00N/ (input/work/artifacts/evidence),prompt 告知"只写自己目录、可读全 workspace/"。
  • dockerode 层:窄接口 seam 供测试注入 fake。安全不变量:镜像白名单、 禁 privileged/host net/pid/ipc、capAdd 白名单、禁 docker.sock、exec 超时与 输出截断、1 PentestRun = 1 容器。
  • Worker fs:当前为 prompt 级协作约束(只写自己的 delegation 目录)。 这是有意接受的设计(owner 决策):
    • 不实现 UID 隔离 / ACL / filesystem jail / 独立 container / mount namespace;
    • 不把该约束宣传为 security boundary;
    • 原因:多个 Worker 属于同一个授权 Pentest Project、同一个信任域,当前架构 优先保证共享 Workspace、多 Agent 协作、实现简单和可维护性。 Worker 默认只写自己的 Delegation 目录,但整个 /workspace 全局可读,且技术上 同一共享 Container 内 Worker 仍可能写入其他 Workspace 路径 —— 这是接受的边界。
  • Worker prompt 注入:delegationId/stage/workspaceDir 由 host 注入 metadata 段。
  • 安全让步(显式记录):无程序化 approval/scope 检查,RoE/Scope 作为数据 注入 prompt + engagement 开始前 ask_user 预授权门 + 镜像白名单 + 容器硬化。

4. Rollback / Rework Timeline

  • pentester_rollback_stage({stage, reason}):stage 是领域 StageId(如 intelligence-gathering),rollback 到该 stage 的 checkpoint,从下一 stage 重新开始(§27)。
  • Host 流程:cancel 当前 starting/running delegation → quiescent → (远程)pull worker 数据 → dirty 则建 backup/rollback-<ts> + WIP commit (wip: before rollback to <stage>)→ 在 HEAD first-parent reachable 历史中 按 subject ptes(<NN>-<stage>): complete 找 checkpoint → 从 checkpoint 建 rework/<next-stage-slug>-<n>(n 自动递增)并 checkout(run.json 随还原)→ (远程)push → 返回 delta。
  • D-ID 在 branch timeline 内跨 Stage 全局递增;rollback 后新 branch 允许复用旧 编号(不搞跨 branch global allocator)。
  • tag 冲突(T25):main 与 rework 都完成同一 stage 时,checkpointStage 遇已 存在 tag 直接跳过(tag 只作人类可读 ref,正确性靠 commit subject)。
  • 不重写历史:当前 active branch 原历史不得 reset/rewrite;不自动 merge、 不自动删旧 branch。

5. Recovery

  • remote volume 还在 → 复用(不 local→remote 覆盖)。
  • container 丢失但 volume 存在 → 重建容器复用 volume。
  • container 与 volume 都丢失 → 新建 volume 并从本地 mirror 恢复。
  • 未完成 Delegation:reconcile 标记 failed/interrupted,不自动重跑; Root 决定是否重新 delegate。

6. 测试计划

  • model/stages/profiles 校验;store 原子写 round-trip。
  • Delegation 生命周期(fake DSH client):批量并行、cancel、continuable start/interrupt、task_prompt 不可变。
  • 工具 caller 身份:worker 调 Root 工具被拒、Root 面无 container_exec。
  • rollback:cancel workers、backup branch、rework branch、checkpoint 查找、tag 冲突。
  • docker 层(fake engine seam):白名单拒绝、HostConfig 硬化、bind/volume 选择、 mirror sync、recovery。
  • run-state:compact 状态渲染、branch 读取。
  • Worker prompt 组装 snapshot。

7. 新增依赖

  • dockerode + @types/dockerode:容器管理/exec 库。tar-stream:volume 同步。 zod:Settings RPC strict codec。其余零新增。

8. 本 wave 明确不做

approval 流 / scope 参数级检查;数据面板 UI;HTML/PDF 报告(report.md 即终稿); 多 PentestRun 并发;stage 跳跃 override;Worker 二级委派;workspace_fs / UID / ACL 文件隔离;Git LFS。