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

The finalization arc — THE live plan (ruled 2026-07-29)

The one plan in flight. The target design lives in docs/ — normative pages for this arc: docs/architecture/principles.md (the golden rules), build-and-artifacts.md (“Pit emits, C reads” + “Finalizing for a target”), boot.md, cartridges.md, docs/glossary.md (the ratified vocabulary), docs/spec/artifact-formats.md (“One producer, many profiles”). Historical rulings and the superseded plans are in plans/archive/ — read them for reasoning, never for direction.

The rulings this implements (John, 2026-07-29)

  • No PORTABLE cement (“no cross-target cement” was a language error). Cement is always for one named profile; cross-pressing carts for other platforms is the expected, ordinary act. Portability ends at mcode.
  • Pit emits everything; C only reads. C never writes what Pit can write; C reads only what boot needs before Pit runs (fixed header + nota metadata); every C-read format has one writer, in Pit, exercised by CI. The authority is the per-arm C reader/executor, gated by pressed-fixture boots (replaces the byte-identity mechanism, which retires with the C emitter).
  • Carts carry pools; mcode never boots. M1 repealed; pmcd and pmac both die. An ABI bump = the old binary presses the new cart (a new ABI is just another profile).
  • Actors are the unit of code-stripping; the compiler is never shipped. A live fleet is a hard prerequisite for all compilation, forever. (“This is ideal” — John.)
  • One execution lane (pmp1). kim8’s stone layout is a future profile arm of the emitter (built when a recipe adopts kim8 — today none does); the kim8 register lane in C deletes. Native/AOT stays parked (edict 7) and conforms to one-lane when its pass comes.
  • Formats: metadata is nota; pools are binary inside (O(1) row indexing — the one sanctioned magic); one fixed outer header on boot media, stamp checked by memcmp before any parse; pool sections at aligned offsets, never inline nota blobs. qop stays — a legitimate format, John 2026-07-29. Daemon wire is JSON lines and stays.
  • Terminology ratified — see the glossary: pool / image / stamp / profile / manifest / realization / cement / press / bundle. Dead words: pmac, pmcd, pit.executable@1.

The bootstrap contract (replaces M1’s protection — enforce, never work around)

  1. Every commit carries a matching (source, cart) pair; make seed verifies.
  2. Ordinary dev: the running system re-presses its own cart.
  3. An ABI/profile change lands WITH its old-binary-pressed cart in one landing. A commit whose cart stamp mismatches its source profile is a broken commit, full stop.
  4. Catastrophe (no working binary): the cold floor (boot/manifest/bootstrap.sh) builds the binary; by rule 1 the committed cart matches it. Wedged mid-crossing: check out the last green pair and press forward.
  5. Foreign targets only ever receive pressed carts; they never self-press.

Landings, in dependency order

Serial where noted; every landing merges by the drill (bottom of this file) and lands green.

L1 — the profile-parameterized emitter. RULED 2026-07-29 (John, after the L1 recon): (a) the per-rep value-encoding table is C, capability-gated — the five ABI-only rep TUs compile only into builds whose recipe grants the press capability; each rep header stays the single writer of its encoding (see build-and-artifacts.md “Pressing is a build capability”). (b) The gate is validate-everywhere, execute-where-endian-matches: one committed fixture table with a row per profile the emitter knows, every arm validates its row, execution proof for foreign-endian rows belongs to L6 on real runners. Byte order belongs to the LINKER, not the fragment. stamp.endian currently never reaches the build (pit_profile.h derives from the toolchain) and arm_identity_lint misses it — fix the lint in-lane. shoplib/mach_pool_emit.cm + the lowering take a full profile record as an argument; every target fact (endian, value width, object header width, text layout, hashes) is read from it, none compiled in. Arms needed now: endian (be targets), value width (nan32/fixed32 constant words), object header 32/64. utf32 stone stays the one text arm until a recipe adopts kim8. Wire the new gate: check-arms presses a fixture pool per arm with the emitter and BOOTS it under that arm’s C (extends the existing tools/pool_fixture.ce + mach_pool_asm_test.c pattern — which flips from “compare bytes with C’s emitter” to “validate and run what Pit pressed”).

L2 — close the pool-lane gaps, flip the lever. Then PIT_POOL_PAYLOAD=1 becomes the only behavior, the env lever deletes, reseed. (Lever reads happen in the DAEMON — ./pit down before any measurement.) State after the 2026-07-29/30 landings:

  • tests/log_stack.ce, profile_reportCLOSED already, green under the lever. The lane-aware stack walk (40db3673) had fixed both; nothing to do.
  • cli/debug_toolCLOSED. One assertion, and its own closes: text was right about the key and wrong about the producer: mach_pool_emit.cm’s emit has never returned an origin map, origin_map is a separate export nothing in the build path called, and mach_lower.cm read a linked.origin field that does not exist — so origin was silently null on every unit and no map was ever stored. Fixed by calling the producer, keying the sidecar by the pool CONTENT hash (the only hash a live frame can name; the store address is unreachable from a frame), and fetching it in shop_tools/debug.ce. Lever-on 19/19, lever-off 20/20.
  • cli/publish_subscribe / bundle_ingestCLOSED, and were never a flake. Carried for weeks as “~1 in 6, pre-existing”, the rate was shop state, not chance: on a fresh shop the refusal was deterministic. The bundle signature covered a RE-DERIVED encoding — publish signed nota.encode of a record it built by insertion, ingest re-built the same field set from the decoded manifest and re-encoded it — and a nota record is an unordered collection whose encoded key order belongs to the record OBJECT, not to its key set. Measured 20/20 disagreement on real published manifests, 15–35% on synthetic records. The signature now covers the /manifest member’s bytes as written and rides beside them in a /signature member; both manifest_signed_fields functions are gone. The rule the docs now state (docs/spec/nota.md, packages-and-distribution.md): nota bytes encode a value, they do not identify one — sign or hash bytes you kept, never bytes re-derived from a decoded value. Worth a grep for the same shape elsewhere; shoplib/canonical.cm exists because this bit once already.
  • cli/pgo_flagsRULED by John 2026-07-30: refuse now, build later. The refusal half is LANDED: --pgo_collect under the pool lane refuses by name in pit-shop/terminal.ce, beside the --aot refusal it copies, and tests/cli/pgo_flags.ce grew a lever arm asserting it (lever-on 1/1, lever-off 1/1). What it prevents, precisely: the pool lane registers no PGO session, so mach_pgo_snapshot_copy returns “no session”, pgo_capture saves an EMPTY profile and then pgo_snapshot_finish refuses to commit a generation of 0 — the user saw “PGO profile saved but collector commit failed” and a zero-site profile in the store. The drain is landing L2b, still open: C returns pool coordinates, pit joins the origin map (the two lanes disagree about what a site IS — a pool’s u64 stable_site_key cannot reconstruct {unit_hash, function, pc, kind}); PGO_SITES emission lands with it (neither producer writes the section today). Touches mach.c, development_shop.ce, pgo.cm, the emitter. The refusal deletes when the drain lands, along with the lever arm in the test.

L2b — the pool drain. THE IDENTITY HALF IS LANDED; THE DRAIN IS NOT. The fork below was RULED by John 2026-07-30 in favour of the docs, and the identity change shipped with it. Do not re-derive the map — build from it.

THE DRAIN IS BLOCKED ON A DEEPER WALL THAN THIS SECTION KNEW — MEASURED 2026-08-01. Everything from step 3 down assumed a working register lane for the pool lane to be joined to. There is none, and there has not been since D5 (d27b0701, “one payload form, and the register lane goes”, 2026-07-31 — the commit before the one this was attempted on). D5 deleted pit_load_mach_code, and with it mach_pgo_runtime_load: the only production constructor of a PitPGORuntimeCode, the only caller of mach_runtime_meta_ensure, and the only production caller of mach_pgo_session_attach. Measured on da6ffa0c:

  • mach_pgo_session_attach has two call sites, both inside pit_mach_test_pgo_snapshot_protocol (source/mach_vm.c:1235,1258) — a C self-test that builds its sessions by hand.
  • mach_runtime_meta_ensure (source/mach_vm.c:295) has zero callers, and nothing anywhere assigns runtime_meta->pgo.
  • mach_pgo_runtime_load and pit_load_mach_code are gone from the tree entirely.

So PGO collection is dead on both lanes, not merely unbuilt on the pool one: no actor registers a session, allocates a collector, or increments a counter. The refusal in pit-shop/terminal.ce now understates the situation rather than overstating it — its text blames the pool lane for a hole that is runtime-wide.

Nothing caught it, and that is the part worth keeping. tests/pgo_executable.ce is the only end-to-end PGO test and it never drains a counter: run_profile_roundtrip (line 177) synthesises its observations (executions: 64) and feeds them back through prepare_from_file, so it covers build, store and consume while the runtime half is absent. A drain test that runs a program and asserts a non-zero count is the gate this family never had, and it should land with the counters rather than after them.

What this does to the sequence below. Step 3 does not become unblocked when the identity road arrives — it becomes a rebuild of the collector-construction path D5 removed, now against a pool binding rather than a PitCodeRegister (PoolBinding, source/pit_internal.h:391, is the natural home, and its “immutable for one image generation” comment is a stated invariant a counter array would change). The session-identity blocker sits on top of that unchanged, and L3 phase 2 is still outstanding. Two walls, in series, not one.

Step 2 therefore stayed in the stash. The B-without-C rule bites harder than when it was written: the reader is not missing, it was deleted. And the hazard is live rather than hypothetical — --pgo_auto/--pgo_from are not refused under the pool lane and do produce PGO site descriptors (MACH_PGO_FIELD_LOAD_PIC via ml_pgo_site, source/mach_pool.c:2633), so an emitter landing alone would start setting the instrumented header bit on consume-mode pools whose sites the VM ignores. The stash was applied, reseeded and smoke-tested to prove it still reconciles — it auto-merges onto post-L3 mach_pool_emit.cm (the only drift is one comment line, mach.cmach_pool.c) — and then withdrawn. It is re-derivable from the shape spelled out in step 2 if lost.

Landed. A site is {mcode, function, site} — the mcode site id, exactly as the origin map names it (pit-compiler/pgo.cm site_key). C composes no identity JSON at all any more (mach_pgo_site_identity and its mid-string splice are gone); pit writes the identity and the runtime carries it as opaque constants. docs/spec/artifact-formats.md “PGO profile” now states the real row, which had been stale in three further ways (it omitted kind, immediate_failures and targets, and spelled the target list values).

The one finding worth carrying forward, because it cost a build-and-diagnose cycle. The obvious shape — store each site’s whole identity — does not work. It repeats a 71-character mcode hash once per site, and 512 selected sites overrun the 256 KiB runtime-wide PGO budget. It failed order-dependently: collection was green on a fresh daemon and red once tests/pgo.cm had run first, because the budget is runtime-wide, not per actor. And it surfaced as could not snapshot PGO session from a mach_pgo_snapshot_reserve failure — nowhere near the cause. The identity is therefore handed down in two halves (site_identity_prefix per code body, site_identity_suffix per site) and concatenated at drain time, where the cost is transient. Anything that adds long-lived per-site bytes should expect to meet this budget the same way. test_pgo_site_identity_halves_compose pins the property that makes concatenation correct (site sorts last), because C cannot notice if a pit-side edit breaks it.

Still to build — the pool drain proper. In this order, and note that B must NOT land without C: an emitter writing PGO_SITES and setting the header’s instrumented flag while C still has no counters would make a pool claim to be instrumented and still run its sites generically, which is the one wrong answer.

  1. Fragment carries PGO descriptors. LANDED. functions[] rows carry pgo_sites: [{pc, semantic_pc, kind}], present only on an instrumented lowering, in the order the VM names them. pc needs no translation: the fragment copies each function’s instruction block verbatim, so a lowering-time pc already indexes it.

  2. shoplib/mach_pool_emit.cm writes the section. WRITTEN AND HELD BACK — it is in a stash on the agent worktree, not in any commit, because of the blocker below. Shape: rows grouped per function in fragment order, first_pgo_site/pgo_site_count on the FUNCTIONS row, counter_index = the pool-global row index, the tenth section placed only when rows exist (an always-present empty section would change every ordinary pool’s bytes and break the byte-identity mach_pool_asm_test.c holds), header bit0 DERIVED from “there are rows” rather than requested, and instrumented folded into derivation_text so two pools over the same units that differ only in instrumentation are different pools.

  3. C builds a per-binding counter array at bind time and mach_exec_pgo stops returning NULL for MACH_EXEC_IMAGE; the VM’s ordinal becomes fn.first_pgo_site + Bx. BLOCKED TWICE — RAISED, NOT GUESSED (2026-07-30, and again 2026-08-01). Read the 2026-08-01 block above first: D5 has since deleted the collector-construction path this step was going to mirror, so it is a rebuild and not a port. The 2026-07-30 blocker below is still true, and still sits on top of it.

    My own map said “the session identity arrives at BIND time from the realization”. It does not, and cannot today: the production pool bind path never sees a realization. The chain is start_plan.c plan_run_unitpit_plan_run_windowplan_run_poolpit_private_image_provider_resident_function(ctx, bytes, size, placement_id, artifact_hash, owner_results, entry_index) — grep semantic_hash and compiler_salt across source/start_plan.c and source/image_provider.c returns nothing. The register lane never had to solve this because the identity rode INSIDE the per-unit mach blob (mc->pgo_semantic_hash); a pool cannot carry it, being content-addressed and shared. $image.binding, which does take a request record, is called from tests only.

    So: where does a pool-lane actor learn the PGO session identity it reports into? Three candidates, none clearly better on the evidence I have:

    • (a) The start plan carries it. Natural — the plan is built per realization, which knows its semantic hash. But it is a plan FORMAT change, and L3 is about to rewrite the cart/plan shape, so it is work done twice.
    • (b) The actor context carries it, set by the shop at actor start. Smallest change, touches no committed format — but it is a runtime API addition, and CLAUDE.md says runtime changes want approval.
    • (c) $pgo carries it. Most in the grain: debugging.md already says counters exist only when $pgo does, so making the endowment the thing that both gates and identifies collection follows the docs rather than bending them. Cost: $pgo today is a DIFFERENT endowment (count_instructions / op_counts, instruction counting), so this reshapes an existing name.

    Not guessed, because the last fork on this landing was decided by “the docs are the source of truth” and (c) is the doc-aligned candidate while (b) is the cheap one — exactly the shape of choice that went the other way last time.

  4. The drain returns pool coordinates (content_hash, function_index, pool pc, kind) and pgo_capture + pgo.cm join them against the origin-map sidecar — already keyed by pool CONTENT hash since the L2 landing — to produce the same {mcode, function, site} the register lane now emits. The join is a pure lookup: no new origin-map field is needed, which is the whole benefit of the ruling.

  5. Delete the --pgo_collect refusal in pit-shop/terminal.ce and the lever arm in tests/cli/pgo_flags.ce; the test then asserts the positive path under both lanes.

  6. Counters exist only when $pgo does — a build without the endowment pays nothing.

stable_site_key: DELETE it. My call, per John’s invitation, with the reasoning. The origin-map join supersedes it — identity comes from the join, so a u64 in the row would be a SECOND way to name a site, which “one way to do each thing” forbids. It is read by nothing (parsed at source/mach.c:297 and never used), and it has no specified derivation, so keeping it means inventing one for a field with no consumer. Cost is contained because no producer has ever written the section: the row goes 24 → 16 bytes ({function_index, pc, kind, counter_index}), touching the row size at source/mach.c:160, the accessor at :297, PitMachPoolPGOSiteRow in source/pit_internal.h:371, the hand-built fixture in source/mach_pool_test.c, and the spec table. No committed artifact contains a PGO_SITES row to migrate.

The fork as it was posed, kept for the reasoning. Two options were priced; John took A.

The C facts the drain rests on, measured. The PGO_SITE row IS specified (docs/spec/artifact-formats.md:1173 — today 24 bytes, {function_index, pc, kind, counter_index, stable_site_key}; drop the last per the ruling above), and source/mach.c:745-753 already validates pc as a POOL-final function-relative pc and requires the rows to be grouped per function to match first_pgo_site/pgo_site_count. The meta word the VM reads (source/mach.c:9578, MACH_GET_Bx of the third word of the three-word region) is function-localml_pgo_site allocates it off McodeLowerState, which is per function (source/mach.c:11152) — so the pool arm is fn.first_pgo_site + Bx with no relocation and no third reloc class, which matters because the fragment spec says import relocs are “the second, and last, operand class the link owns”. The shared mcode→mach lowering ALREADY emits MACH_PGO_LOADF_COLLECT on the fragment lane; mach_exec_pgo returns NULL for MACH_EXEC_IMAGE (source/mach.c:1676), so today a pool-lane instrumented site carries a dangling ordinal and silently executes as a generic load. stable_site_key is parsed at source/mach.c:297 and read by nothing — its derivation is unspecified, unlike stable_function_hash, whose spec says “the target key hash of that same text”.

The session identity does not belong in the pool. _pgo_semantic_hash / _pgo_compiler_salt ride on the mcode main today (pit-compiler/pgo.cm:685) into mc->pgo_*. A pool is content-addressed and therefore SHARED — two executables with different semantic hashes can name one pool — so the {semantic_hash, compiler_salt} that keys a PGO session must arrive at BIND time from the realization, not from the pool bytes. That is the same conclusion as “the realization binding/instance owns the counters”.

RULED by John 2026-07-30 — the identity is a START-SUPPLIED FACT, and the drain sequences BEHIND L3. The recon found the production pool-bind path never sees a realization (plan_run_pool receives placement + artifact hash + results only; no semantic hash anywhere in start_plan.c/image_provider.c), so the identity has no road in today. The ruling: it travels the way the logger token travels in the ruled logging model — a fact the shop supplies at actor start — and it rides the NOTA start plan L3 creates. So the drain’s final wiring lands after L3 rather than teaching the dying plan format one more field. Until then PGO collection stays honestly refused under the pool lane. The emitter step (74 lines, PGO_SITES rows grouped per function, tenth section only when non-empty, header bit derived from row presence) exists as a stash in the L2b worktree and is fully specified here — re-derivable if the stash is lost; it must land TOGETHER with the counters (B-with-C), since --pgo_auto/--pgo_from already produce PIC sites under the pool lane and a pool must never claim instrumentation it does not perform.

THE FORK — what identifies an observation? The docs and the code answer differently, and nothing anywhere calls the other one a defect:

  • Three doc pages say the observation is addressed by mcode function and SITE ID. docs/spec/artifact-formats.md:1390 gives the row as {mcode, function, site: "call:0", executions, values}, sorted by (mcode, function, site). docs/architecture/debugging.md:143: “addressed by mcode function and site ID, which the pool’s origin map supplies”. docs/architecture/build-and-artifacts.md:250 is the most explicit — “A persisted profile object records the mcode hash and function/site ID for each observation”, under the heading “Observations are recorded in mcode identity, not in the pool’s.”
  • pit-compiler/pgo.cm:182 site_key says it is {unit_hash, function, pc, kind}, and validate_site (line 423) requires exactly those four fields. Consumption keys on the whole record (find_observationcanonical(site)), so the shape is load-bearing on both ends.

The origin map supplies {mcode_hash, function_id, site_id, source_hash, span} and drops the mcode pc (shoplib/mach_pool_emit.cm:960-971append_range computes mcode_pc and does not store it). So the join as the brief directs it cannot produce the record the brief names. One of the two has to move:

Option A — TAKEN. Name sites {mcode, function, site_id}. The pool join becomes a pure origin-map lookup with no new field anywhere, which is what all three pages describe. The open risk was whether the sites PGO collects even have site IDs, since sites is sparse — a probe over five real files found 1329/1329 instrumentable loads do (function_sites, pit-compiler/compiler.cm:1331, one row per instruction carrying a source position, id = opcode + per-op ordinal, unique within the function). It also moves identity construction out of C, which is the “Pit emits, C reads” direction. Cost paid: stored profiles invalidate (fine — regenerable), and the register lane moved too.

Option B — the road not taken, kept because its one virtue is real. Keep the pc-shaped identity and add mcode_pc to the origin record: a one-line change in append_range plus a spec line, since append_range already computes mcode_pc and merely discards it (shoplib/mach_pool_emit.cm:952,960). Its virtue is that both lanes would emit byte-identical profiles, so a profile collected before the lane flip would stay consumable after it. It was rejected because it corrects three normative pages to match the code, which method.md names as the wrong default direction. Worth remembering if profile portability across the flip ever turns out to matter more than it appears to. The pc spaces do coincide (lowering_inline_literals is 1:1, pit-shop/mcode_lower.cm:146), so B remains index-correct and buildable.

The rest of the landing, once the fork is called. Fragment functions[] rows gain pgo_sites: [{pc, semantic_pc, kind}] in Bx order (extend the way origin rides today); shoplib/mach_pool_emit.cm writes PGO_SITES grouped per function, fills first_pgo_site/pgo_site_count, sets header flag bit0 (instrumented) and assigns counter_index (the spec: “allocated per actor from the highest counter index plus one”); C builds a per-binding counter array at bind time from PGO_SITES, mach_exec_pgo stops returning NULL for images, and the VM’s ordinal becomes fn.first_pgo_site + Bx; the snapshot returns pool coordinates and pgo_capture + pgo.cm join them against the origin map sidecar (already keyed by pool CONTENT hash since the L2 landing). Counters exist only when $pgo does — a build without the endowment pays nothing.

L2c — pit log <channel> retargets at the logger (RULED by John 2026-07-30) — LANDED. The boot-actor landing left it half-dead: the floor selector still filters the floor’s own lines (it must — the sysym reaches claim-less actors), but a claiming actor’s lines flow unfiltered. Ruling: pit log <channel> configures the LOGGER actor’s channel filter (logger.ce channel_allowed, which already exists for subscribers); per-channel filtering is the logger’s business.

The verb is pit log channel <name> [--off] [--reset] (pit log <name> was not available: pit log [id] is the observe-log listing, whose positional is an actor id). It sends {type: "log_channels", channel, enabled} to the logger, which is the message name the shop already used for the floor selector — one vocabulary, a different target. Two calls the ruling did not scope, both taken the small way:

  • It gates FANOUT, not the store. append_log/remember still run for a silenced channel, so pit log and pit why keep their forensics — and the filter lands as one condition inside the existing channel_allowed, which covers replay-on-subscribe too.
  • It is uniform across channels. No fatal-channel exemption; error/disrupt are silenceable like anything else, and the record survives in the store either way.

tests/log_channel_filter.ce (in the baseline suite) proves all six: enabled → arrives, disabled → reaches nobody, another channel unaffected, still in observe.jsonl, a claim-less actor still runs and is still reported dead through the floor, re-enabled → restored. Two findings from writing it, both about what a claim-less actor can be OBSERVED to emit: its floor_log goes to the boot sink, not the logger (no module published log into its context), and the runtime’s own actor halted line is written at actor_free, which a live overling reference defers past the end of a test. Separately: a start-time disrupt produces no notice on the $start callback at all — only the greet — so tests/log_token_handoff.ce’s disrupt arm is a branch nothing can currently reach.

L1b — stamp truth flows from the recipe (RULED by John 2026-07-30). profile_name, value, and wota are carried by the rep macro today: --set stamp.rep=nan32 builds a binary calling itself playdate-nan32-v1;value=32;wota=32 while its recipe says host-nan64-v1/64/64 — the endian lie-class, three levers wide, pointing the other way. Ruling: build derives from recipe (docs/architecture/recipes.md, “The recipe is the authority”). pit_profile.h stops hardcoding per-rep stamp facts and takes them from the recipe at forge; combinations the toolchain cannot honor are refused at forge by name (the endian-refusal shape L1 built). Touches every arm; arm_identity_lint + the pressed fixture keep it honest during the move.

Refined by John 2026-07-30: value DERIVES from rep — it leaves the recipe schema entirely (a rep names a complete value-word scheme, width included), so rep-vs-value contradiction becomes unwritable, not refused. wota remains a free lever (rep follows the value representation, wota follows what the architecture serializes fastest; a small-rep + wide-wota build is legitimate). Both still render into the profile string. The ps1→fixed32 ruling is RETRACTED (John 2026-07-30), and the retraction is the lesson. The L1b agent held the change and produced the history: ps1=nan32 was John’s own informed ruling of 2026-07-18 (recorded in pit_profile.h) — R5.d measured soft-float nan32 on emulated R3000A as bit-identical to host (“slower than fixed32, never wrong”), and R5.c proved fixed32’s s14.16 integers cap at 16,383 and cannot address a cartridge (an 868KB cart read landed ~852,000 bytes short; the rung STOPPED on it). The “copy-paste default” premise behind the reversal was false. nan32 stands. REVISIT flagged by John: the wanted future is a fixed-point rep that stores larger integers and converts to fixed point only when a value goes out of range — a rep redesign with its own measurement burden, queued behind this arc, never a recipe edit. Method note: a ruling that reverses a committed position must be checked against the history before it is recommended — the orchestrator failed to, the agent caught it.

SQ1 — the actor-lifetime side quest (RULED by John 2026-07-30, all blessed). The liveness model is the scheduler’s, and it is already ~90% implemented: the slow ladder (fast budget → freeze mid-turn, back of the line → repeated overruns accrue strikes → halt at the limit; CONFIRMED including the halt) and the ar/$unneeded reap (idle countdown, default-on, waiting-on-async is NOT liveness, $unneeded(fn, secs) with the goodbye-turn callback; -1 never). The defect is the SECOND liveness system stacked on top — the messaging reply-deadline layer, whose true origin was a memory-leak guard for reply callbacks held forever. Ruled resolution: a reply resolves by answer, by the counterparty’s death, or by the holder’s own death — never by clock. The landing:

  1. Delete the default reply deadline and REPLY_HARD_CAP_S from lang/messaging.cm; explicit per-request deadlines only where a caller passes one; $time_limit is the opt-in bound.
  2. Reply-route death notices over the EXISTING watch machinery (actor_watch_stop_register — couple’s plumbing, monitor-shaped, no lifetime binding): on B’s halt, every pending reply routed to B fires with the death reason; letters still queued at halt bounce the same way. Fix the parked PIT_INPROCESS lock-order deadlock (scheduler_snapshot × actor_watch_stop_register) in the same seam.
  3. The terminal ladder replaces the daemon’s 600s bound: $unneeded(short) awaiting first contact, then explicit $couple to the child + $unneeded(never); the child’s death is the notice that ends the session. Composes with the outstanding-request honesty gate.
  4. Pending-reply count and age surfaced through $inspect — alive-but-silent counterparty is an OBSERVABLE protocol defect, not reclaimed memory.
  5. The knobs go coarse: default ar, fast/slow budgets, strike limit into recipe build.budgets; the 600/900 constants and the bare-vs-arg envelope asymmetry die.
  6. Docs: one lifetime page (positive voice) — the model lives today in the scheduler spec, the endowments list, and one excellent C comment; the glossary carries the sharpened principle (“the runtime reclaims and kills; it never restarts or supervises”). Sweep the std long-wait modules for the $unneeded discipline.

SQ2 — exit-code honesty sweep (same seam, same landing series). The 600s false-green is fixed (the diagnosis landing); the remaining inventory: ./pit compile compile exits 0 silently on syntax errors; the error-surfacing seam per the standing ruling (a caught disruption must not exit 1 — terminal.ce treats any panic-channel line as fatal while Pit_RaiseDisrupt logs to panic AT THE RAISE SITE, before catchability is known; the fix is DELIVERY of the failing path’s error-channel lines, never a new error-return shape — this also closes the inspect_debug intermittent, ~20% measured); pit.c:213’s disruption_reported special case exists only in the boot lane, not for spawned test actors; the first-test-run-after-build timeout reports as an ordinary failure.

SQ3 — sched leaves the stamp (RULED by John 2026-07-30). The flip’s strict pool reader refused byte-identical pools between the playdate sim (sched=single) and the host daemon (sched=threaded) — the exact “checkable open question” the recipe ratification flagged, now checked by reality. The eviction: the profile string drops ;sched=…; sched moves to the recipe’s build group (it selects provider files only); shoplib/recipe.cm axes, cake/plan.cm’s stamp render, pit_profile.h’s string composition, arm_identity_lint, and the pressed fixture all follow; one routine reseed. This greens check-playdate with zero lever plumbing (the sole differing axis stops existing). Findings recorded with it: press_floor_unit now threads the caller’s full rep-profile stamp (real ship-path defect, fixed); bootstrap --numrep nan32 is a PRE-EXISTING dead lane (lower_unit’s foreign-target refusal predates the flip) — the n64/ps1 cross-seed scripts are dead until the press lane serves them, L6 territory.

SQ3 + REGEN1 — MERGED TO THIS BRANCH 2026-07-31. The two-reseed crossing replayed here exactly as recorded: reseed #1 (old binary, new sources) produced the mcode snapshot; TRUE bootability verified with every cart aside (3.45s, vs the agent’s 3.42s); rebuild showed the new spelling (no ;sched=); reseed #2 re-pressed cart/engine/manifests/fixture. check-playdate ALL GREEN on this branch. Budgets render as build| rows (the plan.cm merge put them in build_defines, where SQ1d’s own comment said they belonged). Three findings on the way, each now landed:

  1. The seed blew the 1 GB heap cap embedding what it never reads. load_cached_executable_value parsed every module’s mcode unit into records (one 85-module executable ≈ >1 GB) so the seed could read the payload HASHES. The seed now asks for payloads: "named" and the loader answers existence by build_has_value — same refusals, no parse. The deeper flip (records always carry names; consumers fetch bodies at consumption) belongs to L3’s D5 payload conversion.
  2. RULED (John, 2026-07-31): the heap limit WARNS, it never kills. A heap past its stated limit names a defect (a leak, or a need nobody stated); killing converts the signal into lost work and a mystery death. Warn once per doubling; a target that must kill states it as a recipe budget later. Pit_RaiseOOM now writes its reason into disrupt_msg — a real OOM stops presenting as the bare fallback “disrupted”.
  3. Deaths get their own logger ring. The shared 256-record ring evicted a disruption under two minutes of compile chatter, so pit why answered “no recent deaths” moments after one — the query’s own realization helped evict its answer. Death channels (disrupt/panic/abort/crash/fatal) now keep a separate 64-slot ring that chatty channels cannot touch.

The make-vs-hand check discrepancy is closed: the old gates ruled on tail -4 | grep — a sliding window that any post-summary line (fresh-daemon realization chatter) shifts — and discarded the output, so the red was undiagnosable. scripts/gate.sh rules on exit code AND the last failed: line, and prints the tail on failure. Also RULED (John, 2026-07-31): no AOT or native-perf work anywhere right now — tests and mach bytecode only.

SQ1 + SQ2 — LANDED 2026-07-30. What the work found, beyond the brief:

The lock-order inversion was not a curiosity, it was load-bearing. actor->mutex is the TURN mutex, and actor_watch_stop_register took a FOREIGN actor’s copy of it from inside the watcher’s own turn — so it inverted against scheduler_snapshot (which walks every actor’s mutex from inside ITS caller’s turn) and against a second registration coming the other way. The fix is a leaf lock for stop_watchers and nothing else. It had to land FIRST and separately: once a reply-carrying send registers a watch, the pre-fix binary wedges on ordinary traffic, and it wedged make itself — the forge deadlocked twice building the very binary that fixes it. The escape is PIT_WORKERS=1 (one worker cannot hold two turns, so no cycle). tests/watch_snapshot_lock_order.ce gates it and HANGS on the pre-fix binary, which is how it was proven.

The old reply deadline was an accidental heartbeat. Every reply-carrying send armed a 60 s timer; timers fire as letters, letters are turns, and a turn resets the idle countdown — so any actor with an outstanding request was being kept alive by the deadline it was waiting under. Deleting the deadline let the ar timer do what it is documented to do, and pit-shop/watch (a shop singleton, quiet between subscriptions, no $unneeded) was reaped at 60 s. Two fixes, both ruled shapes: the service states its own lifetime, and shop_actor’s dynamic-service cache stops treating a reaped singleton as permanently dead (it was poisoning the entry forever, so one quiet minute retired pit watch for the rest of the daemon session).

The inspect_debug intermittent was two defects, and the first was hiding the second. A CAUGHT disruption left ctx->disrupt_msg set, so the next BARE disrupt — which carries no message of its own — reported the earlier, caught failure instead of itself, seconds later and from an unrelated frame. That is why the obvious diagnosis kept being wrong: the message named the wrong event. With the buffer cleared at both handler-entry sites the real complaint surfaced (no live number in a frame frozen inside a counting loop — the freeze parking outside the counting loop, where the test’s own retry ladder should have sent it back round). 20%→0/15 measured.

L3 PHASE 1 — LANDED 2026-07-31. The cart is pit.cart@2 end to end: cart2.cm writes and reads the byte table (16-test raw-offset gate), cement decides WHAT and cart2 decides WHERE, C boot reads the 256-byte header entire and nothing else, pit_start_plan_run decodes the boot entry (root path never touches the metadata), a plan row names its pool inline (no MODULES/CODE/string tables on the run path), and the pit-side reader + five consumer tools moved to the value-shaped surface (cart.cm 1356→926 lines; ~530 of v1 hand-rolled decoding deleted). root.cart 4.5MB→1.6MB. Fresh-daemon test all 2728/2 (http2 standing; zz cold per its ruling). What the landing found, each now law: a PIT_ROOT lives at FUNCTION scope (the block-scope variant wedged every boot-service start in an unbounded GC — ASan on the O0 build named it after release-build inference failed three times); an observer never blocks on a turn mutex it does not own (scheduler_snapshot ABBA’d against itself under four CLI sessions — sys_rmutex_trylock joined the seam in all seven providers, busy actors report racy-safe scalars, and pit ps no longer stalls behind long turns); single-threaded observers do not retry (nothing else can release the lock); the layout ceiling is a FIXPOINT (sections sit behind the metadata whose length depends on their offsets’ width — the scratch lane proved it, and the named refusal turned a mislaid cart into a one-line diagnosis). PHASE 2 REMAINS: the deletion per the recon inventory, D5’s payload conversion, and the ==0 observables’ restoration.

L3 — the cart crossing. RULED 2026-07-31 (John, on the recon agent’s batched questions): (1) the byte layout is DRAFTED INTO docs/spec first — it now lives at docs/spec/artifact-formats.md “Cartridge v2” as pit.cart@2, magic pcr2 (the old pcr2 section described a never-implemented format and is replaced); implementation follows the spec exactly. (2) The 16-byte discovery trailer survives — the appended-binary lane is load-bearing boot ABI. (3) The any-generation boot floor is the mcode SNAPSHOT (REGEN1), not the cart: a pools root cart is generation-locked and that is correct; boot_cart.cm’s M1-era comment gets rewritten. (4) The M1-era test assertions are OVERRIDDEN by name: cart_payload_form.ce inverts pmcd→pmp1, runtime_arena_counters.cm’s window-pool observable dies with its cache, the shape observables flip to == 0. Recon also resolved: the header names the engine pool and boot entry DIRECTLY (nota needs an actor context that does not exist at mount), and the deletion inventory measures ~4,250-4,300 lines with two cautions (mach_shape_spec_decode stays — the pool lane calls it; kim8 TEXT encoding stays, only the register arm dies).

The new cart shape: fixed header (magic, profile stamp, nota offset/len) + metadata as one nota value + pmp1 sections at aligned offsets. cement.cm writes it; C boot reads the header by memcmp and the metadata through nota2value; engine/boot_walk.cm receives a decoded record and its hand-rolled plan/string-table decoding deletes. Two phases, one reseed each, per the section-kind recipe: phase 1 = the current binary (which still lowers mcode) presses the first all-pools cart; phase 2 = the new C lands and DELETES: the C pool assembler (Pit_MachAssemblePool*, mach_pool_lower_window), the pmcd lane (Pit_MachWindowIsPoolLane’s mcode arm, the window-pool cache), mach_lower_mcode_window, the pmac writer (mach.c:2873-3142) and readers, pit_load_mach_code, mach_materialize_cpool, mach_resolve_shape_spec/_record_shapes, the code cache + mark_code_tree_shared + the three code->shared GC arms, and the kim8 register arm. $mach_compile_mcode_bin / $mach_load keep their names and change payload to pools (D5 stands; renaming is a later cosmetic landing). Observables: grep -c pmac source/ → 0, grep -c pmcd source/ → 0, every cart window magic pmp1, runtime_code_count == 0, ct_lock callers shrink per the old stone-6 list.

L4 — mach.c splits. After L3’s deletions (~3.5-4k of 12.5k lines gone), split what remains into mach_vm.c / mach_pool.c (+ shared internals); pit_internal.h shrinks with it. Mechanical, behavior-free, make budget guards the hot loop.

L5 — the boot-actor rewrite — LANDED 2026-07-29. The boot actor starts actors: it mints the guid (⇒ $self), receives the request (⇒ $overling), holds the logger token, and the new actor’s first act is walking its own plan (7.3 landed the walk; this landed the facts).

The two halves are one landing, and the ORDER INVERTS the brief’s. Retiring the gate had to come first: with $log_enabled still live, deleting logger_id/shop_id/root_id makes default_log_enabled answer false for every channel on actor zero, so the root’s floor error lines vanish instead of falling through to C’s boot sink. Gate first, wota second.

The gate is gone. pit-compiler/mcode.cm:emit_log_call (was emit_lazy_log_call; “lazy” named the gate) emits one call and no consult (three slots, a call and a branch off every log line); ENGINE_NAMES and the unconditional claim_entry("$log_enabled") are out of cement.cm; engine_lite.cm loses log_enabled, default_log_enabled, log_enabled_fn and actor_set_log_enabled_fn, and with them the dead identity chain they existed to compute (logger_id, shop_id, root_id, log_self_routes_to_root, logger_is_external, log_target_id); C loses PitLogEnabledCallback, the three PitContext fields, pit_log_enabled_callback, actor.set_log_enabled, Pit_LogEnabled (declaration included) and four GC root sites, not three — pit_gc_compact.c one, pit_gc_copy.c three. Log arguments now always evaluate and per-channel filtering is the logger’s.

The claim is the gate. shop_actor.ce:claims_log(exe) reads exe.globals; an actor that mentions log gets the token, one that never does gets neither token nor function. The claim aggregates over the whole CLOSURE, which is correct — the closure is what decides whether log is bound at all — and it means anything importing lang/messaging.cm claims log transitively, so the withholding arm is real but rarely taken.

The boot wota shrank 13 fields → 8. pit.c deletes shop, shop_id, root, root_id and the logger_id: "bootstrap" placeholder. What C still states about actor zero is the one identity it minted (id, self), its own build/target stamps, and this invocation’s command line and medium. It states nothing about who the shop is, who the root is, or where logging goes.

Test. tests/lazy_log_enablement.ce + tests/fixtures/log_enabled_native/ are replaced by tests/log_token_handoff.ce. Note the finding it encodes: the negative case cannot be reported the way the positive one is, because replying needs lang/messaging.cm and that module logs — so the claim-less child answers through the FLOOR (disrupt if it holds a token, clean stop if not) and $start delivers the verdict as an underling notice.

Still open (asked, not decided): $actorsym’s home is unchanged. (The log-selector half of this note was ruled and landed — see L2c.)

L6 — the cross-target proof. THE PRESS HALF IS LANDED; CI ACTIVATION IS THE USER’S. make cross-check: on this machine, press carts + runtime builds for at least linux, emscripten, and windows (playdate if the runner allows), push, and CI runs the test suite on each. Green there = the system works. This is THE acceptance test of the arc and the standing “does this work?” test afterward.

What landed 2026-08-01, and the shape of the fix. The SQ3 finding was right that bootstrap --numrep nan32 was dead, and wrong about where. lower_unit’s foreign-target refusal is CORRECT and did not move: that lane realizes a unit the shop is about to RUN, so the running profile is the only honest answer. What was wrong is that the boot press was walking into it — bootstrap_artifacts realized the root executable payload_mode: "mixed", and boot_cart.pool_executable then threw every mach payload away and re-pressed each module from its portable mcode unit and the target’s stamp. The mach was computed, stored and discarded on every seed, and asking for it while naming a foreign rep is what the refusal caught. The boot realize is now payload_mode: "mcode" and pool_executable keys on the mcode unit rather than on a host payload’s presence. Nothing relaxed; one lane stopped asking a question it never used the answer to.

The second half was the stamp. bootstrap --target linux used to change the provider arms and NOT the stamp — the cart came out host-stamped whatever you named — so the levers (--numrep, --endian, --gc) were the only way to describe a target, and the n64 script carried the axis list by hand. A target is a recipe: rep_profile.target_stamp_for reads all seven axes off recipes/<target>.json through shoplib::recipe profile_string (the one renderer, the one cake renders the build define from), and the levers still override. pit cake profile <target> exposes that same rendering so nothing outside pit needs a second parser or a private copy of the axis order.

Answering the two questions this landing was told to stop on. The content universe ships mcode, and it already did — seed_fleet_entry has realized payload_mode: "mcode" since REGEN1, so “portability ends at mcode” was settled in code before it was asked. It was missing the target REP, though: the seed threaded endian and not numrep, so a cross-rep seed folded its fleet’s constants in the presser’s arithmetic. Both now ride as one {numrep, endian} record. CI artifact transport needed no ruling either: git is the transport for the pressed-elsewhere direction (the committed pair is darwin-pressed and the Linux runner boots it), and the linux job in ci.yml has silently depended on that since it was written.

Evidence. make cross-check presses for linux + emscripten (their recipes declare this host’s own stamp — which is exactly why a cart crosses between them) and for playdate + n64 as the FOREIGN-STAMP arm, because without an arm whose stamp really differs the refusal check is vacuous. The n64 cart comes out n64-nan32-v1;value=32;rep=nan32;endian=be;text=utf32;record=hash;gc=copy;wota=32 on a little-endian nan64 host, pit cart info walks all 30 sections of it, and this binary refuses it naming every differing axis. Foreign-endian EXECUTION proof still belongs to a real runner; the byte-level gate for it is the pressed fixture table in check-arms.

What remains for the user. Push, then activate .gitea/workflows/cross-check.yml (three jobs: the committed darwin-pressed pair running the suite on linux, the linux runner pressing for other targets, and the web lane). Windows needs a ruling — the press arm works today and the run job is written and commented out; standing up a runner is not this landing’s call.

Deliverables — what done looks like

  1. One lane: zero pmac/pmcd in source/; every cart window pmp1; the ENTRIES plan is nota; runtime_code_count == 0 on a booted fleet.
  2. Thousands of lines deleted: the L3 list plus its tests (the byte-identity gates, tests/mach_code_cache.cm rewritten, pmac fixtures dropped). Report the real number.
  3. make cross-check green — carts pressed here run the suite on linux, emscripten, windows CI runners.
  4. A compiler-less runtime proven: a pressed cart boots and runs on a runtime whose store carries no compiler fleet (the vm_only shape) — the actors-as-stripping-unit demonstration.
  5. Docs remain the single source of truth: no plans file contradicts a docs page; plans/ holds this file, method.md, compiler-vision.md (the next arc), and journals only.
  6. The guard-comment sweep (RULED, John 2026-07-31): every surviving “do not relax”-class comment is re-anchored to the current ruling it protects, and old-world ones die with their worlds — a fossil comment must never argue against the next migration. (The rule itself is recorded in method.md.)

Deferred from the test-lifetime work (2026-07-31), needs a ruling when picked up: a reaped actor’s overling notice is {type: "stop", reason: "actor stopped"} — byte-identical to a voluntary $stop(). The harness now compensates (it states each test’s lifetime, so a reap cannot precede the deadline), and tests/reap_is_not_a_pass.ce pins the indistinguishability so a change gets noticed. The open question is runtime surface: should a reap carry its own reason? The lifetime model’s honesty says yes (a mystery death is the class we keep killing); it waits because nothing depends on it now and the arc comes first.

Deferred from the sweep wind-down (2026-07-31): a pit test all client can complete its suite, print the summary, and then fail to EXIT — parked in teardown (exit_handler’s join, most likely on a leftover pit debug sites worker from a failed debug_tool run), leaving a live process with a dead endpoint that correctly refuses all later daemons. One observation, on a binary predating the busy-row snapshot fix; likely moot now that debug_tool passes, but the teardown-join shape also appeared once elsewhere (a v1 binary’s –version joining a stuck thread), so if a “daemon alive but endpoint absent” refusal recurs, this is the first suspect. The parked concurrency experiment’s notes live in the sweep agent’s final report: the PIT_TEST_CONCURRENCY instrument is committed and daemon-read; resume on a quiet machine, add an orphan check between runs, and treat short wall times as suspect by construction.

THE FIRST NAMED ITEM OF THE MACH-BYTECODE PERF WORK (RULED with the L3 phase 2b re-baseline, John 2026-07-31): the image-arm closure-upvalue cost. closure_calls runs an IDENTICAL instruction stream on the pool lane at 4.6× the wall time of the deleted register lane (8.76 ns/i vs ~1.9; isolated to bind_getup, 150k calls), and numeric_loop pays +280 fixed bytes per mach_load (the image function + owner array). The old baseline was measuring a deleted lane; the budget gate now watches the lane the fleet actually runs, and this number is the one it was re-baselined to keep visible. Two findings from the same landing, recorded for the next crosser: the cart-crossing class needs its two reseeds IN ORDER (press lands and reseeds BEFORE C readers go — reversing it leaves a binary that cannot boot the committed cart, and make needs a booting daemon; the escape is the cold floor: rm -f pit && make), and a failing test with a long reason renders in the human errors: list as bare - true (real reason only under –machine) — a rendering defect worth one small fix.

Known defects deliberately left (do not chase inside this arc)

  • network/http2 — the one red test at baseline (2705/1), pre-existing, unrelated.
  • PIT_INPROCESS=1 cold-realization deadlock — FIXED in SQ1 (leaf lock for stop_watchers); tests/watch_snapshot_lock_order.ce gates it.
  • inspect_debug intermittent — FIXED in SQ2; the carriers named here were both real and neither was the cause. See the SQ1+SQ2 landing note above.
  • make check-playdate is RED at baseline (found 2026-07-29 running the drill; it was not on this list and should have been). Two files fail against the installed Playdate SDK: platform/playdate/playdate_sys.c:718 uses kPDLanguageUnknown, which that SDK no longer declares, and platform/playdate/playdate_gfx.c:339 calls makeFontFromData with 2 arguments where it now takes 3. SDK API drift, not a regression — but the drill lists check-playdate, so treat a red there as pre-existing until these two lines are fixed.
  • PGO runtime descriptors hold an unrooted PitValue. MachPGORuntimeCall.key lives in C memory and neither collector scans itgrep pgo source/pit_gc_copy.c source/pit_gc_compact.c returns nothing, while code->cpool (where the key is copied from) IS scanned. So a key goes stale across a collection while its cpool slot stays correct. Found 2026-07-30 while checking the site-identity landing, which had briefly made it reachable on the collect path; that arm is fixed (identities resolve in their own pass before any key is assigned). The PIC path is still exposedmach_resolve_shape_spec allocates after the key assignment — and is left alone deliberately: the fix is either GC scanning for these descriptors or the same reordering, and it is not part of naming sites. Note that check-armsforce-gc/validate-gc arms do NOT catch it, because the C suite never drives a consumed PIC.
  • Five stack-walk sites asking “has a register?” instead of “is Pit?” (scheduler.c:370/439, crash.c:113, runtime.c:29/10555).
  • The mach sidecar key collision (mach_debug_key/mach_origin_key keyed on mach hash alone) — scoped derivation-contract change, not a drive-by.
  • Carried opens for John, none gating: $root vs $shop; $fd off the floor; $self_id accessor; cold-bootstrap build_id reads the clock.

Hazards (each cost real time once — carried from the retired plans)

  • A payload-form change can wedge past make nuke — nuke’s escape IS the reseed. Under the bootstrap contract the escape is: last green (source, cart) pair from git + sh boot/manifest/bootstrap.sh then cp cold-build/pit ./pit. Prove any payload-form change on a scratch program BEFORE it reaches a reseed.
  • Two-phase crossings are normal. Phase files must be untracked phase1_<name>.txt — the .txt matters; SEED_INPUT_HASH globs *.cm/*.ce at the repo root and a bare one poisons the seed hash.
  • The daemon reads env levers, not the client — any measurement without ./pit down && first is vacuous.
  • The first ./pit test run after make all can time out — it now says so by name and states the budget it hit (“Test realization timed out after Ns … rerun before reading the test”), but it is still a red line in the summary. Rerun before believing it.
  • ./pit compile compile <file> exits 0 silently even on syntax errors — FIXED in SQ2; it exits nonzero and prints the compiler’s own diagnostics.
  • A binary without the stop_watchers leaf lock deadlocks its own build. If a tree ever needs building with a pre-SQ1 runtime, PIT_WORKERS=1 make is the escape: one worker cannot hold two actor turns, so the cross-actor mutex cycle cannot form.
  • Floor units sit at the 255-slot ceiling (bootstrap_artifacts at exactly 255/255); overflow counts appear only in .pit/log/observe.jsonl under "channel":"error".
  • Agent worktrees spawn at stale bases — every brief says “verify the base sha and reset”; most agents last run found theirs wrong.
  • Other agents share ~/.pit’s build store; a wedged foreign daemon can stall a build.

The drill — every landing merges this way

Commit source-only in the agent’s worktree (never boot artifacts/stamps — regenerate yourself), cherry-pick, grep for conflict markers, rm -f boot/boot.cart boot/cart.stamp, make smoke, then under set -o pipefail: make check, make check-cli twice (cli BEFORE arms; a first post-reseed run can transiently fail), make check-arms, make lint, make manifest twice (byte-stable; git status --short boot/manifest empty after the second), make budget, make check-playdate, and ./pit down && ./pit test all on a fresh daemon. Then commit the reseed. NOTHING LANDS ON RED. Baseline: 2705 passed / 1 failed (network/http2).

Source: plans/archive/finalization-arc.md