Use this guide to collect reproducible diagnostics for intermittent TUI keyboard freezes (for example: input pauses for 30–60 seconds and then recovers).
Profiling is off by default.
npm run cli -- tui --perf
# or
wl tui --perfThis enables:
- performance timing metrics (expand/collapse, scroll, etc.)
- keypress diagnostic events
- event-loop lag detection
TUI_PROFILE=1 npm run cli -- tui
# or
TUI_PROFILE=1 wl tuiUseful when you want diagnostics without changing command arguments.
TUI_CHORD_DEBUG=1 TUI_LOG_VERBOSE=1 TUI_LOGFILE=./tui-debug.log npm run cli -- tui --perfThis records low-level chord activity to the file in TUI_LOGFILE.
Note: --perf / TUI_PROFILE=1 no longer imply verbose file logging by default. This avoids logging overhead on the keypress hot path while still collecting profiling artifacts.
Use this scenario to reproduce key-input stalls observed in WSL/Windows Terminal setups:
- Write debug logs to a slow mount (for example
/mnt/c/...in WSL). - Enable high-volume chord/debug logging.
- Hold navigation keys (
j,k, arrows) for 10–30 seconds.
Example:
TUI_CHORD_DEBUG=1 TUI_LOG_VERBOSE=1 TUI_LOGFILE=/mnt/c/Users/<you>/wl-tui-debug.log wl tui --perfExpected signal during a bad run:
.worklog/tui-profiling-*.jsonlcontains repeatedevent_loop_lagentries.keypress.handlerDurationMsrises sharply during lag windows.
Validated RCA from field traces (Tableau-Card-Engine repro logs):
- Long freeze class (~30s): main-thread stalls aligned with database refresh lock contention (
scheduleRefreshFromDatabaseandrenderListAndDetailblocked for ~31s). - Residual sluggish class (~1–2s repeated lag): frequent file-watch-triggered refreshes caused repeated full tree/detail re-renders even when the dataset did not change.
Mitigation implemented in this branch:
- TUI file logging now buffers and flushes asynchronously.
- Logging writes are bounded by an in-memory queue cap to prevent unbounded growth under sustained input.
- TUI mode now uses a shorter SQLite busy timeout to avoid multi-second UI stalls when the DB is contended.
- Watch-refresh path now skips expensive re-render work when the refreshed dataset fingerprint is unchanged (diagnostic event:
refresh_skipped_unchanged).
You can tune SQLite busy timeout explicitly:
WL_SQLITE_BUSY_TIMEOUT_MS=250 wl tui --perfWhen profiling is enabled, artifacts are written under your worklog directory (typically .worklog/):
.worklog/tui-performance.json— structured performance metrics.worklog/tui-profiling-<timestamp>-<pid>.jsonl— JSONL diagnostics (keypress events, event-loop lag events, startup/shutdown markers)
If TUI_LOG_VERBOSE=1 is also enabled:
./tui-prototype.logby default, orTUI_LOGFILE=<path>when provided
Use strace while reproducing the freeze:
strace -tt -f -o /tmp/wl-tui.strace wl tui --perfThen attach these to the work item:
.worklog/tui-performance.json.worklog/tui-profiling-*.jsonltui-debug.log(if enabled)/tmp/wl-tui.strace
asciinema rec /tmp/wl-tui-freeze.cast
wl tui --perf
# reproduce freeze, then exit and Ctrl-Devent_loop_lagrecords indicate the event loop was delayed beyondTUI_EVENT_LOOP_LAG_MS(default: 200ms).keypressevents show key metadata and whether chords consumed the key.- Long stretches without
keypressprocessing, or repeated lag spikes, are strong indicators of blocking work on the main thread.
You can tune lag sensitivity:
TUI_EVENT_LOOP_LAG_MS=100 wl tui --perf