# Thunderbird local mail and composition This slice covers a synthetic local mailbox, folder/message-list navigation, opening and returning from a message tab, unsent HTML and plain-text composition, replies/reply-all, inline forwarding, attachment saving/adding, and multiple message selection. The separate [Mozilla reading baseline](mozilla-reading.md) covers Firefox pages and saved Thunderbird messages. Page-load summaries and automatic Read All remain separate feature work. ## Changes and boundaries Thunderbird can register a GTK accessibility application before replacing it with its Gecko application while keeping the same X11 client. Previously the reader could retain the GTK frame and reject real folder/message focus events. Foreground ownership now accepts a replacement only after fresh active/showing state, process and geometry checks, and bounded window enumeration. The candidate's parent application must still be registered on the accessibility desktop; its current window list must include the candidate and exclude the old owner. Existing same-process siblings cannot take ownership. Retained focus and document references belonging to the retired frame are released on the native owner thread. Unknown or incomplete queries reject replacement. The composer keeps native focus on its editable web document while paragraphs emit text, caret and selection events. Previously those insertions were rejected as outside the focused editor; subsequent caret events spoke the growing line, and selection feedback was missing. Native capture now copies the nearest editable-document identity. Paragraph events belong to that document only while it owns focus. They use ordinary typing, deletion, selection, clipboard and Braille presentation. Focus stays on the editor, while the current paragraph provides text and cursor/routing metadata. Moving to Subject or another editor revokes the relationship immediately. A nested read-only document is a boundary. These are shared AT-SPI and event ownership changes. No Thunderbird-specific application-name, window-title or widget-label matching selects production behavior. Orca's Thunderbird editable-message handling and shared web/focus utilities were used as behavioral references. Automatic title changes no longer repeat the focused editor's text during typing, deletion or clipboard edits when the rest of the title stays the same. This uses owned editable focus and recent input, with matching title prefix and suffix. Both AT-SPI and X11 title sources use the same check. Window introductions, unrelated status changes, empty values and ambiguous matches keep their existing behavior. There is no application-name or Subject-label exception. The new recorded-speech assertion reproduced the title echo on the pre-fix reader. ## Automated checks ```sh go build -o /tmp/cthulhu-mozilla-review ./cmd/cthulhu CTHULHU_BINARY=/tmp/cthulhu-mozilla-review /usr/bin/python3 tests/native_thunderbird.py ``` The harness requires Thunderbird, i3, Xvfb, xdotool, D-Bus and Python with pyatspi. It starts a private reader before Thunderbird, with its own display, session/accessibility buses, SSIP recorder, profile and configuration. It seeds Inbox and Archive mbox files, a synthetic local identity, a Cc recipient and a plain-text MIME attachment. No mail credentials or SMTP server are configured and no send command is used. Pass `--format html` or `--format plain` to select one run. Each run checks native focus and recorded speech for: - Folder Home/End and Down navigation, including returning to Inbox. - F6/Shift+F6 between the folder tree and message list, retaining the row. - Up/Down through messages, with native selection and spoken row roles. - Shift+Down/Shift+Up to extend/shrink message selection; Ctrl+Down to move without extending it; Ctrl+Space to add/remove the focused message. Native selected rows must match at each step, and state changes must speak. - Enter to open the selected message in a tab, Ctrl+Home to read its body, Ctrl+W to return to the selected row, and Down to the following message. - Tab from the message body to its attachment bar, Enter to expand the list, and Shift+F10/Down through Open and Save As. Save the received attachment into the evidence directory and verify its contents, then return to the selected message row. - Ctrl+R/Ctrl+Shift+R/Ctrl+L for reply, reply-all and inline forward, with expected Subject and quoted body. Replies retain the sender address chip; reply-all also retains Cc. Forwarding includes recipient entry and Tab to the body. Type into each body, close it, focus Discard changes and confirm return to the selected message. These messages are never sent. - Ctrl+M, recipient typing and committing its address chip, then Subject. - Subject character echo and Backspace without repeated composer titles. - Tab from Subject to the editable body; H reaches the editor as typed text. - Character echo and Backspace, two-line body input, Ctrl+Home/Down reading, selected-word speech and native text selection, and deletion of that word. - Shift+Tab/Tab between the body and Subject. - Ctrl+Shift+A to open the file picker, attach a generated local file, check the selected attachment row and its speech, Escape to clear selection, and a second Escape back to the body. Initial message-list focus need not select the first row: Thunderbird can expose a focused but unselected row until a navigation key selects it. The harness requires selection after Up/Down, rather than treating initial focus as selection. The parent document can expose a selection as embedded-object placeholders; the native selection assertion checks the selected paragraph text instead. The harness ignores hidden duplicate controls in retained tabs and inspects both Thunderbird accessibility applications and the GTK desktop portal's file dialogs. Attachment row names can separate the filename and extension with a space; their descriptions retain the complete filename. File-picker paths and saved content are checked separately from recorded speech. Printed evidence directories retain the profile, mailbox fixtures, settings, reader/application/session logs, `tree.json`, `speech.json` and `report.json`. Successful HTML and plain-text runs were verified with Thunderbird 158.0, with 60 workflow checks in each format. The tests disable Braille; the event-loop tests separately check paragraph Braille cursor and routing metadata. Run the shared regression checks as well: ```sh go test -race ./internal/atspi ./internal/app ./internal/review ./internal/presentation -count=1 -timeout=120s go vet ./internal/atspi ./internal/app ./internal/review ./internal/presentation python3 tests/native_firefox.py python3 tests/check_speech.py CTHULHU_BINARY=/tmp/cthulhu-mozilla-review /usr/bin/python3 tests/native_mozilla.py CTHULHU_BINARY=/tmp/cthulhu-mozilla-review /usr/bin/python3 tests/native_ownership.py CTHULHU_NATIVE_BROWSER_TESTS=editing,selection,modes python3 tests/native_browser.py ``` These cover Firefox tabs/address focus and native metadata, Firefox/Thunderbird reading and Read All, GTK/Qt controls and dialogs, same-process overlapping window ownership, workspace return, and Chromium editing/selection/focus modes. Passing the new tests alone does not establish that these existing behaviors still work. ## Human review and live acceptance Review the diff and test the rebuilt reader before submission, under the [contribution policy](../../CONTRIBUTING.md#ai-assisted-contributions). Recorded SSIP and synthetic X11 input establish requested behavior, not audible speech, physical input, a physical Braille display or native Wayland acceptance. 1. Start Thunderbird with the rebuilt reader already running. In a test mailbox, use arrows, Home/End, expansion/collapse, F6 and Shift+F6 across folders and message rows. Check sender, subject, unread/read state and selected rows. 2. Open a message, read its headers and body, return to the list and switch folders. Check that focus and reading position belong to the current message. 3. Create an unsent HTML message. Type and commit a recipient, Tab to Subject, and type slowly, pause, then use Backspace and paste text. Confirm ordinary echo without repeated composer titles. Clear Subject completely; the empty subject title can still announce. Tab to the body and confirm line/word movement, selection, Backspace/Delete, cut/paste, and header/body return with Tab/Shift+Tab. Repeat in plain text. Check speech and Braille text, selection, cursor and routing. 4. Select several messages with Shift+arrows, move without changing selection with Ctrl+arrows, and toggle rows with Ctrl+Space. Check announced selection state and matching Braille, then return to single selection and open a message. Try a larger folder and nonadjacent selections in a test mailbox. 5. Reply, reply-all and forward a test message without sending it. Verify recipients, Cc, Subject, quoted content and ordinary body editing. Close the composer, inspect the save/discard/cancel prompt, cancel once to return to editing, then discard and verify the original selected message. 6. Tab to a received attachment, expand its list, inspect the context menu, and save a harmless test file to a chosen directory. Verify the saved file. Add a local file to an unsent message with Ctrl+Shift+A, check its filename and selection, then Escape to clear selection and Escape again to return to editing. Also check removal, multiple attachments and other file types; those exceed the automated fixture. 7. Move from the body to Subject, another window or another message. Old body activity must not interrupt the newly focused control. Switch between multiple Thunderbird windows and ordinary Firefox and Chromium windows. 8. Recheck Firefox tab creation/switch/close and address editing; Chromium editing and selection; GTK/Qt menus and dialogs; and empty-workspace return. Remote accounts, sending, forwarding as an attached message, external attachment opening, attachment removal, larger/nonadjacent selections, real mailbox performance and physical speech/Braille remain outside this automated local baseline. Page-load summaries and automatic Read All remain separate features.