@zq-silk/yui 0.15.8 → 0.15.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -0
- package/ARCHITECTURE.zh-CN.md +151 -0
- package/README.md +211 -14
- package/dist/artifacts/artifactCapability.js +74 -0
- package/dist/artifacts/artifactCommitLock.js +249 -0
- package/dist/artifacts/artifactPaths.js +151 -0
- package/dist/artifacts/gitArtifactRef.js +146 -0
- package/dist/artifacts/managedGit.js +332 -0
- package/dist/artifacts/taskArtifactRepository.js +277 -0
- package/dist/cli/commandCatalog.js +14 -10
- package/dist/cli.js +67 -0
- package/dist/commands/operatorCommands.js +33 -2
- package/dist/commands/taskActivationCommands.js +22 -0
- package/dist/commands/taskCommands.js +342 -79
- package/dist/context/runContextPack.js +28 -16
- package/dist/context/taskContext.js +26 -3
- package/dist/controller/controller.js +8 -2
- package/dist/kernel/builtinCapabilities.js +32 -24
- package/dist/message/message.js +56 -0
- package/dist/plugins/pluginService.js +11 -3
- package/dist/resources/projectResource.js +0 -48
- package/dist/resources/projectResourceService.js +3 -81
- package/dist/setup/setupCommand.js +3 -8
- package/dist/storage/migrations/artifactsToGit.js +338 -0
- package/dist/storage/migrations/submitIntent.js +126 -0
- package/dist/storage/sqliteSchema.js +37 -3
- package/dist/storage/sqliteStore.js +1 -21
- package/dist/storage/storageVersions.js +1 -1
- package/dist/storage/storeRpc.js +1 -1
- package/dist/task/taskActivation.js +26 -0
- package/dist/task/taskActivationService.js +85 -69
- package/dist/task/taskSubmission.js +236 -0
- package/dist/web/assets/client/app.js +3 -2
- package/dist/web/assets/client/taskSurface.js +96 -7
- package/dist/web/webServer.js +18 -3
- package/dist/web/webTaskSurface.js +6 -6
- package/dist/workItem/workItem.js +14 -10
- package/docs/agent-result-consumption.md +2 -0
- package/docs/agent-result-consumption.zh-CN.md +81 -0
- package/docs/agent-runtime-drivers.md +2 -0
- package/docs/agent-runtime-drivers.zh-CN.md +77 -0
- package/docs/architecture/README.md +44 -32
- package/docs/architecture/README.zh-CN.md +43 -0
- package/docs/architecture/capabilities-and-resources.md +118 -79
- package/docs/architecture/capabilities-and-resources.zh-CN.md +83 -0
- package/docs/managed-turn-and-session-runtime.md +2 -0
- package/docs/managed-turn-and-session-runtime.zh-CN.md +180 -0
- package/docs/observability/README.md +2 -0
- package/docs/observability/README.zh-CN.md +71 -0
- package/docs/plugin-sdk.md +320 -217
- package/docs/plugin-sdk.zh-CN.md +293 -0
- package/docs/provider-runtime.md +2 -0
- package/docs/provider-runtime.zh-CN.md +132 -0
- package/docs/release-workflow.md +2 -0
- package/docs/release-workflow.zh-CN.md +237 -0
- package/docs/roles-and-configuration.md +2 -0
- package/docs/roles-and-configuration.zh-CN.md +96 -0
- package/docs/sqlite-control-plane-design.md +2 -0
- package/docs/sqlite-control-plane-design.zh-CN.md +62 -0
- package/docs/task-dag-semantics.md +80 -57
- package/docs/task-dag-semantics.zh-CN.md +59 -0
- package/docs/task-delivery.md +2 -0
- package/docs/task-delivery.zh-CN.md +82 -0
- package/docs/task-local-identity.md +2 -0
- package/docs/task-local-identity.zh-CN.md +58 -0
- package/docs/testing/verification-levels.md +2 -0
- package/docs/testing/verification-levels.zh-CN.md +69 -0
- package/i18n/README.zh-CN.md +199 -10
- package/package.json +2 -1
- package/skills/yui-leader/SKILL.md +88 -331
- package/skills/yui-leader/references/execution.md +303 -0
- package/skills/yui-leader/references/planning.md +109 -0
- package/skills/yui-leader/references/task-plugins.md +8 -4
- package/skills/yui-operator/SKILL.md +16 -3
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<p align="right"><a href="./release-workflow.md">English</a> | <strong>简体中文</strong></p>
|
|
2
|
+
|
|
3
|
+
# 获授权的发布操作
|
|
4
|
+
|
|
5
|
+
发布工作流是一段被显式选择、获授权的外部发布效果序列——pull request、CI 确认、
|
|
6
|
+
合并、版本 tag、npm 发布、全新安装冒烟、CLI 更新、Controller 替换、Project 迁移和
|
|
7
|
+
后置验证。它是一个专用的外部效果设施,而不是 Yui 的 Task 规划或 Agent 执行模型。
|
|
8
|
+
Agent 选择一个预先声明的计划,设施从持久状态驱动该计划:每次转换都在下一次外部调用
|
|
9
|
+
之前持久化,因此崩溃、超时或被撤销的 grant 都不会让发布陷入猜测。
|
|
10
|
+
|
|
11
|
+
两个 Task 级记录族支撑它:
|
|
12
|
+
|
|
13
|
+
- **CapabilityGrant**(`capability-grant-N`)——权威。一个具名的授权者把 grant
|
|
14
|
+
限定到若干动作、参数边界、一个过期时间、一个使用次数和一个不可逆上限。
|
|
15
|
+
- **ReleaseWorkflow**(`release-workflow-N`)——计划及其进展:一个确切来源(仓库 +
|
|
16
|
+
钉住的 commit,可选一个 artifact)、一份不可变的有序步骤计划,以及每步一条持久记录。
|
|
17
|
+
|
|
18
|
+
引擎(`src/release/releaseWorkflowEngine.ts`)是一个纯库;`yui task workflow` 和
|
|
19
|
+
`yui task grant` 命令驱动它。每个外部系统都位于 `ReleaseWorkflowPorts`
|
|
20
|
+
(`src/release/releaseWorkflowPorts.ts`)之后,因此整个工作流可以用确定性的 fake
|
|
21
|
+
测试,不产生任何真实的 GitHub、npm、git、Controller 或进程副作用。
|
|
22
|
+
|
|
23
|
+
## 授权模型
|
|
24
|
+
|
|
25
|
+
每一次(再)提交一个步骤,都在外部调用**之前**通过 `checkGrant(grant, request, now)`
|
|
26
|
+
(`src/grant/capabilityGrant.ts`)。步骤 kind 就是 grant 动作:一个 grant 列出它授权的
|
|
27
|
+
步骤 kind,例如 `--action npm-publish --action version-tag`。该判定是 fail-closed
|
|
28
|
+
的——每个拒绝都带一个机器可读原因并停止这次运行:
|
|
29
|
+
|
|
30
|
+
| 原因 | 含义 |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `grant-missing` | 没有 grant 记录绑定到该工作流(引擎级)。 |
|
|
33
|
+
| `grant-revoked` | 该 grant 已被 operator 撤销。 |
|
|
34
|
+
| `grant-expired` | 墙钟已过该 grant 的 `expiresAt`。 |
|
|
35
|
+
| `grant-uses-exhausted` | 该 grant 的 `maxUses` 已被消耗。 |
|
|
36
|
+
| `grant-action-not-allowed` | 步骤 kind 不在该 grant 的动作中。 |
|
|
37
|
+
| `grant-parameter-missing` | 步骤缺少一个受约束参数。 |
|
|
38
|
+
| `grant-parameter-value-not-allowed` | 一个受约束参数的取值越界。 |
|
|
39
|
+
| `grant-irreversibility-exceeds-ceiling` | 该步骤比 grant 的上限更不可逆。 |
|
|
40
|
+
|
|
41
|
+
附加规则:
|
|
42
|
+
|
|
43
|
+
- **每次获授权提交消耗一次。** 引擎在成功判定与外部调用之间记录一次 grant 使用,
|
|
44
|
+
因此一个 `maxUses` grant 会在那次将要超额的尝试上 fail closed。
|
|
45
|
+
- **不可逆步骤需要一个已确认的前缀。** 一个标记为 `irreversible` 的步骤额外要求此前
|
|
46
|
+
每个步骤都是 `succeeded`;否则该步骤以 `prerequisite-not-confirmed` 失败并停止运行。
|
|
47
|
+
这正是让 `npm-publish` 不会跟在一个失败的 PR 之后运行的机制。
|
|
48
|
+
- **拒绝会被记录。** 当一个待处理步骤被拒绝时,引擎会启动并把该步骤失败,日志里带上
|
|
49
|
+
这次拒绝,因此 `workflow status` 能准确显示授权在哪里停下。
|
|
50
|
+
- **重新绑定。** 一个被撤销、过期或过窄的 grant 不会让工作流走进死胡同。签发一个新
|
|
51
|
+
grant 并用 `yui task workflow resume <task> <workflow> --grant <new-grant>` 恢复;
|
|
52
|
+
跨越这次重新绑定,计划、来源和所有已确认的步骤证据都不可变。
|
|
53
|
+
|
|
54
|
+
## 稳定的 Task-final Review 合同
|
|
55
|
+
|
|
56
|
+
兼容的 CLI 包更新和 Controller 替换不改变一个活动 Task 的 final-review 能力。受管
|
|
57
|
+
Session 使用普通的 `yui` 命令,兼容性由协议和存储身份检查,一个替换 Leader 呈现由
|
|
58
|
+
持久 Task 证据已确立的合同。不需要任何版本感知的 Operator 动作。Candidate 和
|
|
59
|
+
Task-final 的 ReviewRound 记录必须全部携带那唯一的合同。冲突的记录 fail closed;
|
|
60
|
+
不存在重新绑定事件、恢复命令或第二套合同状态机。
|
|
61
|
+
|
|
62
|
+
## CLI 与 Controller 发布边界
|
|
63
|
+
|
|
64
|
+
全局 `yui` 命令是稳定的用户与受管 Session 接口。对普通命令,它不跟随
|
|
65
|
+
`runtime/active-release.json`:那个指针选择的是 Controller 发布,而不是 CLI 包。这让
|
|
66
|
+
CLI、Operator Session 和 Controller 替换保持兼容,而不必把每个命令钉在一个不可变构建上。
|
|
67
|
+
|
|
68
|
+
一个源码 checkout 或以其他方式未经验证的本地 CLI 不是这个已发布接口。当 `YUI_HOME`
|
|
69
|
+
已经命名了一个活动发布时,这样的 CLI 会在打开存储之前失败,并报告它的构建/来源、
|
|
70
|
+
持久的 Home 身份以及它的调用类别。`make install-local` 仍默认使用 checkout 隔离的
|
|
71
|
+
`output/dev/home`;把那个 launcher 显式指向一个发布拥有的 Home 会被拒绝。
|
|
72
|
+
|
|
73
|
+
一个显式的 `yui release activate <release-id|build-id>` 是唯一的例外。全局 CLI 校验
|
|
74
|
+
已安装的目标发布及其匹配的冒烟回执,然后把未改动的激活参数委派给那个目标的
|
|
75
|
+
`dist/cli.js`。因此目标发布拥有完整的交接协议和超时层级。一次无目标的激活、help、
|
|
76
|
+
`--json` 以及其他每个命令都留在全局 CLI 上。激活不新增另一条普通 CLI 路由路径。
|
|
77
|
+
|
|
78
|
+
## 步骤目录
|
|
79
|
+
|
|
80
|
+
计划是一个固定、预先声明的操作子集。每个计划条目有一个 id(工作流内唯一)、一个
|
|
81
|
+
kind、可选 params,以及一个可选的不可逆级别(`none` | `reversible` | `irreversible`)。
|
|
82
|
+
|
|
83
|
+
| Kind | 外部效果 | 权威身份 |
|
|
84
|
+
| --- | --- | --- |
|
|
85
|
+
| `pr-create-or-reuse` | 创建发布 PR,或复用一个针对该 head 的开放 PR。 | `pull-request` 号 |
|
|
86
|
+
| `ci-confirm` | 读取该来源 ref 的 CI 结论;仅在 `success` 时成功。 | — |
|
|
87
|
+
| `merge` | 合并具名 PR(默认 squash)。 | — |
|
|
88
|
+
| `version-tag` | 创建并推送带注释的版本 tag。 | `git-tag` 名 |
|
|
89
|
+
| `npm-publish` | 把 tarball 发布到 registry。 | `npm-package` 版本 |
|
|
90
|
+
| `fresh-install-smoke` | 从 registry 安装并运行已发布的包。 | — |
|
|
91
|
+
| `cli-update` | 通过既有更新编排器更新 Yui CLI/Controller home。 | `controller-home` |
|
|
92
|
+
| `controller-replace` | 停止并重启 file-task Controller。 | — |
|
|
93
|
+
| `project-migrate` | 通过既有的 project 命令运行 Project 迁移。 | — |
|
|
94
|
+
| `post-verify` | 运行一个任意的验证命令。 | — |
|
|
95
|
+
|
|
96
|
+
步骤可以引用更早的证据:一个 param 值为 `$externalId:<step-id>` 时,会在运行时解析为
|
|
97
|
+
被引用步骤已确认的 external id,因此一个 `merge` 步骤可以消费 `pr` 步骤产生的 PR 号,
|
|
98
|
+
而 operator 事先并不需要知道它。对一个未确认步骤的引用会让运行失败,而不是猜测。
|
|
99
|
+
|
|
100
|
+
## 恢复与 resume 语义
|
|
101
|
+
|
|
102
|
+
一次运行总是从 **resume 游标**开始:第一个状态非终态(`succeeded` 或 `skipped`)的
|
|
103
|
+
计划步骤。没有“从头再来”——已确认的步骤绝不重跑。
|
|
104
|
+
|
|
105
|
+
因为每次状态转换都在下一次外部调用之前持久化,所以任意一点的进程退出都是可恢复的:
|
|
106
|
+
重新调用 `run`(或 `resume`),引擎就从第一个未确认步骤继续。`--max-steps <n>` 限定
|
|
107
|
+
单次运行;一次在工作流中途耗尽预算的运行返回 `budget-exhausted`,下一次调用继续。
|
|
108
|
+
|
|
109
|
+
在途步骤通过**权威身份查询**解决,绝不盲目重新提交:
|
|
110
|
+
|
|
111
|
+
- 一个留在 `running` 或 `unknown` 的步骤,先按其记录的 `externalIdentity` 查询。
|
|
112
|
+
- `exists` → 该步骤到达 `succeeded`,且**没有第二次提交**(`unknown` 被确认,
|
|
113
|
+
`running` 被完成)。
|
|
114
|
+
- `unknown` → 运行以结果 `unknown` 停止;在其命运不可知期间,该步骤绝不被重新提交。
|
|
115
|
+
- `absent` → 效果从未落地,因此该步骤被重试(一个 `running` 步骤会记录这次恢复尝试)。
|
|
116
|
+
- 一个**没有** external identity 的 `running` 步骤在记录提交结果之前就崩溃了。一个
|
|
117
|
+
不可逆步骤无论如何都通过端口查询(适配器咨询其持久幂等存储):`exists` 不经第二次
|
|
118
|
+
提交确认该步骤,`unknown` 以 `unconfirmed` 停止,只有权威的 `absent` 才恰好重试该
|
|
119
|
+
步骤一次。一个可逆步骤总是落到重试,并沿用同一个幂等键。
|
|
120
|
+
- 一次**没有** external identity 的超时把该步骤标记为 `unknown`(unconfirmed),因此
|
|
121
|
+
它绝不被盲目重新提交;在 resume 时它以 `unconfirmed` fail closed。
|
|
122
|
+
- 一个 `failed` 步骤在下一次运行时被重试;它的 `attempts` 计数和日志按尝试增长。
|
|
123
|
+
|
|
124
|
+
运行结果:`succeeded`、`failed`、`unknown`、`unauthorized`、`unconfirmed`、
|
|
125
|
+
`budget-exhausted`。每个都带一个机器可读的 `stopReason`(例如 `unknown:publish`、
|
|
126
|
+
`unauthorized:grant-revoked`、`budget-exhausted:verify`)以及该次运行尝试过的步骤 id
|
|
127
|
+
列表。
|
|
128
|
+
|
|
129
|
+
## 幂等键合同
|
|
130
|
+
|
|
131
|
+
每个步骤的幂等键在**创建时预先声明**且永不改变:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
<taskId>/<workflowId>/<stepId>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
该键被传给该步骤的每一次 `executeStep` 调用,包括在一次确认为 absent 的超时之后的
|
|
138
|
+
重试。端口合同要求 `executeStep` 在同一键下是幂等的:一次重试尝试不得产生第二次
|
|
139
|
+
副作用。引擎侧的合同更严格——它绝不为一个已标记 `unknown` 的步骤调用 `executeStep`,
|
|
140
|
+
而是按记录的身份重新查询。fake 记录每一个键,因此测试套件直接证明至多一次执行。
|
|
141
|
+
|
|
142
|
+
## Operator 指南
|
|
143
|
+
|
|
144
|
+
Session 权威依据当前持久绑定检查。Telemetry 按 Role/AgentRun 分组,进程 owner 使用
|
|
145
|
+
PID/start 身份。存储变更遵循[唯一的显式升级边界](sqlite-control-plane-design.zh-CN.md);
|
|
146
|
+
普通命令绝不改写 Home schema。
|
|
147
|
+
|
|
148
|
+
grant 的签发与撤销是不可逆权威操作。它们需要当前已登记的全局 Operator 对话。它的
|
|
149
|
+
原生 session ID 必须与持久的活动 session 绑定匹配:Codex 命令在存在时使用
|
|
150
|
+
`CODEX_THREAD_ID`,否则使用 `YUI_NATIVE_SESSION_ID`;Claude 使用 `YUI_NATIVE_SESSION_ID`。
|
|
151
|
+
Host generation 和启动时的 Agent 标签不是调用者身份。通过另一个入口恢复同一段对话
|
|
152
|
+
不撤销其权威。一个未登记、被替换或已结束的对话没有这种权威。一个受管的 Task Agent
|
|
153
|
+
不能自签发或自撤销 grant,清空子进程环境也不赋予用户权威。被记录的授权者/撤销者
|
|
154
|
+
绑定到那个 Operator session(`operator:<agent-id>`);不存在可伪造的 `--granter`/`--by`
|
|
155
|
+
标签。
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
# 1. Operator session 为发布链签发权威。
|
|
159
|
+
yui task grant issue task-15 \
|
|
160
|
+
--action pr-create-or-reuse --action npm-publish --action post-verify \
|
|
161
|
+
--irreversibility-ceiling irreversible
|
|
162
|
+
|
|
163
|
+
# 2. 针对确切来源和预先声明的计划创建工作流。
|
|
164
|
+
# npm-publish 步骤需要一个内容寻址的来源 artifact:不可变的工作流来源以后
|
|
165
|
+
# 永远无法再获得它,因此没有 --source-artifact 的计划在创建时即被拒绝。
|
|
166
|
+
yui task workflow create task-15 \
|
|
167
|
+
--grant capability-grant-1 \
|
|
168
|
+
--source-repo acme/widget --source-commit abc1234deadbeef0000000000000000000000000 \
|
|
169
|
+
--source-artifact widget-1.0.0.tgz@sha512-<base64-integrity> \
|
|
170
|
+
--step pr:pr-create-or-reuse \
|
|
171
|
+
--step publish:npm-publish --step-irreversibility publish=irreversible \
|
|
172
|
+
--step-param publish:tarball=./dist/widget-1.0.0.tgz \
|
|
173
|
+
--step verify:post-verify --step-param verify:command='yui --version'
|
|
174
|
+
|
|
175
|
+
# 3. 运行(或 resume)并检查。
|
|
176
|
+
yui task workflow run task-15 release-workflow-1
|
|
177
|
+
yui task workflow resume task-15 release-workflow-1 [--grant capability-grant-2] [--max-steps 1]
|
|
178
|
+
yui task workflow status task-15 release-workflow-1
|
|
179
|
+
|
|
180
|
+
# 4. 随时撤销权威;下一个步骤以 unauthorized 停止。
|
|
181
|
+
yui task grant revoke task-15 capability-grant-1
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`workflow status` 渲染每个步骤的状态、尝试次数和已确认的 external id,因此 operator
|
|
185
|
+
能准确看到一次发布在哪里停下以及为什么。
|
|
186
|
+
|
|
187
|
+
## 真实资源边界
|
|
188
|
+
|
|
189
|
+
真实执行只通过 `yui` CLI 发生,它接上真实适配器(`createReleaseWorkflowPorts`)。该
|
|
190
|
+
适配器是既有原子操作——`gh`、`npm`、`git`、CLI 更新编排器、Controller stop/restart 和
|
|
191
|
+
`project migrate`——之上的一层薄壳,并且只在一个人类授权者签发了对每个步骤都通过
|
|
192
|
+
`checkGrant` 的显式 CapabilityGrant 时才运行。一个本地测试请求绝不替代那份权威。
|
|
193
|
+
|
|
194
|
+
由 tag 触发的 `publish.yml` 工作流是唯一维护的发布冒烟。它复用那个通过了 core CI 的
|
|
195
|
+
确切 commit,只增加发布所需的产物装配、全新安装和 provenance 检查。
|
|
196
|
+
|
|
197
|
+
该工作流通过 npm Trusted Publishing(OIDC)认证,因此发布身份存在于 tag 之外的两处:
|
|
198
|
+
`repository`、`bugs` 和 `homepage` 由 `assemble-runtime-package.mjs` 从源 `package.json`
|
|
199
|
+
逐字复制进已发布 manifest,而该包的 npm Trusted Publisher 条目点明 GitHub owner、
|
|
200
|
+
仓库、工作流文件和环境。npm 在接受 provenance 之前会区分大小写地将 `repository.url`
|
|
201
|
+
与正在构建的仓库比较。因此重命名或转移 GitHub 仓库时,必须连同重命名一起更新这些 URL
|
|
202
|
+
和 npm Trusted Publisher 条目;否则下一个 tag 会走到 `npm publish` 并在那里失败——此时
|
|
203
|
+
tag 和已过门的构建都已成功。
|
|
204
|
+
|
|
205
|
+
## 适配器安全加固
|
|
206
|
+
|
|
207
|
+
真实适配器(`createReleaseWorkflowPorts`)在引擎的 grant 检查之外再施加额外防护:
|
|
208
|
+
|
|
209
|
+
- **Tarball 选项注入。** 一个看起来像选项的 tarball 路径(以 `-` 开头)在任何子进程
|
|
210
|
+
——`tar -xOf` manifest 检视和 `npm publish`——看到它之前就被拒绝,因此一个精心构造的
|
|
211
|
+
路径永远不会被当作 flag 解释。
|
|
212
|
+
- **Tarball TOCTOU。** 在校验冻结的 `source.artifact.integrity` 之后,被校验的字节被
|
|
213
|
+
快照到一个工作流私有、只读的临时文件。`tar -xOf` manifest 检视和 `npm publish` 都
|
|
214
|
+
读取该快照,而不是活的 tarball 路径,因此校验之后对原文件的替换不能改变所发布的内容。
|
|
215
|
+
步骤完成时移除该快照。
|
|
216
|
+
- **钉住的外部命令。** 适配器在构造时通过 `resolveExecutable` 把它 shell 调用的外部
|
|
217
|
+
命令(`gh`、`git`、`npm`、`tar`、`sh`)解析为绝对路径,只走一次调用者的 `PATH`。每次
|
|
218
|
+
子进程调用都使用解析后的路径,因此之后的 `PATH` 变化(或被操纵的工作目录)不能把一次
|
|
219
|
+
发布效果重定向到另一个二进制。一个无法解析的命令返回一个合成失败(exit 127),不调用
|
|
220
|
+
任何二进制。
|
|
221
|
+
- **钉住的 cli-update 激活目标。** 在不可逆的更新效果之前,适配器把确切的激活目标——
|
|
222
|
+
Home 加上全局 npm 前缀(`bin/yui`)——持久化到 Home 下的一个持久文件
|
|
223
|
+
(`release/cli-update-identity/<idempotency-key>.json`)。一次硬退出的恢复查询(一个
|
|
224
|
+
没有记录身份的步骤)读取这个文件并调用那个钉住的目标;如果该文件不存在(进程在预效果
|
|
225
|
+
持久化之前退出),查询返回 `unknown`,而不是从 resume 调用者的 `npm prefix --global`
|
|
226
|
+
或 `PATH` 推导目标,因此 resume 环境中的另一个安装不能替这个步骤背书。
|
|
227
|
+
- **Controller 生命周期校验。** 一次 `cli-update` 恢复查询会证明替换后的 Controller
|
|
228
|
+
确实拥有目标 Home:它运行 `yui --json controller status`(`YUI_HOME` 钉在记录的 Home
|
|
229
|
+
上),并要求一个 `current` controller 资源,其 `yuiHome` 解析到那个 Home,然后运行
|
|
230
|
+
`yui --json controller identity`,并要求已认证的 Controller 身份与已激活的产物匹配:
|
|
231
|
+
Node.js 可执行路径、由钉住的全局二进制派生的确切 Controller 入口点,以及包版本。仅有
|
|
232
|
+
二进制健康(doctor、`--version`)绝不确认这次交接,任何不可证明的状态都返回 `unknown`。
|
|
233
|
+
这适用于带身份的查询和硬退出查询(一个没有记录身份的步骤)两者。
|
|
234
|
+
- **npm integrity 比较。** 一次 `npm-publish` 恢复查询不止步于已发布版本:它通过
|
|
235
|
+
`npm view <pkg>@<version> dist.integrity` 取 `dist.integrity`,并与冻结的
|
|
236
|
+
`source.artifact.integrity` 逐字节比较。匹配则确认该步骤;同一版本但字节不同是一个
|
|
237
|
+
冲突,返回 `unknown`(绝不确认,绝不重新发布);一个缺失的版本是 `absent`。
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<p align="right"><a href="./roles-and-configuration.md">English</a> | <strong>简体中文</strong></p>
|
|
2
|
+
|
|
3
|
+
# Role、Profile 与执行配置
|
|
4
|
+
|
|
5
|
+
## 职责
|
|
6
|
+
|
|
7
|
+
Agent 选择一个执行组件、连接方案和启动环境。Role 选择一个活动的 Agent 绑定和
|
|
8
|
+
可移植行为。每个绑定保留独立的运行时选项。一个 Role 可以持有多个绑定,而不产生
|
|
9
|
+
并行写者,也不把一个绑定的凭据/配置共享给另一个。
|
|
10
|
+
|
|
11
|
+
Task Role 是 Task 局部的;global Role 提供已配置的默认值和全局对话。Role
|
|
12
|
+
身份/配置不是可写的运行时状态。Session 与 Provider 观察描述实际活动。
|
|
13
|
+
|
|
14
|
+
一次显式的 Task-final Review 使用既有的 Task 局部 Reviewer Role,不要求存在同名
|
|
15
|
+
的 global Role。只有当请求的 Task Role 不存在时,global Role 才作为创建模板。
|
|
16
|
+
可用性、producer 分离和冻结的审查候选仍然适用。
|
|
17
|
+
|
|
18
|
+
## Profile
|
|
19
|
+
|
|
20
|
+
Agent Profile 把可移植行为(指令、Skill 和访问意图)与运行时意图组合在一起。
|
|
21
|
+
运行时要么沿用当前 Global Worker 绑定,要么显式选择一个 Agent 并可选 model 和
|
|
22
|
+
effort。`config profile reset` 提供 `worker`、`explorer`、`implementer` 和
|
|
23
|
+
`reviewer`。
|
|
24
|
+
|
|
25
|
+
从 Profile 创建 Task Role 会冻结其解析后的行为和绑定。之后对 Profile 或 Global
|
|
26
|
+
Worker 的编辑不会改写既有的 Task Role。重新套用一个 Profile 是一次显式配置变更。
|
|
27
|
+
所选 Agent 必须与目标绑定匹配;显式的 Role 选项覆盖对应的模板字段。Profile
|
|
28
|
+
不是 Session、工作区 owner 或资源 grant。
|
|
29
|
+
|
|
30
|
+
原生子代继承其父 Agent 和权限。Profile 可以引导它们的行为;model/effort 覆盖
|
|
31
|
+
需要真实的原生工具支持。它们不获得 Yui Role、独立 Assignment 或更大范围。
|
|
32
|
+
|
|
33
|
+
## 期望、生效与观察
|
|
34
|
+
|
|
35
|
+
期望设置是下一次启动的意图。AgentRun 和 Session 捕获生效启动:Agent/组件、
|
|
36
|
+
协议、model、effort、权限策略、工作区/环境、Role 上下文以及 planning/delivery
|
|
37
|
+
权限。
|
|
38
|
+
|
|
39
|
+
对运行中配置的检查单独报告 Agent 实际声明的内容。unsupported 和 unknown 都是
|
|
40
|
+
显式的;一个被接受的 setter 若没有回报当前值,并不算已观察到的匹配。读取配置
|
|
41
|
+
不会修改 Agent 以让观察与期望一致。
|
|
42
|
+
|
|
43
|
+
Worker 绑定变更保留活动 Assignment 的 Agent 和生效快照;之后的显式派发使用当前
|
|
44
|
+
选择。Leader 替换撤销上一条管理入口,但不改写 Worker Assignment。更改期望配置
|
|
45
|
+
不会热改原生 Session。一次显式的 `task role session new` 请求会在选择新 Session
|
|
46
|
+
之前处理旧运行时清理;它不要求先手动结算 Run 状态。一个有用的 Session 可以复用,
|
|
47
|
+
但它绝不是 Task 上下文的唯一持有者。
|
|
48
|
+
|
|
49
|
+
## 权限与 Project 上下文
|
|
50
|
+
|
|
51
|
+
Provider 权限策略、Profile 访问意图和 Project 写范围是不同的合同。Provider 旁路
|
|
52
|
+
不授予对另一个 Project 的写入。受管工作区 owner、精确 Assignment 和资源 grant
|
|
53
|
+
落实 Yui 操作;宽泛的原生权限不是 OS 沙箱。
|
|
54
|
+
|
|
55
|
+
Yui 提供其通用 Role Skill 和 Context 指针。Project Skill 仍是由 Agent 原生发现的
|
|
56
|
+
普通 Project 文件。Project Knowledge 维护在 `YUI_HOME` 下;把仓库材料复制进 prompt
|
|
57
|
+
并不使其成为权威 Knowledge。
|
|
58
|
+
|
|
59
|
+
## 原生认证
|
|
60
|
+
|
|
61
|
+
账号配置比 Session 活得更久。Yui 保留 `HOME` 和所选的 `CLAUDE_CONFIG_DIR`;
|
|
62
|
+
新建/恢复的 Session 不会复制、清除或伪造原生登录、key 批准或 onboarding 记录。
|
|
63
|
+
|
|
64
|
+
对 Claude Code,标准的 API-key、base-URL、bearer/OAuth、model-alias 以及原生
|
|
65
|
+
provider 选择相关环境变量只转发给 Claude。这些值留在 Controller 可替换的运行时
|
|
66
|
+
环境和子进程中,不进入 Task/Role 记录。取消某个来源并刷新 Controller 环境,即可
|
|
67
|
+
在后续启动中移除它。其他自定义凭据变量仍使用显式的 Agent 环境绑定或原生用户设置;
|
|
68
|
+
Yui 不继承整个 shell 环境,也不推断云凭据。
|
|
69
|
+
|
|
70
|
+
Claude 自身加载原生设置,并按其生效配置在 API key、既有 helper、登录凭据、profile
|
|
71
|
+
和云认证之间做选择。Yui 不注入 `apiKeyHelper`、不复制凭据文件,也不覆盖原生认证
|
|
72
|
+
优先级。显式的 `--settings` 路径和 settings 来源选择被原样透传。
|
|
73
|
+
|
|
74
|
+
全新的原生配置仍可能需要 Claude 的初始化、key、工作区和安全确认,包括访问初始化
|
|
75
|
+
服务。隔离 `YUI_HOME` 或替换 Session 都不要求一个全新的原生账号目录。受管的 Task
|
|
76
|
+
执行使用 Claude 的非交互 stream-json 路径,并沿用同样的原生配置归属。
|
|
77
|
+
|
|
78
|
+
## 命令
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
yui config agent capabilities <agent-id>
|
|
82
|
+
yui config role show <global-role>
|
|
83
|
+
yui config profile show <profile>
|
|
84
|
+
yui task role add <task> <role> --profile <profile>
|
|
85
|
+
yui task role show <task> <role>
|
|
86
|
+
yui task role update <task> <role> --environment <preparation-id>
|
|
87
|
+
yui task role update <task> <role> --managed-environment
|
|
88
|
+
yui task role session inspect <task> <role>
|
|
89
|
+
yui task role session new <task> <role> --reason "<why a fresh Session is useful>"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
创建 Role 时,显式的 Agent 设置需要 `--agent`。更新时,省略 `--agent` 针对活动
|
|
93
|
+
绑定;一个具名绑定会被更新但不被激活。`task role bind` 更改选择。在更改期望设置
|
|
94
|
+
之前,活动 Session 需要该命令的显式确认。
|
|
95
|
+
|
|
96
|
+
关于原生配置和实现限制,参见 [Provider Runtime](provider-runtime.zh-CN.md)。
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<p align="right"><a href="./sqlite-control-plane-design.md">English</a> | <strong>简体中文</strong></p>
|
|
2
|
+
|
|
3
|
+
# SQLite 控制面存储
|
|
4
|
+
|
|
5
|
+
Yui 只有一个权威产品 Store:WAL 模式下的 `YUI_HOME/yui.db`。`schema_migrations`
|
|
6
|
+
中连续且带校验和的最高一行,就是当前发行版接受的那一个 Home 存储版本。
|
|
7
|
+
|
|
8
|
+
## 权威
|
|
9
|
+
|
|
10
|
+
- `yui.db` 拥有 Task、WorkItem、AgentRun、Message、Decision、结果、Project
|
|
11
|
+
Knowledge 引用、受管工作区记录、运行时绑定、mailbox、持久事件和配置。
|
|
12
|
+
- Provider Session、transcript、进程、缓存、telemetry 和运行时观察服务于执行
|
|
13
|
+
与诊断,不替代持久的 Task 事实。
|
|
14
|
+
- 数据库之外的配置和诊断不定义另一个存储版本,也不允许启发式地重建 Task 真相。
|
|
15
|
+
|
|
16
|
+
## 准入
|
|
17
|
+
|
|
18
|
+
普通命令只有在同时满足以下条件时才打开 Home:
|
|
19
|
+
|
|
20
|
+
1. `yui.db` 存在,且其迁移账本是一个有效的不可变前缀。
|
|
21
|
+
2. 账本头恰好等于运行中 CLI 的当前存储版本。
|
|
22
|
+
3. 当前记录校验与引用完整性均通过。
|
|
23
|
+
|
|
24
|
+
落在 CLI 支持区间内的更旧 Home 无法通过普通准入,但被归类为可升级。
|
|
25
|
+
`yui doctor` 和 `yui upgrade --dry-run` 会报告有序的升级路径而不改动 Home。
|
|
26
|
+
显式的 `yui upgrade` 是唯一的独立变更边界:它让 Controller 静止、备份
|
|
27
|
+
`yui.db`、以事务方式套用所有缺失迁移,并校验当前模型。更新的、低于最低版本的、
|
|
28
|
+
不完整的或损坏的 Home 一律 fail closed。不存在运行时归一化、修复 worker、
|
|
29
|
+
文件 Store 回退、双读写路径或第二套迁移权威。
|
|
30
|
+
|
|
31
|
+
## 写入与并发合同
|
|
32
|
+
|
|
33
|
+
- 每次修改是一个 SQLite 事务。
|
|
34
|
+
- WAL 加 `synchronous=FULL` 提供持久提交边界。
|
|
35
|
+
- `home_meta.revision` 是全 Home 范围的 CAS/revision,供需要冻结
|
|
36
|
+
read/modify/write 边界的调用者使用。
|
|
37
|
+
- 类型化列支持按身份和状态建索引查询;完整且经校验的记录负载仍是持久的领域表示。
|
|
38
|
+
- mailbox 认领、精确的 AgentRun 终结、活动指针移除、结果持久化以及下游唤醒创建,
|
|
39
|
+
在它们构成同一条产品事实时以事务方式耦合。
|
|
40
|
+
- 幂等键与唯一约束保护可重复的外部效果确认,不构成第二套工作流状态机。
|
|
41
|
+
|
|
42
|
+
## AgentRun 与 Session 边界
|
|
43
|
+
|
|
44
|
+
AgentRun 是一次明确请求的执行。它记录相关的可见输入和原始结果,而不是隐藏的
|
|
45
|
+
推理过程或完整工具轨迹。一个 Provider Session 可以包含多个 Run、普通原生对话
|
|
46
|
+
和通知。原生对话和通知不会自动创建 Run。只有精确关联的原生终态才结算该 Run;
|
|
47
|
+
WorkItem 与 Task 的验收权威仍归 Leader。
|
|
48
|
+
|
|
49
|
+
## 更新行为
|
|
50
|
+
|
|
51
|
+
`yui update` 暂存一个确切的包,并要求那个暂存二进制把 Home 判定为当前、可迁移
|
|
52
|
+
或受阻。随后它停止那个确切的 Controller、激活同一个包、在需要时运行暂存发行版
|
|
53
|
+
的完整迁移链、校验已安装二进制与当前 Home,再启动替换后的 Controller。
|
|
54
|
+
|
|
55
|
+
每次持久 schema 或负载变更都追加一条不可变、连续的存储迁移。CLI 同时发布
|
|
56
|
+
`storageVersion` 与 `minimumStorageVersion`;处在该闭区间内的每个有效 Home 都能
|
|
57
|
+
直接升级到当前版本,无需安装中间发行版。当前源码在
|
|
58
|
+
`src/storage/storageVersions.ts` 中声明存储版本 **18**、最低支持迁移版本 **1**。
|
|
59
|
+
低于该下限的 Home 不是迁移输入,保持原样不动。目标二进制的
|
|
60
|
+
`upgrade --update-preflight` 与 `--update-apply` 结果形态,以及由父进程持有的
|
|
61
|
+
交接锁证明,对从存储版本 1 起发布的每个 updater 都保持向后兼容,因此一个旧的
|
|
62
|
+
源码 CLI 仍能驱动一个新得多的目标的完整迁移链。
|
|
@@ -1,57 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Run
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
1
|
+
<p align="right"><strong>English</strong> | <a href="./task-dag-semantics.zh-CN.md">简体中文</a></p>
|
|
2
|
+
|
|
3
|
+
# Task dependencies and WorkItem semantics
|
|
4
|
+
|
|
5
|
+
## Requirement and execution are separate
|
|
6
|
+
|
|
7
|
+
A Task is one bounded outcome; a WorkItem is an independently acceptable
|
|
8
|
+
requirement within it. Task type does not dictate execution topology: the Leader
|
|
9
|
+
can work directly or create WorkItems delivered by separate owners. An
|
|
10
|
+
implementation step, a single test, a review finding or a small fix does not
|
|
11
|
+
become a new WorkItem on its own.
|
|
12
|
+
|
|
13
|
+
The persistent WorkItem status is only `open / accepted / retired`:
|
|
14
|
+
|
|
15
|
+
- `open`: the requirement is still in progress — not yet executed, executing,
|
|
16
|
+
awaiting acceptance or needing another attempt.
|
|
17
|
+
- `accepted`: the Leader has explicitly accepted the current delivery.
|
|
18
|
+
- `retired`: the requirement is explicitly retired, with its record and reason
|
|
19
|
+
preserved.
|
|
20
|
+
|
|
21
|
+
Execution status belongs to AgentRun, and a Candidate records the result
|
|
22
|
+
currently awaiting acceptance. Submission, rejection or execution failure does
|
|
23
|
+
not turn a WorkItem into a second runtime state machine. Withdrawing acceptance
|
|
24
|
+
is an explicit action.
|
|
25
|
+
|
|
26
|
+
## One dependency authority
|
|
27
|
+
|
|
28
|
+
`WorkItem.dependsOn` is the list of direct dependencies within the same Task. A
|
|
29
|
+
prerequisite A → downstream B means B's `dependsOn` contains A. Saving checks
|
|
30
|
+
same-Task references, existence and the acyclic constraint. It does not express
|
|
31
|
+
Provider concurrency, Session occupancy or file locks.
|
|
32
|
+
|
|
33
|
+
At dispatch, every direct dependency must exist and be `accepted`. An open,
|
|
34
|
+
retired or missing dependency cannot satisfy it, and the error returns the exact
|
|
35
|
+
ID and current status. A successful Run, an existing Candidate, a completed
|
|
36
|
+
Review or an integrated Git change does not substitute for WorkItem acceptance.
|
|
37
|
+
|
|
38
|
+
A retired WorkItem's replacement field only explains the substitution; it does
|
|
39
|
+
not redirect or rewrite dependencies. The Leader must explicitly revise the
|
|
40
|
+
requirement or its dependencies. The Controller does not release downstream work
|
|
41
|
+
along a replacement chain, cascade cancellation, auto-skip, or turn the
|
|
42
|
+
dependency list into a scheduling plan.
|
|
43
|
+
|
|
44
|
+
## Editing and recovery
|
|
45
|
+
|
|
46
|
+
A legal edit to an open WorkItem definition preserves the before/after values and
|
|
47
|
+
keeps its identity and execution evidence. An already-started Run keeps its
|
|
48
|
+
frozen Assignment; editing the current requirement does not retroactively rewrite
|
|
49
|
+
that Run's Context or permissions. Accepted and retired definitions cannot be
|
|
50
|
+
overwritten by an ordinary edit. Owner and resource-scope changes are checked at
|
|
51
|
+
their own boundaries.
|
|
52
|
+
|
|
53
|
+
On execution failure, the Leader inspects the original result, Session,
|
|
54
|
+
dependencies and workspace, then decides to continue, retry, retire or revise the
|
|
55
|
+
plan. After retirement, a late message keeps its source and non-delivery reason
|
|
56
|
+
and does not auto-reopen. An InputRequest represents an open question; answering
|
|
57
|
+
it does not accept a WorkItem or rewrite dependencies.
|
|
58
|
+
|
|
59
|
+
## Acceptance, integration and Task completion
|
|
60
|
+
|
|
61
|
+
Direct and replicated execution share one Leader acceptance boundary. A
|
|
62
|
+
replicated Producer does not form a Candidate; only the explicitly synthesized
|
|
63
|
+
main Run result enters the candidate path. Delivery the Leader manages directly
|
|
64
|
+
must also satisfy the applicable Candidate, ChangeSet and Integration boundaries.
|
|
65
|
+
|
|
66
|
+
An isolated code result captures a fixed per-Project ChangeSet and integrates via
|
|
67
|
+
compare-and-swap after its checks; an uncaptured, unintegrated or stale latest
|
|
68
|
+
result cannot satisfy delivery. Review is checked against the applicable rule and
|
|
69
|
+
the Task contract. A Task main the Leader delivers itself needs a clean,
|
|
70
|
+
committed, exact snapshot.
|
|
71
|
+
|
|
72
|
+
The Task lifecycle is `draft / active / completed / cancelled / archived`. A
|
|
73
|
+
Draft plans first and then explicitly adopts a workspace; completed and cancelled
|
|
74
|
+
Tasks do not accept implicit new execution, and a reopen never replays old
|
|
75
|
+
requests; an archived Task cannot reopen. Archive also requires resources to be
|
|
76
|
+
quiescent, clean and removable, and never deletes a workspace merely because of
|
|
77
|
+
the dependency graph or a completion status.
|
|
78
|
+
|
|
79
|
+
CLI and Web derive their views and suggestions from these facts; they do not
|
|
80
|
+
maintain a second writable DAG, acceptance state or plan.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<p align="right"><a href="./task-dag-semantics.md">English</a> | <strong>简体中文</strong></p>
|
|
2
|
+
|
|
3
|
+
# Task 依赖与 WorkItem 语义
|
|
4
|
+
|
|
5
|
+
## 需求与执行分离
|
|
6
|
+
|
|
7
|
+
Task 是一个有界结果,WorkItem 是其中可独立验收的需求。Task type 不决定
|
|
8
|
+
执行拓扑;Leader 可以直接工作,也可以创建独立负责人交付的 WorkItem。
|
|
9
|
+
实现步骤、一次测试、审查发现或小修补不因此成为新 WorkItem。
|
|
10
|
+
|
|
11
|
+
WorkItem 持久状态仅为 `open / accepted / retired`:
|
|
12
|
+
|
|
13
|
+
- `open`:需求仍在处理;可能尚未执行、正在执行、等待验收或需要重试。
|
|
14
|
+
- `accepted`:Leader 已显式接受当前交付。
|
|
15
|
+
- `retired`:需求已显式退役,保留记录和原因。
|
|
16
|
+
|
|
17
|
+
执行状态归 AgentRun,Candidate 记录当前待接受的结果。提交、拒绝或执行失败
|
|
18
|
+
不把 WorkItem 变成另一套运行状态。接受撤回是显式动作。
|
|
19
|
+
|
|
20
|
+
## 唯一依赖权威
|
|
21
|
+
|
|
22
|
+
`WorkItem.dependsOn` 是同一 Task 内的直接依赖列表。前置项 A → 下游 B
|
|
23
|
+
表示 B 的 `dependsOn` 包含 A。保存时检查同 Task 引用、存在性和无环约束。
|
|
24
|
+
它不表达 Provider 并发、Session 占用或文件锁。
|
|
25
|
+
|
|
26
|
+
派发时,每个直接依赖必须存在且为 `accepted`。Open、retired 或 missing
|
|
27
|
+
均不能满足依赖,错误返回具体 ID 和当前状态。Run 成功、Candidate 存在、
|
|
28
|
+
Review 完成或 Git 已集成都不能代替 WorkItem 接受。
|
|
29
|
+
|
|
30
|
+
退役的 replacement 字段只解释替代关系,不重定向或重写依赖。
|
|
31
|
+
Leader 必须显式修订需求或依赖;Controller 不沿替换链自动释放下游,
|
|
32
|
+
不级联取消、不自动跳过,也不把依赖列表变成调度计划。
|
|
33
|
+
|
|
34
|
+
## 修改与恢复
|
|
35
|
+
|
|
36
|
+
Open WorkItem 的合法定义编辑保存前后值,保留身份和执行证据。已经启动的
|
|
37
|
+
Run 仍使用冻结 Assignment;修改当前需求不追溯改写其 Context 或权限。
|
|
38
|
+
已接受和退役的定义不能借普通编辑覆盖。负责人与资源范围变更受各自边界检查。
|
|
39
|
+
|
|
40
|
+
执行失败时,Leader 检查原始结果、Session、依赖与工作区,决定续作、重试、
|
|
41
|
+
退役或修改计划。退役后迟到消息保留来源和未投递原因,不自动重开。
|
|
42
|
+
InputRequest 表示待决问题;回答不自动接受 WorkItem 或改写依赖。
|
|
43
|
+
|
|
44
|
+
## 接受、集成与 Task 完成
|
|
45
|
+
|
|
46
|
+
Direct 和 replicated 共享一个 Leader 接受边界。Replicated Producer 不形成
|
|
47
|
+
Candidate;只有显式综合的 main Run 结果进入候选路径。Leader 直接管理的
|
|
48
|
+
交付也必须满足适用的 Candidate、ChangeSet 和 Integration 边界。
|
|
49
|
+
|
|
50
|
+
隔离代码结果按 Project 捕获固定 ChangeSet,检查后 CAS 集成;未捕获、未集成
|
|
51
|
+
或失效的最新结果不能满足交付。Review 依适用规则和 Task 合同检查。
|
|
52
|
+
Leader 自己交付的 Task main 需要干净、已提交的精确快照。
|
|
53
|
+
|
|
54
|
+
Task lifecycle 是 `draft / active / completed / cancelled / archived`。
|
|
55
|
+
Draft 先规划再显式采用工作区;completed/cancelled 不接收隐式新执行,
|
|
56
|
+
reopen 不重放旧请求;archived 不可重开。Archive 还要求资源静止、干净可移除,
|
|
57
|
+
不因依赖图或完成状态自动删除工作区。
|
|
58
|
+
|
|
59
|
+
CLI/Web 从这些事实派生展示和建议,不维护第二套可写 DAG、验收状态或计划。
|