Skip to content

feat(tui): add automation apply and rules editing#30

Merged
BjornMelin merged 6 commits intomainfrom
feat/tui-automation-apply-rules
May 8, 2026
Merged

feat(tui): add automation apply and rules editing#30
BjornMelin merged 6 commits intomainfrom
feat/tui-automation-apply-rules

Conversation

@BjornMelin
Copy link
Copy Markdown
Owner

Summary

  • Add TUI Automation pane actions for rules validation, disabled starter suggestions, editor-backed rules editing, persisted preview run creation, saved-run inspection, and guarded saved-run apply.
  • Preserve the review-first safety model: apply only targets a loaded persisted run, never live rollout output, and requires exact APPLY confirmation with run/candidate/action context.
  • Document the operator contract in the TUI runbook, automation runbook, roadmap, README, and ADR 0011.

Safety

  • No background automation or direct Gmail mutation from rollout previews.
  • Rules editing seeds .mailroom/automation.toml from the tracked example when missing, then validates after editor exit.
  • Apply reuses the existing automation service layer and refreshes readiness after actions.

Verification

  • rtk err cargo fmt --check
  • rtk err cargo clippy --all-targets --all-features -- -D warnings
  • rtk test cargo test
  • cargo run -- paths --json
  • cargo run -- doctor --json
  • script -qefc 'timeout 2s cargo run -- tui' /tmp/mailroom-tui-automation-smoke.txt
  • git diff --check

Closes #26

Copilot AI review requested due to automatic review settings May 8, 2026 02:14
@qodo-code-review
Copy link
Copy Markdown

ⓘ You've reached your Qodo monthly free-tier limit. Reviews pause until next month — upgrade your plan to continue now, or link your paid account if you already have one.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 13e9feeb-8628-419f-b974-dfb3e1be515b

📥 Commits

Reviewing files that changed from the base of the PR and between 0545d69 and abdbe5a.

📒 Files selected for processing (1)
  • src/tui.rs
📜 Recent review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-05-07T23:34:50.823Z
Learnt from: BjornMelin
Repo: BjornMelin/mailroom PR: 23
File: src/tui.rs:61-67
Timestamp: 2026-05-07T23:34:50.823Z
Learning: When reviewing Rust TUI code using ratatui 0.30.0, do not flag `ratatui::try_init()` as missing a panic hook. In this version, `try_init()` installs a panic hook that restores the terminal (similar to `ratatui::init()`), but returns `Result` so callers can handle failures without panicking. In a CLI/TUI handler context (e.g., files like `src/tui.rs`), the correct pattern is to use `try_init()` and ensure terminal restoration via `TerminalGuard`’s `Drop` implementation rather than expecting `init()`-style panic behavior.

Applied to files:

  • src/tui.rs
🔍 Remote MCP Firecrawl

Summary — additional review-relevant facts (concise)

  • Ratatui: official recipe for spawning an external editor from a TUI — leave alternate screen, disable raw mode, spawn blocking Command, re-enter alternate screen, enable raw mode, then call terminal.clear() to avoid redraw artifacts. Also recommended to pause/cancel any event loop while editor runs.,

  • Ratatui panic-hook guidance: install a panic hook that restores terminal state (disable raw mode + leave alternate screen) so panics don’t leave the terminal corrupted. Example patterns shown.

  • Crossterm: canonical APIs for enable_raw_mode / disable_raw_mode and Enter/LeaveAlternateScreen; raw-mode behavior has platform differences (Windows vs UNIX) documented in crossterm issues — ensure editor flow handles cross-platform raw-mode/alternate-screen semantics and pauses any TUI event loop.,

  • TOML seeding/serialization: toml::to_string_pretty exists for user-friendly serialization but is available only when the crate features (serde and/or display) are enabled — confirm the project enables the required toml serde feature (or use toml_edit / toml_pretty alternatives if preserving comments/formatting is needed).,

  • Gmail API (apply safety/scale):

    • messages.batchModify: request body supports up to 1000 message IDs per request (1000-IDs limit documented).
    • Per-method quota units table: messages.batchModify appears in Google’s per-method quota table (messages.batchModify → 50 quota units in the documented per-method table) and overall Gmail quotas include per-minute-per-project (1,200,000 quota units) and per-minute-per-user-per-project (6,000 quota units). Recommend backoff/monitoring for large applies.
    • Community reports: some community threads report batchModify may not deplete quota units in practice, but this is not a substitute for monitoring and the official per-method table should be used for planning.,

Relevant reviewer action items (derived from above)

  • Verify src/tui.rs editor flow:

    • leaves alternate screen and disables raw mode before launching editor;
    • pauses/cancels any TUI event loop while the editor child runs;
    • re-enters alternate screen, enables raw mode, and calls terminal.clear() after editor exit;
    • installs/uses panic-hook or equivalent cleanup to restore terminal on panic.
      (See Ratatui recipes & panic-hooks.),
  • Confirm cross-platform behavior: ensure tests or code handle Crossterm Windows vs UNIX raw-mode/alternate-screen differences and that event-loop pause/resume is robust.

  • Confirm TOML seeding code:

    • that toml::to_string_pretty (or an alternative) is used and the toml crate features (serde) are enabled; handle file I/O errors and preserve usability/readability of seeded .mailroom/automation.toml.
  • Confirm apply safety/scale:

    • TUI apply must respect Gmail API limits (1000 IDs/request) and quota units; add monitoring/backoff and document expected quota impact for large runs. Use per-method quota table and implement truncated exponential backoff for time-based quota errors.,

Sources (Firecrawl searches used)

  • Ratatui spawn-editor recipe and alternate-screen/raw-mode docs,
  • Ratatui panic-hooks recipe
  • Crossterm terminal docs & issue on raw-mode differences,
  • toml::to_string_pretty docs (feature note)
  • Gmail API batchModify and quota docs (1000 IDs limit; per-method quota table; per-minute quotas) and community threads,,
🔇 Additional comments (6)
src/tui.rs (6)

64-71: LGTM!

The terminal action flow correctly implements the Ratatui editor recipe: restoring terminal state before the blocking editor subprocess, reinitializing after exit, and calling terminal.clear() to prevent redraw artifacts. The async result handling is properly deferred until after terminal reinitialization.


742-759: LGTM!

The apply modal correctly implements the safety gates: it requires a loaded persisted run and verifies the run status is Previewed before allowing the destructive APPLY flow. This prevents accidental re-application of already-applied runs.


1826-1856: LGTM!

The automation modal key handling correctly routes Esc/q to cancel, Enter to confirm with validation, and captures text input for all modal types. The simpler handling (no Tab field cycling) is appropriate since each automation modal has a single text field.


2448-2476: LGTM!

The ApplyRun modal rendering provides excellent operator context before destructive actions: run ID, candidate count, action mix summary, blocked rules, and a prominent Gmail mutation warning. This supports the review-first safety model documented in the PR objectives.


3790-3857: LGTM!

Excellent test coverage for the safety-critical apply flow. The tests verify:

  1. Apply is blocked when no persisted run is loaded
  2. Apply modal opens correctly when a Previewed run is loaded
  3. Apply requires typing "APPLY" before Enter
  4. Apply is blocked for non-Previewed runs (e.g., already Applied)

This covers the key safety gates required by the PR objectives.


1260-1279: LGTM!

The explicit match arms for each modal variant improve readability over the previous aliasing pattern. Each field (limit_text, run_id_text, confirm_text) is now clearly matched in its respective variant.


Walkthrough

This PR adds a TUI automation pane with rules validation and suggestion review, editor-backed rules editing (seeded from config), persisted preview run creation and SQLite-backed run loading/inspection, and guarded apply that only executes on a loaded persisted run after typing exact "APPLY". The TUI event loop supports a pending terminal-action queue to restore the terminal, run a blocking editor subprocess, reinitialize the UI, and then refresh automation reports. Documentation (ADR 0011, README, ops, roadmap), automation re-exports, and the TUI handler wiring were updated to match the operator contract.

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 8 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 50.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(tui): add automation apply and rules editing' follows conventional commits format with a feat type and clear scope, and accurately describes the main changes in the pull request.
Description check ✅ Passed The pull request description is directly related to the changeset, detailing the TUI automation features added, safety considerations, and verification steps.
Linked Issues check ✅ Passed The pull request successfully addresses the implementation checklist from issue #26: rule validation, disabled starter suggestions, editor-backed rules editing with seeding/validation, persisted preview run creation, candidate inspection, guarded apply with confirmation, preserved review-first safety model, data refresh after actions, and test coverage.
Out of Scope Changes check ✅ Passed All code changes are directly aligned with the scope of issue #26; documentation updates and automation service re-exports support the TUI automation features without introducing unrelated modifications.
React + Next.Js Best Practices ✅ Passed Check not applicable: This is a Rust/TUI project, not a React/Next.js web application. PR contains only Rust source and documentation, zero JavaScript/TypeScript/React code.
Docstring & Research Standards ✅ Passed This check requires Biome (TypeScript/JavaScript linter) and TSDoc standards. The PR is a Rust project with Cargo.toml, .rs files only, no .ts/.js or biome config. Check is not applicable.
Web Interface Guidelines ✅ Passed Web Interface Guidelines check does not apply. PR is for a Terminal UI (ratatui/crossterm, not HTML/CSS/JavaScript). Zero web interface changes in this PR.
Google Python Style Compliance ✅ Passed Not applicable. PR contains no Python files, only Rust, Markdown, and TOML. Google Python Style guidelines cannot apply to non-Python code.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tui-automation-apply-rules
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/tui-automation-apply-rules

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e2a7b0862d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/tui.rs Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the existing Ratatui/Crossterm operator shell (mailroom tui) to support a review-first automation workflow: validating/editing rules, creating and inspecting persisted preview runs, and applying only a loaded saved run behind explicit confirmation. It also updates the operator runbooks/ADR set to document the new TUI automation contract.

Changes:

  • Add TUI Automation pane actions/modals for rules validate/suggest, persisted run creation/load, candidate inspection, and guarded apply.
  • Add an editor-backed flow for .mailroom/automation.toml (seed from config/automation.example.toml when missing, then validate on exit).
  • Update README, runbooks, roadmap, and add ADR 0011 to document the automation TUI safety model and operator key bindings.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/tui.rs Implements Automation pane actions, modals, candidate inspection UI, apply confirmation gate, and $EDITOR rules editing integration.
src/automation/mod.rs Expands crate-internal re-exports for automation reports used by the TUI.
README.md Updates project posture and ADR references to include TUI automation actions.
docs/roadmap/v1-search-triage-draft-queue.md Updates roadmap slice notes to reflect shipped automation TUI flows.
docs/README.md Adds ADR 0011 to the “Start here” index.
docs/operations/tui-operator-shell.md Updates TUI contract and key bindings to include automation actions and safety gates.
docs/operations/automation-rules-and-bulk-actions.md Documents the TUI automation operator flow and its review-first constraints.
docs/decisions/0011-tui-automation-apply-rules.md Adds ADR capturing the rationale and safety boundaries for automation apply + rules editing in the TUI.
docs/decisions/0008-read-only-tui-foundation.md Clarifies that later ADRs add confirmed actions beyond the original read-only slice.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tui.rs
Comment thread src/tui.rs Outdated
Comment thread src/tui.rs
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tui.rs`:
- Around line 1244-1270: The pattern matches in push_automation_modal_text and
pop_automation_modal_text alias different fields (run_id_text, confirm_text) to
the misleading name limit_text; update the match arms to use a neutral name like
text (or match each variant explicitly) so each variant binds its actual field
with a clear identifier: change the bindings in AutomationModal::RunPreview,
::ShowRun (run_id_text), and ::ApplyRun (confirm_text) to use text, and update
the subsequent push/pop usage to reference text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6acd04b2-f236-464b-a242-97b62cad943f

📥 Commits

Reviewing files that changed from the base of the PR and between 76d6f45 and e2a7b08.

📒 Files selected for processing (9)
  • README.md
  • docs/README.md
  • docs/decisions/0008-read-only-tui-foundation.md
  • docs/decisions/0011-tui-automation-apply-rules.md
  • docs/operations/automation-rules-and-bulk-actions.md
  • docs/operations/tui-operator-shell.md
  • docs/roadmap/v1-search-triage-draft-queue.md
  • src/automation/mod.rs
  • src/tui.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: rust
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{js,jsx,ts,tsx,md,txt,json}

📄 CodeRabbit inference engine (Custom checks)

Reject Unicode EM DASH (code point U+2014) in comments and string literals. Use -- instead. Hard FAIL if any newly introduced content includes U+2014.

Files:

  • docs/README.md
  • docs/decisions/0011-tui-automation-apply-rules.md
  • docs/operations/automation-rules-and-bulk-actions.md
  • docs/roadmap/v1-search-triage-draft-queue.md
  • README.md
  • docs/decisions/0008-read-only-tui-foundation.md
  • docs/operations/tui-operator-shell.md
docs/decisions/**

📄 CodeRabbit inference engine (AGENTS.md)

Update docs in docs/decisions/ when architecture, storage boundaries, or command surfaces change

Files:

  • docs/decisions/0011-tui-automation-apply-rules.md
  • docs/decisions/0008-read-only-tui-foundation.md
docs/{operations,workflows}/**

📄 CodeRabbit inference engine (AGENTS.md)

Put operator procedures in docs/operations/ or docs/workflows/ and keep docs concrete and aligned with the current binary surface

Files:

  • docs/operations/automation-rules-and-bulk-actions.md
  • docs/operations/tui-operator-shell.md
🧠 Learnings (1)
📚 Learning: 2026-05-07T23:34:50.823Z
Learnt from: BjornMelin
Repo: BjornMelin/mailroom PR: 23
File: src/tui.rs:61-67
Timestamp: 2026-05-07T23:34:50.823Z
Learning: When reviewing Rust TUI code using ratatui 0.30.0, do not flag `ratatui::try_init()` as missing a panic hook. In this version, `try_init()` installs a panic hook that restores the terminal (similar to `ratatui::init()`), but returns `Result` so callers can handle failures without panicking. In a CLI/TUI handler context (e.g., files like `src/tui.rs`), the correct pattern is to use `try_init()` and ensure terminal restoration via `TerminalGuard`’s `Drop` implementation rather than expecting `init()`-style panic behavior.

Applied to files:

  • src/automation/mod.rs
  • src/tui.rs
🔍 Remote MCP Context7

Perfect! Now I have enough context. Let me compile a comprehensive summary of my findings:

Summary of Additional Context for PR #30 Review,, [::GitHub_Copilot_get_file_contents::], [::Firecrawl_firecrawl_search::], [::Firecrawl_firecrawl_search::] Based on my investigation of dependencies, library patterns, service layer, and implementation details:

Key Dependencies and Versions

The codebase uses Ratatui v0.30.0 with Crossterm v0.29.0 for TUI rendering and event handling. [::GitHub_Copilot_get_file_contents::] The TOML crate is at v0.9.8 for rules file parsing and serialization. [::GitHub_Copilot_get_file_contents::]

Ratatui Modal and Popup Patterns

Ratatui provides stateless and stateful widget rendering via Frame::render_widget and Frame::render_stateful_widget, which allows modals to overlay on a cleared area. [::Context7_query-docs::] The implementation uses a centered rect approach with Clear widget to render modals, visible in the new render_automation_modal function in the PR.

Crossterm Event Handling

Crossterm supports event handling with event::read() for blocking reads and poll(duration) for non-blocking checks with timeout, including support for key modifiers (ALT, SHIFT, CONTROL). [::Context7_query-docs::] The PR's automation modal input handling uses KeyCode::Char(value) with backspace support and text input validation, matching Crossterm's documented patterns.

Terminal Restoration Pattern

The PR introduces a pending_terminal_action mechanism to safely restore the terminal, launch an external editor, then re-initialize Ratatui. This is critical because: the TUI runs in raw mode and alternate screen mode via Ratatui's backend initialization, so external commands (like $EDITOR) require disabling these modes, then restoring after the editor exits. [::GitHub_Copilot_pull_request_read::] The implementation calls ratatui::restore() before spawning the editor command and terminal = ratatui::try_init()? after to resume rendering.

Automation Service Layer Integration

The automation service provides distinct operations: automation rules validate, automation rules suggest, automation run for persisted preview snapshots, automation apply <run-id>, and automation show <run-id>. [::GitHub_Copilot_get_file_contents::] The PR re-exports these report types (AutomationApplyReport, AutomationRulesValidateReport, AutomationRulesSuggestReport, AutomationRunPreviewReport, AutomationShowReport) in src/automation/mod.rs to expose them to the TUI layer.

Gmail API Quota Considerations

The Gmail API is subject to 250 quota units per user per second (moving average) and 1,000,000,000 quota units per day. [::Firecrawl_firecrawl_search::] Archive, label, and trash operations each consume quota; the PR's apply concurrency limit of 4 (defined in service.rs) should help avoid quota exhaustion during batch operations.

TOML Handling

The toml crate provides toml::from_str for deserialization and toml::to_string for serialization, supporting serde traits. [::Context7_query-docs::] The PR's editor flow reads .mailroom/automation.toml, invokes $VISUAL/$EDITOR, then validates the edited file by re-calling automation::validate_rules. If the file is missing, it seeds from config/automation.example.toml.

Confirmation Modal Safety Pattern

The PR implements high-friction confirmation by:

  • Showing run ID, candidate count, action mix, blocked rules, and Gmail mutation warning in the modal
  • Requiring exact APPLY text input (not just any confirmation)
  • Blocking apply unless a persisted run is loaded (never applying rollout preview directly)
  • Using automation apply <run-id> --execute to target only the saved snapshot, not live rollout output

Prior TUI Work Context

PR #23 introduced the read-only TUI operator shell without draft send, cleanup execution, attachment export, automation snapshots, or apply. [::GitHub_Copilot_pull_request_read::] This PR (#30) builds on that foundation, adding the automation workflow interactions while preserving the review-first model.

Test Coverage

The PR includes unit tests covering:

  • Modal input validation and blocking invalid limits/run IDs
  • Apply confirmation gating (requires APPLY text, rejects mismatches)
  • Prevention of apply without a loaded run
  • Candidate detail rendering for loaded automation runs
  • Terminal action queueing for editor launch
🔇 Additional comments (15)
src/automation/mod.rs (1)

8-11: Internal report re-export expansion is coherent.

The added model report re-exports cleanly expose the automation report types needed by the new TUI automation flows while keeping visibility scoped to pub(crate).

docs/decisions/0008-read-only-tui-foundation.md (1)

31-34: Read-only boundary clarification is strong and consistent.

This update clearly codifies what the first TUI slice excludes while leaving a well-defined path for future confirmed actions.

docs/README.md (1)

23-34: Docs index expansion is well-structured.

The added ADR and operations links keep the onboarding path current with the new automation/TUI contract and maintain clear sequencing.

README.md (1)

8-9: README posture and sequencing updates are aligned.

These edits consistently reflect the reviewed-snapshot automation flow, include ADR 0011 in the right places, and keep the near-term plan concrete.

Also applies to: 175-178, 223-224, 239-245

docs/roadmap/v1-search-triage-draft-queue.md (1)

91-101: Roadmap scope update is precise and safety-preserving.

The added automation capabilities and explicit non-goals are clearly bounded and consistent with the review-first model.

docs/operations/automation-rules-and-bulk-actions.md (1)

172-191: TUI automation runbook flow is concrete and well-guarded.

The key-driven steps, persisted-run requirement, and exact APPLY confirmation make the operator contract explicit and actionable.

docs/operations/tui-operator-shell.md (1)

64-74: Automation keys and mutation guardrails are documented clearly.

The key mappings, confirmation inputs, persisted-run restriction, and post-action refresh contract are all explicit and operationally solid.

Also applies to: 95-103, 132-155

docs/decisions/0011-tui-automation-apply-rules.md (1)

1-73: ADR 0011 is complete and decision-grade.

This decision document cleanly defines boundaries, confirms persisted-run-only apply, and captures the editor-backed rules workflow without introducing a second automation engine.

src/tui.rs (7)

1-6: LGTM!

The new automation imports are correctly structured and include all necessary types from the automation module for the TUI integration.


64-70: LGTM!

The pending terminal action handling correctly implements the pattern for external editor invocation: restore terminal, run action, re-initialize. This follows ratatui best practices for spawning external processes while maintaining proper terminal state management. Based on learnings, try_init() installs a panic hook and returns Result, which is the correct pattern here.


738-748: LGTM!

The apply modal correctly gates on having a loaded persisted run before allowing the user to proceed. Combined with the APPLY confirmation requirement in confirm_automation_modal, this enforces the review-first safety model where apply targets only a loaded persisted run snapshot.


755-764: LGTM!

The APPLY confirmation gate is correctly implemented - it requires an exact match of the string "APPLY" before proceeding with the automation apply operation. This provides the high-friction confirmation specified in the PR objectives.


1300-1334: LGTM!

The editor launching implementation follows established patterns:

  • Uses $VISUAL$EDITORvi fallback chain (standard convention)
  • Uses login shell (-lc) to ensure user's editor configuration is loaded
  • Properly quotes the path for shell interpretation using single-quote escaping
  • Checks exit status and reports errors with path context

1367-1370: LGTM!

The shell quoting uses correct POSIX single-quote escaping ('\''). This safely handles paths containing spaces, special characters, and single quotes when passed to a shell.


3638-3763: LGTM!

The new automation tests provide comprehensive coverage for:

  • Modal input validation (positive limits/run IDs)
  • Apply gate requiring loaded persisted run
  • APPLY confirmation requirement
  • Editor key queuing terminal action

This aligns with the PR objective for "tests for confirmation gates, blocked apply state, and prevention of direct-rollout-apply behavior."

Comment thread src/tui.rs
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tui.rs`:
- Around line 684-699: The refresh_automation snapshot is only called on some
success branches (e.g., in validate_automation_rules) but not on error branches
or in suggest_automation_rules, so update each automation action path to always
refresh the rollout snapshot: ensure validate_automation_rules calls
self.refresh_automation(config_report).await in both Ok and Err branches (after
setting automation_action_report/status), and add the same unconditional refresh
call to suggest_automation_rules and the run/apply handlers (the other blocks
referenced around lines 701-719, 783-803, 831-853, 864-883) so every success and
failure path invokes self.refresh_automation(config_report).await to keep the
readiness panel consistent.
- Around line 876-882: The current Err arm sets self.automation_action_report
and self.status to claim "invalid TOML" even though validate_rules() may fail
for semantic reasons; update the messages to avoid saying "invalid TOML" and
accurately reflect a validation failure: change the status set on error (in the
Err(error) branch) from "automation rules edit returned invalid TOML" to
something like "automation rules validation failed" and adjust the
automation_action_report text to say the edited rules file "did not validate"
including the error details from error; optionally, if you want finer-grained
messaging, detect a TOML parse error (e.g. a toml::de::Error) and only then use
"invalid TOML", otherwise use the generic validation-failed wording, but at
minimum remove the misleading "invalid TOML" wording in the Err(error) branch
for validate_rules().
- Around line 738-748: open_automation_apply_modal currently only verifies a
persisted run is loaded (via loaded_automation_detail()) but must also verify
the run is still preview-only; update open_automation_apply_modal to inspect the
loaded report's run status (e.g., report.detail.run.status or an
is_preview()/is_pending_preview flag) and only set self.automation_modal =
Some(AutomationModal::ApplyRun { ... }) when that status indicates a
preview-only run; otherwise do not create the ApplyRun modal and set self.status
to the blocked message (e.g., "automation apply unavailable: run not in preview
state") so the destructive APPLY flow is prevented for already-applied or
non-preview runs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 581d9f68-a3b1-40dd-9917-c6aa5dbc8441

📥 Commits

Reviewing files that changed from the base of the PR and between e2a7b08 and e79de77.

📒 Files selected for processing (1)
  • src/tui.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rust
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-05-07T23:34:50.823Z
Learnt from: BjornMelin
Repo: BjornMelin/mailroom PR: 23
File: src/tui.rs:61-67
Timestamp: 2026-05-07T23:34:50.823Z
Learning: When reviewing Rust TUI code using ratatui 0.30.0, do not flag `ratatui::try_init()` as missing a panic hook. In this version, `try_init()` installs a panic hook that restores the terminal (similar to `ratatui::init()`), but returns `Result` so callers can handle failures without panicking. In a CLI/TUI handler context (e.g., files like `src/tui.rs`), the correct pattern is to use `try_init()` and ensure terminal restoration via `TerminalGuard`’s `Drop` implementation rather than expecting `init()`-style panic behavior.

Applied to files:

  • src/tui.rs
🔍 Remote MCP Context7, Firecrawl

Relevant factual points to aid review (concise):

  • Ratatui: modal/popups

    • Use Frame::render_widget / render_stateful_widget; common popup pattern is to compute a centered Rect and call frame.render_widget(Clear, area) before rendering the popup Block/Paragraph,.
    • Clear only clears the specified buffer area and cannot be relied on to “clear the terminal on the first render” (terminal.clear() needed for first render) — consider that when restoring/initializing after launching $EDITOR,.
  • Crossterm: event handling and editor/terminal restore considerations

    • event::read() blocks; poll(timeout) allows non-blocking checks. Do not call read/poll from multiple threads — use a single reader thread and dispatch events to others (cross-thread read is unsupported).
    • Key input uses KeyCode::Char / Backspace / Enter variants; Backspace semantics vary by platform (Delete on macOS) — verify TUI modal input mapping and backspace handling match crossterm semantics.
  • TOML (toml crate + serde)

    • Use toml::from_str / toml::to_string (or to_string_pretty) for parsing/serializing rules file; seeding a missing file by copying config/automation.example.toml then validating via automation::validate_rules is consistent with typical workflow. Ensure derived Serialize/Deserialize on types used for rules,.
  • Gmail API quotas (safety / apply implications)

    • Gmail API enforces quota units and per-minute/per-user/per-project limits; per-minute-per-project and per-minute-per-user-per-project limits (example page lists 1,200,000/min project and 6,000/min-user in table) and per-method quota unit costs (e.g., messages.modify, threads.modify consume quota units) — important for planning apply concurrency and rate-limiting when TUI triggers automation apply that issues Gmail mutations.
    • Docs recommend exponential backoff for time-based quota errors; confirm TUI/apply re-tries/backoff and concurrency (PR mentions concurrency limit of 4) align with these guidelines.
  • Practical gotchas & guidance observed in community sources

    • Ratatui Clear/popups: forum posts note Clear helps but rendering diffs and external stdout writes can cause artifacts; initializing/restoring terminal state before spawning $EDITOR and re-initializing Ratatui (as PR does) is correct to avoid terminal buffer corruption and flicker,.
    • Crossterm: multiple-thread reads cause “stealing” of input; use single-threaded event loop or central reader + dispatch, matching PR's queued terminal-action approach for editor launch is appropriate,.

Sources/tools used:

  • Ratatui docs and recipes (widgets, popup/centered layout, Clear) — Firecrawl firecrawl_search scraped pages above,,.
  • Crossterm event docs and issue thread — Firecrawl firecrawl_search,,.
  • toml crate docs (serde usage, to_string/from_str) — Firecrawl firecrawl_search,.
  • Gmail API quota page (quotas, per-method costs, backoff guidance) — Firecrawl firecrawl_search.
  • Context7 library resolution for ratatui (library id / docs availability) — Context7_resolve-library-id returned /ratatui/ratatui.

Comment thread src/tui.rs
Comment thread src/tui.rs
Comment thread src/tui.rs
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown
Owner Author

All actionable review threads have been addressed in pushed commits and resolved. Latest head is 58dcda3460a0d97f9c17f6f96a1a64cef4565130, with CI passing.

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Tip

For best results, initiate chat on the files or code changes.

@BjornMelin: Thank you for the update! I'll kick off a fresh review of the latest commit (58dcda3460a0d97f9c17f6f96a1a64cef4565130) now.

[review]

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tui.rs`:
- Around line 1279-1291: The function run_terminal_action currently ignores the
passed _paths and re-resolves workspace paths via
configured_paths(config_report) when handling
TerminalAction::EditAutomationRules; replace the redundant resolution by using
the provided paths parameter (rename _paths to paths if needed) and pass that to
edit_automation_rules_blocking, or if re-resolution is intentional add a comment
explaining why and keep the variable name; update references to
TerminalAction::EditAutomationRules, configured_paths,
edit_automation_rules_blocking and the function signature run_terminal_action
accordingly so the unused-parameter warning is resolved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: cea18c9b-31de-45e9-9156-d1e79014db7f

📥 Commits

Reviewing files that changed from the base of the PR and between e79de77 and 613b326.

📒 Files selected for processing (1)
  • src/tui.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: rust
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-05-07T23:34:50.823Z
Learnt from: BjornMelin
Repo: BjornMelin/mailroom PR: 23
File: src/tui.rs:61-67
Timestamp: 2026-05-07T23:34:50.823Z
Learning: When reviewing Rust TUI code using ratatui 0.30.0, do not flag `ratatui::try_init()` as missing a panic hook. In this version, `try_init()` installs a panic hook that restores the terminal (similar to `ratatui::init()`), but returns `Result` so callers can handle failures without panicking. In a CLI/TUI handler context (e.g., files like `src/tui.rs`), the correct pattern is to use `try_init()` and ensure terminal restoration via `TerminalGuard`’s `Drop` implementation rather than expecting `init()`-style panic behavior.

Applied to files:

  • src/tui.rs
🔍 Remote MCP Firecrawl

Summary of additional, review-relevant facts

  • Ratatui: popup/clear behavior

    • Use Frame::render_widget(Clear, area) to erase an area before drawing a popup; Clear only clears a buffer area and "cannot be used to clear the terminal on the first render" — use Terminal::clear for initial full-screen clears. Example popup pattern available in ratatui examples.,
  • Ratatui rendering gotchas

    • External stdout/stderr writes or other threads can cause buffer diffs/artifacts; Clear only affects ratatui's buffer and won't fix terminal-printed output. Community guidance recommends restoring/initializing terminal state before spawning external editors to avoid artifacts.
  • Crossterm event handling

    • crossterm::event::read() blocks until an Event is available; combine poll(Duration) + read() for non-blocking behavior. Avoid reading events from multiple threads — prefer a single reader or an async EventStream. (Docs + community guidance on EventStream vs read()).,
  • TOML (toml crate) serializing / seeding rules file

    • toml::from_str / toml::to_string or toml::to_string_pretty are the standard APIs for parsing/serializing with serde; to_string_pretty yields human-friendly formatting (available when serde feature enabled). Seeding a missing file by copying an example and then validating via the rules validator is consistent with common practice.
  • Gmail API quotas & safety guidance (relevant to apply behavior that issues Gmail mutations)

    • Quotas: per-minute-per-project = 1,200,000 quota units; per-minute-per-user-per-project = 6,000 quota units. Per-method quota unit costs are listed (e.g., messages.modify 5, messages.batchModify 50, messages.send 100, threads.modify 10). Apply work that issues many mutations must respect these limits and per-method costs.
    • For time-based quota errors Google recommends (truncated) exponential backoff and provides an example algorithm; consider backoff and rate-limiting when TUI apply triggers automation apply operations.

Sources consulted

  • Ratatui popup and Clear docs and examples; forum discussion on Clear/terminal artifacts.,,
  • Crossterm read/poll and EventStream docs/discussion.,
  • toml crate docs (to_string / to_string_pretty).
  • Gmail API quotas (limits, per-method costs, backoff guidance).
🔇 Additional comments (12)
src/tui.rs (12)

684-699: Refresh not called on error paths.

This issue was identified in a previous review and appears to still be present. The refresh_automation() call on line 691 only runs on the success path. Per the PR objective to "refresh automation data after validate/suggest/run/apply," the rollout snapshot should be refreshed on both success and failure paths to ensure the readiness panel stays consistent.


877-883: Error message still says "invalid TOML" for all validation failures.

This issue was identified in a previous review and appears to still be present. Line 882 sets status to "automation rules edit returned invalid TOML" but validate_rules() can fail for semantic reasons after successful TOML parsing. Consider using "automation rules edit returned invalid rules" or similar generic wording.


739-749: Block APPLY unless the loaded run is still in preview status.

This issue was identified in a previous review and appears to still be present. The function only checks that a persisted run is loaded but doesn't verify that report.detail.run.status == AutomationRunStatus::Previewed. If an operator loads an already-applied run, the TUI would still present the APPLY confirmation flow rather than blocking it.


64-70: LGTM!

The terminal action handling correctly restores the terminal before spawning the editor, then reinitializes ratatui after the editor exits. Using take() ensures the action is only executed once. This follows the recommended pattern for external process spawning in TUI applications.


98-106: LGTM!

The new automation state fields follow the established pattern from workflow state management, providing consistent UX for candidate selection and scrolling.


1326-1349: LGTM!

Good editor resolution pattern: check VISUAL first, then EDITOR, with sensible platform-specific defaults (vi on Unix, notepad on Windows). The let-chain syntax for checking both the env var result and non-empty value is clean.


1373-1420: LGTM!

The shell-like command parsing correctly handles single and double quotes, backslash escapes (including escaped quotes within quoted strings), and whitespace tokenization. The unterminated quote detection provides a helpful error message.


1245-1265: LGTM!

The push/pop functions now match each variant explicitly with its own field name (limit_text, run_id_text, confirm_text), which is clearer than the previous aliased binding approach noted in past reviews.


1632-1668: LGTM!

Automation view key bindings follow the established pattern and provide intuitive shortcuts: j/k for navigation (matching vim conventions), v for validate, g for suggest (mnemonic: "generate"), n for new run, o for open/show, a for apply, and e for edit.


2439-2468: LGTM!

The ApplyRun modal provides comprehensive context for the destructive operation: run ID, candidate count, action mix, blocked rules, and a clear Gmail mutation warning. This aligns with the PR objective to show "run id, candidate count, action mix, blocked rules, and Gmail mutation warning" before apply.


3781-3826: LGTM - but consider adding a test for blocking already-applied runs.

This test correctly verifies that apply requires a loaded run and APPLY confirmation. However, it doesn't cover the scenario where the loaded run has status Applied instead of Previewed. Consider adding a test case that loads an already-applied run and verifies the modal doesn't open (once the status check mentioned in the past review is implemented).


3868-3893: LGTM!

Good test verifying that the seeding function respects custom workspace configuration and creates the rules file in the configured runtime root rather than the default location.

Comment thread src/tui.rs
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tui.rs`:
- Around line 64-70: After reinitializing the Ratatui terminal (the line with
terminal = ratatui::try_init()?) add a call to clear the terminal buffer
(terminal.clear()) before proceeding to app.handle_terminal_action_result so
that leftover content from the external editor doesn't flash; update the block
where app.pending_terminal_action is taken, run_terminal_action is called, and
the terminal is reinitialized (terminal = ratatui::try_init()) to invoke
terminal.clear() immediately after reinit and before awaiting
app.handle_terminal_action_result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: a5143751-f6fd-4855-b002-99911643fc97

📥 Commits

Reviewing files that changed from the base of the PR and between 58dcda3 and 0545d69.

📒 Files selected for processing (2)
  • src/handlers/tui.rs
  • src/tui.rs
📜 Review details
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-05-07T23:34:50.823Z
Learnt from: BjornMelin
Repo: BjornMelin/mailroom PR: 23
File: src/tui.rs:61-67
Timestamp: 2026-05-07T23:34:50.823Z
Learning: When reviewing Rust TUI code using ratatui 0.30.0, do not flag `ratatui::try_init()` as missing a panic hook. In this version, `try_init()` installs a panic hook that restores the terminal (similar to `ratatui::init()`), but returns `Result` so callers can handle failures without panicking. In a CLI/TUI handler context (e.g., files like `src/tui.rs`), the correct pattern is to use `try_init()` and ensure terminal restoration via `TerminalGuard`’s `Drop` implementation rather than expecting `init()`-style panic behavior.

Applied to files:

  • src/handlers/tui.rs
  • src/tui.rs
🔍 Remote MCP Firecrawl

Summary of additional, review-relevant facts (from Firecrawl searches)

  • Ratatui provides an explicit recipe for spawning an external editor from a TUI: leave alternate screen, disable raw mode, run child Command (blocking), re-enter alternate screen, enable raw mode, then call terminal.clear() to avoid redraw artifacts. Example code and rationale are in the Ratatui "Spawn External Editor (Vim)" recipe.

  • Ratatui docs + recipes emphasize using panic hooks / cleanup to restore terminal state (disable raw mode + leave alternate screen) so the terminal isn't left corrupted after panics; common pattern shown in Ratatui "Setup Panic Hooks".

  • Crossterm (ratatui's typical backend) documents the alternate screen and raw-mode APIs and provides enable/disable raw mode and Enter/LeaveAlternateScreen primitives that match the TUI→editor flow; there are platform-specific raw-mode gotchas discussed in Crossterm issues (Windows vs UNIX differences). Reviewers should confirm cross-platform behavior in tests.,

  • For seeding/writing TOML rules files: the official toml crate exposes toml::to_string_pretty (requires serde feature) to serialize config structs to a human-friendly TOML string—useful for seeding .mailroom/automation.toml then writing to disk. Community guidance also shows common patterns to write/serialize TOML files.,

  • Gmail API specifics relevant to "apply" safety and scale:

    • users.messages.batchModify supports up to 1000 message IDs per request (server-side limit).
    • Gmail per-method quota table lists quota units per call; messages.batchModify is shown as costing 50 quota units per request (monitor per-minute-per-user and per-minute-per-project quotas). Reviewers should note rate/quotas and recommend instrumentation or backoff for large applies.
    • Community/StackOverflow threads warn that batchModify behavior and quota accounting have nuances; monitor quotas in CI/ops.,

Relevant implications for this PR review (concise)

  • Editor launch approach in src/tui.rs (restore terminal → spawn editor → reinitialize terminal → terminal.clear()) matches Ratatui recipe and panic-hook guidance — verify implementation calls terminal.clear() and installs/uses panic-hooks or equivalent cleanup to avoid terminal corruption.,

  • Cross-platform raw-mode/alternate-screen differences exist; ensure tests exercise editor flow on supported platforms or that code handles platform-specific edge cases documented in Crossterm issues.,

  • TOML seeding/serialization: prefer toml::to_string_pretty (serde feature) when seeding .mailroom/automation.toml so the rules file is readable; confirm code enables serde feature and handles file I/O errors.

  • Gmail apply safety/scale: applying saved runs that map to many Gmail mutations must consider:

    • the 1000-id-per-request batchModify limit;
    • messages.batchModify per-request quota unit cost (50 units) and per-minute quotas (e.g., 6,000 per-minute-per-user per-project); and
    • need for exponential backoff/monitoring to avoid quota exhaustion during large applies. Recommend CI/ops tests or instrumentation to observe quota impact for typical runs.,

Tools/sources used

  • Firecrawl (firecrawl_search) — ratatui recipes (spawn-vim, panic-hooks), Crossterm docs & issue, toml docs and examples, Gmail API batchModify and quota docs, relevant community/StackOverflow threads.
🔇 Additional comments (5)
src/handlers/tui.rs (1)

10-13: LGTM!

The handler correctly derives workspace paths from the resolved config, ensuring the TUI operates with configured paths (e.g., custom runtime_root) rather than falling back to defaults. This aligns with the PR objective of honoring configured paths for terminal actions.

src/tui.rs (4)

741-758: LGTM!

The apply modal correctly enforces the review-first safety model: it requires both a loaded persisted run and verifies the run is still in Previewed status before presenting the destructive APPLY flow. This addresses the PR objective to block apply for already-applied or non-preview runs.


1302-1326: LGTM!

The editor launch flow correctly: seeds the rules file from the tracked example when missing, resolves the editor command from $VISUAL/$EDITOR with platform-appropriate fallbacks, and validates the editor exit status before reporting success. Error messages include helpful context (editor program, rules path, and underlying error).


2447-2476: Apply modal shows comprehensive safety context.

The confirmation modal for AutomationModal::ApplyRun correctly displays the run ID, candidate count, action mix, any blocked rules from the rollout snapshot, and prominent Gmail mutation warnings (red text). This satisfies the PR objective to require explicit confirmation showing sufficient context before destructive operations.


3789-3856: Good test coverage for apply safety gates.

The tests verify both required safety conditions:

  1. automation_apply_requires_loaded_run_and_apply_confirmation checks that apply is blocked without a loaded run and requires exact APPLY confirmation.
  2. automation_apply_blocks_non_preview_runs confirms that already-applied runs cannot be re-applied.

This fulfills the PR objective to add tests for confirmation gates, blocked-apply state, and prevention of direct-rollout-apply.

Comment thread src/tui.rs
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@BjornMelin BjornMelin merged commit 494ce4e into main May 8, 2026
3 checks passed
@BjornMelin BjornMelin deleted the feat/tui-automation-apply-rules branch May 8, 2026 03:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(tui): add automation apply and rules editing

2 participants