feat(ack): add structured worker model routing

This commit is contained in:
2026-07-31 23:34:13 +08:00
parent ee66dbe9ce
commit ae3bce7b5d
23 changed files with 6491 additions and 327 deletions
+24 -6
View File
@@ -31,13 +31,25 @@
- 派发 prompt 模板:`references/prompt-templates.md`
- Orca 编排命令(可选):`references/orca-adapter.md`
## 模型档位(项目可覆盖,默认见 references/model-routing.md
## Worker 路由
| 角色 | 默认档位 | 本项目实际 |
|------|----------|------------|
| Coordinator (PM) | 强模型 | `<model_or_default>` |
| Test | 中低模型 | `<model_or_default>` |
| Developer | 中低模型 | `<model_or_default>` |
机器可校验的模型、reasoning effort、权限模式、默认 profile、允许 worktree 和启动
receipt 全部以 `docs/ack/tasks.yaml``project.orchestration` 与顶层
`workerReceipts` 为准。本文件不保存可执行 worker 命令。
默认 profile
| 角色 | profile ID | 档位 |
|------|------------|------|
| Developer | `codex-dev-standard` | standard |
| Test | `codex-test-standard` | standard |
| Developer 升级 | `codex-dev-strong` | strong |
项目如改用 Cursor,应修改结构化 profile、allowlist 和 defaults,再运行任务板
校验;不能在这里粘贴 `orca --command`、Agent CLI 参数或自由 shell。
每次自动派发必须先审阅 launcher plan,再把其中的 `launchFingerprint` 作为
`--expected-launch-fingerprint` 启动 fresh worker。v0.10 的 `receiptHash` 只作
审计 checksum,不授权自动复用旧终端。
## 路径权限(项目覆盖层,必须填实际路径)
@@ -86,6 +98,12 @@ Skill 的 `scripts/run_verification.py` 执行,不直接拼接 path/args。检
- 三角色独立:Coordinator 只编排、Test 只验证、Developer 只实现(验证者 ≠ 实现者)。
- 模型分层:Coordinator 用强模型且不亲自跑测试,Test/Developer 用中低模型,必要时升级(见 references/model-routing.md)。
- 自动 worker 只能由 ACK 的 `scripts/launch_worker.py` 按结构化 profile 启动;
禁止直接拼 `orca terminal create --command`,禁止 `command``extraArgs``env`
等第二配置面。
- v0.10 自动 launcher 只支持 `read-only``workspace-write`。full-access、
bypass、YOLO/force 与关闭 sandbox 均 fail closed;需要可信平台审批通道后再开放。
- v0.10 不自动复用持久化 receipt 指向的旧终端;每次自动派发都重新 plan/launch。
- `worker_done` 与复测报告都不等于完成。必须 Test 独立复测 + Coordinator 终检后才能 `verified`
- 只有 Coordinator 写 `tasks.yaml``knowledge.yaml`Developer 与 Test 都只读,
通过消息回报。
+534 -2
View File
@@ -12,6 +12,7 @@
"source": { "type": "string" },
"ackVersion": {
"type": "string",
"pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(?:-(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$",
"description": "接入时所基于的 ack 版本,便于日后 diff 升级"
},
"kitVersion": {
@@ -35,6 +36,9 @@
"type": "string",
"const": "docs/ack/knowledge.yaml",
"description": "项目知识护栏库的唯一权威路径"
},
"orchestration": {
"$ref": "#/definitions/orchestration"
}
}
},
@@ -49,12 +53,538 @@
}
},
"statusReference": { "type": "object" },
"workerReceipts": {
"type": "array",
"items": { "$ref": "#/definitions/workerReceipt" }
},
"tasks": {
"type": "array",
"items": { "$ref": "#/definitions/task" }
}
},
"allOf": [
{
"if": {
"properties": {
"ackVersion": {
"type": "string",
"pattern": "^(?:0\\.[1-9][0-9]+\\.[0-9]+|[1-9][0-9]*\\.[0-9]+\\.[0-9]+)(?:-|\\+|$)"
}
},
"required": ["ackVersion"]
},
"then": {
"required": ["workerReceipts"],
"properties": {
"workerReceipts": {},
"tasks": { "$ref": "#/definitions/launchableTasks" },
"project": {
"type": "object",
"required": ["orchestration"],
"properties": {
"orchestration": {}
}
}
}
}
},
{
"if": {
"properties": {
"project": {
"type": "object",
"required": ["orchestration"],
"properties": {
"orchestration": {}
}
}
},
"required": ["project"]
},
"then": {
"required": ["workerReceipts"],
"properties": {
"workerReceipts": {},
"tasks": { "$ref": "#/definitions/launchableTasks" }
}
}
},
{
"if": {
"required": ["workerReceipts"],
"properties": {
"workerReceipts": {}
}
},
"then": {
"properties": {
"tasks": { "$ref": "#/definitions/launchableTasks" },
"project": {
"type": "object",
"required": ["orchestration"],
"properties": {
"orchestration": {}
}
}
}
}
}
],
"definitions": {
"sha256": {
"type": "string",
"pattern": "^sha256:[0-9a-f]{64}$"
},
"profileId": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]{1,63}$"
},
"launchableTasks": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"
}
}
}
},
"modelList": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/+@-]{0,127}$"
}
},
"modelTierAllowlist": {
"type": "object",
"minProperties": 1,
"additionalProperties": false,
"properties": {
"standard": { "$ref": "#/definitions/modelList" },
"strong": { "$ref": "#/definitions/modelList" }
}
},
"modelRoleAllowlist": {
"type": "object",
"minProperties": 1,
"additionalProperties": false,
"properties": {
"developer": { "$ref": "#/definitions/modelTierAllowlist" },
"test": { "$ref": "#/definitions/modelTierAllowlist" }
}
},
"modelAllowlist": {
"type": "object",
"additionalProperties": false,
"properties": {
"codex": { "$ref": "#/definitions/modelRoleAllowlist" },
"cursor-agent": { "$ref": "#/definitions/modelRoleAllowlist" }
}
},
"workerProfile": {
"type": "object",
"required": [
"role",
"cli",
"tier",
"model",
"reasoningEffort",
"permissionMode"
],
"additionalProperties": false,
"properties": {
"role": {
"type": "string",
"enum": ["developer", "test"]
},
"cli": {
"type": "string",
"enum": ["codex", "cursor-agent"]
},
"tier": {
"type": "string",
"enum": ["standard", "strong"]
},
"model": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/+@-]{0,127}$"
},
"reasoningEffort": {
"type": ["string", "null"],
"enum": ["low", "medium", "high", "xhigh", null]
},
"permissionMode": {
"type": "string",
"enum": ["read-only", "workspace-write"]
}
}
},
"workerDefaults": {
"type": "object",
"additionalProperties": false,
"properties": {
"developer": { "$ref": "#/definitions/profileId" },
"test": { "$ref": "#/definitions/profileId" },
"developerUpgraded": { "$ref": "#/definitions/profileId" }
}
},
"orchestration": {
"type": "object",
"required": [
"profileVersion",
"mode",
"allowedWorktrees",
"modelAllowlist",
"profiles",
"defaults"
],
"additionalProperties": false,
"properties": {
"profileVersion": {
"type": "integer",
"const": 1
},
"mode": {
"type": "string",
"enum": ["orca", "manual"]
},
"allowedWorktrees": {
"type": "array",
"uniqueItems": true,
"items": {
"type": "string",
"minLength": 1,
"pattern": "^/"
}
},
"modelAllowlist": {
"$ref": "#/definitions/modelAllowlist"
},
"profiles": {
"type": "object",
"propertyNames": {
"$ref": "#/definitions/profileId"
},
"additionalProperties": {
"$ref": "#/definitions/workerProfile"
}
},
"defaults": {
"$ref": "#/definitions/workerDefaults"
}
},
"allOf": [
{
"if": {
"properties": {
"mode": { "const": "orca" }
},
"required": ["mode"]
},
"then": {
"properties": {
"allowedWorktrees": { "type": "array", "minItems": 1 },
"modelAllowlist": { "type": "object", "minProperties": 1 },
"profiles": { "type": "object", "minProperties": 1 },
"defaults": {
"type": "object",
"required": ["developer", "test"],
"properties": {
"developer": {},
"test": {}
}
}
}
}
}
]
},
"worktreeIdentity": {
"type": "object",
"required": [
"path",
"device",
"inode",
"gitCommonDir",
"gitCommonDevice",
"gitCommonInode"
],
"additionalProperties": false,
"properties": {
"path": {
"type": "string",
"pattern": "^/"
},
"device": {
"type": "integer",
"minimum": 0
},
"inode": {
"type": "integer",
"minimum": 1
},
"gitCommonDir": {
"type": "string",
"pattern": "^/"
},
"gitCommonDevice": {
"type": "integer",
"minimum": 0
},
"gitCommonInode": {
"type": "integer",
"minimum": 1
}
}
},
"receiptRequested": {
"type": "object",
"required": [
"cli",
"tier",
"model",
"reasoningEffort",
"permissionMode",
"executable",
"executableDevice",
"executableInode",
"cliVersion",
"argv",
"argvHash",
"environmentPolicy"
],
"additionalProperties": false,
"properties": {
"cli": {
"type": "string",
"enum": ["codex", "cursor-agent"]
},
"tier": {
"type": "string",
"enum": ["standard", "strong"]
},
"model": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:/+@-]{0,127}$"
},
"reasoningEffort": {
"type": ["string", "null"],
"enum": ["low", "medium", "high", "xhigh", null]
},
"permissionMode": {
"type": "string",
"enum": ["read-only", "workspace-write"]
},
"executable": {
"type": "string",
"pattern": "^/"
},
"executableDevice": {
"type": "integer",
"minimum": 0
},
"executableInode": {
"type": "integer",
"minimum": 1
},
"cliVersion": {
"type": "string",
"minLength": 1
},
"argv": {
"type": "array",
"minItems": 2,
"items": {
"type": "string"
}
},
"argvHash": {
"$ref": "#/definitions/sha256"
},
"environmentPolicy": {
"type": "string",
"const": "per-cli-allowlist-v1"
}
}
},
"receiptBinding": {
"type": "object",
"required": [
"orchestrator",
"runtimeId",
"handle",
"incarnationId",
"observedWorktreePath",
"connected",
"writable",
"boundAt"
],
"additionalProperties": false,
"properties": {
"orchestrator": {
"type": "string",
"const": "orca"
},
"runtimeId": {
"type": "string",
"minLength": 1
},
"handle": {
"type": "string",
"minLength": 1
},
"incarnationId": {
"type": "string",
"minLength": 1
},
"observedWorktreePath": {
"type": "string"
},
"connected": {
"type": "boolean"
},
"writable": {
"type": "boolean"
},
"boundAt": {
"type": "string",
"minLength": 1
}
}
},
"workerReceipt": {
"type": "object",
"required": [
"receiptVersion",
"id",
"launchId",
"profileId",
"profileHash",
"launchFingerprint",
"slot",
"createdFor",
"worktree",
"requested",
"binding",
"createdAt",
"receiptHash"
],
"additionalProperties": false,
"properties": {
"receiptVersion": {
"type": "integer",
"const": 1
},
"id": {
"type": "string",
"pattern": "^WR-[0-9a-f]{64}$"
},
"launchId": {
"type": "string",
"pattern": "^[0-9a-f]{64}$"
},
"profileId": {
"$ref": "#/definitions/profileId"
},
"profileHash": {
"$ref": "#/definitions/sha256"
},
"launchFingerprint": {
"$ref": "#/definitions/sha256"
},
"slot": {
"type": "integer",
"minimum": 1,
"maximum": 99
},
"createdFor": {
"type": "object",
"required": ["taskId", "attemptId", "role"],
"additionalProperties": false,
"properties": {
"taskId": {
"type": "string",
"minLength": 1
},
"attemptId": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*-A[1-3]$"
},
"role": {
"type": "string",
"enum": ["developer", "test"]
}
}
},
"worktree": {
"$ref": "#/definitions/worktreeIdentity"
},
"requested": {
"$ref": "#/definitions/receiptRequested"
},
"binding": {
"$ref": "#/definitions/receiptBinding"
},
"createdAt": {
"type": "string",
"minLength": 1
},
"receiptHash": {
"$ref": "#/definitions/sha256"
}
}
},
"roleDispatch": {
"type": "object",
"required": ["profileId", "receiptId", "attemptId", "taskId", "dispatchId"],
"additionalProperties": false,
"properties": {
"profileId": {
"type": ["string", "null"],
"pattern": "^[a-z][a-z0-9-]{1,63}$"
},
"receiptId": {
"type": ["string", "null"],
"pattern": "^WR-[0-9a-f]{64}$"
},
"attemptId": {
"type": ["string", "null"],
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*-A[1-3]$"
},
"taskId": {
"type": ["string", "null"]
},
"dispatchId": {
"type": ["string", "null"]
}
},
"allOf": [
{
"if": {
"properties": {
"receiptId": { "type": "null" }
},
"required": ["receiptId"]
},
"then": {
"properties": {
"attemptId": { "type": "null" }
}
},
"else": {
"properties": {
"profileId": { "type": "string" },
"attemptId": { "type": "string" }
}
}
}
]
},
"status": {
"type": "string",
"enum": [
@@ -76,7 +606,7 @@
"round": { "type": "integer", "minimum": 1, "maximum": 3 },
"attemptId": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*-A[1-9][0-9]*$",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*-A[1-3]$",
"description": "稳定逻辑轮次 ID,应为 <task-id>-A<round>;旧轮次可缺省,但作为知识来源前必须补齐"
},
"result": { "type": "string", "enum": ["passed", "failed"] },
@@ -230,11 +760,13 @@
"verification": { "type": "object" },
"dispatch": {
"type": "object",
"additionalProperties": true,
"additionalProperties": false,
"properties": {
"taskId": { "type": ["string", "null"] },
"dispatchId": { "type": ["string", "null"] },
"worker": { "type": ["string", "null"] },
"developer": { "$ref": "#/definitions/roleDispatch" },
"test": { "$ref": "#/definitions/roleDispatch" },
"rounds": {
"type": "array",
"items": { "$ref": "#/definitions/round" }
+71 -3
View File
@@ -10,6 +10,65 @@ project:
devWorktree: "<dev_worktree>"
overlayFile: "docs/ack/project.md"
knowledgeFile: "docs/ack/knowledge.yaml"
orchestration:
profileVersion: 1
mode: "orca"
allowedWorktrees:
- "<dev_worktree>"
modelAllowlist:
codex:
developer:
standard: ["gpt-5.6-terra"]
strong: ["gpt-5.6-sol"]
test:
standard: ["gpt-5.6-luna"]
cursor-agent:
developer:
standard: ["auto"]
test:
standard: ["auto"]
profiles:
codex-dev-standard:
role: "developer"
cli: "codex"
tier: "standard"
model: "gpt-5.6-terra"
reasoningEffort: "medium"
permissionMode: "workspace-write"
codex-test-standard:
role: "test"
cli: "codex"
tier: "standard"
model: "gpt-5.6-luna"
reasoningEffort: "low"
permissionMode: "workspace-write"
codex-dev-strong:
role: "developer"
cli: "codex"
tier: "strong"
model: "gpt-5.6-sol"
reasoningEffort: "high"
permissionMode: "workspace-write"
cursor-dev-standard:
role: "developer"
cli: "cursor-agent"
tier: "standard"
model: "auto"
reasoningEffort: null
permissionMode: "workspace-write"
cursor-test-standard:
role: "test"
cli: "cursor-agent"
tier: "standard"
model: "auto"
reasoningEffort: null
permissionMode: "workspace-write"
defaults:
developer: "codex-dev-standard"
test: "codex-test-standard"
developerUpgraded: "codex-dev-strong"
workerReceipts: []
summary:
verified: []
@@ -62,9 +121,18 @@ tasks:
- "<visible text or interaction expected>"
dispatch:
taskId: null
dispatchId: null
worker: null
developer:
profileId: "codex-dev-standard"
receiptId: null
attemptId: null
taskId: null
dispatchId: null
test:
profileId: "codex-test-standard"
receiptId: null
attemptId: null
taskId: null
dispatchId: null
rounds: []
resolution: