A record the phone keeps to itself
A door learned once should not have to be learned again, least of all at a station with no signal. EntranceMemory is the phone's record of the doors of the buildings Dad walks to. Per building it holds a name, a centre, the door Dad confirmed (with the barometer's altitude there), the doors he turned down, and OpenStreetMap's doors as last read, with when. It is a value: the app changes a copy and writes it as JSON beside the recent places, and its doc comment is explicit that it is the phone's own record and never leaves it. Pippa's pins live on her server; Dad's doors live in his pocket.
Four constants shape it:
sameVenueMetres = 120: two centres this close are the same building, whatever their names. Pippa's pin may call it "Atocha" and Apple's search "Madrid Puerta de Atocha"; as long as the two centres fall within 120 m, the memory files both under one building.sameDoorMetres = 15: a door this close to one already known is that door.candidatesLifetimeof 30 days: after that OpenStreetMap is asked again. Only a fresh answer counts as known.limit = 200buildings. Every change moves a building to the front, and the list is trimmed from the back, so the ones whose record changed longest ago go first. A read does not count: a walk planned from doors already remembered, while OpenStreetMap's answer is still fresh, leaves the building where it is. So this is least recently changed, not least recently visited.
How a plan is made
ArrivalPlan.make turns a destination and the memory into a door to walk to and the doors to try after it. It collects candidates in rank order: the door Dad confirmed, then the door Pippa's pin or handoff named, then OpenStreetMap's ranked doors (just read, or remembered). It drops any door Dad turned down. Two doors within 15 m are one door, kept at the first one's position, and the first one inherits a note or a level it lacked from the later one. So when Dad confirms a door a couple of metres from Pippa's, his door leads and her note "2층 출발 홀" still rides along. If nothing survives, the plan has no entrance and the walk goes to the building's centre as before, with the spoken last stretch still on.
One subtle line keeps the plan stable. A door Pippa named stays attached to the destination itself, while a door the phone chose belongs only to the plan. When the plan is made again (Dad switches from driving to walking, or OpenStreetMap's answer arrives late) her door is still known and still leads. The kit test aLateMapAnswerKeepsPippasDoor pins that down.
In the app, the timing matters as much as the order. When Dad routes a walk, the plan is made at once from memory and the route is asked to that door. OpenStreetMap is asked in the background while the preview shows, and if its answer changes the door while Dad is still looking at the same walk, the preview is routed again. The sketch below runs the ordering and merging rules on synthetic doors around a building's centre.
Dad's two words
Instruments propose; Dad decides. While the last stretch is on, the approach card shows two buttons, "여기 아니야" and "여기가 입구야", and the same words work aloud in a talk with Pippa. The talk still goes to her; Pathfinder acts on the two phrases at once. ArrivalWords.meaning(of:) removes the spaces and looks for any of a handful of phrasings: eight for "not here" (여기아니야, 여기아냐, 입구아니야 and so on) and five for "this is it" (여기가입구야, 여기맞아, 입구찾았어 and others). It only listens while the stretch is active, so "여기 맞아" in an ordinary conversation moves no door.
"여기 아니야" rejects the door for good: it is never chosen again, and if it was Dad's own confirmed door, it stops being his. If another door is left, the current walk ends and a fresh walk starts to the next door, with "다른 입구로 안내할게". If none is left, the stretch keeps going toward the building's centre, still spoken but blind to level, and Pippa says "다른 입구는 모르겠어. 입구를 찾으면 여기가 입구야라고 말해줘".
"여기가 입구야" stores where Dad stands as this building's door, with source dad, the level, note and label of the door he was walking to, and the barometer's absolute altitude when it is accurate to 6 m. From then on that altitude is the level check Pathfinder trusts first: it compares two barometer readings above sea level directly, with no assumed floor height and no baseline. It is still a measurement, not a survey. Each reading is accepted with an estimated accuracy as loose as 6 m, and the verdict calls anything within 2.5 m the same level, so on a bad day it can still name the wrong floor. It also lifts any earlier "not here" within 15 m of that spot. Pippa says "기억할게. 다음엔 여기로 안내할게", and the walk ends a few seconds later.
Notice the order inside meaning(of:): the refusals are checked first, so a sentence holding both ("여기 맞아? 아니, 입구 아니야") is a refusal. My reading of why that is the right default: a wrong refusal costs one reroute, while a wrong confirmation writes a bad door into the memory at the highest rank there is.