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
//! The one-line row projection of a transcript (DESIGN §11 transcript
//! density rule).
//!
//! Vertical space is the scarce resource: **every** transcript row — a
//! delivered message, one model text block, one thinking block, one tool
//! call, one tool result, the live tail — renders as exactly ONE line that
//! folds open to its full payload. A row is therefore a *block*, not a file:
//! a model message that says something and then calls two tools is three
//! rows, because it is three things.
//!
//! **Expansion is derived, never stored per row.** The auto-state is a pure
//! function of the row's class and the two durable knobs ([`AutoExpand`],
//! `ui.json` §4.1): the conversation expands, the machinery around it
//! contracts. The caller's fold set holds *explicit overrides only* — the
//! `ui.json.collapsed` discipline applied to RAM (§5.3): `expanded = auto
//! XOR overridden`. That dissolves "state on arrival" as a special case —
//! there is no arrival event, and a row that appears mid-frame is already in
//! its auto-state without anyone having to notice it appeared.
//!
//! Keys are the row's identity — `tx/<entry filename>#<block index>` — so
//! they survive the stateless re-read of the whole transcript each frame and
//! never collide with the jsonview collapse paths sharing the caller's set.
//!
//! Cut at the real seams: **what a row is** (the vocabulary below — the
//! classes, the tones, the auto-state rule), **what an entry becomes**
//! ([`project`] — the exhaustive per-variant match and the preview/body
//! split), and **what a finished turn becomes** ([`turns`] — the rollup of a
//! turn's machinery to one aggregate row). The vocabulary is read by the
//! render and by every test; the other two are read by nothing but [`rows`].
use HashSet;
use Transcript;
pub use key;
/// The two auto-state knobs (§4.1 `ui.json`, §11): whether a class expands on
/// its own. Defaults are the operator's ruling — the conversation open, all
/// else folded — and both are knobs so the policy is config, not code
/// (severability).
/// Which auto-knob a row answers to. The split is **conversation vs
/// machinery**, not model vs everyone: a message delivered *to* the agent is
/// the other half of the exchange the operator came to read, so it arrives
/// expanded beside the reply it provoked (bl-6ec6 — a user turn folded shut
/// is the operator's own words hidden from them).
/// The paint hue a row asks for; the render maps each to a `theme` constant
/// (never an RGB restated here — §11 single colour authority).
/// What a row's `▶` opens onto — the two things a fold can reveal.
/// One transcript line. `prefix` is the always-visible label (`sender:`,
/// `⚙ Read`, `✔ tool result — ok`); `preview` is the payload's first line, shown
/// while contracted; `body` is the full payload, shown while expanded and
/// **empty when the payload already fits the one line** (such a row has
/// nothing to fold and shows no toggle); `hover` is what the prefix stands for,
/// empty when the label says everything it has to say.
/// Project `transcript` into one-line rows. `speaker` is the conversation's
/// §3.3 display name — **who** the model turns are, since a speaker is an agent
/// and not a model id (bl-2335); `auto` is the durable knob pair; `folds` is the
/// caller's RAM override set (§5.3) — membership *flips* a row's auto-state, so
/// an empty set means "everything as configured".
/// The auto-state, flipped by an explicit override (the whole expansion rule).
/// A row that is **in flight** auto-expands whatever its class knob says: while
/// a step is happening it is the show, and completion returns it to its class
/// auto-state with no event to notice and nothing to store.
/// Is this row a step happening **right now** — the live streaming tail, or a
/// tool call no result has retired yet? Already said by the tone the
/// projection gave it, so in-flightness stays the query it always was.