newt-tui 0.8.0

Newt-Agent TUI surfaces (ratatui): code mode + pilot mode
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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
//! **One answer to "where is the cursor?" for every inline surface** (#1950).
//!
//! An inline viewport has to know which row it starts on, so ratatui asks the
//! terminal — `backend.get_cursor_position()`, which is a DSR query (`ESC[6n`)
//! whose reply arrives back on the *input* stream. Any other consumer of that
//! stream can take the reply first, and some terminals never send one. When
//! that happens crossterm returns
//! `"The cursor position could not be read within a normal duration"` after a
//! two-second timeout and `Terminal::with_options` fails — so the panel does
//! not open at all.
//!
//! That is what the operator hit on `/backends` (#1950).
//!
//! # The mechanism is NOT raw mode
//!
//! #1950 was filed against `RawModeGuard` (#1924) on the theory that setting
//! raw via `libc::tcsetattr` leaves crossterm's own raw-mode flag unset, so
//! `cursor::position()` takes its not-raw branch and mis-reads. The premise is
//! true — the flag really is unset — but it is **not** the cause, and it was
//! measured rather than argued:
//!
//! | raw mode taken by | competing reader | outcome |
//! |---|---|---|
//! | `RawModeGuard` (flag `false`) | none | opens, 14 ms |
//! | `crossterm::enable_raw_mode` (flag `true`) | none | opens, 17 ms |
//! | `RawModeGuard` (flag `false`) | one | **fails, 2000 ms** |
//! | `crossterm::enable_raw_mode` (flag `true`) | one | **fails, 2000 ms** |
//!
//! The pre-#1924 shape fails identically, so syncing the flag would fix
//! nothing. Reading crossterm 0.28 says why: *both* branches of `position()`
//! end in the same `read_position_raw()`; the not-raw branch only wraps it in
//! an `enable_raw_mode`/`disable_raw_mode` pair that is a no-op when the
//! terminal is already raw. Two other candidate differences were checked and
//! eliminated too — crossterm's `raw_terminal_attr` *is* `cfmakeraw`, and its
//! `tty_fd()` returns `STDIN_FILENO` whenever stdin is a tty, which is the
//! same descriptor `RawModeGuard` uses.
//!
//! # So this fixes the class, not the instance
//!
//! Whichever consumer wins the race — newt's own interrupt watcher, a
//! multiplexer that owns the outer pty, a terminal that simply does not answer
//! — the surface should still open. **Degrade, do not refuse.** A panel drawn
//! at a slightly wrong row beats a panel that will not appear.
//!
//! # Why here and not at four call sites
//!
//! `config_panel`, `rich_input`, and `interaction_view` each built the same
//! `Terminal::with_options(CrosstermBackend::new(stdout), Inline(h))`, and
//! `cockpit::presenter` calls `cursor::position()` directly. A rescue written
//! into each is four copies of one rule — the shape F0b (#1923) spent a slice
//! removing. The seam ratatui actually calls is the **backend**, so the rule
//! lives in one `Backend` implementation and every inline surface inherits it.

use std::io::{self, Write};

use ratatui::backend::{Backend, ClearType, CrosstermBackend, WindowSize};
use ratatui::buffer::Cell;
use ratatui::layout::{Position, Rect, Size};
use ratatui::{Terminal, TerminalOptions, Viewport};

/// Where an inline surface's bytes go.
///
/// **Two destinations, ONE terminal type.** A panel opened from the plain
/// prompt writes to `stdout`; a panel opened under the cockpit must NOT, because
/// the cockpit has `dup2`'d a pty slave onto fd 1 to capture stray output
/// (`cockpit::pty::PtyCapture`) — bytes written there are drained by the capture
/// and re-emitted as flattened transcript rows, which is exactly how
/// `/backends` came out as a single squashed border line. That panel writes to
/// a clone of the REAL terminal instead.
///
/// Expressed as one enum rather than a generic parameter on purpose: every
/// panel loop stays written against a single `Term`, so routing a panel to the
/// cockpit is a constructor change and not a rewrite of its loop.
pub(crate) enum PanelOut {
    Stdout(io::Stdout),
    /// A clone of the real terminal, handed over by the cockpit presenter.
    Tty(std::fs::File),
}

impl Write for PanelOut {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self {
            Self::Stdout(w) => w.write(buf),
            Self::Tty(w) => w.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match self {
            Self::Stdout(w) => w.flush(),
            Self::Tty(w) => w.flush(),
        }
    }
}

/// The terminal type every inline surface in this crate uses.
pub(crate) type InlineTerm = Terminal<AnchoredBackend<PanelOut>>;

/// Say it once per process, before anything paints.
///
/// Same idiom, and for the same reason, as the cbreak warning in
/// `with_live_spill_watch`: losing a terminal capability silently is how a
/// wrong-looking surface becomes undiagnosable. Once, because the operator's
/// report already showed a config warning printing three times per command,
/// and a fourth repeated line is noise rather than information.
fn warn_once(err: &io::Error) {
    static WARNED: std::sync::Once = std::sync::Once::new();
    WARNED.call_once(|| {
        eprintln!(
            "⚠ terminal did not report the cursor position ({err}) — inline \
             panels will be anchored at the bottom of the screen"
        );
    });
}

/// Where to draw when the terminal will not say where the cursor is.
///
/// **The assumption, stated because a silent one rots:** that the cursor is at
/// **column 0 of the last row** — where a shell prompt sits after output, and
/// where every one of these surfaces is opened from. If the cursor was really
/// higher up, ratatui's `compute_inline_size` appends its lines from here and
/// the panel is drawn at the bottom of the screen instead of inline at the
/// cursor: the content is right, the position is lower than ideal. If the
/// screen height is unknown too, `(0, 0)` is the only remaining answer and the
/// panel draws at the top.
fn anchor(size: Size) -> Position {
    Position {
        x: 0,
        y: size.height.saturating_sub(1),
    }
}

/// A `CrosstermBackend` that answers "where is the cursor?" even when the
/// terminal does not.
///
/// Every other method delegates untouched — this exists to change exactly one
/// answer, and a wrapper that quietly changed a second would be worse than the
/// four copies it replaces.
pub(crate) struct AnchoredBackend<W: Write> {
    inner: CrosstermBackend<W>,
    /// The rows this backend is allowed to paint (#1979).
    ///
    /// Held here so the terminal OWNS its lease: the rows are returned when
    /// the surface is dropped, in the right order, with no caller to forget.
    /// `None` is the query-only path — [`cursor_position_or_anchor`] asks
    /// where the cursor is and paints nothing, so it holds no rows.
    lease: Option<newt_core::tty::RegionLease>,
}

impl<W: Write> AnchoredBackend<W> {
    /// Query-only: answers "where is the cursor?" and never paints a viewport.
    ///
    /// **`#[cfg(unix)]` to match its only caller**, exactly as
    /// [`cursor_position_or_anchor`] below is and for the same stated reason.
    /// That caller is the cockpit presenter's, and the live cockpit is unix-only
    /// by construction (`openpty`/`dup2`/termios), so on Windows this function
    /// has nobody to serve and `-D warnings` correctly calls it dead.
    ///
    /// **This is not the lease-taking path, and Windows is not losing a
    /// viewport.** Inline surfaces reach [`Self::with_lease`] through
    /// [`inline_terminal`], which is ungated — `config_panel`, `rich_input`
    /// and `interaction_view` are `rich-tui`-gated only. What is absent on
    /// Windows is the *cockpit*, not the rescue and not the lease.
    ///
    /// An `#[allow(dead_code)]` would have been the smaller edit and the wrong
    /// one: it says "trust me" and stays silent forever, whereas the cfg names
    /// which caller justifies the function and becomes a compile error in the
    /// same commit that gives Windows a cockpit. The boundary should break when
    /// it drifts.
    #[cfg(unix)]
    pub(crate) fn new(writer: W) -> Self {
        Self::with_lease(writer, None)
    }

    fn with_lease(writer: W, lease: Option<newt_core::tty::RegionLease>) -> Self {
        Self {
            lease,
            inner: CrosstermBackend::new(writer),
        }
    }
}

impl<W: Write> Backend for AnchoredBackend<W> {
    /// **The one overridden answer.** A failure here is a terminal that did
    /// not reply, not a broken terminal: fall back and keep going.
    fn get_cursor_position(&mut self) -> io::Result<Position> {
        // #2644 round 2: this used to detach the query onto a helper thread
        // and time out `recv_timeout` around it — but dropping the receiver
        // does not cancel `crossterm::cursor::position()`. The leaked thread
        // kept consuming terminal input under crossterm's shared event-reader
        // mutex and could still be mid-`read_position_raw` (raw mode enabled,
        // termios saved) when the caller had already moved on and the cockpit
        // entered its own raw-mode guard — a live reader plus a termios owner
        // left behind (PR #2646 review). The actual defect was in crossterm's
        // retry loop, not in this call being synchronous; it is patched at
        // the source instead (`vendor/crossterm-0.28.1-patched/`, wired via
        // workspace `[patch.crates-io]`), so the call here is synchronous
        // again and crossterm's own raw-mode enable/disable cleanup runs
        // uninterrupted, exactly as ratatui's `CrosstermBackend` expects.
        match crossterm::cursor::position().map(|(x, y)| Position { x, y }) {
            Ok(position) => Ok(position),
            Err(err) => {
                warn_once(&err);
                // `size()` is an ioctl, not a query — it does not depend on
                // the terminal answering anything, so it is still trustworthy
                // in exactly the situation that got us here.
                // #1979/#1977: if this surface holds rows, THOSE rows are the
                // anchor. The bare bottom-of-screen answer is what put two
                // viewports on the same rows — the panel and the prompt each
                // asked "where do I go?" and got the same reply.
                //
                // When nothing collided the lease IS the bottom rows, so this
                // returns exactly what `anchor` did and today's panels keep
                // their position. It differs only when the mint shifted the
                // request, which is the case that was broken.
                if let Some(newt_core::tty::Region::Rows { top, .. }) =
                    self.lease.as_ref().map(newt_core::tty::RegionLease::region)
                {
                    return Ok(Position { x: 0, y: top });
                }
                Ok(anchor(self.inner.size().unwrap_or(Size {
                    width: 0,
                    height: 0,
                })))
            }
        }
    }

    fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
    where
        I: Iterator<Item = (u16, u16, &'a Cell)>,
    {
        self.inner.draw(content)
    }

    fn hide_cursor(&mut self) -> io::Result<()> {
        self.inner.hide_cursor()
    }

    fn show_cursor(&mut self) -> io::Result<()> {
        self.inner.show_cursor()
    }

    fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()> {
        self.inner.set_cursor_position(position)
    }

    fn clear(&mut self) -> io::Result<()> {
        self.inner.clear()
    }

    fn clear_region(&mut self, clear_type: ClearType) -> io::Result<()> {
        self.inner.clear_region(clear_type)
    }

    fn append_lines(&mut self, n: u16) -> io::Result<()> {
        self.inner.append_lines(n)
    }

    fn size(&self) -> io::Result<Size> {
        self.inner.size()
    }

    fn window_size(&mut self) -> io::Result<WindowSize> {
        self.inner.window_size()
    }

    fn flush(&mut self) -> io::Result<()> {
        // Disambiguated: `CrosstermBackend` implements both `Backend::flush`
        // and `Write::flush`, and this is the Backend one.
        Backend::flush(&mut self.inner)
    }
}

// `scroll_region_up`/`scroll_region_down` are ratatui's `scrolling-regions`
// feature, which this build does not enable; the trait's provided
// implementations stand. Adding them here would not compile.

impl<W: Write> Write for AnchoredBackend<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.inner.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Write::flush(&mut self.inner)
    }
}

/// **The ONE inline-viewport constructor, and it takes a lease** (#1979).
///
/// Every surface in this crate that wants `Viewport::Inline` comes through
/// here — F0b (#1923) collapsed four copies into this one — so requiring the
/// capability HERE requires it of all of them in a single edit. There is no
/// bare form to call: the height is read off the lease, because a height that
/// disagreed with the leased rows would be a viewport painting outside what it
/// owns, which is the whole defect (#1977).
///
/// The terminal owns the lease, so the rows are returned on drop with no
/// caller left to forget.
pub(crate) fn inline_terminal(lease: newt_core::tty::RegionLease) -> io::Result<InlineTerm> {
    let (top, height) = match lease.region() {
        newt_core::tty::Region::Rows { top, height } => (top, height),
        // A whole-screen holder is the alternate screen, not an inline strip.
        newt_core::tty::Region::WholeScreen => {
            return Err(io::Error::other(
                "an inline viewport cannot be built from a whole-screen lease",
            ))
        }
    };
    let placed = lease.cursor_return().is_some();
    let mut backend = AnchoredBackend::with_lease(PanelOut::Stdout(io::stdout()), Some(lease));
    let viewport = if placed {
        // The arbiter placed these rows under the transcript, handed them out
        // blank, and returns the cursor when the lease drops
        // (`Terminal::lease_below_cursor`): open exactly there. `Fixed`, not
        // `Inline`, so ratatui neither queries the cursor nor emits opening
        // newlines, the two moves whose answers this surface no longer owns.
        // The cockpit's panels have opened this way since #2574
        // (`cockpit_panel_terminal`), for the same reason.
        Viewport::Fixed(Rect::new(0, top, backend.size()?.width, height))
    } else {
        // A bottom-anchored lease (the prompt editor's, or the fallback for a
        // terminal that did not answer the arbiter's query): ratatui's own
        // placement. A lease a holder SHIFTED above the bottom rows: park the
        // cursor on its top row before ratatui looks at it. An inline
        // viewport opens at the CURSOR and emits its opening newlines from
        // there, so a cursor left anywhere else puts the viewport outside the
        // rows this surface leased, scrolling the holder below it. (Measured:
        // without this, a panel re-opened after a grow beside a holder on a
        // silent terminal ran its newlines from the old panel's last row and
        // scrolled the holder's rows away, `a_panel_beside_a_row_holder_
        // stays_open_at_its_granted_height`.) A bottom-anchored lease keeps
        // ratatui's placement, which scrolls the transcript up to make room,
        // where a park would paint over it.
        if top.saturating_add(height) < backend.size()?.height {
            backend.set_cursor_position(Position { x: 0, y: top })?;
        }
        Viewport::Inline(height)
    };
    Terminal::with_options(backend, TerminalOptions { viewport })
}

/// A panel drawn into rows the COCKPIT already reserved, on the real terminal.
///
/// Three differences from [`inline_terminal`], each of them the fix for a
/// symptom the operator saw:
///
/// - **`Viewport::Fixed`, not `Inline`.** The presenter says which rows this
///   panel owns, so nothing has to ask the terminal where the cursor is. That
///   removes the `ESC[6n` round trip entirely — under the cockpit it could
///   never be answered (the presenter's reader owns stdin), which is where
///   `⚠ terminal did not report the cursor position` came from.
/// - **The real tty, not fd 1.** See [`PanelOut`].
/// - **No lease of its own.** The rows belong to the presenter's modal
///   reservation, which outlives this terminal and is released by the window
///   the caller holds — one owner for the rows, not two.
pub(crate) fn cockpit_panel_terminal(
    out: std::fs::File,
    area: ratatui::layout::Rect,
) -> io::Result<InlineTerm> {
    Terminal::with_options(
        AnchoredBackend::with_lease(PanelOut::Tty(out), None),
        TerminalOptions {
            viewport: Viewport::Fixed(area),
        },
    )
}

/// Lease the bottom `height` rows, which is where every inline surface here
/// sits, and say what should happen if somebody already holds them.
///
/// The screen measurement stays with the caller-facing helper rather than in
/// the arbiter: #1979's non-goal is a layout engine, and the arbiter's
/// vocabulary is a row range plus a policy.
pub(crate) fn lease_bottom_rows(
    height: u16,
    policy: newt_core::tty::OnCollision,
) -> io::Result<newt_core::tty::RegionLease> {
    let screen =
        ratatui::backend::Backend::size(&CrosstermBackend::new(io::stdout())).unwrap_or(Size {
            width: 80,
            height: 24,
        });
    // A zoomed modal asks for "all of it" (`modal_size::FILL`); the lease is
    // what the screen actually has.
    let height = height.min(screen.height);
    let top = screen.height.saturating_sub(height);
    newt_core::tty::Terminal::lease_region(newt_core::tty::Region::Rows { top, height }, policy)
        .ok_or_else(|| io::Error::other("another surface already owns these rows"))
}

/// Lease `height` rows under the transcript, where a frame belongs, or, when
/// the terminal will not say where that is, the bottom rows as before.
///
/// The first is `Terminal::lease_below_cursor`: the rows come blank, the
/// cursor goes back to the transcript's end when the lease drops, and
/// [`inline_terminal`] opens them as a `Fixed` viewport with no cursor query
/// of its own. The second is [`lease_bottom_rows`] and ratatui's `Inline`
/// placement, which a surface reaches only when the terminal did not answer
/// or could not safely be asked: it keeps the placement it had before the
/// arbiter owned the row, and never guesses one.
pub(crate) fn lease_below_transcript(
    height: u16,
    policy: newt_core::tty::OnCollision,
) -> io::Result<newt_core::tty::RegionLease> {
    match newt_core::tty::Terminal::lease_below_cursor(
        height,
        policy,
        newt_core::tty::Sink::Stdout,
    )? {
        Some(lease) => Ok(lease),
        None => lease_bottom_rows(height, policy),
    }
}

/// The cursor position for a caller that is not building a ratatui terminal —
/// `cockpit::presenter`, which queries it directly to place its block.
///
/// Same rule, same anchor, same one-shot warning: a cockpit that refuses to
/// open because the terminal stayed quiet is the same defect as a panel that
/// does, and it must not be a second implementation of the answer.
///
/// **`#[cfg(unix)]` to match its only caller**, not to silence a lint. The
/// live cockpit — the fd 1/2 capture and this presenter — is unix-only by
/// construction (`openpty`/`dup2`/termios); Windows keeps the classic
/// per-turn surface until a ConPTY backend lands (#1746). A
/// `#[allow(dead_code)]` here would say "trust me"; the cfg says which
/// caller, and goes stale in the same commit that gives Windows a cockpit.
///
/// **Windows panels are NOT left unrescued by this.** They reach the same
/// fallback through [`inline_terminal`], which is not gated: `config_panel`,
/// `rich_input` and `interaction_view` are `rich-tui`-gated only, so
/// `AnchoredBackend::get_cursor_position` runs there exactly as it does here.
/// What is absent on Windows is the *cockpit*, not the rescue.
#[cfg(unix)]
pub(crate) fn cursor_position_or_anchor() -> Position {
    let mut backend = AnchoredBackend::new(PanelOut::Stdout(io::stdout()));
    // `get_cursor_position` above already rescues; this is the last resort if
    // even the rescue's own `size()` path errors, and it is the only remaining
    // answer.
    backend
        .get_cursor_position()
        .unwrap_or(Position { x: 0, y: 0 })
}

#[cfg(test)]
mod region_lease_door {
    /// Every file that may construct an inline viewport. **Declared, not
    /// discovered** (F0b): a scan that trusted a glob would silently start
    /// permitting a new file the day someone added one.
    const DESTINATIONS: &[&str] = &["inline_viewport.rs"];

    /// The CALL FORM, never the bare name (#1924). Seven files mention
    /// `Viewport::Inline` in prose — including the doc comment that explains
    /// this very rule — and a name-shaped needle would count all of them, so
    /// the guard would pass by matching its own explanation.
    const DOOR: &str = "Viewport::Inline(";
    const OPTIONS: &str = "Terminal::with_options(";

    fn sources() -> Vec<(String, String)> {
        let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
        let mut out = Vec::new();
        let mut stack = vec![dir];
        while let Some(d) = stack.pop() {
            for entry in std::fs::read_dir(&d).expect("newt-tui/src is readable") {
                let path = entry.expect("a readable entry").path();
                if path.is_dir() {
                    stack.push(path);
                } else if path.extension().is_some_and(|e| e == "rs") {
                    let name = path
                        .file_name()
                        .expect("a file name")
                        .to_string_lossy()
                        .into_owned();
                    out.push((name, std::fs::read_to_string(&path).expect("readable")));
                }
            }
        }
        out
    }

    /// Region claims that still hold NO lease.
    ///
    /// A ratchet, not a permission list: the count may only go DOWN, and
    /// #1980 brought it to **zero**. The cockpit presenter was the last
    /// entry — two `Viewport::Fixed` regions built from its own `self.top`
    /// arithmetic — and it now holds a session-scoped lease that it
    /// `relocate`s on every move.
    const UNLEASED_REGION_CLAIMS: &[(&str, usize)] = &[];

    /// **The door is one door, and it takes a lease.**
    ///
    /// `inline_terminal` is the only inline-viewport constructor, and its
    /// signature requires a `RegionLease` — so there is no bare form to call
    /// and no second place to add one. This is the `PromptWindow` seal pattern
    /// at region scale: the capability is the way in.
    #[test]
    fn the_inline_viewport_door_exists_in_exactly_one_declared_place() {
        let files = sources();
        // POSITIVE READ ASSERTION FIRST. An absence-check that silently read
        // nothing passes forever, and gets MORE likely to pass as the scan
        // breaks.
        assert!(
            files.len() > 10,
            "the scan found {} files, so it is not reading the crate",
            files.len()
        );
        assert!(
            files.iter().any(|(n, _)| n == "inline_viewport.rs"),
            "the scan never reached the file that holds the door"
        );

        for (name, body) in &files {
            if body.contains(DOOR) {
                assert!(
                    DESTINATIONS.contains(&name.as_str()),
                    "`{DOOR}` appears in {name}, which is not a declared \
                     destination. An inline viewport is a claim on rows: mint a \
                     `RegionLease` and go through `inline_terminal`."
                );
            }
        }
    }

    /// The wider category: every OTHER way a surface claims rows must hold a
    /// lease for them.
    ///
    /// Separate from the door above because the door's baseline was zero from
    /// birth, while this one started at two (#1979) and reaches zero here. It
    /// asks for a HOLDER rather than counting call sites, because the claim is
    /// not the defect — claiming rows nobody arbitrates is.
    #[test]
    fn every_region_claim_holds_a_lease() {
        const HOLDS: &str = "RegionLease";
        for (name, body) in &sources() {
            if name == "inline_viewport.rs" {
                continue; // the door itself, and this test's own needles
            }
            if !body.contains(OPTIONS) {
                continue;
            }
            let allowed = UNLEASED_REGION_CLAIMS
                .iter()
                .find(|(f, _)| *f == name)
                .map_or(0, |(_, n)| *n);
            assert!(
                body.contains(HOLDS) || allowed > 0,
                "{name} builds a viewport but holds no `RegionLease`. Rows a \
                 surface claims without telling the arbiter are rows another \
                 surface can be handed (#1977)."
            );
        }
    }

    /// **Every whole-screen writer holds the screen (#1980).**
    ///
    /// The collision proof next door shows the ARBITER refuses under a
    /// whole-screen lease. It does not show that the pager and the splash
    /// actually take one — it mints the lease itself. This does: entering the
    /// alternate screen IS claiming every row, so a file that enters it must
    /// hold a `RegionLease`.
    ///
    /// Needle on the call form, as ever (#1924): prose about the alternate
    /// screen is everywhere in this crate.
    #[test]
    fn every_alternate_screen_entry_holds_a_region_lease() {
        const ENTER: &str = "EnterAlternateScreen)";
        const HOLDS: &str = "_region: newt_core::tty::RegionLease";
        let files = sources();
        assert!(
            files.len() > 10,
            "the scan found {} files, so it is not reading the crate",
            files.len()
        );
        let mut entrants = 0;
        for (name, body) in &files {
            if !body.contains(ENTER) {
                continue;
            }
            entrants += 1;
            assert!(
                body.contains(HOLDS),
                "{name} enters the alternate screen but holds no `RegionLease`. \
                 Taking every row without telling the arbiter is what let an \
                 inline surface open underneath the pager (#1980)."
            );
        }
        // POSITIVE READ ASSERTION: without this, a scan that matched nothing —
        // a renamed import, a moved file — would report every entrant leased.
        assert_eq!(
            entrants, 2,
            "expected the pager and the splash to be the two alternate-screen \
             entrants; found {entrants}. A new one must hold the screen, and a \
             removed one must lower this number."
        );
    }

    /// Cursor-relative clear-to-screen-end holdouts, even when they hold leases.
    /// Live spill paints ordinary frames on leased absolute rows, but width
    /// reflow still uses MoveUp plus Clear(FromCursorDown); the stale lease
    /// does not bound that clear. Keep that limitation visible in the ratchet.
    const CURSOR_RELATIVE_CLAIMS: &[(&str, &str)] = &[
        (
            "lean_input.rs",
            "rows_above_cursor on the plain-scroller path",
        ),
        (
            "live_spill.rs",
            "width-reflow cleanup rewinds and clears from the cursor down",
        ),
    ];

    fn cursor_relative_claim(body: &str) -> bool {
        body.contains("Clear(ClearType::FromCursorDown)")
            && (body.contains(concat!("Move", "Up("))
                || !(body.contains("RegionLease") || body.contains("lease_bottom_rows")))
    }

    #[test]
    fn a_lease_does_not_hide_cursor_relative_reflow_cleanup() {
        assert!(cursor_relative_claim(concat!(
            "RegionLease; Move",
            "Up(3); Clear(ClearType::FromCursorDown)"
        )));
        assert!(!cursor_relative_claim(
            "RegionLease; MoveTo(0, top); Clear(ClearType::FromCursorDown)"
        ));
    }

    /// The cursor-relative holdouts are exactly the declared ones.
    ///
    /// Not a permission list: a NEW writer that paints from the cursor down
    /// is a new unarbitrated region, and it fails here until someone either
    /// leases it or argues it onto this list. The list started at two (#1979)
    /// and remains at two until live spill no longer clears cursor-relative.
    #[test]
    fn cursor_relative_region_painters_are_the_declared_holdouts() {
        let files = sources();
        assert!(
            files.len() > 10,
            "the scan found {} files, so it is not reading the crate",
            files.len()
        );
        let mut found: Vec<&str> = Vec::new();
        for (name, body) in &files {
            if !cursor_relative_claim(body) {
                continue;
            }
            found.push(name.as_str());
        }
        found.sort_unstable();
        let mut declared: Vec<&str> = CURSOR_RELATIVE_CLAIMS.iter().map(|(f, _)| *f).collect();
        declared.sort_unstable();
        assert_eq!(
            found, declared,
            "the cursor-relative holdouts changed. A new one must lease its \
             rows or be declared here with a reason; a migrated one must be \
             removed from the list."
        );
    }

    /// Probe one: the needle WOULD fire on a new site. Without this the test
    /// above passes equally well when the needle matches nothing at all.
    #[test]
    fn the_door_needle_catches_a_bare_construction() {
        let smuggled = "let t = Terminal::with_options(b, TerminalOptions { \
                        viewport: Viewport::Inline(6) });";
        assert!(smuggled.contains(DOOR), "the needle misses a real call");
        assert!(
            smuggled.contains(OPTIONS),
            "the options needle misses a real call"
        );
    }

    /// Probe two: it does NOT fire on prose. Six files discuss
    /// `Viewport::Inline` without constructing one, and a name-shaped needle
    /// would have flagged every one of them — which is how a guard gets
    /// weakened until it means nothing.
    #[test]
    fn the_door_needle_ignores_prose_about_the_rule() {
        let prose = "//! opens this transient ratatui `Viewport::Inline` overlay: one surface";
        assert!(
            !prose.contains(DOOR),
            "the needle matches prose, so the guard would flag documentation"
        );
    }
}

#[cfg(test)]
mod screen_lease_collision {
    use newt_core::tty::{OnCollision, Region, Terminal};

    /// **#1980's observable consequence.** The pager and the splash now hold
    /// the whole screen, so an inline surface that asks for the bottom rows
    /// while one is up is refused and degrades (#1952) instead of painting
    /// through it. Before the sweep the arbiter did not know the screen was
    /// taken and handed the rows out.
    #[serial_test::serial(tty_arbiter)]
    #[test]
    fn an_inline_surface_is_refused_while_the_whole_screen_is_held() {
        let screen = Terminal::lease_region(Region::WholeScreen, OnCollision::SuspendHolder)
            .expect("the alternate screen is always grantable");
        assert!(
            super::lease_bottom_rows(6, OnCollision::Refuse).is_err(),
            "an inline surface was granted rows the pager owns"
        );
        // Shifting cannot rescue it either: there is nowhere above a holder
        // that occupies every row.
        assert!(
            super::lease_bottom_rows(6, OnCollision::Shift).is_err(),
            "a shift found free rows under a whole-screen holder"
        );

        // TWIN: the refusal is about the SCREEN being held, not about
        // refusing always. Release it and the same call succeeds.
        drop(screen);
        let rows = super::lease_bottom_rows(6, OnCollision::Refuse)
            .expect("with the screen free, the inline surface opens");
        assert!(matches!(rows.region(), Region::Rows { height: 6, .. }));
    }
}