Artifact Formats
This specification defines the durable objects in the pit content graph. The normative pipeline is:
source blob -> pit.mcode.unit@3 -> pit.executable.manifest@1
-> pit.mach.fragment@1
-> pit.mach.pool@1 (+ pit.mach.origin@2)
-> pit.target.realization@1
-> pit.cart@2 / pit.bundle@2
Every arrow is a pure derivation. The derivation key covers the semantic inputs to that arrow; the output content hash covers the canonical output bytes. A locator names an object through a catalog, a version or lock selects package content, and a content hash identifies exact bytes.
Two of those rows are shaped differently from the rest.
pit.mach.fragment@1 is an internal handoff between the two stages of pool
emission — it is specified here, and it is never stored. pit.mach.origin@2 is
a stored sidecar of one pool rather than a step toward the next artifact: it
exists so a target-final PC can be read back as mcode and source.
The Pipeline narrates this chain end to end; the sections below define each format.
Common rules
Hashes and canonical records
Durable hashes use the repository’s configured 256-bit content hash and its
algorithm-qualified text spelling, currently blake2:<64 lowercase hex digits>.
Binary formats carry the raw 32 bytes where fixed-width lookup matters.
Canonical record artifacts use binary Nota with these rules:
- record keys are sorted by UTF-8 byte order at every depth;
- arrays retain their declared order;
- text uses Nota’s Unicode text spelling;
- numbers that recover exactly use Nota’s integer or normalized decimal
spelling. A number that the general Nota decimal reader would round is
encoded as the reserved canonical record
{schema: "pit.canonical.number@1", decimal: <former canonical JSON spelling>}and restored withnumber(decimal). The escape is a scalar wire spelling, not a user record, and preserves both the runtime value and cross-migration dump text; - absent optional fields are omitted; and
- hashes are calculated over the complete canonical bytes, excluding only a field explicitly identified as an out-of-band catalog key.
These rules exist to make one artifact have one address no matter who produced
it. A record’s key order is a property of how it was built — two producers
assembling the same artifact do not agree on it, and a copying collection can
change it again afterwards — and two producers do not agree on whether an
optional field they have no value for is written as null or left out. If
either reached the stored bytes, the artifact would have two content hashes and
no cache could be shared across producers.
Consequently there is exactly one canonical encoder, and every stored record artifact is written through it: the portable mcode unit and its slim metadata, the executable manifest, the workspace snapshot and resolution, the target realization, the policy decision, the cached executable, the Mach debug and origin sidecars, and the semantic profile and its index. It is a Pit walker that appends container headers, sorted key/value pairs, and scalar Nota bytes into one growing blob; it never builds per-subtree text values. A second implementation of “canonical” is a second answer to what an artifact is.
Readers accept both these binary records and legacy canonical-JSON records so
an old object store remains inspectable across the reseed boundary. pit dump <hash> reads either representation and emits the former compact canonical JSON
spelling for comparison; objects that are not records are emitted in a JSON
envelope with their bit length and hexadecimal bytes. That text is diagnostic
only and is never hashed as an artifact.
Blobs and pools are not record artifacts. Mach pools, mcode payloads, and every other value that is already a byte string are stored as the bytes they are, and their content hash is taken over those bytes directly. Canonical encoding applies only where an artifact’s bytes have to be derived from a value, which is the only place a key order can differ between producers.
Schema names include their major version. A reader accepts exactly the named schema it implements.
Build manifests
pit.build-manifest|1|<recipe> is cake’s committed, line-oriented rendering
of a runtime recipe. It is generated as boot/manifest/<recipe>.manifest so a
cross-build script — and the cold bootstrap, before a pit runtime exists — can
consume the same file and symbol plan as forge. Empty fields are meaningful;
consumers split on | and ignore comment lines beginning with #.
The row kinds are:
| Row | Meaning |
|---|---|
| `stamp | |
| `build | |
| `entry | |
| `runtime | |
| `support | |
| `gc | |
| `text | |
| `extension | |
| `static | lead|trail |
| `floor | |
| `link |
entry is deliberately not a runtime row. Forge links the runtime objects
without a main into C tests and adds the entry object only to the executable;
cross-builds that replace or rename main can likewise handle the row
explicitly. The generated boot/manifest/bootstrap.sh embeds the same plan
rather than defining another source list.
Complete target profile
Target-final artifacts carry one canonical profile record and its canonical hash:
{
schema: "pit.target.profile@1",
target: "n64",
system: "n64",
arch: "mips64-vr4300",
endian: "be",
value: {bits: 32, references: "pit.ref.region-offset-v1"},
object: {header_bits: 32, layout: "pit.object.nan32-v1"},
number: {representation: "nan32"},
text: {representation: "utf32"},
record: {representation: "hash"},
gc: {collector: "compact"},
scheduler: {mode: "single"},
mach: {abi: "blake2:..."},
providers: "blake2:..."
}
mach.abi is the exact pit.mach.abi@1 artifact hash. providers is the
exact permanent pit.provider.catalog@1 hash generated for the linked runtime.
Every closure-specific provider registry separately names that catalog through
its provider_catalog field.
The catalog answers what the build can grant. A power such as native building, native loading, or one of the debugging endowments is present exactly when its provider is a row in the catalog, so the profile records the catalog hash and nothing further.
The profile is passed and hashed as one value. object.layout is the versioned
base object-header/layout ABI; v1 names are pit.object.nan64-v1 with 64-bit
headers and pit.object.nan32-v1 with 32-bit headers. It is independent of the
value, number, text, record, and GC axes. Axis values are validated before
derivation or cache lookup.
Mach ABI and finalizer identities
The VM/pool contract and the implementation that produces a pool are separate content-addressed artifacts:
{
schema: "pit.mach.abi@1",
name: "mach-v4",
pool: {schema: "pit.mach.pool@1", version: 1},
instruction: {
encoding: "pit.mach.instruction-v4",
module_results: {
local: "LOAD_MODULE_RESULT-v1",
bound: "LOAD_BOUND_MODULE-v1"
}
},
endian: "be",
value: {bits: 32, references: "pit.ref.region-offset-v1"},
object: {header_bits: 32, layout: "pit.object.nan32-v1"},
number: {representation: "nan32"},
text: {representation: "utf32"},
record: {representation: "hash"},
stone: {
contract: "pit.stone.image-v1",
text: "canonical-fash64-v1"
}
}
{
schema: "pit.mach.finalizer@1",
input: "pit.mcode.unit@3",
output: "pit.mach.pool@1",
implementation: "blake2:...",
toolchain: "blake2:...",
flags: {}
}
The ABI artifact is the complete pre-entry C/VM execution-safety contract. It
commits to the instruction ABI and name, pool schema/version, endian,
value/reference representation, object header/layout, numeric/text/record
representations, stone contract, and module-result import opcodes. Every
duplicated axis in the target profile and pool header must agree with it.
canonical-fash64-v1 requires STONE text to use the canonical packed UTF-32
form and its finalized 64-bit FASH hash.
LOAD_MODULE_RESULT encodes an executable-local provider unit ID; execution
adds the executable instance base and reads that slot from the actor-owned
realization result array. LOAD_BOUND_MODULE indexes the pool-local
cross-image binding row; the immutable PoolBinding resolves that row to its
provider realization instance/result slot. Both opcode contracts are part of
the ABI hash.
The finalizer artifact identifies the exact implementation closure, target-neutral toolchain semantics it invokes, and semantic finalization flags. Checkout paths, timestamps, process identity, and machine identity are outside both records. Changing either exact identity changes the pool derivation without changing its input mcode.
Target bootstrap configuration
The thin root cart carries one canonical pit.bootstrap.target@1 object. It
is the target-specific configuration Pit needs before it can locally finalize
the portable development bundle:
{
schema: "pit.bootstrap.target@1",
target: {
system: "n64",
selector: {system: "n64"},
profile_stamp: "n64-nan32-v1;..."
},
providers: {
hash: "blake2:...",
catalog: {
schema: "pit.bootstrap.provider.catalog@1",
target: {system: "n64", selector: {system: "n64"}},
rows: [
{key: "shoplib/crypto", kind: "extension",
locator: "gitea.pockle.world/john/shoplib::crypto",
symbol: "pit_shoplib_crypto_use",
lane: "normal", lease: "", init: ""}
]
}
},
profile: {
schema: "pit.bootstrap.profile.config@1",
constructor: "pit.target.profile@1",
provider_catalog: "blake2:...",
profile_stamp: "n64-nan32-v1;..."
},
mach_abi: {hash: "blake2:...", value: {
schema: "pit.mach.abi@1", name: "mach-v4",
pool: {schema: "pit.mach.pool@1", version: 1},
instruction: {
encoding: "pit.mach.instruction-v4",
module_results: {
local: "LOAD_MODULE_RESULT-v1",
bound: "LOAD_BOUND_MODULE-v1"
}
},
endian: "be",
value: {bits: 32, references: "pit.ref.region-offset-v1"},
object: {header_bits: 32, layout: "pit.object.nan32-v1"},
number: {representation: "nan32"},
text: {representation: "utf32"},
record: {representation: "hash"},
stone: {
contract: "pit.stone.image-v1",
text: "canonical-fash64-v1"
}
}},
finalizer: {hash: "blake2:...", value: {
schema: "pit.mach.finalizer@1",
input: "pit.mcode.unit@3", output: "pit.mach.pool@1",
implementation: "blake2:...", toolchain: "blake2:...", flags: {}
}},
implementations: {
finalizer: {hash: "blake2:...", value: {
schema: "pit.mach.finalizer.implementation@1",
root: "gitea.pockle.world/john/shoplib::mach_pool_emit.cm",
units: [{locator: "...", mcode_hash: "blake2:..."}],
bindings: [], extensions: []
}},
toolchain: {hash: "blake2:...", value: {
schema: "pit.compiler.toolchain.implementation@1",
root: "gitea.pockle.world/john/pit-compiler::compiler.cm",
units: [{locator: "...", mcode_hash: "blake2:..."}],
bindings: [], extensions: []
}},
policy: {hash: "blake2:...", value: {
schema: "pit.bootstrap.policy.implementation@1",
root: "gitea.pockle.world/john/pit-shop::bootstrap_policy.cm",
units: [{locator: "...", mcode_hash: "blake2:..."}],
bindings: [], extensions: []
}}
},
policy: {
program: "blake2:...",
program_kind: "pit.bootstrap.policy.implementation@1",
config: {hash: "blake2:...", value: {
schema: "pit.bootstrap.policy.config@1",
profile: "development",
roles: {
services: [
"pit-shop/clerk",
"pit-shop/daemon_listener",
"pit-shop/logger",
"pit-shop/policy",
"pit-shop/courier",
"pit-shop/builder_worker",
"pit-shop/terminal",
"shop_tools/down",
"shop_tools/ps",
"shop_tools/shop"
],
roots: {
"pit-shop/clerk":
"gitea.pockle.world/john/pit-shop::clerk.ce",
"pit-shop/daemon_listener":
"gitea.pockle.world/john/pit-shop::daemon_listener.ce",
"pit-shop/logger":
"gitea.pockle.world/john/pit-shop::logger.ce",
"pit-shop/policy":
"gitea.pockle.world/john/pit-shop::policy.ce",
"pit-shop/courier":
"gitea.pockle.world/john/pit-shop::courier.ce",
"pit-shop/builder_worker":
"gitea.pockle.world/john/pit-shop::builder_worker.ce",
"pit-shop/terminal":
"gitea.pockle.world/john/pit-shop::terminal.ce",
"shop_tools/down":
"gitea.pockle.world/john/shop_tools::down.ce",
"shop_tools/ps":
"gitea.pockle.world/john/shop_tools::ps.ce",
"shop_tools/shop":
"gitea.pockle.world/john/shop_tools::shop.ce"
}
},
execution_forms: ["mach"],
native: false,
endowments: {mode: "claimed", grant: "available-claimed"},
content: {identity: "verified-hash", authority: "active-local-policy"}
}},
issuer: "local:root"
}
}
Every hash named by finalizer.implementation, finalizer.toolchain, and
policy.program is cross-linked to its exact canonical implementation-closure
record in implementations. The root-cart producer derives those records from
the exact root executable graph and embeds them in the canonical target asset.
Before finalization, the bootstrap realizer verifies each cross-link and stores
the standalone canonical record bytes under that content hash. A bare
implementation hash is not a complete bootstrap target.
policy.program_kind explicitly identifies the latter record as
pit.bootstrap.policy.implementation@1.
The provider rows are the exact post-probe, post-trim Cake rows used to generate the linked static provider table. The finalizer implementation and toolchain, policy program, policy configuration, Mach ABI, provider catalog, and profile configuration all carry content identities. The bootstrap record contains no bundle or QOP identity: content hashes verify the independently selected bundle’s bytes, and this active local policy decides whether its executables may run and which claimed endowments they receive. Each authorized service locator is paired with its canonical executable-root locator, so a bundle catalog cannot assign an allowed boot role to different code. The boot policy carries the executable manifest’s requested actor limits into the local request, realization, and start packet.
Store contract
All stores provide:
get_manifest(callback, request)
get_content(callback, {hash, range?})
get_manifest returns a pit.store.manifest@1. get_content returns bytes
whose content hash is verified before use. A range response also carries the
whole-object hash, offset, returned length, and range proof supplied by the
backing manifest or sealed container.
{
schema: "pit.store.manifest@1",
identity: "blake2:...",
catalog: {
"gitea.example/alice/game::main": {
kind: "realization",
object: "blake2:..."
}
},
objects: {
"blake2:...": {kind: "pit.target.realization@1", size: 1234}
},
packages: {
"gitea.example/alice/game": {
schema: "pit.package.selections@1",
selections: [
{kind: "git", version: "1.6.2",
commit: "git-sha1-commit:...", tree_hash: "git-sha1-tree:..."},
{kind: "workspace", version: "1.7.0-dev",
workspace_snapshot: "blake2:..."}
]
}
},
signature: {issuer: "...", algorithm: "ed25519", value: "..."}
}
The manifest identity is the hash of the canonical manifest core without its
identity and signature fields. Signatures cover the identity plus the
container/store scope declared by the signer.
The packages index is keyed by canonical package locator. A
pit.package.selections@1 row contains one or more canonical selection rows sorted by
their canonical bytes with exact duplicates removed. Workspace selections name
declared pit.workspace.snapshot@1 objects; Git selections carry a same-algorithm exact
commit/tree pair. Layered stores union these immutable selections. Executable manifests
and their lock or workspace resolution remain the authorities that choose one selection
per canonical package for a particular executable.
Source objects
A source object is the exact UTF-8 bytes of one .cm module or .ce actor
program. Its content hash is calculated over those bytes. Package trees map
normalized relative paths to source hashes:
{
schema: "pit.package.tree@1",
package: "gitea.example/alice/image",
entries: [
{path: "decode.cm", kind: "source", hash: "blake2:...", size: 8192},
{path: "sprites/player.png", kind: "asset", hash: "blake2:...", size: 9401}
]
}
Entries are sorted by normalized path. Package selection records locator, selector, declared version information, commit, and tree hash in the lock and executable manifest.
Portable mcode unit
pit.mcode.unit@3 is the sole portable compiler artifact. One object represents
one source unit under one selected target-neutral compiler pipeline.
{
schema: "pit.mcode.unit@3",
language: {name: "pit", semantics: "blake2:..."},
format: {name: "mcode", version: 3},
compiler: {
identity: "blake2:...",
pipeline: "thorough",
stages: ["parse", "fold-exact", "mcode", "streamline"],
flags: {compact_slots: true, infer_shapes: true}
},
source: {
hash: "blake2:...",
encoding: "utf-8",
kind: "module"
},
imports: [
{id: 0, request: "std::stream", kind: "module"}
],
claims: {
endowments: [],
globals: [],
logs: ["debug", "panic"],
extensions: [],
executables: []
},
literals: [
{kind: "text", utf8: "hello"},
{kind: "integer", decimal: "42"},
{kind: "number", text: "3.1415926535897933e-16"}
],
functions: [
{
id: "main",
name: "main",
arity: 0,
close_slots: 0,
frame_slots: 3,
abi_flags: 1,
disruption_pc: 0,
instructions: [
"_log_begin_0:debug:2",
["literal", 0, 0], ["call", 2, 3, 1, 0], "_log_end_0",
["return", 2]
],
sites: [{id: "return:0", pc: 4, kind: "return", span: 0}],
logs: [{id: "log:0", channel: "debug", start: 0, end: 2, result: 2}]
}
],
spans: [
{start: {line: 1, col: 1}}
],
facts: {
code: {},
functions: [{id: "main", facts: {}}]
}
}
Literals are interned per unit: one row per distinct constant, named by dense
index from a ["literal", dest, index] instruction. Two rows of the same kind
never carry the same value, and the kind is part of that identity — the text
"42" and the integer 42 are two rows. A text row carries its exact
characters; an integer row its canonical base-10 spelling; any other number its
shortest recovering decimal, per the canonical-record rules above. An integral
value too large for a base-10 integer spelling is a number row, because it
has no integer spelling to give.
The pool is a property of the artifact, not of the instruction language.
Mcode carries literals inline on access (see Mcode) and every
compiler pass reads them there; interning happens on the way out, and a reader
turning a unit back into mcode restores the inline form. That is what keeps the
pool from becoming a second encoding the lowering lanes must learn. The
per-unit table is the standalone transport form. Once units link, it is
replaced by the linked program’s group pool below; target lowering therefore
sees one semantic literal identity before a Mach STONE section exists.
Each function’s logs rows name target-neutral semantic regions. start and
end are inclusive mcode PCs covering channel construction, every argument
expression, and the log call; result is the destination that becomes null
when the region is stripped. The unit’s claims.logs is the sorted set of
channels present in those rows. The semantic linker can therefore remove one
channel without guessing from Mach instructions, and when the last channel is
removed it removes the ordinary log global claim as well.
Linked mcode program
pit.mcode.program@1 is the semantic linker’s output, still before target
lowering. It owns executable-local unit ids, member-granular import rows, link
groups, and one literal table per group. A fully linked program currently has
one group:
{
schema: "pit.mcode.program@1",
plan: {
schema: "pit.mcode.link-plan@1",
profile: "ship",
granularity: "program",
stripping: {names: true, logs: ["debug"]}
},
groups: [{id: 0, units: [0, 1], literals: [{kind: "text", utf8: "hello"}]}],
units: [
{
unit_id: 0,
locator: "example::provider",
literal_group: 0,
unit: {schema: "pit.mcode.linked-unit@1", literals: [], functions: [...]}
}
],
member_imports: [
{importing_unit: 1, import_id: 0, locator: "example::provider", name: "encode"}
],
stripping: {
names: {enabled: true, stack: [{stable_id: "blake2:...#main"}]},
logs: {
channels: ["debug"], unevaluated: true,
stack: [{stable_id: "blake2:...#main#log:0", channel: "debug"}]
}
}
}
The link plan is a required semantic input, never inferred from a build mode. It has exactly three ruled profile/granularity pairs:
| profile | granularity | link groups | edge treatment |
|---|---|---|---|
dev | module | one per unit | unresolved, cache/hot-reload friendly |
ship | program | one program group | legal semantic edges finalized |
boot | program | one program group | legal semantic edges finalized |
stripping.names and stripping.logs are producer flags in the same explicit
input. The profile name supplies no hidden default for them. A contradictory
pair, an omitted plan, duplicate log channels, or an unknown field is a link
error. A module-granular program retains one literal table per unit; a
program-granular link owns one table for all units.
A pit.mcode.linked-unit@1 body deliberately is not a standalone mcode unit:
its literal operands name its group’s table, and its private literals array
is empty. The lowering boundary materializes one transient
pit.mcode.unit@3 view by attaching that group table. Storing the table on
every nested unit would reproduce the duplication the program pool removes.
Literal rows retain the standalone unit spellings and are interned by kind and value in stable unit/instruction order. Link-produced text and number constants enter the same table. This is placement, not optimization: no instructions are folded except the member-edge finalization already licensed by an exact literal stone export, and no streamline pass runs over the program.
Name stripping writes null to the portable function name. The target pool
then emits its ruled stripped-name sentinel while retaining the function’s
stable ID, source.hash + "#" + function.id, for stack traces and host-side
symbolication. Per-channel log stripping replaces every operation in the
declared region with zero-word labels except for one null at the original
result PC. Consequently argument expressions are unevaluated. The literal
pool is rebuilt after stripping, so constants reachable only from removed log
regions do not survive. stripping records both producer flags and stable-ID
stacks; it contains no target or Mach identity.
The compiler rejects direct effects in a log-argument subtree: assignment, send, a property store on a non-fresh receiver, and sensory-classified intrinsics. Calls remain conservatively permitted until interprocedural purity facts land; a stripped call argument is still unevaluated, but this tier does not yet prove that keeping the same call on another channel is pure.
Spans are interned per unit: one row per distinct source position, named by
dense index from a site. A span’s source is the unit’s own source.hash, so a
row does not repeat it. Rows carry the positions the compiler records —
line and column; a span does not carry byte offsets, because the front end does
not retain them.
facts is keyed by the same function ids the body uses, and carries one
code-level bucket for whole-unit facts. Each bucket holds the durable
target-neutral outputs of the selected stages; a reader that cannot interpret a
fact name rejects the unit rather than lowering without it.
Function and site IDs are stable within the source-derived unit: a function is
"main" or its dense index, and a site is its opcode plus that opcode’s
ordinal within the function. Import rows retain the programmer’s unresolved
request. Canonical package/file provenance and resolved import destinations are
executable-manifest data.
A portable function obtains a module result with
["import", destination_slot, import_id]. The dense import_id indexes this
unit’s imports rows. The executable manifest binds that ID to a provider unit;
the target finalizer turns same-image edges into direct indices and emits only
cross-image edges in the Mach image’s IMPORT table.
The mcode derivation is:
K_mcode = hash(
source content hash,
language semantics hash,
compiler identity,
mcode format,
ordered selected target-neutral stages,
canonical target-neutral flags,
unit kind,
static binding salt
)
K_mcode -> mcode content hash
The last two components are part of the key because they change the output: the same text lowers differently as a module and as a program, and static bindings are resolved during lowering. The compiler identity is the toolchain stamp — the hash of every compiler and linker source that can change the result — which is what makes editing the compiler invalidate the derivation.
The catalog holds K_mcode -> content hash, and the object store holds the
unit’s bytes under that content hash. A derivation key never names bytes and a
content hash never names a computation.
facts contains durable output of selected target-neutral stages. Each pipeline
declares the fact schema it emits. Exact literal meaning is retained for final
target lowering.
Executable manifest
pit.executable.manifest@1 is the portable exact logical actor executable.
{
schema: "pit.executable.manifest@1",
root: {unit: 7, function: "main"},
packages: [
{
id: 0,
canonical: "gitea.example/alice/game",
kind: "git",
version: "1.6.2",
commit: "git-sha1-commit:...",
tree_hash: "git-sha1-tree:..."
},
{
id: 1,
canonical: "gitea.example/alice/editor",
kind: "workspace",
version: "0.4.0",
workspace_snapshot: "blake2:..."
}
],
units: [
{
id: 7,
package: 0,
path: "main.ce",
locator: "gitea.example/alice/game::main.ce",
source_hash: "blake2:...",
mcode_hash: "blake2:...",
kind: "program"
}
],
bindings: [
{importer: 7, import: 0, provider: 3}
],
initialization: [3, 5, 7],
claims: {
units: [{unit: 7, endowments: ["screen"], globals: [], extensions: []}],
aggregate: {endowments: ["screen"], globals: [], extensions: []}
},
resolution: {kind: "workspace", hash: "blake2:..."},
policy_request: {execution_forms: ["mach"], deny_c: true, limits: {}}
}
Unit IDs are deterministic dense integers assigned after canonical graph
sorting, whose key is the unit’s structured (package, path) origin rather
than its locator text. Each canonical package/path occurs once. Binding rows
are sorted by (importer, import). Initialization is the deterministic
topological order and contains each unit instance once, with the root last.
Distinct locators may retain separate unit rows when they are distinct
semantic references to identical mcode bytes.
A unit’s import index is its position in the portable unit’s own imports
array, so an import row and its binding row name the same edge. A request
satisfied by a native provider has no binding row: there is no provider
unit to bind to, and the requirement is already carried as an extensions
claim. Import indices stay dense and positional regardless, because those
indices are what the unit’s instructions name.
Every unit row names exactly one package row. Content that belongs to no
package on disk — an evaluated program, a script given by absolute path —
uses the reserved canonical package name <script>, whose identity is an
ordinary pit.workspace.snapshot@1 over that content’s own source. The
snapshot is the script, which is the honest identity for content with no
published home; the reserved name cannot collide with a package locator
because a locator never contains <.
The manifest content hash is the executable identity. Pool grouping, target profile, policy context, and placement do not enter it. That is checkable rather than asserted: the same closure built for two different targets must produce the same manifest hash, because the manifest holds nothing target-shaped to vary.
Manifest finalization refuses a closure that lands one canonical package at two identities, and the refusal names both identities together with a root-to-unit path for each. This is the only point in the system where two candidates of one package are visible at once, and therefore the only point that can see the collision at all — which is why resolution must land on a package identity and never be recovered from locator text afterwards. See Executables, “Resolution produces identities”.
Package rows use exactly one identity arm. kind:"git" requires matching typed
commit and tree identities and carries no workspace snapshot.
kind:"workspace" requires a pit.workspace.snapshot@1 content hash and carries
no Git identity. resolution.kind:"lock" names the exact committed package lock;
resolution.kind:"workspace" names a pit.workspace.resolution@1. Selector and
dependency-path provenance remains in that resolution object and is not duplicated in
package rows.
Workspace snapshot
pit.workspace.snapshot@1 is the exact identity of the selected portion of one
mutable development package:
{
schema: "pit.workspace.snapshot@1",
package: "gitea.example/alice/editor",
version: "0.4.0",
manifest_hash: "blake2:...",
selected_target_arms: {display: "host"},
files: [
{path: "main.ce", source_hash: "blake2:..."},
{path: "ui/render.cm", source_hash: "blake2:..."}
]
}
Files are sorted by canonical package-relative path and appear once. Only source rows selected by the executable are included. Checkout paths, mtimes, and machine identity stay in the deletable freshness index and cannot change this artifact. The snapshot identifies development content and does not claim Git ancestry.
Workspace resolution
pit.workspace.resolution@1 is the exact, path-free development alternative to
a committed published lock:
{
schema: "pit.workspace.resolution@1",
root: "gitea.example/alice/game",
target: "host",
packages: [{
id: 0,
canonical: "gitea.example/alice/game",
version: "0.4.0",
manifest_hash: "blake2:...",
workspace_snapshot: "blake2:...",
dependencies: [{
alias: "image",
locator: "gitea.example/alice/image",
selector: {kind: "semver", constraint: "^2"},
arm: "host"
}]
}]
}
Package and dependency rows are canonical and include only packages selected by the executable. Declared versions and typed selectors preserve compatibility meaning; manifest and workspace-snapshot hashes preserve exact byte identity. Checkout roots, link aliases, mtimes, and machine identity are excluded.
policy_request.deny_c is part of executable identity. When true, manifest
finalization rejects any nonempty per-unit extensions claim before a target
realization can be formed. The diagnostic identifies the native provider and a
deterministic root-to-provider import path. Finalization also verifies every
binding provider precedes its consumer in initialization; the runtime does not
repair or rediscover dependency order.
Policy request
pit.policy.request@1 names the exact subject presented to policy:
{
schema: "pit.policy.request@1",
executable: "blake2:...",
claims_hash: "blake2:...",
requester: {kind: "guest", identity: "blake2:..."},
target_profile: "blake2:...",
execution: {form: "mach", images: ["blake2:..."]},
provider_registry: "blake2:...",
policy: {
program: "blake2:...",
program_kind: "pit.executable.manifest@1",
config: "blake2:...",
issuer: "local:shop"
},
limits: {}
}
The policy program hash and its declared artifact kind form one identity. The
request’s content hash commits to both. provider_registry is the exact
closure-specific pit.provider.registry@1 hash. Its provider_catalog must
equal the selected target profile’s providers value.
Provider catalog
pit.provider.catalog@1 is the exact post-selection provider inventory generated
by Cake for one linked runtime and target profile:
{
schema: "pit.provider.catalog@1",
runtime_image: "blake2:...",
target: {
system: "darwin",
selector: {system: "darwin", arch: "arm64"},
profile_stamp: "...",
mach_abi: "..."
},
rows: [
{
logical: "gitea.pockle.world/john/shoplib::crypto",
key: "shoplib/crypto",
provider: {
kind: "static-extension",
abi_hash: "blake2:...",
entry: {
kind: "static-symbol",
symbol: "pit_shoplib_crypto_use"
}
}
},
{
logical: "$hook",
key: "endowment/hook",
provider: {
kind: "hook-primitives",
abi_hash: "blake2:...",
entry: {
kind: "static-symbol",
symbol: "pit_platform_darwin_trace_use"
}
},
adapter: {
executable: "blake2:...",
unit: 0,
private_binding: "$provider"
}
}
]
}
Rows are sorted by (logical, key). key is the canonical exact lookup key
used by the generated static table. provider.entry records the selected typed
entry and its provenance; its symbol is not a second lookup spelling. An
adapter row names one exact pit.executable.manifest@1, one local unit ID in
that manifest, and the private binding through which the runner supplies the
raw provider.
A dynamic extension is selected through a cataloged native-loader provider and
an exact pit.native.image@1 descriptor. Its identity is the native-image
content hash, native ABI hash, and typed entry ID rather than a host path or
unqualified symbol name.
Provider registry
pit.provider.registry@1 binds logical provider claims to exact target
implementations. A direct endowment row names one target implementation. An
adapted row also names the exact portable executable and selected unit that
construct the public value:
{
schema: "pit.provider.registry@1",
provider_catalog: "blake2:...",
endowments: [
{
endowment: "$hook",
key: "endowment/hook",
adapter: {executable: "blake2:...", unit: 0},
private_binding: "$provider",
provider: {kind: "hook-primitives", abi_hash: "blake2:..."}
},
{
endowment: "$native_loader",
key: "endowment/native_loader",
adapter: {executable: "blake2:...", unit: 0},
private_binding: "$provider",
provider: {
kind: "native-loader-primitives",
abi_hash: "blake2:..."
}
}
],
extensions: []
}
provider_catalog is the content hash of the exact
pit.provider.catalog@1 from which these rows were selected. Each row’s
key, provider kind, ABI, and adapter agree with that catalog. A row exists
exactly when the catalog carries the provider, so the registry is the answer to
what this build can grant.
The target profile used by a request or realization satisfies
registry.provider_catalog == profile.providers.
adapter.executable is a pit.executable.manifest@1 content hash and
adapter.unit is a unit ID in that manifest. private_binding is scoped to
that selected unit. provider.kind and provider.abi_hash identify the raw
target implementation supplied through it. Target finalization resolves the
adapter executable’s complete closure into the requesting executable’s single
target realization.
Dynamic extension rows additionally carry the exact native-image content hash,
native ABI, and typed entry ID selected from a validated
pit.native.image@1.
Native-loader runtime interface
The root runner captures the raw native-loader provider privately. It exposes typed static-entry invocation, typed host-native image placement/entry materialization, and an opaque process-pinned owner. Pit selects the provider row the realization names, verifies native bytes by content hash, checks ABI and entry identity, and retains the owner for the resulting image-backed values.
The public adapted endowment accepts only exact content-addressed requests:
$native_loader.load(callback, {
image: "blake2:...",
abi: "blake2:...",
entry: 0
})
The adapter resolves host placement internally. Its executable row, manifest, instances, and images appear in the same target realization as the requesting executable and therefore share its ordered image set and actor-owned result array.
Policy decisions are not artifacts
Policy answers one question when a program is built: may this be built. The answer is not serialized into a portable, signed, re-verifiable record, because nothing re-verifies it. The shop that asked is the shop that builds, and a start executes a plan already decided — see Capabilities.
A shop may keep a local audit log of decisions. That is a shop’s own bookkeeping, not an artifact any other component reads, and no realization carries its hash.
Mach pool
pit.mach.pool@1 is the final VM image. It contains dispatchable instructions
and immutable stone in the exact target profile. The VM validates the image and
uses its sections in place.
Byte order and alignment
Every multi-byte scalar uses the target profile’s byte order. Every section begins at an offset aligned to its declared alignment; v1 alignments are powers of two no larger than 16. Relations inside the pool are unsigned offsets or indices. Offset zero is reserved as null where a field is optional.
Header
off size field
0 4 magic "pmp1"
4 2 u16 format_version = 1
6 1 u8 endian: 1 little, 2 big
7 1 u8 flags: bit0 instrumented, bit1 host-pointer-table permitted
8 4 u32 header_size
12 4 u32 section_count
16 8 u64 file_size
24 32 payload checksum computed with this field zeroed
56 32 target-profile hash
88 32 Mach-ABI hash
120 32 finalizer/toolchain hash
152 32 link-derivation hash
184 8 reserved, zero
192 24*n section rows
The content store hashes the complete final pool bytes and that hash is the
pool/image identity. The header’s payload checksum is only a container
integrity check calculated with its own field zeroed; it is never used as an
artifact identity or store key. The header endian and target-profile axes must
agree with the exact Mach-ABI artifact named at offset 88.
A section row is:
u32 kind
u32 alignment
u64 offset
u64 length
Rows are sorted by kind. Nonempty sections are placed in the same increasing
order and do not overlap, which lets the bounded reader validate placement in
one pass without allocation. Every section’s offset lies in payload space, at
or after header_size, whether or not it has any length; only a nonempty
section is additionally aligned and ordered against its neighbours. A section
is present when a row declares its kind — an empty section is present, and
ENTRIES through STONE must each be declared. Unknown required kinds invalidate
the image; extension kinds have bit 31 set and may be skipped.
Sections
| Kind | Name | Contents |
|---|---|---|
| 1 | ENTRIES | public (unit instance, entry id) -> function rows |
| 2 | FUNCTIONS | fixed immutable function descriptors |
| 3 | INSTRUCTIONS | aligned final u32 instruction words |
| 4 | VALUES | fixed zero-allocation value encodings |
| 5 | STONE | exact target-layout immutable objects and their bodies |
| 6 | SHAPES | immutable record-shape descriptors, each reaching its key rows by displacement |
| 7 | SHAPE_KEYS | self-relative displacements to STONE key text, plus precomputed target key hashes |
| 8 | IMPORTS | declared cross-image import slots |
| 9 | FUNCTION_REFS | function indices for nested-function relations |
| 10 | PGO_SITES | optional instrumented site descriptors |
ENTRY rows are 16 bytes:
u32 unit_instance
u32 entry_id
u32 function_index
u32 flags
FUNCTION rows are 64 bytes:
u32 stable_id_value # text value naming the stable mcode function ID
u32 name_value # text value, 0xffffffff when stripped
u32 first_instruction
u32 instruction_count
u32 reserved_value0 # zero in the current ABI
u32 reserved_value1 # zero in the current ABI
u32 first_child_ref
u32 child_count
u32 first_pgo_site
u16 pgo_site_count
u16 arity
u16 close_slots
u16 frame_slots
u16 entry_pc
u16 disruption_pc
u16 abi_flags
u16 reserved
u32 flags
u64 stable_function_hash
first_child_ref/child_count indexes a contiguous range of u32 function
indices in FUNCTION_REFS. FUNCTIONS are emitted in canonical preorder; the
explicit reference section distinguishes direct children from descendants.
reserved_value0 and reserved_value1 are zero. Before pool-global VALUES,
the predecessor ABI used them as first_value/value_count; the temporary,
default-off one-generation crossing reader recognizes that meaning only after
the exact predecessor ABI stamp has passed its named gate. Current pools with
either field nonzero are invalid. P3 retires that crossing path.
arity, close_slots, and frame_slots name Mach registers and occupy u16
fields, so each is at most 65535. An ordinary instruction has 8-bit A/B/C
fields; when any register operand is wider, a preceding wide word supplies
their high bytes. For iABx the same prefix supplies the high 16 bits of Bx.
The prefix and following word are one logical instruction, and the narrow
one-word encoding is unchanged. entry_pc and disruption_pc are
function-relative and 16 bits wide, so a function carries at most 65535
instruction words; a FUNCTIONS row claiming more is refused rather than
addressed with a truncated PC. That keeps 0xffff outside the PC space, which
is what lets it mean no disruption handler — a handler that really begins
at pc 0 is an ordinary disruption_pc of 0. name_value is
0xffffffff when the name is stripped, and a table holds at most 0xffffffff
rows, so that sentinel is never a VALUES index either.
stable_id_value, name_value, and every instruction constant operand are
pool-global VALUES indices. The stable id is the mcode function’s own id
qualified by the unit’s source hash
(<source hash>#<mcode function id>) — the unqualified id repeats in every
unit of a pool, and a matching key that collides matches nothing.
stable_function_hash is the target key hash of that same text, so a consumer
holding either can derive the other.
VALUE rows are 16 bytes:
u8 tag
u8 flags
u16 reserved
u32 aux
u64 payload
Tags are:
| Tag | Meaning |
|---|---|
| 1 | complete target-profile immediate value bits in payload |
| 2 | image-relative reference to a target-layout object in STONE; aux is the object kind |
| 3 | function descriptor index in payload |
| 4 | shape descriptor index in payload |
| 5 | logical/null symbol code in payload when the profile does not encode it as an immediate |
VALUES is one pool-global intern table. Byte-equal finalized rows occur once,
irrespective of the unit or function that supplied them; instruction operands
index this table directly. When a relocated index exceeds u16, the linker
inserts wide, rebases every affected branch and function-relative PC, and
duplicates the word’s provenance onto the prefix. The loader never converts
VALUES to a PitValue array. An immediate row already contains the exact target representation. A
STONE reference is resolved by the profile’s image-reference accessor from the
validated placement base plus payload; this constructs only the scalar
reference used by the VM register and performs no allocation or object copy.
STONE contains complete target-layout immutable objects, including object headers, text/blob lengths, text hashes, and bodies. Relations stored inside a STONE object are null, immediates, section indices, or image-relative references as selected by the target profile. They contain no allocator pointers or placement-dependent absolute addresses.
Image text objects carry exactly the text, stone, and canonical-key low-byte header flags. Their capacity equals their length, the unused low half of an odd UTF-32 word is zero, and their cached hash covers that unique packed representation. Record lookup therefore uses them directly and never attempts actor-local interning or an in-place header write. Pool validation rejects any other image-text representation. Empty text is the target profile’s canonical immediate value and therefore does not occupy a STONE object.
A reference into STONE names an object start. STONE is validated once as a complete sequence of objects, and every reference is checked against that sequence rather than against the bytes it points at, so a well-formed object forged inside another object’s body is not addressable.
For the hosted nan64 profile, a relation in a STONE object’s value slot is a
profile-reserved tagged slot-relative relation. Its signed payload is the
displacement from the address of that value slot to the referenced STONE object.
The image-backed object accessor therefore has all required origin information:
it adds the displacement to the slot address and returns the ordinary absolute
heap-reference PitValue used in a VM register. No placement registry and no
load-time relocation are involved. A relation copied into actor heap state is
stored in that ordinary absolute form. The GC recognizes the resulting pointer
as image-backed immutable stone, leaves it in place, and scans dynamic actor
objects normally. A segmented/banked profile defines the equivalent slot-local
bank-and-offset scalar and resolves it through the active MachImageView while
the bank is pinned.
External VALUE STONE_REF rows instead carry an image-relative byte offset;
their accessor resolves placement_base + payload before producing the same
ordinary target-profile register value. Consequently text, blob, record, array,
and shape accessors read STONE/SHAPES directly. No per-load or per-image
materialized constant/object tree is permitted.
A FUNCTION_REF resolves to one immutable FUNCTIONS row in the same image. When
ordinary execution creates a closure, the actor-owned function object stores an
immutable PoolBinding, function index, actor-owned provider-owner reference,
and actor-owned outer frame. The traced owner retains the exact pinned placement
generation and is inherited by nested closures. The binding supplies the
MachImageView and section bases needed to interpret the row’s instruction,
value, child, and PGO ranges. Register dispatch uses the binding and index
directly; it does not construct a PitCodeRegister, PitCode, or per-function
host descriptor. A flat hosted profile may add a resolved
FUNCTIONS-row pointer or VM-owned host-pointer table to PoolBinding; those are
optional dispatch accelerators and are never part of the pool or closure
identity. Banked and segmented profiles retain the same function index and
resolve it through the binding’s active placement.
An opened pool whose profile matches the running runtime is directly executable.
The provider keeps its placement pinned, image-backed object accessors preserve
STONE references, GC leaves those immutable placements in place, actor closures
retain their binding and function index, and the ordinary Mach dispatch loop
reads FUNCTIONS, INSTRUCTIONS, VALUES, and FUNCTION_REFS from the validated
views. The hosted nan64/UTF-32 Mach ABI uses
stone.text: "canonical-fash64-v1" and validates STONE as a complete sequence
of canonical packed UTF-32 immutable text objects with finalized FASH64 hashes.
Each additional object/profile arm supplies a complete Mach-ABI artifact,
structural validator, and accessor.
Text and shape-key hashes are finalized into immutable table data. The target
profile defines the hash width and interpretation selected by aux and by the
STONE object ABI.
SHAPE rows are 24 bytes:
u32 reserved # zero
u32 key_count
u64 canonical_shape_hash
i64 key_rows_relative # from this row's own address
SHAPE_KEY rows are 16 bytes:
i64 text_relative # from this row's own address; 0 is the empty key
u64 target_key_hash
Both are displacements, not indices, and that is what makes a shape a stone
object like any other. A shaped record holds a bare pointer to its SHAPE row —
building the record is a pointer store and reading a field is an index — so
everything the row can say must be reachable from that pointer alone. A
displacement is; an index is not, because resolving one would mean carrying the
pool base alongside every record. Each displacement is measured from the address
of the row that carries it: key_rows_relative reaches that shape’s first
SHAPE_KEY, and text_relative reaches that key’s STONE text. This is the same
self-relative convention STONE already uses for a relation in an object’s value
slot.
A SHAPE row is therefore the runtime’s whole record-shape descriptor. There is no second, runtime-side shape kind and no shape table: a record either points at a shape or it does not, and adding or deleting a key drops the pointer and degrades the record to an ordinary keyed one. Descriptors the runtime builds for code it did not map — a decoded Mach unit’s declared shapes — are the same 24 byte row followed by the same key rows, so one accessor reads both.
A row’s key rows are contiguous and in dense value order, and the key rows of
the shapes in one image are contiguous and in shape order, which is what lets
the reader validate SHAPE_KEYS in a single pass with no allocation. Empty text
occupies no STONE object, so a text_relative of zero names the target
profile’s canonical empty text rather than an address.
IMPORT rows are 24 bytes:
u32 importing_unit
u32 import_id
u32 expected_kind
u32 flags
u64 stable_binding_key
expected_kind is 1 for a module-result import. stable_binding_key is the
target profile’s precomputed 64-bit key hash of the portable mcode import
request. The import ID is the dense ID from that mcode unit.
importing_unit is the importer’s executable-local unit id — the same
number an ENTRIES row’s unit_instance carries and the same one an
instances[] row names — not this pool’s row index, which disambiguates
nothing once an executable is covered by more than one pool.
The realization maps each IMPORT row to an image and entry. References within one pool are final indices and require no binding rows.
PGO_SITE rows are 16 bytes:
u32 function_index
u32 pc
u32 kind
u32 counter_index
pc is function-relative, like entry_pc, and a row whose pc reaches its
function’s instruction_count is refused. Rows are grouped by function and
ordered exactly as that function’s instrumented sites appear, so a function’s
range is first_pgo_site .. first_pgo_site + pgo_site_count and a site’s own
ordinal within the function indexes into it. Counters are allocated per actor
from the highest counter index plus one.
A pool carries site coordinates and no site identity. What names a site —
the mcode unit, function, and site ID — comes from the
origin map, which is a sidecar precisely so a shipped pool
does not carry debug information. A drained counter is turned back into an
identity by joining (function_index, pc) against that map, which is also how a
stopped frame resolves; one mechanism serves both. See
PGO profile.
Pool derivation
K_pool = hash(
ordered mcode hashes and unit-instance bindings,
link options,
complete target-profile hash,
Mach ABI/backend hash,
finalizer/toolchain hashes,
finalization flags,
consumed PGO hashes
)
K_pool -> pool content hash
For today’s ordinary one-unit pool, ordered mcode hashes and unit-instance bindings reduces to that unit’s mcode content hash and its source locator (the
locator identifies the debug/origin sidecars emitted beside the pool). The
shop records this specialization in the same derivation catalogue used for
portable mcode: the pool key maps to the already-stored pool content hash.
Content-addressing the output alone is insufficient, because the output hash
is not known until after the expensive finalization it is meant to avoid.
The ordinary one-unit entry excludes PGO output. PGO finalization uses the full key above, including the selected profile, executable-wide site budget, semantic executable identity, and consumed observations.
Mach pool fragment
Pool emission has two stages inside one pit tool: a lowering stage that
decides meaning, and a linking stage that decides placement. What a
constant is — a number’s exact bit pattern, a text object’s header, hash and
packing, which record shape a construction site names — is target knowledge
the lowering reads from the target profile record; where it lands in the pool
is the linker’s. pit.mach.fragment@1 is how one lowered unit crosses that
border.
It is an internal handoff, not a stored artifact: it never leaves the process that produced it, has no content hash and no catalog entry, and the linker is its only reader. It is specified here because it is the border between the two stages of pool emission.
{
schema: "pit.mach.fragment@1",
endian: 1, // 1 little, 2 big — the order of every scalar below
abi: "mach-v4+fuse1", // opcode set + fusion table + global VALUES
profile: "host-nan64-v1;value=64;rep=nan64;...", // complete target profile
object_align: 8, // STONE object alignment
text_object_kind: 4, // the object kind a STONE text reference declares
instructions: <blob>, // final u32 words, every function concatenated
origin: <blob>, // u32 per instruction word
shape_relocs: <blob>, // u32 instruction indices
import_relocs: <blob>, // u32 instruction indices
import_op_local: 144, // opcode for a same-image edge
import_op_bound: 145, // opcode for a cross-image edge
wide_op: 146, // WIDE opcode, supplied by the lowering
shapes: [["alpha", "beta"], ...], // key texts, unit-local ordinal order
functions: [
{
mcode_index: 0, // 0 is the unit's `main`, k its `functions[k-1]`
name: "f" | null,
arity: 0, close_slots: 0, frame_slots: 10,
entry_pc: 0, disruption_pc: 65535, abi_flags: 0,
first_instruction: 0, instruction_count: 42,
values: [ <row>, ... ], // this function's cpool, in cpool order
value_relocs: <blob>, // triples: logical start, base, local K
branch_relocs: <blob>, // triples: base, target, branch kind
children: [ <fragment function index>, ... ],
pgo_sites: [ {pc: 7, semantic_pc: 3, kind: 1}, ... ] // absent when none
}, ...
]
}
pgo_sites is present only on an instrumented lowering, and its ORDER is
load-bearing: the third word of an instrumented site’s region carries that
site’s ordinal within its own function, so the link writes the function’s
PGO_SITES base beside it rather than rewriting the instruction. pc is
function-relative in the fragment; the linker rebases it if constant widening
inserts a word before the site.
Functions are in canonical preorder from the unit’s main, each appearing
once: a function two closures reach is one row that two references name.
A value row is one of:
{tag: 1, bits: <blob>} // eight bytes, the payload field's exact content
{tag: 2, text: "..."} // a STONE text object
{tag: 4, shape: 0} // a record shape, by unit-local ordinal
Everything in a row is final except the payload of tags 2 and 4, which name things the layout has not placed yet. A tag-1 row is already the target’s own value bits; a literal the running representation cannot hold as an immediate arrives as the target’s null, because that is what the target would say.
instructions are target-final words with fusion applied, but their constant
indices are not placement-final. value_relocs names each logical instruction
start, the physical base word that owns Bx, and the function-local cpool slot
the lowering wrote there. The linker interns finalized rows into pool-global
VALUES, rewrites the operand, and uses wide_op when the global index exceeds
u16. branch_relocs names every branch base, target, and displacement kind so
the linker can repair control flow after those insertions without learning an
opcode. It rebases entry_pc, disruption_pc, PGO site PCs, instruction bases,
and the origin column in the same pass.
Every current-ABI constant-bearing instruction is therefore representable as iABx. In particular, REGEXP literals are normalized by the lowering into two LOADK instructions feeding scratch registers; REGEXP itself takes those registers in B/C. The predecessor bridge alone recognizes the old B/C-as-local- constant encoding.
Record shapes remain a separate pool-global operand class: the lowering writes
a unit-local ordinal for newrecord_shaped, lists the instruction index in
shape_relocs, and the linker adds the unit’s SHAPES base. A tag-4 value row is
the same relocation in VALUES.
import_relocs names the other placement-owned operand class. An
import instruction (see Mcode) lowers to one word whose Bx still
holds the unit’s own dense import id, because only the covering knows whether
the provider ended up in the same image. The link rewrites the word’s opcode
AND its Bx from the covering’s decision: a same-image edge becomes
import_op_local with the provider’s executable-local unit id, which the
running actor’s instance base turns into a slot of its own result array, and
no IMPORT row is written for it at all; a cross-image edge becomes
import_op_bound with the pool-local IMPORTS-row index, and the row carries
the importer’s executable-local unit id, the dense import id, and the
precomputed binding key. An import site the covering does not decide is
refused rather than defaulted — a guessed edge would produce a pool that only
fails once an actor runs it.
The two opcode numbers ride in the fragment for the same reason the constant bytes do: the linker must be able to write them without knowing what they mean. It never decodes an instruction, and this file’s opcode set stays the lowering’s.
origin is the provenance column: for each instruction word, the index of the
mcode instruction that produced it, or 0xffffffff where none did. Joined with
the unit’s own sites and spans it is the whole of the pool origin map, and
it is the only thing in a fragment that exists for debugging rather than for
the bytes.
The lowering spells “no disruption handler” as pc 0, because a handler never
begins there; a pool spells it 0xffff so that pc 0 stays a real position. The
fragment carries the pool’s spelling.
Stone object bytes are not in the fragment. The linker asks the lowering for them one text at a time, because some of the texts it must place are its own — a function’s stable id qualifies the mcode id with the unit’s source hash, and no lowering could have produced that. One accessor, one authority: Pit never constructs an object header.
One producer, many profiles
A pool has one writer: the pit emitter. It consumes fragments — N units, cross-unit stone deduplication, import finalization from a covering, every unit’s functions, instructions and shapes renumbered onto pool-global bases — and every target fact it writes comes from the profile record it was handed. The same emitter presses a pool for the running machine, for a console, or for the next Mach ABI; a foreign profile is an argument, not a variant of the tool.
The reader is the authority on correctness. A pool’s structure is checked by the target runtime’s validator at open, and the gate that keeps writer and reader agreeing is behavioral: every profile arm the build system knows boots a fixture pool pressed by the emitter for that arm. A profile whose fixture boots is a profile the emitter speaks.
Every pool stamps three identities, which is why a pool is never ABI-neutral: the target-profile hash, the Mach-ABI hash, and a finalizer hash naming the format’s writer version. A pool is executable exactly by a runtime whose stamps match and refused by every other — see Target Profiles.
The emitter writes the byte order the profile declares — a big-endian pool for a big-endian profile — as it does every other axis: endianness is one more field of the record, not a capability boundary.
Pool origin map
pit.mach.origin@2 stores the compact target-final-PC to portable-mcode
column needed to recover source lazily:
{
schema: "pit.mach.origin@2",
pool_hash: "blake2:...",
content_hash: "blake2:...",
link_derivation_hash: "blake2:...",
target_profile_hash: "blake2:...",
functions: [
{
index: 0,
pc_count: 3,
unit: 0,
mcode_hash: "blake2:...",
function_index: 0,
origins: [0, 0, 1],
inline_chains: []
}
]
}
Function rows are sorted by final pool function index. Each origins element
is the integer mcode PC behind the corresponding final pool PC; its length is
exactly pc_count. The row’s mcode_hash selects the portable unit and
function_index selects its function. At first symbolication,
debug_resolve joins those integers to the unit’s sites and spans, coalesces
equal adjacent PCs into the same range shape legacy readers observed, and
caches the joined ranges in memory. A missing site stays a hole rather than
being guessed.
inline_chains reserves a parallel optional column for future inline-chain
records. It is empty today. Stripped products omit the whole sidecar while
retaining the exact pool hash needed to retrieve it elsewhere. Readers also
accept legacy pit.mach.origin@1 objects whose expanded ranges contain the
already-joined function/site/span records.
Two hashes name the pool, and a debugger needs both. pool_hash is the
store address — how the map is fetched. content_hash is the pmp1 header’s
own field, computed over the pool with that field zeroed — how the map is
matched to a running frame. A frame reaches its binding’s MachImageView and
nothing else, and the view carries the header field rather than the store
address, so content_hash is the only one of the two a live frame can name.
$inspect reports it as the frame’s image_hash; selecting the right map for a
frame is then a comparison rather than a guess, which matters because function
indices are dense and pool-local — the wrong map does not fail to resolve, it
resolves to a confident lie.
PGO profile
pit.pgo.profile@1 stores observations in portable mcode identity:
{
schema: "pit.pgo.profile",
schema_version: 1,
semantic_hash: "blake2:...",
compiler_salt: "...",
content_hash: "blake2:...",
dropped_sites: 0,
dropped_targets: 0,
observations: [
{
site: {mcode: "blake2:...", function: "main", site: "call:0"},
executions: 200,
immediate_failures: 0,
targets: [{identity: "RSF...", count: 200}]
}
]
}
A site is named by mcode identity and nothing else: the unit’s source hash,
the mcode function id, and the mcode site ID — the stable <op>:<ordinal>
name every instruction carrying a source position already has (see
Mcode sites). It is deliberately not an instruction index: a pc
belongs to one lowering of one unit, and the origin map —
which is what turns a pool’s own coordinates back into mcode — yields the site
ID rather than the index. One identity therefore serves both the register and
the pool lane, and a profile outlives the pool it was gathered from.
The kind of observation a row carries is implied by its evidence rather than
named in the key: a site is one instruction, and one instruction has exactly one
kind. targets holds the bounded top-k of observed targets, each an opaque
identity string whose meaning belongs to the observation kind (for record-field
loads, the shape-field identity); immediate_failures counts executions that
reached the site but produced no target.
Observation rows are sorted by their site identity, and content_hash covers the
sorted whole — so two profiles of the same run agree byte for byte regardless of
the order observations were drained in. The originating pool, target profile,
executable, and workload remain provenance. Consuming a PGO profile changes
K_pool; it does not mutate or re-identify mcode.
Native image descriptor
Native image bytes use the platform’s object or executable format. Their store
row is accompanied by pit.native.image@1:
{
schema: "pit.native.image@1",
bytes: "blake2:...",
target_profile: "blake2:...",
abi: "blake2:...",
toolchain: {compiler: "blake2:...", sdk: "blake2:...", linker: "blake2:..."},
entries: [{unit: 7, entry: 0, symbol: "pit_entry_..."}],
link_derivation: "blake2:..."
}
The native derivation includes the ordered mcode/bindings, link flags, complete profile and ABI, compiler/SDK/linker/runtime-ABI identities, and consumed PGO.
Catalog rows
A catalog row resolves a locator to exactly one object hash. There is no per-target variant dimension: mcode is the only shared artifact, a Mach pool is host-final and never crosses a machine boundary, and a machine that must lower its own Mach cannot consume another machine’s realized executable. One bundle therefore describes one target, and a multi-target product is several bundles.
An entry that is not an object hash is refused by name at every reader rather than read past.
Target realization
pit.target.realization@1 makes one executable startable on one complete
profile through exactly one execution form.
{
schema: "pit.target.realization@1",
executable: "blake2:...",
derivation: {
schema: "pit.resident.derivation@1",
source_closure: "blake2:..."
},
target_profile: "blake2:...",
execution: {form: "mach"},
provider_registry: "blake2:...",
images: [
{id: 0, kind: "pit.mach.pool@1", hash: "blake2:...",
target_profile: "blake2:...", mach_abi: "blake2:...", entry: 0},
{id: 1, kind: "pit.mach.pool@1", hash: "blake2:...",
target_profile: "blake2:...", mach_abi: "blake2:...", entry: 0}
],
bindings: [],
extension_bindings: [],
instances: [
{id: 0, executable: 0, unit: 0, image: 0, entry: 0},
{id: 1, executable: 0, unit: 1, image: 0, entry: 1},
{id: 2, executable: 1, unit: 0, image: 1, entry: 0}
],
executables: [
{
id: 0,
kind: "main",
manifest: "blake2:...",
images: [0],
instances: [0, 1],
initialization: [1, 0],
root: {unit: 0, instance: 0, image: 0, entry: 0}
},
{
id: 1,
kind: "provider-adapter",
manifest: "blake2:...",
images: [1],
instances: [2],
initialization: [2],
root: {unit: 0, instance: 2, image: 1, entry: 0},
provider: {
registry_row: "blake2:...",
endowment: "$hook",
private_binding: "$provider",
abi_hash: "blake2:..."
},
selected: {unit: 0, instance: 2, image: 1, entry: 0}
}
],
start: {
executables: [1, 0],
engine_claims: "blake2:...",
root: 0,
trim: ["$bootstrap"]
},
claims_hash: "blake2:...",
limits: {heap_bytes: 4194304}
}
derivation.source_closure equals executable; it is repeated as a typed
handoff because a boot resident is carried without requiring the manifest object to be
decoded before startup. The manifest hash covers the selected source closure and the
target-neutral compiler flags through its unit mcode hashes. A boot-time freshness check
compares this field, not the target-realization cache key: changing only profile, pool
grouping, or payload form produces another realization of the same current source.
Image IDs, executable IDs, and global instance IDs are dense deterministic
indices. Every executable retains its own dense local unit namespace;
executables[].instances[local_unit] maps it into the actor’s one realization-
state array. Every instance is unique across the main executable and every
adapter closure. instance.entry and provider_entry are
indices into the selected image’s ENTRIES table. A binding row’s import is
the selected image’s IMPORTS-row index; that row retains the portable
(importing_unit, import_id) pair. This keeps fused images unambiguous when
several units each declare dense import ID zero. Binding rows are sorted by
(image, import).
Each kind: "provider-adapter" executable agrees with one adapted provider-
registry row through provider.registry_row. Its manifest is the exact
portable adapter-manifest identity. instances maps the complete adapter
closure’s local unit IDs to finalized image entries and global actor-state
slots. The exact adapter manifest supplies its precomputed initialization
order, root, imports, and claims. The registry’s selected adapter.unit
resolves through selected to the public endowment’s result slot.
start.executables lists every adapter executable before executable zero, the
main executable. Adapter images participate in the realization’s one ordered
image set.
limits are the limits policy granted when this realization was built, and are
part of realization identity. Startup and every privileged runtime operation
consume them. The realization’s exact provider registry names the same permanent
provider catalog as profile.providers.
A realization is meant to be explicit enough that starting is following rows. Anything a runner would otherwise have to work out — which name gets which value, which slot a unit’s result goes in — belongs here instead.
What the shop produces today
The shop’s realize step already produces a pit.target.realization@1 for every
build, and it is the only executable-shaped record in the system: the mixed
pit.executable@1 that fused logical identity with one way of running is gone,
with no reader for it anywhere. The record agrees with the schema above on its
load-bearing vocabulary and states the rest in plain fields, because the parts
of this section it does not yet reach are unbuilt mechanism rather than a
disagreement about shape:
| carried today | says |
|---|---|
executable | the pit.executable.manifest@1 content hash. This is the identity of the logical program, exactly as above |
execution | {form: "mach" | "mcode" | "mixed"} — which payloads the realization’s module rows carry. mach carries pressed pools, mcode carries portable units, mixed carries both |
identity | the realization’s OWN key, folding the manifest hash over everything that varies the run. Two realizations of one executable are two records naming one executable |
modules | one row per unit, naming its mach and/or mcode payload by content hash, with that unit’s static bindings |
module_order | the initialization order, as locators |
form names the payload a realization ships, not a second way of running one.
There is one execution lane: an actor runs a pit.mach.pool@1 and nothing
else. A module row carrying a portable unit is pressed to a pool on the way to
running — the same press any other unit takes, run at start instead of at build
— which is what lets an mcode payload cross a generation that has no pool it
can mount.
images, instances, bindings and executables are not produced yet: a
realization covers its units with one payload each rather than with mach pools,
so there is no image set to index and no cross-image import to bind. start,
provider_registry and claims_hash wait on the same mechanism. Those rows are
the target and this section stays their statement; nothing writes them today,
and nothing reads a field this list does not name.
The manifest is a separately stored artifact and the realization holds only
its hash. Building a manifest and storing it are one act — the builder writes
the exact canonical bytes it hashed into the object store, so executable is
the address of an object that exists by the time the hash does. Nothing carries
a copy: the publish closure walks the reference like any other, and a cart’s
executable record names its manifest rather than repeating it.
Two hashes name a realization, and they answer different questions. identity.hash
is the shop’s build-cache key: it folds everything that varies the run over the
manifest hash, and it is computable before the record exists, which is what
makes it a cache key at all. The realization’s store identity is the blake2
of its stored bytes, knowable only after it is written. The shop’s own
pit.realize.entry cache record carries both, and the catalog maps the first to
the second. That entry is the shop’s host-local record of one realization — not
an artifact format in its own right — and it is deliberately named apart from
pit.target.realization@1 so the two are never read for each other.
One divergence is deliberate and belongs to named later work: the realization
carries no target_profile. The profile is folded into the shop’s realization
cache key and reaches the record only through the payload hashes it names, which
is enough to keep two profiles apart but is not the explicit row this section
asks for.
pit.target.start@1 is the transient packet a runner consumes. It carries the
realization, profile, Mach ABI, provider registry, and backend-local placements —
and nothing a runner does not read. It carries no policy artifacts: the decision
was made when the program was built and is not re-examined here.
It still carries one canonical manifests array indexed by realization
executable ID, entry zero being the main executable, because per-unit binding
rows currently live in the manifests. Once those rows move into the realization
the array goes away, and no manifest travels at start:
{
schema: "pit.target.start@1",
manifests: [
{hash: "blake2:...", bytes: ..., manifest: {...}},
{hash: "blake2:...", bytes: ..., manifest: {...}}
],
realization: {hash: "blake2:...", bytes: ..., realization: {...}},
profile: {hash: "blake2:...", bytes: ..., profile: {...}},
mach_abi: {hash: "blake2:...", bytes: ..., mach_abi: {...}},
provider_registry: {hash: "blake2:...", bytes: ..., registry: {...}},
placements: [{image: 0, path: "..."}],
extension_placements: []
}
Every manifest artifact hash is the content hash of its canonical bytes and
equals the corresponding executables[].manifest. Each manifest’s
initialization, root, claims, and unit closure agree with that executable row.
The producer establishes those agreements; a runner does not re-derive them.
It follows start.executables, initializes adapter closures before the main
executable, and stores all returned module values in the same actor-owned
realization-state array. A runner has exactly two callers — the shop, which
constructed the realization, and the C floor at cold boot, which mounts a
medium trusted by ruling — so re-checking here establishes nothing while
costing every actor start.
Image-provider runtime interface
The provider reaches pit as $image, an ordinary claimable, deniable
endowment. It is held by boot; a pool’s bytes are ordinary store content
anyone may read, and what $image gates is executable placement. See
The Executable as an Array.
Provider handles are opaque runtime values and are never serialized as durable identity. Every operation is synchronous and takes one record: these are address-space operations with no waiting in them, so the requestor shape a callback implies would be a lie about what happens. The interface is:
authorize({realization, manifests?, profile?, provider_registry?})
-> authorization
open({path, hash, target_profile, mach_abi, limits?, authorization})
-> image_handle
pin(image_handle) -> pin_handle
binding({pin, realization?, image?, limits?, authorization}) -> binding_handle
bind({binding, import, provider_binding, provider_entry, provider_instance,
limits?, authorization})
bind_value({binding, import, provider, limits?, authorization})
entry({binding, owner, entry, unit, limits?, authorization}) -> initializer
unpin(pin_handle)
close(image_handle)
pinned() -> count
authorize takes the realization a runner was handed and returns an opaque
authorization value. Image open, binding, cross-image bind, entry lookup, and
provider acquisition require that value; source code cannot construct or select
it, which is what keeps image references unforgeable. It re-decides nothing —
the value marks that these operations came from a realization rather than from
ordinary data. The token is a value of a runtime class the language has no
constructor for, so a record shaped like one is refused; the realization it was
minted from rides on it as a traced property.
pin, unpin and close take a handle and no authorization: a pin can only be
taken over a handle an authorized open already produced.
open’s path is the physical placement identity, not a content name.
Byte-identical pools at two paths are two placements and pin independently,
because placement is about address space and content is about identity. A cart
or ROM window adopts a resident range through the same seam without a path.
The start walk uses that seam directly. A cartridge CODE window that holds a
finalized pool is already resident — mapped, or laid out in RAM — so the walker
adopts it where it lies, takes the binding’s pin, and resolves the entry, in one
step and with no file. It carries no authorization because it requests nothing:
the caller is a runner following a plan the cartridge already committed to,
which is the same authority the engine window is loaded under. What it does
carry is this runtime’s own profile and Mach-ABI identity, compared against the
pool’s, so a window that this binary cannot interpret is refused at the door
rather than executed. The walker’s result array is the owner the entry
function traces, so the pin lasts exactly as long as any value the pool produced
— the ordinary rule, reached from C.
entry’s owner is the actor’s realization state — [binding, results, instance base] — and it is the array the returned function traces. bind_value binds an
actor-owned module result for a provider the target registry supplies, which is
“provider acquisition” and is gated with the rest.
pinned is a reading, not a lever: the number of distinct placements this
runtime holds pinned. It needs no authorization because it adds no authority to
a holder of $image, who can already pin and unpin. What it adds is that the
eviction rule is observable — the count falling to zero is a placement
being released.
An authorized open validates the content hash, pool header, profile, ABI,
sections, and placement. A pin keeps the complete addressable image placement
alive while an actor can reference it. One validated provider-owned
MachImageView is shared by pins to a placement. One VM-owned PoolBinding
covers that image and the realization binding environment; its storage is
proportional to declared cross-image imports. A binding handle retains its own
pin, and every image function traces that binding owner, so explicit open/pin
tokens may be released without invalidating a live closure. Unit result values,
image-backed stone roots, and PGO counters remain ordinary actor state.
“While an actor can reference it” includes while that actor is being torn down. A record built by pool code lives in the actor’s heap but its shape is a row in the pool’s SHAPES section, so an actor’s heap can only be walked while the mapping is still there. A placement whose last reference goes during a teardown therefore leaves the live set immediately — nothing can open onto it again — and its address space is released once the heap block is gone.
Cartridge v2
pit.cart@2 is the cart format: a fixed header, one nota metadata value, and
pmp1 pool sections at aligned offsets, with a discovery trailer. Two
encodings cover the whole object — nota for everything that is metadata, the
pool format for the one thing that is ABI-specific by nature. C reads the
header by comparison; everything past the header is read by pit.
All header and trailer integers are unsigned little-endian, always. The mounting binary is the target itself, so on a big-endian target the swap is a compile-time-known no-op-or-bswap; a foreign inspector swaps explicitly. (The pool sections inside carry the target byte order as an axis of the stamp, as they always do.)
Fixed header
The header is the whole C↔pit boot ABI and the versioning boundary of the system: these fields are read by a binary that has not yet run any pit, so they are the one place two generations must agree. Everything else in the cart is pit-read and free to change shape.
The header is 256 bytes at offset 0, zero-padded past the last field:
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | ASCII pcr2 |
| 4 | 4 | version | format version, 2 |
| 8 | 8 | total_len | byte length of the whole cart, header through trailer |
| 16 | 128 | profile_stamp | the full profile string, UTF-8, zero-padded; memcmp against the binary’s own PIT_PROFILE_STRING decides mountability |
| 144 | 8 | engine_pool_off | byte offset of the engine’s pmp1 pool section |
| 152 | 8 | engine_pool_len | its byte length |
| 160 | 8 | boot_entry_off | byte offset of the boot entry |
| 168 | 8 | boot_entry_len | its byte length; the entry’s contents belong to the engine, not to this format |
| 176 | 8 | nota_off | byte offset of the metadata nota value |
| 184 | 8 | nota_len | its byte length |
| 192 | 4 | section_align | alignment every pool section offset satisfies; writer default 4096 |
| 196 | 4 | start_flags | the start declaration — what kind of program this cart is (below) |
| 200 | 56 | reserved | zero |
A writer refuses a profile string of 128 bytes or longer rather than truncating — a truncated stamp is a stamp that can collide.
The start declaration
start_flags is how a cart says what its program is. It is read by the
host launcher before any role is chosen and before any pit exists, which is
why it is a header word and not a member of the boot entry: choosing between
“forward my argv to a daemon” and “boot pit here and run to completion”
happens before there is an actor to decode nota into.
Each bit subtracts a default, so start_flags == 0 is the declaration of
the development program — resident, with a shop, with a daemon — and every
cart pressed before this field existed reads as exactly that. Nothing bridges;
the zero is the statement.
| Bit | Name | Set means |
|---|---|---|
0x1 | one_shot | the program boots in this process, runs its root to completion and exits. No daemon is spawned and no argv is forwarded to one. Clear: resident — the client/daemon pair |
0x2 | no_shop | the program has no shop. Nothing is created on disk that the program did not ask for: no shop directory tree, no crash log file, no boot.log. Diagnostics are not lost with the files — the boot trace still reaches stderr. Clear: the launcher resolves and creates a shop |
0x4 | no_daemon | the program neither spawns a daemon nor serves as one. Implied in practice by one_shot, stated separately because “resident but never a daemon” is a real program |
| others | — | reserved, zero |
A launcher that meets a bit it does not know must refuse rather than guess: an unknown bit is a program shape it cannot honour.
The declaration is what the mode used to be inferred from. There is no environment variable, no path convention, and no launcher heuristic behind it; a binary that must behave differently carries a different cart.
Mount refusals are named and ordered: a wrong magic is not a cart (the boot medium moves to its next lane); a right magic with a wrong version, and a right version with a foreign stamp, each refuse by name. A stamp move is crossed before the new binary lands: forge has the predecessor press the new profile. The development snapshot is portable input to that press, not a binary-independent boot lane (see Boot).
Metadata
One nota value at nota_off. It decodes into ordinary pit records once an
actor exists to decode into — nothing in it is needed before that, which is
why the engine pool and boot entry are named by the header directly rather
than through it. It carries the catalog (what can start), the section
directory, and the service/plan records described in
Cartridges.
The section directory addresses every pool section as (offset, length, content hash) rows. Offsets satisfy section_align. On windowed profiles,
placement also keeps every pool wholly inside one image-encoding window; the
contiguous cartridge may span adjacent windows, but a raw pool never does.
Sections do not overlap, and nothing outside the directory addresses a section. A directory
row may carry annotations the writer knows and tooling wants — the module
locator, notably — as additional nota members; readers that only run code
ignore them.
Start plans
The metadata carries one plan per cemented executable: {name, package, params, entries}, where entries is
the executable array as ordinary nota
records. An absent field is the field’s zero, so a writer emits only what it
has to say and a reader defaults the rest.
{kind: 0, flags: 4} // the engine core
{kind: 2, flags: 0, name: "$self", source: 0} // projected out of entry 0
{kind: 1, flags: 3, symbol: "endowment/clock"} // a native provider
{kind: 0, unit: {off: 233472, len: 918016, // a unit of bytecode
hash: <32 bytes>, entry: 7},
imports: [{name: "log", producer: 4}],
names: [{name: "std::stream", flags: 1}]}
A UNIT row’s unit names the pool section to run — off/len are the
section’s own placed coordinates, inline in the row so that running it needs
no directory lookup — and entry names which ENTRIES row of that pool is
this unit. Absent entry is 0.
entry is what lets one section carry a whole program: a cart is one mach
pool per executable, so N plan rows share one {off, len, hash} and differ
only in entry. Splitting a program back across sections — the ROM-window
targets, where a pool must fit a paged window — writes N sections whose rows
each carry entry: 0, and needs no other change. Units-per-pool is the
press’s lever, not a fact of this format.
A unit’s entry is a row index into the pool’s ENTRIES section. It is not the
same number as that entry’s unit_instance, which is the unit’s
executable-local id and therefore its slot in the running actor’s result
array; a LOAD_MODULE_RESULT reads the latter.
Pool sections
Raw pmp1 bytes at their directory offsets, mapped where they lie. The pool
format is specified elsewhere in this page; the cart adds nothing around a
section — no per-section framing, so a mapped section IS the pool.
One section may be named by many plan rows, each with its own entry. The
directory’s per-section locator annotation then names one of the program’s
modules and the exec catalog names them all.
Trailer
The last 16 bytes of the cart:
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 4 | magic | ASCII pcr2 |
| 4 | 4 | version | 2 |
| 8 | 8 | total_len | equals the header’s total_len |
The trailer exists for the appended lane: a cart appended to a binary (with a
content qop appended after it) is discovered by scanning backwards for the
trailer and stepping total_len bytes to the header. A cart read from a file
starts at offset 0 and the trailer is a consistency check.
Bundle v2
pit.bundle@2 is a snapshot of a shop presented as a store manifest plus
content objects in a QOP container:
{
schema: "pit.bundle@2",
manifest: "blake2:...",
roots: ["blake2:..."],
slices: {
player: {objects: ["blake2:..."]},
development: {objects: ["blake2:..."]},
debug: {objects: ["blake2:..."]}
},
signature: {issuer: "...", algorithm: "ed25519", value: "..."}
}
The QOP contains canonical bundle, manifest, and
objects/<algorithm>/<digest> members. Ingest verifies the signed manifest,
checks all local store layers, fetches only missing objects, verifies each
object hash, and activates the catalog atomically after the selected closure is
complete.
Player slices contain realizations, pools/native images, and assets. Development slices can add sources, mcode, compiler inputs, and build metadata. Debug slices add pool-origin maps and source trees.
Value and archive encodings
Wota remains the profile-specific same-runtime value encoding used by actor mailboxes and profile-local bootstrap records. Its scalar widths and byte order come from the complete runtime profile. See Wota.
Nota remains the runtime-independent decimal-shaped interchange encoding. Decimal values cross the API as an exact signed coefficient plus base-10 exponent. See Nota.
QOP remains the indexed member container used by bundles and source package archives. QOP membership does not provide object identity: manifests name each member’s content hash.