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
//! yog's converging UI state (DESIGN §4.1, §15 Y8) — the four attention `seen`
//! watermarks, `pinned`, `identity_last_used`, `ceiling`, `prices`, and the
//! pane's own `panels` / `collapsed` / knobs ([`knobs`]: the §11
//! transcript-density automatics, the zoom, the §6 escalation).
//!
//! **It is two documents, split on what the fact is about** (REMOTE §7,
//! bl-8bbc). `ui.json` holds facts about the **world** — an acknowledgement,
//! a pin, a spend ceiling — and every seat shares it, because attention
//! answered on the phone must clear on the desktop (I0). A **pane of glass**
//! fact — how wide a panel was dragged, what is collapsed, how big the text is
//! — belongs to the client whose glass it is, and lives in that client's own
//! document under [`registry`](crate::registry). Both are read through one
//! [`UiState`], so which file owns a key is stated exactly once, in the
//! accessor for that key, and no caller knows there are two.
//!
//! **Single source of truth:** each document is one [`serde_json::Value`]
//! object (`root`); every known field is a *query* over that map and every
//! unknown key round-trips for free — no parallel typed struct plus extra-map
//! to drift (the "one struct, flattened extra" discipline without a `serde`
//! derive dependency: `serde_json` only).
//!
//! Convergence (§4.1, I5) is last-writer-wins whole-file: forgiving load
//! (missing/corrupt ⇒ default doc, never an error), **write-through** atomic
//! writes (temp dotfile + `rename`, I3), echo suppression by content hash
//! ([`UiState::is_echo`]), and wholesale [`UiState::adopt`] otherwise.
//!
//! **No write is ever in flight.** Every mutator lands on disk before it
//! returns, so the document has no RAM window to lose — not to a SIGTERM
//! (`pkill`, what `make ux` does every iteration), not to a SIGKILL, not to a
//! crash. This dissolves the shutdown-hook problem instead of handling one
//! signal's worth of it (bl-b54e): there is no exit path to flush on, graceful
//! or otherwise. The coalescing a debounce used to buy is bought instead by
//! the same content hash that suppresses echoes — a mutation that does not
//! change the bytes writes nothing at all, so re-acknowledging an already-seen
//! agent is free and a held arrow key writes only on the steps that change
//! something.
/// The §3.5 spend ceiling — `ui.json`'s `ceiling` number (§4.1).
/// The crate's one injected time seam and its one calendar routine — split off
/// at §12's budget and re-exported here, so `ui_state::Clock` and
/// `ui_state::iso8601_extended` stay the one address they always were.
/// One JSON document's file mechanics — forgiving load, echo hash, atomic
/// write-through — spent twice since the REMOTE §7 split (bl-8bbc).
/// The §11 resizable panel sizes — `ui.json`'s `panels` object (§4.1).
/// The §3.6 workspace prune — a deleted workspace's keys leave the document.
pub use format_iso8601;
pub use ;
pub use SeenKind;
use ;
pub use Panel;
use ;
use PathBuf;
/// The two §11 transcript auto-expand knobs' `ui.json` keys (§4.1).
const EXPAND_RESPONSES: &str = "transcript_expand_responses";
const EXPAND_OTHERS: &str = "transcript_expand_others";
/// Stable content hash of file bytes — the echo-suppression identity (§4.1).
/// Startup focus (§4.1, §6): first attention-bearing workspace in the caller's
/// derived roster order, else the first, else none. Pure over ids.
/// The live UI-state handle: **two** documents (REMOTE §7, bl-8bbc), read and
/// written through one interface.
///
/// - `world` is `ui.json` — the operator's facts about the world, shared by
/// every seat as they always were. Attention answered on the phone must clear
/// on the desktop; that is I0's whole point.
/// - `pane` is that seat's client's own document — the facts about a pane of
/// glass, held server-side so a client that is stateless (REMOTE §6) still
/// finds its panel sizes, and so any two seats of one client converge.
///
/// The split is invisible to every caller: which document owns a key is a
/// property of the key, stated once in the accessor that reads it, so nothing
/// outside this module knows there are two files.