Context
While reviewing PR #403 (touch message actions), a reviewer noted a pre-existing inconsistency: .claude/rules/dioxus-signal-safety.md requires signal mutations in synchronous event handlers to be wrapped in crate::util::defer() (Firefox-mobile re-entrant RefCell already borrowed / empty-scope panics), but several local (use_signal) mutations in ui/src/components/conversation.rs set subscribed signals directly in onclick/oninput handlers without deferring.
Concrete example the reviewer found (NOT introduced by #403):
- The inline reaction-add ("+") button handler sets
picker_show_above and open_emoji_picker directly (around ui/src/components/conversation.rs:3004). Both are subscribed in render (picker_show_above.read(), the inline-picker gate), so on Firefox mobile a subscriber notification can fire from the write's Drop.
Other same-shape sites exist (e.g. editing_message.set, edit_text.set, open_emoji_picker.set, replying_to.set), all pre-existing.
PR #403 wrapped every mutation it added (the kebab menu handlers, and the IntersectionObserver is_at_bottom set that #403 made reactive), so the new code complies. This issue tracks bringing the pre-existing local-signal call sites into line.
Scope
Audit ui/src/components/conversation.rs (and siblings) for signal mutations in synchronous handlers that aren't deferred, and wrap them per the rule. Verify no timing regressions (defer runs on setTimeout(0)). Not urgent — these have shipped without widespread reports — but they are latent crash paths of a known class.
[AI-assisted - Claude]
Context
While reviewing PR #403 (touch message actions), a reviewer noted a pre-existing inconsistency:
.claude/rules/dioxus-signal-safety.mdrequires signal mutations in synchronous event handlers to be wrapped incrate::util::defer()(Firefox-mobile re-entrantRefCell already borrowed/ empty-scope panics), but several local (use_signal) mutations inui/src/components/conversation.rsset subscribed signals directly inonclick/oninputhandlers without deferring.Concrete example the reviewer found (NOT introduced by #403):
picker_show_aboveandopen_emoji_pickerdirectly (aroundui/src/components/conversation.rs:3004). Both are subscribed in render (picker_show_above.read(), the inline-picker gate), so on Firefox mobile a subscriber notification can fire from the write's Drop.Other same-shape sites exist (e.g.
editing_message.set,edit_text.set,open_emoji_picker.set,replying_to.set), all pre-existing.PR #403 wrapped every mutation it added (the kebab menu handlers, and the IntersectionObserver
is_at_bottomset that #403 made reactive), so the new code complies. This issue tracks bringing the pre-existing local-signal call sites into line.Scope
Audit
ui/src/components/conversation.rs(and siblings) for signal mutations in synchronous handlers that aren't deferred, and wrap them per the rule. Verify no timing regressions (defer runs onsetTimeout(0)). Not urgent — these have shipped without widespread reports — but they are latent crash paths of a known class.[AI-assisted - Claude]