vipirc 0.5.0 refresh and pre-poll resize review

Scope: source inspection and narrowly targeted local diagnostics. Original
release binary 793e50d85c315d38833aa6cf86b39858e3f2a237630e65c6d9af46faeeecb88f
was not modified. The parent applied the eventual event-loop correction.

1. clearok propagation is not the demonstrated defect

The installed libncursesw6/libtinfo6 package is 6.4+20240113-1ubuntu2.
/lib/x86_64-linux-gnu/libncursesw.so.6 SHA256:
a7d7897c415473e5a4e393fe1a6faf5828c73e06ed2eb6d11648a2cef4ea3552

Actual library disassembly, retained in
release-050-refresh-library-disassembly.txt, establishes:
- clearok stores its Boolean at window offset 0x19 (address 0xc349).
- wnoutrefresh tests that same offset, clears it on the source window, and
  sets it on the virtual screen (addresses 0x1d848-0x1d858).
- wrefresh calls that wnoutrefresh, then doupdate_sp.

Thus the application's inner wnoutrefresh stages followed by its final
wnoutrefresh+doupdate do propagate clearok on the installed implementation.
Changing the final call to wrefresh would not address the proven defect.
This inspection does not establish every other curses implementation's
internal behavior.

Official documentation consulted:
https://invisible-island.net/ncurses/man/curs_outopts.3x.html
https://invisible-island.net/ncurses/man/curs_refresh.3x.html
https://invisible-island.net/ncurses/man/resizeterm.3x.html

2. A different, real idle-resize race was reproduced

The original ui_run consumed curses input only when a previous batch was
pending, stdin reported POLLIN, or poll returned an error/interruption.
A SIGWINCH handled immediately before poll can leave a curses-internal
resize pending while poll later returns 0. A disconnected idle session then
does not call getch to consume that pending event.

The temporary LD_PRELOAD diagnostic covered both poll and glibc's fortified
__poll_chk entry. It performed a real 24x80 -> 15x50 TIOCSWINSZ change on the
controlling PTY before the main 1000 ms poll. It temporarily blocked SIGWINCH
around ioctl and then restored the mask: the signal was pending while
blocked and no longer pending before real poll began. No keyboard or
network event occurred during the observation.

Original binary: real poll returned 0 with stdin_revents 0; no terminal bytes
were emitted over 3.2 s. A later single key caused the correct resized screen
and preserved draft to appear. See release-050-prepoll-probe.json.

Fixed binary SHA256:
e989dac78ae80b1c559d37f663ddd4b2dbbfb68d8db9ba6823395329797c5b59
The parent changed main-loop curses input to nonblocking and retained the
bounded 512-event drain after every poll iteration. The same probe produced
a complete redraw without input in 977.558 ms, within the idle poll interval.
See release-050-prepoll-fixed-probe.json.

3. Permanent regression and limits

tests/test_controls.py now compiles tests/prepoll_resize.c into a temporary
Linux-only interposer. It checks actual geometry, pre-poll signal delivery,
no-keyboard redraw, exact draft and visible caret, bounded poll counts/CPU,
normal exit and restored terminal settings. Existing portable resize tests
remain separate. Dynamic ASan runtimes are kept first in the child's preload
list; sanitizer link-order checks are not disabled.

The same permanent test failed the original executable at the expected idle
redraw assertion and passed the corrected final executable. Commands,
source/binary hashes and both raw logs are retained in
release-050-prepoll-regression.json.

This deterministic race is a confirmed production defect and the targeted
test confirms its correction. It does not prove that this was the cause of
the earlier rare long-soak failure involving a discarded screen model and a
same-size signal. That failed long run remains failed evidence; the revised
full soak and final sanitizer gates must complete on the corrected source.
