ReviewOS

also looking at this

craft-native/craft

fix(ios): give getPendingNotifications a deadline, on the shared block table

#247
Merged glennmichael123 wants to merge fix/ios-notification-deadlines into main
2 files +164 -60
9 days ago

Refs #223 — the first of its six actions, on the table #245 extracted.

The action

getPendingNotifications is answered only by getPendingNotificationRequestsWithCompletionHandler:. No person is involved, and nothing settled the call if that completion never fired.

It could not simply take a deadline, which is what #223 spends most of its length on: the module kept a side table keyed by reply-slot index, so a deadline that freed slot k let the next call lease slot k and receive the same block, and the first call's late completion would then answer the second with the first one's notifications.

It now parks on ios_pending.Table(Sels), and the blocks are indexed per block rather than per reply slot — 32 of them rather than 16, so every slot can be waiting while as many blocks again are still owed a completion that has not come.

10 s. Comfortably under the 30 s the page's own _invoke allows, so the caller hears this answer rather than its own timeout. A completion arriving after it is logged with how late it was and ignored; a block with no call recorded is a stray and says so.

A ratchet for the remaining five

a module parks calls on ios_pending.Table and never calls scheduleDeadline.
  A parked call whose completion never comes settles nothing at all.

Parking makes a late completion harmless. It does not make one that never comes answer. Both halves or neither — and as the rest of #223 lands, this is what stops the second half being forgotten.

I added it because a mutation exposed the gap in my own work: removing the scheduleDeadline call passed every test. Nothing asserted the deadline was armed at all, and a host test cannot observe dispatch_after_f without a main queue. The scan is what closes that, and it now fails the mutation.

mutationfails
the deadline is never armedthe new ratchet (passed everything before it existed)
every call gets the same blockthe module's own block tests

What is deliberately not here

scheduleNotification stays on the old side table. It is two stages, and #223 is explicit that its deadline has to start after the authorization prompt rather than at dispatch — a prompt has a person in front of it and must not be timed out. That is a different shape and gets its own change, along with getHealthData, saveHealthWorkout, openSettings and openURL.

openSettings will need the most care: the app is backgrounded while Settings is open, a main-queue deadline does not run while suspended, and a naive one would report TIMEOUT for an open that succeeded.

A local toolchain note, unrelated to this change

bun run test currently fails on this machine, and not because of anything here: the local Zig moved from 0.17.0-dev.1441+d5181a9c9 to 0.17.0-dev.2163+89ff10d56 during the session, and the external zig-js library no longer compiles against it (expected optional type, missing struct field: pointer_stability in its compiler.zig, value.zig and vm.zig).

Confirmed pre-existing: zig build test-js fails the same way on a clean main with these changes stashed, and zero of the errors are in craft's own sources. CI pins its own toolchain, so it is unaffected — but anyone running the suite locally will hit it until zig-js catches up or the toolchain is pinned back.

Verification

zig build test:ios (which covers this module), Pickier (0 errors), and the mutations above. zig build test is blocked locally by the zig-js issue described above, not by this change.

2 changed files on the files tab, with 0 review threads.

Sign in to comment on this pull request.