Type: Bug (hardening follow-up)
Part of #2654. Five-agent review of merged #2711 (full findings on that PR); the decode/apply layer was already hardened in #2714. This issue covers the surviving scroll/pin surface.
Implemented in #3391.
What
The TUI's local transcript scroll and pin-intent reporting work on the happy path, but the behavior is untested at the Model.Update level where it actually happens, and three edge paths leave a wrong-or-stuck view (or a desynced BEAM follow state) with no signal.
Why
The pin flag drives BEAM-side auto-follow; a silent desync means "chat stopped following" bug reports with nothing in the logs. The untested seams (key routing, wire bytes, composer gating) are exactly where a refactor regresses silently. The review constructed several green-tests-wrong-behavior scenarios.
Acceptance Criteria
Type: Bug (hardening follow-up)
Part of #2654. Five-agent review of merged #2711 (full findings on that PR); the decode/apply layer was already hardened in #2714. This issue covers the surviving scroll/pin surface.
Implemented in #3391.
What
The TUI's local transcript scroll and pin-intent reporting work on the happy path, but the behavior is untested at the
Model.Updatelevel where it actually happens, and three edge paths leave a wrong-or-stuck view (or a desynced BEAM follow state) with no signal.Why
The pin flag drives BEAM-side auto-follow; a silent desync means "chat stopped following" bug reports with nothing in the logs. The untested seams (key routing, wire bytes, composer gating) are exactly where a refactor regresses silently. The review constructed several green-tests-wrong-behavior scenarios.
Acceptance Criteria
Model.Updatewith real key/wheel input against a live out channel asserts exactly one0x5Con the scroll-away edge and exactly one0x5Don the return edge, with no duplicates on repeated same-direction input.EncodeGUIChatScrolledAwayFromBottomandEncodeGUIChatReturnedToBottom.j,k,Ctrl+d,Ctrl+u,G,PgUp, andPgDn, including not-handled modifier combinations.InputFocused = true, navigation keys reach the composer and do not scroll the transcript, and vice versa. The0x09section decode has round-trip coverage including the absent-section default.maxTop == 0, exact-fit, and clamp-to-bottom paths recordpinReturned.truncatedflag is surfaced through an in-budgetearlier messages hiddenaffordance at the top of a capped transcript.