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
213
214
215
216
217
//! Watch registry + repaint bridge (DESIGN §7.2, §15 Y6).
//!
//! Three pieces wire the built-but-unwired [`fs_watcher`](crate::fs_watcher)
//! to a live-re-rendering UI:
//!
//! - [`WatchSet`] owns one [`Watcher`] per `(root, RootKind)` and
//! [`reconcile`](WatchSet::reconcile)s a *desired* root list against the live
//! one — dropping watchers no longer wanted, creating missing ones, and
//! leaving surviving watchers (and their armed inotify state) untouched. A
//! construction failure is normal (a missing root is absent, not an error):
//! it is skipped, never poisoning the set, and retried on the next reconcile
//! (the live set is the single source of truth — "absent" is `desired`
//! minus `live`, computed, never stored).
//! - [`DirtySet`](crate::state::DirtySet) is the announcement hand-off: a
//! mutex-guarded map of dirty root → [`Mark`] the bridge fills and the §7.2
//! derivation worker drains.
//! - [`Bridge`] is the ingest thread. DESIGN §7.2 describes it "blocking on the
//! aggregated notify channels"; the existing [`Watcher`] is **pull-based**
//! ([`Watcher::tick`] drains coalesced changes). Rather than grow the watcher
//! a channel-exposing surface, the smallest faithful mechanism is a thread
//! that *polls* every live watcher's `tick()` on a short interval and parks
//! between polls ([`BRIDGE_POLL`]) — the pull API's equivalent of blocking on
//! the channels.
//!
//! **Ingest stays its own thread, and that is deliberate** (bl-ee0a). The
//! derivation moved off the frame onto [`Worker`](crate::app::Worker), and it
//! would have been easy to let that one thread drain the watchers too. It must
//! not: an *announcement* and a *derivation* are the two halves §7.2's drift
//! instrumentation compares (a change with no announcement is a dropped event),
//! and folding them into one thread makes the comparison unobservable — nothing
//! could ever exercise "disk moved and nothing said so". Two threads, one
//! question each. Neither thread wakes anything: **there is no face in this
//! process to wake** (bl-7942). A seat is on the far side of the wire and asks
//! on its own cadence (`wire::ASK_PERIOD`), so a published snapshot is simply
//! the next thing a gesture reads.
//!
//! Correctness never rides on this thread — the sweeps are the floor ("watches
//! are latency, polls are correctness", I4).
use ;
use ;
use Arc;
use ;
use JoinHandle;
use Duration;
use crate;
use crate;
/// Bridge poll cadence: how often the ingest thread drains the watchers. Short
/// enough that a disk change reaches the worker's next pass; the sweeps are the
/// correctness backstop (§7.2), so this is a latency knob only, deliberately not
/// clock-injected (it is a real thread sleep, not a time-gated decision under
/// test).
const BRIDGE_POLL: Duration = from_millis;
/// **Why** a root is dirty — the provenance a mark carries from whatever marked
/// it to the re-derivation that consumes it (DESIGN §7.2 instrumentation).
///
/// This is the whole instrumentation mechanism: a re-derivation that changes a
/// snapshot is *evidence* only in the light of what claimed the root had
/// changed. Under [`Watch`](Mark::Watch) it is the watcher working; under
/// [`Poll`](Mark::Poll) it is the liveness probe, for which no filesystem event
/// exists at all; under [`Sweep`](Mark::Sweep) **nobody announced it**, and that
/// is a dropped event, measured at the moment it costs something.
///
/// The variants are ordered weakest-explanation-first and merged with `max`, so
/// two marks on one root in one window keep the strongest explanation and a
/// blanket sweep mark can never mask a real announcement.
/// The provenance a tick's worth of changes carries: [`Mark::Desync`] if the
/// backend announced a loss, else [`Mark::Watch`]. Pure over the changes so the
/// classification is provable without forcing a kernel into overflow.
/// One [`Watcher`] per `(root, RootKind)` (DESIGN §7.1). The live map is the
/// only state; a desired root that fails to arm is simply not present and is
/// retried on the next [`reconcile`](Self::reconcile).
/// The ingest thread (DESIGN §7.2). Owns its join handle and a stop flag;
/// [`Drop`] signals stop, unparks, and joins for a clean shutdown.
/// One bridge iteration: drain the watchset into the dirty hand-off. Returns
/// whether anything became dirty, so both arms are unit-tested without the
/// thread.