Archive — history, not state. Kept for its reasoning and its evidence; its plan is closed.
Shop actor and native-runtime split handoff
Status: merge checkpoint prepared 2026-07-15.
This note connects two concurrent changes that must land together conceptually:
- splitting the monolithic shop actor into smaller service actors; and
- splitting the runtime’s globally linked C/module fleet into package-owned native providers selected by executable dependency closure.
The first change improves ownership, failure isolation, and service authority. It does not by itself materially reduce a process image or startup memory. That reduction only appears when each new actor has its own package closure and the target build stops linking every native extension and endowment merely because the target can support it.
What this checkpoint implements
This checkpoint is the follow-on to the standard-library federation commit. It finishes three capability verticals that the shop split can consume directly.
Process
pit-processowns the public process and capture APIs.- Darwin and Linux adapt
$posix_spawn; Windows adapts$create_process_w. - Web, Playdate, and Apple embedded targets have no process arm. Absence is by omission, not an unavailable stub.
- Git, the linker, and desktop native builds declare
pit-processexplicitly. - The shop selects
native_build_desktoponly for Darwin/Linux/Windows andnative_build_nonefor targets that cannot run a local compiler toolchain.
Fetch
fetchis independent of the portable HTTP experiment and no longer pullsnetinto the shop transitively.- Target arms adapt the actual host facilities:
$nsurl_session,$libcurl,$winhttp,$browser_fetch, and$playdate_http. - Linux resolves libcurl dynamically. If a suitable thread-safe libcurl cannot be realized, the endowment is absent; there is no hidden HTTP fallback.
Watch
pit-watch/watchselects Darwin, Linux, and Windows adapters.- Raw providers expose facility-shaped events from
$fsevents,$inotify, and$read_directory_changes_w. - Recursive traversal, rename pairing, portable action names, subscription management, and cancellation live in Pit.
- Unsupported targets have no
watcharm.
The committed boot fleet is regenerated so those package and target selections are present in the Darwin, Linux, Windows, Web, and Playdate firmware graphs.
What the shop-actor split should preserve
Each new shop service actor should have a deliberately small program root and manifest. Do not replace one monolithic actor with several actors that all load the old shop closure.
Suggested ownership:
| Service | Packages/capabilities it should own |
|---|---|
| source/package service | file, archive/QOP, fetch, Git where remote source actually needs it |
| store/realization service | file, archive/QOP, crypto/signature verification |
| build service | compiler, linker, Cake, process on desktop only |
| target/bundle service | compiler/linker target metadata, archive/QOP; no process on sealed targets |
| logger/profiler service | shop logging plus privileged runtime/VM observation capabilities |
Services should exchange records through actor messages. They should not all
import core/internal/pitfs, os, mach, nota, wota, crypto, and
shop_paths merely because the old shop actor did. Move shop-owned helpers
under pit-shop/internal, and give other facilities declared public seams in
their owning packages. This is also the prerequisite for enforcing
same-package-only internal/ resolution.
The remaining image-size blocker
cake/cake.ce still has three broad global lists:
base_runtime()includes support libraries that are not all runtime substrate (monocypher,wildmatch, fullminiz,cJSON, and the unusedwota_jsonadapter);qbe_runtime()links the compiler backend into ordinary desktop runtimes;extension_files()registers the complete native module fleet and then appends every target endowment.
Therefore package federation is currently a correct authority/dependency model, but it is not yet a native link-closure model. The next build step is to derive native extensions, support sources, external libraries/frameworks, and target endowments from the realized executable claims. A shop process should only carry QBE, Git, WebGPU, WinHTTP, libcurl, watching, or process support when one of its resident program roots actually closes over that facility.
For memory work, measure all of the following after each split:
- modules and native providers in each executable manifest;
- linked image size and mapped external libraries/frameworks;
- boot QOP/firmware size;
- runtime allocator and per-actor heap footprint.
Actor count alone is not evidence of a memory reduction and can initially add mailboxes, stacks, and actor contexts.
Native work ready to continue
Safe removals
source/wota_json.cand.hare an unused JSON-to-WOTA adapter.internal/libgit2.chas no current Pit consumer; Git usespit-process.debug/debug.canddebug/runtime.care obsolete stub surfaces. Their two working limit setters should not preserve those modules.- The importable
internal/kim.cmodule is test-only. Its KIM primitive must remain private to NOTA until NOTA is rewritten. - Test-only native modules should be selected only by test build roots.
Runtime and VM observation
The useful implementation currently sits mostly on the ambient actor module:
VM counters, actor snapshots, heap profiles, buddy allocator state, value
footprints, stack capture, and profiling controls. Host memory facts sit in
sysinfo.
Consolidate the read-only runtime-owned information into two privileged endowments:
$pit_runtime: actor/scheduler snapshots, allocator state, aggregate GC and runtime memory information;$pit_vm: VM counters, stacks, heap profiles, value footprints, opcode counts, function information, and disassembly.
Keep mutation and policy separate. Heap/stack limits, closure mutation, tracing, and profiler control are stronger authorities and should remain boot policy or later become separate control endowments.
Host/process memory is not intrinsically uniform. A Pit observation package should combine the runtime endowments with actual platform facilities such as Mach task/host statistics, Linux proc/sysinfo, Windows process/global memory, or WebAssembly memory. Missing target facts are omitted.
WebGPU
WebGPU is used and must not be deleted. Move wgpu/gpu.c into an explicit
WebGPU package rather than registering it in every runtime.
Keep device/resource APIs separate from surface integration so headless GPU
work does not require a window. Desktop code claims $wgpu_native; Web claims
the actual browser/Emscripten WebGPU facility. Target surface adapters combine
that GPU capability with an actor-owned window capability:
- AppKit window to
CAMetalLayer; - Win32 window to
HWND/HINSTANCE; - X11 or Wayland window to its matching surface descriptor;
- Web window to an HTML canvas selector.
Native shims must continue validating the owning actor and unwrapping opaque handles internally. Do not expose native pointers as Pit numbers.
cJSON
cJSON now has two real consumers. Web argument JSON can be passed as text to a
Pit actor and decoded with use('json'). POSIX daemon control JSON runs partly
before Pit startup, so it cannot simply import a Pit module. Retire it by
moving post-connection session semantics into Pit and using a minimal
length-framed WOTA bootstrap protocol for the irreducible C launcher/client.
NOTA and WOTA
Do not remove NOTA as dead code. Courier/SEIF uses NOTA for cross-runtime wire envelopes and then converts received messages to WOTA for the local actor mailbox. NOTA also encodes signed bundle manifests. WOTA remains the same-runtime/boot encoding.
NOTA can leave the primary binary as a declared codec package. A later pure-Pit implementation is plausible, but it must preserve private actor-value serialization, record traversal, cycles, replacer/reviver hooks, and binary compatibility. Define the narrow runtime seam for private actor data before removing the C codec.
Boot-only seams
- Keep QOP reading and a minimal inflater in the runtime while boot members are compressed; move full deflate/miniz functionality to archive/compression.
- Keep WOTA wire primitives required by actors and boot; move the importable codec facade to an owning package.
- Keep Mach loading/execution in the runtime; move QBE generation and the importable compiler facade to compiler/linker ownership.
- Replace importable
bootgateandshop_pathsmodules with private runtime boot operations/configuration delivery.
Verification for this checkpoint
make seedcompletes and regenerates all committed target firmware arms.- Focused process, fetch, watch smoke, and watch cancellation contracts pass.
- The default suite passes: 1,953 passed and 0 failed.
./pit test networkpasses the HTTPBingo fetch case, but the independentpit-httpHTTP/2 case times out after connecting tonghttp2.org. The same endpoint responds over HTTP/2 with curl, and this checkpoint does not modifypit-http,pit-tls,pit-net, or the HTTP/2 test. Treat that integration failure as a visible follow-up rather than as fetch coverage for this split.- Native Linux libcurl/inotify execution and native Windows WinHTTP/ReadDirectoryChangesW execution remain target CI gates; their target firmware graphs compile during the fleet rebuild.
Source: plans/archive/perf-2026-07/shop-actor-native-split-handoff-2026-07.md