fix(WhereUI): show splash before the first foreground reveal - #229
fix(WhereUI): show splash before the first foreground reveal#229kyleve wants to merge 3 commits into
Conversation
| // Include visibility in the identity: a background runner can remain | ||
| // `.ready` across foreground promotion, and that false → true transition | ||
| // is what must start an opt-in first-reveal hold. | ||
| .task(id: isReadyAndVisible) { |
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Review focus: visibility is deliberately part of this task identity. A background runner can remain .ready before and after foreground promotion, so readiness alone would not restart the task that establishes the first visible splash hold.
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Addressed in 9587d79. The hosted regression test now mounts a ready runner headlessly, applies a coalesced foreground-only reason change while the phase stays ready, proves the splash appears and releases, and was mutation-checked to fail if the task identity is reduced to readiness alone.
| splashSeen, contentBuilt, contentRevealCount, | ||
| splashPhaseRendered, resumeCount>> | ||
|
|
||
| \* A SwiftUI update reads the runner atomically on the main actor. The |
There was a problem hiding this comment.
Posted by an AI agent on kve's behalf.
Review focus: Render deliberately keeps the synchronous onChange hold update atomic with the main-actor view update, while StartReadyTask is a separate scheduled action. That source-correspondence assumption is load-bearing; if SwiftUI permits another main-actor mutation to interleave inside the synchronous callback, the model result becomes inconclusive until this boundary is revised.
Summary
MainTabswarming beneath the splash, then reveal its honest state without replaying the splash on warm resumesLifecycleReadyRevealPolicywhile preserving LifecycleKitUI's phase-driven default for existing callersWhy
A background-ready runner can be promoted and finish its foreground drive between SwiftUI render passes. The container then observes
.readywithout ever observing the intervening splash phase, so its existing minimum-duration hold is never armed and the Locations loading surface can appear directly.Review focus
.readydoes not add a second 800 ms holdFirstForegroundRevealabstracts the positive duration to deadline epochs and treats SwiftUI render coalescing nondeterministically; gates, failures, resets, scene recreation, and actual scheduler behavior remain explicitly excludedTesting
./swiftformat --lint./test LifecycleKitTests LifecycleKitUITests— 79 tests passed./test WhereUITests— 420 tests passed./test --snapshots— 42 tests passed; no reference changes./tla-check FirstForegroundReveal— 7 cases passed: 2 expected broken-design failures, 3 reachability controls, and 2 clean current bounds