Follow-up to #189 (JIT executor Phase 3, PR #190). Phase 3 core is complete: the JIT executor is wired into the macOS daemon behind a StructuralReloader seam — structural edits render in the agent and preview_snapshot serves the agent PNG; literal edits on an agent-backed session rewrite a baked design-time-values JSON and re-render the same .o with no recompile. Measured structural latency is ≈281ms (compile ≈218ms + link/respawn/render ≈62ms).
The render/respawn half is within budget; the whole-module compile is the entire gap to the design's <200ms target. This issue tracks the remaining work, in priority order.
1. Recompile-narrowing (the dominant lever)
PreviewSession.compileObjectForJIT() currently does a whole-module compileObject (~218ms). Wire it to the stable-module/editable-unit split: single-file @testable compile of the edited file against prebuilt .swiftmodules for the rest of the module. The compile-strategy research (W4–W7 on previews-research) found this mandatory and feasible (~0.14s relink at 1000 files; split at file granularity). This is what gets structural edits under 200ms.
2. Capped-persistent reloader
The ratified executor shape is capped-persistent (one persistent agent + a fresh JITDylib per edit + background respawn every ~100 generations), not respawn-per-edit. Swap the body of Sources/PreviewsJITLink/JITStructuralReloader.swift accordingly; the StructuralReloader protocol does not change. This makes the literal path truly in-place (~10ms — re-seed DesignTimeStore + re-render without relink) and amortizes the ~70ms respawn warmup.
- The agent must call
LLJIT::initialize per generation (registers __swift5_* metadata; segfaults without). Satisfied by construction under respawn; must be added explicitly for a persistent agent.
3. examples/ E2E verify
An examples/ project test: a literal edit hot-reloads via DesignTimeStore (~10ms) and a structural edit reloads via the JIT path (respawn), in the same daemon session, no daemon restart. This is the P3.4 acceptance the seam was built for (the routing lives in the FileWatcher closure and is currently covered only by unit tests of the building blocks).
4. JIT-in-CI infra
CI skips the JIT tests because the targets need third_party/llvm-build (multi-GB prebuilt LLVM + orc-rt). Cache or build-once that artifact so CI can run swift test --filter PreviewsJITLinkTests. Self-contained infra; does not affect the daemon design.
Also conditional
P3.3 — in-place write_mem fast path + the Begin/End/cancelUpdate handshake (design §5/§6) — stays conditional, added only if no-restart with @State preservation later earns its keep.
Pointers
- Plan/source of truth:
docs/jit-executor-phase3-plan.md (the "Immediate next step" resume pointer + the P3.4 seam key-files map).
- Design:
prompts/jit-executor-design.md §8 Phase 3+ (on previews-research).
- Compile-strategy research arc:
research/scripts/analysis/jit-compile-arc.md (W4–W7, on previews-research).
Follow-up to #189 (JIT executor Phase 3, PR #190). Phase 3 core is complete: the JIT executor is wired into the macOS daemon behind a
StructuralReloaderseam — structural edits render in the agent andpreview_snapshotserves the agent PNG; literal edits on an agent-backed session rewrite a baked design-time-values JSON and re-render the same.owith no recompile. Measured structural latency is ≈281ms (compile ≈218ms + link/respawn/render ≈62ms).The render/respawn half is within budget; the whole-module compile is the entire gap to the design's <200ms target. This issue tracks the remaining work, in priority order.
1. Recompile-narrowing (the dominant lever)
PreviewSession.compileObjectForJIT()currently does a whole-modulecompileObject(~218ms). Wire it to the stable-module/editable-unit split: single-file@testablecompile of the edited file against prebuilt.swiftmodules for the rest of the module. The compile-strategy research (W4–W7 onpreviews-research) found this mandatory and feasible (~0.14s relink at 1000 files; split at file granularity). This is what gets structural edits under 200ms.2. Capped-persistent reloader
The ratified executor shape is capped-persistent (one persistent agent + a fresh
JITDylibper edit + background respawn every ~100 generations), not respawn-per-edit. Swap the body ofSources/PreviewsJITLink/JITStructuralReloader.swiftaccordingly; theStructuralReloaderprotocol does not change. This makes the literal path truly in-place (~10ms — re-seedDesignTimeStore+ re-render without relink) and amortizes the ~70ms respawn warmup.LLJIT::initializeper generation (registers__swift5_*metadata; segfaults without). Satisfied by construction under respawn; must be added explicitly for a persistent agent.3.
examples/E2E verifyAn
examples/project test: a literal edit hot-reloads viaDesignTimeStore(~10ms) and a structural edit reloads via the JIT path (respawn), in the same daemon session, no daemon restart. This is the P3.4 acceptance the seam was built for (the routing lives in theFileWatcherclosure and is currently covered only by unit tests of the building blocks).4. JIT-in-CI infra
CI skips the JIT tests because the targets need
third_party/llvm-build(multi-GB prebuilt LLVM + orc-rt). Cache or build-once that artifact so CI can runswift test --filter PreviewsJITLinkTests. Self-contained infra; does not affect the daemon design.Also conditional
P3.3 — in-place
write_memfast path + the Begin/End/cancelUpdate handshake (design §5/§6) — stays conditional, added only if no-restart with@Statepreservation later earns its keep.Pointers
docs/jit-executor-phase3-plan.md(the "Immediate next step" resume pointer + the P3.4 seam key-files map).prompts/jit-executor-design.md§8 Phase 3+ (onpreviews-research).research/scripts/analysis/jit-compile-arc.md(W4–W7, onpreviews-research).