You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
From-popup menu enumeration now polls for a populated menu (#296, the menu-layer sibling of #295, found by its live re-smoke). Under in-process NSAppleScript the popup's menu can evaluate EMPTY right after click (the identical matcher passes under osascript — same class as the documented in-process front window unreliability), so the for-in enumerated zero items and mis-reported SENDERPOPUP: no From account exactly matches. The script now polls (bounded 12×0.3s) for count of menu items > 0, re-clicks ONCE on a still-empty menu and polls again, and enumerates by guarded index (the #295 pattern); total failure keeps the fail-closed sentinel, whose message now discloses the menu count seen. Live-verified end-to-end (2026-07-22, direct binary drive): create_draft with from_address returned Draft created successfully (mailto path) [sender verified via From popup: d06227105@ntu.edu.tw] and the saved draft's sender matched — the #219 clean-body + verified-custom-sender combination delivered live for the first time (v2.23.0 raw -2700 → c82ec50 scan guard → this menu poll). 1026 tests.
Fixed
Verified sender-popup identifies the From control by AXIdentifier + matches Mail's real value format — #219's clean path finally works safely (#219, reopened). A cross-model re-verify (Codex BLOCKING) of the format fix below caught a deeper hole: the From popup was discovered by "the pop-up-button whose value contains @", which a signature popup named like an email could satisfy — the poll could then lock onto it and pass a self-consistent select + read-back on the WRONG control while the real From stayed on the default account (wrong-account send). A live AX dump showed every compose-window popup carries a stable, locale-independent AXIdentifier (popup_priority / popup_from / popup_signature), so the From popup is now identified by AXIdentifier = "popup_from" — deterministic, #174-safe, and structurally immune to a signature-popup mix-up (the _fromPopupCount value-@ heuristic is gone). Combined with the en-dash format fix (below) and the #296 menu-population poll, the clean path selects + verifies the correct account or fails closed to legacy. A live smoke (once #295 removed the -2700 crash masking it) + an AX dump of a real compose window revealed the blind spot behind #219's entire cross-model verification: Mail's From popup renders Display Name – addr@domain — a SPACE + EN DASH (U+2013) + SPACE separator, no angle brackets (e.g. 鄭澈 Che Cheng – che830621@as.edu.tw). Every round of Codex R2→R5 + 2 Claude lenses had reasoned about senderMatches against an assumed Name <addr> form, so branches _label is _addr and _label ends with "<addr>" never matched the real value → the clean path silently fell to legacy on every account (unit tests + static analysis structurally can't see this — only a live smoke against real Mail can). Fix: senderMatches gains a separator-agnostic branch — the addr is the LAST space-delimited token of the label (isSimpleAddrSpec gates the addr to no-whitespace upstream, so a simple addr is always that final token), compared with exact is (anti-spoof preserved: a … – notche@x label's last token is notche@x ≠ che@x; a …@as.edu.tw.evil.com last token ≠ …@as.edu.tw — verified against the real value + spoof/subdomain/hyphen/bare/angle cases in isolation). Also a bounded poll (12 × 0.3s) before the scan, because the From popup value is empty for a beat after the compose window opens (an early scan got SENDERPOPUP: From popup not found). Unit-locked (script must carry the AXIdentifier discovery + last-token match + poll); the match logic verified live against the exact popup value (bare / angle / en-dash / hyphen + spoof / subdomain cases), the AXIdentifier discovery grounded in the live AX dump, and the AXIdentifier hardening re-verified by Codex (PASS — the value-based wrong-control path is structurally gone). The full clean-body + verified-custom-sender pipeline is confirmed live end-to-end (see #296 — create_draft returned [sender verified via From popup: …] and the saved draft's sender matched).
From-popup scan no longer leaks a raw -2700 on a settling AX tree (#295, regression from the #219-verify-R4 exactly-one-popup change). A live smoke of v2.23.0's verified sender-popup (driving the notarized binary against a real Mail.app) caught it: create_draft with a custom from_address fell to legacy with AppleScript error (-2700): … Can't get item 2 of every pop up button … Invalid index. — the popup scan's repeat … in (pop up buttons of _w) re-fetches item N each pass, and a compose window whose AX tree is still settling (or a degraded/slow Mail) throws from that item-fetch OUTSIDE the inner try, crashing the whole clean path (the invariant still held — draft created under the correct account, wrapped body + disclosed — but #219's clean body wasn't delivered). The R4 change had removed the original exit repeat (which stopped at item 1, never reaching item 2), exposing this. Fix: snapshot the popup count once (count of pop up buttons of _w) and fetch each by guarded index (pop up button _pbi of _w inside the try), so an unstable/vanished index is skipped → the scan fails closed to a clean SENDERPOPUP → legacy, never a leaked -2700. Static + unit locked (the generated script must use the indexed guarded form, not the bare collection loop). Live re-smoke required when Mail is healthy — the AX-instability path is GUI-timing, not unit-coverable.