notes editor: pushing right escapes the card and lands on the header menu button nf-ne39 ← Beads

open priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/415 by tools/beads/import_github.py's reconcile pass.

From @aedanpope's playtest, 2026-08-02, on the f5/integration build fcd3d42:

> "Pushing right with focus on the notes editor jumps focus to menu btn. Nowhere else does this."

Evidence — journal + capture 2

Published telemetry: playtest-logs/2026-08-02-fcd3d42/ on the screenshots branch ([journal.jsonl](https://github.com/cfsh/ninefold/blob/7beee4e/playtest-logs/2026-08-02-fcd3d42/journal.jsonl), [capture-2.png](https://github.com/cfsh/ninefold/blob/7beee4e/playtest-logs/2026-08-02-fcd3d42/capture-2.png)).

It reproduces three times in the session, always the same shape — focus sitting in the notes card, one input, focus is on the header:

``` 10:49:28.170 focus_change input zone=Notes …/@PanelContainer@136/@VBoxContainer@135 > @Control@134 10:49:28.415 focus_change input zone=Notes …/@VBoxContainer@22/@HBoxContainer@28 > @Button@27 ← header 10:49:39.204 focus_change input zone=Notes …/@VBoxContainer@22/@HBoxContainer@28 > @Button@27 ← header 10:50:31.930 focus_change input zone=Notes …/@PanelContainer@136/@VBoxContainer@135 > @Control@134 10:50:33.330 focus_change input zone=Notes …/@VBoxContainer@22/@HBoxContainer@28 > @Button@27 ← header 10:50:35.890 capture(2) zone=SongGrid ```

@HBoxContainer@28 / @Button@27 is the pinned header built by TonapseHome.BuildHeader() (TonapseHome.cs:306+) — the menu button, exactly as reported. Capture 2 was taken ~2.5s after the third repro, once he had walked focus back to the SONG grid.

Diagnosis — this is NOT #385

Every one of these is trigger=input, with no paired rebuild event and no second focus_change a few ms later. So it is not a deferred re-grab race — it is the neighbour graph itself, i.e. layer 1 of #385's taxonomy, not layer 3.

The cause looks like an unset right-neighbour rather than a wrong one. FocusNeighborRight is only ever assigned in ui/TonapseMenu.cs and ui/SoundEditorModal.cs; nothing in PianoRoll / the notes card wires horizontal neighbours. With FocusNeighborRight empty, Godot falls back to its default nearest-control-in-direction search, which is free to leave the card — and since the notes card is the last thing in its column, the geometrically-nearest control to the right/up is the header. That also explains "nowhere else does this": the menu and the sound-editor modal both wire all four directions explicitly, and the song grid's cells are in a GridContainer with real neighbours on every side.

What "right" should do instead

Needs a call — the notes card is the rightmost thing in its column, so there is no natural right-neighbour. Options, in rough order of how the rest of the app behaves:

A is the cheap, consistent default unless there's a reason otherwise.

Gate

Per CLAUDE.md, a focus-flow fix needs an expect_focus probe leg, not just a screenshot — assert that right-from-the-roll lands where the traversal says and *not* on the header. #385 item 3 proposes exactly this per rebuild-triggering transition; this one is a plain traversal edge, so it should be cheap to pin.

Refs #385 (same subsystem, different layer — that issue's audit covers deferred re-grabs; this is a missing neighbour link and shouldn't wait on it).

Dependencies

None.

Comments

No comments.

Add a comment