codex-rescue 0.1.0a1__tar.gz

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.
@@ -0,0 +1,27 @@
1
+ # Changelog
2
+
3
+ All notable changes to Codex Rescue will be documented in this file.
4
+
5
+ ## v0.1.0-alpha
6
+
7
+ Initial experimental alpha release.
8
+
9
+ ### Included
10
+
11
+ - Recent Codex session discovery (`sessions` command)
12
+ - Interrupted and damaged session diagnosis (`doctor` command)
13
+ - Immutable evidence-backed recovery salvage (`salvage` command)
14
+ - Git repository state verification (`verify` command)
15
+ - Confidence-labeled recovery handoff (VERIFIED / RECONSTRUCTED / UNKNOWN)
16
+ - Sanitized synthetic regression corpus (5 fixture types)
17
+ - Sanitized real-origin regression corpus (3 cases)
18
+ - Crash-safe append-only journal
19
+ - Bounded recovery brief generation
20
+ - Secret redaction in handoff artifacts
21
+
22
+ ### Known limitations
23
+
24
+ - Broad real compaction recovery not yet validated
25
+ - Interactive continuation depends on terminal/TTY environment
26
+ - Previous Codex version recovery coverage is limited
27
+ - Not every arbitrary corruption type is supported
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 shleder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,21 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ include pyproject.toml
5
+
6
+ prune fixtures
7
+ prune real-corpus
8
+ prune tests
9
+ prune .github
10
+ prune .validation-output
11
+ prune .pypi-release-venv
12
+ prune .release-venv
13
+ prune .validation-baseline
14
+ prune .validation-runtime
15
+ prune .cli-smoke
16
+ prune .codex-rescue-poc
17
+ prune .codex-rescue-final
18
+ prune .codex-rescue-final-3
19
+ prune .review-output
20
+
21
+ global-exclude *.pyc *.pyo __pycache__
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: codex-rescue
3
+ Version: 0.1.0a1
4
+ Summary: Local-first recovery tool for interrupted and damaged OpenAI Codex sessions
5
+ Author: shleder
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/shleder/codex-rescue
8
+ Project-URL: Repository, https://github.com/shleder/codex-rescue
9
+ Project-URL: Issues, https://github.com/shleder/codex-rescue/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development :: Quality Assurance
20
+ Classifier: Topic :: System :: Recovery Tools
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Dynamic: license-file
25
+
26
+ <p align="center">
27
+ <a href="https://github.com/shleder/codex-rescue/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/shleder/codex-rescue/ci.yml?branch=main&style=flat-square&label=CI&logo=github" alt="CI Status"></a>
28
+ <a href="https://github.com/shleder/codex-rescue/releases/tag/v0.1.0-alpha"><img src="https://img.shields.io/badge/version-v0.1.0--alpha-3fb950?style=flat-square" alt="Version"></a>
29
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
30
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-1f6feb?style=flat-square&logo=python&logoColor=white" alt="Python"></a>
31
+ <a href="#privacy"><img src="https://img.shields.io/badge/privacy-100%25%20local--first-238636?style=flat-square" alt="Privacy"></a>
32
+ </p>
33
+
34
+ ---
35
+
36
+ ## Overview
37
+
38
+ When **OpenAI Codex CLI** can't resume safely, **Rescue** tells you what actually happened and gets you back to work.
39
+
40
+ Codex Rescue is a local-first fsck and crash-recovery tool for OpenAI Codex sessions. It diagnoses interrupted or damaged sessions, verifies repository working tree state, and reconstructs a bounded evidence-backed continuation **without modifying the original Codex rollout**.
41
+
42
+ > [!WARNING]
43
+ > **Codex Rescue is experimental alpha software.**
44
+ > It is an evidence-gathering release designed to collect real failure cases.
45
+ > See [Alpha Limitations](#alpha-limitations) below.
46
+
47
+ ---
48
+
49
+ ## Core Commands
50
+
51
+ Rescue provides four narrow, read-only diagnostic and recovery entry points:
52
+
53
+ | Command | Usage | Description |
54
+ |---|---|---|
55
+ | **`sessions`** | `codex-rescue sessions` | Discover and list recent local Codex rollout sessions |
56
+ | **`doctor`** | `codex-rescue doctor --latest` | Inspect and diagnose a damaged session (**read-only**) |
57
+ | **`salvage`** | `codex-rescue salvage --latest --fork` | Create an immutable, content-addressed recovery handoff |
58
+ | **`verify`** | `codex-rescue verify <rescue-id>` | Detect repository divergence before executing continuation |
59
+
60
+ ---
61
+
62
+ ## Confidence Model
63
+
64
+ Rescue reconstructs facts with explicit, uncompromised confidence levels. Model prose alone is **never** accepted as source of truth.
65
+
66
+ | Level | Badge | Meaning & Source of Truth |
67
+ |---|---|---|
68
+ | **VERIFIED** | `VERIFIED` | Directly proven by durable evidence: Git HEAD SHA, working tree diff, tool execution exit code, or durable output record |
69
+ | **RECONSTRUCTED** | `RECONSTRUCTED` | Strongly inferred from available evidence with no unresolved contradictions |
70
+ | **UNKNOWN** | `UNKNOWN` | Cannot be proven safely. **UNKNOWN is deliberate.** Rescue refuses to guess when execution state is uncertain |
71
+
72
+ > [!NOTE]
73
+ > **Safety Invariants:**
74
+ > 1. Source rollouts are **immutable** (`doctor`, `salvage`, and `verify` never write to the original `.jsonl` file).
75
+ > 2. **No automatic replay** — an action whose execution status is `UNKNOWN` is never automatically re-executed.
76
+
77
+ ---
78
+
79
+ ## Quick Start
80
+
81
+ ### 1. Installation
82
+
83
+ Install directly from the GitHub release tag:
84
+
85
+ ```bash
86
+ # Recommended global installation via pipx
87
+ pipx install git+https://github.com/shleder/codex-rescue.git@v0.1.0-alpha
88
+
89
+ # Or via standard pip
90
+ pip install git+https://github.com/shleder/codex-rescue.git@v0.1.0-alpha
91
+ ```
92
+
93
+ ### 2. Workflow Example
94
+
95
+ ```bash
96
+ # 1. Discover recent Codex sessions
97
+ codex-rescue sessions
98
+
99
+ # 2. Diagnose the latest session
100
+ codex-rescue doctor --latest
101
+
102
+ # 3. Generate an immutable recovery handoff
103
+ codex-rescue salvage --latest --fork
104
+
105
+ # 4. Verify repository state before continuing
106
+ codex-rescue verify <rescue-id>
107
+ ```
108
+
109
+ ### Sample Output
110
+
111
+ ```text
112
+ $ codex-rescue doctor --latest
113
+
114
+ Doctor: UNFINISHED_TOOL_CALL
115
+ Findings: UNFINISHED_TOOL_CALL
116
+ Repository: /path/to/repo (HEAD a6cfe48)
117
+
118
+ $ codex-rescue salvage --latest --fork
119
+
120
+ Salvage: 8f8f4e822c9ce353ed584c5f
121
+ Original session untouched: yes
122
+ Rescue directory: .codex-rescue/rescues/8f8f4e822c9ce353ed584c5f
123
+
124
+ $ codex-rescue verify 8f8f4e822c9ce353ed584c5f
125
+
126
+ Verify: REVIEW_REQUIRED
127
+ Review: unfinished action requires inspection before replay
128
+ Review: handoff contains load-bearing unknowns
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Proven Compatibility & Evidence
134
+
135
+ | Version / Scope | Status | Proven Real-World Evidence |
136
+ |---|---|---|
137
+ | **Codex CLI 0.147.0** | **Validated** | Genuine interrupted session diagnosed (`UNFINISHED_TOOL_CALL`), source rollout preserved, repo state verified |
138
+ | **Codex CLI 0.146.1** | **Smoke-tested** | Isolated authentication & basic rollout parser validation |
139
+ | **Codex 0.145.0-alpha.18** | **Observed** | Legacy envelope format compatibility observed |
140
+ | **Synthetic Fixtures** | **5/5 PASS** | `kill_apply_patch`, `kill_shell_before_result`, `lost_tail_after_compaction`, `malformed_jsonl`, `oversized_payload` |
141
+
142
+ ---
143
+
144
+ ## Alpha Limitations
145
+
146
+ > [!IMPORTANT]
147
+ > The following limitations are documented honestly. Do not claim recovery guarantees that have not been validated.
148
+
149
+ - **Compaction recovery** — broad real compaction-related recovery is not yet validated; only synthetic fixtures exist.
150
+ - **Interactive continuation** — automatic fresh continuation depends on terminal/TTY environment (Windows ConPTY limitations noted).
151
+ - **Previous versions** — validation is focused on Codex CLI 0.147.0; earlier versions are smoke-tested or observed.
152
+ - **Side-effect replay** — Rescue does not automatically replay unknown side effects; it reports them as `REVIEW_REQUIRED`.
153
+
154
+ ---
155
+
156
+ ## Privacy & Security
157
+
158
+ - **100% Local-First** — zero telemetry, zero analytics, zero network uploads, zero cloud dependencies.
159
+ - **No private DB mutation** — Rescue never modifies `state_*.sqlite` or internal Codex databases.
160
+ - **Secret Redaction** — built-in secret redaction automatically filters common API key patterns (`sk-*`, `ghp_*`, `AKIA*`, Bearer tokens).
161
+ - **Sanitization Notice** — Codex rollouts can contain secrets; sanitize all session files before attaching to public issues.
162
+
163
+ ---
164
+
165
+ ## Development & Verification
166
+
167
+ ```bash
168
+ # Clone the repository
169
+ git clone https://github.com/shleder/codex-rescue.git
170
+ cd codex-rescue
171
+
172
+ # Install in editable mode
173
+ pip install -e .
174
+
175
+ # Run full unit test suite (43 passed, 1 skipped)
176
+ python -m unittest discover -s tests -v
177
+
178
+ # Run synthetic fixture harness (5/5 PASS)
179
+ python -m codex_rescue.harness fixtures --output .validation-output/test
180
+
181
+ # Run deterministic alpha demo
182
+ python scripts/demo_alpha.py
183
+ ```
184
+
185
+ ---
186
+
187
+ ## Submit a Recovery Report
188
+
189
+ The primary goal of this public alpha is collecting real broken Codex sessions to expand our sanitized regression corpus.
190
+
191
+ [**Open a Recovery Report →**](https://github.com/shleder/codex-rescue/issues/new?template=recovery-report.yml)
192
+
193
+ > [!CAUTION]
194
+ > **Do NOT upload raw rollout files containing secrets or credentials.** Always sanitize session data before attaching.
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ Distributed under the [MIT License](LICENSE). Copyright (c) 2026 shleder.
@@ -0,0 +1,175 @@
1
+ <p align="center">
2
+ <a href="https://github.com/shleder/codex-rescue/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/shleder/codex-rescue/ci.yml?branch=main&style=flat-square&label=CI&logo=github" alt="CI Status"></a>
3
+ <a href="https://github.com/shleder/codex-rescue/releases/tag/v0.1.0-alpha"><img src="https://img.shields.io/badge/version-v0.1.0--alpha-3fb950?style=flat-square" alt="Version"></a>
4
+ <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
5
+ <a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-1f6feb?style=flat-square&logo=python&logoColor=white" alt="Python"></a>
6
+ <a href="#privacy"><img src="https://img.shields.io/badge/privacy-100%25%20local--first-238636?style=flat-square" alt="Privacy"></a>
7
+ </p>
8
+
9
+ ---
10
+
11
+ ## Overview
12
+
13
+ When **OpenAI Codex CLI** can't resume safely, **Rescue** tells you what actually happened and gets you back to work.
14
+
15
+ Codex Rescue is a local-first fsck and crash-recovery tool for OpenAI Codex sessions. It diagnoses interrupted or damaged sessions, verifies repository working tree state, and reconstructs a bounded evidence-backed continuation **without modifying the original Codex rollout**.
16
+
17
+ > [!WARNING]
18
+ > **Codex Rescue is experimental alpha software.**
19
+ > It is an evidence-gathering release designed to collect real failure cases.
20
+ > See [Alpha Limitations](#alpha-limitations) below.
21
+
22
+ ---
23
+
24
+ ## Core Commands
25
+
26
+ Rescue provides four narrow, read-only diagnostic and recovery entry points:
27
+
28
+ | Command | Usage | Description |
29
+ |---|---|---|
30
+ | **`sessions`** | `codex-rescue sessions` | Discover and list recent local Codex rollout sessions |
31
+ | **`doctor`** | `codex-rescue doctor --latest` | Inspect and diagnose a damaged session (**read-only**) |
32
+ | **`salvage`** | `codex-rescue salvage --latest --fork` | Create an immutable, content-addressed recovery handoff |
33
+ | **`verify`** | `codex-rescue verify <rescue-id>` | Detect repository divergence before executing continuation |
34
+
35
+ ---
36
+
37
+ ## Confidence Model
38
+
39
+ Rescue reconstructs facts with explicit, uncompromised confidence levels. Model prose alone is **never** accepted as source of truth.
40
+
41
+ | Level | Badge | Meaning & Source of Truth |
42
+ |---|---|---|
43
+ | **VERIFIED** | `VERIFIED` | Directly proven by durable evidence: Git HEAD SHA, working tree diff, tool execution exit code, or durable output record |
44
+ | **RECONSTRUCTED** | `RECONSTRUCTED` | Strongly inferred from available evidence with no unresolved contradictions |
45
+ | **UNKNOWN** | `UNKNOWN` | Cannot be proven safely. **UNKNOWN is deliberate.** Rescue refuses to guess when execution state is uncertain |
46
+
47
+ > [!NOTE]
48
+ > **Safety Invariants:**
49
+ > 1. Source rollouts are **immutable** (`doctor`, `salvage`, and `verify` never write to the original `.jsonl` file).
50
+ > 2. **No automatic replay** — an action whose execution status is `UNKNOWN` is never automatically re-executed.
51
+
52
+ ---
53
+
54
+ ## Quick Start
55
+
56
+ ### 1. Installation
57
+
58
+ Install directly from the GitHub release tag:
59
+
60
+ ```bash
61
+ # Recommended global installation via pipx
62
+ pipx install git+https://github.com/shleder/codex-rescue.git@v0.1.0-alpha
63
+
64
+ # Or via standard pip
65
+ pip install git+https://github.com/shleder/codex-rescue.git@v0.1.0-alpha
66
+ ```
67
+
68
+ ### 2. Workflow Example
69
+
70
+ ```bash
71
+ # 1. Discover recent Codex sessions
72
+ codex-rescue sessions
73
+
74
+ # 2. Diagnose the latest session
75
+ codex-rescue doctor --latest
76
+
77
+ # 3. Generate an immutable recovery handoff
78
+ codex-rescue salvage --latest --fork
79
+
80
+ # 4. Verify repository state before continuing
81
+ codex-rescue verify <rescue-id>
82
+ ```
83
+
84
+ ### Sample Output
85
+
86
+ ```text
87
+ $ codex-rescue doctor --latest
88
+
89
+ Doctor: UNFINISHED_TOOL_CALL
90
+ Findings: UNFINISHED_TOOL_CALL
91
+ Repository: /path/to/repo (HEAD a6cfe48)
92
+
93
+ $ codex-rescue salvage --latest --fork
94
+
95
+ Salvage: 8f8f4e822c9ce353ed584c5f
96
+ Original session untouched: yes
97
+ Rescue directory: .codex-rescue/rescues/8f8f4e822c9ce353ed584c5f
98
+
99
+ $ codex-rescue verify 8f8f4e822c9ce353ed584c5f
100
+
101
+ Verify: REVIEW_REQUIRED
102
+ Review: unfinished action requires inspection before replay
103
+ Review: handoff contains load-bearing unknowns
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Proven Compatibility & Evidence
109
+
110
+ | Version / Scope | Status | Proven Real-World Evidence |
111
+ |---|---|---|
112
+ | **Codex CLI 0.147.0** | **Validated** | Genuine interrupted session diagnosed (`UNFINISHED_TOOL_CALL`), source rollout preserved, repo state verified |
113
+ | **Codex CLI 0.146.1** | **Smoke-tested** | Isolated authentication & basic rollout parser validation |
114
+ | **Codex 0.145.0-alpha.18** | **Observed** | Legacy envelope format compatibility observed |
115
+ | **Synthetic Fixtures** | **5/5 PASS** | `kill_apply_patch`, `kill_shell_before_result`, `lost_tail_after_compaction`, `malformed_jsonl`, `oversized_payload` |
116
+
117
+ ---
118
+
119
+ ## Alpha Limitations
120
+
121
+ > [!IMPORTANT]
122
+ > The following limitations are documented honestly. Do not claim recovery guarantees that have not been validated.
123
+
124
+ - **Compaction recovery** — broad real compaction-related recovery is not yet validated; only synthetic fixtures exist.
125
+ - **Interactive continuation** — automatic fresh continuation depends on terminal/TTY environment (Windows ConPTY limitations noted).
126
+ - **Previous versions** — validation is focused on Codex CLI 0.147.0; earlier versions are smoke-tested or observed.
127
+ - **Side-effect replay** — Rescue does not automatically replay unknown side effects; it reports them as `REVIEW_REQUIRED`.
128
+
129
+ ---
130
+
131
+ ## Privacy & Security
132
+
133
+ - **100% Local-First** — zero telemetry, zero analytics, zero network uploads, zero cloud dependencies.
134
+ - **No private DB mutation** — Rescue never modifies `state_*.sqlite` or internal Codex databases.
135
+ - **Secret Redaction** — built-in secret redaction automatically filters common API key patterns (`sk-*`, `ghp_*`, `AKIA*`, Bearer tokens).
136
+ - **Sanitization Notice** — Codex rollouts can contain secrets; sanitize all session files before attaching to public issues.
137
+
138
+ ---
139
+
140
+ ## Development & Verification
141
+
142
+ ```bash
143
+ # Clone the repository
144
+ git clone https://github.com/shleder/codex-rescue.git
145
+ cd codex-rescue
146
+
147
+ # Install in editable mode
148
+ pip install -e .
149
+
150
+ # Run full unit test suite (43 passed, 1 skipped)
151
+ python -m unittest discover -s tests -v
152
+
153
+ # Run synthetic fixture harness (5/5 PASS)
154
+ python -m codex_rescue.harness fixtures --output .validation-output/test
155
+
156
+ # Run deterministic alpha demo
157
+ python scripts/demo_alpha.py
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Submit a Recovery Report
163
+
164
+ The primary goal of this public alpha is collecting real broken Codex sessions to expand our sanitized regression corpus.
165
+
166
+ [**Open a Recovery Report →**](https://github.com/shleder/codex-rescue/issues/new?template=recovery-report.yml)
167
+
168
+ > [!CAUTION]
169
+ > **Do NOT upload raw rollout files containing secrets or credentials.** Always sanitize session data before attaching.
170
+
171
+ ---
172
+
173
+ ## License
174
+
175
+ Distributed under the [MIT License](LICENSE). Copyright (c) 2026 shleder.
@@ -0,0 +1,42 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "codex-rescue"
7
+ dynamic = ["version"]
8
+ description = "Local-first recovery tool for interrupted and damaged OpenAI Codex sessions"
9
+ readme = "README.md"
10
+ license = {text = "MIT"}
11
+ requires-python = ">=3.11"
12
+ dependencies = []
13
+ authors = [
14
+ {name = "shleder"},
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Quality Assurance",
27
+ "Topic :: System :: Recovery Tools",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/shleder/codex-rescue"
32
+ Repository = "https://github.com/shleder/codex-rescue"
33
+ Issues = "https://github.com/shleder/codex-rescue/issues"
34
+
35
+ [project.scripts]
36
+ codex-rescue = "codex_rescue.cli:main"
37
+
38
+ [tool.setuptools.dynamic]
39
+ version = {attr = "codex_rescue.__version__"}
40
+
41
+ [tool.setuptools.packages.find]
42
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Codex Rescue — local-first recovery for OpenAI Codex sessions."""
2
+
3
+ __version__ = "0.1.0a1"
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+
10
+ def canonical_json(data: Any) -> bytes:
11
+ return json.dumps(data, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
12
+
13
+
14
+ def atomic_write(path: Path, data: bytes) -> None:
15
+ path.parent.mkdir(parents=True, exist_ok=True)
16
+ temp = path.with_name(f".{path.name}.{os.getpid()}.tmp")
17
+ fd = os.open(temp, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
18
+ try:
19
+ offset = 0
20
+ while offset < len(data):
21
+ offset += os.write(fd, data[offset:])
22
+ os.fsync(fd)
23
+ finally:
24
+ os.close(fd)
25
+ os.replace(temp, path)
26
+ if os.name != "nt":
27
+ dir_fd = os.open(path.parent, os.O_RDONLY)
28
+ try:
29
+ os.fsync(dir_fd)
30
+ finally:
31
+ os.close(dir_fd)
32
+
33
+
34
+ def write_rescue(root: Path, handoff: dict[str, Any], brief: str, continuation: str) -> tuple[str, Path]:
35
+ handoff_bytes = canonical_json(handoff)
36
+ rescue_id = hashlib.sha256(handoff_bytes).hexdigest()[:24]
37
+ rescue_dir = root / "rescues" / rescue_id
38
+ atomic_write(rescue_dir / "handoff.v1.json", handoff_bytes + b"\n")
39
+ atomic_write(rescue_dir / "RECOVERY_BRIEF.md", brief.encode("utf-8"))
40
+ atomic_write(rescue_dir / "CONTINUATION_PROMPT.md", continuation.encode("utf-8"))
41
+ return rescue_id, rescue_dir
42
+
43
+
44
+ def load_handoff(root: Path, rescue_id: str) -> dict[str, Any]:
45
+ path = root / "rescues" / rescue_id / "handoff.v1.json"
46
+ data = json.loads(path.read_text(encoding="utf-8"))
47
+ actual_id = hashlib.sha256(canonical_json(data)).hexdigest()[:24]
48
+ if actual_id != rescue_id:
49
+ raise ValueError(f"handoff hash mismatch: expected {rescue_id}, actual {actual_id}")
50
+ return data
51
+