Skip to content

Commit 073eaeb

Browse files
authored
Merge pull request #41 from vitry/fix/rescue-child-recovery
fix: reactivate persisted Rescue children
2 parents fc6fb10 + dad4a6c commit 073eaeb

45 files changed

Lines changed: 5677 additions & 409 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All notable changes follow Semantic Versioning.
44

55
## Unreleased
66

7+
- Added persisted stopped Rescue child recovery before replacement spawn: the plugin restores the original Codex thread and history by joining sanitized app-server identity with private executor provenance, rejoins already active children, and never treats age or a name/path collision as authority.
78
- Restored compatibility with the legacy PR #39 Rescue route: after origin-to-worktree binding, a child launched or resumed from the conversation root can resolve the immutable execution target. This qualification does not broaden authority beyond that bound target.
89
- Added compatible Rescue worktree late binding: lifecycle proof retains the origin workspace while the first trusted prepare automatically and immutably binds one execution workspace from the same canonical Git common-dir, without manual handoff. Role preview and children cannot claim; unrelated repositories fail closed; Root Stop, a new prompt, and SessionEnd revoke or replace authority before target cleanup.
910
- Accepted ZCode CLI 0.16.3's captured initial empty-session revision and pre-turn settings snapshots while retaining exact empty-state, event-sequence, identity, workspace, and activity checks. Real qualification now proves two visible responses through each turn's exact persisted user-root parent chain when the CLI remaps request input IDs.

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ Rescue has two equivalent entry forms. An explicit `$zcode:rescue` request is li
5656

5757
Root starts `prepare rescue` on a raw-capable TTY. The companion enables raw mode before it emits the exact task-free readiness line; readiness is nonterminal. Only after that line does Root send one JSON line terminated by LF over private stdin, with no EOF or U+0004. The companion consumes that one frame, restores raw mode, and commits exact session, turn, workspace, and executor-bound prepared state. Non-TTY or raw-mode failure stops before task delivery and no child is spawned. Tool output never contains or echoes the payload; only the task-free readiness and final prepared acknowledgement cross back. The named Role and generic child then run the same constant `invoke-prepared rescue` forwarder, without receiving the task, options, capability, or authorization material. If an active `rescueChildId` already exists, Root rejoins and waits for that exact Rescue child instead of repeating preflight, preparation, spawn, or invocation.
5858

59-
A durable Rescue binding now keeps one exact stopped Rescue child attached to one exact ZCode session. Its private `anchorJobId` identifies the adopted operation, and `currentJobId` advances when each continuation job is durably reserved and published, even if that job later queues, fails, or is cancelled; neither identifier is sent in a child message. A clear proactive continuation prepares resume and follows up the same stopped child, which runs the same `invoke-prepared rescue` assignment with no second `SubagentStart`. An explicit bound request without `--resume` or `--fresh` also follows up that same child and lets its bound `needs-choice` result drive the one user choice. `--fresh` always prepares an independent operation and a new child.
59+
The plugin's Companion, during preparation and before any replacement spawn, discovers the parent's persisted Codex children. A persisted stopped Rescue child is recovered before any spawn: the original Codex thread and its history are restored, rather than creating a lookalike child. The plugin joins sanitized Codex app-server identity with private executor provenance and requires one exact match; ambiguous or contradictory evidence fails closed. Root receives and executes only the resulting task-free directive; it does not discover or choose a child identity. An active Rescue child is rejoined through the existing active-child path. Neither 30-minute age nor a name or path collision is authority and neither authorizes recovery or replacement.
60+
61+
A durable Rescue binding now keeps one exact stopped Rescue child attached to one exact ZCode session. Its private `anchorJobId` identifies the adopted operation, and `currentJobId` advances when each continuation job is durably reserved and published, even if that job later queues, fails, or is cancelled; neither identifier is sent in a child message. A clear proactive continuation prepares resume and follows up the same stopped child, which runs the same `invoke-prepared rescue` assignment with no second `SubagentStart`. An explicit bound request without `--resume` or `--fresh` also follows up that same child and lets its bound `needs-choice` result drive the one user choice. `--fresh` always prepares a new independent ZCode operation, but it need not allocate a fresh Codex child: the planner may reactivate and follow up a qualified stopped Rescue child, preferring the managed base and then the deterministic newest compatible executor, and prescribes a spawn only when none exists. Reusing a Codex child does not resume its prior ZCode binding or session; the new operation creates a peer session with the current permission snapshot. A name or path collision is never authority for that choice.
6062

6163
Ordinary foreground Rescue completion has no plugin-defined wall-clock deadline. Active parent authority is lifecycle-bound rather than time-bound, so a clear continuation in that still-active parent turn can replace the consumed one-shot preparation with the next 30-minute generation, follow up the exact stopped child, and reuse the exact bound ZCode session. Caller credentials and every preparation generation remain bounded to 30 minutes; request RPCs, the optional Stop review gate, qualification harnesses, and explicit status waits also retain finite budgets. Root `Stop`, a replacement `UserPromptSubmit`, `SessionEnd`, `$zcode:cancel`, `SIGINT`, and `SIGTERM` remain authoritative termination or revocation boundaries.
6264

README.zh-CN.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ Rescue 有两种等价入口:显式 `$zcode:rescue` 是请求中字面且适
5656

5757
Root 在 raw-capable TTY 上启动 `prepare rescue`。companion 先启用 raw mode,再输出精确且不含 task 的 readiness;readiness 是非终态。只有看到该行之后,Root 才通过私有 stdin 发送一行 JSON,并以 LF 结尾;不发送 EOF 或 U+0004。companion 消费这一帧、恢复 raw mode,并提交绑定精确 session、turn、workspace 和 executor 的 prepared state。非 TTY 或 raw mode 失败会在 task 交付前停止,且不会 spawn child。tool output 绝不包含或回显 payload;返回边界只有不含 task 的 readiness 和最终 prepared 确认。随后具名 Role 或 generic child 都只运行常量 `invoke-prepared rescue` forwarder,不接收 task、options、capability 或授权材料。若已经有活动的 `rescueChildId`,Root 会重新加入并等待这个精确的 Rescue child,不会重复 preflight、prepare、spawn 或 invoke。
5858

59-
durable Rescue binding 现在把同一个已停止的 Rescue child 绑定到一个精确 ZCode session。私有 `anchorJobId` 标识被采用的操作,`currentJobId` 在每个续做 job 被持久预留并发布时前移,即使该 job 随后排队、失败或取消;两个标识都不会进入 child message。明确的主动续做会 prepare resume 并 follow up 同一个已停止的 Rescue child;它复用相同的 `invoke-prepared rescue` assignment,不会产生第二次 `SubagentStart`。显式 bound 请求若没有 `--resume``--fresh`,也 follow up 同一 child,并由其 bound `needs-choice` 结果触发一次用户选择。`--fresh` 始终准备独立操作和新的 child。
59+
插件的 Companion 在 preparation 期间、任何替代 spawn 之前,发现该 parent 的持久化 Codex children。持久化且已停止的 Rescue child 会被恢复,这发生在任何 spawn 之前:原 Codex thread 及其历史会被恢复,而不是创建一个外观相似的新 child。插件把已净化的 Codex app-server identity 与私有 executor provenance 结合,并要求只有一个精确匹配;证据有歧义或相互矛盾时会 fail closed。Root 只接收并执行由此产生且不含 task 的 directive,不负责发现或选择 child identity。活动的 Rescue child 仍通过现有路径重新加入。30 分钟 age 与名称或路径碰撞都不构成授权或权威,也不能授权恢复或替代创建。
60+
61+
durable Rescue binding 现在把同一个已停止的 Rescue child 绑定到一个精确 ZCode session。私有 `anchorJobId` 标识被采用的操作,`currentJobId` 在每个续做 job 被持久预留并发布时前移,即使该 job 随后排队、失败或取消;两个标识都不会进入 child message。明确的主动续做会 prepare resume 并 follow up 同一个已停止的 Rescue child;它复用相同的 `invoke-prepared rescue` assignment,不会产生第二次 `SubagentStart`。显式 bound 请求若没有 `--resume` 或 `--fresh`,也 follow up 同一 child,并由其 bound `needs-choice` 结果触发一次用户选择。`--fresh` 始终准备新的独立 ZCode 操作,但不要求分配新的 Codex child:planner 可以恢复并 follow up 合格的已停止 Rescue child,优先选择受管 base,其次选择确定性的最新兼容 executor;两者都不存在时才 prescribe spawn。复用 Codex child 不会 resume 其先前的 ZCode binding 或 session;新操作会以当前 permission 快照创建 peer session。名称或路径碰撞绝不是该选择的权威。
6062

6163
普通前台 Rescue 的完成等待不设插件定义的墙钟截止时间。活动父 turn 的授权由生命周期而非时间绑定,因此在同一个仍活动的父 turn 中,明确续做可以用下一代 30 分钟的一次性 preparation 替换已消费代,follow up 精确的已停止 child,并复用精确绑定的 ZCode session。caller credential 和每一代 preparation 仍以 30 分钟为界;request RPC、可选 Stop review gate、qualification harness 和显式 status wait 也继续使用各自有限预算。Root `Stop`、替换性的 `UserPromptSubmit``SessionEnd``$zcode:cancel``SIGINT``SIGTERM` 仍是权威的终止或撤销边界。
6264

SECURITY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Report suspected vulnerabilities privately through GitHub's private vulnerabilit
1717
- Child stderr and detailed progress stay in the child thread. Parent-visible output is limited to host lifecycle events and the final public result. Subscription or optional progress-sink failure is observational and cannot weaken the authoritative completion guard.
1818
- Rescue task material exists in the routing rollout only as the Root parent's single LF-terminated JSON line sent through `write_stdin` to `prepare rescue`. The companion requires a raw-capable TTY and enables raw mode before emitting task-free readiness and before accepting any task bytes; readiness is nonterminal. Root sends no EOF or U+0004. Non-TTY/readiness/raw-mode failure stops before delivery. Tool output must never contain or echo the payload. Prepared state is bound to the exact Codex session, initiating turn, canonical workspace, and executor identity; it is single consume, has a bounded expiry, and is subject to private-state cleanup. The task, source, and options must never appear in argv, environment variables, output, logs, artifacts, relays, status, task names, or any child assignment/transcript. Named and generic children are task-blind and capability-free and receive only the constant `invoke-prepared rescue` assignment.
1919
- Rescue records the trusted prompt cwd as the origin workspace and lets only the first trusted prepare bind one execution workspace. Cross-worktree binding requires an exact canonical Git top level with the same canonical Git common-dir; the first prepare makes that target immutable for the turn. Role preview is read-only, a child cannot claim authority, and an unrelated repository fails closed. Root Stop, a new prompt, and SessionEnd revoke or replace authority before target cleanup, while all preparation, executor, job, binding, broker, and peer state remains scoped to the execution workspace.
20+
- Persisted-child recovery joins sanitized Codex app-server identity with private executor provenance under the existing parent and workspace proofs. Only one exact persisted stopped child may restore its original thread and history; ambiguous, duplicate, contradictory, or cross-parent evidence fails closed, while an already active child uses the existing rejoin path. A 30-minute age or collision must never authorize recovery, replacement, or execution.
2021
- A durable Rescue binding authorizes the same stopped child to continue only its exact ZCode session. The private `anchorJobId` and `currentJobId` remain inside protected plugin state and never cross the parent-to-child message boundary. Missing, closed, corrupt, permission-incompatible, workspace-mismatched, executor-mismatched, or provenance-inconsistent bindings fail closed.
2122
- Ordinary foreground completion has no plugin wall-clock deadline. Authority still ends at Root `Stop`, replacement prompt, `SessionEnd`, explicit `$zcode:cancel`, `SIGINT`, or `SIGTERM`; request, review-gate, qualification, caller credential, and one-shot preparation budgets remain finite. Same-parent-turn continuation requires the exact stopped executor, exact binding operation/anchor/current CAS values, and exact ZCode session. Each 30-minute preparation generation is single-consume and generation 2 is bound to generation 1's exact executor.
2223
- Role readiness is fail-closed but distinguishes unavailable caller authority (`caller-unavailable`) from an unavailable inspection channel (`inspection-unavailable`) and from managed install/upgrade/drift/conflict/restart/genuine-unsupported states. Only the managed states authorize setup guidance; owned prior Role bytes require the normal one-time upgrade and foreign Role state is never adopted.

0 commit comments

Comments
 (0)