8e3252679a79bfc33234a19f8f1a9be155c25d2e
"Mark as Spam" moved the message but left it on screen. Two causes, both fixed generally rather than for this one action. `move_job` published message.changed without a thread_id, so the WS handler invalidated the message list but never the thread the user was reading — the panel had no reason to refetch. It now names the thread. And a thread whose last visible message has gone should not linger. MailLayout closes the panel when the open thread comes back empty, whoever emptied it — core action or plugin. `move_to_special` now also publishes the move immediately rather than waiting for the IMAP job, since a plugin acting on the user's behalf has no client-side handle to update optimistically the way the core endpoint's caller does. That exposed an ordering bug: the optimistic event reaches the passive-learning hook, which would re-teach the lesson /learn had just taught. /learn now records `learned` before moving, so the hook's dedup stands down — and records it with an upsert, because provider-filed spam has no verdict row of ours to update. One real mistake on the way: the event first reported the destination folder as the source, which would have made every move look like a no-op to anything reading the pair. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SqJYt7jD7oUEkoY68sBZo
Description
No description provided
11 MiB
Languages
Python
57.3%
TypeScript
31.7%
JavaScript
8.1%
Shell
1.5%
HTML
0.8%
Other
0.5%