The phone is in a pocket
A drive has a mounted phone and a speaker. A walk has neither. The phone is locked in a pocket, the street is loud, and the screen that showed the next turn is dark. Pippa's voice still speaks (the app holds the audio background mode, and guidance keeps running with the screen off), but a voice muffled by fabric on a busy pavement is easy to miss. Dad named the answer when the watch app was built: "도보는 특히 워치도 지원해야 하고", walking above all should support the watch.
There are two ways a turn can reach a wrist. The watch app can tap it, but only while the watch's own navigation session runs, and watchOS lets that session start only with the watch app in front. Most of a walk, nobody opens it. The other way needs no watch code at all. Apple's own rule: if your iPhone is locked or asleep, you get notifications on your Apple Watch, unless your Apple Watch is locked. So a notification posted by the phone is the one path to the wrist that works when the watch app is closed.
That is why the turns go out as notifications rather than as more audio. Audio from a pocket competes with the street; a notification on a locked phone is handed to the wrist, which taps. The voice keeps speaking; the notification is a second channel that reaches the body instead of the ear.
When a turn becomes a notification
The decision is TurnAlertPolicy.shouldAlert in PathfinderKit, a pure function with six inputs and a test table. A turn goes out only when all of these hold:
- Turn alerts are on. The setting "Turn alerts on the lock screen" (잠금 화면 회전 알림) defaults to on.
- It is a walk. A driver should not be reading.
- The phone app is not on screen. If it is, Dad is already looking at the turn.
- The watch's own session is not live. If it is, the open watch app taps by itself, and two taps for the same moment is noise.
- The stage is prepare or imminent, or it is the arrival. The early stage, 200 m out on a walk, is too far ahead to act on.
"Live" is measured, not assumed. The watch publishes a presence, watching(true), as its own application context every 30 seconds while its session runs, and the phone believes the last one for 75 seconds. A watch that went quiet, or whose app was swiped away, stops counting as live, and the notifications resume. The presence rides the application context rather than the capture lane on purpose: a heartbeat in a durable queue piled up while the phone was away, and every reconnect re-offered the whole pile.
Two halves of one rule
The watch has the mirror image of the same rule in WatchModel.tapIfDue. It taps a cue from the phone's glance only if its own session runs, or the phone app is in front, or the trip is a drive. On a walk with the phone app in the background and no watch session, it stays quiet, because the notification is the tap. Read together, the phone's policy and the watch's guard make exactly one tap per moment, not per turn. A turn on a walk has two moments that tap, prepare and then imminent ("Now"), and the notification identifier carries the stage for exactly that reason, so a turn reaches the wrist twice by design. What the pair rules out is the same moment twice: it taps through the watch's session when it has one, through the mirrored notification when it does not, and never through both.
On a Google walk the same moments arrive, because FeedGuidedTrip reports Google's feed through the same moment hook. Google's SDK could post its own background notifications; Pathfinder turns that off (sendsBackgroundNotifications = false) and posts the walk's turns itself, in its own words. A simulated trip posts nothing.
The poster
TurnAlerts in the app does the posting, and it is small on purpose. The title is the maneuver in readable words ("Arriving" for the arrival), the body is the distance, or "Now" for the imminent stage. Every notification shares one thread. Each has an identifier made of the step and the stage, and posting one removes the earlier ones from the lock screen, so only the turn ahead stays there. When the walk ends or arrives, everything it posted is cleared.
Permission is asked once, when the first walk starts, the moment the reason for asking is obvious. Under XCTest the notification center is nil, so a hosted test suite never presents a prompt that a fresh simulator would never answer.
What is proven, and what is not
The policy is proven where it can be. turnAlertsReachTheWristOnlyWhenNothingElseWill in the kit's suite checks every row of the table above, and the presence tests check the 75-second trust. The app's hosted tests check that the setting defaults to on. The posting itself is not exercised there: the suite runs with no notification center, by design.
The last link is not Pathfinder's code. Mirroring a locked phone's notification to the wrist is iOS's behaviour, and it has conditions Pathfinder cannot see: the watch must be unlocked, and the notifications are posted at the ordinary .active interruption level, which a Focus can hold back. The project's own notes say real WatchConnectivity timing is still Dad's devices' to prove, and I found no entry in the record that confirms a mirrored turn tapping Dad's wrist on a walk. A Live Activity, which would put the turn on the lock screen, the Dynamic Island and the watch's Smart Stack, is listed as the next candidate, not built. Say it the way the record does: designed, tested on a Mac, waiting for the street.