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
pages64
claims1316
MATCHES1095
CONTRADICTS75
OVERREACH12
STALE28
ruled-but-unbuilt89
UNVERIFIED17
docs self-contradictions18 (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

  1. §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.md nine lines below its own statement of it. This is the authority model, and no page states the reconciliation.
  2. §b arch-core-47 — the policy default is fail-open, not default-deny. capabilities.md:129 says a configuration naming nothing grants nothing. pit-shop/policy.ce:194-200 returns {granted: array(ALL_ENDOWMENTS)} when defaults.endowments is null, behind one log line. The doc states the opposite of the code on the one sentence a reader hardening a shop acts on.
  3. §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-12 and :2288-2345 re-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.
  4. §b arch-debug-7 / arch-debug-11 — $inspect has 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-276 reaches 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 unconditional sys_rmutex_lock on the debuggee’s turn mutex.
  5. §b library-40 — crypto.shared is documented with its arguments reversed. crypto.md:73 shows crypto.shared(my_secret, their_public); shoplib/crypto.c:88-99 reads 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}, and crypto.verify takes (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-163slow_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-1552Two hashes name the pool, and a debugger needs bothcontent_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-121pit.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:190pit cement --product presses the cart”; shop/compilation.md:152pit 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:60month 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:92There 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.secondtime.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.0hours — 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@1 mints 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.cart carrying one pit.cart.metadata@2 (pit-shop/cement.cm:80).
  • spec-formats-42 · :918-968 · pit.provider.registry@1 defines a second artifact for the question pit.provider.catalog@1 already answers, plus a cross-invariant tying them together, plus the third bootstrap-local restatement above. Live mechanism is one thing: cake’s extension|… rows in boot/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 built pit.bundle@1 manifest already does (root/catalog/objects
    • detached /signature, shop_realize.cm:1754-1802); the packages selections index restates what pit.executable.manifest@1 and pit.workspace.resolution@1 already decide — which the page itself concedes.
  • spec-formats-16 · :429-442 · pit.package.tree@1 is redundant with the built pit.workspace.snapshot@1’s files map, 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-instruction frame/setarg/invoke decomposition has no producer: every ordinary call goes through emit_call (mcode.cm:1942-1959) emitting one fused call row. The runtime still carries the whole documented-but-unfed lane (MACH_FRAME/MACH_INVOKE), and call/ tail_call — the real thing — appear nowhere on the page.
  • spec-exec-21 · streamline.md:353-359 · “mcode.cm renames the final invoke to tail_invoke”. Both renames exist at mcode.cm:4292-4305, but the invoke branch is a limb with no producer; the live rename is calltail_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, and mach_exec_pgo returns NULL for MACH_EXEC_IMAGE — which since L3 is the shipped lane. The 368-line collector in source/pgo_profile.c plus its two opcodes cannot attach to anything shipped.
  • library-58 · library/io.md:142 · “the raw socket control adds only set_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 as internal/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.cm is 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-198 names 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 · capabilities framed as a live per-target lever. shoplib/features.cm:34-37 says outright: “There is deliberately no per-target table and no per-recipe list: recipe.build.capabilities.daemon was the per-target spelling of exactly this and it is what R9 replaces.” The per-product half of the claim (daemon C swapped for daemon-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)

iddocsaysactually
spec-exec-1streamline.md:8passes 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-4streamline.md:40-67Pass 1 infer_param_typesno such function anywhere; the mechanism moved to mcode.cm:4663-4670 + pit-compiler/resolve.cm (AST-level, whole-program)
spec-exec-5streamline.md:69-112write-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-8streamline.md:147-161Pass 4 simplify_algebragone; folded into another pass (streamline.cm:1970 names it as former). is_identical is not an opcode at all
spec-exec-15streamline.md:256-274all passes run once in sequence in optimize_functionit 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-16streamline.md:280-293push(arr,val) → one opcode; length(x) → one opcodepush 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-19streamline.md:321-336+ propagates to a target only when target == left_slotbroadened 2026-07-07 by 02ac4063b; the page’s Future Work asks for something already done
spec-exec-20streamline.md:340-351pit mcode --pretty, pit streamline --types/--statsstreamline.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-23streamline.md:409-411copy 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-24streamline.md:476-478LICM is unimplemented future workpit-compiler/licm.cm is a first-class pass, switched by pass_on.licm, on in SHIP
spec-exec-25streamline.md:441-448TCO not implementedpit-compiler/tco.cm is a dedicated pass, on in SHIP, satisfying every bullet the doc lists as required
spec-exec-42mcode.md:288-304the same intrinsic-inlining table, duplicatedsame defect as spec-exec-16; must be fixed twice
spec-exec-43mcode.md:308-318labels 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 · 01011 is documented as “Immediate string”; it is PIT_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_NewStringLen returns 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)

iddocstale item
arch-targets-73packages-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-94targets.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-91targets.md:81-84darwin_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-11c-modules.md:100-113Pit_FreeCString(ctx, str)869afc259 dropped the ctx param; the two-arg form appears twice on the page
shop-core-42shop.md:317-320engine is “one unit” — the boot walker was lifted out of C into its own pressed pool, so it is two
shop-core-49shop.md:407-410“std is file and io” — omits actor, crypto, log, proxy, utf8, all fallback-reachable by bare name
shop-core-75endowments.md:139-162the 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-28compilation.md:234-236pit product pit-compiler/mcode.ce — no .ce files exist in pit-compiler; the real product is shop_tools/mcode_tool.ce
spec-exec-58executables.md:37-48modules 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-17artifact-formats.md:450-519the 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-133spec/pipeline.md:178-183the Debug Tools table — zero of its four invocations are runnable; streamline.ce was deleted by 2a43734f9
spec-runtime-134spec/pipeline.md:187-196the 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.

areacountclaim ids
spec/dec64.md (the whole page — no DEC64 rep exists)7spec-runtime-92,93,95,96,97,98,99
spec/artifact-formats.md (unbuilt schema names)10spec-formats-14,39,40,41,43,70,72,75,76,85
architecture/capabilities.md (policy over closures, guest code, sealed player)6arch-core-39,43,44,45,46 + arch-core-35
glossary.md (placement group, $image, alias pins, guest code, extension spec)5arch-core-85,100,110,113,116
architecture/debugging.md ($pgo drain, remote debugger, counter-free builds)5arch-debug-4,33,38,58,66
architecture/actors-and-memory.md (three regions, stone pool, placement on banked targets)5arch-debug-78,79,85,105,106
shop/store.md (the store contract — get_manifest/get_content, backends, fetch)5shop-c-55,56,58,59,60
shop/endowments.md (c_endowments, $clerk/$logger/$args/$shop_path, $start)5shop-core-85,98,99,100,101
architecture/consoles.md (memory table, access modes, tiny/nano targets)4arch-targets-78,80,83,84
shop/compilation.md (pools as layout unit, service table, shipping forms)4shop-dist-15,36,37,39
architecture/boot.md (boot as a distinct deliberately-stupid actor)3arch-build-97,107,118
architecture/build-and-artifacts.md (instrumented pools, PGO consumption, profile provenance)3arch-build-42,44,45
architecture/packages-and-distribution.md (lock.json, alias sources, bundle slices)3arch-targets-68,69,75
shop/packages.md (package as distribution unit, version selectors, lock.json)3shop-dist-69,77,78
architecture/pipeline.md (artifact chain, pit.cart@2 header)2arch-targets-52,63
architecture/cartridges.md (sealed store, extension spec, asset index)2arch-targets-96,101
architecture/target-profiles.md (axis table, val16 nano word)2arch-targets-43,47
architecture/assets.md (locator-reached assets, shadow lint)2arch-core-61,66
architecture/security.md (sealed player, the four-gate table)2arch-debug-152,159
shop/extensions.md (c_native gate, shortened symbols)2shop-dist-42,56
architecture/executable-array.md (three entry kinds, {value} origins)2arch-debug-111,112
singles7arch-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.

pageclaimsmatchcontraoverstaleunbuiltunver
architecture/_index.md11.....
architecture/actors-and-memory.md34253..51
architecture/assets.md1053..2.
architecture/boot.md3936...3.
architecture/build-and-artifacts.md4542...3.
architecture/c-build.md39363....
architecture/capabilities.md18111..6.
architecture/cartridges.md1412...2.
architecture/consoles.md95...4.
architecture/debugging.md756721.5.
architecture/executable-array.md2826...2.
architecture/implementors-guide.md1212.....
architecture/nightly-distribution.md1811....7
architecture/overview.md1010.....
architecture/packages-and-distribution.md1152.13.
architecture/pipeline.md13101..2.
architecture/principles.md1191..1.
architecture/providers.md981....
architecture/recipes.md2221.1...
architecture/security.md22191..2.
architecture/target-profiles.md119...2.
architecture/targets.md119..2..
glossary.md59486..5.
language/_index.md10....1
language/actors.md3231...1.
language/builtins.md2424.....
language/functions.md88.....
language/parallelism.md77.....
language/running.md1515.....
language/semantics.md1586..1.
language/syntax.md29281....
library/_index.md852..1.
library/blob.md23212....
library/crypto.md1376....
library/io.md2928.1...
library/json.md835....
library/math.md66.....
library/random.md44.....
library/time.md1028....
practice/_index.md55.....
practice/ci-inspection.md17131...3
shop/_index.md11.....
shop/c-modules.md5149.11..
shop/compilation.md3934..14.
shop/endowments.md4842..15.
shop/extensions.md2422...2.
shop/packages.md17122..3.
shop/shop.md60525.21.
shop/store.md138...5.
spec/_index.md22.....
spec/artifact-formats.md8863641104
spec/dec64.md801..7.
spec/executables.md1182.1..
spec/gc.md1313.....
spec/kim.md971...1
spec/mach.md1111.....
spec/mcode.md1915112..
spec/nota.md17142..1.
spec/pipeline.md1816..2..
spec/scheduler.md2626.....
spec/stone.md1413.1...
spec/streamline.md2513.111..
spec/values.md1310..3..
spec/wota.md1412.1.1.
total (64 pages)131610957512288917

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)

iddocwhy
arch-targets-30nightly-distribution.md:68-70gitea’s [repository.release] defaults — only the server’s app.ini settles it. Repo-side half is consistent: 4 archives + compatibility.json
arch-targets-39nightly-distribution.md:154-157same, five files / 2048 MB
arch-targets-32nightly-distribution.md:86-92Docker-emulation speed on Apple Silicon. Probe skipped as too heavy (full linux CI lane under emulation)
arch-targets-34nightly-distribution.md:99-104runner-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-35nightly-distribution.md:106-112Alpine host-setup commands; outside the repo entirely
arch-targets-37nightly-distribution.md:129-135act_runner label→image mapping lives in the runner’s own config.yaml. The workflow side is confirmed
arch-targets-40nightly-distribution.md:163-176a checklist of standard shell/Docker commands for the runner host
arch-core-139ci-inspection.md:66-68/actions/tasks — probe returned 404 unauthenticated, indistinguishable from an auth refusal. Needs a GITEA_TOKEN
arch-core-141ci-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-147ci-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-83spec/kim.md:8Crockford 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 to spec/wota.md, which is another lane’s page.
  • spec-formats-87 · artifact-formats.md:2105-2107 · one-line cross-reference to spec/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’s mach_derivation_key carries 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 under rt->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 tracked boot.qop — the daemon died with “no content universe: invalid qop archive”, so plain make failed. Recovered through the Makefile’s own cold floor (forge-bootstrapboot/manifest/bootstrap.sh → forge). No make seed, no make nuke.
  • New red on dev tip, found in passing: the numrep-nan32 arm fails gc_policy test 3 heap_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"), and pit --machine '<script>' emitted zero events and exit 1 for a script that works without the flag.
  • scripts/check_arms.sh’s comment cites source/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