pi-claude-supervisor 0.4.1 → 0.5.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  All notable changes to this project will be documented here.
4
4
 
5
+ ## [0.5.1](https://github.com/btnalit/pi-claude-supervisor/compare/v0.5.0...v0.5.1) (2026-09-14)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * harden single-worker recovery lifecycle ([14c01ec](https://github.com/btnalit/pi-claude-supervisor/commit/14c01ec610b1210eda1ea2d60269fad25b8b3575))
11
+
12
+ ## [0.5.0](https://github.com/btnalit/pi-claude-supervisor/compare/v0.4.1...v0.5.0) (2026-09-14)
13
+
14
+
15
+ ### Features
16
+
17
+ * add acceptance review repair loop ([fe29c78](https://github.com/btnalit/pi-claude-supervisor/commit/fe29c78a228494768aa52b03ee1bf1545b079119))
18
+
19
+ ## [Unreleased]
20
+
21
+ ### Added
22
+
23
+ - Structured task specifications with Goal, scope, constraints, forbidden actions and multiple argv-based acceptance checks.
24
+ - Independent read-only Reviewer results with bounded findings and automatic repair rounds.
25
+ - JSONL malformed-record handling and duplicate result/permission suppression fixtures.
26
+ - Active JSONL request shutdown coverage and deterministic acceptance/review tests.
27
+ - Durable Decision Worker recovery claims with stale-owner reconciliation and explicit fail-closed takeover.
28
+ - Identity-bound tmux handoff cleanup and recovery/lease lifecycle coverage.
29
+ - Claude Code 2.1.270 bounded stability matrix evidence in `docs/stability-matrix-2.1.270.md`.
30
+
5
31
  ## [0.4.1](https://github.com/btnalit/pi-claude-supervisor/compare/v0.4.0...v0.4.1) (2026-09-14)
6
32
 
7
33
 
@@ -69,7 +95,7 @@ All notable changes to this project will be documented here.
69
95
  - Historical Claude CLI 2.1.268 permission allow/deny and SIGTERM/SIGINT transport spike evidence; current release validation uses Claude CLI 2.1.270.
70
96
  - Event-driven JSONL `control_request`/`result`/exit events, permission responses, persistent Pi Decision Worker automation, bounded duplicate/turn handling, and outbound human-intervention webhooks.
71
97
  - Long-task defaults are now 100 automatic turns, 4 hours wall time and 20 minutes without output; Decision Worker API failures alert human operators directly instead of attempting an LLM fallback.
72
- - Automatic Decision Worker sessions now persist as Pi JSONL with a 0600 task registry. Unclean Pi restarts expose explicit `/supervise recover <task-id>` recovery; Claude work is not silently duplicated.
98
+ - Automatic Decision Worker sessions now persist as Pi JSONL with a 0600 task registry. Unclean Pi restarts expose explicit `/supervise recover [--takeover] <task-id>` recovery; Claude work is not silently duplicated.
73
99
  - Local tests and package-content checks.
74
100
 
75
101
  ### Limitations
package/README.cn.md CHANGED
@@ -51,9 +51,10 @@ Claude CLI `2.1.270` 运行,跨版本兼容性不在本轮范围内。
51
51
  ```text
52
52
  /supervise capabilities
53
53
  /supervise start inspect the current repository
54
+ /supervise start --spec ./task.json
54
55
  /supervise poll
55
56
  /supervise sessions
56
- /supervise recover <task-id>
57
+ /supervise recover [--takeover] <task-id>
57
58
  /supervise stop human requested stop
58
59
  /supervise verify
59
60
  /supervise approve <task-id> allow|deny [request-id]
@@ -61,6 +62,21 @@ Claude CLI `2.1.270` 运行,跨版本兼容性不在本轮范围内。
61
62
  /supervise resume-auto <task-id>
62
63
  ```
63
64
 
65
+ `--spec` 接受 JSON 文件;验收命令始终使用 argv 执行,不经过 shell。例如:
66
+
67
+ ```json
68
+ {
69
+ "goal": "实现请求的修改",
70
+ "scope": ["src/"],
71
+ "constraints": ["保持公共 API 兼容"],
72
+ "forbidden": ["不要发布构建产物"],
73
+ "acceptance": [
74
+ { "id": "tests", "name": "tests", "command": "npm", "args": ["test"], "required": true }
75
+ ],
76
+ "maxRepairRounds": 3
77
+ }
78
+ ```
79
+
64
80
  人工升级通知的 generic JSON 格式为:
65
81
 
66
82
  ```json
@@ -78,12 +94,21 @@ Claude CLI `2.1.270` 运行,跨版本兼容性不在本轮范围内。
78
94
 
79
95
  当前 webhook 是出站通知,不直接接受批准命令;批准或接管仍通过 Pi。
80
96
  自动模式会将 Decision Worker 会话持久化到状态目录。Pi 非正常重启后,`/supervise sessions`
81
- 会显示 `recoverable` 任务;显式执行 `/supervise recover <task-id>` 会恢复 Decision Worker 上下文并
82
- 重新启动 Claude Worker,不会静默恢复或重复执行任务。
97
+ 会显示 `recoverable` 任务;显式执行 `/supervise recover [--takeover] <task-id>` 会恢复 Decision Worker 上下文并
98
+ 重新启动 Claude Worker,不会静默恢复或重复执行任务。旧 Pi 进程已退出且租约确认旧 Worker
99
+ 进程组已消失且 cgroup 仍是真实、可读取的空边界时,才可显式添加 `--takeover`;缺失、仍存活或无法确认的 Worker 会被拒绝。持久 tmux
100
+ Worker 应使用 `adopt-tmux`,而不是 takeover。
83
101
  自动模式下,Decision Worker 可以安全拒绝 `AskUserQuestion`,让 Claude 将问题转成普通文本,
84
102
  再根据任务和仓库证据自动回答;无法确定时才升级人工。如需微信内闭环,需要另建带签名验证、
85
103
  一次性 action token 和重放保护的入站 callback 服务。
86
104
 
105
+ `v0.5.0` 已完成并发布“多命令验收—独立只读 Reviewer—结构化修复轮次—再次验收”闭环。
106
+ 任务可通过 API 或 JSON spec 提供 `goal`、`scope`、`constraints`、`forbidden` 和多个
107
+ `acceptance` 命令;旧的纯文本任务继续使用默认 `git diff --check`。Reviewer 只能使用
108
+ `read`、`grep`、`find`、`ls`,不会修改工作树或批准权限。短期剩余门禁是固定 Claude Code
109
+ `2.1.270` 的重复稳定性统计和 recovery 测试;协同多 Worker 属于后续独立开发阶段,
110
+ 暂不把多版本兼容、sandbox、低权限和网络隔离作为本阶段门禁。
111
+
87
112
  ### tmux/PTY 交互模式
88
113
 
89
114
  如果希望在可见的 Claude Code 终端中工作,可显式启用 tmux transport:
@@ -128,6 +153,11 @@ PTY 屏幕文字不是 Claude JSONL。权限/信任对话框和无法确定的 T
128
153
  /supervise send <task-id> continue after checking the test failure
129
154
  ```
130
155
 
156
+ 当前支持的是**独立任务会话并行**,不是共享工作树的协同多 Worker。后续多 Worker
157
+ 开发任务会引入 parent/child 任务图、依赖、并发上限、结构化 handoff、汇总验收和
158
+ 跨进程恢复,但不会放宽“一个 worktree 一个写入者”的边界,也不会自动 merge 或 publish。
159
+ 该阶段应安排在固定 Claude `2.1.270` 稳定性统计和单 Worker recovery 语义完成之后。
160
+
131
161
  Pull Request 必须通过聚合的 `CI / Quality gate`。Release Please 根据 Conventional Commits 创建版本 PR;维护者合并后,Release workflow 会针对精确 tag commit 重新验证,并通过受保护的 `npm` environment 使用 npm provenance 发布。
132
162
 
133
163
  详细内容见 [engineering-plan.md](docs/engineering-plan.md)、[independent-review.md](docs/independent-review.md)、[architecture.md](docs/architecture.md)、[testing.md](docs/testing.md) 和 [releasing.md](docs/releasing.md)。
package/README.md CHANGED
@@ -57,8 +57,9 @@ export PI_CLAUDE_SUPERVISOR_WORKER=claude
57
57
  ```text
58
58
  /supervise capabilities
59
59
  /supervise start inspect the current repository and report what should be changed
60
+ /supervise start --spec ./task.json
60
61
  /supervise sessions
61
- /supervise recover <task-id>
62
+ /supervise recover [--takeover] <task-id>
62
63
  /supervise poll
63
64
  /supervise poll all
64
65
  /supervise send continue with read-only inspection
@@ -68,6 +69,22 @@ export PI_CLAUDE_SUPERVISOR_WORKER=claude
68
69
  /supervise verify
69
70
  ```
70
71
 
72
+ `--spec` accepts a JSON file; checks are always executed with argv (never through
73
+ a shell), for example:
74
+
75
+ ```json
76
+ {
77
+ "goal": "Implement the requested change",
78
+ "scope": ["src/"],
79
+ "constraints": ["Keep the public API compatible"],
80
+ "forbidden": ["Do not publish artifacts"],
81
+ "acceptance": [
82
+ { "id": "tests", "name": "tests", "command": "npm", "args": ["test"], "required": true }
83
+ ],
84
+ "maxRepairRounds": 3
85
+ }
86
+ ```
87
+
71
88
  The default MVP writes the task to the worker's stdin as plain process-pipe
72
89
  text. After running the transport spike for the target CLI, JSONL framing can
73
90
  be selected explicitly:
@@ -83,16 +100,36 @@ The supervisor allows only one active JSONL request per session: poll until its
83
100
  yet exposed by the adapter. Multiple independent task sessions can run
84
101
  concurrently when they use different canonical working directories or
85
102
  worktrees; same-directory starts are rejected even when concurrent, and
86
- `/supervise sessions` lists the sessions. Unattended use still requires the
87
- remaining lifecycle, signal and recovery checks. Host permissions and network
88
- access follow explicit caller authorization and host policy; there is no
89
- automatic merge, deploy, release or publish.
103
+ `/supervise sessions` lists the sessions. This is independent-session
104
+ parallelism, not coordinated multi-worker collaboration. A future multi-worker
105
+ milestone will add explicit parent/child task graphs, dependencies, bounded
106
+ scheduling, structured handoffs, aggregate acceptance and graph-aware recovery;
107
+ it will not relax the one-writer-per-worktree rule or enable automatic
108
+ merge/publish. Unattended use still requires the remaining lifecycle, signal and
109
+ recovery checks. Host permissions and network access follow explicit caller
110
+ authorization and host policy; there is no automatic merge, deploy, release or
111
+ publish.
112
+
113
+ The `v0.5.0` automation milestone adds a structured acceptance pipeline:
114
+ multiple argv-based checks, an independent read-only Reviewer, bounded structured
115
+ findings and repair rounds. Legacy text tasks keep the default `git diff --check`.
116
+ The Reviewer only has `read`, `grep`, `find` and `ls`; it cannot edit files or grant
117
+ permissions. The next gates are pinned Claude Code `2.1.270` stability statistics
118
+ and explicit session recovery. Coordinated multi-worker scheduling is a later
119
+ milestone; CI will use deterministic fake Workers/replay fixtures, and real
120
+ multi-worker Claude tests will remain authenticated manual Spikes. CLI
121
+ multi-version compatibility, sandboxing, low-privilege execution and network
122
+ isolation are not part of this milestone.
90
123
 
91
124
  Automatic mode persists the Pi Decision Worker session under the configured state
92
125
  directory. After an unclean Pi restart, `/supervise sessions` lists recoverable
93
- tasks; `/supervise recover <task-id>` explicitly restores the Decision Worker
126
+ tasks; `/supervise recover [--takeover] <task-id>` explicitly restores the Decision Worker
94
127
  context and starts a new Claude Worker. It never silently resumes or duplicates
95
- work. The adapter intentionally does not inherit arbitrary host environment variables.
128
+ work. If the old Pi owner is dead, add `--takeover` only after the lease proves
129
+ the old Worker's process group is gone and its cgroup is a real, readable empty
130
+ boundary; missing or unverifiable Worker evidence is refused.
131
+ For a persistent tmux Worker, use explicit `adopt-tmux` instead of takeover.
132
+ The adapter intentionally does not inherit arbitrary host environment variables.
96
133
  Pass credentials through an explicit `WorkerStartInput.env` in an embedding
97
134
  integration. For the built-in command, opt in to named variables, for example
98
135
  `PI_CLAUDE_SUPERVISOR_WORKER_ENV=ANTHROPIC_API_KEY`.
@@ -27,6 +27,28 @@ directories/worktrees; same-cwd and parent/child cwd starts are rejected before
27
27
  spawn, including concurrent starts, to prevent uncoordinated edits. Pending starts
28
28
  are also awaited during Pi shutdown.
29
29
 
30
+ ### Multi-worker boundary and roadmap
31
+
32
+ The current implementation supports multiple **independent** task sessions, not
33
+ coordinated shared-worktree editing. Every active session must own a
34
+ non-overlapping canonical cwd/worktree and has an isolated Supervisor,
35
+ watchdog, Worker handle and acceptance/review loop. The shared EventLog is only
36
+ an audit stream; it is not a collaboration or authorization channel.
37
+
38
+ A future multi-worker scheduler must introduce an explicit parent/child task
39
+ graph, roles, dependencies, bounded concurrency and structured handoff
40
+ artifacts. Child Workers must communicate through validated evidence and event
41
+ references rather than another Worker's control channel. Each child is accepted
42
+ independently; the parent can complete only after aggregate acceptance and
43
+ independent Review. Integration, conflict resolution, merge and publication
44
+ remain explicit human-controlled operations in a separate integration worktree.
45
+
46
+ Recovery and shutdown must be graph-aware: a parent with an unknown child state
47
+ cannot complete, cancellation must propagate within a bounded budget, and Pi
48
+ shutdown must leave every child either cleanup-verified or explicitly
49
+ recoverable. This work is scheduled after single-worker stability and session
50
+ recovery, not by relaxing the current cwd lease rule.
51
+
30
52
  ## MVP transport
31
53
 
32
54
  `ProcessWorkerAdapter` uses `node:child_process.spawn` with:
@@ -126,9 +148,12 @@ registry before spawning Claude. The default registry is
126
148
  may point all Pi processes at an alternate shared directory. Canonical paths
127
149
  conflict with both their parents and descendants, and the registry lock
128
150
  serializes acquisition across independent Pi processes. A lease is released
129
- only after the adapter confirms the worker and its descendant cleanup; an
130
- unconfirmed lease left by a crashed Pi is intentionally retained and requires
131
- operator verification/manual cleanup rather than unsafe automatic reclamation.
151
+ only after the adapter confirms the worker and its descendant cleanup. An
152
+ unconfirmed lease left by a crashed Pi is intentionally retained. Ordinary
153
+ recovery refuses it; an operator may use `recover --takeover` only when the old
154
+ owner is dead, the Worker process group is gone, and the lease independently
155
+ reads a real empty cgroup boundary for the old Worker. Missing or unverifiable
156
+ Worker evidence still requires manual cleanup rather than unsafe reclamation.
132
157
  An explicitly adopted tmux session may hand off an existing lease only after
133
158
  its owner identity is no longer live and its canonical cwd, tmux session/socket,
134
159
  pane id, pane PID/start time, and pane command all match; ordinary starts
@@ -170,7 +195,8 @@ duplicate turns. The adapter also exposes event subscriptions for `result`,
170
195
  `control_request`, permission requests and process exit. Automatic mode routes
171
196
  those events to a persistent, read-only Pi Decision Worker; its Pi session JSONL
172
197
  and task mapping are persisted under the supervisor state directory. After an
173
- unclean Pi restart, recovery is explicit: `/supervise recover <task-id>` restores
198
+ unclean Pi restart, recovery is explicit: `/supervise recover [--takeover]
199
+ <task-id>` restores
174
200
  the Decision Worker context and starts a new Claude Worker. It does not silently
175
201
  resume or duplicate a task. It does not poll to detect turn completion. A watchdog timer remains only as a deadlock safety
176
202
  fallback. Permission actions pass through `evaluatePermission` and can be
@@ -181,6 +207,29 @@ human operator; it does not attempt a second LLM fallback. Alert delivery is
181
207
  kept independent from event-log persistence so an audit write failure cannot
182
208
  suppress the alert.
183
209
 
210
+ ## Acceptance, review and repair loop
211
+
212
+ A task may provide a structured `TaskSpec` with `goal`, `scope`, `constraints`,
213
+ `forbidden` and an ordered list of required or optional acceptance checks. A
214
+ legacy plain-text task is normalized to a goal with the default `git diff
215
+ --check` acceptance check. The verifier runs every configured check with argv,
216
+ bounded output and the same deterministic command policy; a Worker completion
217
+ claim never substitutes for these results.
218
+
219
+ When automatic supervision is enabled, a successful check set is passed to a
220
+ fresh read-only Reviewer session. The Reviewer receives the task specification, repository status/diff evidence,
221
+ check results and bounded Worker completion evidence, but not the Decision Worker
222
+ conversation or control channel. It can inspect only `read`, `grep`, `find` and `ls`, and must return
223
+ `pass`, `revise` or `human` with bounded structured findings. Invalid Reviewer
224
+ output or a Reviewer API failure is a human-required condition.
225
+
226
+ A `revise` result produces an audited repair round and sends a bounded corrective
227
+ instruction to a still-live JSONL/tmux Worker. Checks and review then run again.
228
+ The repair budget defaults to three rounds; repeated findings and P0/P1 findings
229
+ stop automation and escalate. A non-persistent Worker that has already exited
230
+ cannot be silently recreated for repair; it remains failed/recoverable rather
231
+ than replaying the original task.
232
+
184
233
  ## Deliberate non-goals
185
234
 
186
235
  - automatic merge/deploy/release;
@@ -192,4 +241,7 @@ suppress the alert.
192
241
  - shell command interpolation;
193
242
  - automatic network denial or a fake domain allowlist. Network access follows
194
243
  Claude's own permission model and the command policy; suspicious download-to-
195
- shell patterns require human review rather than blanket network rejection.
244
+ shell patterns require human review rather than blanket network rejection;
245
+ - Claude CLI multi-version compatibility in the current stability milestone;
246
+ - OS sandbox, low-privilege execution and network isolation in the current
247
+ lifecycle milestone.
@@ -1,6 +1,6 @@
1
1
  # Pi Claude Supervisor 完整方案
2
2
 
3
- > 文档状态:方案设计稿 / MVP 实施基线
3
+ > 文档状态:`v0.5.0` 已发布 / 后续开发路线图
4
4
  > 目标项目目录:`pi-claude-supervisor`
5
5
  > 适用对象:W、项目负责人、实现人员、评审人员
6
6
 
@@ -36,7 +36,7 @@ Claude Code Worker
36
36
  4. Supervisor 因误判导致无限循环、危险操作或不可审计的修改。
37
37
  5. 人工无法随时接管或恢复任务。
38
38
 
39
- **总体判断:架构方向可以 GO。先完成兼容性 Spike、生命周期和故障恢复验证;低权限用户、OS sandbox 与网络隔离不作为当前主线或硬性阻塞,按调用者明确授权和宿主机策略运行,后续再做安全加固。**
39
+ **当前状态:`v0.5.0` 已完成“验收—独立 Review—自动修复—再验收”闭环并正式发布。下一阶段先完成固定 Claude Code `2.1.270` 的稳定性统计和恢复语义,再推进有边界的多 Worker 协作;低权限用户、OS sandbox 与网络隔离仍是后续安全加固,不作为当前主线硬性阻塞。**
40
40
 
41
41
  ---
42
42
 
@@ -74,7 +74,9 @@ Claude Code 适合作为实际开发 Worker,但在长时间任务中可能出
74
74
  - 不自动 merge、deploy 或 release。
75
75
 
76
76
  当前扩展已支持多个独立任务会话并行推进,但不允许活动会话共享同一
77
- 工作目录。事件日志由跨进程锁协调,状态和 watchdog 按会话隔离。
77
+ 工作目录。事件日志由跨进程锁协调,状态和 watchdog 按会话隔离。这里要区分两种
78
+ “多 Worker”:**独立会话并行**已经属于当前能力;**有依赖、交接和汇总验收的协同多
79
+ Worker**属于后续开发任务,不能通过简单地放宽 cwd 限制来实现。
78
80
 
79
81
  暂不支持:
80
82
 
@@ -916,3 +918,115 @@ PTY 和 headless JSONL 只能选择一个作为 MVP 的主 transport,禁止两
916
918
  ## 附录 B:一句话版本
917
919
 
918
920
  > 先用最小、可审计、可接管的 Supervisor 闭环证明可靠性,再逐步开放 LLM 判断和自动化权限;不要从“自动化最多”开始,而要从“边界最清楚、证据最可靠”开始。
921
+
922
+ ## 20. 近期落地与剩余门禁:稳定的自动验收闭环
923
+
924
+ 本轮已落地 TaskSpec、多命令验收、独立只读 Reviewer、结构化 repair round、重复 finding/P0/P1 人工升级、JSONL 去重和确定性 replay fixture。剩余门禁是固定 CLI 的重复运行统计,而不是继续扩大安全边界。近期目标从“扩大安全边界”调整为先证明单一已验证 Claude CLI 版本上的真实功能稳定性。当前只验证固定的 Claude Code `2.1.270`,不把多版本兼容作为本阶段任务。OS sandbox、低权限用户、网络 allowlist、SBOM 和更深的供应链加固后置,不作为本阶段门禁;现有 no-shell、Policy Gate、人工接管和独立验收边界继续保留。
925
+
926
+ ### 20.1 Goal / Evidence / Sign-off 模型
927
+
928
+ 任务规格统一为:
929
+
930
+ ```yaml
931
+ goal: 实现用户邀请接口
932
+ scope:
933
+ - 新增接口
934
+ - 添加权限校验
935
+ constraints:
936
+ - 不修改核心数据库模型
937
+ forbidden:
938
+ - 不执行生产部署
939
+ acceptance:
940
+ - id: tests
941
+ command: npm
942
+ args: [test]
943
+ - id: typecheck
944
+ command: npm
945
+ args: [run, typecheck]
946
+ - id: diff-check
947
+ command: git
948
+ args: [diff, --check]
949
+ maxRepairRounds: 3
950
+ ```
951
+
952
+ 兼容旧任务时,普通任务文本作为 `goal`,默认验收仍为 `git diff --check`。所有验收命令使用 argv 和确定性 Policy Gate,不经过 shell。
953
+
954
+ 验收流程固定为:
955
+
956
+ ```text
957
+ Worker result
958
+ → 多命令 acceptance checks
959
+ → 独立只读 Reviewer
960
+ ├── pass → completed
961
+ ├── revise → 结构化修复指令 → Worker → 重新验收
962
+ └── human → 人工接管
963
+ ```
964
+
965
+ Reviewer 必须使用独立 Pi session,只允许 `read`、`grep`、`find`、`ls`,输出结构化 verdict 和 findings;不能修改工作树或直接批准权限。默认最多三轮修复;相同 finding 重复出现或出现 P0/P1 问题时升级人工。
966
+
967
+ ### 20.2 JSONL 稳定性证据
968
+
969
+ 只对 Claude Code `2.1.270` 建立证据,覆盖:
970
+
971
+ - JSONL 跨 chunk 拆分、单 chunk 多记录和 malformed 行;malformed 行不能触发完成事件;
972
+ - 重复 result、重复 permission request、重复 Supervisor idempotency key 不产生重复动作;
973
+ - active request 期间的 SIGTERM、SIGINT、stop 和 Pi shutdown;
974
+ - 普通完成、低风险 Bash allow、`AskUserQuestion` deny-to-text、多轮、验收失败修复和恢复回放。
975
+
976
+ 真实 Claude Spike 不进入普通 CI;确定性 fake Worker/replay fixture 进入 CI。自动模式继续保持显式 opt-in,直到以下门禁通过:普通任务连续十次成功,权限和问题转文本场景各至少五次成功,无重复动作、无错误 complete、无未清理 Worker,且关键事件可以完整回放。
977
+
978
+ ### 20.3 明确不属于本阶段
979
+
980
+ - Claude CLI 多版本兼容;
981
+ - OS sandbox、低权限执行和网络隔离;
982
+ - 自动 merge、deploy、release、publish;
983
+ - 多 Worker 在同一工作树协作。
984
+
985
+ ## 21. 后续开发路线图
986
+
987
+ `v0.5.0` 的发布不代表所有自动化目标都已完成。后续任务按“稳定性 → 恢复 → 协同
988
+ 调度 → 安全加固”推进;多 Worker 可以纳入开发任务,但应作为独立阶段,不能与当前
989
+ 单 Worker 稳定性门禁混在一起。
990
+
991
+ ### 21.1 短期:稳定性收尾
992
+
993
+ - 完成真实 Claude Code `2.1.270` 重复 Spike:普通任务连续 10 次,权限和问题回退各至少 5 次;
994
+ - 补齐 replay:多轮修复、验收失败修复、repair budget 耗尽、takeover、recover 和 Pi shutdown;
995
+ - 补齐边界测试:Reviewer 流式输出上限、`DecisionSessionStore.list()` 任务 ID 校验、跨进程恢复和超时/输出截断;
996
+ - 继续观察 npm `0.5.0`、GitHub Release 资产、provenance 和回滚路径;
997
+ - 验收标准:无重复动作、错误 complete、未清理 Worker 或未审计的自动放行。
998
+
999
+ ### 21.2 中期:恢复能力
1000
+
1001
+ - 设计安全的 Claude session resume;明确 `--resume` 与实时 PTY attach 的边界;
1002
+ - 完善 takeover、recover、Pi shutdown、Worker 崩溃和部分完成的状态语义;
1003
+ - 增加跨进程恢复端到端测试,包括 cwd lease、Decision Worker session、Worker 身份和事件日志一致性;
1004
+ - 恢复失败必须进入 `HUMAN_REQUIRED`,不能静默重放原始任务或重复发送输入。
1005
+
1006
+ ### 21.3 后续:多 Worker 协作与调度
1007
+
1008
+ 第一阶段只做**独立 worktree 的多 Worker 编排**,不允许共享工作树写入。建议拆成以下
1009
+ 开发任务:
1010
+
1011
+ 1. **任务图与角色模型**:增加 `parentTaskId`、Worker role、`dependsOn`、worktree、handoff
1012
+ artifact 和子任务状态;明确 root task 与 child task 的审计关联。
1013
+ 2. **受限调度器**:实现并发上限、依赖就绪、全局时间/修复预算、取消传播和失败隔离;
1014
+ 不让任意 Worker 自行启动、停止或批准另一个 Worker。
1015
+ 3. **结构化交接**:Worker 之间只通过受限 artifact、事件引用和验收报告交接,不直接共享
1016
+ 控制通道;交接内容必须经过 schema 校验和大小限制。
1017
+ 4. **汇总验收**:每个 child 先独立验收,root task 再汇总目标、diff、测试和 Reviewer 结果;
1018
+ 冲突、缺失证据或任一 P0/P1 自动升级人工。
1019
+ 5. **恢复与关闭**:支持单个 child、整棵任务图和 Pi shutdown 的一致性恢复;父任务不能在
1020
+ 子任务状态未知时报告 `completed`。
1021
+ 6. **冲突检测和人工整合**:只允许在独立 integration worktree 中进行显式整合;不自动
1022
+ merge/publish,冲突和整合动作必须保留人工控制权。
1023
+
1024
+ 多 Worker 阶段的最小验收矩阵:两个独立 Worker 并行、依赖顺序、一个 Worker 失败、取消
1025
+ 传播、重复交接、工作树冲突、单 child 恢复、整棵任务图恢复和 shutdown 中断。通过这些
1026
+ 门禁后,才评估是否需要更复杂的 lead-worker 或动态任务分解。
1027
+
1028
+ ### 21.4 后置:安全加固
1029
+
1030
+ - CLI 多版本兼容矩阵;
1031
+ - OS sandbox、低权限执行、网络隔离/allowlist;
1032
+ - 更深的供应链、SBOM、密钥隔离和生产监控。
@@ -0,0 +1,24 @@
1
+ # Recovery follow-up review
2
+
3
+ The independent read-only review of the recovery changes initially returned
4
+ `BLOCK` with three P1 findings, one P2 finding, and a coverage note. The findings
5
+ were addressed in this follow-up.
6
+
7
+ - Stale `starting`/`registered`/`recovered_idle` claims now persist recovery
8
+ owner PID/start time, are reconciled only after the old owner and Worker
9
+ boundary are independently gone, and return to an explicit `interrupted`
10
+ state.
11
+ - `--takeover` requires a dead owner, dead Worker/process group, and a real,
12
+ readable empty cgroup boundary; missing or unverifiable Worker evidence is
13
+ rejected.
14
+ - Worker registration and `recovered_idle` transitions require an active record,
15
+ persist atomically, and are read back and checked before the recovered session
16
+ is exposed.
17
+ - Adopted tmux handoff reports the replaced task and closes its old Decision
18
+ session mapping only after worker identity registration succeeds.
19
+ - Session closure now carries cleanup evidence and intent; uncertain cleanup
20
+ retains the active record and cwd lease.
21
+
22
+ Validation: `npm run check`, `npm run build`, the pinned Claude Code 2.1.270
23
+ question matrix (5/5 verified), and the bounded stability evidence in
24
+ [`stability-matrix-2.1.270.md`](stability-matrix-2.1.270.md).
@@ -0,0 +1,32 @@
1
+ # Claude Code 2.1.270 stability matrix
2
+
3
+ Run date: 2026-09-14. The executable was resolved as
4
+ `/home/yancao/.local/share/mise/installs/claude/2.1.270/claude` and reported
5
+ `2.1.270 (Claude Code)`. Runs used the authenticated local provider and
6
+ `scripts/spike-claude-automation.mjs`; no Claude `--resume` was used.
7
+
8
+ ## Required matrix (120 s bounded run)
9
+
10
+ | Scenario | Runs | Completed + verified | Fail-closed outcomes |
11
+ | --- | ---: | ---: | --- |
12
+ | ordinary task | 10 | 9 | 1 stopped at the bounded deadline without verification |
13
+ | permission handling | 5 | 5 | 0 |
14
+ | question handling | 5 | 5 | 0 |
15
+
16
+ The ordinary outlier was not treated as success: the spike exited non-zero,
17
+ kept verification false, and stopped rather than retrying or replaying the task.
18
+ This is the intended timeout fail-closed behavior. An earlier question spike also
19
+ escalated after invalid Decision Worker output; it was likewise not counted as a
20
+ success. The five-run question matrix above was then rerun with a 180 s bound and
21
+ all five completed with `verified=true` and zero human interventions.
22
+
23
+ ## Bounded follow-up
24
+
25
+ Three additional ordinary and three additional question runs with the same
26
+ pinned executable and a 180 s bound also completed with `verified=true` and zero
27
+ human interventions. These runs support a provider-latency explanation for the
28
+ 120 s outliers; they do not turn an outlier into a success.
29
+
30
+ The deterministic replay, acceptance, recovery-state, lease, cleanup and
31
+ package checks remain the CI evidence. Authenticated Claude runs are manual
32
+ release evidence only.
package/docs/testing.md CHANGED
@@ -49,9 +49,9 @@ non-sensitive prompt, and prints protocol metadata rather than raw model output.
49
49
  It must not be added to the normal CI gate because authentication is an owner
50
50
  controlled prerequisite.
51
51
 
52
- The historical fixtures validate one prompt, multiple turns, session resume,
53
- permission allow/deny and SIGTERM/SIGINT behavior with Claude Code 2.1.268.
54
- The current release validation uses Claude Code 2.1.270 at
52
+ The transport fixtures validate one prompt, multiple turns, session resume,
53
+ permission allow/deny and SIGTERM/SIGINT behavior. The current release validation
54
+ uses Claude Code 2.1.270 at
55
55
  `/home/yancao/.local/share/mise/installs/claude/2.1.270/claude`, including real
56
56
  owned tmux turns, pause/resume, and restart re-adoption.
57
57
  The adapter regression suite also verifies event subscription, parsed
@@ -59,11 +59,18 @@ The adapter regression suite also verifies event subscription, parsed
59
59
  The automation spike additionally exercises a real Pi SDK Decision Worker with
60
60
  Claude: ordinary completion, harmless Bash permission approval, and an
61
61
  `AskUserQuestion` denial-to-text fallback followed by automatic verification.
62
+ A local pinned-CLI run completed all three scenarios with `state=completed`,
63
+ `verified=true`, and zero human interventions. Provider/model latency can still
64
+ cause a later run to fail closed as human-required after the bounded Decision
65
+ Worker or Reviewer timeout; this is evidence for the manual spike only, not a CI
66
+ guarantee.
62
67
  The extension persists each automatic Decision Worker session as Pi JSONL plus a
63
68
  0600 task mapping. Recovery is explicit and safe: after an unclean Pi restart,
64
69
  `/supervise sessions` shows the task as `recoverable`, and `/supervise recover
65
- <task-id>` restores the Decision Worker history before starting a new Claude
66
- Worker.
70
+ [--takeover] <task-id>` restores the Decision Worker history before starting a new
71
+ Claude Worker. `--takeover` is accepted only when the old Pi owner is dead, the
72
+ Worker process group is gone, and its cgroup is a real readable empty boundary;
73
+ persistent tmux sessions use `adopt-tmux`.
67
74
  Run the permission and signal probes explicitly when validating a CLI release:
68
75
 
69
76
  ```bash
@@ -89,7 +96,9 @@ response, and an exact result marker; it also records metadata only.
89
96
 
90
97
  For each release, pin and record the validated Claude Code version, resolved
91
98
  executable path, and model. The spikes reject an unpinned/mismatched executable
92
- version. For this release the validated version is `2.1.270` with model `opus`.
99
+ version. For this release the validated version is `2.1.270` with model `opus`;
100
+ the bounded matrix and its fail-closed outliers are recorded in
101
+ [`docs/stability-matrix-2.1.270.md`](stability-matrix-2.1.270.md).
93
102
  Record:
94
103
 
95
104
  1. exact version and resolved executable path;
@@ -144,3 +153,68 @@ not eliminate the post-spawn attachment window. `SIGSTOP` and `SIGKILL` of the P
144
153
  verify and document the resulting orphan behavior.
145
154
  Default behavior must be fail-closed and leave no orphaned worker process within
146
155
  the managed process group.
156
+
157
+ ## Near-term automation acceptance gate
158
+
159
+ The `v0.5.0` implementation of the acceptance—independent Review—repair—reacceptance
160
+ loop is shipped. The remaining gate focuses on real stability for the pinned
161
+ Claude Code `2.1.270` CLI. It does not add a multi-version matrix or wait for
162
+ OS sandbox, low-privilege or network-isolation work.
163
+
164
+ ### Acceptance and Reviewer fixtures
165
+
166
+ Deterministic tests must cover:
167
+
168
+ - legacy text tasks normalized to a Goal with the default `git diff --check`;
169
+ - multiple required/optional checks with bounded output, timeout and exit-code evidence;
170
+ - independent read-only Reviewer pass/revise/human results;
171
+ - invalid Reviewer JSON and Reviewer API failure escalating to human;
172
+ - repair rounds, repeated finding detection, P0/P1 escalation and repair-budget exhaustion;
173
+ - completion being impossible without passing all required checks and review.
174
+
175
+ Reviewer sessions use only `read`, `grep`, `find` and `ls`; they must not modify
176
+ the worktree or send Worker input. Decision Worker and Reviewer model calls are
177
+ bounded; timeout or API failure escalates instead of auto-completing. Review reports
178
+ are persisted as bounded event payloads and are not treated as permission grants.
179
+
180
+ ### JSONL protocol and replay fixtures
181
+
182
+ The adapter/replay matrix must cover:
183
+
184
+ - JSON split across stdout chunks and multiple records in one chunk;
185
+ - malformed JSON between valid records without a false completion event;
186
+ - duplicate result and permission records without duplicate actions;
187
+ - duplicate Supervisor idempotency keys without duplicate input;
188
+ - stop, SIGTERM, SIGINT and Pi shutdown while a JSONL request is active;
189
+ - ordinary completion, low-risk permission allow, AskUserQuestion deny-to-text,
190
+ multi-turn, verifier failure/repair, takeover and explicit recovery.
191
+
192
+ Real Claude tests remain authenticated manual Spikes and are pinned to
193
+ `2.1.270`; they are not part of normal CI. Normal CI runs deterministic fake
194
+ Worker and replay fixtures. The short-term stability gate is still pending and
195
+ must include ten consecutive ordinary automatic runs and at least five runs each
196
+ for permission and question handling, with no duplicate action, false completion
197
+ or unreaped Worker.
198
+
199
+ ## Future multi-worker test plan
200
+
201
+ Multiple independent task sessions already run concurrently when their canonical
202
+ cwd/worktrees do not overlap. This is not yet coordinated multi-worker
203
+ collaboration. The future multi-worker milestone must be tested as a task graph,
204
+ not as unrestricted shared-worker access.
205
+
206
+ Required deterministic and integration coverage:
207
+
208
+ - two independent Workers with separate worktrees and aggregated parent status;
209
+ - dependency ordering and a blocked child that must not start early;
210
+ - child failure, timeout, cancellation propagation and bounded global budgets;
211
+ - schema-validated handoff artifacts with duplicate/oversized/stale handoffs;
212
+ - conflicting diffs detected before integration, with no same-worktree writes;
213
+ - independent child acceptance followed by root-task aggregate acceptance and Review;
214
+ - single-child recovery, whole-graph recovery and Pi shutdown during scheduling;
215
+ - no child can grant permissions, send control input to another child or bypass Policy Gate;
216
+ - explicit human-controlled integration in a separate worktree; no automatic merge or publish.
217
+
218
+ The multi-worker gate should be added only after the pinned single-worker stability
219
+ and recovery gates pass. CI should use fake Workers and replay fixtures; authenticated
220
+ Claude multi-worker Spikes remain manual and version-pinned.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-claude-supervisor",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "A policy-gated Pi supervisor for observing and verifying Claude Code workers.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {