Working state — a note taken while the work happens, not a specification. The system as it is meant to be is in Architecture.
docs-vs-system audit — 2026-08-07
Base: dev @ a1057e153c6060a9fb19a8f6d3682d94fe5b0aa9. All 64 pages of docs/
audited, complete claim inventory per page (not a sample). Machine ledger:
plans/audit/2026-08-07-docs-ledger.json.
| count | |
|---|---|
| pages | 64 |
| claims | 1316 |
| MATCHES | 1095 |
| CONTRADICTS | 75 |
| OVERREACH | 12 |
| STALE | 28 |
| ruled-but-unbuilt | 89 |
| UNVERIFIED | 17 |
| docs self-contradictions | 18 (12 real, 6 wording) |
docs/ is target-final by doctrine, so ruled-but-unbuilt is expected state
and is listed in §e for the ledger, not as an alarm. The 115 items in §b–§d are
the ones that need a ruling.
18 behavioural probes were collected; 15 ran. Probe verdicts were folded into the
claim verdicts they settle: no claim verdict changed — 5 probes confirmed a
MATCHES live, 4 confirmed a DIVERGES live, 6 came back inconclusive, 3 were not
runnable. Per-probe detail is in the ledger’s probes.results.
Read these five first
- §a-1 — nothing is checked at start / everything is checked at start. The
security track’s headline invariant is denied by four pages and by
spec/executables.mdnine lines below its own statement of it. This is the authority model, and no page states the reconciliation. - §b arch-core-47 — the policy default is fail-open, not default-deny.
capabilities.md:129says a configuration naming nothing grants nothing.pit-shop/policy.ce:194-200returns{granted: array(ALL_ENDOWMENTS)}whendefaults.endowmentsis null, behind one log line. The doc states the opposite of the code on the one sentence a reader hardening a shop acts on. - §b arch-targets-57 — the linker does the three things the pipeline page says
it does not.
pipeline.md:63-69: the program link “does not run streamline again, inline across units, remove guards”.pit-linker/mcode_link.cm:1-12and:2288-2345re-run the full streamline pipeline per linked unit, compact the proven guard ladder, and copy provider bodies across units under the link plan’s inline budget. The code says so in its own banner. - §b arch-debug-7 / arch-debug-11 —
$inspecthas neither the scoping nor the non-blocking property the debugging page sells. There is no token scoping and no ownership test (std_endowments/inspect.c:253-276reaches any actor by bare id), applying it to your own actor is refused rather than “looks at that actor”, and 9 of its 13 calls take an unconditionalsys_rmutex_lockon the debuggee’s turn mutex. - §b library-40 —
crypto.sharedis documented with its arguments reversed.crypto.md:73showscrypto.shared(my_secret, their_public);shoplib/crypto.c:88-99reads arg0 as the public key and arg1 as the private one. Both are 256-bit blobs, so following the doc produces a wrong shared secret silently. Same page:crypto.keypair()returns{public, private}, not{secret, public}, andcrypto.verifytakes(signature, public, message).
Runners-up: arch-debug-86 (a process-wide intern table is live, and
source/pit_text.h asserts the doc’s sentence verbatim then declares the table
two lines later); library-93 (the entire time constants table is unreachable —
pitlib/time.cm never returns the record it sets them on); arch-core-102 /
§a-3 (empty c_native grants C to every package, which the glossary calls
impossible).
a. Docs self-contradictions
Doc-vs-doc only. Every cited line was read in the doc text.
Real (12)
a-1. Is anything checked when an actor starts?
spec/executables.md:145 “Nothing is checked when an actor starts; a start
executes a plan that was already decided” — echoed by capabilities.md:22-25
(“no second decision at start”) and security.md:107-111 (“The gate is
compilation, not start”).
Against: spec/executables.md:154 “At start, the shop confirms the running
runtime can supply each one”; debugging.md:19-21 “A claim with no provider in
the running binary is an error when the actor starts”; extensions.md:241
“actor startup fails and names the missing endowment”; language/actors.md:124-131
“Endowments are fulfilled at actor spawn, not baked into a module at build
time … a spawn-time error”.
A reconciliation exists — policy decided at build, provider presence confirmed at
start — but no page says it. As written, one set of pages promises no start-time
failure mode and the other documents one.
a-2. What fields make up “the complete target profile”.
spec/artifact-formats.md:126-142: pit.target.profile@1 carries scheduler
and providers, no wota, “passed and hashed as one value”.
Against: recipes.md:95-112 — stamp axes are exactly value/rep/endian/text/
record/gc/wota, and “sched is a build lever, not a stamp axis” because
stamping it would “refuse byte-identical pools over an axis that never touches
bytes”; target-profiles.md:55-58 same. glossary.md:34-37 gives a third field
set (adds wota width and Mach ABI, drops scheduler and providers).
If glossary.md:39 is right that the stamp is the profile’s canonical hash, then
hashing the record hashes the scheduler mode — the exact false fork the rule
exists to prevent.
a-3. Does an empty c_native list permit everything or nothing?
extensions.md:31-32 “a package on neither list compiles nothing. Absence is
never permission” (same at c-build.md:151, glossary.md:174-175).
Against: shop.md:195-196 “The current empty list means all packages may compile
C”; endowments.md:267-268; security.md:54-55.
An empty list is absence and it grants C to everyone. The security page and the
glossary hand a reader opposite defaults. (Code agrees with the permissive
spelling — shoplib/recipe.cm:87, shop_source.cm:1972; see arch-core-102.)
a-4. How many fields package.json has.
packages.md:38 “The manifest has three fields and no others”; identical closed
lists at packages-and-distribution.md:15-26 (“That is the whole of it”) and
c-build.md:72-73.
Against: recipes.md:202-215 documents a fourth, requirements, with a worked
n64 example carrying a nested provides.
(packages-and-distribution.md:24 also denies natives by name; that half is
docs-vs-code, §b arch-targets-67.)
a-5. Whether use('fetch') resolves the fetch package.
library/io.md:236-241 “Fetch is another explicit package” followed by
def fetch = use('fetch').
Against: shop.md:133-136 “A bare single-segment import like use('fetch')
is a path … it never means "the fetch package". The fix is to qualify the
import, use('fetch::fetch')” — verbatim repeat at packages.md:154-157.
The library page’s example is the literal counterexample the shop pages use, same
package, same call. io.md qualifies its three other packages correctly
(net::network_info, process::process, pit-watch::watch); only fetch is
spelled the forbidden way.
a-6. Who sets the slow-strike threshold and what it does.
language/running.md:61,67-70 “After enough strikes the runtime may remove
the actor … Both the threshold and what happens at it are settable — per actor,
and differently for guest actors than for your own”.
Against: recipes.md:152-163 — slow_strikes is a recipe budget belonging “to a
target rather than to the code”; actors-and-memory.md:126-128 and
glossary.md:132-135 “at the strike limit the actor is halted”, flat, no per-actor
variation and no “may”. shop/compilation.md:286-293 frames it as a shop-ship
choice — a third granularity.
a-7. Which hash keys the origin map.
debugging.md:328 “It is keyed by the pool’s content hash”, :357 “Because
the map is addressed by the pool hash”, :373 exports <pool-hash>.origin — two
names for one key.
Against: spec/artifact-formats.md:1545-1552 “Two hashes name the pool, and a
debugger needs both … content_hash is the only one of the two a live frame can
name.”
Taken literally, pit debug symbols export names files by the store address while
a stopped frame can only produce the header field, so the documented --actor
export path would not find its own map. (Code sides with the spec — §b arch-core-124.)
a-8. Whether pit cement exists.
spec/pipeline.md:119-121 “pit.bare, appendable boot tails, boot/boot.cart,
and cement as a separate producer do not exist in this lane”.
Against: boot.md:73 “The producer is pit cement”;
build-and-artifacts.md:190 “pit cement --product presses the cart”;
shop/compilation.md:152 “pit cement presses a cart and pit forge embeds it”.
The hedge “in this lane” lists cement beside two things that exist nowhere.
a-9. Whether a cart is ever appended to a binary.
c-build.md:322 “There is no pit.bare, append step, repack target, or runtime
file lookup for boot bytes”; spec/pipeline.md:120 likewise.
Against: spec/artifact-formats.md:2065-2068 “The trailer exists for the appended
lane: a cart appended to a binary … is discovered by scanning backwards for the
trailer”; architecture/pipeline.md:129 repeats it.
16 bytes of every cart are reserved for a lane two pages say was abolished.
a-10. Whether name/log stripping is built.
build-and-artifacts.md:217-221 — stripping is one of the two things that
distinguish a product press.
Against: build-and-artifacts.md:258-259, forty lines later on the same page:
“general outlining and selective name/log stripping are not yet built.”
shop/compilation.md:194-199 (stripped by default, --no-strip opts out) and
spec/artifact-formats.md:576-611 both specify it as operative. Line 259 is a
status note that survived into a positive-voice, target-final tree.
a-11. Whether a month in a time record counts from 0 or 1.
library/time.md:60 “month counts from 0, so January is 0”, with :57
showing month: 0 for January 15.
Against: :96 time.number({year: 2024, month: 1, day: 15}) and :113
time.record(1702656000) // {year: 2024, month: 1, day: 15, ...} — the same
running January-15 example with month: 1, which under the page’s own rule is
February. Same page, and the two conversion functions are exactly where the base
matters. :104/:149 also use token MM, absent from the token table at :78.
a-12. Whether random.random_fit() respects the target’s fit width.
library/random.md:22-23 “Returns a random 53-bit whole number, from 0 … to
9007199254740991”.
Against: language/semantics.md:60-70 “The range is chosen per target … Write
against is_fit rather than a constant”; glossary.md:83-85 “The range is
target-selected”.
The function is named for fit and pins the range to the one constant the
language pages say never to write down. On the nan32 profiles at
spec/values.md:92-97, 9007199254740991 is not a fit number at all.
Wording (6)
a-13. Whether a runtime constant pool exists. spec/stone.md:10 “There is no
runtime constant pool and no intern table” vs actors-and-memory.md:29-36, which
names “the runtime stone pool” as one of exactly three regions a value may
live in (repeated at overview.md:91-93). Substance agrees (fixed, never grows);
the flat sentence denies a region the architecture track counts.
a-14. Whether pit interns values. actors-and-memory.md:92 “There is no
interning anywhere” (also pipeline.md:100, spec/gc.md:115) vs
spec/artifact-formats.md:1160 “VALUES is one pool-global intern table” and
build-and-artifacts.md:111 the linker “interns finalized VALUES pool-wide”. Two
senses of one verb, neither page marking its scope. (Separately, the runtime half
is false — §b arch-debug-86.)
a-15. What over-application of a function does. language/functions.md:131
“Passing more arguments than the function accepts halts” vs
language/syntax.md:328-330 “disrupts; when the compiler can prove the call
over-applies, it refuses the compile”. “Halt” is a defined term for actor death at
the strike limit (glossary.md:132-135).
a-16. Which failures disrupt and which yield null. glossary.md:88-90
“operands are the wrong kind of thing disrupts … Arithmetic that has no answer
yields null” vs semantics.md:20-24 arithmetic “never disrupts … equally when
an operand was not a number in the first place”, with 2 + "x" // null. The
glossary inverts the concrete case semantics.md leads with. (Code sides with
neither cleanly — §b language-65.)
a-17. Whether Mach bytecode is a 1:1 encoding of mcode. spec/mcode.md:8 “a
direct binary encoding of these same instructions” vs
spec/artifact-formats.md:1423 “target-final words with fusion applied” (ABI
string mach-v4+fuse1) and debugging.md:148-153 naming a fused
compare-and-branch superinstruction as ordinary. Fusion means the lowering is not
an encoding.
a-18. Whether time_limit is a global or an endowment. boot.md:342 lists
“fallback, parallel, race, sequence and time_limit” as five modules,
all spelled without $, vs language/parallelism.md:10 “$time_limit is an
endowment, because granting a deadline is granting access to time” and
endowments.md:369-372. Mechanically compatible, but boot.md drops the sigil on
the one member of the five that is deniable.
b. CONTRADICTS — the system actively does something else (75)
Architecture — principles, capabilities, providers, assets
arch-core-15 · architecture/principles.md:33-36 · “Every format C reads has
exactly one writer, in pit … every profile arm boots a fixture pool pressed by the
emitter for that arm.” · shoplib/nota.c, source/wota_codec.h,
source/pit_actor.c:404-407, source/mach_pool.c · The only nota encoder in the
tree is C, C both reads and writes wota, and mach_pool_test.c:2039-2043 carries
one emitted fixture (host-nan64-v1); every other arm hits the profile-hash mismatch,
prints “another profile’s - skipped” and returns pass. Probe-confirmed; the
per-profile table mach_pool_profiles[] (source/mach_pool_fixture.h:1702) has no
consumer in the tree.
arch-core-27 · architecture/providers.md:80-83 · the Playdate sound callback
“touches only the provider’s preallocated ring and signals that lane” ·
platform/playdate/playdate_sound.c:175,191 · The callback’s own contract line is
“no Pit calls, allocation, locks, or signal delivery”; the notification is latched
in the ring and the frame lane polls it. The lane name and ring halves are exact.
arch-core-47 · architecture/capabilities.md:129-131 · “A policy configuration
is default-deny — a configuration that names nothing grants nothing” ·
pit-shop/policy.ce:194-200, :69 · A configuration with null defaults.endowments
logs “policy has no default endowments, granting all capabilities” and returns
{granted: array(ALL_ENDOWMENTS)}; the shipped default is endowments: ["*"].
Fail-open. (The ["*"] half was correctly narrowed in plans/rejected-findings.md:18;
the null-defaults arm is a different code path and is not covered by it.)
arch-core-65 · architecture/assets.md:61-68 · “the clerk searches its mounts
in the order they were mounted, and the first hit wins … The cart the runtime booted
from is mounted first, so it wins by default” · shoplib/pitfs.cm:203, :426 · The
probe walk is first-hit (confirmed), but add_mount is replace-on-collision, so for
a named package the last mount wins — which is how a linked working tree shadows
the install. Right outcome, wrong rule.
arch-core-67 · architecture/assets.md:82-92 · “asset locator -> content hash ->
offset, length, alignment, range” · pit-shop/cement.cm:812-814,902 · The only asset
representation is {package, path, bytes} inlined into the cart’s
pit.cart.metadata@2 nota value. No hash, offset, length, alignment or range exists.
arch-core-68 · architecture/assets.md:94-98 · “read by range only when something
asks for them, through the store’s ordinary get_content(hash, range), so a cart full
of art does not have to be resident to be startable” · source/cart_boot.c · No
get_content(hash, range) exists anywhere outside docs; asset bytes sit inside the
metadata value at offset 256, which boot decodes wholesale — a cart full of art
would be resident. Latent: every producer currently writes assets: [].
arch-core-83 · glossary.md:57-61 · entry kind “{value} — a constant the shop
resolved” · pit-shop/cement.cm:92,95,105-107 · Three kinds and no more is confirmed
(ENTRY_UNIT/ENTRY_NATIVE/ENTRY_VALUE), but ENTRY_VALUE is a projection
(“read property name of the result of entry source”); a literal-constant entry has
no representation at all.
arch-core-87 · glossary.md:76-78 · “stone text uses its length field to hold a
hash, while antestone text uses that field for the letter count” ·
source/pit_internal.h:1638-1655 · Both text profiles carry length (“character
count (always)”) and a separate hash field. There is no dual use on either
profile.
arch-core-88 · glossary.md:83-85 · “fit — a whole number the build
represents exactly. The range is target-selected; is_fit tests membership.” ·
pitlib/fit.c:6-9, source/runtime.c:9297 · FIT_BITS is hardcoded 56 with no
profile conditional, and pit_is_fit accepts short floats up to 2^53 — so the
intrinsic and the module disagree by two bits and neither consults the target. The
module half of the definition is exact.
arch-core-99 · glossary.md:149-153 · “boot — the first pit actor, and
deliberately stupid” · pit-shop/boot_cart.cm:718, pit-shop/shop_actor.ce · There
is no actor named boot; the first pit actor is pit-shop/shop_actor.ce, 1436 lines,
driving cement, mcode_lower, canonical, nota, wota, crypto, qop and
resident_derivation, and doing several of the jobs the glossary assigns to the clerk.
No $boot endowment and the root-overling cascade are confirmed.
arch-core-102 · glossary.md:172-177 · “c_native (which packages may compile C
— a real gate that blesses by naming, so absence is never permission)” ·
shoplib/recipe.cm:87, pit-shop/shop_source.cm:1972,1613 · “EMPTY = EVERY PACKAGE
IS ALLOWED, which is the ruled default”; recipe_allows_c_native returns true on an
empty list, and the committed default is empty. The five list names are exact. See
§a-3.
arch-core-124 · glossary.md:282-286 · origin map “keyed by pool hash” ·
pit-shop/shop_store.cm:711,720, shoplib/mach_pool_emit.cm:1173 · The store is
emphatic that the key is the pool’s content hash, “and NOT the store address …
keying by [the store address] produces a sidecar no frame can ask for”. The glossary
picks the one of the two hashes the code says is wrong. Payload shape is also pre-@2.
arch-core-137 · practice/ci-inspection.md:51 · “If neither exists the script
says so by name and exits 1. It never prompts.” · scripts/ci_runs.sh:64 · The named
refusal is real (:67-72, die() at :26), but git credential fill 2>/dev/null
runs with no GIT_TERMINAL_PROMPT=0 and no askpass override, so on a machine with no
helper git prompts on /dev/tty and the script hangs instead of refusing. One-line fix.
(Probe could not reach the credential-less state; settled by reading.)
Architecture — c-build, packages, pipeline
arch-build-52 · architecture/c-build.md:72-84 · “A package.json … has three
fields” · cake/plan.cm:167,601,626,741,940, platform package.json · modules,
aliases and compilation are all real and behave as described — but the
exhaustive claim is wrong: the live top-level fields across the tree are aliases,
modules, compilation, natives, requirements, fallback.
arch-build-60 · architecture/c-build.md:156-166 · the {"modules": {"render": {"emscripten": "render_web", "*": "render"}}} example, in the section “Declaring C
without writing a cake” · cake/plan.cm:235-244,920-931 · The arm mechanics shown are
exact, but cake never reads modules (zero hits for .modules); the field the C
build consults is natives. Today not one in-tree modules arm names a .c file.
arch-build-64 · architecture/c-build.md:199-203 · “What it does not carry is a
mapping: nothing in it says which file provides which module” ·
boot/manifest/darwin.manifest · Every extension row is that mapping —
extension|shoplib/bootgate.c|shoplib/bootgate|pit_shoplib_bootgate_use|normal||| —
and for 20 endowment rows on darwin the key is not recoverable from the path
(platform/apple/darwin_tls.c -> endowment/darwin_tls). Everything else in the
claim holds.
arch-targets-57 · architecture/pipeline.md:63-69 · a program link “does not run
streamline again, inline across units, remove guards, or learn a target
representation” · pit-linker/mcode_link.cm:1-12, :2288-2345 · Three of the four
negations are false, and the code’s own banner says so: phase 2 “COMPACTS THE
NOW-PROVEN GUARD/CONTROL-FLOW LADDER”, phase 3 “COPIES AN ELIGIBLE PROVIDER BODY INTO
THE CONSUMING UNIT”, and streamline_linked_units() re-runs the ordinary streamline
pipeline per linked unit with stage:'link'.
arch-targets-66 · architecture/packages-and-distribution.md:17-23 · “That is
the whole of it” over a three-row field table · pit-shop/shop_source.cm:2057,2289,
cake/plan.cm:143,904,997 · Wrong by three: fallback is read twice in the closure
walk, requirements is read by cake (12 platform packages carry it) and is
documented by recipes.md:200-214, and natives is read by cake’s
extension_files(). See §a-4.
arch-targets-67 · architecture/packages-and-distribution.md:24 · “There is no
natives listing the package’s C, because a C file’s path is its name too” · root
package.json, shoplib/package.json, cake/plan.cm:920-931 · The runtime package’s
own manifest carries a natives array (keys internal/sysinfo, internal/os), and
cake explains why it survives: “only what a listing cannot say — a per-system arm, or
a provider outside the declaring package’s own tree.” CLAUDE.md documents the field.
Architecture — debugging, actors-and-memory, security
arch-debug-7 · architecture/debugging.md:24-26 · “Each of the four is scoped by
an actor token. Applied to the actor holding it, it looks at that actor … reach runs
down the tree an actor created.” · std_endowments/inspect.c:253-276,
std_endowments/hook.c:73-82, source/scheduler.c:3260-3370 · There is no token and
no ownership test: inspect_open takes a bare id text and reaches any actor;
applying it to your own actor is explicitly refused (if (target == ctx) … cannot inspect the current actor); and snapshot() enumerates every actor, so any id is
obtainable.
arch-debug-11 · architecture/debugging.md:47-51 · “An observer never blocks on a
turn it does not own.” · std_endowments/inspect.c:273,
source/pit_internal.h:2825-2827 · False for 9 of $inspect’s 13 calls:
inspect_open takes an unconditional sys_rmutex_lock(target->mutex) and
run_actor_turn holds that mutex for the whole turn, so frames/depth/frame_fns/
locals/closure/fn/bytecode/mailbox/address block until the debuggee’s turn ends.
The enumeration half (trylock, 40×1ms retry, partial row) is exact.
shop_tools/debug.ce:997-1000 repeats the doc’s version and is wrong the same way.
arch-debug-86 · architecture/actors-and-memory.md:92-97 · “There is no
interning anywhere — not process-wide, not per-actor.” ·
source/pit_text_utf32.c:99-159, source/pit_text_kim.c:124-185,
source/pit_text.h:100-114 · rt_intern_text_to_value locks rt->ct_lock,
hash-probes rt->ct_hash and hands back a pointer into a runtime-wide immortal
arena. pit_text.h:100-112 asserts the doc’s sentence verbatim, then at :112-114
declares the “runtime-wide constant-text pool (the interning index over the rt ct
arena)”. See §a-14.
arch-debug-103 · architecture/actors-and-memory.md:207-213 · “The public actor
module a program uses holds only token display and actor-local scheduler operations;
it cannot create an actor or manufacture a delivery.” · std/actor.c:27-31,
source/pit_actor.c:899-947 · std/actor.c returns pit_actor_funcs whole — 44
entries including create_actor_shell, boot_actor, run_boot, register_actor,
mailbox_push, mailbox_push_silent, set_actor_overling, register_image and
every limit setter. There is no separate delivery provider anywhere in the tree.
arch-debug-104 · architecture/actors-and-memory.md:215-218 · “Both are ordinary
endowments held by whoever the realization says holds them.” ·
pit-shop/policy.ce:14-41 · The premise fails: there is one ordinary use()able
module, not two endowments — neither an actor-shell primitive nor a delivery provider
appears on ALL_ENDOWMENTS. The second half (no per-unit privacy inside one actor)
is correct.
arch-debug-151 · architecture/security.md:92-96 · “a deny_c policy checks the
transitive closure … Every native claim is traced back to the unit that imported it,
and that path is reported when policy is evaluated.” ·
pit-shop/executable_manifest.cm:195,417,647 · deny_c has no consumer: a comment, a
pass-through into the manifest record, and a hardcoded producer writing
deny_c: false. No transitive walk and no import-path report exists.
Read the prior adjudication: plans/archive/worklist.md:155-158 records a
correction claiming it is built at executable_manifest.cm:410 with tests at
tests/executable_artifacts.cm:239; both citations were re-checked and neither says
what the note says.
Language
language-64 · language/semantics.md:11-14 · “An operation yields null when its
result type has a defined absence, and disrupts when it does not.” ·
source/mach_vm.c:3279-3324 vs pit-compiler/mcode.cm:1175-1179,1211-1213, 1256-1262,1291-1296,1382-1385 · The MACH layer honours the rule (arithmetic is
total; spec/mach.md:231 says so); the compiler emits a type guard in front of
every arithmetic instruction whose failure arm is emit_log_panic(...) + disrupt. The
doc states the rule the VM was built to and the compiler overrides.
language-65 · language/semantics.md:21-30 · “Every arithmetic operator — +,
-, *, /, //, %, and unary negation — produces a number or null, and never
disrupts … 2 + "x" // null” · pit-compiler/mcode.cm:1174-1179,1256-1296,1362-1389
· // is the only one of the seven that yields null; every other operator panics
and disrupts on a non-number operand, statically or dynamically.
Probe-confirmed live: 2 + "x" disrupts.
language-66 · language/semantics.md:21,119-121 · “+ is a claim that both
operands are numbers … neither does the other’s job” · pit-compiler/mcode.cm: 1163-1166,1190-1199, tests/vm_suite.ce:7845-7859 · + concatenates text, on both
the static both-text arm and the dynamic path (“Check text path first (since add
doubles as concat)”), and the suite pins it: "ret" + "urn" must equal "return".
language-67 · language/semantics.md:32-33 · “null then propagates: arithmetic
on null yields null” · pit-compiler/mcode.cm:1243-1262,1268-1296 · A null
operand fails the is_num guard and takes the panic+disrupt arm for every operator
but //. tests/store_freshness.ce:1113-1122 records this exact shape killing a
clerk mid-walk.
language-77 · language/semantics.md:138-144 · var label = "total: " & (price + quantity) // disrupts if either was not a number — the failure surfaces “at the point
you try to render it” · pit-compiler/mcode.cm:1181-1184,1198-1213,1268-1296 · The
+ disrupts first; the actor dies with cannot apply '+': tried to add … and never
reaches the &. The teaching example teaches the wrong failure site.
language-78 · language/semantics.md:148-152 · “Neither + nor & is
overloaded, and that is the point.” · same as language-66 · + is overloaded, and the
“Why two operators” section is the normative statement of a property the compiler does
not have.
language-85 · language/syntax.md:78-99 · “Arithmetic operators work on numbers
only. Give one a non-number and the result is null.” · pit-compiler/mcode.cm: 1163-1166,1256-1296,1382-1385 · False for six of the seven operators (they disrupt),
and “numbers only” is false for + (it concatenates). :96-97 repeats the framing
language-78 refutes.
Library
library-4 · library/_index.md:62-72 · the per-target example keys the map under
"file" · std/package.json, std/file.cm · The live key is file_provider
(def file_impl = use('file_provider')); git shows it was renamed from file_impl
straight to file_provider — the example was never right. Mechanism is real.
library-5 · library/_index.md:74-76 · “There is no file.cm” ·
std/file.cm · It exists and has since aaa7f9e88; it is the composition wrapper
around the dispatched provider. The property being defended is true of
std/file_provider.cm, so the repair is to rename the example’s key, not to change
code.
library-18 · library/blob.md:93-99 · “Append text (kim-encoded length +
characters).” · pitlib/blob.c:375-386 · Writes a fixed 64-bit little-endian length
prefix then raw UTF-8. No Kim anywhere; git log -S kim -- pitlib/blob.c is empty.
Same false claim at spec/kim.md:93-103 (spec-runtime-90), so the fix touches two
pages.
library-24 · library/blob.md:143-149 · “Read kim-encoded text.” ·
pitlib/blob.c:572-609 · Reads the fixed 64-bit prefix then raw bytes. Symmetric with
library-18.
library-33 · library/crypto.md:14 · “It is an explicit dependency: name it in
your package.json before importing it.” · shoplib/recipe.cm:104,
pit-shop/shop_source.cm:1574 · crypto lives at std/crypto.cm and std is on the
shop fallback list, so a bare use('crypto') resolves with no declaration. Zero
"crypto" declarations exist in any package.json, and six in-tree call sites
import it successfully.
library-34 · library/crypto.md:16-17 · “use [random], which is a deterministic
convenience PRNG” · pitlib/random.cm, internal/os_posix.c:604,
platform/posix-runtime/source/sys_os_posix.c:189-205 · random has no seed, no
state and no algorithm: every entry point calls os.random() → getrandom(2) //dev/urandom,
the same CSPRNG crypto.random uses. std/crypto.cm:8-9 repeats the false claim, so
two documents describe a mechanism that was never built and the code burns kernel
entropy for non-security randomness.
library-39 · library/crypto.md:62-66 · crypto.chacha20(key, nonce, counter, data) · shoplib/crypto.c:259-277 · The real order is (key, nonce, data, counter?)
— counter and data are swapped and counter is last and optional. Following the doc
passes a number where a blob is expected and disrupts.
library-40 · library/crypto.md:72-75 · crypto.keypair() // {secret, public}
and crypto.shared(my_secret, their_public) · shoplib/crypto.c:88-99,242-256 ·
keypair sets public/private, and shared takes arg0 = public,
arg1 = private. Both args are 256-bit blobs, so the reversed call is silent
and yields a wrong shared secret. (sign_keypair does use secret/public, so the
two keypair functions disagree with each other.)
library-41 · library/crypto.md:77-83 · crypto.verify(identity.public, message, signature) · shoplib/crypto.c:137-150, tests/sign_keypair.ce:22,
tests/crypto_empty.cm:84-87 · Real order is verify(signature, public, message);
both in-tree tests call it the code’s way. The doc’s order raises on the 512-bit
signature check. sign_keypair and sign halves hold.
library-43 · library/crypto.md:89-95 · “It is what seeds [random]” ·
pitlib/random.cm · random never calls crypto.random and holds no seed. The
size/blob/CSPRNG parts of the claim are exact and pinned by
tests/crypto_empty.cm.
library-74 · library/json.md:16-18 · “With no space argument, output is
pretty-printed with 1-space indent.” · pitlib/json.c:5-6,919-921 · With no argument
pretty=0 and gap is the empty string: the default is fully compact, no
newlines, no spaces.
library-75 · library/json.md:20-22 · json.encode({a: 1, b: 2}) // '{ "a": 1, "b": 2 }' · same · Actual output is {"a":1,"b":2} — identical to the page’s own
“compact” example four lines below, which makes the page self-contradictory as
written.
library-77 · library/json.md:28-33 · json.encode({a: 1, b: 2}, 2) pretty-prints
with 2-space indent · pitlib/json.c:5-6 · The space argument is used for its
truthiness only and then discarded, substituting a hardcoded Pit_NewInt32(ctx, 2).
json.encode(v, 4) and json.encode(v, '\t') both silently produce 2-space indent.
The engine underneath supports the documented semantics; one wrapper line drops the
argument. Probe-confirmed live.
library-78 · library/json.md:36-39 · parameter table for space · same · Wrong
in three ways (number-of-spaces ignored, string form ignored, default is compact not
pretty). replacer and whitelist are honoured correctly.
library-81 · library/json.md:58-65 · reviver “called like JSON.parse’s reviver”,
with an example keying off if (key == "date") · pitlib/json.c:27-38 · The reviver
is called exactly once, on the root, with the empty key; there is no recursive
bottom-up walk, so the doc’s own example never fires. (The encode side does call the
replacer per property.)
library-92 · library/time.md:14-18 · “$clock is asynchronous everywhere … time
is built on that raw reading” · pitlib/time.cm:2, pitlib/internal/time.c ·
$clock exists and is async, but time binds internal/time directly, whose
pit_time_now/pit_time_monotonic are synchronous C calls. time bypasses $clock
entirely — two parallel time surfaces where the page describes one layered design.
library-93 · library/time.md:22-30 · the constants table (time.second …
time.year) · pitlib/time.cm:20-24,218-219 · month and year were never defined,
and none of the seven are reachable: the constants are set on a local record that
the module’s tail return ({record, number, text, now, monotonic}) never exports.
time.day and friends are all null; grep confirms nothing in-tree has ever used them.
library-95 · library/time.md:40-43 · “With an argument, it converts a time record
or formatted text to seconds since the Unix epoch.” · pitlib/time.cm:119-161 ·
There is no text-parsing branch. Passing text does not error — every property read
yields null, || 0 turns it into 0, and the function returns a meaningless timestamp.
library-97 · library/time.md:50-58 · “zone the offset in seconds from UTC” ·
pitlib/internal/time.c:47, pitlib/time.cm:77,158,193 · computer_zone() returns
offset_sec / 3600.0 — hours — and every internal use multiplies it by
time.hour. Anyone trusting the doc is off by 3600×. Field list, month-from-0 and
day-from-1 are exact.
library-98 · library/time.md:64-71 · ### time.text(format) and
time.text("y-mm-d hh:nn:ss") · pitlib/time.cm:164,166,176,206 · Three defects:
(1) the real signature is time_text(_num, _fmt, _zone, _dst) — the documented
single-argument form binds the format string to the timestamp parameter and every
rec.* read goes null; (2) default_fmt is "vB mB d hh:nn:ss a z y c" (full weekday
then full month), the opposite order to the doc’s example; (3) z renders unpadded, so
UTC prints +0, not +0000. Probe-confirmed: the documented call panics.
library-99 · library/time.md:73-88 · the format-token table ·
pitlib/time.cm:207-209 · mm, m and v are implemented as regexes
(/mm[^bB]/g etc.) and pit_text_replace substitutes the whole match, so each
swallows the following character: "y-mm-d hh:nn:ss" becomes "2024-115 10:30:45".
mm also gets no zero-padding while dd/hh/nn/ss do.
library-100 · library/time.md:91-114 · time.number({year: 2024, month: 1, day: 15}) · pitlib/time.cm:125-131 · time_number reads year/hour/minute/second/zone/
dst/yday and never reads month or day: the example silently returns
2024-01-01. A record from time.record() round-trips because it carries yday; a
hand-built calendar record as taught does not. The "yyyy-MM-dd" example also uses a
token that is not in the table.
library-101 · library/time.md:118-134 · now + time.day, now - time.week,
now + 2*time.hour · downstream of library-93 · Every expression evaluates against
null. Every runnable snippet in the Time Arithmetic section is broken.
Shop
shop-core-11 · shop/shop.md:82-84 · “a build cache that travels carries no trace
of them” · pit-shop/shop_realize.cm:845-858,953-985,904-910 · The key half is true
(keys fold only content hashes and the compiler stamp), but write_realize_entry
stores deps verbatim into pit.realize.entry, each source row carrying
stat: {size, mtime, isFile}, upstream_stat, and a host-absolute path — and that
record is the root every publish closure walks from. The code’s own comment states the
honest version: the fingerprints travel, a consumer just reads only the hashes.
shop-core-29 · shop/shop.md:214-217 · use('other::internal/timer') // from anywhere else: refused · pit-shop/shop_source.cm:1348-1361,2152-2165,2368 · Only the
bare-path short-circuit exists; nothing compares the requested package against the
caller or tests for an internal/ segment. The design comments at :2150-2151 describe
the guard as a possibility. Worse: cross-package qualified internal/ imports are
load-bearing right now (pitlib/random.cm:3, shoplib/config.cm:4,
shoplib/recipe.cm:57, …).
shop-core-31 · shop/shop.md:223-227 · “The refusal is a rule on requests, at
resolution time, and it fires on the package the candidate belongs to.” · same · The
“built artifact may record <pkg>::internal/x” half is true
(executable_manifest.cm:307-320); the refusal mechanism it describes does not exist.
shop-core-32 · shop/shop.md:229-231 · “The rule arrives whole. There are no
carve-outs and no exempted packages” · same · There is no rule to carve out of, and
the runtime package is a de-facto universal exemption — runtime::internal/os and
runtime::internal/sysinfo are qualified-imported from at least six packages. If the
refusal were built as documented, the shop’s own boot closure would fail to resolve.
shop-core-35 · shop/shop.md:264-269 · “Because internal/ is package-private,
the guard is what stops anyone reaching past std::file to one target’s
implementation” · same · The arm-value half is true; no such guard exists, and nothing
prevents use('std::internal/file_darwin').
shop-dist-68 · shop/packages.md:38-45 · “The manifest has three fields and no
others” · every package.json in the tree · Six distinct fields —
compilation:15, requirements:12, modules:10, fallback:5, natives:2,
aliases:1 — three of them read by live code
(shop_source.cm:2057,2289,760; cake/plan.cm:146,601,626,741,940). The negative half
(no name, no members, a nested package.json invents nothing) does hold. See §a-4.
shop-dist-71 · shop/packages.md:79-87 · “There is exactly one such folder. A
package does not have a src/ beside a vendor/ beside a source/.” ·
pit-shop/package.cm:41-48, pit-qbe/cake.ce, repo root · is_native_file() special-
cases both source/ and vendor/; pit-qbe/vendor/ exists on disk and reaches the
build through 33 explicit per-file paths in pit-qbe/cake.ce — precisely the per-file
support list the doc says does not exist — and the runtime package has both source/
and src/.
Spec
spec-exec-26 · spec/mcode.md:8 · “The mcode instruction set is the
authoritative reference” · pit-compiler/stream_ir.cm:30-46 · OP_NAMES is
declared exhaustive and holds 99 opcodes; the page’s tables cover about 45. Two
omissions are load-bearing: call/tail_call are the only call opcodes the compiler
emits, and pretext/append are what concat lowers to.
spec-exec-62 · spec/executables.md:112-127 · entry kind “{value: <any>} — a
constant the shop already resolved” · pit-shop/cement.cm:84-107,
engine/boot_walk.cm:7-8,275-291 · The count is right and the kind is not: the third
kind is “a VALUE PROJECTED OUT OF SOMETHING ALREADY PRODUCED” — the runner reads
property row.name off an earlier entry’s result or off the boot globals record. Same
root as arch-core-83.
spec-exec-65 · spec/executables.md:151-156 · “At start, the shop confirms the
running runtime can supply each one” · pit-shop/shop_realize.cm:865-873 · The
logical-names-only half is exact. There is no start-time confirmation step: the only
check on a native provider is a realize-time stat fingerprint folded into the
realization’s dependency set. This is the docs-vs-code half of §a-1.
spec-formats-11 · spec/artifact-formats.md:122-158 · pit.target.profile@1 with
scheduler and providers · source/pit_profile.h:170-212,
source/mach_pool.c:449-452 · The schema name is absent repo-wide; the live complete
profile is the compile-time string PIT_PROFILE_STRING (<name>;value=;rep=;endian=; text=;record=;gc=;wota=), hashed as a string and stamped at pmp1 offset 56. Two of the
doc’s fields are ruled out of it by recipes.md and target-profiles.md. See §a-2.
spec-formats-12 · spec/artifact-formats.md:160-218 · pit.mach.abi@1 /
pit.mach.finalizer@1 as canonical records, with LOAD_MODULE_RESULT/LOAD_BOUND_MODULE
“part of the ABI hash” · source/mach_internal.h:27,365-370,
source/mach_pool.c:455-490,2324-2332 · Both schema names are absent; the offset-88
identity is blake2 of <PIT_MACH_ABI>|<PIT_PROFILE_STRING> where PIT_MACH_ABI is the
literal mach-v4+fuse1. The two opcodes exist but are marked DORMANT — “no emitter
produces them … and PIT_MACH_ABI does not move”.
spec-formats-21 · spec/artifact-formats.md:576-589 · “It has exactly three ruled
profile/granularity pairs” + “an unknown field is a link error” ·
pit-linker/mcode_link.cm:75-133,2388 · The three pairs and all four error conditions
are confirmed verbatim — but valid_link_plan’s allowed set includes join_types and
inline_budget, which canonical_link_plan emits. The spec as written refuses the
plan the linker actually produces. (CP7 landed 2026-08-04; the spec predates it.)
spec-formats-44 · spec/artifact-formats.md:993-1001 · “The answer is not
serialized into a portable, signed, re-verifiable record … no realization carries its
hash.” · pit-shop/shop_build.cm:298-310,2133,2200,2248,2290 · Both halves false: a
pit.policy.decision record is canonically encoded, blake2’d and written into the
store under that hash, and that hash is a field of pit.target.realization@1 and
is folded into the realization’s identity seed. Line 68 of the same page lists it.
spec-formats-61 · spec/artifact-formats.md:1324-1344 · K_pool includes “complete
target-profile hash” · pit-shop/shop_store.cm:751-765 · mach_derivation_key folds
only numrep and endian of the eight profile axes; text, record, gc, wota and object
layout do not enter, and current_mach_abi() carries no profile string. Two profiles
differing only in text share one K_mach catalog row. The rest of the key composition
is right.
spec-formats-73 · spec/artifact-formats.md:1738-1791 · the “what the shop produces
today” table, incl. “bindings and executables are not produced yet” ·
pit-shop/shop_build.cm:2182,2185,2251-2291 · The realization carries fifteen further
fields, including bindings and executables — with different meanings from the
target schema’s (bindings is the module_context static-binding map; executables is
the closure’s executable claims). One name now denotes two things on one page, which is
worse than absence.
spec-runtime-90 · spec/kim.md:95-103 · “The blob.write_text and
blob.read_text functions use Kim to encode text into binary data” ·
pitlib/blob.c:376-386,588-598 · Fixed 64-bit length prefix then raw UTF-8. Kim lives
in shoplib/kim.c and the nota/wota codecs, not in blob text. Same defect as
library-18/24 — fix both pages or the code.
spec-runtime-94 · spec/dec64.md:17-19 · “Two runtimes that selected different
numeric representations therefore exchange numbers through a common decimal form.” ·
source/nota.h:383,410-457, shoplib/nota.c:373 · The live nota float encoder derives
the coefficient/exponent from a binary double via floor(log10(...)) and a pow10
table to 14 digits. The exchange form is capped at 14 significant digits and subject to
binary-float rounding — it cannot carry a 56-bit DEC64 coefficient. The one dec64 claim
that is not merely unbuilt.
spec-runtime-112 · spec/nota.md:135-144 · “nota_write_decimal(buffer, coefficient, exponent) and nota_read_decimal(...) … The coefficient therefore crosses
the wire without conversion through binary floating point” · source/nota.h:40,58,410 ·
Neither function exists anywhere outside this page. The real surface is
nota_write_number(NotaBuffer*, double) / nota_read_float(double*, char*) — IEEE-754
in and out. Trailing-zero stripping, zero-as-integer and exponent-zero-as-integer are
built.
spec-runtime-113 · spec/nota.md:145-152 · the four worked byte sequences ·
source/nota.h:280-293 · All four decode correctly (hand-verified), but the fourth
is never emitted: nota_write_int_or_float_buf routes any integral double in int64
range to the integer writer, so -10000000000000 is written as a nota integer, not as
C8 0D 01. tests/nota.cm:127-147 round-trips these values without pinning any byte
sequence, so the gate could not have caught it.
c. OVERREACH — docs describe the system doing more than it should (12)
Grouped by area, since the question is whether a track is doing too many things.
Boot / bootstrap configuration — spec/artifact-formats.md (4)
The single largest concentration. Three sections mint new schema names for configuration the live boot already carries in one small record.
- spec-formats-13 ·
:220-372·pit.bootstrap.target@1mints six new schema names, three of which (bootstrap.provider.catalog,bootstrap.profile.config,bootstrap.policy.config) are bootstrap-local restatements of records the same page already defines, and it embeds full inline copies of the mach_abi and finalizer values beside their hashes. Live equivalent:boot/root.cartcarrying onepit.cart.metadata@2(pit-shop/cement.cm:80). - spec-formats-42 ·
:918-968·pit.provider.registry@1defines a second artifact for the questionpit.provider.catalog@1already answers, plus a cross-invariant tying them together, plus the third bootstrap-local restatement above. Live mechanism is one thing: cake’sextension|…rows inboot/manifest/<system>.manifest. - spec-formats-15 ·
:387-425·pit.store.manifest@1+pit.package.selections@1: a signed multi-selection store manifest on top of the unbuilt store contract, duplicating what the builtpit.bundle@1manifest already does (root/catalog/objects- detached
/signature,shop_realize.cm:1754-1802); thepackagesselections index restates whatpit.executable.manifest@1andpit.workspace.resolution@1already decide — which the page itself concedes.
- detached
- spec-formats-16 ·
:429-442·pit.package.tree@1is redundant with the builtpit.workspace.snapshot@1’sfilesmap, which is already “normalized package-relative path -> source content hash, each path once, sorted”.
Compiler spec inventing a call lane — spec/mcode.md, spec/streamline.md (2)
- spec-exec-38 ·
mcode.md:236-244· the three-instructionframe/setarg/invokedecomposition has no producer: every ordinary call goes throughemit_call(mcode.cm:1942-1959) emitting one fusedcallrow. The runtime still carries the whole documented-but-unfed lane (MACH_FRAME/MACH_INVOKE), andcall/tail_call— the real thing — appear nowhere on the page. - spec-exec-21 ·
streamline.md:353-359· “mcode.cm renames the finalinvoketotail_invoke”. Both renames exist atmcode.cm:4292-4305, but theinvokebranch is a limb with no producer; the live rename iscall→tail_call, which the section never mentions.
Endowment / capability surfaces the tree does not have (3)
- arch-debug-37 ·
debugging.md:215-222· “an actor allocates its counters when it starts”. The PGO reader is real (mach_pool.c:254-260); there is no writer, andmach_exec_pgoreturns NULL forMACH_EXEC_IMAGE— which since L3 is the shipped lane. The 368-line collector insource/pgo_profile.cplus its two opcodes cannot attach to anything shipped. - library-58 ·
library/io.md:142· “the raw socket control adds onlyset_nonblocking(handle, enabled)”. No such pit-visible function exists; non-blocking is applied automatically inside the C provider (platform/shared/socket_completion_posix.inc:236). Meanwhile the raw endowment surface that does exist has 21 operations. - spec-runtime-32 ·
spec/wota.md:31-34· “The cold-boot runtime temporarily exposes the same primitive module asinternal/wota_bootstrap”. That name exists only in this sentence; the real cold boot is a plain C call,wota2value(ctx, ctx->init_wota)(source/pit.c:190). The doc invents a naming mechanism no ruling calls for, in the present tense, for something that never existed.
Mechanisms specified that could not be built as stated (3)
- shop-c-5 ·
c-modules.md:63-64· “targets with symbol length limits take a deterministic shortened name from the same place”.shoplib/symbols.cmis the whole authority (safe_c_name+c_symbol_for_file) and has no shortening path; no in-tree target declares a limit and no ruling asks for one. (extensions.md:197-198names a concrete scheme,pitx_<hash>, that appears nowhere in the tree — counted under §e as shop-dist-56 because the extensions page frames it as target work rather than as a present-tense property.) - arch-targets-13 ·
recipes.md:138-145·capabilitiesframed as a live per-target lever.shoplib/features.cm:34-37says outright: “There is deliberately no per-target table and no per-recipe list:recipe.build.capabilities.daemonwas the per-target spelling of exactly this and it is what R9 replaces.” The per-product half of the claim (daemon C swapped fordaemon-stub) is confirmed. - spec-runtime-72 ·
spec/stone.md:21-26· “Text carries one length-sized field” that holds the letter count while antestone and the hash once stoned. Not buildable as written —length()and indexing must still work on stoned text — and both profiles carry the two fields separately. Same root as arch-core-87.
d. STALE — describes something deliberately deleted or renamed (28)
spec/streamline.md holds 11 of the 28. It is the single most out-of-date page in
docs/ and is a candidate for rewrite rather than repair.
spec/streamline.md + spec/mcode.md — the optimizer chapter (13)
| id | doc | says | actually |
|---|---|---|---|
| spec-exec-1 | streamline.md:8 | passes are reorderable and “communicate only through the instruction array” | order is fixed and the code says so by name (streamline.cm:5236-5241,5277-5284,5307-5312); passes exchange func._param_types, _write_types, _resolved_calls, _no_overflow, ir._switch_census |
| spec-exec-4 | streamline.md:40-67 | Pass 1 infer_param_types | no such function anywhere; the mechanism moved to mcode.cm:4663-4670 + pit-compiler/resolve.cm (AST-level, whole-program) |
| spec-exec-5 | streamline.md:69-112 | write-type table row “move → T_UNKNOWN” | streamline.cm:635-680 resolves a move’s write type from its source by fixed point; only unresolved moves are poisoned — the scheme the page’s own Future Work says was abandoned |
| spec-exec-8 | streamline.md:147-161 | Pass 4 simplify_algebra | gone; folded into another pass (streamline.cm:1970 names it as former). is_identical is not an opcode at all |
| spec-exec-15 | streamline.md:256-274 | all passes run once in sequence in optimize_function | it is a 16-cycle fixpoint that disrupts if it does not converge; six of its real passes are unnamed by the doc, and eleven more run outside it |
| spec-exec-16 | streamline.md:280-293 | push(arr,val) → one opcode; length(x) → one opcode | push as a call was deleted by a1b41d5ec (“rm push/pop”); the surviving arr[] = val syntax lowers to eight instructions and length to a five-way guarded dispatch |
| spec-exec-19 | streamline.md:321-336 | + propagates to a target only when target == left_slot | broadened 2026-07-07 by 02ac4063b; the page’s Future Work asks for something already done |
| spec-exec-20 | streamline.md:340-351 | pit mcode --pretty, pit streamline --types/--stats | streamline.ce was deleted by 2a43734f9; pit mcode has no --pretty. Live surface is shop_tools/compile.ce modes, which CLAUDE.md already documents |
| spec-exec-23 | streamline.md:409-411 | copy propagation “attempted but abandoned” | built, inside eliminate_moves (streamline.cm:2151-2154, 2230-2340), including the multi-operand call rows the doc calls the unsolved case |
| spec-exec-24 | streamline.md:476-478 | LICM is unimplemented future work | pit-compiler/licm.cm is a first-class pass, switched by pass_on.licm, on in SHIP |
| spec-exec-25 | streamline.md:441-448 | TCO not implemented | pit-compiler/tco.cm is a dedicated pass, on in SHIP, satisfying every bullet the doc lists as required |
| spec-exec-42 | mcode.md:288-304 | the same intrinsic-inlining table, duplicated | same defect as spec-exec-16; must be fixed twice |
| spec-exec-43 | mcode.md:308-318 | labels collected into a name→index map for O(1) jump resolution “during loading” | there is no loading stage left; the serializer’s resolution is an O(patches×labels) strcmp scan (mach_pool.c:5014-5020). The second sentence is true |
spec/values.md — the deleted immediate-ASCII lane (3)
aeaf3ed15 + 24e6fbdd1 (2026-07-25/26) deliberately removed the second text
representation. Three claims describe it as live:
- spec-runtime-62 ·
:65-72·01011is documented as “Immediate string”; it isPIT_TAG_EMPTY_TEXT, renamed by that commit “named for what it is now that the empty text is the only immediate that can exist”. - spec-runtime-63 ·
:74-88· the whole “Immediate Strings” section is dead text —Pit_NewStringLenreturns an immediate only for length 0, so the section’s worked example"hello"is heap-allocated. (Note: the user-memory entry “PIT_ASCII_MAX_LEN is 7 on nan64” is itself stale as of that commit.) - spec-runtime-68 ·
:124-127· the summary sentence “short immediate text values do not require heap allocation” was not swept with the mechanism.
Deleted files and renamed producers (12)
| id | doc | stale item |
|---|---|---|
| arch-targets-73 | packages-and-distribution.md:93-107 | “a minimal boot cartridge runs the bundle’s finalized pools” — bundles no longer carry mach pools (R8, 3127caca4); and the dev slice has no source or lockfile member |
| arch-targets-94 | targets.md:113-124 | “shipped bundles carry the compact per-VM mach payload” — shop_tools/bundle.ce:40 RETIRED_PAYLOAD_FORMS = ['mach','mixed'] and :148 refuses it by name |
| arch-targets-91 | targets.md:81-84 | darwin_file.c and metal.c moved out of platform/darwin/ by 01bba7317; lands on the page’s own “there is no second place to check” |
| shop-c-11 | c-modules.md:100-113 | Pit_FreeCString(ctx, str) — 869afc259 dropped the ctx param; the two-arg form appears twice on the page |
| shop-core-42 | shop.md:317-320 | engine is “one unit” — the boot walker was lifted out of C into its own pressed pool, so it is two |
| shop-core-49 | shop.md:407-410 | “std is file and io” — omits actor, crypto, log, proxy, utf8, all fallback-reachable by bare name |
| shop-core-75 | endowments.md:139-162 | the lang-endowments/ half of the worked layout: the real filenames carry the sigil ($delay.cm, $start.cm), so the “ordinary module lang-endowments::delay” spelling is wrong too |
| shop-dist-28 | compilation.md:234-236 | pit product pit-compiler/mcode.ce — no .ce files exist in pit-compiler; the real product is shop_tools/mcode_tool.ce |
| spec-exec-58 | executables.md:37-48 | modules is not a field of claims (it is the sibling imports, redirected at shop_build.cm:1188-1190), and extensions is hard-coded [] by the compiler — a unit does not declare its native requirements; the shop derives them |
| spec-formats-17 | artifact-formats.md:450-519 | the normative pit.mcode.unit@3 example: stages show fold-exact (real: fold), flags show infer_shapes (real: streamline), and two emitted fields (exports, diagnostics) are missing. stages is a derivation-key input, so this is not cosmetic |
| spec-runtime-133 | spec/pipeline.md:178-183 | the Debug Tools table — zero of its four invocations are runnable; streamline.ce was deleted by 2a43734f9 |
| spec-runtime-134 | spec/pipeline.md:187-196 | the Test Files table — 7 of 8 rows point at nothing: two files were deleted by 70f560550, five have never existed in any reachable ref. Worth deleting outright |
e. Ruled-but-unbuilt (89) — expected state, listed for the ledger
docs/ is target-final, so these are the target describing itself. No action implied.
| area | count | claim ids |
|---|---|---|
spec/dec64.md (the whole page — no DEC64 rep exists) | 7 | spec-runtime-92,93,95,96,97,98,99 |
spec/artifact-formats.md (unbuilt schema names) | 10 | spec-formats-14,39,40,41,43,70,72,75,76,85 |
architecture/capabilities.md (policy over closures, guest code, sealed player) | 6 | arch-core-39,43,44,45,46 + arch-core-35 |
glossary.md (placement group, $image, alias pins, guest code, extension spec) | 5 | arch-core-85,100,110,113,116 |
architecture/debugging.md ($pgo drain, remote debugger, counter-free builds) | 5 | arch-debug-4,33,38,58,66 |
architecture/actors-and-memory.md (three regions, stone pool, placement on banked targets) | 5 | arch-debug-78,79,85,105,106 |
shop/store.md (the store contract — get_manifest/get_content, backends, fetch) | 5 | shop-c-55,56,58,59,60 |
shop/endowments.md (c_endowments, $clerk/$logger/$args/$shop_path, $start) | 5 | shop-core-85,98,99,100,101 |
architecture/consoles.md (memory table, access modes, tiny/nano targets) | 4 | arch-targets-78,80,83,84 |
shop/compilation.md (pools as layout unit, service table, shipping forms) | 4 | shop-dist-15,36,37,39 |
architecture/boot.md (boot as a distinct deliberately-stupid actor) | 3 | arch-build-97,107,118 |
architecture/build-and-artifacts.md (instrumented pools, PGO consumption, profile provenance) | 3 | arch-build-42,44,45 |
architecture/packages-and-distribution.md (lock.json, alias sources, bundle slices) | 3 | arch-targets-68,69,75 |
shop/packages.md (package as distribution unit, version selectors, lock.json) | 3 | shop-dist-69,77,78 |
architecture/pipeline.md (artifact chain, pit.cart@2 header) | 2 | arch-targets-52,63 |
architecture/cartridges.md (sealed store, extension spec, asset index) | 2 | arch-targets-96,101 |
architecture/target-profiles.md (axis table, val16 nano word) | 2 | arch-targets-43,47 |
architecture/assets.md (locator-reached assets, shadow lint) | 2 | arch-core-61,66 |
architecture/security.md (sealed player, the four-gate table) | 2 | arch-debug-152,159 |
shop/extensions.md (c_native gate, shortened symbols) | 2 | shop-dist-42,56 |
architecture/executable-array.md (three entry kinds, {value} origins) | 2 | arch-debug-111,112 |
| singles | 7 | arch-core-18, language-38, language-71, library-6, shop-core-39, spec-runtime-30, spec-runtime-101 |
f. Per-page coverage ledger
Complete claim inventory per page. . is zero. Every page in docs/ appears.
| page | claims | match | contra | over | stale | unbuilt | unver |
|---|---|---|---|---|---|---|---|
architecture/_index.md | 1 | 1 | . | . | . | . | . |
architecture/actors-and-memory.md | 34 | 25 | 3 | . | . | 5 | 1 |
architecture/assets.md | 10 | 5 | 3 | . | . | 2 | . |
architecture/boot.md | 39 | 36 | . | . | . | 3 | . |
architecture/build-and-artifacts.md | 45 | 42 | . | . | . | 3 | . |
architecture/c-build.md | 39 | 36 | 3 | . | . | . | . |
architecture/capabilities.md | 18 | 11 | 1 | . | . | 6 | . |
architecture/cartridges.md | 14 | 12 | . | . | . | 2 | . |
architecture/consoles.md | 9 | 5 | . | . | . | 4 | . |
architecture/debugging.md | 75 | 67 | 2 | 1 | . | 5 | . |
architecture/executable-array.md | 28 | 26 | . | . | . | 2 | . |
architecture/implementors-guide.md | 12 | 12 | . | . | . | . | . |
architecture/nightly-distribution.md | 18 | 11 | . | . | . | . | 7 |
architecture/overview.md | 10 | 10 | . | . | . | . | . |
architecture/packages-and-distribution.md | 11 | 5 | 2 | . | 1 | 3 | . |
architecture/pipeline.md | 13 | 10 | 1 | . | . | 2 | . |
architecture/principles.md | 11 | 9 | 1 | . | . | 1 | . |
architecture/providers.md | 9 | 8 | 1 | . | . | . | . |
architecture/recipes.md | 22 | 21 | . | 1 | . | . | . |
architecture/security.md | 22 | 19 | 1 | . | . | 2 | . |
architecture/target-profiles.md | 11 | 9 | . | . | . | 2 | . |
architecture/targets.md | 11 | 9 | . | . | 2 | . | . |
glossary.md | 59 | 48 | 6 | . | . | 5 | . |
language/_index.md | 1 | 0 | . | . | . | . | 1 |
language/actors.md | 32 | 31 | . | . | . | 1 | . |
language/builtins.md | 24 | 24 | . | . | . | . | . |
language/functions.md | 8 | 8 | . | . | . | . | . |
language/parallelism.md | 7 | 7 | . | . | . | . | . |
language/running.md | 15 | 15 | . | . | . | . | . |
language/semantics.md | 15 | 8 | 6 | . | . | 1 | . |
language/syntax.md | 29 | 28 | 1 | . | . | . | . |
library/_index.md | 8 | 5 | 2 | . | . | 1 | . |
library/blob.md | 23 | 21 | 2 | . | . | . | . |
library/crypto.md | 13 | 7 | 6 | . | . | . | . |
library/io.md | 29 | 28 | . | 1 | . | . | . |
library/json.md | 8 | 3 | 5 | . | . | . | . |
library/math.md | 6 | 6 | . | . | . | . | . |
library/random.md | 4 | 4 | . | . | . | . | . |
library/time.md | 10 | 2 | 8 | . | . | . | . |
practice/_index.md | 5 | 5 | . | . | . | . | . |
practice/ci-inspection.md | 17 | 13 | 1 | . | . | . | 3 |
shop/_index.md | 1 | 1 | . | . | . | . | . |
shop/c-modules.md | 51 | 49 | . | 1 | 1 | . | . |
shop/compilation.md | 39 | 34 | . | . | 1 | 4 | . |
shop/endowments.md | 48 | 42 | . | . | 1 | 5 | . |
shop/extensions.md | 24 | 22 | . | . | . | 2 | . |
shop/packages.md | 17 | 12 | 2 | . | . | 3 | . |
shop/shop.md | 60 | 52 | 5 | . | 2 | 1 | . |
shop/store.md | 13 | 8 | . | . | . | 5 | . |
spec/_index.md | 2 | 2 | . | . | . | . | . |
spec/artifact-formats.md | 88 | 63 | 6 | 4 | 1 | 10 | 4 |
spec/dec64.md | 8 | 0 | 1 | . | . | 7 | . |
spec/executables.md | 11 | 8 | 2 | . | 1 | . | . |
spec/gc.md | 13 | 13 | . | . | . | . | . |
spec/kim.md | 9 | 7 | 1 | . | . | . | 1 |
spec/mach.md | 11 | 11 | . | . | . | . | . |
spec/mcode.md | 19 | 15 | 1 | 1 | 2 | . | . |
spec/nota.md | 17 | 14 | 2 | . | . | 1 | . |
spec/pipeline.md | 18 | 16 | . | . | 2 | . | . |
spec/scheduler.md | 26 | 26 | . | . | . | . | . |
spec/stone.md | 14 | 13 | . | 1 | . | . | . |
spec/streamline.md | 25 | 13 | . | 1 | 11 | . | . |
spec/values.md | 13 | 10 | . | . | 3 | . | . |
spec/wota.md | 14 | 12 | . | 1 | . | 1 | . |
| total (64 pages) | 1316 | 1095 | 75 | 12 | 28 | 89 | 17 |
Clean pages (every claim MATCHES): architecture/_index.md,
architecture/implementors-guide.md, architecture/overview.md,
language/builtins.md, language/functions.md, language/parallelism.md,
language/running.md, library/math.md, library/random.md,
practice/_index.md, shop/_index.md, spec/_index.md, spec/gc.md,
spec/mach.md, spec/scheduler.md.
g. Remaining UNVERIFIED (17), with why
Not settleable from this repository (11)
| id | doc | why |
|---|---|---|
| arch-targets-30 | nightly-distribution.md:68-70 | gitea’s [repository.release] defaults — only the server’s app.ini settles it. Repo-side half is consistent: 4 archives + compatibility.json |
| arch-targets-39 | nightly-distribution.md:154-157 | same, five files / 2048 MB |
| arch-targets-32 | nightly-distribution.md:86-92 | Docker-emulation speed on Apple Silicon. Probe skipped as too heavy (full linux CI lane under emulation) |
| arch-targets-34 | nightly-distribution.md:99-104 | runner-host image footprint. Probe measured local arm64 pit-ci:local at 7.09 GB against the doc’s ~1.7 GB, but that is not the runner host, so it does not settle the claim — worth a real measurement |
| arch-targets-35 | nightly-distribution.md:106-112 | Alpine host-setup commands; outside the repo entirely |
| arch-targets-37 | nightly-distribution.md:129-135 | act_runner label→image mapping lives in the runner’s own config.yaml. The workflow side is confirmed |
| arch-targets-40 | nightly-distribution.md:163-176 | a checklist of standard shell/Docker commands for the runner host |
| arch-core-139 | ci-inspection.md:66-68 | /actions/tasks — probe returned 404 unauthenticated, indistinguishable from an auth refusal. Needs a GITEA_TOKEN |
| arch-core-141 | ci-inspection.md:84-86 | /actions/runners “comes back empty” — same 404. The page’s fallback advice is live-confirmed (runner_name carried pit-server / mac-runner) |
| arch-core-147 | ci-inspection.md:143-145 | “a job dying in under a minute” — ci_runs.sh surfaces no durations, so the heuristic cannot be selected for. One sample supports the substance (run 433 died in checkout, node missing, exit 127) |
| spec-runtime-83 | spec/kim.md:8 | Crockford attribution is provenance; “simpler and more compact than UTF-8 for most text” is a design assertion the page’s own table concedes parity on for ASCII. Reword rather than test |
Not code claims (3)
- language-1 ·
language/_index.md:11· “syntax.md then semantics.md cover everything the other pages assume” — an editorial assertion about prose completeness. Left unverified deliberately rather than counted as a match. - spec-formats-86 ·
artifact-formats.md:2101-2103· one-line cross-reference tospec/wota.md, which is another lane’s page. - spec-formats-87 ·
artifact-formats.md:2105-2107· one-line cross-reference tospec/nota.md. Corroborating detail from this lane does not contradict it. - spec-runtime-99 ·
spec/dec64.md:63-72· the DEC64-vs-IEEE-754 comparison table. Intrinsic to Crockford’s format definition; this tree has no DEC64 implementation to exhibit or refute it. Correct as background for a queued rep.
Wants a targeted test (3)
- arch-debug-77 ·
actors-and-memory.md:19-21· the platform-ledger inventory. Not re-examined in the verification pass and not in the spot-check sample; the only claim in the audit left at its extractor verdict. - spec-formats-62 ·
artifact-formats.md:1346-1348· whether the PGO finalization key includes the executable-wide site budget and selected profile. The ordinary lane’smach_derivation_keycarries no PGO term (consistent with the first half); the probe found the shop holds 0 PGO profiles, so no finalization key could be observed. - spec-formats-78 ·
artifact-formats.md:1909-1914· “a placement whose last reference goes during teardown leaves the live set immediately”. A lifetime ordering claim over placements underrt->image_lock; no safe read-only command settles it. Wants a C-level test.
Notes from the audit run (not findings about docs/)
- The committed
./pit(Aug 4) could not read the Aug-7 trackedboot.qop— the daemon died with “no content universe: invalid qop archive”, so plainmakefailed. Recovered through the Makefile’s own cold floor (forge-bootstrap→boot/manifest/bootstrap.sh→ forge). Nomake seed, nomake nuke. - New red on dev tip, found in passing: the
numrep-nan32arm failsgc_policytest 3heap_limit_refuses_by_name— “raising the limit did not let the allocation through: out of memory (heap 0KB, block 0KB, limit 64MB)”. Only that one arm was run. - Two probe commands were written against a dead CLI:
pit -e '<script>'now errors ("-e has been removed; pass the script text directly"), andpit --machine '<script>'emitted zero events and exit 1 for a script that works without the flag. scripts/check_arms.sh’s comment citessource/mach_pool_asm_test.c, which does not exist; and 4 of its 14 arms (the kim8 ones) have no fixture row at all.
Source: plans/audit/2026-08-07-docs-report.md