@twinsearth/w2m-dsh-plugin 1.3.1 → 1.3.11
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +588 -0
- package/bin/w2m-maintenance.mjs +112 -0
- package/codex/mcp-servers.toml +1 -1
- package/deploy/maintenance/bootstrap.ps1 +30 -0
- package/deploy/maintenance/bootstrap.sh +59 -0
- package/deploy/server/w2m-maintenance.path +10 -0
- package/deploy/server/w2m-maintenance.service +20 -0
- package/deploy/windows/w2m-maintenance.xml +31 -0
- package/docs/COLLAB/COLLABORATION-MODEL.md +240 -0
- package/docs/COLLAB/EXECUTION-AUTH-MODEL.md +250 -0
- package/docs/COLLAB/M1-ACCEPTANCE-RUNBOOK.md +70 -0
- package/docs/COLLAB/M1-MAINTENANCE.md +313 -0
- package/docs/COLLAB/M2-TASK-GRANT.md +231 -0
- package/docs/COLLAB/M3-GIT-NATIVE-TASKS.md +291 -0
- package/docs/COLLAB/M4-PROJECT-ROOM.md +260 -0
- package/docs/COLLAB/M5-MULTI-CLIENT-PRIMITIVES.md +263 -0
- package/docs/COLLAB/M6-CROSS-NETWORK-RELIABILITY.md +231 -0
- package/docs/COLLAB/M7-METRICS-ACCEPTANCE.md +263 -0
- package/docs/COLLAB/TASK-MODEL.md +281 -0
- package/docs/MULTI-MACHINE-COLLABORATION-PLAN.md +186 -0
- package/docs/RELEASE-STABLE.md +193 -0
- package/docs/acceptance/1.3.10-beta.10/M1-LIVE-DIAG.json +27 -0
- package/docs/acceptance/1.3.10-beta.10/M1-LIVE-POSTUPDATE-DIAG.json +18 -0
- package/docs/acceptance/1.3.10-beta.10/M1-LIVE-RESTART.json +24 -0
- package/docs/acceptance/1.3.10-beta.10/M1-LIVE-UPDATE.json +24 -0
- package/docs/acceptance/1.3.11/M1-LIVE-DIAG.json +26 -0
- package/package.json +22 -4
- package/plugin.json +1 -1
- package/src/acceptance/evidence.mjs +79 -0
- package/src/agent/agent.mjs +64 -2
- package/src/agent/grant-gate.mjs +82 -0
- package/src/agent/maintenance-ferry.mjs +111 -0
- package/src/agent/outbox.mjs +138 -0
- package/src/agent/patch-artifact.mjs +53 -0
- package/src/agent/worktree.mjs +109 -0
- package/src/maintenance/actions.mjs +203 -0
- package/src/maintenance/grant.mjs +139 -0
- package/src/maintenance/operator-key.mjs +151 -0
- package/src/maintenance/protocol.mjs +204 -0
- package/src/maintenance/runner.mjs +189 -0
- package/src/plugin/tools.mjs +1 -1
- package/src/relay/blob-sessions.mjs +148 -0
- package/src/relay/merge-queue.mjs +137 -0
- package/src/relay/project-locks.mjs +179 -0
- package/src/relay/project-notifications.mjs +182 -0
- package/src/relay/project-reviews.mjs +161 -0
- package/src/relay/project-room.mjs +163 -0
- package/src/relay/reliability-metrics.mjs +180 -0
- package/src/relay/server.mjs +164 -1
- package/src/relay/state.mjs +128 -1
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# 任务模型(Task Model)设计规格 — v1.4.1-beta
|
|
2
|
+
|
|
3
|
+
> 状态:**模型级设计稿**。把 M3(worktree/patch/合并队列/冲突)与既有任务/数据面能力归纳为统一任务模型,冻结任务种类、工作区、制品、分支与合并语义。
|
|
4
|
+
> 版本:`1.4.1-beta.*`;实现按 M3(1.3.4)与 M5 的审查/锁(1.3.6)分步交付,模型一致性验收在 1.4.1-beta 完成。
|
|
5
|
+
> 相关:`docs/COLLAB/M3-GIT-NATIVE-TASKS.md`、`docs/COLLAB/M5-MULTI-CLIENT-PRIMITIVES.md`、`docs/COLLAB/EXECUTION-AUTH-MODEL.md`。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 问题陈述
|
|
10
|
+
|
|
11
|
+
现状的任务模型只有三个要素:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
任务 = argv + 每台机器自己的项目副本 + 事后锚点一致性检查
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
它隐含三个假设,全部与现实不符:
|
|
18
|
+
|
|
19
|
+
1. **假设只读**:任务不会改动代码;但真实开发必须改。
|
|
20
|
+
2. **假设幂等**:重试安全;但写文件/提交不幂等,重试会产生两份改动。
|
|
21
|
+
3. **假设结果只是文本**:stdout/stderr;但代码改动需要**可合并的制品**(commit/tree/patch)与**冲突语义**。
|
|
22
|
+
|
|
23
|
+
后果:多台机器只能"各自跑命令",无法共同完成一个改动;没有分支/合并/冲突,就没有"联合开发"。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. 任务模型总览
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Task = 意图 + 输入 + 工作区 + 义务 + 结果 + 证据
|
|
31
|
+
|
|
32
|
+
意图 kind(exec/worktree/merge/review/maintenance)
|
|
33
|
+
输入 argv、argv 约束、base_commit、project/branch、依赖、授权能力
|
|
34
|
+
工作区 none / copy(旧行为)/ worktree(隔离)
|
|
35
|
+
义务 gates:测试门禁、审查门禁、锁、锚点
|
|
36
|
+
结果 结构化信封:status/outcome + artifacts + workspace 证据 + tests
|
|
37
|
+
证据 ledger 事件 + 内容寻址制品 + 签名/授权来源(provenance)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
任务模型与另外两个模型的分工:
|
|
41
|
+
|
|
42
|
+
| 模型 | 回答的问题 |
|
|
43
|
+
|---|---|
|
|
44
|
+
| 执行授权模型(v1.4.0) | 这台机器**能否执行**这条命令/这次维护 |
|
|
45
|
+
| **任务模型(本文)** | **执行什么、在哪个工作区、产出什么、如何合并** |
|
|
46
|
+
| 协作模型(v1.4.2) | **谁在哪个项目/房间**与谁协作、权限与通知 |
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 3. 任务种类(kind)与副作用分类
|
|
51
|
+
|
|
52
|
+
| kind | 工作区 | 副作用 | 执行者 | 重试语义 |
|
|
53
|
+
|---|---|---|---|---|
|
|
54
|
+
| `exec` | none/copy | 只读(红线保证) | agent | 可自由重试(幂等由只读保证) |
|
|
55
|
+
| `worktree` | 隔离 worktree | 改动代码(制品化) | agent | 新尝试 = 新 worktree(丢弃半成品) |
|
|
56
|
+
| `merge` | 合并专用 worktree | 推进项目 ref | 指定合并器(M2 grant) | 幂等(patch_sha+head 去重,已合并即 no-op) |
|
|
57
|
+
| `review` | 无 | 无代码副作用(结论) | 人/客户端 | 幂等(重复结论拒绝) |
|
|
58
|
+
| `maintenance` | 无 | root 系统动作 | root runner | 幂等(request_id) |
|
|
59
|
+
|
|
60
|
+
**副作用分类是模型的根**:任务的幂等/重试/隔离策略由副作用类型决定,而不是由调用方口头声明。
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## 4. 工作区模型
|
|
65
|
+
|
|
66
|
+
### 4.1 三种工作区
|
|
67
|
+
|
|
68
|
+
| workspace.kind | 语义 | 隔离 | 用于 |
|
|
69
|
+
|---|---|---|---|
|
|
70
|
+
| `none` | 不提供项目副本(纯命令) | 与机器其他任务共用 | 诊断类 exec |
|
|
71
|
+
| `copy`(兼容默认) | 机器上的现有项目副本 | 无(v1.3.x 行为) | 既有调用方 |
|
|
72
|
+
| `worktree` | 每任务独立 git worktree,起点=base_commit | 强隔离 | 所有会产生代码改动的任务 |
|
|
73
|
+
|
|
74
|
+
### 4.2 worktree 不变量
|
|
75
|
+
|
|
76
|
+
1. 起始点严格等于 `base_commit`(不存在则 `BASE_COMMIT_UNKNOWN`)。
|
|
77
|
+
2. 写权限**仅限 worktree 内**;`.git` 管理目录由执行器接管(hooks/config 禁用)。
|
|
78
|
+
3. 任务结束:成功 → 制品化(commit/patch)→ 清理;失败/超时 → 丢弃 worktree。
|
|
79
|
+
4. 并发上限(默认 4/机器);超限 `WORKTREE_LIMIT`。
|
|
80
|
+
5. 执行前后取 `git status` 快照,作为证据的一部分。
|
|
81
|
+
6. 同一 base 上的两个任务互不可见;合并时才相遇。
|
|
82
|
+
|
|
83
|
+
### 4.3 为什么不是"各自副本"
|
|
84
|
+
|
|
85
|
+
`copy` 工作区无法回答"这台机器的改动是相对哪个版本",也无法隔离并发任务。`worktree` 让改动**总是相对一个明确 base**,从而可传输、可合并、可审计。
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 5. 制品模型(Artifact)
|
|
90
|
+
|
|
91
|
+
制品是任务结果的**一等公民**,内容寻址且不可变:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"sha256": "…",
|
|
96
|
+
"kind": "patch|conflict|diagnostic|report|log|binary",
|
|
97
|
+
"bytes": 12345,
|
|
98
|
+
"output_mode": "inline|blob",
|
|
99
|
+
"label": "patch for 01M6…",
|
|
100
|
+
"produced_by": { "task_id": "…", "machine_id": "…", "attempt": 1 },
|
|
101
|
+
"basis": { "base_commit": "…", "head_commit": "…", "tree": "…" },
|
|
102
|
+
"created_at": "…"
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
规则:
|
|
107
|
+
|
|
108
|
+
- **上传完成前不可引用**;引用后内容不可变(sha 就是身份)。
|
|
109
|
+
- `patch` 制品必须携带 `base_commit` 与头部提交信息;合并器只接受"从声明的 base 生成"的 patch,并重新计算 sha 校验。
|
|
110
|
+
- `conflict` 制品是冲突现场(含 conflict markers 的 diff),任何项目成员可下载。
|
|
111
|
+
- 制品可超过内联阈值 → M6 分块/blob 通道;大 patch 不阻塞任务上报。
|
|
112
|
+
- 制品生命周期与项目绑定(M4);默认保留 30 天,可选永久(发布附件)。
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 6. 分支与合并模型
|
|
117
|
+
|
|
118
|
+
### 6.1 分支
|
|
119
|
+
|
|
120
|
+
- 项目(M4)拥有一个或多个分支 ref;任务声明 `target_branch`。
|
|
121
|
+
- `base_commit` 必须属于目标分支历史(合并器校验)。
|
|
122
|
+
- 分支 head **只由合并任务推进**;agent 绝不直接写项目 ref。
|
|
123
|
+
- 红线:禁止 force push/改写历史(`FORCE_PUSH_REFUSED`);head 单调前进。
|
|
124
|
+
|
|
125
|
+
### 6.2 合并队列
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
(queue per project+branch)
|
|
129
|
+
item = {queue_id, patch_sha, base_commit, source_task_id, submitted_by, state}
|
|
130
|
+
state: queued → claimed → applying → merged | conflict | failed
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- 同一队列同一时刻一个合并器(merge-slot lease,M5 的锁是用户级协调,二者互补)。
|
|
134
|
+
- 合并步骤固定:取队首 → 校验 patch_sha/base → `git apply --3way`/`git am` → 门禁 → 推进 head → 事件 → 释放。
|
|
135
|
+
- 合并策略(项目配置):
|
|
136
|
+
- `strict`(默认):base 必须等于当前 head,否则 `BASE_MISMATCH`
|
|
137
|
+
- `replay`:能干净应用到新 head 则重放,否则冲突
|
|
138
|
+
- `queue-base`:按队列顺序依次应用(顺序保证,不等价最新 head)
|
|
139
|
+
- 门禁(可组合):测试门禁(同 patch_sha 测试任务通过)、审查门禁(同 patch_sha 有 approved 审查)、锁门禁(enforced 分支/文件锁)。
|
|
140
|
+
- 幂等:同一 `(patch_sha, target_head)` 已合并 → `already_merged`(no-op);重放/重试安全。
|
|
141
|
+
|
|
142
|
+
### 6.3 冲突是一等结果
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"status": "conflict",
|
|
147
|
+
"reason_code": "MERGE_CONFLICT",
|
|
148
|
+
"merge": {
|
|
149
|
+
"patch_sha": "…", "target_head": "…", "base_commit": "…",
|
|
150
|
+
"files": ["src/a.mjs"],
|
|
151
|
+
"hunks": [{"file": "src/a.mjs", "start": 10, "lines": 4, "side": "both"}],
|
|
152
|
+
"artifact_sha256": "冲突现场(blob)",
|
|
153
|
+
"next": "由人选择解决者:重新提交到新 base / 手动解决后作为新 patch 入队"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
- 冲突时**绝不推进 head、绝不覆盖任何人的改动**。
|
|
159
|
+
- 不自动重试(防抖动);解决方式是新 patch 入队。
|
|
160
|
+
- 冲突现场可被审查任务、项目房间、通知引用(M4/M5)。
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 7. 结果信封与证据
|
|
165
|
+
|
|
166
|
+
任务结果统一为结构化信封(向后兼容既有字段):
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"task_id": "…", "attempt": 1, "kind": "worktree",
|
|
171
|
+
"status": "ok|failed|refused|conflict|timeout|expired",
|
|
172
|
+
"outcome": "ok|no_change|merged|already_merged|…",
|
|
173
|
+
"reason_code": null,
|
|
174
|
+
"authorization": { "provenance": "grant|allow-list|maintenance", "capability_id": "…" },
|
|
175
|
+
"workspace": { "kind": "worktree", "base_commit": "…", "head_commit": "…", "tree": "…", "cleaned": true },
|
|
176
|
+
"artifacts": [{ "sha256": "…", "kind": "patch", "bytes": 1234, "output_mode": "blob" }],
|
|
177
|
+
"tests": { "ran": true, "exit_code": 0, "summary": "…" },
|
|
178
|
+
"evidence": { "status_before": "…", "status_after": "…", "diffstat": {…} },
|
|
179
|
+
"timings": { "started_at": "…", "ended_at": "…", "duration_ms": 1234 }
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
规则:
|
|
184
|
+
|
|
185
|
+
- 结果必须可**仅凭信封**回答:执行了什么(授权来源)、在什么基础上、产出了什么(制品 sha)、有没有门禁。
|
|
186
|
+
- 不引用不存在的制品;上传失败 → `BLOB_UPLOAD_FAILED`(任务失败而不是静默降级)。
|
|
187
|
+
- 结果进 ledger,可重放;`provenance` 用于审计"哪次显式授权"。
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## 8. 状态机与重试
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
created → queued(waiting: deps/locks/gates) → offered → running → reporting → terminal
|
|
195
|
+
terminal = done | failed | refused | conflict | timeout | expired | cancelled
|
|
196
|
+
|
|
197
|
+
merge 任务:queued → claimed → applying → merged | conflict | failed
|
|
198
|
+
retry 规则(按副作用):
|
|
199
|
+
exec:可直接重试(只读),attempt += 1
|
|
200
|
+
worktree:重试 = 新 worktree(从同一 base),旧产物丢弃并记录
|
|
201
|
+
merge:重试 = 重新入队(幂等);已合并则 no-op
|
|
202
|
+
maintenance:重试 = 同 request_id(幂等),已执行返回既有结果
|
|
203
|
+
任何重试都必须保留 attempt 与去重键,防止双执行
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
关键不变量:
|
|
207
|
+
|
|
208
|
+
1. **at-most-once 副作用**:同一 `(task_id, attempt, dedupe_key)` 最多执行一次。
|
|
209
|
+
2. **结果幂等**:relay 对重复结果去重;agent outbox(M6)保证最终投递。
|
|
210
|
+
3. **不悬挂**:租约过期后任务可重派发;策略(halt)决定是否由其他机器接手。
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 9. 失败分类(模型级)
|
|
215
|
+
|
|
216
|
+
```
|
|
217
|
+
输入类:BASE_COMMIT_UNKNOWN、BASE_MISMATCH、PATCH_APPLY_FAILED、ARTIFACT_UNKNOWN
|
|
218
|
+
资源类:WORKTREE_LIMIT、BLOB_QUOTA、OUTBOX_FULL
|
|
219
|
+
门禁类:TESTS_REQUIRED、REVIEW_REQUIRED、LOCK_WAIT_TIMEOUT、PATH_LOCK_CONFLICT
|
|
220
|
+
合并类:MERGE_CONFLICT、FORCE_PUSH_REFUSED、NOT_MERGE_EXECUTOR、MERGE_ABORTED
|
|
221
|
+
授权类:RED_LINE_VIOLATION、NOT_AUTHORIZED、GRANT_*、MAINTENANCE_*
|
|
222
|
+
传输类:BLOB_INCOMPLETE、BLOB_SHA_MISMATCH、SESSION_NOT_FOUND
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
每类都必须有负向测试(M7 的 negative matrix)。
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## 10. 兼容与迁移
|
|
230
|
+
|
|
231
|
+
- 新字段全部可选;`kind` 缺省 = `exec`,`workspace.kind` 缺省 = `copy` → 既有调用方行为不变。
|
|
232
|
+
- 旧 relay 忽略新字段;旧 agent 按旧逻辑执行(可能拒绝或只读)。
|
|
233
|
+
- 旧任务(无 project_id)惰性归入 default 项目(M4);不重写 ledger。
|
|
234
|
+
- 迁移路径:`exec/copy` → 逐步把写任务切到 `worktree`;合并队列按项目启用(默认不启用,显式开启)。
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 11. 验收(模型一致性)
|
|
239
|
+
|
|
240
|
+
### 正向(真实任务证据)
|
|
241
|
+
|
|
242
|
+
1. **联合改动**:两机各自 worktree 任务(不同文件)→ 两个 patch 入队 → 合并器依次合并 → 项目 head 含两者改动,测试通过,两条 ref.updated 事件。
|
|
243
|
+
2. **冲突**:两机改同一处 → 第二个 item 返回结构化 `MERGE_CONFLICT`(文件/hunk/现场 blob),head 不变。
|
|
244
|
+
3. **base 前进**:strict 下返回 `BASE_MISMATCH`;replay 下干净应用则自动合并。
|
|
245
|
+
4. **门禁**:测试/审查/锁门禁分别挡住合并,满足后续行。
|
|
246
|
+
5. **幂等**:同 patch 重复入队 → `already_merged`;worktree 任务重试不产生两份改动。
|
|
247
|
+
6. **结果证据**:每个任务信封能独立回答"授权来源/base/制品/门禁"。
|
|
248
|
+
|
|
249
|
+
### 负向(自动化矩阵)
|
|
250
|
+
|
|
251
|
+
```
|
|
252
|
+
非 worktree 产出的 patch / 篡改 sha / 写 .git / 直接改项目 ref / force push /
|
|
253
|
+
merge 中断后锁恢复 / worktree 超限 / 冲突被误判为成功 / 缺门禁仍合并 /
|
|
254
|
+
重试双执行 / 结果引用不存在的 blob → 全部对应错误码且 ref 不变
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 12. 与版本/模块的映射
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
1.3.4-beta M3 实现:worktree/patch/合并队列/冲突(本章 §4–§7 的落地)
|
|
263
|
+
1.3.6-beta M5 实现:锁与审查任务(本章门禁部分)
|
|
264
|
+
1.4.1-beta 模型一致性验收:统一 kind/结果信封/幂等语义/失败分类
|
|
265
|
+
共享模块:
|
|
266
|
+
src/relay/task-model.mjs 任务种类与状态机、副作用分类
|
|
267
|
+
src/relay/merge-queue.mjs 队列/merge-slot/门禁/幂等
|
|
268
|
+
src/relay/project-ref.mjs 分支 head 与单调推进
|
|
269
|
+
src/agent/worktree.mjs 工作区生命周期(M3)
|
|
270
|
+
src/agent/patch-artifact.mjs 制品生成/上传/证据
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## 13. 开放问题(实现前确认)
|
|
274
|
+
|
|
275
|
+
1. **写任务的默认 kind**:显式 `worktree` 才允许写(推荐),还是 copy 也允许写(兼容但危险)?
|
|
276
|
+
2. **仓库来源**:项目 origin 指向 GitHub 私仓还是 relay 本机 bare?合并在哪一侧执行?
|
|
277
|
+
3. **合并策略默认**:strict(推荐)还是 replay?
|
|
278
|
+
4. **门禁默认**:测试/审查默认关闭、按项目开启(推荐)?
|
|
279
|
+
5. **非 git 项目**:是否支持"无 git 的 worktree"(文件级快照/补丁)还是只支持 git?
|
|
280
|
+
6. **Windows**:大小写不敏感与 symlink 限制如何表达(限制 patch 内容/仅告警)?
|
|
281
|
+
7. **制品保留**:30 天默认够不够?发布附件是否永久保留?
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# 多机 / 多客户端 / 跨网络协同:能力体检与可行方案
|
|
2
|
+
|
|
3
|
+
> 写作目的:回答一个具体问题 —— **本插件目前没有真正实现"多机协同完成一个任务/联合开发",能力缺口在哪,怎样补,先补什么。**
|
|
4
|
+
> 状态:设计提案(未实现)。所有"已实现"的判断都指向仓库里的具体模块;所有"未实现"都写了可验收的判据。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. 能力体检:现在到底有什么
|
|
9
|
+
|
|
10
|
+
| 能力 | 现状 | 证据(代码/实测) |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| 控制面:多机派发、聚合、等待 | ✅ 可用 | `src/relay/server.mjs` 的 `/v1/task`、`src/agent/agent.mjs`、`w2m_run`/`w2m_wait`;实测 jp-shared 执行 `node --version` 成功 |
|
|
13
|
+
| 数据面:分片、缺分片、reduce 建议/执行 | 🟡 部分 | `src/util/dataflow.mjs`、`src/util/reduce-suggestion.mjs`、`reduce_of/reduce_inputs` + agent 取件(v1.3.1,实测 `REDUCE_INPUT_FETCH_FAILED` 生效) |
|
|
14
|
+
| 跨网络传输 | 🟡 中继可用,P2P 不可靠 | relay HTTP 是权威通道;P2P 有明文/`P2P_CRYPTO_PLAINTEXT_PEER` 拒绝,NAT 场景无成功记录 |
|
|
15
|
+
| 多机"联合改代码" | ❌ 没有 | 每台机器各跑各的副本;任务只声明 `base_commit` 做**一致性检查**,没有"产出补丁→合并→冲突"的工作流 |
|
|
16
|
+
| 多客户端(多人/多 DSH 实例)共事 | ❌ 没有 | 会话状态在各自 DSH;fleet chat 只解决"看消息",不解决共享任务/工作区/权限 |
|
|
17
|
+
| 机器运维(安装/升级/重启/排障) | ❌ 没有(本应是最基本的能力) | allow-list 是**静态配置**;TwinsEarth 实测连 `node --version` 都 `COMMAND_NOT_ALLOWED`;jp-shared 的升级只能靠我临时用 relay 任务通道 + 杀进程绕过 |
|
|
18
|
+
| 机器加入后的"可用性" | ❌ 默认不可用 | join/pair 成功 ≠ 能干活;空 allow-list 的机器在编队里只是"在线但不能执行任何东西" |
|
|
19
|
+
|
|
20
|
+
**一句话**:现在的能力是"一个操作员向若干预先配置好的只读/受限执行器派发命令",不是"多台机器 + 多个客户端协同完成一项工作"。
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. 根因(不是缺一个功能,是缺三个模型)
|
|
25
|
+
|
|
26
|
+
1. **执行授权模型缺失**:allow-list 是机器本地静态配置,只覆盖创建它的人预先想到的命令。远程升级/排障/装插件全部落在清单外,于是"编队"退化成"只读观测网"。放宽 allow-list 不是答案(把任意命令暴露给任何能调度的人)。
|
|
27
|
+
2. **任务模型缺"工作区"**:任务 = argv + 每台机器自己的项目副本 + 事后锚点检查。它假设"命令是幂等只读的";真实联合开发是"产出改动 → 审查 → 合并",需要**补丁/分支/合并队列/冲突**这些一等公民。
|
|
28
|
+
3. **协作模型缺"共享对象"**:没有 relay 侧的 project/room/board/artifact 对象,所以多客户端各看各的;chat 是消息流,不是共享状态;memory 是 CAS 文档,不是任务上下文。
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 3. 设计原则(不牺牲现有安全边界)
|
|
33
|
+
|
|
34
|
+
1. **不放宽 allow-list 来方便自己**:需要更强执行的场面,用**显式的、可审计的、带时限的授权**替代"清单加一条"。
|
|
35
|
+
2. **执行与数据分离**:relay 负责授权、事件、租约、路由;机器只在自己边界内做**被授权**的事。
|
|
36
|
+
3. **内容寻址 + 租约 + 事件日志**是现有底座,继续复用:blob sha256、`depends_on`/`assignee`、ledger 重放。
|
|
37
|
+
4. **跨网络以 relay 为权威传输**:P2P 只做机会性加速,不承担正确性(现在它承担了一部分,是错误的)。
|
|
38
|
+
5. **每个能力都要有"真实任务可触发"的验收**,不是单元测试通过就算数。
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 4. 模块方案(M1–M7)
|
|
43
|
+
|
|
44
|
+
### M1 运维通道(maintenance agent)— 最高优先级
|
|
45
|
+
|
|
46
|
+
**目标**:编队里任何一台机器,都能在**操作员显式授权**下完成"更新自身/重启服务/收集诊断",不需要 SSH,也不需要曾经预先配置过命令。
|
|
47
|
+
|
|
48
|
+
**做法**:
|
|
49
|
+
- 包内新增固定入口 `bin/w2m-maintenance.mjs`(只接受 `--action update|restart|diag`,不做任意 shell)。
|
|
50
|
+
- 机器上的 systemd/Windows 服务用**独立单元**(root/SYSTEM 权限)监听一个请求队列目录(Linux:`/var/lib/w2m/maintenance/queue`,Windows 计划任务同理);agent(非特权用户)只能**写请求文件**,不能执行。
|
|
51
|
+
- 请求文件 = 操作员私钥签名 + 动作 + 目标 sha256 + 过期时间;root 单元校验签名/hash/TTL 后执行固定动作,结果写回 `/var/lib/w2m/maintenance/done/` 并由 agent 上报 relay。
|
|
52
|
+
- 这样"远程升级 TwinsEarth 插件"变成一次签名请求,而不是求人 SSH。
|
|
53
|
+
|
|
54
|
+
**验收**:操作员发一条 `w2m_update` 类任务 → 目标机器 2 分钟内插件到新版本并重启 → relay 事件日志可审计(谁、何时、hash、结果)。
|
|
55
|
+
|
|
56
|
+
### M2 任务级签名授权(task grants)
|
|
57
|
+
|
|
58
|
+
**目标**:让"清单外命令"在**单次任务、单台机器、短时限**内可执行,而不是永久扩 allow-list。
|
|
59
|
+
|
|
60
|
+
**做法**:
|
|
61
|
+
- 复用既有 Ed25519 基础设施(`src/util/envelope-signature.mjs`、配对时登记的 device public key)。
|
|
62
|
+
- 操作员用独立密钥签 `grant = {argv_hash/mode, machine_ids, ttl, task_id, issued_at}`;relay 把 grant 随 offer 下发;agent 验签通过则跳过 allow-list(仍受红线:不跑 shell 字符串、cwd 限制、输出/时长上限)。
|
|
63
|
+
- grant 进 ledger,可审计、可撤销(撤销 = 停发新的)。
|
|
64
|
+
|
|
65
|
+
**验收**:对一台空 allow-list 的机器派发"一次性授权"命令并成功执行;同一命令无 grant 时仍被拒;grant 过期/换机/改 argv 全部被拒(负向测试)。
|
|
66
|
+
|
|
67
|
+
### M3 Git 原生任务与合并队列(worktree + patch + merge)
|
|
68
|
+
|
|
69
|
+
**目标**:多机真正"联合完成一个代码任务"。
|
|
70
|
+
|
|
71
|
+
**做法**:
|
|
72
|
+
- 任务携带 `repo` + `base_commit` + `branch`;agent 在**每任务独立 worktree**里执行,结果 = `commit`/`patch` 制品(blob)+ 测试结果。
|
|
73
|
+
- relay 侧新增**合并队列**:同一分支的合并串行化(复用 lease/`depends_on`),每个 merge 任务由指定机器执行 `git merge`/`git am`,冲突作为**一等结果**(`MERGE_CONFLICT` + 冲突文件列表 + 冲突 patch),绝不静默覆盖。
|
|
74
|
+
- 合并后再跑锚点校验:`base_tree` 与声明一致才允许入队。
|
|
75
|
+
|
|
76
|
+
**验收**:两台机器改不同文件 → 自动合并成功;改同一文件 → 返回 `MERGE_CONFLICT` 且两人都能看到冲突内容;重放 ledger 后合并状态一致。
|
|
77
|
+
|
|
78
|
+
### M4 项目房间(project room)
|
|
79
|
+
|
|
80
|
+
**目标**:多客户端看到同一个"项目"而不是各自会话。
|
|
81
|
+
|
|
82
|
+
**做法**:
|
|
83
|
+
- relay 新增 `project` 对象:members/roles(已有 role 模型可复用)、任务板、制品、memory 文档、chat 线程、决策记录。
|
|
84
|
+
- 客户端 API:`GET /v1/projects/:id`(快照)+ SSE/WebSocket 增量;DSH 插件侧新增 项目房间工具(未实现,暂用中性名)与面板视图。
|
|
85
|
+
- 任务/制品/决策都挂在 project 下,session 只是"视图"。
|
|
86
|
+
|
|
87
|
+
**验收**:两个不同 DSH 客户端(不同账号/机器)打开同一 project,看到相同的任务板/制品/决策;一个客户端创建任务,另一个 3 秒内看到。
|
|
88
|
+
|
|
89
|
+
### M5 多客户端协作原语
|
|
90
|
+
|
|
91
|
+
- **占位/锁**:branch/file lease(复用租约机制),避免两个客户端同时改同一分支。
|
|
92
|
+
- **审查任务**:`review` 类型任务(指定 reviewer 机器/人),结果 = approve/changes-requested。
|
|
93
|
+
- **通知**:mentions(已有)+ 任务状态变化推送到项目房间。
|
|
94
|
+
- **决策**:council 决策落 memory(已实现雏形)→ 升级为 project 级决策账本。
|
|
95
|
+
|
|
96
|
+
**验收**:A 提交补丁 → B 收到审查任务 → B 批准 → 合并队列执行;A 持锁期间 B 不能改同一分支。
|
|
97
|
+
|
|
98
|
+
### M6 跨网络与可靠性
|
|
99
|
+
|
|
100
|
+
- 明确 relay 是**权威数据通道**:blob 支持分块/断点续传(现在 16 MiB 硬上限、无断点);任务/事件支持断线重放(ledger 已具备)。
|
|
101
|
+
- P2P 降级为"机会性加速":P2P 失败不影响任务正确性;修掉明文拒绝与 NAT 不可测的问题(或直接默认 `relay` 模式,让 P2P 成为显式实验开关)。
|
|
102
|
+
- 离线机器:任务进入队列,机器回来后被 re-offer(已有 re-offer 基础)。
|
|
103
|
+
|
|
104
|
+
**验收**:把 relay 与执行机之一断网 60 秒,任务不丢、不重复执行,恢复后按租约重新派发;10 台机器并发派发/归并不丢事件。
|
|
105
|
+
|
|
106
|
+
### M7 观测与验收
|
|
107
|
+
|
|
108
|
+
- 指标:任务成功率、合并冲突率、授权使用次数、每机器可用命令/授权状态、relay 事件延迟。
|
|
109
|
+
- 测试:复用现有双机/跨平台测试附件(`test/` 与 `deploy/` 有真机脚本),每个模块都要有"真实任务可触发"的集成测试 + 负向测试。
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 5. 落地路线(建议顺序)
|
|
114
|
+
|
|
115
|
+
### Phase 1(1–2 周):先把"编队可用"变成真的
|
|
116
|
+
|
|
117
|
+
1. M1 运维通道(update/restart/diag,签名请求 + root 单元)
|
|
118
|
+
2. M2 任务级签名授权
|
|
119
|
+
3. 机器加入后默认"可被操作员授权",不再是空 allow-list 死机器
|
|
120
|
+
|
|
121
|
+
**Phase 1 验收任务(真实场景)**:
|
|
122
|
+
- 在一台**空 allow-list** 的机器(TwinsEarth)上,仅凭一次操作员授权完成:插件升级到 1.3.1 → 重启 DSH → 回报版本。
|
|
123
|
+
- relay 升级同一套流程(替代本次"杀进程"操作)。
|
|
124
|
+
- 全程 ledger 可审计;无 grant 时同一命令被拒。
|
|
125
|
+
|
|
126
|
+
### Phase 2(2–4 周):联合改代码
|
|
127
|
+
|
|
128
|
+
4. M3 worktree/patch/merge 队列 + 冲突一等结果
|
|
129
|
+
5. M4 项目房间(先做任务板 + 制品 + 决策,后做面板)
|
|
130
|
+
6. 基于 M2 的 review 任务(M5 的审查部分)
|
|
131
|
+
|
|
132
|
+
**Phase 2 验收任务**:两台机器并行修一个 bug(不同文件)→ 自动合并成功并跑测试;同一文件冲突 → 冲突可见、可选人解决;两个客户端看到同一任务板。
|
|
133
|
+
|
|
134
|
+
### Phase 3(4–6 周):多客户端与跨网络规模化
|
|
135
|
+
|
|
136
|
+
7. M5 锁/审查/通知 + M4 面板完整视图
|
|
137
|
+
8. M6 分块上传/断点重传/离线队列/P2P 降级
|
|
138
|
+
9. M7 指标与混沌测试(断网、重启、机器掉线)
|
|
139
|
+
|
|
140
|
+
**Phase 3 验收任务**:3 个客户端 + 5 台机器共同完成"改代码→审查→合并→发布"一条链,期间重启 relay/断网各一次不丢任务。
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 6. 最小可行闭环(如果只做一件)
|
|
145
|
+
|
|
146
|
+
**"一次签名,远程升级任意编队机器"**(M1+M2 的最小交集):
|
|
147
|
+
|
|
148
|
+
1. 操作员本地签 `grant`(argv=`node bin/w2m-maintenance.mjs --action update --version 1.3.1`,TTL 10 分钟,目标 machine_id)。
|
|
149
|
+
2. 用 `w2m_run`/relay 派发;目标机器 maintenance 单元验签 → 下载 tarball(sha256 校验)→ 更新 → 重启 → 回报。
|
|
150
|
+
3. 客户端 `w2m_wait` 看到 `status=done` + `version=1.3.1`;ledger 记录了 grant 与结果。
|
|
151
|
+
|
|
152
|
+
所需新增:一个 `bin/w2m-maintenance.mjs`(~200 行)、一个 systemd/计划任务单元模板、`grant` 签名/验证(复用 envelope-signature,~150 行)、relay 对 grant 的透传/审计(~80 行)、插件工具 远程更新工具(未实现,暂用中性名)(~120 行)、双机负向测试。**这就是"最基本功能"的正确起点。**
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## 7. 与现有代码的映射
|
|
157
|
+
|
|
158
|
+
| 新模块 | 复用 | 新增 |
|
|
159
|
+
|---|---|---|
|
|
160
|
+
| M1 maintenance | `bin/` 打包、systemd 单元生成经验(`deploy/server/`) | `bin/w2m-maintenance.mjs`、单元模板、队列协议 |
|
|
161
|
+
| M2 grants | `src/util/envelope-signature.mjs`、device public key 登记、ledger | grant 结构/签发/验证、relay 透传、agent 校验、撤销 |
|
|
162
|
+
| M3 worktree/merge | `src/util/dataflow.mjs`(制品哈希)、blob 通道、`depends_on`/lease | worktree 生命周期、merge 队列、`MERGE_CONFLICT` 结果、patch blob |
|
|
163
|
+
| M4 project room | `fleet-messages`、memory CAS、roles、council 决策账本 | project 对象、快照/增量 API、项目房间工具(未实现,暂用中性名) |
|
|
164
|
+
| M5 协作原语 | lease、mentions、review/approval 机制 | 分支/文件锁、review 任务类型、通知路由 |
|
|
165
|
+
| M6 可靠性 | ledger 重放、re-offer、blob 通道 | 分块/断点、离线队列、P2P 降级开关 |
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 8. 风险与取舍
|
|
170
|
+
|
|
171
|
+
| 风险 | 处置 |
|
|
172
|
+
|---|---|
|
|
173
|
+
| 签名 grant 变成新的后门 | 单次/单机/短 TTL/argv hash 绑定 + ledger 审计 + 可撤销;默认关闭 |
|
|
174
|
+
| maintenance 单元权限过大 | 只允许固定 action;不接受任意 shell;更新包必须 sha256 匹配 release 资产 |
|
|
175
|
+
| 合并队列成为瓶颈 | 按分支/路径分片串行;冲突直接回给提交者,不自动猜 |
|
|
176
|
+
| relay 仍是单点 | 短期接受;M6 做事件重放与多 relay 只读镜像(后续) |
|
|
177
|
+
| 多客户端一致性 | 以 relay 事件日志为唯一事实源;客户端只做视图,不做本地权威状态 |
|
|
178
|
+
| 现有 beta 已声明"多机",与实际不符 | 文档修正:把"多机派发/聚合"与"多机协同开发"分成两个能力级别,不再混写 |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 9. 建议的下一步(需要用户决策)
|
|
183
|
+
|
|
184
|
+
1. **批准 Phase 1 MVP**(M1+M2,远程运维),我用真实机器(TwinsEarth/jp-shared)作为验收对象,两周内出可演示闭环。
|
|
185
|
+
2. 批准后同步修正 README/CHANGELOG 里"多机协同"的口径,避免把"派发/聚合"写成"联合开发"。
|
|
186
|
+
3. Phase 2 的 worktree/merge 模型涉及产品取舍(中心化合并 vs 去中心 git),建议先做一个 3 页的对比决策再动手。
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# 稳定版发布流程(Stable Release Runbook)
|
|
2
|
+
|
|
3
|
+
> 适用:本项目(`@twinsearth/w2m-dsh-plugin`)从版本决定到五方核验完成的全过程。
|
|
4
|
+
> 角色边界:**版本号与发布时间由用户决定**;执行者负责门禁、打包、推送、核验;**Stable 批准只能由用户操作**。
|
|
5
|
+
> 原则:门禁红绝不打 tag;先发布、后部署 relay;每个版本留证据。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 0. 发布前条件(缺一不可)
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
[ ] 用户已明确版本号(稳定版 X.Y.Z;预发布必须 X.Y.Z-beta.N)
|
|
13
|
+
[ ] 工作区没有未完成的半成品改动(未发布的功能不能混进稳定版)
|
|
14
|
+
[ ] 本机 PATH 包含打包的 node 目录(否则 agent 测试会误报
|
|
15
|
+
COMMAND_EXECUTABLE_PATH_MISMATCH)
|
|
16
|
+
[ ] 已阅读本次要发布的 CHANGELOG 条目(next section 写什么)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
PATH 准备(Windows):
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
$node = 'E:\DS\resources\runtime\primary-runtime\dependencies\node\bin\node.exe'
|
|
23
|
+
$env:PATH = (Split-Path $node) + ';' + $env:PATH
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. 版本 bump(5 个文件)
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
package.json
|
|
32
|
+
plugin.json
|
|
33
|
+
.claude-plugin/plugin.json
|
|
34
|
+
.claude-plugin/marketplace.json (version + metadata.version + plugins[].version)
|
|
35
|
+
codex/mcp-servers.toml (@X.Y.Z)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
注意:用 Node 写 JSON,**不要用 PowerShell `ConvertTo-Json` 回写**(会带 BOM,pack 直接崩)。
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 2. CHANGELOG
|
|
43
|
+
|
|
44
|
+
- 新条目放在**最上面**(newest-first)。
|
|
45
|
+
- 标题格式:`## [X.Y.Z] — YYYY-MM-DD`。
|
|
46
|
+
- 必须写:改了什么、没有改什么(明确不包含项)、已知限制、验证数字。
|
|
47
|
+
- 排序规则由 `claims` 检查:**prerelease 按 semver 比较**(`X.Y.Z-beta.2 > X.Y.Z-beta.1`)。
|
|
48
|
+
- `package.json` 版本必须等于最新条目版本(claims 断言)。
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 3. 打包与门禁(两遍)
|
|
53
|
+
|
|
54
|
+
```powershell
|
|
55
|
+
Remove-Item dist -Recurse -Force -ErrorAction SilentlyContinue
|
|
56
|
+
& $node scripts/pack.mjs
|
|
57
|
+
# 记录:bytes 与 sha256
|
|
58
|
+
|
|
59
|
+
& $node scripts/preflight.mjs # 第一遍
|
|
60
|
+
& $node scripts/preflight.mjs # 第二遍(必须同样 GREEN)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
通过标准:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
pre-flight: 15 pass, 0 fail, 1 unverifiable(host 环境项)
|
|
67
|
+
declared suite: N tests / pass / 0 fail / 14 skip
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
红灯常见原因与修法:
|
|
71
|
+
|
|
72
|
+
| 失败项 | 原因 | 修法 |
|
|
73
|
+
|---|---|---|
|
|
74
|
+
| lint | 未使用 import、Promise executor 返回、未定义变量 | 修代码;不得用 eslint-disable 绕过 |
|
|
75
|
+
| declared suite | 测试失败 | 先跑单个文件定位;PATH 问题看 `COMMAND_EXECUTABLE_PATH_MISMATCH` |
|
|
76
|
+
| claims | 版本顺序 / package 与最新条目不一致 / 文档未声明 / 未注册工具名 | 按断言修;新文档要么登记 shipped 要么排除并写理由 |
|
|
77
|
+
| layer-model | 新模块/新跨层 import 未声明 | 在 `scripts/layer-model.mjs` 声明层与允许边(不要放宽成环形) |
|
|
78
|
+
| packed tarball | dist 陈旧 / 文档缺失 / 工具数不符 | 删除 dist 重 pack;同步 verify-installed/README/preflight 的计数 |
|
|
79
|
+
| CHANGELOG shape | 非降序 / 格式不符 | 调整条目位置与标题 |
|
|
80
|
+
|
|
81
|
+
**门禁不绿:停止,不 commit,不打 tag。**
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 4. 提交与打 tag
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
1. 写 commit 消息(release: vX.Y.Z — <一句话主题>,正文列变更与验证数字)
|
|
89
|
+
2. 用推送脚本 commit + push main,取回 COMMIT_SHA(脚本输出 COMMIT_SHA=...)
|
|
90
|
+
3. 用 GitHub API 建 tag:POST /repos/<owner>/<repo>/git/refs
|
|
91
|
+
{ "ref": "refs/tags/vX.Y.Z", "sha": COMMIT_SHA }
|
|
92
|
+
4. 轮询 Release workflow:waiting 出现 = 进入 Stable 环境审批
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
# 轮询示例(node)
|
|
97
|
+
# /repos/<repo>/actions/runs?per_page=8 → 找 name === 'Release' 且 head_sha 匹配
|
|
98
|
+
# jobs 里有 status === 'waiting' → 等待审批
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 5. Stable 审批(只能用户做)
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
GitHub → Actions → release run → Review deployments → Stable → Approve
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
审批后 workflow 继续:verify → pack → publish(GitHub release + npm)。
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 6. 五方核验(全部通过才算发布完成)
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
1. npm:latest 变为 X.Y.Z(注意传播延迟,可重试)
|
|
117
|
+
2. GitHub release:prerelease=false;资产包含 tgz + SHA256SUMS
|
|
118
|
+
3. 资产校验:下载 tgz 实算 sha256,必须与 SHA256SUMS 一致
|
|
119
|
+
4. Packages:dispatch packages workflow(inputs.version=X.Y.Z),job success
|
|
120
|
+
5. CI:该 commit 的 ci.yml run success
|
|
121
|
+
6. Compat:该 commit 的 compat.yml run success(红则视为不可发布,见下)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Compat 红的高频原因:打包产物与 loader gate 的 `EXPECTED_TOOLS` 不一致
|
|
125
|
+
(v1.3.0 实例)。定位方法:看 Compat 日志的 “registers every w2m_* tool” 子测试,
|
|
126
|
+
它会打印 live tools 与 expected 的差异。
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## 7. relay 部署(发布包含 relay 变更时)
|
|
131
|
+
|
|
132
|
+
用**官方 release 资产**(sha 与五方核验一致),不要用本地 pack 产物。
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# SSH(或 fleet 通道以 w2m 用户执行)
|
|
136
|
+
cd /opt/w2m && rm -rf app.bak && cp -a app app.bak
|
|
137
|
+
# 上传官方 tgz 到 /tmp
|
|
138
|
+
bash /opt/w2m/app.bak/deploy/server/deploy-w2m.sh /tmp/<tgz> <sha256>
|
|
139
|
+
# 若 systemd 拒绝重启(非 root):kill -TERM <MainPID> 触发 Restart=always
|
|
140
|
+
systemctl status w2m-rabbit w2m-stun w2m-localside --no-pager
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
线上复核(必须做):
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
/healthz 200;relay_id 变化、uptime 归零(证明是新进程)
|
|
147
|
+
/v1/fleet/members 200;未认证 /v1/fleet/messages 401
|
|
148
|
+
任务派发 → 目标机执行成功(plain task)
|
|
149
|
+
新版本特性路径生效(如 reduce 取件失败码、maintenance 字段透传)
|
|
150
|
+
磁盘占用正常;app.old 保留(回滚材料)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
回滚:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
systemctl stop w2m-rabbit w2m-stun w2m-localside
|
|
157
|
+
mv /opt/w2m/app /opt/w2m/app.1 && mv /opt/w2m/app.old /opt/w2m/app
|
|
158
|
+
systemctl start w2m-rabbit w2m-stun w2m-localside
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 8. 收尾
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
[ ] 证据入库:docs/acceptance/<version>/<case>.json(真实任务 task_id + 断言结果)
|
|
167
|
+
[ ] CHANGELOG 的验证数字与实际门禁输出一致
|
|
168
|
+
[ ] 需要时更新各机器插件(TwinsEarth / macmini / ToFuture),并在发布说明中标注 relay 版本
|
|
169
|
+
[ ] 若本版本被后续版本纠正,写明代替关系(如 v1.3.0 → v1.3.1)
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 9. 本会话踩过的坑(已修复,写下来防止复发)
|
|
175
|
+
|
|
176
|
+
1. **PATH 缺 node 目录** → agent 测试 18 个 `COMMAND_EXECUTABLE_PATH_MISMATCH`。跑门禁前先 prepend。
|
|
177
|
+
2. **PowerShell 回写 JSON 带 BOM** → pack 报 `Unexpected token ''`。用 Node 写 JSON。
|
|
178
|
+
3. **CHANGELOG 比较器忽略 prerelease** → beta.1/beta.2 相等、顺序断言互相矛盾。已改成 semver 比较。
|
|
179
|
+
4. **陈旧 dist** → “packed package.json 与 tree 不一致”。发布前删除 dist 重 pack。
|
|
180
|
+
5. **工具数变化(16 tools)** 需要同步:README、verify-installed、preflight packed-tarball 计数、tool-cards、claims、update-wiring、p2p-plugin、marketplace 清单。
|
|
181
|
+
6. **Compat 只在打包产物+真实 profile 暴露**:本地 loader 检查可能跳过,必须看 Compat 的 capture 输出。
|
|
182
|
+
7. **npm 传播延迟**:dist-tag 未更新不等于发布失败,重试读取。
|
|
183
|
+
8. **relay 上的 systemd 权限**:w2m 用户不可 systemctl;要么 root(SSH/控制台),要么 kill 触发 Restart=always(并确认 localside 也会回来)。
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 10. 角色与红线(再次强调)
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
用户:决定版本号、批准 Stable、决定是否把 beta 部署到生产 relay
|
|
191
|
+
执行者:门禁、打包、推送、五方核验、部署与线上复核
|
|
192
|
+
红线:门禁红不打 tag;不用 beta 冒充稳定版;不未经用户同意部署生产;不自行决定版本号
|
|
193
|
+
```
|