[PATCH b4 v2 01/44] review-tui: mark all outgoing mail as read, not just review replies
Christian Brauner <[email protected]> Fri, 31 Jul 2026 23:58:42 +0200
| Newsgroups | org.kernel.linux.tools |
|---|---|
| Message-ID | <20260731-work-b4-editor-branch-guard-v2-1-243fd19d322d@kernel.org> |
Only review replies were marked as read at send time. The thank-you note and the lite viewer's follow-up reply relied on matching the sender address on the next fetch, which fails when the mail goes out from another address such as b4.thanks-from-email. The message then comes back from the list and lights up the unread badge. Add a shared helper that marks outgoing mail as read at send time. It respects --email-dry-run and never raises. Use it for the follow-up reply; the thank-you path follows in a later patch. Signed-off-by: Christian Brauner (Amutable) <[email protected]> --- src/b4/review_tui/_common.py | 23 +++++++++++++++++++++++ src/b4/review_tui/_lite_app.py | 2 ++ src/b4/review_tui/_review_app.py | 16 +++------------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/b4/review_tui/_common.py b/src/b4/review_tui/_common.py index 935f553..33ab7ea 100644 --- a/src/b4/review_tui/_common.py +++ b/src/b4/review_tui/_common.py @@ -114,6 +114,29 @@ _CallFromThreadReturn = TypeVar('_CallFromThreadReturn') _WorkerResult = TypeVar('_WorkerResult') +def mark_outgoing_seen( + msgs: List[email.message.EmailMessage], dryrun: bool = False +) -> None: + """Flag messages b4 just sent as read, before the list echoes them back. + + Every send path that puts a message into a tracked thread wants this: + a reply, a follow-up, a thank-you note. Without it the maintainer's + own mail comes back a few minutes later and lights up the series' + unread badge. + + Never raises: the message is already gone, so a bookkeeping failure + here must not be reported to the caller as a failure to send. + """ + if dryrun: + return + try: + from b4.review import messages + + messages.mark_outgoing_seen(msgs) + except Exception as ex: + logger.debug('Could not mark sent messages as seen: %s', ex) + + def get_thread_msgs( topdir: str, message_id: str, diff --git a/src/b4/review_tui/_lite_app.py b/src/b4/review_tui/_lite_app.py index 9c418ad..86a201e 100644 --- a/src/b4/review_tui/_lite_app.py +++ b/src/b4/review_tui/_lite_app.py @@ -26,6 +26,7 @@ from b4.review_tui._common import ( _quiet_worker, _write_diff_line, display_width, + mark_outgoing_seen, pad_display, resolve_styles, run_lore_worker, @@ -816,6 +817,7 @@ class LiteThreadScreen(ModalScreen[None]): self.app.notify(f'Dry-run: reply to {lmsg.fromemail} logged, not sent') self._mark_answered(node) else: + mark_outgoing_seen([msg], dryrun=self._email_dryrun) self.app.notify(f'Reply sent to {lmsg.fromemail}') self._mark_answered(node) except Exception as ex: diff --git a/src/b4/review_tui/_review_app.py b/src/b4/review_tui/_review_app.py index 81c3890..8139518 100644 --- a/src/b4/review_tui/_review_app.py +++ b/src/b4/review_tui/_review_app.py @@ -48,6 +48,7 @@ from b4.review_tui._common import ( _write_followup_trailers, get_thread_msgs, logger, + mark_outgoing_seen, notify_quit_hint, resolve_styles, reviewer_colours, @@ -1664,7 +1665,7 @@ class ReviewApp(LoreNodeShutdownMixin, CheckRunnerMixin, App[None]): review['sent-revision'] = current_rev self._save_tracking() self._mark_patches_answered(msgs) - self._mark_outgoing_seen(msgs) + mark_outgoing_seen(msgs, dryrun=self._email_dryrun) self.notify(f'Sent {sent} review email(s).') except Exception as ex: self.notify(f'Send failed: {ex}', severity='error') @@ -1746,7 +1747,7 @@ class ReviewApp(LoreNodeShutdownMixin, CheckRunnerMixin, App[None]): elif self._email_dryrun: self.notify(f'Dry-run: reply to {entry["fromemail"]} logged, not sent') else: - self._mark_outgoing_seen([msg]) + mark_outgoing_seen([msg], dryrun=self._email_dryrun) self.notify(f'Reply sent to {entry["fromemail"]}') except Exception as ex: self.notify(f'Send failed: {ex}', severity='error') @@ -2063,17 +2064,6 @@ class ReviewApp(LoreNodeShutdownMixin, CheckRunnerMixin, App[None]): except Exception: pass - def _mark_outgoing_seen(self, msgs: List[Any]) -> None: - """Mark just-sent messages as Seen so they never show up as unread.""" - if self._email_dryrun: - return - try: - from b4.review import messages - - messages.mark_outgoing_seen(msgs) - except Exception: - pass - def _mark_patches_answered(self, msgs: List[Any]) -> None: """Mark the original patches as Answered based on In-Reply-To.""" entries = [] -- 2.53.0