# Upgrade Guide — vNEXT

<!-- assembled-by: assemble-next-md -->
<!-- bump: patch -->

## What Changed

New `src/core/paneText.ts` (trimTrailingBlankRows + meaningfulTail, PromptGate's exact semantics); PromptGate imports the shared helper (zero behavior change, its full suite passes); SessionManager gains `captureMeaningfulTail` and migrates its two n=5 idle/age call sites. Generalizes #818 per the cycle-2 differential finding (task #77).

## What to Tell Your User

Sessions idling in tall terminal windows are now detected as idle correctly. Previously a tall pane's trailing blank rows could blind the small idle checks, so genuinely-idle sessions were counted as "active" forever — quietly delaying updates and restarts that wait for sessions to go idle.

## Summary of New Capabilities

- `SessionManager.captureMeaningfulTail(session, n)` — blank-fill-immune small-tail capture (wider physical window, trailing blanks trimmed, last n meaningful rows); the over-age activity gate and idle-at-prompt check now use it.
- `core/paneText.ts` — the shared trim/tail primitives, extracted from PR #818's PromptGate fix so detector semantics can never drift apart.
- The process-level safety net (`hasActiveProcesses`) is unchanged — a working session still cannot be mistaken for idle.

## Evidence

Reproduced in test: a 50-row pane with the idle prompt at top and 45 blank rows below — the n=5 physical capture is pure blank (read as ACTIVE forever, the #20/#47 inflated-blocker shape), while `captureMeaningfulTail(.., 5)` returns the prompt row and the session correctly reads idle. Pinned by `tests/unit/paneText.test.ts` (the bug shape, boundary, all-blank, interior-blank preservation, and the SessionManager windowing integration with a stubbed transport); PromptGate's 33-test suite including #818's both-pane-shape regressions passes unchanged against the shared helper.
