Three QA-found issues in the approval gate:
- displayState gated the in-session/approval surfaces on hasApproval
before sessionEntered, so moving the list cursor onto a session with a
pending gate auto-opened it, and `l` back-to-list couldn't escape
(the gate re-popped). Require sessionEntered first.
- The band ran every preview through the two-column diff renderer, so a
shell tool's argv JSON rendered as an identical-column "diff". Detect
real unified diffs (isUnifiedDiff); render other previews as plain
text, and drop the ^x fullscreen hint when there's nothing to expand.
- The footer duplicated the band's approve/reject/steer/diff keys. It now
shows navigation (l back / e events / q quit) instead.
The plane-2 tool-call assessor records verified preconditions
("[PATH_OUTSIDE_WORKSPACE] …") and the server already ships them in
RiskSummaryDto.rationale, but the Go TUI's RiskSummaryDto had no
Rationale field — so the justification was silently dropped at decode
and the gate showed only an opaque tier.
Decode the rationale, carry it on Approval, and render it under the
header in the approval band (warn-marked, above the diff). This closes
the last deferred item of the plane-2 slice-1 plan: the assessment
surfaced to the approval UX. Golden test pins the rationale decode.