ReviewOS

craft-native/craft

bridge_mobile_locrecording.zig's stated blockers have expired: two of three no longer hold

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

bridge_mobile_locrecording.zig's module comment argues at length that the five lifecycle recording actions cannot move to Zig. Two of its three blockers have since been removed by other work, and nothing re-checked the argument. This is the same failure mode as #110 and #114 — a reason recorded in prose, outliving the thing it described.

The five actions are startLocationRecording, pauseLocationRecording, resumeLocationRecording, stopLocationRecording, getLocationRecordingState. They are rows in the deliberate_deferrals table in packages/zig/test/ios_conformance_test.zig.

Blocker 1 — "a flag with no mirror" — expired

packages/zig/src/bridge_mobile_locrecording.zig:167 says startLocationRecording is behind config.enableGeolocation, "a flag with no mirror anywhere in packages/zig/src", and concludes that serving it would mean writing a location track in an app that disabled geolocation.

packages/zig/src/ios_config.zig now reads craft.config.json — the same bytes Swift decodes — and exposes exactly that flag at ios_config.zig:141 (.geolocation => "enableGeolocation"). Its own header states it closes this gap, and names this very note as one of the two occurrences it closes (ios_config.zig:5-7). It also singles out startLocationRecording as one of only five gated Swift cases that answer CAPABILITY_DISABLED properly rather than hanging (ios_config.zig:47), so the gated reply shape is already settled.

Blocker 2 — "an event channel that does not exist" — expired, wrong enum

bridge_mobile_locrecording.zig:190 says the recorder's live samples go out as craftLocationUpdate, that capabilities.Channel has no such member, and that .location_update is "craft:location:update" — "which no iOS page listens for".

That is true of capabilities.zig:165, but it is not the enum the iOS event path uses. ios_events.Event.location_update is "craftLocationUpdate" (ios_events.zig:65, pinned by a test at ios_events.zig:259), and bridge_mobile_location.zig:1249 already emits on it for the shipped watchPosition. The channel the paragraph calls missing is in use one module away.

Blocker 3 — the summary's memory-vs-file divergence — real, and portable

bridge_mobile_locrecording.zig:155-164 is still correct: Swift answers getLocationRecordingState from memory, and restoreLocationRecordingState's guard state["active"] as? Bool == true else { return } leaves id/startedAt nil after a relaunch that follows a stop, while the state file still holds the stopped recording's values.

This is a rule, not a wall — a Zig reader that applies the same guard reaches the same answer. It has to be ported deliberately rather than discovered.

The deferral-table reason — mechanically true, but not an ObjC wall

The table's reason is "Coordinator.init re-adopts recordings at launch; Zig cannot stop what Swift restored". The mechanism is real: restoreLocationRecordingState() is called from init(config:) (packages/ios/templates/CraftApp.swift:460), and SwiftUI runs makeCoordinator() before makeUIView, where CraftZigRuntime.attach reaches craft_ios_set_webview (CraftApp.swift:345). Swift restores first, every launch.

But that is a statement about where Swift chooses to restore, not about CoreLocation. craft_ios_set_webview only stores a pointer (packages/zig/src/ios_dispatch.zig:474); there is no launch hook yet. An adoption export that Swift consults in place of its own restore would settle it, with the no-Zig fallback being exactly today's behaviour.

Why this is worth doing rather than just re-documenting

bridge_mobile_location.zig:106-116 records a live defect that only this migration closes: while a recording runs, Swift's manager and Zig's manager both feed craftLocationUpdate, so a page that records and watches gets roughly two events per fix. Its own words — "it disappears when the recording actions migrate".

The faithful shape is one manager with three consumers, which is what Swift already is: a flag on the shared delegate plus two files. didUpdateLocations (bridge_mobile_location.zig:1210) currently drops a fix when neither a one-shot nor a watch is waiting, so a recording has to become a consumer there rather than a second CLLocationManager.

Refs #110, #114, #117.

Sign in to comment on this issue.