`MenuPrompt` was not the only writer. `BufferSnapshot` clears the menu
--- a popup anchored in the prior buffer would hijack input --- and left
the icon alone, so an open-menu arrow survived a buffer replacement over
document text until the pointer moved.
Menu state now has ONE writer, `set_menu`, which re-derives the icon.
A third site added later gets it for free instead of reintroducing the
same defect, and `self.menu = ` appears exactly once in the crate.
The snapshot also needs the icon re-derived AFTER the reshape, for a
different reason: it changes geometry. `text_left` is
`TEXT_LEFT + gutter_width_px` and the gutter is sized from the line
count, so a snapshot moves the text boundary under a stationary pointer
--- a pixel that was gutter becomes text.
BOTH MECHANISMS FIRE ON THE SNAPSHOT PATH, so at first each masked the
other: removing either alone left every row green, and only removing
both fired anything. That is the "one omission at a time" defect R4/R5
is written to avoid, reproduced here. Each now has its own witness:
set_menu's apply removed -> 2 rows (the MenuPrompt legs)
post-reshape apply removed -> 1 row (the new geometry leg)
The geometry row moves the line count between one and four digits so the
gutter widens and narrows under a stationary pointer, and asserts the
icon follows. Its setup steps assert the gutter actually moved, so a
fixture that stopped discriminating fails rather than passing quietly.