@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,231 @@
|
|
|
1
|
+
# M6 跨网络可靠性设计规格
|
|
2
|
+
|
|
3
|
+
> 状态:**设计稿**。只定义权威通道、分块/断点、离线队列与 P2P 降级语义,不含实现。
|
|
4
|
+
> 版本:`1.3.7-beta.*`(GitHub prerelease,不入 npm)。
|
|
5
|
+
> 上游:`docs/MULTI-MACHINE-COLLABORATION-PLAN.md` M6;承接 M3(大 patch 制品)与 M4(事件流)的传输需求。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 目标与非目标
|
|
10
|
+
|
|
11
|
+
### 目标
|
|
12
|
+
|
|
13
|
+
1. **正确性只依赖 relay**:任务、结果、事件、制品全部走 relay 通道;任何链路的短暂中断都表现为"重试/断点/补齐",而不是"任务丢失或重复执行"。
|
|
14
|
+
2. **大制品可传**:blob 支持分块上传、断点续传、Range 下载;打断后从缺失块继续,最终 sha256 校验通过才算成功。
|
|
15
|
+
3. **离线不丢**:机器离线期间任务不被丢(队列 + 重派发);机器产出的结果先进本地 outbox,重连后幂等投递;客户端事件按 seq 补齐。
|
|
16
|
+
4. **P2P 只做加速**:P2P 失败不影响任何任务的正确性;提供明确的模式开关与可观测的成功率,而不是把它当传输保障。
|
|
17
|
+
5. **可观测**:重试、断点、outbox 深度、SSE 重连、P2P 成功率、事件延迟全部有指标。
|
|
18
|
+
|
|
19
|
+
### 非目标(本版本不做)
|
|
20
|
+
|
|
21
|
+
- 不做多 relay 集群/主备切换(relay 仍是单点;本版本只保证**重启后恢复**)。
|
|
22
|
+
- 不做 P2P 数据通道传输大文件(P2P 本版本仍只用于 offer 推送加速)。
|
|
23
|
+
- 不做端到端 TLS 终止(relay 当前 HTTP;TLS 由部署层反代决定,本版本只保证协议向后兼容)。
|
|
24
|
+
- 不做跨 relay 的数据迁移。
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. 现状与缺口
|
|
29
|
+
|
|
30
|
+
| 现有 | 缺口 |
|
|
31
|
+
|---|---|
|
|
32
|
+
| relay 持久化(tasks/devices/results/messages/ledger/blob) | 重启恢复已具备;缺**进行中传输**的恢复 |
|
|
33
|
+
| blob 单次 PUT,帧上限 16 MiB,存储上限 8 MiB/256 个 | 无分块、无断点;>8 MiB 制品直接失败;中断即丢弃 |
|
|
34
|
+
| SSE 事件流 + seq | 断线重连可用;但**事件保留窗口外的补齐**依赖快照(M4 已有) |
|
|
35
|
+
| 任务 re-offer(设备重连时 re-offer offered/queued) | 已有;缺"结果本地 outbox + 幂等重投" |
|
|
36
|
+
| P2P(STUN/UDP,auto/direct/relay) | 明文拒绝、NAT 不可测;当前把 P2P 当传输路径,失败才回落 |
|
|
37
|
+
| 心跳/租约 | 已有;缺"离线机器的任务不丢"的明确语义(等待 vs 过期) |
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 3. 通道分级(权威性)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
控制通道(权威):POST /v1/task、任务/租约/结果、项目事件、memory、通知 —— 全部走 relay HTTP
|
|
45
|
+
数据通道(权威):blob store(分块/断点后)—— 与任务解耦,内容寻址(sha256)
|
|
46
|
+
加速通道(机会性):P2P offer push —— 只影响"offer 到达得快不快",不影响正确性
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
不变量:
|
|
50
|
+
|
|
51
|
+
1. **结果只通过 relay 提交**(P2P 不承载结果)。
|
|
52
|
+
2. **任何任务可被重派发**:P2P 推送的 offer 与 relay SSE 的 offer 用同一 `(task_id, attempt, dedupe_key)` 去重(已有),所以 P2P 丢失/重复都不破坏 exactly-once 语义。
|
|
53
|
+
3. **制品以 sha256 为身份**:上传完成前不可引用;引用后内容不可变。
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 4. Blob 分块 / 断点
|
|
58
|
+
|
|
59
|
+
### 4.1 上传会话协议
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
POST /v1/fleet/blob-sessions
|
|
63
|
+
{ sha256, size, chunk_bytes? } → 201 { session_id, chunk_bytes, chunks, received: [] }
|
|
64
|
+
PUT /v1/fleet/blob-sessions/:sid/chunks/:index (octet-stream, ≤ chunk_bytes)
|
|
65
|
+
→ 200 { received: [..] } | 409 SESSION_COMMITTED | 413 CHUNK_TOO_LARGE
|
|
66
|
+
GET /v1/fleet/blob-sessions/:sid → { received: [..], missing: [..], expires_at }
|
|
67
|
+
POST /v1/fleet/blob-sessions/:sid/commit → 200 { sha256, bytes } | 400 BLOB_SHA_MISMATCH
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `chunk_bytes` 默认 1 MiB(上限 8 MiB,必须整除 size 或最后一块短);`chunks ≤ 256`(即单 blob ≤ 256 MiB,默认配额另设)。
|
|
71
|
+
- 会话 TTL 24h;commit 后会话删除,块拼成最终 blob 并校验 sha256;校验失败删除并返回 `BLOB_SHA_MISMATCH`。
|
|
72
|
+
- 块 PUT 幂等:同一 index 重传覆盖;乱序允许;`received` 返回已收列表,客户端据此续传。
|
|
73
|
+
- 并发:同一会话的块可并发(不同 index),commit 等待所有块到齐(否则 `BLOB_INCOMPLETE` + missing)。
|
|
74
|
+
- 配额:单机器并发会话 ≤2、未完成会话总字节 ≤ 512 MiB;超限 `BLOB_QUOTA`。
|
|
75
|
+
- 存储:块存临时目录;commit 后写入现有 blob store(复用现有 `MAX_BLOB_BYTES` 机制,但改为可配置上限,默认 64 MiB)。
|
|
76
|
+
|
|
77
|
+
### 4.2 下载断点
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
GET /v1/fleet/blobs/:sha (全量;小文件)
|
|
81
|
+
GET /v1/fleet/blobs/:sha?range=0-1048575 → 206 Partial Content + Content-Range
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- 客户端按需 Range 重试;下完校验 sha256,不符重下。
|
|
85
|
+
- 大制品(M3 的 patch/conflict)优先 Range 下载,避免一次占满内存。
|
|
86
|
+
|
|
87
|
+
### 4.3 agent 集成
|
|
88
|
+
|
|
89
|
+
- 上传决策:输出 > 内联阈值(64 KiB)→ 分块会话上传;≤ 阈值仍内联。
|
|
90
|
+
- 断点续传:agent 在 state 目录持久化 `{session_id, sha, received[]}`;重连后 GET 会话 → 缺失块补传。
|
|
91
|
+
- 重试策略:块级指数退避(1s/2s/4s/8s,上限 60s,最多 10 次);会话过期则重新开新会话并全量重传(不无限重试)。
|
|
92
|
+
- 失败语义:上传最终失败 → 任务结果标记 `BLOB_UPLOAD_FAILED`(与 v1.3.1 一致),不引用不存在的 blob。
|
|
93
|
+
|
|
94
|
+
### 4.4 错误码
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
BLOB_INCOMPLETE commit 时缺块(返回 missing)
|
|
98
|
+
BLOB_SHA_MISMATCH 拼接后 sha 不符(删除会话)
|
|
99
|
+
BLOB_QUOTA 会话/字节超配额
|
|
100
|
+
CHUNK_TOO_LARGE 块超过 chunk_bytes
|
|
101
|
+
SESSION_NOT_FOUND 会话过期/不存在
|
|
102
|
+
SESSION_COMMITTED 已 commit 后继续写块
|
|
103
|
+
BLOB_TOO_LARGE 声明 size 超过配置上限
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 5. 离线队列与结果 outbox
|
|
109
|
+
|
|
110
|
+
### 5.1 任务侧(relay)
|
|
111
|
+
|
|
112
|
+
- 任务创建后若无在线可执行机器:任务保持 `queued`(不丢),机器上线时 re-offer(已有);`depends_on` 在依赖完成后释放(已有)。
|
|
113
|
+
- 租约过期不等于任务失败:`expired` 是租约状态;relay 管理端看到任务仍可被重派发(`max_attempts` 策略决定是否终止)。
|
|
114
|
+
- 明确语义:`halt` 策略(never/now)已有,保持;本版本不改语义,只补可观测与测试。
|
|
115
|
+
|
|
116
|
+
### 5.2 结果侧(agent outbox)
|
|
117
|
+
|
|
118
|
+
- agent 把结果先写本地 outbox(state 目录 JSONL,原子写):`{result_id, task_id, attempt, dedupe_key, payload_sha, attempts, next_retry_ms}`。
|
|
119
|
+
- 投递成功(relay 200/已 dedupe)→ 标记 ack 并清理;失败/断网 → 指数退避重试,跨重启继续。
|
|
120
|
+
- 幂等:relay 按 `(task_id, attempt)` 结果去重(已有);outbox 重复投递安全。
|
|
121
|
+
- 上限:outbox 200 条/16 MiB,超限只保留最近 + 告警(`OUTBOX_FULL`),避免磁盘无限增长。
|
|
122
|
+
- 结果中的 blob 引用:先确保 blob 已 commit,再投递结果(顺序保证)。
|
|
123
|
+
|
|
124
|
+
### 5.3 客户端侧(DSH 插件)
|
|
125
|
+
|
|
126
|
+
- SSE 断线重连(已有)+ `since_seq` 补齐(M4);超出保留窗口 → 快照。
|
|
127
|
+
- 通知/项目事件按 seq 补齐;本地只存水位。
|
|
128
|
+
- 读请求失败不阻塞界面,显示"连接中/离线"状态(M4 连接状态已有)。
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 6. 重启与恢复
|
|
133
|
+
|
|
134
|
+
| 场景 | 期望行为 | 验收 |
|
|
135
|
+
|---|---|---|
|
|
136
|
+
| relay 重启(持久化开启) | 设备/任务/结果/事件恢复;租约重派发;seq 连续 | 重启前后任务不丢、事件 seq 连续 |
|
|
137
|
+
| agent 重启 | outbox 恢复、未完成 blob 会话续传、worktree/产物状态检查 | 重启后任务重试成功且不重复执行 |
|
|
138
|
+
| 客户端重启 | 水位持久化,未读通知仍正确 | 重启后 unread 计数一致 |
|
|
139
|
+
| 网络闪断(<30s) | SSE 重连、请求重试;无用户可见失败 | 断网 30s 任务照常完成 |
|
|
140
|
+
| 断网 60s(执行机) | 租约过期 → 机器回归后 re-offer;任务不丢 | 断网 60s 后任务完成或明确失败(不悬挂) |
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## 7. P2P 降级为机会性加速
|
|
145
|
+
|
|
146
|
+
### 7.1 模式定义(保持现有三值,语义收紧)
|
|
147
|
+
|
|
148
|
+
| 模式 | 行为 | 正确性依赖 |
|
|
149
|
+
|---|---|---|
|
|
150
|
+
| `relay`(推荐默认) | 不绑 UDP、不尝试 P2P;offer 只走 relay | 无 |
|
|
151
|
+
| `auto`(保持现有默认) | 尝试 P2P push offer;失败/超时静默回落 relay;结果仍只走 relay | 无(P2P 只影响延迟) |
|
|
152
|
+
| `direct` | 要求 P2P 成功,失败则拒绝 offer(`P2P_UNAVAILABLE`) | 有(仅用于可控内网/实验) |
|
|
153
|
+
|
|
154
|
+
### 7.2 修复与约束
|
|
155
|
+
|
|
156
|
+
- **明文拒绝**:启用加密时,P2P 握手失败(对端明文)→ 只记录 `P2P_CRYPTO_PLAINTEXT_PEER` 并回落 relay,不重试明文通道。
|
|
157
|
+
- **NAT 不可测**:`auto` 下 N-1 台机器之间无成功记录时,P2P 成功率指标会下降;不做"强制打洞"。
|
|
158
|
+
- **去重**:P2P offer 与 relay offer 以 `(task_id, attempt, dedupe_key)` 去重(已有),重复到达不执行两次。
|
|
159
|
+
- **默认值建议**:`auto` 保持默认以兼容现有配置,但文档明确"P2P 不承担正确性";`direct` 标记为实验性。
|
|
160
|
+
- **指标**:`p2p_push_attempts / success / fallback`、`p2p_crypto_refusals`、offer 到达延迟(P2P vs relay)。
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 8. 可观测性指标(M6)
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
blob_upload_sessions_open / committed / failed
|
|
168
|
+
blob_chunks_retried / bytes_transferred / resume_count
|
|
169
|
+
blob_download_range_requests / sha_mismatch
|
|
170
|
+
agent_outbox_depth / retries / dropped
|
|
171
|
+
sse_reconnects / events_replayed
|
|
172
|
+
task_requeued_on_reconnect / lease_expired_total
|
|
173
|
+
p2p_push_attempts / p2p_push_success_ratio / p2p_fallback_total
|
|
174
|
+
relay_event_lag_ms(事件时间 vs 客户端应用时间)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
全部经 `w2m_stats`/metrics 路由暴露;M7 统一验收。
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 9. 验收(真实任务 + 混沌)
|
|
182
|
+
|
|
183
|
+
### 正向
|
|
184
|
+
|
|
185
|
+
1. **大制品**:上传 40 MiB patch 制品(分块)→ 下载校验 sha 一致;同时验证 8 MiB 旧上限不再阻断。
|
|
186
|
+
2. **断点续传**:上传到 50% 断开 agent → 重连后只补缺失块,最终 commit 成功、sha 正确。
|
|
187
|
+
3. **离线结果**:执行机断网 60s 完成任务 → 结果进 outbox → 恢复后投递,任务只执行一次(ledger 无重复结果)。
|
|
188
|
+
4. **断网 30s**:SSE 客户端断网 30s → 重连补齐事件,无丢事件。
|
|
189
|
+
5. **relay 重启**:重启前后项目事件 seq 连续、任务不丢、租约重派发。
|
|
190
|
+
|
|
191
|
+
### 负向(自动化)
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
块缺失 commit → BLOB_INCOMPLETE(missing)
|
|
195
|
+
块被篡改 → BLOB_SHA_MISMATCH,blob 不存在
|
|
196
|
+
会话过期后写块 → SESSION_NOT_FOUND
|
|
197
|
+
超配额 → BLOB_QUOTA
|
|
198
|
+
重复块 PUT → 幂等(received 去重)
|
|
199
|
+
P2P 明文对端 → 回落 relay,任务成功
|
|
200
|
+
P2P direct 模式无通道 → P2P_UNAVAILABLE(仅此模式)
|
|
201
|
+
outbox 满 → 保留最近 + OUTBOX_FULL 告警,进程不崩
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 10. 交付物清单(实现阶段)
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
src/relay/blob-sessions.mjs 分块会话、commit 校验、配额、TTL 清理
|
|
210
|
+
src/relay/server.mjs blob-sessions 路由、Range 下载、帧上限适配
|
|
211
|
+
src/relay/state.mjs blob 元数据(size/上限可配)
|
|
212
|
+
src/agent/blob-upload.mjs 分块上传、断点续传、持久化会话状态、重试
|
|
213
|
+
src/agent/outbox.mjs 结果 outbox(原子写、退避、aek 清理、上限)
|
|
214
|
+
src/agent/agent.mjs 接入 blob-upload/outbox;重连后恢复
|
|
215
|
+
src/plugin/fleet-chat-route.mjs 面板连接状态(SSE 重连/事件延迟)
|
|
216
|
+
src/plugin/tools.mjs w2m_stats 增加 M6 指标
|
|
217
|
+
lib/client.js 连接状态显示(重连/补事件)
|
|
218
|
+
test/blob-sessions.test.mjs 会话/缺块/篡改/配额/幂等
|
|
219
|
+
test/outbox.test.mjs 重试/幂等/上限/跨重启
|
|
220
|
+
test/reliability-e2e.test.mjs 断网/重启/大文件(本地模拟)
|
|
221
|
+
docs/COLLAB/M6-CROSS-NETWORK-RELIABILITY.md 本文
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 11. 开放问题(实现前确认)
|
|
225
|
+
|
|
226
|
+
1. **blob 上限**:默认 64 MiB/单个是否够用(M3 的 patch 通常小,但二进制制品可能大)?总配额(每机器 512 MiB 未完成会话)是否合适?
|
|
227
|
+
2. **chunk 大小**:1 MiB 默认是否合适(帧上限 16 MiB,可调到 4 MiB)。
|
|
228
|
+
3. **P2P 默认模式**:保持 `auto` 还是改为 `relay`(更诚实但改变现有行为)?
|
|
229
|
+
4. **Range 下载**:本版本就做,还是只做全量下载 + 客户端分段拉取?
|
|
230
|
+
5. **outbox 上限**:200 条/16 MiB 是否够用?
|
|
231
|
+
6. **relay TLS**:是否把反代 TLS 作为 M6 部署验收的一部分(当前 HTTP 明文,跨网络安全性问题)?
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# M7 指标与验收设计规格
|
|
2
|
+
|
|
3
|
+
> 状态:**设计稿**。只定义指标口径、验收体系与门禁,不含实现。
|
|
4
|
+
> 版本:`1.3.8-beta.*`(GitHub prerelease,不入 npm)。
|
|
5
|
+
> 上游:`docs/MULTI-MACHINE-COLLABORATION-PLAN.md` M7;覆盖 M1–M6 与三个模型(v1.4.x)的验收。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 1. 目标与非目标
|
|
10
|
+
|
|
11
|
+
### 目标
|
|
12
|
+
|
|
13
|
+
1. **每个能力都必须能被真实任务触发**:不允许"单测过了就算完成";验收记录必须能追溯到具体 task_id、机器、时间、ledger 区间。
|
|
14
|
+
2. **负向测试是必选项**:每个模块的错误码都必须有一条自动化用例证明"该拒绝时确实拒绝,且没有副作用"。
|
|
15
|
+
3. **指标统一口径**:任务成功率、重试/重派、分块断点、outbox、事件延迟、锁冲突、审查时效、合并冲突、P2P 成功率等,全部由 relay 真实数据计算,不靠客户端自报。
|
|
16
|
+
4. **门禁可执行**:preflight 增加"验收证据存在且可校验"的检查;beta 与 stable 的验收门槛不同,写死为门禁而不是口头约定。
|
|
17
|
+
5. **证据可留存、可复现**:验收产物(evidence)进仓库固定目录,含命令、结果、sha、ledger 区间,后续版本可回放核对。
|
|
18
|
+
|
|
19
|
+
### 非目标
|
|
20
|
+
|
|
21
|
+
- 不做外部 APM/监控平台接入(本版本只暴露指标 + 本地快照)。
|
|
22
|
+
- 不做性能压测基线(M7 只做正确性与混沌验收;吞吐性能另立)。
|
|
23
|
+
- 不追求 100% 自动化真实机器测试(允许"人工执行 + 证据上传",但证据格式与校验必须统一)。
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## 2. "真实任务可触发"的定义(验收硬标准)
|
|
28
|
+
|
|
29
|
+
一条能力算通过,必须同时满足:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
1. 存在一个真实 task_id(relay 可查、结果可复现)
|
|
33
|
+
2. 涉及 ≥1 台真实机器(不是进程内 mock;单机能力可 1 台)
|
|
34
|
+
3. 结果通过 relay 聚合可验证(outcome/status/字段断言)
|
|
35
|
+
4. sanitized 证据入仓库:docs/acceptance/<version>/<case>.json + 关联 artifact
|
|
36
|
+
5. 负向用例证明"拒绝路径正确且无副作用"(head/任务/文件未变)
|
|
37
|
+
6. 能在另一台机器/另一时间重跑(命令、版本、前置条件齐全)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
证据文件格式(统一):
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"version": "1.3.2-beta.1",
|
|
45
|
+
"case": "M1-UPDATE-EMPTY-ALLOWLIST",
|
|
46
|
+
"kind": "positive|negative|chaos",
|
|
47
|
+
"requirement": "空 allow-list 机器远程升级",
|
|
48
|
+
"machines": ["1c14d7d2-…", "6c92b251-…"],
|
|
49
|
+
"commands": [["node", "bin/w2m-maintenance.mjs", "--only-check"]],
|
|
50
|
+
"task_id": "01M6…",
|
|
51
|
+
"ledger_seq": [100, 104],
|
|
52
|
+
"result": { "outcome": "ok", "assertions": { "version": "1.3.2-beta.1" } },
|
|
53
|
+
"artifacts": [{ "sha256": "…", "bytes": 1234 }],
|
|
54
|
+
"executed_at": "2026-10-21T14:00:00Z",
|
|
55
|
+
"executor": "lead|human",
|
|
56
|
+
"reproduce": "docs/acceptance/<version>/RUNBOOK.md#M1-UPDATE-EMPTY-ALLOWLIST"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## 3. 指标口径(统一由 relay 计算)
|
|
63
|
+
|
|
64
|
+
### 3.1 任务与调度
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
wm_tasks_total{status, mode}
|
|
68
|
+
wm_task_duration_ms{status, mode} p50/p95/p99(直方图)
|
|
69
|
+
wm_task_requeued_total 重派发次数(reconnect/lease 过期)
|
|
70
|
+
wm_lease_expired_total{reason}
|
|
71
|
+
wm_result_duplicate_total 重复结果被去重的次数(应为 0 效果、>0 收到)
|
|
72
|
+
wm_dependency_released_total
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3.2 授权(M1/M2)
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
wm_grant_issued_total{machine_scope}
|
|
79
|
+
wm_grant_denied_total{code} 各 GRANT_* 拒绝码计数
|
|
80
|
+
wm_grant_expired_total
|
|
81
|
+
wm_maintenance_requests_total{action,outcome}
|
|
82
|
+
wm_maintenance_rollback_total
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 3.3 数据面(M3/M6)
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
wm_blob_upload_sessions_total{state}
|
|
89
|
+
wm_blob_chunks_total{retried}
|
|
90
|
+
wm_blob_resume_total
|
|
91
|
+
wm_blob_bytes_total{mode}
|
|
92
|
+
wm_blob_sha_mismatch_total
|
|
93
|
+
wm_agent_outbox_depth
|
|
94
|
+
wm_agent_outbox_dropped_total
|
|
95
|
+
wm_worktree_active / wm_worktree_cleaned_total
|
|
96
|
+
wm_merge_queue_depth{project,branch}
|
|
97
|
+
wm_merge_conflict_total
|
|
98
|
+
wm_merge_merged_total
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 3.4 协作(M4/M5)
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
wm_project_events_total{type}
|
|
105
|
+
wm_event_lag_ms{client} 客户端应用时间 - 事件时间(p95)
|
|
106
|
+
wm_sse_reconnects_total
|
|
107
|
+
wm_lock_acquired_total{kind} / wm_lock_conflict_total / wm_lock_force_released_total
|
|
108
|
+
wm_review_pending / wm_review_decision_total{decision}
|
|
109
|
+
wm_review_latency_ms 创建→首个结论(p95)
|
|
110
|
+
wm_notification_sent_total{kind} / wm_notification_digest_total / wm_notification_unread
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 3.5 传输(M6)
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
wm_p2p_push_attempts_total / wm_p2p_push_success_total / wm_p2p_fallback_total
|
|
117
|
+
wm_p2p_crypto_refusals_total
|
|
118
|
+
wm_relay_restarts_total(relay 启动时从持久化文件推断或写入)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3.6 暴露方式
|
|
122
|
+
|
|
123
|
+
- `GET /metrics`(Prometheus 文本格式,已有路由形态可复用)或 `w2m_stats` 聚合视图。
|
|
124
|
+
- 指标只存计数器/直方图聚合(内存 + 定期快照到 state),不存原始事件。
|
|
125
|
+
- 标签基数限制:machine_id 可入标签,task_id 不入(避免爆炸)。
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 4. 验收体系分层
|
|
130
|
+
|
|
131
|
+
| 层 | 名称 | 运行环境 | 强制程度 |
|
|
132
|
+
|---|---|---|---|
|
|
133
|
+
| L0 | 单元/纯函数 | 任意 | beta 必过(已有 node --test) |
|
|
134
|
+
| L1 | 组件集成 | 本地 fake relay + 真 agent 进程 | beta 必过 |
|
|
135
|
+
| L2 | 真实任务 | 编队真机(jp-shared / TwinsEarth / macmini / ToFuture) | beta 子集、stable 全量 |
|
|
136
|
+
| L3 | 混沌 | 本地/真机断网、杀进程、重启、配额 | beta 抽测、stable 必过 |
|
|
137
|
+
| N | 负向矩阵 | 随每模块交付 | 全部版本必过 |
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 5. 验收矩阵(按版本)
|
|
142
|
+
|
|
143
|
+
| 版本 | 模块 | L2 正向(真实任务) | N 负向(必须自动化) | L3 混沌 |
|
|
144
|
+
|---|---|---|---|---|
|
|
145
|
+
| 1.3.2-beta | M1 | 空 allow-list 机器远程 update/restart/diag;relay 升级 | 未签/错签/过期/换机/重放/越界 action/sha 不符/包内版本不符/篡改 | 升级中断回滚;relay 重启后恢复 |
|
|
146
|
+
| 1.3.3-beta | M2 | 空 allow-list 执行 node -e;多机 grant;撤销生效 | GRANT_* 全矩阵;重放;超 max_uses;旧 agent | 撤销后立即拒绝;重启后计数保留 |
|
|
147
|
+
| 1.3.4-beta | M3 | 两机并行改不同文件 → 合并;同文件 → MERGE_CONFLICT | 篡改 patch/写 .git/非合并器/force push/中断恢复 | 合并中断后锁恢复;重放幂等 |
|
|
148
|
+
| 1.3.5-beta | M4 | 双客户端同任务板/制品/决策;断线补齐 | 非成员/observer 越权/seq 缺口/重复事件 | relay 重启 seq 连续 |
|
|
149
|
+
| 1.3.6-beta | M5 | 锁冲突/过期/强制释放;审查通过/拒绝;离线通知补齐 | 并发抢锁/非 holder/自审/重复结论/通知风暴 | 锁过期重入;通知限流不丢 |
|
|
150
|
+
| 1.3.7-beta | M6 | 40MiB 分块上传下载;断点续传;outbox 恢复 | BLOB_* 全矩阵;outbox 满;P2P 明文回落 | relay/agent 重启;断网 30/60s |
|
|
151
|
+
| 1.3.8-beta | M7 | 验收证据可执行、指标可读;跑一遍前六项 | 证据缺失/伪造/过期 → preflight 拒绝 | 指标在混沌下保持单调/无倒挂 |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 6. 测试与混沌基础设施
|
|
156
|
+
|
|
157
|
+
### 6.1 本地
|
|
158
|
+
|
|
159
|
+
- **fake relay**(已有 `startFakeRabbit`):L1 用;扩展支持 blob-sessions/项目房间路由。
|
|
160
|
+
- **双机 harness**(已有 `test/agent.test.mjs` 与部署脚本):L1 两 agent + 一个 relay。
|
|
161
|
+
- **chaos 工具**(新增,纯 JS 优先,避免外部依赖):
|
|
162
|
+
- `pause(agent)` / `kill(agent)` / `kill relay`(进程级)
|
|
163
|
+
- 网络中断:本地代理(node net server 转发,可主动断开)模拟断网/丢包/慢速
|
|
164
|
+
- 时钟偏移:注入 `now()`(部分模块已支持)
|
|
165
|
+
- 配额耗尽:直接填满 blob/outbox/锁上限
|
|
166
|
+
- 所有 chaos 用例必须有确定性断言(轮询超时而非 sleep 固定值)。
|
|
167
|
+
|
|
168
|
+
### 6.2 真机(L2)
|
|
169
|
+
|
|
170
|
+
- 机器池:`jp-shared`(Linux)、`TwinsEarth`(Windows)、`macmini`(macOS)、`ToFuture`(Windows)。
|
|
171
|
+
- 前置:M1/M2 完成后通过 grant 授权执行;不能在验收中放宽 allow-list(验收本身要证明"不放宽也能做")。
|
|
172
|
+
- 数据安全:M3 验收使用**临时测试仓库**(本地 bare 或专用 demo repo),不碰本插件发布仓库的 main。
|
|
173
|
+
- 清理:验收后停服务/删临时 worktree/撤销 grant,脚本化。
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 7. 门禁集成(preflight 扩展)
|
|
178
|
+
|
|
179
|
+
新增检查项(注册进 preflight 的 15 项清单,替换/扩展现有"declared suite"):
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
1. acceptance-evidence:docs/acceptance/<current_version>/ 存在;每个 case JSON 通过 schema 校验;
|
|
183
|
+
task_id 能在当前 ledger/relay 中查到(或标记 archived 并带哈希);artifact sha 可下载且匹配。
|
|
184
|
+
2. negative-matrix:每个已声明错误码在证据中有至少一条 negative case;缺一个即 RED。
|
|
185
|
+
3. metrics-smoke:/metrics(或 stats)包含全部声明指标名;无重复/无非法标签。
|
|
186
|
+
4. chaos-lite(stable 门禁):本地 chaos 用例全过;beta 只需抽测并记录。
|
|
187
|
+
5. docs-claims:与现有 claims 检查合并,新增文档必须被索引(§9)。
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
beta / stable 门槛:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
beta :L0+L1 全过 + 本版本 L2 正向至少 1 条 + 对应 N 负向全过 + 证据入库
|
|
194
|
+
stable:beta 全部 + L2 全量 + L3 本版本相关用例全过 + 上版本回归
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 8. 验收证据的保存与索引
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
docs/acceptance/README.md 索引(版本 → case 列表 → 状态)
|
|
203
|
+
docs/acceptance/<version>/RUNBOOK.md 可复现步骤(命令/前置/期望)
|
|
204
|
+
docs/acceptance/<version>/<case>.json 机器可读证据
|
|
205
|
+
docs/acceptance/<version>/artifacts/ 可选小产物(大产物只存 sha,走 blob/ release)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
规则:
|
|
209
|
+
|
|
210
|
+
- 证据必须由 `scripts/acceptance.mjs`(新增)生成骨架,人工填结果后校验,避免手写非法 JSON。
|
|
211
|
+
- 每次发布(beta/stable)时,CHANGELOG 对应条目必须引用该版本的 acceptance 目录。
|
|
212
|
+
- 证据随版本冻结;后续修改以新 case 追加,不改历史。
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 9. 文档与声明的一致性
|
|
217
|
+
|
|
218
|
+
- 新文档(含本系列设计稿)必须登记进 `docs/acceptance/README.md` 或 `docs/INDEX`(实现时按现有 claims 机制选择),否则门禁拒绝。
|
|
219
|
+
- **能力级别口径修正**(M7 一并落地):
|
|
220
|
+
- "多机派发/聚合"(已实现)
|
|
221
|
+
- "多机协同开发"(M1–M6 完成后才算)
|
|
222
|
+
- "多客户端共享项目"(M4–M5 完成后才算)
|
|
223
|
+
- README/CHANGELOG 不再用"多机协同"泛称覆盖未完成能力。
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 10. 风险与对策
|
|
228
|
+
|
|
229
|
+
| 风险 | 对策 |
|
|
230
|
+
|---|---|
|
|
231
|
+
| 真机验收不可重复(机器掉线/环境漂移) | 证据带机器快照(版本/OS/caps);允许同 case 重跑覆盖(保留历史);关键 case 至少两台机器 |
|
|
232
|
+
| 测试变慢导致门禁不可用 | 分层:beta 只跑子集;stable 全量;chaos 用确定性轮询而非 sleep |
|
|
233
|
+
| 指标本身不可信 | 指标由 relay 计算;对关键指标加自检(如 task 计数 = ledger 事件计数校验) |
|
|
234
|
+
| 证据造假/过期 | task_id + ledger 区间 + artifact sha 三重校验;过期(>90 天)标记 stale 并在门禁提示 |
|
|
235
|
+
| 测试污染生产数据 | 验收专用项目/临时仓库;grant 限时;验收后清理脚本 |
|
|
236
|
+
| 时长失控(六模块验收) | 每个模块 ≥1 条正向 + 全负向矩阵;完整矩阵按版本 incremental 累加 |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 11. 交付物清单(实现阶段)
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
scripts/acceptance.mjs 证据骨架生成/校验/汇总
|
|
244
|
+
scripts/chaos.mjs 进程/网络/配额混沌工具(本地)
|
|
245
|
+
scripts/metrics-check.mjs 指标名与自检
|
|
246
|
+
src/relay/metrics.mjs 新增 M1–M6 计数器/直方图
|
|
247
|
+
src/relay/server.mjs /metrics 暴露(或复用现有路由)
|
|
248
|
+
scripts/preflight.mjs 新增三项检查(evidence/negative/metrics)
|
|
249
|
+
docs/acceptance/README.md 索引
|
|
250
|
+
docs/acceptance/<version>/… 每个 beta 的证据
|
|
251
|
+
test/acceptance-schema.test.mjs 证据 schema 校验(无证据即失败)
|
|
252
|
+
test/metrics.test.mjs 指标名/单调/自检
|
|
253
|
+
docs/COLLAB/M7-METRICS-ACCEPTANCE.md 本文
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## 12. 开放问题(实现前确认)
|
|
257
|
+
|
|
258
|
+
1. **真机验收执行方式**:人工执行 + 证据上传,还是配置 self-hosted runner 自动跑?前者快、后者可复现。
|
|
259
|
+
2. **SLO 阈值**:任务成功率/事件延迟/上传断点成功率的硬阈值定多少(本稿暂不写数值)?
|
|
260
|
+
3. **证据保留**:90 天过期提示是否合适?历史版本证据是否永久保留?
|
|
261
|
+
4. **混沌工具**:本版本只做本地代理模拟断网,还是也要真机断网(更真实但操作成本高)?
|
|
262
|
+
5. **stable 门槛**:L3 混沌是否强制全过才能 stable(推荐),还是允许豁免清单?
|
|
263
|
+
6. **文档索引机制**:新增 `docs/acceptance/README.md` 作为唯一索引,还是并入现有 claims 的 shipped-documents 列表?
|