Skip to content

Return to the Imbox once The Screener is empty - #530

Merged
dhh merged 7 commits into
mainfrom
tui-screener-closes-when-empty
Sep 29, 2026
Merged

dhh merged 7 commits into
mainfrom
tui-screener-closes-when-empty

Conversation

@dhh

@dhh dhh commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Screening the last sender used to leave the reader on an empty Screener ("Nobody is waiting to be screened") until they pressed Escape. The web app goes back to the Imbox once the Screener is empty, and the TUI now does too.

  • The rule: once the reader has screened someone or cleared The Screener, it closes to the Imbox as soon as the queue is known to be empty. That means no rows on screen, a pending count of zero, no further page to read, and no request still on its way to HEY. A Screener that opened empty stays open and says "Nobody is waiting".
  • One check, not one per handler: Update now wraps update and asks that question after every message. Review kept finding orders in which the messages land that a per-handler check missed: a decision racing a clear, a page below coming back empty, or a live re-read being the first to say the queue is empty. Asking once after each update covers all of them.
  • Messages survive the close: the "Jane Doe screened in" toast shows over the Imbox. "The Screener is clearing…" is now a toast rather than a notice on a screen that closes. Any failure notice that would close with The Screener (a clear or decision that failed while the other emptied the queue) is turned into a toast too.
  • Waits for requests in flight: a decision still on its way keeps The Screener open until it lands. Otherwise it would land on a closed Screener, never be counted done, and leave a reopened Screener that Escape couldn't leave.
  • Where it goes: screenerClosedMsg gets a toImbox flag, and closeScreener switches to the Imbox found by its kind (mailView.imboxIndex, which imboxSource now shares), so a renamed Imbox still works. Escape and q still go back to wherever The Screener was opened from.

docs/tui.md gets a sentence. Tests cover the last decision closing, a queue with more pages or a decision in flight staying open, an empty page or a live re-read after the last decision closing it, a clear waiting on a decision in flight (successful or failed), a failed clear being shown as it closes, and the model landing on the Imbox, renamed or not, while Escape returns to The Feed.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings September 29, 2026 19:39
@dhh
dhh requested a review from a team as a code owner September 29, 2026 19:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Clearing can close with decisions in flight, and Imbox navigation incorrectly relies on its display name.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Returns users to the Imbox after they empty The Screener.

Changes:

  • Adds automatic closing after final decisions or clearing.
  • Preserves Escape/q behavior and moves clearing feedback to a toast.
  • Adds tests and TUI documentation.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
internal/​tui/​tui.go Routes Screener closure to mail or Imbox.
internal/​tui/​screener.go Detects an emptied queue and requests closure.
internal/​tui/​screener_test.go Tests closure, pagination, mutations, and navigation.
docs/​tui.md Documents automatic return to the Imbox.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/tui/screener.go Outdated
v.pendingCount = 0
v.notice = "The Screener is clearing. Everyone waiting will be asked about again on their next email."
return nil, true
return tea.Batch(notify("The Screener is clearing. Everyone waiting will be asked about again on their next email."), v.closeToImbox()), true
Comment thread internal/tui/tui.go
Comment on lines +1096 to +1098
if toImbox {
cmd = tea.Batch(cmd, m.mailView.switchBox(boxForShortcut("1", m.mailView.boxes)))
}
dhh and others added 3 commits September 29, 2026 22:18
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mptied it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dhh
dhh force-pushed the tui-screener-closes-when-empty branch from 992c3cb to ab120b8 Compare September 29, 2026 20:19
dhh and others added 4 commits September 29, 2026 22:22
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Checking in each handler missed the orders the messages can land in: a
decision racing a clear, a page below, or a live re-read that is the first
to say the queue is empty. One check after every update covers them all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dhh
dhh merged commit 7b51ea2 into main Sep 29, 2026
25 checks passed
@dhh
dhh deleted the tui-screener-closes-when-empty branch September 29, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants