1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
//! On-disk layout for a step (ARCH §2.3 and §2.10).
//!
//! Each step lives in its own directory under
//! `<conv-repo>/steps/<conv-id>/<NNN>/`, zero-padded 3-digit and
//! 1-indexed. The tree is at the conversation-repo root, *outside
//! every worktree* (§2.2 / §2.3), so context assembly (§3.5, §5)
//! cannot see step records as model context. Namespacing by
//! conversation id is what lets every conversation in the tree
//! (root and every subagent) write into a single shared `steps/`
//! tree without filename collision.
//!
//! Per-step files in v0.3.1+:
//!
//! - `meta.json` — `{commit, started_at, ended_at}`. The `commit`
//! field is the sha of the branch tip at step-start; replay
//! reproduces the wire input by re-running the context assembler
//! (§5) against this commit's tree (§2.10).
//! - `request.json` — diagnostic snapshot of the wire request the
//! model saw. Written for audit / human inspection only; the
//! harness never reads it at runtime (§2.3 Diagnostic-only contract).
//! - `response.json` — JSONL of §4.4 stream events, appended by the
//! harness as the adapter writes them. Writer-closes-fd is the
//! `IN_CLOSE_WRITE` end-of-stream signal (§3.5). Diagnostic-only;
//! the harness never reads it back (§2.3).
//! - `stderr.log` — the adapter subprocess's stderr, appended across
//! the model call's attempts. Empty on an ordinary run: brazen
//! speaks its failures in-band on stdout (§4.4), so bytes here mean
//! the adapter failed *outside* that contract — a startup failure
//! with nothing on stdout at all. Diagnostic-only; the tail quoted in
//! a half-stream error comes from the live capture, never a read-back
//! (§2.3).
//! - `tools/<tool-id>/` — per-tool-call records (`input.json`,
//! `output.json`); diagnostic raw capture, written but never read at
//! runtime (§2.3 Diagnostic-only contract). A tool result's runtime
//! home is its transcript entry, `messages/NNN-tool.json` (§2.3, §3.3).
//! - `staging.json` — the transcript entry under construction (§2.3
//! *The transcript writer*): the writer's own sink, not a diagnostic
//! record, renamed out to the worktree at the model call's settling
//! `Finish`.
use crate;
use ;
/// Top-level directory holding per-conversation step records, located
/// at the conversation-repo root outside every worktree (ARCH §2.2 /
/// §2.3). Joined onto the conv-repo path by writers, never the
/// worktree path.
pub const STEPS_DIR: &str = "steps";
/// Diagnostic snapshot of the wire request the model saw. Written
/// for audit only — harness never reads at runtime (§2.3).
pub const REQUEST_FILE: &str = "request.json";
/// JSONL of §4.4 stream events, written event-by-event by the harness
/// as the adapter emits them. End-of-stream is the writer closing the
/// fd (§3.5 IN_CLOSE_WRITE). Diagnostic-only; harness never reads it
/// back (§2.3).
pub const RESPONSE_FILE: &str = "response.json";
/// The adapter subprocess's stderr for a model call, appended per
/// attempt beside `response.json` (§2.3). Empty on an ordinary run —
/// brazen surfaces failures in-band on stdout (§4.4) — so a non-empty
/// file is the signature of an adapter that died outside that contract.
/// Diagnostic-only: written, never read back (§2.3).
pub const STDERR_FILE: &str = "stderr.log";
/// Step metadata: branch-tip sha at step-start plus timestamps
/// (§2.3). Readable by the harness — it carries the commit a
/// replay re-assembles against, which is the load-bearing piece.
pub const META_FILE: &str = "meta.json";
/// The model-output transcript entry *under construction* (ARCH §2.3
/// *The transcript writer*). Content blocks stream here block-by-block as
/// a JSON array; segment authority (§4.4) truncates it on an `Error`
/// segment, accumulates it on `Pause`, and the final `Finish` seals it,
/// whereupon the executor renames it into the worktree as
/// `messages/NNN-<model-id>.json` (§2.3). The one path under `steps/`
/// that is not a diagnostic record — the writer's own sink, never read
/// back as a step record (§2.3 Diagnostic-only contract).
pub const STAGING_FILE: &str = "staging.json";
/// Width of the zero-padded step sequence in on-disk paths
/// (`steps/<conv-id>/001`, `…/002`, ...). Three digits gives comfortable
/// headroom for any realistic conversation while keeping directories
/// lexically sortable.
const STEP_SEQ_WIDTH: usize = 3;
/// The conv-repo-relative directory for step `seq` within conversation
/// `conv_id`. `seq` is 1-indexed. Joined onto the conv-repo root
/// (not any worktree) — step records live outside every worktree
/// per ARCH §2.2 / §2.3.
/// The branch's next step sequence, derived — never stored — as
/// max-present-plus-one over the `steps/<conv-id>/` directory listing
/// (ARCH §6: workflow position is a function of disk state; the same
/// derivation discipline as the transcript counter, §2.3). An absent or
/// empty directory yields `1` — the general path with empty inputs, not
/// a bootstrap special case. A fresh `lernie advance` hop reads its
/// position here instead of carrying a loop counter across the exec
/// baton.
/// The framing outcome of `agent`'s latest step's `response.json`, or
/// `None` when no step tree, no numeric step, or no readable response
/// exists (the general path with empty inputs). Reads only the §4.4
/// framing tail via [`classify`] — a sanctioned framing read under the
/// §2.3 diagnostic-only contract (framing-yes / content-no).
///
/// This is the single derivation behind every "did this branch's work
/// end well?" question — the §8 silent-death sweep and the
/// `lernie message` failed-branch advisory alike: a latest step that
/// never settled complete (§2.3) — [`Outcome::NoTerminal`] (killed or
/// stopped mid-work, §2.9) or [`Outcome::Failed`] (retries exhausted or
/// a non-retryable error, §2.10) — committed no transcript entry, so
/// the branch cannot advance without a new touch.
/// On-disk shape of `meta.json`. The `commit` field is the branch
/// tip's sha at step-start — the read state for the model call
/// (§2.10). `started_at` / `ended_at` bookend the call's wall-clock
/// duration. Replay tooling reads `commit` to locate the tree state
/// the request was assembled against.