Working state — a note taken while the work happens, not a specification. The system as it is meant to be is in Architecture.

Deletion inventory — plans/programs.md R1–R9

Worktree: /Users/johnalanbrook/Documents/work/cell/.claude/worktrees/agitated-dubinsky-a3501e Branch claude/module-export-link-review-9f8813 @ c13443301. Read-only pass, 2026-08-05. No daemon was running (lsof -t .pit/pit.sock empty; .pit/pit.sock is a stale node from 11:52). Nothing was built, seeded, tested, edited or deleted.

Sizes are wc -l of whole files or of the named line spans; treat them as order-of-magnitude. “Region” line numbers are exact.


0. Summary table

Order is a dependency order, not a priority order. Rows 1-6 are free-standing and can land today; 7-11 need their ruling implemented first; 12-14 have named prerequisites.

#SystemRuling that kills itEvidence (file:line)SizeRiskOrder
1stale PIT_POOL_PAYLOAD state block (lever read by nothing)subsumed by R6/R7pit-shop/mach_lower.cm:42-79; + :316-318, shop_tools/test.ce:149, tests/hook_image_name.ce:1538 comment lineszero1
2allow_compile + allow_static + the type:"allow" policy handlerresidue; R3a supersedes (refusal is by actor absence, by name)pit-shop/policy.ce:61,63, 236,239, 369-376~10 Llow1
3docs hot-reload: two-traversal swap + restart_frameR4docs/architecture/debugging.md:176-205; duplicate at docs/shop/compilation.md:94-108~30 L deleted / ~20 rewrittenzero — no code implements restart_frame1
4PIT_APP env probe + app-mode inferenceR1platform/host/source/host.c:476-480, 488~6 L + fanoutlow2
5sys_is_app_bundle (decl + 2 impls + 1 caller)R1source/sys_os.h:52-59; platform/posix-runtime/source/sys_os_posix.c:291-305; platform/windows/source/sys_os_win32.c:146-151; host.c:479~35 L, 4 fileslow2
6app_shop() convention + unconditional ensure_shop_dirsR1 + R2host.c:243-252 (used :261-262); :212-224 (def), :269-273 (call)~30 L (mostly conditionalized, not deleted)low2
7pit.bootstrap.target@1 spec block (no producer, no reader)R8 + residuedocs/spec/artifact-formats.md:219-357~140 doc lineslow, needs one ruling2
8dev pass profile (and small) — collapse to one profileR7pit-compiler/passflags.cm:88-108; DEV_LINK at :92-94 is byte-identical to SHIP at :95-97~21 L machinery + 4 test blocks + 1 doc section; zero cache invalidationlow-med3
9mach in bundles / mach payload CLIs / bundle-supplied mach executionR8shop_build.cm:2924-2945; shop_realize.cm:1663, :1802-1808, :1871; shop_tools/bundle.ce + publish.ce; shop_actor.ce:614-643~85 Lmed — breaks the Playdate ship lane4 (after §7.3)
10multi-target executable catalog (pit.catalog.variants@1)R8pit-shop/target_catalog.cm (whole, 188 L) + --targets plumbing~208 Lmed-high — appears in boot.qop’s own manifest4 (after §7.3)
11shoplib/mach_press.cm cross-press arm (the no-refusal bypass)R8shoplib/mach_press.cm:22-29, 50-58, 120, 132~15 of 143 Llow-med — verify pit-shop/mcode_lower.cm:25 first4
12linker program-side immutability census / mutable_export_riskR5pit-linker/mcode_link.cm:798-1091, :2543-2558, :2497, :2500, :2654; tools/export_taxonomy.ce:134-142, 157~330 L + 1 test case + 3 oracle rowsmed — hinges on R5 emitting a real stone op5
13the STATIC link lane (prepare_static_export_defs, $linked_export_N, cart IMPORTS/NAMES rows, boot-walk name binding)R6 + R7pit-compiler/mcode.cm (~207 L); compiler.cm (~33); shop_build.cm/shop_source.cm (~93); cement.cm:392-432 + engine/boot_walk.cm:262-272, :328-343 (~65); tooling (~149)~550-600 L code + ~210 L testsHIGH — the only lane production uses today6
14build.capabilities.daemon all-or-nothing recipe lever + daemon-stubR1 tail / R912× recipes/*.json:29; 12× platform/*/package.json endowments.daemon; cross-check tests/recipes.ce:194-196; platform/posix-daemon/ (1,076 L), platform/daemon-stub/ (24 L)24 recipe/manifest lines gate ~1,100 L of Cmed — needs the R9 per-product lever designed first7
pit-shop/terminal.ce pool-lane PGO refusalNOT killed by these rulings (L2b, carried forward at plans/programs.md:263)pit-shop/terminal.ce:2175-2183, 2418-2432~22 Ldo not sweep
cart N-section machineryR6 ALMOST kills it — the ROM-window escape clause saves itcement.cm:731-782; cart2.cm:279-330; cart/cart.cm:227, :282, :510, :540, :732-786~150-250 L becomes unexercisedsee §5.0

1. R1 — the cart declares the mode; PIT_APP dies; daemon split

1.1 Every PIT_APP / sys_is_app_bundle / PIT_INPROCESS site

Full grep (excluding build/, plans/, .qop). Classified.

DIES (R1 replaces with a cart-declaration read):

sitetextverdict
platform/host/source/host.c:476const char *app_env = getenv("PIT_APP");DIES
platform/host/source/host.c:477-479app_mode = !daemonized && ((app_env && …) || sys_is_app_bundle(paths.binary));DIES — becomes a read of the boot entry’s start declaration
platform/host/source/host.c:488if (app_mode) force_inprocess = 1;DIES (folds into the declared mode)
platform/host/source/host.c:243-252app_shop() — invents ~/Library/Application Support/<exe>/shopDIES under R2 (the declaration says whether a shop exists at all, and the product names it)
platform/host/source/host.c:261-262else if (app_mode) paths->shop = app_shop(paths->binary);DIES
platform/host/source/host.c:489, 493resolve_paths(&paths, requested_shop, app_mode) / if (!daemonized && !force_inprocess && !app_mode)REWRITTEN to read the declaration
source/sys_os.h:52-59declaration + the doc-comment that asserts the env-probe model (“an app gets its own shop and an in-process boot rather than the development daemon … the launcher’s PIT_APP override still works there”)DIES
platform/posix-runtime/source/sys_os_posix.c:291-305impl. #if defined(__APPLE__)strstr(binary, ".app/Contents/MacOS/"), #elsereturn 0; — this is exactly the plan’s §2 claim: a shipped Linux binary has no way to say what it isDIES
platform/windows/source/sys_os_win32.c:146-151impl, return 0, comment says “PIT_APP remains the way to ask for app behaviour here”DIES

STAYS (compat shim / test harness — PIT_INPROCESS is not named by R1):

R1 deletes PIT_APP by name. PIT_INPROCESS is a different thing: it is the test harness’s way to force a no-daemon boot, and it has a large live consumer set. It should be re-expressed as “the declaration says in-process” but the tests need an override that does not require re-forging a cart.

sitenote
platform/host/source/host.c:481-487the PIT_INPROCESS read itself; #if !defined(_WIN32)
platform/host/source/host.c:533-538the “forced in-process node has no daemon transport” comment + config.daemon_socket_path gate — still needed under a declared mode
source/pit_internal.h:2650-2658pit_set_cli_exit_code doc names “(windows/app/PIT_INPROCESS)” — comment edit when PIT_APP goes
internal/os_posix.c:735-745in-process CLI exit-code path — comment mentions PIT_INPROCESS
pit-shop/terminal.ce:2145“In-process CLI (windows/PIT_INPROCESS): no client control fd” — comment
source/scheduler.c:859historical deadlock note
tests/cli/inprocess.ce:5,26,69,71; tests/cli/plan_image_cap.ce:6,18,85,125,131; tests/cli/reply_lifetime.ce:11,102; tests/cli/fuzz_progress.ce:73,120; tests/fixtures/plan_image_cap_child.ce:6; tests/watch_snapshot_lock_order.ce:14live test harness uses
cake/forge.cm:1191var env = {PIT_INPROCESS: '1', PIT_CONTENT: content}forge itself boots in-process to press; this is load-bearing for the seed lane
aot_bench/perf_one.ce:3bench harness

Not app-mode at all (false positives on the grep, listed so nobody re-raises them): platform/watchos/watchkit_interface.c:3-5, platform/uikit/uikit_window.c:3-5, platform/darwin/appkit_window.c:3-4 — those are PIT_APPLE_UI_* macros.

1.2 The .app consumers that depend on the path probe

sys_is_app_bundle’s only reason to exist is the macOS .app double-click path. The producers and their tests:

  • shop_tools/bundle.ce — 896 L, pit bundle app. Lays out Contents/MacOS (:175), Contents/Frameworks (:176), Contents/Resources (:177), writes Contents/Info.plist (:302). It never writes PIT_APP — it relies entirely on the path probe. Under R1 this file gains a start-declaration write and loses nothing else.
  • tests/cli/app_bundle.ce (131 L) — asserts “double-clickable app boots in-process and runs its app root”. Pins the probe behaviour; must be rewritten to assert the declaration.
  • tests/cli/aot_app_bundle.ce (170 L) — same shape plus the native dylib.

Docs carry nothing about PIT_APP or app mode. rg 'PIT_APP|app bundle|app mode' docs/ returns only two unrelated hits (docs/architecture/debugging.md:134, docs/architecture/build-and-artifacts.md:117). So the mode is entirely undocumented environmental behaviour — the plan’s charge is exact, and there is no doc to delete, only a doc to write.

1.3 What makes the daemon all-or-nothing today

Three coupled levers, none of them per-product:

  1. build.capabilities.daemon — a boolean at line 29 of every recipe: recipes/darwin.json:29 and recipes/linux.json:29 are true; the other ten (emscripten, ios, tvos, watchos, windows, n64, ps1, psp, dc, playdate) are false. One bit per target, not per product.
  2. The platform package’s endowments.daemon row picks the C file:
    • platform/darwin/package.json:9runtime::platform/posix-daemon/source/daemon_posix.c
    • platform/linux/package.json:8 → same
    • platform/{windows,ios,tvos,watchos,web,playdate,n64,ps1,psp,dc}/package.jsonruntime::platform/daemon-stub/source/daemon_stub.c docs/architecture/recipes.md:50,201 documents both halves.
  3. tests/recipes.ce:194-196 asserts the two agree: check(r.build.capabilities.daemon == …) with the message “capabilities.daemon disagrees with the platform package’s daemon provider”. This test is what makes the pair a contract; a per-product lever has to replace it, not just drop it.
  4. linked_packages names posix-daemon directly — recipes/darwin.json:38 region ("posix-daemon" in the linked_packages array).

C surface the lever selects (the whole thing that a daemon-free product would stop compiling):

fileLOC
platform/posix-daemon/source/daemon_posix.c942
platform/posix-daemon/source/sys_ipc_uds.c134
platform/daemon-stub/source/daemon_stub.c24 (the null arm)
source/daemon.h (12 exported entry points, :19-36)~40

Plus the client half in host.c:492-512 (pit_daemon_launch — the “never boots pit, forwards argv” role) and host.c:405-443 (setup_daemon_identity, pid file), and source/scheduler.c:3222 (pit_daemon_listener_stop).

R9’s shape, noted not designed: today the pair is {capability bit in the recipe} × {file in the platform package}. R9 wants the same pair keyed by product, and wants it to do both halves — strip the C and drop the module shim, so an actor asking for an absent feature is refused at realization by name. $hook is the existing model (source/pit_internal.h:41-53, “no ring, no field”); the endowment set is recipe.lists.endowments / endowments_whole read by link_scope() (cake/plan.cm:367-418 — the take() closure at :394-404 is exactly the per-recipe read that must become per-product).

Risk on deleting daemon-stub: the stub is the definition of “this target has no daemon”. Under R9 it becomes the default rather than a selected file, so it is a rename/relocation more than a deletion. Deleting it before the per-product lever exists breaks ten recipes.

1.4 STATUS after D1 (branch arc/start-declaration, 2026-08-05)

Landed: the declaration itself. start_flags is a u32 at header offset 196 of pit.cart@2, carved out of the 60 reserved bytes — so the crossing is additive and no existing cart needed a read bridge. Each bit subtracts a default, making 0 the development program (resident/shop/daemon), which is exactly what every pre-declaration cart already says. pit_cart_start_flags (source/cart_boot.c) reads it from the linked image before any role is chosen; pit_host_main takes its role from it and from nothing else. PIT_APP is gone. sys_is_app_bundle survives at one call site — choosing the Application Support shop path for a bundle that DECLARES a shop — and decides no mode. ensure_shop_dirs runs only for a program that declared a shop or whose invoker named one with --shop.

NOT landed: the daemon split (row 14 above, R1’s tail). D1 made the daemon conditional at RUN time — a cart declaring no_daemon never spawns one, never serves one, and is handed no socket path — but the ~1,100 L of daemon C is still LINKED into every desktop binary. Closing that needs three things D1 does not have, in this order:

  1. A per-product replacement for the per-recipe pair. “Does this build have a daemon” is recipes/*.json build.capabilities.daemon × platform/*/package.json endowments.daemon, and tests/recipes.ce:194-196 asserts the two agree — so it is a contract, and a per-product lever must replace it rather than sit beside it. That lever is R9/D3, not D1.
  2. Closure discovery, to know whether daemon actors are in the product at all. That is D2’s $start-site static analysis; without it “this closure contains no daemon actor” is not a computable fact, only a hand-assertion.
  3. A named realization refusal for an actor that asks for an absent daemon (R9), or stripping the C turns a missing feature into a link error or a mystery runtime failure instead of a refusal.

The declaration is the right input to that lever — a no_daemon cart is by definition a product that should not link posix-daemon — which is why D1 defines the bit even though nothing strips C on it yet. Wiring the bit into link_scope() before (1) and (3) exist would remove the code and leave the refusal missing.


2. R8 — mach is never shared or shipped

2.1 Do the bundles carry mach? — No today, but the writers still can

Measured by parsing the qop indexes and inflating the /manifest members (qop format source/qop.h:17-42; index = trailing index_len/archive_size/qopf):

archivebytesentriesmanifest kind tally
boot.qop13,700,682153module 323, mcode 128, program 13, executable 12, manifest 12, mach 0
boot/targets/linux/boot.qop13,257,178153identical tally, mach 0
shop.qop13,384,036709manifest.json + packages/**pure source (.c/.cm/.ce/.h)

The only mach substrings in boot.qop’s manifest are three module locators (shoplib/mach_pool_emit, shoplib/mach_press, pit-shop/mach_lower) — not artifacts. The ruling behind that is recorded in-tree at pit-shop/shop_build.cm:2832-2864 (payload_mode “mcode”, RULED John 2026-07-30) and pinned at :2980; the manifest writer is write_prepared_content (:3047-3095, format line :3069).

DELETE — the dormant mach arm in the seed writer. pit-shop/shop_build.cm:2942-2945 plus its comment :2924-2941, ~22 LOC:

if (is_text(m.mach_hash) || (m.mach && is_text(m.mach.hash))) {
  objects["blake2:" + bare_hash(m.mach_hash || m.mach.hash)] = {kind: "mach"}
  carried = carried + 1
}

Unreachable only because :2980 pins mcode — this is the exact code that would put mach into a content bundle.

DELETE — the mach edge in the publish closure walk. pit-shop/shop_realize.cm:1663 (1 line, load-bearing): if (m.mach && m.mach.hash) push(m.mach.hash, "mach", …). That walk is documented as “exactly what publish ships” at :1536-1547, and publish_one_root writes every walked object into the archive at :1830-1843.

DELETE — mach as the publish default. pit-shop/shop_realize.cm:1871 (verified verbatim): payload_mode: request && request.payload_mode ? request.payload_mode : "mach". Gated by the CLI test tests/cli/bundle_info.ce:154 (if (x.payload_mode != "mach") bad(…)).

DELETE — cross-rep publish threading, pit-shop/shop_realize.cm:1802-1808 (~7 LOC): it exists only because mach ships — “mach is target-final and rep-stamped at generation, so a bundle destined for a narrow-rep runtime must realize under that rep or every module in it is refused at mount”.

DELETE — the mach payload form in the shipping CLIs (~40 LOC): shop_tools/bundle.ce:37 (PAYLOAD_FORMS = ["mcode","mach","source"]), :51 (flag help “default: mach”), :138 (the default), :141 (refusal text), and the bundle info accounting at :465, :473-487, :525, :725-727; shop_tools/publish.ce:19, :54 (--payload “mach (default), mcode, mixed”).

DELETE — bundle-supplied mach execution. pit-shop/shop_actor.ce:614-643 (~14 LOC). scratch_blob_map’s header at :614-618 names its three sources — “dev realize, supplied bundle, qop content volume” — and the mach arm at :630-638 maps a received blob straight into the scratch image. KEEP the mcode arm (:645-661), which is already the lower-on-arrival path R8 mandates (and :642-645 already refuses an unhydrated mach reference by name).

KEEP — realize_payload_mode’s "mach" default at pit-shop/shop_realize.cm:334-341: that is the mode for running locally.

2.2 boot/targets/linux/engine_lite.machnot the forge floor; a Git-transported CI seed, and byte-identical to the host one

Exactly two committed .mach files exist in the tree:

filebytes
boot/engine_lite.mach69,360
boot/targets/linux/engine_lite.mach69,360cmp says IDENTICAL (verified)

By contrast boot/root.cart (9.48 MB) vs boot/targets/linux/root.cart DIFFER, and the two boot.qops differ. The identity of the two .mach files is load-bearing for the plan: the engine pool is stamped by profile (rep/endian/mach-ABI), not by ISA, so one blob already serves darwin-arm64 and linux-x86_64.

Consumers of boot/targets/** — all CI, never forge: scripts/use_ci_seed.sh:10,12,25,26 (copies root.cart/engine_lite.mach/boot.qop over boot/), scripts/ci_platform_vm.sh:20, scripts/ci_local.sh:23,53,131-135,259, .gitea/workflows/ci.yml:79,207,256,306, .gitea/workflows/cross-check.yml:67,137,195, ci/README.md:36,47-50, .gitignore:96. Never referenced by cake/forge.cm, cake/plan.cm, Makefile, or boot/manifest/.

Consumers of the host boot/engine_lite.mach — this is the forge floor: Makefile:342 (seed-freshness prerequisite), cake/forge.cm:1260 (FIXPOINT_ARTIFACTS), :1293 (stage), :1327-1329 (promote); produced by pit-shop/shop_build.cm:3173, :3218, :3240; freshness at pit-shop/derivation_status.cm:62, :120-123. It is cemented into root.cart, which forge .incbins into the binary (cake/forge.cm:64-72 boot_section_source; Makefile:88). Never shipped loose. KEEP — R8-allowed.

boot/targets/linux/* is the awkward case. It is 22.8 MB (9.48 MB cart + 69 KB mach + 13.26 MB qop) crossing machines over Git so a Linux box with no pit can bootstrap. Under a literal reading of R8 the .mach and the .cart (which is pools, i.e. mach — pit-shop/boot_cart.cm:118-260) are shared mach. Recommend: KEEP, and state it as a named second exception in R8 — “the bootstrap floor may be transported as a committed pair”. As written, R8 deletes CI. Existing risk already recorded: this seed goes stale silently (plans/archive/night-2026-08-04/cross-builds.md:97, ci/README.md:54-60 — 81 commits behind while the lane stayed green).

A third committed mach artifact R8 hits: source/mach_pool_fixture.h — 96,815 bytes (verified), GENERATED by tools/pool_fixture.ce (308 LOC), carrying ten cross-pressed pools for ten distinct profiles (source/mach_pool_fixture.h:1701-1722: base, gc-compact, endian-be, nan32, nan32+compact, fixed32, fixed32+compact, f32, fixed, n64-be — two of them big-endian at :1706, :1720). Compiled into source/mach_pool_test.c:16, read at :1943-1962, regenerated on every make smoke (Makefile:313-334). It is cross-target mach lowering outside the forge path whose product is committed to the repo. KEEP + R8 needs a third carve-out (“test fixtures”), or the rule fails on day one of make smoke.

2.3 Can mach be served to another machine? — one path only

(a) pit-shop/courier.ce (572 LOC) + courier_transport_net.cm (25) + courier_transport_web.cm (15) — actor messages only, NO artifacts. Wire vocabulary fixed at courier.ce:10-15; envelope constructors :230-238, :241-263, :301-309 carry only {type: "contact", portal_port, data} / {type: "user", target, data} plus reply/trace fields. KEEP — not an artifact path at all.

(b) advertise / serve (pit-shop/source_upstream.cm, 400 LOC) — SOURCE TEXT ONLY. The kind filter is the key derivation itself:

pit-shop/source_upstream.cm:132-135
function peer_source_key(locator) {
  return shop_store.bare_hash(shop_store.hash_text(
    "pit.source.file@1\n" + text(locator || "")))
}

advertise (:218-255) returns {files: […]} for git (:223), shop-peer mount (:234) and directory (:249); serve (:258-312) returns {data: raw} for the same three; peer object reads go through peer_object (:155-163) → peer_catalog_hashpeer_source_keypit.source.file@1. Bound in at pit-shop/shop_build.cm:207-208, re-exported pit-shop/shop_source.cm:3058-3059. KEEP entirely — never sees mcode or mach.

(c) publish → signed .qop → HTTP ingest_bundle — THE mach wire. Producer pit-shop/shop_realize.cm:1858-1935 (realize_publish), default mach at :1871, closure objects into the archive at :1830-1843, archive written :1932. Consumer pit-shop/shop_source.cm:2884-2930 (ingest_bundle), fetched at :2861-2869, verified at :2829-2857 (re-hashes every object, :2850-2856). Execution of a received blob: pit-shop/shop_actor.ce:630-638. This is the whole of §2.1’s DELETE list.

Narrowing worth recording: cross-rep mach publish is ALREADY refused. The realize lowering path is shop_build.finish_unit_mach (:932-978) → lower_mach_unit (:759-783) → build_fleet.request {type:"mach", numrep, endian}pit-shop/builder_worker.ce:246mach_lower.fragment_unit → the refusal at pit-shop/mach_lower.cm:205-218. So --target playdate --numrep nan32 from a nan64 host is already blocked. The surviving hole is host-rep mach shipped to a foreign system — narrower than R8’s framing implies, so the artifact-path deletion is smaller than §7.4 suggests. The bigger deletion is the executable catalog (§2.5a).

2.4 pit-shop/shop_store.cm K_mach paths — zero deletions

846 LOC file, 70 lines mention mach. Every one classified:

functionlines~LOCroleverdict
current_mach_abi20-3213process-constant ABI stamp folded into every K_mach identityKEEP (cache correctness)
cache_mach_blob_value621-63010content-address the pool into the LOCAL object storeKEEP (a) local cache
mach_debug_key632-660 (comment 632-657)3 + 26f(mach content hash) → debug sidecar keyKEEP (c) §7.2
cache_mach_debug_value662-6687write pit.mach.debug sidecarKEEP (c)
mach_origin_key670-687 (comment 670-684)3 + 15f(pool_content_hash)pit.mach.origin@2the exact function plans/programs.md:302 citesKEEP (c), explicitly carved out
cache_mach_origin_value689-6979write the origin sidecarKEEP (c)
mach_derivation_key (K_mach)703-73115K_mach\npit.mach.pool@1\n<abi>\n<lowering_identity>\n<mcode_hash>\n<label>\n<numrep>\n<endian>KEEP (a) — purely local derivation cache, never leaves the shop
stage_mach_result733-7449payload + both sidecars, staged in a disposable actorKEEP (a)+(c)
publish_mach_result746-7538“publish” = write the LOCAL catalog edge (catalog_put_value only)KEEP (a) — misnamed only
cache_mach_result755-77521lookup-or-fill on K_machKEEP (a)
exports836-8449KEEP

Net: no deletions in shop_store.cm. Nothing in the store shares mach; it is all local cache plus the §7.2 identity/debug keys. Two naming hazards worth fixing in the same landing so a later grep audit stays legible: publish_mach_result (:747) reads like distribution and is not, and build_read_value’s comment at :498 says “mach blobs, bundle-served objects”. The numrep/endian fields inside mach_derivation_key (:717-718, :727) only differ from host when a caller is cross-repping — harmless as cache inputs.

2.5 Cross-target mach lowering outside the forge path

The refusal is pit-shop/mach_lower.cm:196-218 (host normalization at :197-198, refusal at :205-218), rationale comment :22-40 — the line-38 the plan cites is mid-sentence in “because a caller asking THIS lane for a foreign target has confused realizing-to-run with pressing-to-ship”. Pinned by tests/cross_target_lowering.ce (106 LOC), both directions. KEEP — permanent per plans/programs.md:256-260.

Three routes around it:

(a) press_unit / press_floor_unit — same module, no refusal. KEEP: this IS the forge path. pit-shop/mach_lower.cm:336-389 (~54 LOC), exported :391. Takes a full rep_profile stamp, derives a foreign target at target_of (:304-312), passes {target} to both mach.mach_compile_mcode_bin(…, {fragment: true, mach: false, target}) (:342-347) and pool_emit.emit(…, {target}) (:378). Callers: pit-shop/boot_cart.cm:176 (every module of every cart executable), :272 (engine/engine_lite), :282 (engine/boot_walk) — all inside pool_executable (:118-260) and cement_root_cart; plus shop_tools/cement.ce:204. AUDIT that last one: pit cement (539 LOC) is a user-reachable cross-target press with an --endian flag at :49 and an --app ship-cart mode at :43, :332 — the forge path exposed as a command.

(b) shoplib/mach_press.cm — a full cross-press with NO refusal at all. 143 LOC; its own header states the bypass at :22-29: “The heavy realization lane is pit-shop::mach_lower, which does the same two steps plus … the foreign-target refusal a shop realization owes. This module is what everything ELSE presses through… CROSS-PRESSING is opts.stamp. target_of at :50-58 (a duplicate of mach_lower.target_of), mach_compile_mcode_bin at :120, pool_emit.emit at :132. Non-test importers: scheme/compiler.cm:8, pit-compiler/compiler.cm:9, pit-shop/mcode_lower.cm:25, pit-shop/mach_lower.cm:151, tools/cross_unit_inline_probe.ce:12, tools/compiler_budget.ce:26, aot_bench/{vs,mt,pause_test,mstress,census}.ce, aot_bench/diagnostics/fannkuch_bisect.ce:5. DELETE the stamp/target parameter (~15 of 143 LOC); KEEP the host press. Every listed caller presses for the host; the cross arm has no in-tree production consumer. Risk: pit-shop/mcode_lower.cm:25 imports it and mcode_lower is the runtime’s start-time lowering — verify no stamp reaches it before cutting.

(c) tools/pool_fixture.ce — a ten-profile cross-press, committed. See §2.2. Uses shoplib::mach_pool_emit directly (:21) and mach.mach_compile_mcode_bin (:149, :236), bypassing BOTH mach_lower and mach_press; self-described at :7-16 as “THE CROSS-EMITTER GATE”. KEEP + carve out.

Also: shoplib/mach_pool_emit.cm (1,190 LOC) is fully target-parameterised (profile-mismatch refusals at :266, :277, :957, :966). That parameterisation is what the forge path needs — survives R8 intact.

2.6 Executable-sharing machinery — yes, and this is the big one

(a) The per-target executable catalog — pit-shop/target_catalog.cm, 188 LOC, pure distribution. DELETE the multi-target variant dimension. Header :1-12: “A catalog entry lets one logical locator name several independently realized executables: {schema: "pit.catalog.variants@1", variants: [{selector: {system: "darwin"}, object: "blake2:…"}, {selector: {system: "linux"}, object: "blake2:…"}]}. Selector axes at :24-33 (target, system, arch, cpu, abi, toolchain). Written during publish at pit-shop/shop_realize.cm:1834, :1846-1850 and during seed at pit-shop/shop_build.cm:3025-3027. The schema appears in boot.qop’s own manifest. This is exactly the “executable-sharing machinery” plans/programs.md:335 names. Under R8 a machine that must lower its own mach cannot consume a foreign variant, so the variant dimension is dead; keep at most a single-object catalog. ~188 LOC + --targets plumbing at shop_tools/publish.ce:22-23, :49-53, pit-shop/shop_realize.cm:1864-1866, shop_tools/bundle.ce:216-217 (~20 LOC).

(b) Executable objects in every shipped archive — KEEP the records, delete the mach hashes they name. Seed: pit-shop/shop_build.cm:2906 (kind: "executable"), :2921 (kind: "manifest") — measured 12 + 12 in boot.qop. Publish: pit-shop/shop_realize.cm:1643-1666 walks executable → manifest → mcode/mach → pgo; :1827 picks the root exe hash. These objects are records, not machine codepit-shop/executable_manifest.cm:1-11: “The manifest is the program’s LOGICAL identity… It carries no code, no target profile, no placement.” That is the mcode-side identity R8 needs.

(c) pool_executable — KEEP, the sanctioned product. pit-shop/boot_cart.cm:118-260 (~143 LOC), exported :325. Runs mcode_link.link_result(rows, PRESS_LINK_PLAN) then mach_lower.press_unit per module into profile-stamped pools. Callers :245 (root exe), :258 (each fleet row), shop_tools/cement.ce:204; referenced by pit-shop/shop_build.cm:3258. Its output goes into root.cart, which forge .incbins into the binary — the fused-blob-in-the-binary product R8 allows.

(d) The one path that ships a linked image off-machine: pit bundle app --seed-only for a foreign --target. shop_tools/bundle.ce:210-223 sends {type: "publish", target, targets, numrep, payload_mode: planned.payload}; scripts/build_playdate_sim.sh:269, scripts/build_playdate_device.sh:369, scripts/build_playdate_linux.sh:222 all pass --target playdate --payload mach and drop the resulting seed.qop into the .pdx. DELETE the mach arm; keep mcode/source. See risk 3 below.

No path in pit-linker/ (build.cm, mcode_link.cm, static_link.cm, toolchains.cm) ships anything off-machine — it produces link plans and static-link inputs consumed in-process.

2.7 R8 risk register — five things to settle before deleting

  1. R8 as written deletes CI. boot/targets/linux/ is 22.8 MB of mach-carrying artifacts (root.cart is pools; engine_lite.mach is a pool) transported between machines over Git and consumed by 8 CI steps. R8 needs an explicit “bootstrap floor” exception, or scripts/use_ci_seed.sh and both workflows must be redesigned first.
  2. R8 as written also deletes make smoke. source/mach_pool_fixture.h is ten cross-pressed pools, committed, regenerated every smoke (Makefile:313-334).
  3. The Playdate ship lane breaks. The three scripts/build_playdate_*.sh are the only in-tree consumers of --payload mach, and the .pdx seed is exactly “mach in the content bundle”. The replacement (ship mcode, let the target press) needs a target-side presser in the Playdate build — nothing today does this.
  4. plans/programs.md:326-331 (§7.3) is a hard blocker on the positive half. mcode is host-rep-tainted, so “mcode is the only shared artifact” ships a nan64-limited artifact to a nan32 target. Deleting mach sharing before fixing §7.3 removes the only currently-correct way to get a rep-exact payload onto a narrow-rep target. Fix 7.3 first; it is a prerequisite, not a parallel item.
  5. Two names will mislead a later grep auditpublish_mach_result (shop_store.cm:747, actually a local catalog write) and build_read_value’s “bundle-served objects” comment (:498). Rename in the same landing.

3. R5 — the compiler stones module returns; the linker census collapses

Anchors verified by hand:

  • The promise already exists in the spec, unimplemented: docs/spec/stone.md:52-58 — “Every module’s return value is automatically stoned … The returned object is stone inside the actor.”
  • The C read that does not stone: source/mach_vm.c:5447 VM_CASE(MACH_LOAD_BOUND_MODULE) reads results->values[slot] / the binding’s $providers row raw. Related opcode sites: source/mach_vm.c:223, 3080; source/mach_pool.c:1285, 1443, 1906, 3183; source/mach_internal.h:372.
  • pit_stone_value is one header bit and shallow — source/pit_internal.h:1505.

3.0 BLOCKING PRECONDITION — the deletion depends on how R5 stones

pit-linker/mcode_link.cm:772 is the hinge:

return {kind: "stone_record", fields,
        frozen: run.return_fact.kind == "stone_record",
        complete, member_count: length(names)}

frozen is true only when a stone op in the module main’s mcode dominates the return. The census at :2543-2558 runs only for frozen != true.

  • If R5 makes the compiler emit a real stone instruction immediately before module main’s return, frozen becomes universally true and everything in §3.2 is unreachable dead code.
  • If R5 freezes on the runtime side instead (at MACH_LOAD_BOUND_MODULE, source/mach_vm.c:5447 — the site plans/programs.md:143-145 cites), export_summary still sees no stone op, frozen stays false, and nothing below is deletable without separately telling the linker “module main returns are frozen by construction” (a one-line change at :772).

R5’s own wording — “stoned by the compiler at the module main’s return” — picks the first. Record it as a hard requirement of the implementation, and also require that the stone be the last thing before return: mcode_link.cm:641-647 marks a candidate escaped when base.kind == "stone_record", so any store after the emitted stone drops the whole export to generic.

3.1 KEEP — the provider-side recognizer, mcode_link.cm:159-775 (~617 LOC)

Stone proves immutability; it does not prove identity. Finalization rewrites p.f into ["function_ref", …] (mcode_link.cm:1236-1239) and must know which function each member holds. Nothing about stoning the return says that. So the CFG builder, the definite-assignment lattice, the escape check and the per-member exactness all survive R5 intact:

regionlines~LOC
same_fact159-1679
CFG-shape rationale comment (the control_safe post-mortem)169-18113
BLOCK_TERMINATORS/BLOCK_COND_JUMPS/jump_label182-19615
build_blocks198-27376
lattice comment, UNKNOWN_FACT, copy_state, merge_states280-32950
transfer_fact (incl. the is_stone/is_record fold, :372-389)331-38353
taken_successors384-42239
safe_candidate_use419-43416
note_member435-44814
member_key/copy_assigned/intersect_assigned450-47122
block_assignments473-50028
union_slot_set/nested_touches_slots496-52732
RECOGNIZER_INSTRUCTION_CAP + analyze_export_body529-670142
export_summary676-775100

Sub-line edits only: :772 frozen: becomes constant true (or the field goes), and its explanatory comment at :686-690 goes with it.

3.2 DELETE OUTRIGHT — the program-side census, mcode_link.cm:798-1091 (~294 LOC)

regionlines~LOC
census header comment (“a module result is NOT frozen when the runtime hands it out — a consumer really can assign to an import”)798-81720
safe_import_use819-83820
mark_providers_unsafe839-85315
union_holder855-86410
merge_holder_states866-87914
copy_holder_state881-90020
holder_seeds_main899-91719
holder_seeds_nested919-93012
transfer_holder932-95524
audit_holders954-104188
withhold_units_imports1040-105819
mutable_export_risk1060-109132

:798-817 is the block R5 falsifies verbatim — its whole premise is that the runtime hands out an unfrozen record. Every unsafe use it enumerates (store into the import, import-as-call-argument, push, re-export) becomes a runtime disrupt once the record carries the stone bit, because shallow stone freezes exactly the member bindings finalization rewrites.

Do not demote to a debug assert. An assert would have to re-run the whole 294-line dataflow to fire, and would fire on programs that are now legal-but- disrupting — a runtime question, not a link-time one.

One carve-out to record, not to keep: mcode_link.cm:1017-1019 (op == "put"mark_providers_unsafe(…, "put@cell")) is the only census check stone does not cover — it guards rebinding the slot the import arrived in, not mutating the record. But it is not load-bearing today either: the census applies only to frozen != true exports (:2552), so a stone(...)ed export already reaches rewrite_function with this hole open (rewrite_function propagates import origin through get at level 1, :1268-1272, and has no put handling; pit-compiler/structured.cm:129 classes put as cell_write so local_defs never reports it as a def of the parent slot). Delete it with the rest and track the put-rebinding gap in rewrite_function as the pre-existing defect it is — the fix is ~15 lines (a per-unit “which main slots does any nested function put to” scan feeding slot_set(origins, …, null)), not 294.

3.3 DELETE — census application and census-only telemetry

sitewhat~LOC
mcode_link.cm:2543-2558the withhold loop; risk = mutable_export_risk(rows); reason: "export_may_be_mutated" at :2554; stats.mutable_exports_withheld += 1 at :255516
mcode_link.cm:2497mutable_exports_withheld: 0 in the stats initializer1
mcode_link.cm:2500var risk = null1
mcode_link.cm:2654mutable_export_risk in the module return record (the export)1
mcode_link.cm:846-847, :1051-1053risk.reasons[…] / risk.sites[why] += 1 reporting5
tools/export_taxonomy.ce:134mcode_link.mutable_export_risk(rows)the only non-test caller of the exported function1
tools/export_taxonomy.ce:136-142, 157withheld[] list and risk_all/risk_sites/withheld JSON fields10

KEEP: mcode_link.cm:2559-2568 (the exact_exports/exact_export_members tally — reindent out of the if), :1219-1233 (rewrite_function’s summary.complete gate on link.missing_membercomplete is per-member exactness, orthogonal to stone), and stats.finalized_sites (declared :2488, computed :2604 as constant_members + function_members) — it counts finalization, not the census.

Total deletable in the linker: ~330 LOC, leaving the 617-line provider recognizer intact.

3.4 Tests that pin the current contract

tests/mcode_link.cm (809 L):

linescaseverdict
527-531comment: “An UNFROZEN export is finalizable only when the program itself proves the record is never mutated… a consumer that assigns to the import takes it away again”DELETE — R5 repeals the premise
532-552test_plain_record_return_finalizes_only_when_no_unit_can_mutate_itthe one test that pins the censusthe clean arm (:534-536) survives as “a plain record return finalizes”; the mutating arm (:537-542, source p.f = function(x){…}) must be deleted or inverted — under R5 that consumer disrupts at runtime rather than silently de-finalizing
547-548count_op(instructions(mutating), "function_ref") != 0deleted with the arm
549-550census(mutating, "mutable_exports_withheld") != 1the only assertion on the census counter in the whole tree — DELETE

Survive unchanged (provider-recognizer rows): :439-463, :466-489 (asserts finalized_sites at :486), :492-509, :511-525, :554-572, :574-589, :591-604, :606-625, :627-636, :638-645, :647-656.

shop_tools/internal/diff_runner.cm (the differential oracle) carries a parallel set: DELETE :135-139 (the mutated case), :170 (census(mutated)), :204 (check("consumer-mutated export stays generic", !finalized(mutated))). KEEP :102-134 and :199-203 (provider-side).

finalized_sites elsewhere — all KEEP, none census-specific: tests/mcode_link.cm:486,546; shop_tools/internal/diff_runner.cm:76,152; benchmarks/link_inline.ce:103,127; pit-shop/boot_cart.cm:135 (the press log line). Frozen fixture data recording "finalized_sites":0 (pre-recognizer): plans/archive/night-2026-08-04/rows/ship_linked.json:1, plans/archive/night-2026-08-04/rows/ship_linked_join.json:1.

Stale prose to update (not code): plans/archive/night-2026-08-04/link-opt.md:563-604 (the census design section), :612, :654-658, :752-756.

3.5 What R5 retroactively justifies rather than deletes

  • pit-compiler/mcode.cm:110-115, 149-241, 3939-3968 — the static export cache. The compiler already hoists p.member into a hidden slot once, at the def p = use(...) site: descriptors built at :190-221 (gated on m.object_definition_fn_nr == 0), emission at :3946-3967 doing one is_record guard (:3956-3957) then a batch of loads into $linked_export_N slots — with no invalidation on any later write to p. So the compiler has already baked in “an export’s members never change”, unproven, on the static-link lane. R5 makes that sound retroactively. Not deleted by R5 — but it is the strongest argument that the linker’s 294-line census was proving something the toolchain had already assumed. (See §5 — this same code is the static lane R6/R7 puts in question.)
  • pit-compiler/cross_unit_inline_experiment.cm:103-190prove_export_impl / prove_export / prove_export_any (exported at :318): a straight-line abstract executor over module main that recognizes one literal export record and returns a member’s function id. The direct ancestor of export_summary, and a second, older, unreconciled export recognizer. Note :148-149 folds is_stone on a candidate record to false and :167-169 passes stone through transparently — both stay correct under R5. Merge candidate with export_summary regardless.
  • pit-compiler/stone_records.cm:1-19 (CP2b level-1 folding) — intra- function, requires an explicit dominating stone and no escape before it. An R5 stone at module main’s return lands after every body load, so this pass neither gains nor loses. KEEP.
  • pit-compiler/notstone.cm:1-26 (is_stone guard elision from “provably never stone” facts) — its escape list already excludes any slot that is returned, so an export record can never be claimed not-stone. Safe under R5, but this is the pass most likely to miscompile if that escape rule is ever relaxed — worth a comment pinning it to R5.

4. R4 — repoint reload, no frame migration

Confirmed: restart_frame exists ONLY in prose. Whole-tree grep (rg 'restart_frame|restart frame', excluding build/) returns exactly two hits:

  • docs/architecture/debugging.md:193
  • plans/programs.md:136 (the ruling itself)

No C, no pit, no test implements it. So R4’s deletion is a pure docs rewrite. The block is docs/architecture/debugging.md:159-205 — the whole ## Hot reload section (## Debug information starts at :207). Specifically:

lineswhat it saysR4 verdict
:159## Hot reload headingkeep
:161-165“A reload builds a new Mach pool … and installs it into a running actor”; stable {mcode unit hash, function ID} identitykeep — the identity half is S1, needed by both reload and the debugger
:171-174The link plan sets the granularity.keep, now restated by R7
:176-181“Installing it is a traversal, not a blind repoint. The swap creates one replacement function object per compatible old function and rewrites the actor’s heap and roots to point at the new ones.”DELETE — R4 mutates the existing function objects in place (PitFunction.u.image = {binding, owner, outer_frame} + image_index, source/pit_internal.h:3115). No replacement objects, no heap rewrite. The “an active frame keeps running its old pool” half (:179-181) survives and becomes the whole story
:182-186the second traversal at a later safe point for escaped-closure stragglersDELETE — R4 accepts the straggler as a named residual (“a closure already handed out by an old-code frame keeps old code until it dies”, plans/programs.md:139-140). The “old pool stays pinned” sentence (:185-186) is kept, reworded — R4 keeps that residual
:188“Two things decide whether an individual function can be swapped”rewrite — under R4 the deciding question is export-record shape, not per-function swappability
:190-195The captured environment. … A layout-changing swap uses restart_frame, which unwinds and re-enters the function from the top; re-entering runs it again from its start, including effects it already performedDELETE ENTIRELY — the section R4 names by name
:197-201A unique replacement. … a development build disables the passes that would fold two distinct functions into one shared sequence”restate under R7 — R7 says identity uniqueness is the reason the granular pool form is the reloadable one, not a separate lever, so this stops being a pass-level rule (“disable the folding passes”) and becomes a pool-granularity consequence. Note this is the same claim §5’s pass-profile question turns on
:203-205“Rollback is the same traversal aimed at the prior pool”restate — “the same traversal” no longer exists; rollback under R4 is a second repoint

Missing and to be added, not deleted: R4’s refusal rule — “you cannot add or remove functions on the exported record. A mismatch is a warning or an error from the reload machinery — never a silent partial swap” (plans/programs.md:126-128), and the dependency on R5 (:146-147).

Also to sweep for stale references to the old design:

  • docs/architecture/debugging.md:147-149 (the $pgo “profile outlives the pool” claim is unaffected — keep).
  • docs/shop/compilation.md#how-much-code-per-pool is linked from :170; check it does not repeat the two-traversal story.

New size: ~30 lines deleted, ~20 rewritten, out of a 49-line section. Risk: zero (no code changes).


5.0 The cart format today is N pools, one per module — R6 ALMOST kills the machinery

This is the finding to hold carefully, because R6’s own escape clause saves the code it appears to condemn.

Today a cart carries one pool section per deduped module:

  • pit-shop/cement.cm:731-744 — the comment says it outright: “One section per deduped module, in the module table’s canonical order, so section i IS module i and the two never need a mapping table.” The loop is :738-743 (sections[] = stone(m.bytes), section_of_hash[m.hash] = i).
  • pit-shop/cement.cm:746-753engine_section / walker_section looked up through section_of_hash.
  • pit-shop/cement.cm:761-782plans_for(rows) / unit_row(hash): every plan UNIT row carries its own pool’s placed coordinates.
  • pit-shop/cart2.cm:165-200, 279-330 — the iterative ceiling-convergence layout over N sections: up to 5 probe rounds (while (ceiling_rounds < 5), :281) because the boot entry names sections by offset and cannot be encoded until they are placed, then a real layout pass and two “layout did not converge” refusals (:320-323, :327-330).
  • cart/cart.cm:227 (meta.sections), :282 (section(cb, index) — “one pool’s verbatim bytes, read on demand”), :510 (“pool sections: N”), :540 (report.dedup.unique — “pools: N sections, …”), :732-786 (the per-section verify sweep with its hash check and stamp cross-check), :640 (“the cart carries no pool section at all”), :656-667 (the header’s engine pool must equal the directory’s row).

Sizes: pit-shop/cement.cm 865 L, pit-shop/cart2.cm 467 L, cart/cart.cm 926 L, shop_tools/cart.ce 287 L, cart/image.c 93 L, source/cart_boot.c 397 L.

Under R6 the default collapses to one section — which deletes the reason for section_of_hash, the plan-row coordinate mapping, the dedup report, and most of the convergence loop. But R6 says the split survives “for esoteric targets with ROM windows and paging (gameboy)”, and cart2.cm:160-161, 171-172, 196-199 already carries exactly that lever (section_window: “no pool may cross one of these absolute image-window boundaries”). So:

Verdict: R6 makes the N-section path dead in practice but keeps it in the format. Estimated ~150-250 LOC becomes unexercised-but-live across cement.cm/cart2.cm/cart.cm. This is a “note it, do not delete it” item unless the arc’s owner rules that the gameboy case is speculative enough to delete now and re-derive later. Whichever way it goes, the press change (one pool, whole-program) is real deletion and belongs to §5.1.

Genuinely dead already, adjacent: cart/cart.cm:188-217 decode_mach_stamp keeps "pmac" (per-unit register-lane mach blob) and "pmcd" (mcode) arms — diagnostics only, since :768-778 refuses both by name (“a cart section is a pool”, ruled 2026-07-31). Under R8 the pmac arm has no producer anywhere (pmac count is 0 post-L3). ~30 L, keep-as-diagnostic is defensible; flag for the codename/residue sweep rather than this arc.

5.0b Docs that R6/R7 narrow

  • docs/shop/compilation.md:68-92 — “## How much code per pool” presents a three-row menu (One unit per pool / One executable per pool / Several executables per pool, :74-77) plus “You can also partition anywhere between those points” (:79). R7 says there are exactly two shop forms and the cart is not a choice at all. Delete row 3 and the free-partition sentence; restate the cart as a fact.
  • docs/shop/compilation.md:81-86 — “A development build usually puts each module in its own pool … a shipped build usually merges” — restate as R7’s named default rather than “usually”.
  • docs/shop/compilation.md:94-108 — a second “## Hot reload” section repeating the swap-and-move-references story (“the running actor’s references are moved over”; “Two things bound what a swap can do. A function whose captured state carries meaning needs…”). Same R4 rewrite as docs/architecture/debugging.md:176-205 (see §4); do not fix one and leave the other.

5.1 The answer to the key question: the static lane has no surviving consumer

Today, nobody in production asks for the pool lane, and everybody gets the static lane by default. The default is a chain of x == "pool" ? "pool" : null guards that all fall through:

  • pit-shop/shop_build.cm:1788var link_mode = msg && msg.link == "pool" ? "pool" : null, with the comment at :1785-1787 saying it outright: “Nothing in the tree asks for it yet: the fleet is statically linked and stays that way until the fleet-from-pools landing.”
  • pit-shop/shop_build.cm:898“null (the default, and every lane in the tree today) keeps static linking.”
  • pit-shop/boot_cart.cm:80-86“The press compiles its units on the STATIC link lane (shop_build’s link_mode is null unless a caller asks for ‘pool’)… a use() is a context load, not an import op.”
  • Other fall-through guards: pit-shop/shop_realize.cm:440, :1067; pit-shop/shop_build.cm:97; pit-shop/build_fleet.cm:69; pit-shop/builder_worker.ce:64, :73.
  • Nothing in Makefile, scripts/, ci/ or .gitea/ mentions --link-mode or link_mode at all.

The dev realize lane is static, not pool — this is the load-bearing answer: prepare_simple_bundle is the entry for both dev realize and the press (shop_build.cm:1788 is inside it), state.link_mode (null) is threaded into every compile_unit of the closure walk (shop_build.cm:1426, :1451, :1492), and no caller of realize_executable sets req.link — the two production requests are shop_realize.cm:1757-1758 (compile_root_native) and :1800-1802 (publish_one_root), neither of which does.

So the only two things keeping the static lane alive are (1) the cart press (pit-shop/boot_cart.cm:118 pool_executable, called at :245, :258 and shop_tools/cement.ce:204) — which R6 flips to pool — and (2) the dev realize lane — which R7 moves to one-pool-per-mcode-unit, i.e. the pool lane’s import op resolving through MACH_LOAD_BOUND_MODULE.

Conclusion: under R6 + R7 the static lane has zero remaining production consumers.

5.2 DELETE — static-lane-only code

pit-compiler/mcode.cm — ~207 LOC, the bulk:

regionlines~LOC
s_static_export_defs / s_static_export_descriptors state + comment110-1156
prepare_static_export_defs (the P8 export-cache hoist)149-24395
static_export_ref / static_export_slot forward decls245-2462
emit_linked_export_load1325-13273
emit_get_prop linked-slot arms1329, 1346-1348, 1362-1364~8
emit_call_method linked-slot arm1868, 1908-1910~4
static_export_ref body2909-293325
static_export_slot body2935-29384
gen_expr locals linked_export_slot/_ref3207-32082
.-access call site (collapses to plain emit_get_prop)3338-33392
method-call site (collapses to plain emit_call_method)3598-36003
def x = use() export-cache locals3873-38797
the static use() lowering armintrinsic_value(linked.name) + export-cache priming (:3928-3931 is the static use() itself; :3936-3969 is pure export cache)3928-396942
“was not resolved for static linking” diagnostic3970-39734
prepare_static_export_defs(ast) call46081

KEEP mcode.cm:4601 (s_static_bindings = ast._static_bindings) — the pool lane still reads it as evidence the request was answered (:4601-4606). KEEP intrinsic_value (:510-518) and prepend_unit_intrinsics (:520-541) — the static lane rides them, but they are shared with real intrinsics (log, text, format, $receiver: :549, :562, :943, :2980, :3264, :3329, :3659).

pit-compiler/compiler.cm — ~33 LOC: claim_static_bindings (:1492-1520, 29 L), folded._static_bindings = … (:1605), analyze_result_from attach (:221, :225), mcode_unit_result default (:1652). The record survives; the exports sub-map it carries (:1498-1516) does not.

Shop / executable side — ~93 LOC: claim_static_bindings shop copy (pit-shop/shop_build.cm:1264-1296, 33 L), add_context_bindings (:1299-1315, 17 L), static_bindings on the executable module row (:373, :888, :1054, :1665, :1686), module_context accumulation published as bundle.bindings (:1806, :1872, :2118), add_provided_name (pit-shop/shop_source.cm:1923-1932).

Cart / boot seam — ~65 LOC, and this is R6’s actual seam: pit-shop/cement.cm:392-416 (cart IMPORTS rows built from static_bindings, 25 L), :420-432 (cart NAMES rows built from exe.bindings, 13 L), engine/boot_walk.cm:262-272 (the name-binding loop env[irow.name] = values[irow.producer], 11 L) and :328-343 (16 L).

Tooling — ~149 LOC: shop_tools/compile.ce:1003-1009, :1031-1088, :1123-1126 (linked_plan / linked_ir, both named “static”, ~70 L); shop_tools/footprint.ce:242-320 (module_context_keys mirror, ~79 L).

Lane-selection scaffolding that collapses to nothing: the link field in mcode_cache_key (pit-shop/shop_store.cm:86-88, :102) becomes a constant, and every threading guard (shop_build.cm:97, :898, :1788; shop_realize.cm:440, :1067; build_fleet.cm:69; builder_worker.ce:64, :73) collapses from a two-valued lever to nothing.

Tests pinned to the static lane (must be deleted or rewritten): tests/linked_export_cache.ce (131 L) + 3 fixtures tests/fixtures/linked_export_{record,proxy,number}.cm; tests/linked_export_plan.ce (81 L); tests/compile.cm:1010-1030, :1115-1128, :1129-1170, :1244-1270.

Spec text to rewrite: docs/spec/mcode.md:106-110“The default lane resolves use() by static linking, lowering it to a context load … and emits no import instruction at all.” (This is also plans/archive/todo.md:121-123’s “lane” ambiguity — R7 settles it.)

Static-lane total: roughly 550-600 LOC of code plus ~210 LOC of tests. Highest-risk deletion in the whole inventory: it is the only lane anything in production uses today, so it can only go after the press flip and the dev realize move both land and are green.

5.3 What R6/R7 makes LIVE (not deleted) — the counterweight

pit-linker/mcode_link.cm carries ~1,200 of its 2,661 lines as import-edge finalization machinery that is structurally dead today because nothing in production emits an import op: the provider recognizer (:169-796, 628 L), the import-holder census (:798-1092, 295 L — which R5 deletes, see §3.2), import_link_type/rewritten_sites/slot_called_on_cfg (:1093-1184, 92 L), rewrite_function (:1185-1283, 99 L), discovered_main_members/ member_references (:1284-1369, 86 L), and the finalize_edges gate (:2513, :2522, :2536, :2546, :2575, :2605, :2642).

Same on the C side: source/mach_pool.c:4143, :4324, :4563-4582, :4590-4617; source/mach_vm.c:5417-5438 (MACH_LOAD_MODULE_RESULT), :5441-5500+ (MACH_LOAD_BOUND_MODULE); the module_imports relocation sidecar (source/mach_pool.c:877-883, :4578).

Reconciliation note: §3 and §5 disagree in appearance only. §5 classifies the census as pool-lane (so it survives the static lane’s death); §3 classifies it as R5-obsolete (so it dies to the stone ruling). Both hold: the census is pool-lane machinery that R5 deletes. Net, mcode_link.cm loses ~330 LOC and the remaining ~900 goes from dead to live.

5.4 source/mach_pool.c:4590 — function_ref lowering pays off, it does not die

:4590-4617 (28 LOC, contract comment at :4583-4589) lowers the linker’s ["function_ref", dest, provider_unit, function_id, member] into three mach instructions:

EM_ABX(MACH_LOAD_MODULE_RESULT, s.module_scratch, provider_unit)      // :4612
EM_ABX(MACH_LOADK,              s.key_scratch,    cpool(member))      // :4613
EM_ABC(MACH_LOAD,               ref_dest, module_scratch, key_scratch)// :4614

It reads the provider’s already-initialized stone export record rather than manufacturing a fresh closure (the exported function may close over its module frame), and unlike member_import at :4578 it does not set s.module_imports[…] — a finalized same-program edge needs no fragment-linker relocation (:4588-4589).

It is purely pool-lane: function_ref is produced only by pit-linker/mcode_link.cm:1242 inside rewrite_function, which fires only when a slot traces back to an ["import", …] op.

The consequence R6 must own: MACH_LOAD_MODULE_RESULT indexes state.base + bx into the actor’s one results array (source/mach_vm.c:5433-5436), so a function_ref is resolvable only if the provider is in the same pool (recorded at plans/archive/night-2026-08-04/press-switch.md:230-238). Under one-unit-per-pool it is not. R6’s “a cart is always ONE mach pool” is exactly the precondition that makes this instruction resolvable. :4590 is code that starts working when R6 lands, not code that dies. Its streamline/structured registrations (pit-compiler/structured.cm:29, :56, :125, :265, :1021; pit-compiler/stream_ir.cm:44; pit-compiler/streamline.cm:373, :3111, :3156, :3172) all stay.

Corollary for R7’s shop default: “one pool per mcode unit” cannot use function_ref finalization at all — cross-pool edges must stay MACH_LOAD_BOUND_MODULE. So the reloadable form is also the unfinalized form. Worth stating in the plan; it is the mechanical reason R7’s granularity lever is also the optimization lever.

5.5 The pass profiles — dev is mostly already gone

pit-compiler/passflags.cm (221 L). Profile machinery proper is :88-108 = 21 LOC; the rest is the switch registry (:31-58), aliases (:60-64), helpers, parse (:145-166), the env diagnostic read (:170-188) and resolve (:194-219).

Exactly what differs, verified line by line:

:88     ALL      = all 25 switches on
:89-91  DEV_UNIT = ALL minus {inline, licm, int_ranges, sroa, forward, join_types, switch}
:92-94  DEV_LINK = ALL minus {join_types}
:95-97  SHIP     = ALL minus {join_types}
:98-101 SMALL    = ALL minus {join_types}, then inline = false

Two real facts (dev/unit turns off 6 passes at :90; small turns off inline at :100) and two dead ones:

  1. DEV_LINK (:92-94) is byte-identical to SHIP (:95-97) — same construction, same set. Half of “three profiles” is already one profile.
  2. join_types is off in all three at both stages (:90, :93, :96, :99), so it is not a profile axis at all — the linked streamline turns it on through its own link-plan switch (pit-linker/mcode_link.cm:68-71), as the header says at :12-18.

No production caller ever passes dev or small. Every producer defaults to "ship": pit-shop/builder_worker.ce:75-79, :134-138; pit-shop/build_fleet.cm:72, :85; pit-shop/shop_build.cm:98-99, :123, :1798-1799; pit-shop/shop_realize.cm:388-392; literal "ship" at shop_realize.cm:1758, :1801 and shop_build.cm:2552, :2776; pit-shop/boot_cart.cm:45 (link-plan vocabulary). Every literal "dev"/"small" compiler_profile in the tree is in tests/ or plans/. The only compiler-side reader of PROFILES is pit-compiler/streamline.cm:20, :36.

The profile name DOES feed both derivation caches — deleting the value is free, deleting the field is not:

  1. K_mcodepit-shop/shop_store.cm:97-105, specifically :103 ("\n" + text(d.compiler_profile || "ship") +), documented at :95-96. Constructed at pit-shop/shop_build.cm:983-987, pit-shop/shop_fetch.cm:693-697, pit-shop/derivation_status.cm:35-39.
  2. The realization context hash — pit-shop/shop_realize.cm:416, with the landmine comment at :410-415: “a realization built with the dev pass set must never satisfy ship. Keep the profile in the realization salt as well as each K_mcode key.” Threaded at :1058, :1436, :1458. The regression history is written at :367-387 — a dev realization default meant no seeded resident could match its own realization: cold ps 0.42 s → 21.0 s, +36 % store bytes.

Because of the || "ship" default, every existing key is byte-identical after deleting the dev profile — no cache invalidation. Dropping the field itself does re-key everything; don’t.

What breaks if dev goes:

whatfile:linenote
the definitionspassflags.cm:89-91 (DEV_UNIT), :92-94 (DEV_LINK), :104 (PROFILES.dev)delete, 8 LOC
header doc examples naming devpassflags.cm:5, :7, :9doc edit
resolve returns null for an unknown profilepassflags.cm:204a stale --compiler-profile dev now returns null → streamline gets no switch record. Needs a named refusal, not a null.
the link-plan profile vocabulary, which separately names devpit-linker/mcode_link.cm:104-108 (valid_link_plan accepts dev|ship|boot; dev forces granularity: "module"), consumed at :2424-2425 (plan.profile == "boot" ? "ship" : plan.profilepassflags.resolve)a dev link plan would resolve to null. The one real breakage in shipped code, invisible today only because no production caller builds one. And R7 makes granularity the whole lever, so this vocabulary is exactly what R7 is about.
profile validatorshop_tools/internal/compiler_perf.cm:456-459drop the dev arm
CLI flag textshop_tools/shop.ce:21, :159-160; shop_tools/compile.ce:1139says (dev|ship|small; default ship)
test_join_types_profile_switchtests/compile.cm:3734-3754 (asserts at :3735-3736, :3746-3747)fails — resolve({profile:"dev"}) returns null
key_checks “compiler profile did not move K_mcode”tests/store_freshness.ce:83-86passes if the field stays
profile_cache_checkstests/store_freshness.ce:52-112 (helper), :225-278 — esp. :231, :237-240, :261-263, :273, :277fails — compiles the same fixture under both profiles and asserts distinct content hashes; unsatisfiable
resident_stability_checkstests/store_freshness.ce:300-323, esp. :310, :321-323assertion becomes vacuous; rewrite or delete
profile realize round-triptests/store_freshness.ce:325-340passes msg.compiler_profile = profile
DEV_PLAN link plantests/mcode_link.cm:12, :228, :261-266, :518:261-266 asserts dev-vs-ship produce different instruction shapes (load vs function_ref) — this is the link-plan dev, and R7 keeps granularity while retiring passes
docsdocs/architecture/build-and-artifacts.md:195-217, esp. :200-202 ("dev is the per-unit rebuild profile") and :212-214 ("dev skips the expensive unit-stage inline, LICM, integer-range, SROA, field-forwarding, and switch passes; its link-stage settings remain all-on")rewrite — this is where R7’s “dev differs by pool granularity, not passes” lands
fuzz commentshop_tools/fuzz.ce:29 (“OFF in every shipped profile (dev, dev/link, ship, small)”)reword

Verdict on the dev pass-profile: DELETABLE, and cheap. ~8 LOC of definition, ~21 LOC of profile machinery, 2 shipped source files, 2 CLI strings, 1 validator, 4 test blocks across 3 files, 1 doc section, and zero cache invalidation. It matches the switch report’s measurement (dev within 0.32 % of ship while compiling slower).

small should collapse too. passflags.cm:100 (SMALL.inline = false) is the entire difference from ship. If profiles collapse, small is better expressed as {profile: "ship", passes: {inline: false}} — which resolve already supports at :207. That leaves one pass profile, and R7’s dev/ship distinction becomes purely the link plan’s granularity.


6. Residue these rulings subsume

6.1 PIT_POOL_PAYLOAD stale state block — CONFIRMED STALE, delete

plans/archive/todo.md:93-94 says “the lever is read by nothing. Delete it.” Verified, and it is larger than todo.md says:

  • pit-shop/mach_lower.cm:42-79 — the whole “STATE, 2026-07-29: the pool lane is BUILT AND NOT ON. PIT_POOL_PAYLOAD=1 turns it on” block, including the RUNG-2 measurement table and the cli/pgo_flags gap note. 38 comment lines. todo.md names :42-55; the block actually runs to :79.
  • The lever is genuinely gone from code: pit-shop/terminal.ce:2181-2183 is now function pool_payload_wanted() { return true } with the comment “FLIPPED 2026-07-30: pools are the only payload the shop cements”. No getenv/os.env read of PIT_POOL_PAYLOAD survives anywhere (rg PIT_POOL_PAYLOAD outside plans/ hits only comments).
  • pit-shop/mach_lower.cm:53-56 (the “recipe is ./pit down && PIT_POOL_PAYLOAD=1” instruction) is actively misleading — it tells a reader to set a variable nothing reads.
  • Adjacent stale comments naming the dead lever, same sweep: pit-shop/mach_lower.cm:316-318, shop_tools/test.ce:149, tests/hook_image_name.ce:15.
  • R6/R7 subsume this: once “a cart is always one mach pool” and “the shop is one pool per unit or per executable” are the ruling, there is no “pool lane off” state to describe.

NOT deletable in the same pass: pit-shop/terminal.ce:2418-2432 — the --pgo_collect refusal. Its own comment says “at which point this whole block deletes”, but the trigger is L2b’s drain, which plans/programs.md:263-265 explicitly carries forward untouched. Listed in the table as row 15 so it is not swept by mistake.

6.2 allow_compileCONFIRMED DEAD, and it takes the whole handler with it

plans/archive/todo.md:112-114 asks for “one look and a ruling”. The look:

  • pit-shop/policy.ce:63allow_compile: true in CONFIG.policy.
  • pit-shop/policy.ce:234-240function allow(kind); :239 is if (kind == "compile") return p.allow_compile != false.
  • allow() has exactly three call sites, all inside policy.ce: :370 (msg.type == "allow"), :378 (msg.type == "native"), :483 (msg.type == "executable_policy").
  • rg "'allow'|\"allow\"" --glob '!plans/**' --glob '!website/**' finds exactly one hit outside policy.cehttp/hpack_tables.cm:89, the HTTP allow header name. Nothing in the tree ever sends {type: "allow"}. So policy.ce:369-376 is an unreachable handler, and allow_compile (:63) and allow_static (:61) are only reachable through it.
  • Same for executable_policy (:482) and therefore allow_mach (:62,238): the only tree hits are the handler itself and tests/executable_policy.ce:18 (which is a test_result send, not a request). shop_build.cm builds a local compatibility_policy_decision (:2086-2096) instead of asking.
  • Same for type: "native" (:378) and therefore allow_dylib: the two hits for type: "native" are a record field in shop_build.cm:1392 and a fixture in tests/pgo.cm:46, not sends.
  • The one caveat that keeps this honest: pit-shop/clerk.ce:1077-1085 is a generic passthrough{type: "policy", request: {…}} forwards any record to the policy actor. So an out-of-tree caller could reach {type: "allow", kind: "compile"}. In-tree the passthrough is used only for {type: "configure"} (tests/cli/policy_veto.ce:56, :150, :173), and the shop’s own policy traffic is {type: "environment"} (clerk.ce:600), {type: "catalogs"} (shop_source.cm:2947) and {type: "configure"} (clerk.ce:1661). So: no in-tree sender, reachable only through the documented passthrough — which is what makes it a deletable knob rather than a dead one.

Verdict: the diary’s record was right and the deletion was incomplete — the knob survived because the handler survived. Delete policy.ce:369-376, :63, :61, and the "static" / "compile" arms of allow() (:236, :239). ~10 lines. Keep allow_dylib/native (:60, :237, reached from :378) and allow_mach (:62, :238, reached from :483).

Why a ruling subsumes it: R3a says the shop degrades by actor availability — “it cannot compile, because there is no mcode compiler actor in this cart”, refused by name. A allow_compile: false policy bit is the other model (a knob that says no while the compiler is present), and R3a replaces it. R8 does the same for allow_mach: once mach is never shipped, “may this shop accept a mach payload” stops being a policy question — flag allow_mach (:62, :238, :483) as a second-round delete once §2 lands.

6.3 pit.bootstrap.target@1 — the open ruling

plans/archive/todo.md:96-100 records the remaining ~140 spec lines as needing a ruling. Located: docs/spec/artifact-formats.md:219-357 ("### Target bootstrap configuration" through the pit.bootstrap.provider.catalog@1 rows and the “implementation hash is not a complete bootstrap target” close at :357). Confirmed no producer and no reader in code — the only non-doc hits are plans/archive/transition-diary.md:796,933,943,1399,1524, which record its constructor as deleted (T014, audited 2026-08-01).

R8 bears on it: the record is per-target bootstrap configuration for locally finalizing a portable bundle. Under R8 the shipped cross-target artifact is “the C binary plus its fused mach blob”, built by forge — which does not read this record. That makes it dead design, not pending target truth. Recommend: delete, citing R8. ~140 doc lines, zero code.

6.4 Residue items these rulings do NOT cover (leave in plans/archive/todo.md)

  • plans/archive/todo.md:101-104 — the second codename pass (CAKE1/FRESH1/SHOP1/…).
  • plans/archive/todo.md:105-107 — stale “pit.cart@1 trailer” comments at source/cart_boot.c:344 and cake/manifest.cm:376.
  • plans/archive/todo.md:108-111 — T020’s skipped meson parity gate.
  • plans/archive/todo.md:115-117 — the do-not-delete note on runtime_code_count/code_cache_* (pinned at zero by tests/runtime_arena_counters.cm as L3’s observable). Keep-list item.
  • plans/archive/todo.md:118-120docs/shop/c-modules.md names nonexistent recipes.
  • plans/archive/todo.md:121-123 — the “lane” glossary ambiguity. R7 resolves the compilation half of this (pool-per-unit vs pool-per-executable is now the named lever), so the glossary sentence should be written from R7 rather than from mcode.md:104-108.

7. Keep-list (do not delete under any of these rulings)

thingwhy
local K_mach caching in the shop storeR8 kills sharing, not local cache — a machine must cache the mach it lowered for itself
the forge cross-build lane and boot/targets/** machR8’s one legitimate cross-platform product is “the C binary plus the heavily fused mach blob bound into it” (plans/programs.md:177-179)
pool content-hash identity (image_hash on frames, mach_origin_key)plans/programs.md:296-308 (§7.2) keeps identity while deleting sharing — it is the debug key
pit-shop/mach_lower.cm:38 foreign-target refusalplans/programs.md:258-260 — “correct and permanent for every other path”
{mcode unit hash, function ID} stable identityS1; both R4’s repoint and the debugger need it
PIT_INPROCESSR1 names PIT_APP only; cake/forge.cm:1191 uses it to press the seed, and 6 test files depend on it
runtime_code_count / code_cache_* countersplans/archive/todo.md:115-117, pinned at zero by tests/runtime_arena_counters.cm
pit-shop/terminal.ce:2418-2432 PGO refusalits deletion trigger is L2b, carried forward untouched by plans/programs.md:263
pit-compiler/passflags.cm semantic loweringspassflags.cm:22-25insert_stone, lower_concat, lower_concat_space, compress_slots “define valid mcode output and are never switchable”
pit-shop/shop_store.cmall 11 K_mach functions§2.4: every one is local cache or §7.2 identity; zero deletions
pit-shop/courier*.cm / courier.ce§2.3(a): actor messages only; carries no artifacts of any kind
advertise / serve (pit-shop/source_upstream.cm)§2.3(b): the key derivation is the kind filter — pit.source.file@1 only
boot/engine_lite.mach§2.2: forge build input, cemented into root.cart and .incbin’d into the binary; never shipped loose
source/mach_pool.c:4590-4617 (function_ref lowering)§5.4: pool-lane only, starts working when R6 lands; it is the payoff, not the casualty
pit-linker/mcode_link.cm:159-796 (the provider recognizer, 628 L)§3.1: stone proves immutability, not identity; finalization still must know which function each member holds
pit-compiler/mcode.cm:510-541 (intrinsic_value, prepend_unit_intrinsics)§5.2: the static lane rides them, but they are shared with log/text/format/$receiver

8. What a ruling ALMOST kills but doesn’t — and why

These are the traps. Each looks deletable from the ruling’s text and is not.

thingwhich ruling seems to kill itwhy it survives
cart N-section machinery (cement.cm:731-782, cart2.cm:279-330, cart/cart.cm:227,282,510,540,732-786)R6, “a cart is always one mach pool”R6’s own next sentence keeps the split “for esoteric targets with ROM windows and paging (gameboy)”, and cart2.cm:160-161,171-172,196-199 already implements exactly that (section_window). ~150-250 L goes unexercised but live. Needs a separate ruling to actually delete
boot/targets/linux/{root.cart,engine_lite.mach,boot.qop} (22.8 MB)R8, “mach blobs are neither shared nor shipped”It is mach crossing machines over Git — but it is the cold bootstrap floor for a Linux box with no pit, consumed by 8 CI steps (scripts/use_ci_seed.sh + both workflows). R8 as written deletes CI. Needs a named second exception
source/mach_pool_fixture.h (96,815 b, ten cross-pressed profiles)R8, “cross-target mach lowering outside the forge path”It is the cross-emitter gate for source/mach_pool_test.c, regenerated on every make smoke (Makefile:313-334). R8 as written deletes make smoke. Needs a third (“test fixtures”) exception
pit-shop/mach_lower.cm:196-218 (the foreign-target refusal)it looks like the cross-target machinery R8 removesplans/programs.md:256-260 rules the opposite: it is “correct and permanent for every other path”. KEEP, and keep tests/cross_target_lowering.ce with it
pit-linker/mcode_link.cm:798-1092 (the import-holder census)§5 classifies it as pool-lane, so it survives the static lane’s death…but R5 deletes it anyway, for a different reason (stone makes the proof unnecessary). Both classifications are right; the census dies to R5, not to R6/R7
PIT_INPROCESSreads like the same environmental mode-inference R1 abolishesR1 names PIT_APP only. cake/forge.cm:1191 uses PIT_INPROCESS to press the seed, and 6 test files depend on it. It becomes “the declaration says in-process”, but the override must survive for tests that cannot re-forge a cart
pit-shop/terminal.ce:2418-2432 (the --pgo_collect refusal)its own comment says “this whole block deletes”…but the trigger is L2b’s drain, which plans/programs.md:263 explicitly carries forward untouched. Do not sweep it with the PIT_POOL_PAYLOAD residue next door
platform/daemon-stub/ (24 L)R9, “optionality must move from the recipe to the product”It is the definition of “this target has no daemon”. Under R9 it becomes the default rather than a selected file — a relocation, not a deletion. Deleting it before the per-product lever exists breaks ten recipes
pit-shop/target_catalog.cm’s catalog itselfR8 kills executable sharingOnly the multi-target variant dimension dies. A single-object catalog is still how a locator names its realized executable locally, and pit.catalog.variants@1 appears in boot.qop’s own manifest — so the seed writer must be changed in the same landing or the seed stops parsing
pit-compiler/cross_unit_inline_experiment.cm:103-190 (prove_export*)R5 makes export immutability a compiler fact, so a second recognizer looks redundantIt is a merge candidate with export_summary, not a deletion — and merging it is orthogonal to R5. Flag it; don’t fold it into this arc

9. Sequencing notes

  1. §7.3 (mcode is host-rep-tainted) blocks the positive half of R8. Until tokenize.cm:281-284 / fold.cm:118 stop folding in host arithmetic, “mcode is the only shared artifact” ships a nan64-limited artifact to a nan32 target — and deleting mach sharing first removes the only currently correct way to get a rep-exact payload onto a narrow-rep target. Fix 7.3 before rows 9-11, not in parallel.
  2. R5’s deletion hinges on the compiler emitting a real stone op at the module main’s return, immediately before it (§3.0). A runtime-side freeze makes row 12 worth zero lines.
  3. Row 13 (the static lane) can only land after BOTH the press flip (R6) and the dev realize move (R7) are green. It is the only lane production uses. Land it as the last thing in the arc, behind make check-all.
  4. Row 14 (the daemon split) needs R9’s per-product lever designed first. The recipe bit and the platform-package file are a contract enforced by tests/recipes.ce:194-196; a per-product lever has to replace that test, not drop it.
  5. The Playdate ship lane (--payload mach) needs a target-side presser before row 9 can land. Nothing in the tree presses on the Playdate today.

Source: plans/proposal-notes/deletion-inventory.md