Symptom
User reports: when new messages arrive in an open DM thread modal, the scroll position doesn't move to the bottom. Worked before, broken on production build commit `94fcd8c2` (PR #278).
Root cause
The auto-scroll `use_effect` in `ui/src/components/direct_messages/dm_thread_modal.rs:356` doesn't subscribe to any reactive signal. It:
- Captures `message_count` as a plain `usize` (not a signal read)
- Reads `OUTBOUND_SEND_COUNTER.peek()` — `.peek()` does NOT register a subscription
- Touches `prev_outbound_bump` / `first_scroll_done` — `Rc`, not signals
Dioxus 0.7 `use_effect` only re-runs when a reactive signal read inside the closure changes. With no signal reads inside, the effect runs once on mount and never again.
The PR #278 Codex round-1 P2 fix replaced `.read()` with `.peek()` on `OUTBOUND_SEND_COUNTER` to avoid a hypothetical re-entrant borrow panic. `.peek()` is non-subscribing by design — that fix killed the auto-scroll's reactivity.
Working reference
`ui/src/components/conversation.rs` (main room) uses a `Signal<Option<Rc>>` updated by the last bubble's `onmounted` handler. The effect reads the signal (`let trigger = last_chat_element();`) → subscribes → re-runs on each new mount. Mirror that pattern for the DM modal.
Fix shape (~30 lines)
- Add `let last_dm_bubble: Signal<Option<Rc>> = use_signal(|| None);`
- In the bubble rendering loop, attach `onmounted` to the last bubble that sets `last_dm_bubble`.
- Inside `use_effect`, read `last_dm_bubble()` → subscribes → re-runs each render-with-new-bubble.
- Keep `OUTBOUND_SEND_COUNTER.peek()` for the "force-scroll on user send" decision (a value read on an already-triggered effect, not the subscription trigger).
Regression test
The test should pin "effect re-runs when a new bubble mounts." Build a fixture with a small thread, drive an inbound or outbound message → assert effect closure fired. Without this test, the next Codex round chasing a phantom `.peek` panic would silently re-break the same thing.
[AI-assisted - Claude]
Symptom
User reports: when new messages arrive in an open DM thread modal, the scroll position doesn't move to the bottom. Worked before, broken on production build commit `94fcd8c2` (PR #278).
Root cause
The auto-scroll `use_effect` in `ui/src/components/direct_messages/dm_thread_modal.rs:356` doesn't subscribe to any reactive signal. It:
Dioxus 0.7 `use_effect` only re-runs when a reactive signal read inside the closure changes. With no signal reads inside, the effect runs once on mount and never again.
The PR #278 Codex round-1 P2 fix replaced `.read()` with `.peek()` on `OUTBOUND_SEND_COUNTER` to avoid a hypothetical re-entrant borrow panic. `.peek()` is non-subscribing by design — that fix killed the auto-scroll's reactivity.
Working reference
`ui/src/components/conversation.rs` (main room) uses a `Signal<Option<Rc>>` updated by the last bubble's `onmounted` handler. The effect reads the signal (`let trigger = last_chat_element();`) → subscribes → re-runs on each new mount. Mirror that pattern for the DM modal.
Fix shape (~30 lines)
Regression test
The test should pin "effect re-runs when a new bubble mounts." Build a fixture with a small thread, drive an inbound or outbound message → assert effect closure fired. Without this test, the next Codex round chasing a phantom `.peek` panic would silently re-break the same thing.
[AI-assisted - Claude]