iOS preview: shell-owns-agent flash-free respawn (draft)#241
Draft
obj-p wants to merge 4 commits into
Draft
Conversation
Checkpoint of the shell-owns-agent work toward the daemon<->shell<->agent topology (plan: shell-owns-agent iOS preview architecture). Stage 0 (in-session spawn + xcrun-free CoreSimulator primitives + agent applicationState breadcrumb) and the productionized FrontBoard scene-hosting shell (HostAppSource/Shell). Stage 2 (this session): _relaunch() now passes --agent-sock to the relaunched agent and relaunches the shell so it re-hosts the new agent's cross-process scene. Previously _relaunch relaunched only the agent (no --agent-sock, no re-host), so the shell kept hosting the dead scene and the device-display composite went stale. This flashes for now (shell restart); Stage 6 makes respawn flash-free via shell-owned respawn + hold-last-frame. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
relaunchReRendersCurrentPreview now saves the post-relaunch device-display screenshot (the shell composite). A JPEG-size assertion can't distinguish a re-hosted frame from a dead-black one (cap-E showed both ~70KB), so re-host is verified visually. Confirmed: after relaunch the device display shows the rendered preview re-hosted by the shell (not a stale/black scene). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… respawn The shell now owns the agent respawn gap so the device display never blanks. Mechanism (all derisked on the sim first): - The shell periodically snapshots its live hosted view (drawViewHierarchyInRect rasterizes the cross-process scene — proven by probe). - It detects the agent's death via its agent-UDS connection returning EOF. - On death it freezes the cached frame + a dim scrim + spinner over the dead scene, reconnects to the same stable sock path the new agent rebinds, re-hosts into its existing window, and drops the overlay. No shell restart, no flash. - Fixed a crash: a BaseBoard foreground assertion must be invalidated before release (it traps in -dealloc otherwise), which had dropped the shell to springboard during the gap. Daemon: _relaunch relaunches ONLY the agent on a stable agent-sock path (agentSockPath kept on the session); the live shell re-hosts itself. This skips the planned agent self-assertion (Stage 3) and control brokering (Stage 5), both shown unnecessary by the Stage 2 evidence. Verified on the dev sim: the gap shows the held "Hello" + spinner (not black, not springboard); re-host shows the new content. flashFreeRespawnGap asserts the held band; relaunchReRendersCurrentPreview covers re-host. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ground The cross-process hosted scene loses its content when the shell backgrounds and does not recover on its own (returning from background showed a blank screen). Re-asserting the foreground activation was not enough; the scene must be re-hosted. On sceneWillEnterForeground (after a background), the shell now tears down the host and re-hosts the live agent via the existing connectAndHost path (briefly holding the cached frame). Snapshot caching stops on background so the overlay keeps the last good frame. Factored the teardown into teardownHost (shared with the respawn path) and the activation into activateHosted. Verified live on the dev sim: background to Safari then return now restores the preview (was blank before). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft for review of the diff. Not ready to merge (xcrun removal, default-flip, and the pre-merge /simplify + /code-review gate are still pending).
What this does
Makes the iOS preview respawn the agent with no flash, on the surface we actually ship (the device display), which all three use cases consume: agent CLI/MCP capture, a human on the real Simulator.app, and the MCP-app stream.
The long-lived foreground SHELL hosts the respawnable AGENT's SwiftUI scene as a real cross-process FrontBoard scene (display + input). On respawn the shell holds a cached frame + dim + spinner over the gap, then re-hosts the new agent. No shell restart, so the device never blanks or shows springboard.
Mechanism (all derisked on the sim first)
drawViewHierarchyInRectrasterizes the cross-process scene — verified by probe)._relaunchrelaunches ONLY the agent on a stableagentSockPath; the live shell re-hosts itself.invalidated before release (it traps in-dealloc), which had dropped the shell to springboard mid-gap.Why leaner than the original plan
Stage 2 evidence showed the agent survives scene-less and direct daemon↔agent control re-dials fine, so the planned agent self-assertion (Stage 3) and control brokering (Stage 5) were unnecessary and are skipped.
Reverse-engineering that informed this
Captured Apple's real Xcode Previews in a VM: the agent runs foreground, and Apple renders to the Xcode CANVAS while the preview DEVICE screen stays black. We deliberately diverge (composite to the device display), so the device-display gap UX has no Apple precedent and is ours — hence hold-frame + spinner.
Verification (dev sim)
flashFreeRespawnGap: kills only the agent, asserts the held band (not black ~61KB, not springboard ~364KB; held ~86KB), saves frames.relaunchReRendersCurrentPreview: full respawn re-host; saves the post-relaunch device frame (shows re-hosted content).Not done yet
xcrun(CoreSimulator-only launch/terminate/boot)./simplify+/code-review.🤖 Generated with Claude Code