Skip to content

v2.23.1

Choose a tag to compare

@kiki830621 kiki830621 released this 22 Jul 01:03

Fixed

  • 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@xche@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 #296create_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.