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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
//! A shared RAII guard that serializes tests touching the **process-global
//! operator settings** — cognition, tenacity, initiative, and the env vars the psyche /
//! backend-routing paths read — and restores them on drop.
//!
//! These settings are process-wide (`set_cli_cognition` / `set_cli_tenacity` /
//! `set_initiative_config` / `set_active_model_family` / `NEWT_PROVIDER` / …), so
//! tests in *different modules* that mutate them will interleave under the test
//! runner's threads, and manual end-of-test restoration does not survive a panic,
//! an early return, or an assertion failure. One shared lock + a Drop-restored
//! snapshot fixes both: acquire the guard at the top of any test that reads or
//! writes these globals.
//!
//! ```ignore
//! let _g = newt_core::test_guard::GlobalSettingsGuard::acquire();
//! // …mutate cognition / tenacity / config / family / NEWT_* freely; restored…
//! ```
//!
//! Exposed (not `#[cfg(test)]`) so tests in dependent crates (`newt-tui`) share
//! the SAME lock — a module-local mutex cannot serialize tests in other crates.
//!
//! ## The lock lives in [`crate::process_env`] (#1850)
//!
//! This guard used to own a private `Mutex`, and `newt-tui` owned a *second*,
//! independent `RwLock` over the same variables. Two locks over one process
//! environment serialize nothing: a test holding either one raced every test
//! holding the other, which is what made `cargo test -p newt-tui --lib
//! --all-features` fail ~30% of runs with whole modules going down together.
//! Both now delegate to the single reentrant lock in [`crate::process_env`],
//! which the production writers take too.
//!
//! ## What the snapshot covers, and why (audited 2026-07-31)
//!
//! The guard must snapshot **exactly** the mutable state that can change what
//! `effective_tenacity()` / `effective_initiative()` / `effective_cognition()`
//! return between tests. Rather than reach into each global piecemeal, it
//! composes the crate-owned runtime snapshots, which together cover every
//! resolution global:
//!
//! - [`cognition::CognitionRuntimeSnapshot`]: `CLI_COGNITION`, `PERSONA_COGNITION`
//! (the only two globals read by `effective_cognition`).
//! - [`tenacity::TenacityRuntimeSnapshot`]: `CLI_TENACITY` (the only input to
//! `effective_tenacity`) and the two round-cap globals.
//! - [`initiative::InitiativeRuntimeSnapshot`]: `CLI_INITIATIVE`,
//! `PERSONA_INITIATIVE`, **`INITIATIVE_CONFIG`**, **`ACTIVE_FAMILY`** (all four
//! read by `effective_initiative`). The last two were the gap the old
//! piecemeal guard missed: `Config::publish_runtime_settings` installs the
//! config and the `solve` model-selection path installs the active family,
//! both process-wide, so a test exercising either leaked a per-family default
//! into a sibling test.
//! - [`crate::runtime::PreferenceRuntimeSnapshot`] (#1668): the posture-ACTION
//! accumulator and the recorded CLI posture axes. Neither feeds
//! `effective_*`, but both are process-global operator state written by the
//! same commands: an action marked by one test and never drained would be
//! attributed to the NEXT test's conversation, and a recorded CLI axis would
//! silently suppress another test's pin apply.
//! - [`crate::posture::ActivePosture`]: the resolved permission clamp and
//! guidance shared by `/posture`, settings, and accepted turns. This is
//! distinct from the preference-action accumulator above.
//!
//! Plus the env vars below, which are *upstream* (model / backend selection →
//! `ACTIVE_FAMILY`) or *downstream* (cognition wire emission) of the resolutions
//! — not read inside them, but mutated by backend / psyche / crew routing tests.
//! (There is no `NEWT_TENACITY` / `NEWT_INITIATIVE` / `NEWT_COGNITION` env var —
//! the dials are only ever sourced from CLI flags into the globals above.)
//! `CLI_BACKEND_OVERRIDE` (config.rs) is on the backend axis, not read by either
//! resolution fn, so it is intentionally out of scope here.
use crateCognitionRuntimeSnapshot;
use crateInitiativeRuntimeSnapshot;
use crateEnvGuard;
use cratePreferenceRuntimeSnapshot;
use crateTenacityRuntimeSnapshot;
/// The env vars the psyche + backend-routing paths read (and tests mutate).
/// `NEWT_OPENAI_API` gates the cognition wire scope, so it belongs here too.
const ENV_KEYS: & = &;
/// How long a test may wait on an event before the test is declared hung.
///
/// This is a HANG GUARD, not a budget, and the distinction is the whole rule
/// (the operator's, 2026-10-01: wall-clock decides nothing diagnostic). A test
/// completes when the event it awaits arrives — a oneshot, a channel, a socket
/// closing — never when a clock says so. The guard exists so a broken arm that
/// never produces its event fails instead of wedging the suite, and it is set
/// where no machine, however loaded, reaches it: measured on 2026-10-01, a
/// 32-thread nextest run beside a build stretched one-second tests past a
/// minute and broke every 30 s "budget" in the unit tier.
///
/// Never combine it with `tokio::time::pause()` while the awaited event comes
/// from another OS thread or a socket: a paused clock auto-advances when the
/// runtime idles and would fire the guard at once.
pub const HANG_GUARD: Duration = from_secs;
/// Await `fut`, panicking (naming `what`) if it is still pending after
/// [`HANG_GUARD`]. The assertion is the awaited event; this only names a hang.
///
/// `fut` is boxed here, synchronously, before any future of this function's
/// own exists: the guarded future is often a whole agentic turn, and holding
/// one inline in a wrapper's state overflowed a test thread's 2 MiB stack
/// (`ollama_completed_call_survives_cancelled_sibling`, 2026-10-01).
/// The blocking twin of [`hang_guarded`] for a `std::sync::mpsc` receiver: the
/// sent value is the event, and only a hang is named.
/// A kernel session config for the unit tier, with the navigation elapsed-time
/// budget out of reach.
///
/// The kernel charges REAL elapsed time — its own `Instant` around every
/// catalog, projection and re-read, plus the harness's auxiliary timers —
/// against `max_elapsed_ms`, 30 s by default, and refuses navigation past it.
/// That budget bounds a slow auxiliary model in production; in a unit test the
/// auxiliary is an instant closure and the elapsed time is the loaded test
/// box. Measured on 2026-10-01 under a 32-thread nextest run beside a build:
/// five `smart_harness` navigation tests failed at 36–100 s with the budget
/// error, none of them about the budget. The budget's own behaviour is tested
/// in agent-harness against its injected clock, where it belongs.
/// Exclusive access to the process-global operator settings for the duration of a
/// test. Snapshots cognition + tenacity + initiative + the relevant env on `acquire`, restores
/// them on `drop` — even through a panic or assertion failure.