Twinned from https://github.com/cfsh/ninefold/issues/531 by tools/beads/import_github.py's reconcile pass.
Suggestions from ninefold-reviewer's review of #529. Advisory residuals from a CONVERGED verdict — nothing is blocked on these, and they are deliberately not folded back into that PR.
PianoRoll.OnStateChanged dereferences _playBtn without the guard its sibling handler got#529 moved both subscriptions into _EnterTree (games/tonapse/ui/PianoRoll.cs:339-343), which is the fix. OnPlayheadMoved was null-guarded at the same time (:194), with the reason stated at the call site — _EnterTree runs before _Ready builds _playBtn. OnStateChanged (:505) was subscribed on the adjacent line and opens with two unguarded _playBtn calls:
```csharp _playBtn.AddThemeFontSizeOverride("font_size", TonapseStyle.Fs(12)); _playBtn.ResetSize(); ```
The window is real: TonapseHome.cs:764 col.AddChild(editWrap) propagates _EnterTree over the whole editGroup subtree — including the roll — before _propagate_ready runs SoundPicker._Ready and PatternPicker._Ready. A RaiseChanged from either picker's build would be a startup NullReferenceException.
Not reachable today — neither Rebuild() raises Changed, and Chip._Ready doesn't either. It is one line, and it removes the dependence of the roll's startup on what a sibling section happens not to do yet.
Changed half of #529's fix has no probe assertiontools/probes/split-notes-editor.json asserts only PlayheadMoved-driven facts: PlayheadShown, PlayheadAdvancing, and the ▶/⏹ button text. Nothing exercises EditorState.Changed.
So this mutation survives the probe green:
```csharp public override void _EnterTree() { EditorState.PlayheadMoved += OnPlayheadMoved; // stays } public override void _Ready() { EditorState.Changed += OnStateChanged; // moved back — the bug, restored } ```
…and the symptom it restores is the one Aedan reported as *"when looping the pattern in split view, it doesn't always pick up notes added / removed in the loop music playing"* (#517 symptom 4). #529 mutation-tested the whole-fix revert but not the halves.
What would close it: an assertion that a roll edit during Loop playback actually rebuilds — a probe-readable counter on OnStateChanged, or asserting an existing property that only RecomputeLayout refreshes, after placing a note mid-playback at 1906x807 forced split.
Related: #517 (still open for the header-flicker symptom), #513 (the duplicated playhead renderers).
None.
No comments.