Archive — history, not state. Kept for its reasoning and its evidence; its plan is closed.
Worklist — endowment, gate, and boot model
Generated 2026-07-24 from a design review of docs/ against John’s rulings. This is a
work ledger, not target design: the target lives in docs/. Every row cites both sides.
The rulings this implements, in one paragraph: an endowment is a name a program
requests that the shop may deny — nothing about power level, $self and $cores
qualify. Globals are the same delivery path without the deniability. A granted
name arrives in exactly two ways — a constant the shop knows, or the return value of a
unit in the realization — and the runtime holds no recipes. Compilation is the gate:
built here means it runs, nothing is checked at start, and the boot cart is trusted by
ruling. A mount is the trust decision. Minimal C is a prime edict: C is the audit
surface, Pit is safe by construction.
Applicability: this ledger was written against 9466791a, we build from a3184e5e
The worklist below was drawn up against the 47k-line tip. This branch starts from the last green commit instead, so a good part of it describes code that was never written here. Surveyed on the base:
| Section | On the green base | Meaning |
|---|---|---|
| A — start-time ceremony | absent. engine_lite.cm is 1766 lines with zero run_target_realization / exact_start_record / start_refuse | nothing to delete; simply never write it |
| B1 — three engine-value name tables | one deleted; the other two are not the same table. plan_engine_values (C) existed only to compare its ids against the ids ENGINE_VALUES baked, so both id halves are gone. What is left is a membership SET in cement.cm (build time: is this claim the engine’s?) and engine_value() in engine_lite.cm (run time: what is it?) — two halves of one fact either side of the build/run line, not a duplicate | done as far as it goes; the rest dissolves with the executable-as-array |
| B2-B4 — uniform endowment delivery | forward work | design lands first |
| C — explicit realization | no realization exists yet | forward work |
D1 — cart_v2_boot.c | absent | never write it; read carts in Pit |
D2 — source/start_plan.c | present | blocked on the new boot design |
| E — boot actor | forward work | |
| F — split engine_lite | present, 1766 lines | actionable |
| G — interning | present (intern_table, pit_intern_text, pit_record_shape_intern) | actionable |
| K — shop modes | present | actionable |
| L — hardcoded targets | applies | actionable |
| M — engine mcode in the cart | needs the new cart | forward |
Two consequences worth stating plainly. First, section A evaporates — the single largest cleanup on the list is work we now simply decline to do. Second, most of what remains is forward work rather than deletion, so the ledger’s framing (“delete X at file:line”) only fits rows G, K, L, and B1; everywhere else the line references point into a commit this branch does not contain and must be re-derived before use.
source/cache_profile_test.c, which proved caches-off correctness, also came with the
47k. Until it is rewritten, make check (vm suite, language suite, baseline, fuzz) is
the gate for row G.
A. Delete the start-time authorization ceremony — N/A on this branch
The runner has exactly two callers — the shop, which holds the decision, and the C floor at cold boot, which mounts a medium trusted by ruling. Re-deriving the decision proves nothing (the checking code arrives in the same cart) and costs every actor start.
| # | Do | Evidence |
|---|---|---|
| A1 | Delete packet.claims from the start packet and its decode. Decoded, hash-verified, never read. | internal/engine_lite.cm:1914; produced at pit-shop/bootstrap_realizer.cm:574 |
| A2 | Delete packet.policy_program and packet.policy_request. policy_program is decoded and never read; policy_request is read only to learn what schema to check policy_program against — a closed loop. | internal/engine_lite.cm:1921, :1988-1991; pit-shop/bootstrap_realizer.cm:586-592 |
| A3 | Delete packet.receipt and the whole pit.policy.receipt@1 artifact. The shop is the authority and it is in-process. | pit-shop/bootstrap_realizer.cm:593; docs/spec/artifact-formats.md:782-830 |
| A4 | Drop exact_start_record/exact_start_value re-hashing. The shop just built these; blake2 + JSON-decode per artifact per start buys nothing. | internal/engine_lite.cm:1880-1907 |
| A5 | Stop shipping canonical JSON bytes for every artifact in the packet — they exist only so the runner can re-hash. | pit-shop/bootstrap_realizer.cm:571-601 |
| A6 | Remove every start_refuse path. The runner makes no decisions; a failed primitive is a disruption (broken invariant), not a refusal (a decision). ~20 call sites. | internal/engine_lite.cm:1865, callers throughout run_target_realization |
| A7 | Delete the private-binding guards. Naming is not a privilege; the actor is the trust domain. Includes the hardcoded package-locator list. | internal/engine_lite.cm:1596-1606, :2231-2245 |
B. Uniform endowment delivery
No recipes in the runtime. Two cases only: a constant, or a unit’s return value.
| # | Do | Evidence |
|---|---|---|
| B1 | Delete the engine-value name table. It exists in three places with a hand-maintained “keep BOTH in sync” comment. | internal/engine_lite.cm:1570-1593; source/start_plan.c:71-98; pit-shop/cement.cm:80-83 |
| B2 | Convert the built-in constructors — $clock, $delay, $start, $stop, $couple, $unneeded, $connection, $contact, $portal — into ordinary Pit modules claiming raw runtime primitives. | internal/engine_lite.cm:1608-1739 |
| B3 | Make log and send ordinary modules too, so the system is modifiable by swapping a module rather than editing the runtime. | internal/engine_lite.cm:350-553, :708-913 |
| B4 | Generalize the provider-adapter executable kind into the delivery path rather than a special case for $runtime/$native_loader. | internal/engine_lite.cm:2296-2302; pit-shop/provider_adapters.cm |
| B5 | Confirm liveness falls out for free: no claim → no realization row → no unit instantiated. No stripping pass needed. | docs/shop/endowments.md “What is not claimed is not there” |
| B6 | Keep globals a distinct claim kind. Same delivery, no deniability. The fixed global-name set survives. | docs/spec/pipeline.md:32; docs/spec/executables.md:31-36 |
C. The realization becomes fully explicit
“The runner should do no thinking” means the realization is a program in a very small language and the runner is its interpreter.
| # | Do | Evidence |
|---|---|---|
| C1 | Move per-unit claim lists out of the executable manifest and into the realization as explicit name→value binding rows. Today the runner carries and decodes every manifest solely to read these. | internal/engine_lite.cm:2218-2271 |
| C2 | Bake the result-array slot index per unit instance into the realization. | internal/engine_lite.cm:2196-2215 |
| C3 | Stop sending manifests in the start packet once C1/C2 land. The manifest stays a build artifact. | pit-shop/bootstrap_realizer.cm:557-573 |
| C4 | Spec the realization’s row kinds — open image, bind import, install name, invoke entry into slot N — as a closed list. artifact-formats.md specifies every artifact except the one the runner consumes. | docs/spec/artifact-formats.md (no pit.target.start@1 section) |
D. Minimal C
C is the audit surface. The Pit half of this already exists and is complete.
| # | Do | Evidence |
|---|---|---|
| D1 | Delete source/cart_v2_boot.c (847 lines). It is a second implementation of a format Pit already reads and writes. | source/cart_v2_boot.c; Pit codec at pit-shop/cart_v2.cm, runtime mount at pit-shop/cart_store.cm |
| D2 | Delete source/start_plan.c (870 lines) — the realization walk in C, complete with its own name table. | source/start_plan.c |
| D3 | Remove the two-runner fork. | source/pit.c:208 |
| D4 | Shrink cold boot to: map cart → read a fixed header (magic, profile/ABI stamp, engine offset, boot offset) → memcmp the stamp → load the engine image → create actor 0 → enter. Target ~100-150 lines. | replaces D1+D2 |
| D5 | Keep exactly one check in C: the profile/ABI stamp compare. It is not security — it is “these bytes are uninterpretable on this build”, the same class as a bad magic number. | source/cart_v2_boot.c:254; docs/architecture/target-profiles.md:65 |
| D6 | The fixed header is the entire C↔Pit boot ABI. Everything else about the cart — directory, catalog, placements, assets — is Pit’s. | — |
E. The boot actor
| # | Do | Evidence |
|---|---|---|
| E1 | Introduce boot as the first Pit actor. Same code in dev and game builds; only the cart’s entry differs. Frees “root” (root actor / root cart / policy root) and “shop”. | — |
| E2 | Boot holds $mount so the entry does not. It mounts the cart, mounts adjacent bundles, and hands the entry a store rather than the power to mount. This is capability narrowing at the first hop, and it is the security story in one sentence: what a build can do is decided by what its boot cart’s entry may hold. | — |
| E3 | Boot is the front door for start requests: answer from the cart, or (dev) forward to a realize actor that can fetch source and build. Boot itself has no fallback chain. | today’s chain lives in pit-shop/shop_actor.ce (1519 lines) |
| E4 | Boot canonicalizes locators for now — it knows the requesting package and its package.json aliases, so prosperon/sound resolves against prosperon = gitea.pockle.world/john/prosperon. | docs/shop/shop.md:23-57 |
| E5 | Later: rewrite locators to canonical form when they are placed into the stone image pool. A build-time string rewrite; every runtime locator is then already full, lookups get faster, and E4 disappears from boot. | — |
| E6 | Rename boot/root.cart → boot.cart. It is 859 KB today, which is not a Gameboy artifact; the sealed case should carry no shop consortium at all. | pit-shop/shop_actor.ce + development_shop.ce + shop_realize.cm = 5,564 lines |
F. Split engine_lite
The runtime owns engine_lite (intrinsic, no realization names it) — so everything in it is paid for by every target, Gameboy included. It is 119 KB today.
| # | Do | Evidence |
|---|---|---|
| F1 | Keep the realization walk intrinsic (~460 lines). | internal/engine_lite.cm:1865-2327 |
| F2 | Split out the ~1870 lines of standard library — logging, send/reply, turn processing, requestors — as claimable modules. | internal/engine_lite.cm:1-1560 |
| F3 | Remove the $args scrub. The shop should not have put private realization input inside a public endowment’s value; fix it upstream instead of grooming it in the runner. | internal/engine_lite.cm:69-74 |
G. Memory
| # | Do | Evidence |
|---|---|---|
| G1 | Delete text interning entirely — not shared, not per-actor. With a solid image stone pool it earns nothing. | source/cache_profile_test.c (actor_text_interning) |
| G2 | Delete the runtime constant pool. Constants live in Mach images. | docs/spec/stone.md:8, :101 |
| G3 | Keep stoned text caching its hash in the length field — independent of interning, and what makes dynamic keys cheap without a table. | docs/spec/stone.md:19-24 |
H. Documentation — done
The site builds clean with no dead links. docs/ now describes the model above.
| # | Change | File |
|---|---|---|
| H1 | Endowment definition rewritten: a name a program requests that the shop may deny. Globals vs endowments; the two delivery cases with an explicit no third case; layering over a raw primitive; unused-is-absent; narrowing between actors. | docs/shop/endowments.md |
| H2 | Rewritten around the gate: compilation decides, boot cart trusted by ruling, policy not retroactive, mounts decide entry, guest-code flag. Receipt machinery gone. | docs/architecture/capabilities.md |
| H3 | Start-time verification sentences deleted; the runner-does-no-thinking rule stated where startup is described. | docs/spec/executables.md, docs/architecture/actors-and-memory.md |
| H4 | “Storage is not permission” → mounting is the trust decision, with the content-verifies / catalog-is-trust split as the hook for later per-mount policy. | docs/shop/store.md |
| H5 | Opens with “what a build can do is decided by what its boot cart’s entry may hold”; adds the entry/mount row and the guest-code row. | docs/architecture/security.md |
| H6 | New page. Minimal C as a prime edict, the fixed header as the whole C↔pit boot ABI, the boot actor, boot-holds-$mount, forwarding to a realize actor, engine ownership. | docs/architecture/boot.md |
| H7 | shop is the consortium, not a store; new boot, realize, mount, guest code entries; policy receipt deleted; locator says its whole meaning belongs to the shop. | docs/glossary.md |
| H8 | use() stays literal-only — that is what makes the closure knowable. Added the $start literal-or-variable rule and the guest-code flag. Opens by naming what is intrinsic (two naming rules) versus what is this shop’s design. | docs/shop/shop.md |
| H9 | The shop derives provider keys, not the engine. | docs/shop/extensions.md |
| H10 | Log-sink registration is an ordinary endowment, not a protected name. | docs/architecture/debugging.md |
| H11 | “Three sources” over four subsections — fixed by the rewrite. | docs/shop/endowments.md |
| H12 | Migration ledger deleted from the canonical spec; pit.policy.receipt@1 and its pipeline arrow removed; start packet no longer carries claims/policy_program/policy_request/receipt; authorize no longer re-decides. | docs/spec/artifact-formats.md |
| H13 | Interning and the runtime constant pool deleted. | docs/spec/stone.md, docs/spec/gc.md, docs/architecture/actors-and-memory.md |
| H14 | Realization described as explicit enough that starting is following rows. | docs/architecture/build-and-artifacts.md, docs/glossary.md |
Correction recorded: deny_c was described in an older audit as wholly unbuilt. It
is built — pit-shop/executable_manifest.cm:410 walks the extension bindings, traces the
import path back to the root, and fails the build, with tests at
tests/executable_artifacts.cm:239. The docs describe it accurately.
Still open in docs: docs/shop/spec.md — see section J.
J. Split docs/shop/spec.md — done
The page is mined and deleted.
| Content | Where it went |
|---|---|
| Shop modes | Deleted — rejected design, see section K |
| Payload policy | docs/architecture/targets.md, reframed as cake defaults for what goes into a cart rather than a runtime mode |
Catalog variants (pit.catalog.variants@1) | docs/spec/artifact-formats.md, new section before Target realization |
| Fixed-root-shop responsibilities, C bootloader narrative, boot artifact layout | Deleted — superseded by docs/architecture/boot.md |
Build-cache file shapes, dylib manifest spellings, .pit/build/<hash> | Deleted — implementation trivia |
Platform packaging / pit bundle app layout | Deleted — the parts that matter are in docs/architecture/boot.md and docs/shop/compilation.md |
K. Delete shop modes — capability is cart composition
Ruled: what a shop can do is decided by which actors its boot cart carries, not by a
mode. No compiler actor means it cannot compile; no cake means it cannot build C; no
realizer means it resolves nothing it was not shipped. The absence is structural and
therefore checkable — the same argument the docs already make for omitting $runtime.
If no combination fits, write a bespoke boot actor and put that on the cart.
docs/shop/compilation.md already described exactly this (“you choose which actors to
include”); spec.md’s mode table contradicted it. The doc side is now fixed.
| # | Do | Evidence |
|---|---|---|
| K1 | Delete sealed_mode(), compile_refused(), native_load_refused() and the four-mode enum. | pit-shop/shop_source.cm:1977-1985, pit-shop/development_shop.ce:1553-1566; ~10 call sites |
| K2 | dev and extensible were already identical in every column of the mode table — evidence the enum was not carrying real distinctions. | docs/shop/spec.md mode table |
| K3 | native_load is gated twice: once as a build-time profile power the binary either has or does not, and again as a shop mode. Keep the profile power, drop the mode gate. | internal/engine_lite.cm:2072 (profile.powers.native_load) vs native_load_refused() |
| K4 | “Mounts and ingest frozen” becomes: boot does not hand out $mount. Not a mode — an endowment that was not granted. | section E2 |
| K5 | Make the resulting failures legible. With no mode to name, a missing capability shows up at the point of use, so boot’s diagnostic must say which actor was absent — “no realizer in this cart” rather than a generic lookup failure. | pit-shop/shop_actor.ce fallback chain |
L. No hardcoded targets — docs done, code to audit
Edict: a target name is a label for a set of lever positions, not something the system knows. Nothing in the VM, compiler, shop, or runtime branches on “is this a PS1”. A build script sets levers — word width, numeric rep, collector, scheduler, powers, and which actors the cart carries — and that combination is the build. Two components legitimately know target names because they straddle the C boundary: cake (per-platform sources, flags, toolchains) and raw endowments (thin wrappers over one OS’s real surface).
Docs updated: target-profiles.md is now explicitly normative and says a target name is a
label; its axis table no longer enumerates a closed target list. targets.md is reframed
as a catalog of settings that have been built, plus how to add one. consoles.md reads as
hardware rationale for lever positions. extensions.md names cake as the exception.
| # | Do | Evidence |
|---|---|---|
| L1 | Audit the runtime and shop for branches on a target/system name outside cake and platform/<os>/. Each one is either a lever that should be in the profile or a fact that belongs in a platform folder. | source/, pit-shop/ |
| L2 | Check that a profile axis exists for every lever a port needs, so a new machine never requires a new conditional. | docs/architecture/target-profiles.md axis table |
| L3 | Keep the two decisions separate in code as well as docs: what the machine can do (profile + platform folder) versus what a build is allowed to do (cart composition + endowments). | sections E, K |
M. Retiring the ABI crossing — measured on the green base
The crossing exists because boot/root.cart carries the engine as a finalized
pool. Bump the Mach ABI and the runtime refuses its own engine, so it cannot run the
Pit code that would re-cement the cart. Four agents lost a session to that circle.
Three things were established by experiment on a3184e5e, not by reading:
1. The Pit step and the ABI step are cleanly separable (pit-shop/shop_build.cm:2244).
compiler.compile_result(source) produces streamlined mcode in Pit and is ABI-neutral;
mach.mach_compile_mcode_bin(mcode) produces the stamped pool and is C. Recompiling
internal/engine_lite.cm from source and serializing reproduces the committed
boot/engine_lite.mach byte for byte — blake2 e9162acb…, 119,684 bytes both sides.
Round-tripping the mcode through JSON and re-serializing yields the identical pool, so
the mcode alone is a sufficient input.
2. A loose engine on disk is never consulted at boot — hypothesis disproven.
boot_mach_data is fed only from pit_cart_engine_image() (source/scheduler.c:3851,
:3879); the engine always rides inside a mounted cart. With both carts moved aside and
boot/engine_lite.mach + boot.qop present, a cold bare binary refuses outright:
“no root cartridge: none appended, no boot/root.cart, and PIT_ROOT_CART is unset.”
So “boot the engine plus the qop with no cart” is not a path. boot/engine_lite.mach is
a cementing input, not a boot input.
3. The C serialize step costs 7.5 ms. Measured five runs: 37.6 ms total, 7.5 ms each, against 1.16 s for the Pit compile. Caching it is unnecessary.
The fix
Let the cart’s engine section carry mcode rather than a finalized pool, with one header bit saying which form it is. C serializes at mount when it is mcode — 7.5 ms — and runs the result at whatever ABI the binary was built for. The same dev cart then boots on a v2 or a v3 binary, and an ABI bump requires no re-cementing at all.
This is the rule the system already applies to payloads, applied to the engine: dev ships mcode because mcode survives VM edits, ship cements the finalized pool. A shipped cart is unchanged — finalized engine, zero serialize cost.
| # | Do | Note |
|---|---|---|
| M1 | Add the engine-form bit to the cart’s fixed header; C serializes mcode at mount, maps a pool directly. | folds into D4’s fixed header |
| M2 | Cement dev carts with an mcode engine; keep ship carts finalized. | matches cake/plan.cm:692 payload policy |
| M3 | Budget: a dev cart’s engine section grows ~120 KB → ~955 KB. Irrelevant for dev; ship is untouched. | |
| M4 | Fallback if M1 is deferred: automate a stage-1 crossing — build the pinned old binary, cement with it, proceed. No new C, but the ritual stays. |
The engine is one translation unit — a standing constraint
Two steps make images, and only one of them is C:
| Step | Where | |
|---|---|---|
| 1:1 | one mcode unit -> one mach blob | C, pit_mach_compile_mcode_bin (source/runtime.c:9290) |
| N:1 | several mcode units -> one pool | Pit, internal/mach_pool_emit.cm (958 lines, new in 9466791a: “Pure-Pit pit.mcode.unit@3 -> pit.mach.pool@1 finalization”) |
At the green base nothing fuses units at all: an executable is a record whose modules
array carries one blob each (pit-shop/shop_build.cm:347, :383, :456), and the cart
cements those N blobs into sections. The link group is the new idea.
So M1 is viable only because internal/engine_lite.cm has no use() imports and is
therefore a single mcode unit that C’s 1:1 serializer can rebuild. Were the engine ever
several units, C would need the pool emitter, and porting 958 lines of Pit into the audit
surface is exactly what the minimal-C edict forbids.
This constrains F2. Splitting the ~1,870 lines of standard library out of the engine
must be done by removing code from engine_lite.cm into ordinary modules that go
through the normal N:1 path — never by having the engine use() its pieces. An import
would make the engine multi-unit and silently break C’s ability to rebuild it, which
would surface only as a failed ABI bump much later. Done the right way F2 helps M: a
smaller engine means less mcode in the cart than the 955 KB measured today.
Corroboration that this is the grain of the system rather than a new invention:
payload_mode already has mcode / mach / mixed arms with a matching engine_abi
(pit-shop/shop_build.cm:278-298). Dev-ships-mcode is implemented one level up already;
M extends it to the engine.
L1 findings — audited on the green base
The codebase is not uniformly leaky. It is clean where the levers already exist and
target-keyed where they do not. pit-compiler/ branches only on rep names, never on
target names (rep_fold.cm:301-312); pitlib/ has zero hits; the shop’s source resolver
does target arms by data lookup with no hardcoded names (shop_source.cm:694-716); and
internal/sysfacts.c / source/pit.c:12-16 publish PIT_TARGET_* as build-injected
facts with "unknown" defaults, which is the right plumbing. Two places already
demonstrate the correct pattern: rep-keyed folding in pit-compiler/rep_fold.cm, and
lever-keyed sizing in source/capacity_harness.c (contrast adder_harness.c, which does
the same job by being the PS1).
There is one structural spine and nearly everything hangs off it.
source/pit_profile.h is an eight-arm #if/#elif chain — one per console, at lines 13,
26, 41, 57, 146, 177, 275, #else 305 — and each arm sets profile name, value-word bits,
object ABI, numeric rep, region defaults, and image cap together, indivisibly. Because
a cart’s stamp must match that bundle byte for byte, pit-shop/rep_profile.cm:60-69 was
forced to grow a mirror-image TARGET_AXES = {psp, dc, n64, ps1} table in the shop, which
internal/cement.ce:250,360,412 then threads through as --target. Adding a console
today means editing pit_profile.h, sys_thread.h, rep_profile.cm, three
package.json manifests, and pit-linker/toolchains.cm — runtime enums that grow, which
is what the edict forbids. Fixing pit_profile.h collapses most of the rest in one move.
Four axes do not exist and are required:
| Axis | Why | Evidence |
|---|---|---|
| memory budget (dynamic region / static region / max images) | every pit_profile.h arm exists partly to set three numbers; there is no way to say “2 MiB dynamic” without being the N64 | pit_profile.h:20,21,24 / 37,39 / 53,55 / 142,144 / …; pgo_profile.h:16 |
| endian | see the ruling needed below | rep_profile.cm:63 |
| thread-primitive provider | distinct from the scheduler axis: PIT_SINGLE_THREAD says “one drain”, not “which mutex links”. Six unrelated targets share one #if for four documented reasons | sys_thread.h:33,56 |
| out-of-process daemon power | whether the host may fork a daemon, symlink a socket, honour PIT_INPROCESS. Currently answered by !defined(_WIN32) | source/host.c:334-343,393-399 |
Three more removals need no new axis, only routing: the profile name as a
build-supplied string rather than a chain output; default content path as a startup
fact (shop_actor.ce:138-139 hardcodes playdate/emscripten); and provider set
discovered from linked providers rather than declared by hand in internal/policy.ce:13-27,
which enumerates every platform’s raw endowments by name.
Platform-fact leaks — portable code doing OS-specific work. Well-scoped, no new axis,
each belongs in platform/<os>/: internal/vm.c:82-89 (Playdate memory stats called from
the portable VM-stats endowment), source/runtime.c:2589,2617 (pit_web_log_tee inside
Pit_Log), source/host.c:242-249 (macOS .app path sniffing), source/crash.c:159-165
(Win32 pipe shim), internal/bundle.ce:238-249 (hardcoded macOS .app layout).
Build-system work outside cake. pit-linker/build.cm selects IO backends, link flags,
Objective-C source lists, and executable suffixes by tc.system (lines 526-528, 546-557,
859-873, 2032, 2156-2161), and pit-linker/toolchains.cm carries the canonical 22-target
supported list plus a hardcoded developer path at line 14. Legitimate kind of work in
the wrong folder — cake already owns plan.link_flags(tc).
Roughly 410 further target-name mentions are non-branching: comments, log strings, help text, test fixture names. Not worth touching.
RULING NEEDED — endian
docs/architecture/target-profiles.md lists endian in the axes table, but the profile
string it documents carries no endian= field, and source/pit_profile.h:58-70 says the
omission is deliberate, with a stated reason: adding it “would change every existing
little-endian stamp and break the desktop cart’s byte-identity.” Endian instead travels
three ways — the distinct profile name (n64-nan32-v1), the mach header’s endian byte,
and the cart header’s endian byte.
That decision is exactly what forces rep_profile.cm:60-69 to recover byte order from the
literal name n64, which is a target-name branch in the shop and precisely what the edict
forbids. The two positions cannot both stand:
- Add
endian=to the profile string. The name stops being semantically load-bearing and the shop’s target table dies. Cost: every existing stamp changes. That cost is near zero right now — the Mach ABI is being bumped anyway, so stamps are already moving. It will not be near zero later. - Keep it out. The profile name stays load-bearing, and the shop keeps a name-to-endian table that the edict has to carve out an exception for.
The doc currently asserts the first and the code implements the second, so one of them is wrong either way. Recommend adding the axis while stamps are already in motion.
Source: plans/archive/worklist.md