Archive — history, not state. Kept for its reasoning and its evidence; its plan is closed.

Overnight run — judgement calls made without a ruling (2026-07-28 → 29)

John left with: “Continue on and finish out 6 and 7… If you encounter blockers like bad diagnostics or tests are taking a long time, investigate and fix it… It’s OK to delete code, and expected; we’re cleaning it up after all. If we need something, we have the git history. Any decisions you make that were not scoped to get it working through 7, just document them and report when it’s all done.”

This file is that report. Every entry is a decision an agent or the orchestrator made without a ruling, with the reasoning, so John can reverse any of them cheaply. Rulings he actually gave live in plans/edicts.md; landing records live in plans/next-arc.md.


Decisions

D1 — $hook naming for pool-backed functions (delegated explicitly)

5b stopped because mach_exec_name_cstr returns NULL for images by design (an image keeps its names as stone text in the pool), so $hook events carry no name and hook_wake.ce cannot match a site. John delegated this call. Framing used: $hook is a ring recorder (gather; a drainer derives tracing/counting/timing), and $pgo/$hook must compile out when not granted — so a cost paid only when the hook is armed is consistent with the design, a cost paid on every call is not. Outcome: recorded below when 5c reports.

D2 — the git requestor test cloned the repository (orchestrator, unscoped, already landed)

tests/git_requestor.ce set its clone source to config.runtime_path, so every test all handed git a 1.07 GiB pack to serve; pack-objects pinned a core for a minute per run, several suites multiplied it, and each run leaked a ~50 MB clone under a fixed /tmp name (2.0 GB accumulated on this machine). John spotted the CPU himself. Rewritten to build a one-file, one-commit fixture repo in a minted temp root: 1m+ and 51 MB → 0.84s and nothing. Nothing the test asserts depends on the source’s history. Landed fecf1e48.

D3 — cli/vm_only provisions its shop (orchestrator, in-class, already landed)

It builds a shop from the seed alone, so it could not resolve the log claim its test program writes — the same provisioning source_bundle and fuzz_progress already needed after the log-is-claimed landing, and exactly the “correct behavior pending the shop-composition verb” the edicts describe. Copied, never linked. Landed d902252e.

D4 — SUPERSEDED BY JOHN 2026-07-29: there is no cross-target cement at all

He ruled directly: “There should be no cross target cement. There should only be pmp1… you have the mcode that the runtime can lower to its specific ABI.” So the question D4 answered does not arise — a build does not cement for a foreign target, it ships mcode and the target lowers it. The {numrep, endian} arm deletes rather than migrating. See the edicts section “ONLY pmp1. NO CROSS-TARGET CEMENT.” The original text is kept below for the reasoning trail only.

D4 (original, superseded) — cross-target cement uses pmcd windows; pmac dies entirely (orchestrator)

The question (recon §5.1): the cross-target/big-endian cement lane (mach_lower.cm:76-78, driven by builder_worker.ce:114 and shop_build.cm:732) is a PERMANENT pmac producer, not a transitional one — mach_lower.cm:22-27 calls it a deliberate capability boundary: “a cross-rep or big-endian build keeps the per-unit mach blob until the lowering can stamp a foreign target.” If it keeps pmac, stone 6 cannot claim the format is gone, and because every target builds from one source tree, keeping any pmac READER keeps it everywhere.

Decision: route cross-target cement through pmcd windows instead. The reasoning is M1’s own: a pmp1 header carries a target-profile hash and a mach-ABI hash and the opener refuses a mismatch, but pmcd carries no stamp at all (mach.c:2765-2782) — that is exactly why root.cart’s windows are pmcd. A cross-target cart therefore does not need a foreign-target pool stamp; it needs no stamp, and the target’s own runtime lowers the window with its own emitter at load, which is already the normative dev boot lane (docs/architecture/boot.md:51-59). This deletes pmac outright rather than preserving it behind a named exception, and it adds no new stamping machinery.

Fallback if an agent proves this infeasible: keep pmac for the cross-target arm only, name the exception explicitly in edicts.md, and record the retirement condition. Do not silently leave it and claim stone 6 complete.

Caveat: no gate cements a cross-target cart today (recon §6), so this lane is untested either way. An agent taking D4 must add that coverage or say plainly that it did not.

D5 — $mach_load / $mach_compile_mcode_bin keep their NAMES and change payload form (orchestrator)

The question (recon §5.1): edicts.md rules the two names “verify and kill”, but they have 125 call sites across 40 .cm/.ce files (38 in tests/compile.cm alone, which make check runs), and John’s surviving constraint is that engine_lite must keep the ABILITY to make C functions from C modules, because functions cannot cross actors.

Decision: do not touch the names or the 125 sites in this arc. Change what they carry. mach_compile_mcode_bin produces a pool instead of a pmac blob; mach_load accepts one. The capability stays engine-side exactly as ruled, the call sites are untouched, and pmac still dies. Renaming or deleting the surface is a separate, later, purely-cosmetic landing with no bearing on the premise arc — and doing it now would put a 125-site mechanical edit in the middle of the deletion chain for no structural gain.

This also preserves tests/image_lanes.ce:102’s already-proven shape (mach_compile_mcode_bin(name, code, {fragment: true}) + mach_pool_emit) as the migration path rather than inventing a second one.

D6 — stone 7 scope calls, decided per the recon’s recommendation (orchestrator)

Taken as recommended in plans/stone-6-7-map.md §3.2-§3.3, all documented there in full:

  • The crossing moves engine_claims derivation into build_engine_record first, after which C never reads ENTRIES and 4b’s section-kind recipe applies (additive BOOT word → Pit boot walker → start_plan.c deletes). Two phases, one reseed each.

  • root.cart keeps M1’s ABI-neutrality and gets SMALLER — two pmcd windows (engine + boot walker) instead of 23. shop_actor stops being a cold-boot concern and takes the pool lane like any other module, so its structural exclusion evaporates without touching M1’s rule. Explicitly NOT chosen: making root.cart carry a pool (an ABI bump becomes a flag day again, which is the exact thing M1 bought).

  • Medium discovery: keep appended-to-binary + PIT_ROOT_CART in C; --cart/PIT_CART/ boot/boot.cart become a clerk mountTHIS BULLET IS WRONG AND WAS RETRACTED 2026-07-29. The 7.4 agent refused it and proved four things: (1) there is no clerk — the word appears in zero lines of executable code; (2) docs/architecture/boot.md:122, which I cited FOR the move, says the opposite — “Boot is deliberately stupid. It has the cart C mapped for it, starts the clerk” — and the clerk ships INSIDE the cart, so it cannot be what discovers the cart; (3) --cart is the only boot lane for four consoles (n64/psp/dc/ps1 all have a hard-NULL getenv and no argv of their own; platform/n64/main_n64.c:305 calls it “the seam”); (4) boot/boot.cart is the dev daemon’s own boot medium, not a convenience. PIT_ROOT_CART also stays LAST rather than being promoted: putting an env var above the appended cart would let it override the runtime’s own always-ABI-matched medium, which is the guarantee 7.3’s walker fallback rests on.

    Consequence for the ~150-line target: unreachable as stated. cart_boot.c splits almost evenly into ~227 lines of header-parse-and-enter (already as small as validating a stamped, sectioned format costs) and ~229 lines of medium discovery, which is a function of how many media the system must boot from, not of how the C is written. The next real reduction is the clerk split itself, after which the content lanes can leave — and --cart stays in C regardless, for the consoles.

  • The honest line number is ~150 for the cart-mount + header + enter path and ~240-260 counting runtime creation and the boot wota, excluding host.c. Reported rather than chased: hitting 150 by moving work into host.c would be bookkeeping, not simplification.

D7 — five allocation budgets rebaselined after the interning change (orchestrator)

Pit_SetPropertyStr no longer interns, so a C-string property name now allocates an actor-heap text instead of hitting the runtime table. Measured effect: every bench got FASTER (numeric_loop 5.5→5.3ms, gc_churn 2.8→2.6ms, compile corpus flat), and alloc_bytes rose by a constant 2.2–4.3 KB / 28–63 allocations per run, independent of workloadgc_churn performs 100,017 allocations and gains 63. It is fixed harness setup, not per-iteration cost, which is why it reads as 200% on benches whose totals are under 14 KB.

Decision: rebaseline those five entries to their measured values; leave the timing baselines and the four in-tolerance allocation entries untouched. The Makefile’s documented re-baseline is “delete the file”, which would also discard every timing baseline — too blunt for a change that improved timings. Rebaselining only what moved keeps the gate tight everywhere else. John has ruled that performance work is explicitly not wanted right now; this is a correctness-and-contention win with a small constant memory cost, and it is recorded rather than tuned.

Worth noting as an unlooked-for win: pit_key_new took rt->ct_lock, a process-wide mutex, on every Pit_SetPropertyStr — ~796 call sites. That lock is now off the runtime’s hottest path for all actor threads, which is the likely source of the timing improvement.

Also corrected by measurement: the expectation that this would drop the ct arena substantially was wrong. It drops 9,928 bytes (0.68%). The table dedups, so 796 sites over a small fixed vocabulary cost ~10 KB, while compilation moves that arena by ~3.7 MB. Largest caller by call count is not largest contributor by bytes. What the change does close is the uncapped path — names that vary at runtime, e.g. regexp named groups.

A latent GC bug fell out of it and is fixed: pit_regexp_exec held a per-capture substring unrooted across Pit_SetPropertyStr and then used it again at Pit_SetPropertyNumber. Pre-existing (both could already collect), but the unconditional key allocation makes it reachable.

D8 — $hook resolves a pool-backed name AT FIRE TIME (agent, delegated by John)

The delegated call from 5b. Decided for a reason that turned out to be decisive rather than a preference: wake-on-site matches on the name inside the firing turn (pit_hook_match_check), so a name that only exists after a drain cannot arm a pinpoint breakpoint at all — the deferred design does not merely cost more machinery, it cannot express the feature. The cost is paid only by an armed debuggee (every site is inside PIT_HOOK_ARMED and compiles out without the endowment), which is John’s ruling exactly. Guarded on Pit_IsText so it never reaches Pit_ToString; pit_malloc_rt triggers no GC, so live frame pointers stay valid. File and line stay absent — those live in the origin map.

D9 — PLAN_IMAGE_MAX raised 256 → 1024 (orchestrator)

The cap bounds a daemon-lifetime scratch registry and makes the refusal honest; it is not meant to be a particular number, and tests/cli/plan_image_cap.ce fills to whatever it is rather than hardcoding it, so the refusal path stays gated. 256 had become a wall the suite hits in ordinary use: test all registers an image per test actor, a two-actor test costs two, and the suite could no longer accept a new test without displacing an existing one — 5c’s $hook gate could not be added at all. It was also the documented source of spurious reds on long sessions. 1024 entries is ~88KB of static array. Verified: test all went 2683/2 → 2693/1 with the new test in.

D10 — the second lever blocker is REAL and is being fixed, not worked around (orchestrator)

5c found that PIT_POOL_PAYLOAD is still blocked, and no longer by naming: the image lane has no in-loop call path. MACH_CALL/INVOKE/GOINVOKE enter a callee in-loop only under PIT_FUNC_KIND_REGISTER; an image callee falls to the “C, native, or bytecode” arm, which does vm_call_depth++ + Pit_CallInternal. The only guard between pause_flag == 1 and goto suspend is vm_call_depth == 0, so nothing below the outermost Pit function in a pool-backed actor can be preempted mid-turn. Measured: the wake letter arrives at 0.051s (register) vs 0.528s (pool), the latter being turn end.

This is not a debugger feature — it is runaway-actor protection and mid-turn freeze for the entire fleet once the lever flips. Dispatched as stone 5d rather than deferred, because turning the lever on without it would ship a fleet that cannot be preempted. The encouraging half: every accessor is already lane-aware and mach_exec_resume already returns into image code in-loop, so the machinery exists and only the call-side entry is missing.

D11 — the lever stays OFF despite 5d closing the preemption blocker (orchestrator)

5d reached rung 2: in-loop image calls work and the pool lane is preemptible (wake letter at 56ms instead of 525ms == turn end). But test all with PIT_POOL_PAYLOAD=1 is 2686/2692, not clean. The five remaining failures are pre-existing image-lane gaps, not 5d’s: profile_report + cli/pgo_flags (mach_exec_pgo returns NULL for images by construction), tests/log_stack.ce (the pool origin map is unconsulted, so the stack is empty), one cli/debug_tool assertion, and cli/publish_subscribe (flaky only under the lever, and proven pre-dating 5d — the identical six runs failed three times against the pre-fix binary too).

Turning the lever on would put the tree red, which violates the standing rule that nothing lands on red. So the lever stays off and the gaps are now named with measurements in pit-shop/mach_lower.cm’s state block (which was stale — it still described 5b’s failure). Closing them is stone 5e; each is a lane-awareness gap of the same family 5b and 5d fixed ($pgo, the origin map, the debug surface), so they are tractable rather than deep.

D12 — the inspect_debug diagnosis I handed down was WRONG, and the agent was right to revert (agent)

I passed 5d a root cause from an earlier agent: Pit_RaiseDisrupt leaves ctx->disrupt_msg stale when a Pit handler catches, and scheduler.c later uses it as the death reason. 5d implemented that one-liner, measured it, and it changed nothing. It then instrumented and found two real carriers, neither of which is disrupt_msg:

  1. pit-shop/terminal.ce:2539 treats any panic-channel line as fatal, and Pit_RaiseDisrupt logs to panic at the raise site — before anyone can know a handler will catch it. That is why a caught $inspect.frames(self) exits 1 while a caught bare disrupt exits 0: MACH_DISRUPT never calls Pit_RaiseDisrupt, so it emits no panic line. The disrupt_msg difference was a correlated red herring.
  2. For ./pit test run, the harness keys on the lifecycle event type, driven by disruption_reported, which the halt-time unwind sets true at top level. pit.c:213 has a special case for exactly this — but only in the boot lane, not for a spawned test actor.

Both real fixes sit in the error-surfacing seam that edicts already has a standing ruling on (“the fix for invisible errors is DELIVERY — never a new error-return shape”), and would collide with queued work there. The agent reverted its one-liner rather than shipping a partial unmeasured change into the exact seam the real fix lives in. That was the right call and is why inspect_debug remains a known intermittent.

D13 — kim8 keeps the register lane as a PROFILE arm, and the question is sharpened (agent)

A pool’s STONE section is UTF-32 by format, so a text=kim8 build has no mcode→pool path at all — kim8 holds up not merely the pmac reader but the whole register lane. Deleting the arm would narrow a target’s capability while John’s ruling is open, so the agent made it a profile arm (sanctioned by the system description) rather than a compatibility arm (forbidden by edict 1), and pinned the kim8 answer with a C test that runs in every arm before that file’s self-skip.

The sharpened question for John: must a kim8 build BOOT, or is kim8 compile-only? Nothing in the tree establishes that a kim8 build has ever mounted a cart. If the answer is compile-only, the register lane collapses further than stone 6 currently plans.

D14 — a pre-existing deadlock found and deliberately NOT fixed (agent)

PIT_INPROCESS=1 deadlocks on a cold realization — reproduced at 68b97fc9 with zero changes applied. Two actors block: one in scheduler_snapshot, one in actor_watch_stop_register — a lock-order inversion the in-process lane’s timing exposes. It cost the agent ~30 minutes because it presents exactly like the payload switch having broken boot. No gate catches it: cli/inprocess runs against already-realized content. Left alone deliberately — a scheduler lock-order fix inside a payload-form change would make both unreviewable.


Carried forward — open questions NOT resolved overnight

These were live before John left and are not in scope for stones 6-7. Recorded so they are not lost:

  • $root vs $shop — his own hypothesis that they are the same, untested.
  • $mach_load / $mach_compile_mcode_bin — his “totally handled by the root now” is contradicted by four live users (policy.ce, mcode_lower.cm, forth/demo.ce, tests/forth.cm). Retiring them needs a home for the capability.
  • $fd leaving the floor — a real conversion, not a free deletion.
  • $self_id’s three callers (terminal.ce, courier.ce, profile.ce) — need an id accessor off $self before the name can go.
  • The mach sidecar key collision (shop_store.cm mach_debug_key/mach_origin_key): keyed on the mach content hash alone, so two different sources lowering to identical mach resolve stack frames to the wrong file. The key-completeness agent found the brief’s proposed fix is a no-op and the real fix (fold the module locator) is a derivation-contract change on both sides with no reader coverage. Scoped work, deliberately not a drive-by.
  • -DPIT_TARGET_ARCH is the host arch on cross builds — fixing it means an arch field in the recipe schema.
  • Cold-bootstrap build_id reads the clock — making it constant would break the daemon’s stale-binary detection, which compares build_id strings. Needs a ruling, not a patch.
  • network/http2 — the one genuinely red test, pre-existing, unrelated to this arc.

Source: plans/archive/overnight-decisions.md