Fix i18n gaps in Mail integration; correct stale beta-bug messaging
Localize mailAccessNote and AppleMailService's account-count string
(was a manual singular/plural literal, now uses inflect syntax). Also
correct the requestAccess() doc comment and the suspectedPlatformBug
fallback message, both of which still asserted "known macOS 27 beta
issue" — that diagnosis was wrong (see 6b4448d): the real cause was a
missing entitlement, already fixed. The instant-failure heuristic stays
as a defensive fallback, just no longer misattributed.
This commit is contained in:
@@ -101,24 +101,23 @@ final class AppleMailService {
|
||||
/// Triggers the real macOS "Confab wants to control Mail" Automation permission prompt if
|
||||
/// the user hasn't been asked yet (a no-op if already granted or denied).
|
||||
///
|
||||
/// Live-verified (2026-08-19, several rounds with Rune): the prompt never appears on this
|
||||
/// machine (macOS 27 beta) for Confab specifically — not a threading bug (tried direct call,
|
||||
/// `DispatchQueue.main.async`), not the wrong API (tried `AEDeterminePermissionToAutomateTarget`
|
||||
/// AND a real Apple Event via `runHandler`, both fail identically), not a build/signing issue
|
||||
/// (verified the installed app's signature, team ID, Info.plist key, and even a notarized
|
||||
/// build — all correct), and not an OS-wide Automation outage (Terminal → Mail works fine).
|
||||
/// Every failure returns in single-digit milliseconds — far too fast for a real dialog to have
|
||||
/// been shown and answered. This matches an already-documented macOS 27 beta bug in this same
|
||||
/// project (`EKEventStore.requestFullAccessToEvents()`/`CNContactStore.requestAccess()` failing
|
||||
/// identically for Calendar/Contacts while Reminders/Location work fine) — a category of
|
||||
/// TCC-gated permission requests that this OS beta just never prompts for from third-party
|
||||
/// apps, regardless of what the app does.
|
||||
/// History (2026-08-19 through 2026-08-26): this prompt appeared to never show on Rune's
|
||||
/// machine (macOS 27 beta), with every attempt failing in single-digit milliseconds — far too
|
||||
/// fast for a real dialog to have been shown and answered. Four rounds of investigation ruled
|
||||
/// out threading, the wrong API, and a build/signing issue, converging on "genuine macOS 27
|
||||
/// beta OS bug" (matching an apparently identical Calendar/Contacts failure elsewhere in this
|
||||
/// project). **That diagnosis was wrong.** Checking `tccd`'s own unified log directly (instead
|
||||
/// of trusting the pattern-match to the Calendar/Contacts case) showed the real reason:
|
||||
/// `Confab.entitlements` was missing `com.apple.security.automation.apple-events`, so `tccd`'s
|
||||
/// hardened-runtime policy refused to even prompt. Adding that entitlement fixed it —
|
||||
/// live-verified granting successfully on beta 7. See `feedback_tccd_log_before_os_bug_diagnosis`
|
||||
/// in project memory for the standing lesson this produced.
|
||||
///
|
||||
/// Given that, this still attempts the real thing first (the way it *should* work, and will
|
||||
/// once the OS bug is fixed) via the same `runHandler` path `mail_list_accounts`/
|
||||
/// `testConnection()` use, but times the attempt and treats an implausibly-fast failure as the
|
||||
/// known platform bug rather than a real denial — callers can then fall back to sending the
|
||||
/// user straight to System Settings' Automation pane instead of a dead-end "nothing happened."
|
||||
/// The instant-failure heuristic below is kept as a defensive fallback (not dead code) in case
|
||||
/// a future regression — a missing entitlement again, a stuck TCC denial state, or a genuine
|
||||
/// new OS issue — reintroduces the same symptom: it distinguishes "no dialog was ever shown"
|
||||
/// from a real, human-timed denial, and routes the former to System Settings instead of a
|
||||
/// dead-end "nothing happened."
|
||||
@discardableResult
|
||||
func requestAccess() async -> MailAccessOutcome {
|
||||
Log.mail.info("requestAccess: called — attempting a real Apple Event (listAccounts) to trigger the OS consent prompt")
|
||||
@@ -717,7 +716,7 @@ final class AppleMailService {
|
||||
}
|
||||
}
|
||||
let namesSuffix = names.isEmpty ? "" : ": \(names.joined(separator: ", "))"
|
||||
return .success("Connected \u{2014} found \(count) account\(count == 1 ? "" : "s")\(namesSuffix)")
|
||||
return .success(String(localized: "Connected \u{2014} found ^[\(count) account](inflect: true)\(namesSuffix)"))
|
||||
case .failure(let error):
|
||||
let message: String
|
||||
switch error {
|
||||
|
||||
@@ -1178,12 +1178,14 @@ It's better to admit "I need more information" or "I cannot do that" than to fak
|
||||
mailAccessState = .denied
|
||||
mailAccessNote = nil
|
||||
case .suspectedPlatformBug:
|
||||
// Known macOS 27 beta issue (see AppleMailService.requestAccess doc
|
||||
// comment) — the OS never shows the consent dialog for this app, so
|
||||
// there's nothing more to try in-app. Send the user to System Settings
|
||||
// directly rather than leaving the button looking like it did nothing.
|
||||
// Defensive fallback, not the expected path anymore — see
|
||||
// AppleMailService.requestAccess doc comment. The one confirmed real
|
||||
// cause (a missing entitlement) was fixed 2026-08-26; this still
|
||||
// triggers if some future issue reproduces the same instant-failure
|
||||
// symptom, so there's nothing more to try in-app but sending the user
|
||||
// to System Settings.
|
||||
mailAccessState = .denied
|
||||
mailAccessNote = "macOS isn't showing the permission prompt (a known macOS 27 beta issue) — opened System Settings instead. If Confab isn't listed there under Automation, this can't be granted until Apple fixes it."
|
||||
mailAccessNote = String(localized: "macOS isn't showing the permission prompt — opened System Settings instead. If Confab isn't listed there under Automation, try quitting and relaunching Confab, or check Settings → MCP → Mail again after a moment.")
|
||||
openPrivacySettings(anchor: "Privacy_Automation")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user