ReviewOS

craft-native/craft

fix(ios): Zig actions that wait on a framework completion have no deadline, and cannot safely get one yet

#223
Closed glennmichael123 opened this 10 days ago ·
10 days ago

#211 gives removeSiriShortcut a native deadline, because its only answer came from a framework completion that sometimes never arrives. Several other actions served by Zig have the same shape: no person is involved, the only answer is a completion or delegate call from a system daemon, and nothing else settles the call if it never comes.

actionwhere it waitsnotes
getPendingNotificationsbridge_mobile_notifications.zig, answered only in pendingCompletionFired
scheduleNotificationthe stage after authorization (addNotificationRequest:)start the deadline after the prompt, never at dispatch
getHealthDatabridge_mobile_health.zig, HKStatisticsQuery
saveHealthWorkoutthree chained healthd completions
openSettingsbridge_mobile_permissions.zig, the openURL: completionthe app is backgrounded while Settings is open, and a main-queue deadline does not run while it is suspended, so a deadline could report TIMEOUT for a successful open
openURLbridge_mobile_system.zig, the openURL: completionborderline: tel: and facetime: show a confirmation

Why this is not just "call ios_async.scheduleDeadline"

Each of these keeps a side table read by reply-slot index alone: takeCall, takeSettingsCall, takePendingCall, takeScheduleCall. A deadline that releases slot k lets the next call lease slot k, and the first call's late completion then answers the second one with its own result.

#211 solved this for Siri by separating completion blocks from reply slots. A block answered by the deadline is kept owed, and never handed to another call, until its completion arrives. The same design, or a completion that carries the whole ticket, is needed here before any deadline is safe.

Also found in the same files: failures after the lease

  • openSettings looks up its selector after publishing the call (bridge_mobile_permissions.zig).
  • getHealthData resolves classes and selectors after publishCall.
  • The HealthKit stage chain has sel_registerName(...) orelse return; after taking the call. That releases neither the parked reply nor the slot.

#211 moved every fallible step above acquire in Siri for the same reason.

The slice fixture

page.m's __craftBridgeError handles a location TIMEOUT only for i=112. A deadline answering i=110 or i=111 would be dropped, and the harness would stall on the ids after it. SFSpeechRecognizer requestAuthorization: and AVAudioSession requestRecordPermission: also gate awaited ids with no deadline, although a real app puts a person in front of those.

10 days ago

Reopened: this was closed by accident, not by decision.

#251's description had a heading reading "Proposal: close #223 with this merged", and close #223 is a GitHub closing keyword, so merging #251 closed this issue automatically. Whether to close it had been put to the maintainer as an open question and had not been answered.

Where it stands:

  • Four of six actions have a deadline: getPendingNotifications (#247), scheduleNotification (#248, armed after the grant), getHealthData and saveHealthWorkout (#250, the chain re-arming per stage).
  • Two deliberately have none, with the reason at each call (#251):
    • openSettings suspends the app while the uptime clock runs on, so a deadline shorter than the visit answers TIMEOUT for an open that succeeded.
    • openURL leases no reply slot — its request id travels in the block — so this issue's concern does not apply, and a deadline would time out someone deciding on a tel: call.
  • The groundwork: #245 (the shared table), #249 (the per-claim ratchet), and every fallible step listed here resolving before its lease.

Close it if those two exclusions are agreed; otherwise it stays open for them.

10 days ago

Closing, as agreed.

Four of the six actions now have deadlines, and each is registered on the shared block table (ios_pending) so a late completion can't answer a newer call:

  • the notification reads, in #247
  • scheduleNotification, in #248, with the clock starting only after the person answers the authorization prompt
  • getHealthData and saveHealthWorkout, in #250, re-armed at every stage of the workout chain

openSettings and openURL deliberately have none, and #251 documents why in code. openSettings' completion races app suspension, so a deadline would answer while the person is still in Settings. openURL leases no reply slot for a deadline to free. The ratchet from #249 makes any new parked call either set a deadline or say why it doesn't.

Sign in to comment on this issue.