chore(debt): close sixteen Phase 1 debt entries (M1.D) - #81
Merged
Merged
Conversation
Absorbs points 1 and 2 of the cache-saturation arbitration, which were merged as e9371a9 and are not reachable from any ref (cf. RD-1). The -build save and its size measurement are deleted, and the budgets go 55 -> 75 and 20 -> 35. A budget must separate SLOW from HUNG: against a cold windows-2025/ReleaseSafe cell measured at 52-57 min and a cold Debug cell at 21, the previous pair separated nothing. M1.D.8's written hypothesis is refuted before the change, not after. The brief requires the -build restore hypothesis to be settled against the existing logs; measured over 82 ubuntu-24.04-arm/ReleaseSafe job logs in two windows -- 38 from 2026-08-13..08-21, the window the debt was observed in, none of them expired, and 44 from 2026-09-11..09-14 -- ZERO restores landed on a -build entry. 51 landed on a bare sha, 31 were fully cold. The size guard never fired on that cell; the one warning in the set is a tar failure at save time. What the same logs do show is a fully cold restore 12 of 38 then 19 of 44, which is the 129-of-132 recompilation the entry describes. The cause is the absence of the lineage, not its contamination. The all-or-nothing doctrine lived in the removed block and the surviving block referenced it, so it is moved rather than dropped; the three dangling references to the deleted step are rewritten. The superseded budget justification is removed rather than left beside its correction. Verified: YAML parses, the matrix job keeps exactly three cache steps, and every steps.<id> reference resolves. 1200 -> 1094 lines.
M1.D.9, confirmed against the tree then closed. The cache key carried os, mode, zig version and zon hash and NO cpu axis, and neither zig build invocation passed -Dcpu, so both compiled for the runner's native CPU; ZIG_CPU did not appear in the file at all. Both halves move together. A key can only record an axis the build controls, so pinning the key alone would register an axis nothing exercises -- which is why this was left rather than half-done. The archived crossover numbers therefore shift once, being now measured at baseline; the file's own header states the real perf gates run locally on the reference machine and that CI carries the compile-and-run smoke. A live false justification goes with it: the key's comment claimed it shared ci.yml's exact key scheme so the warm cache was reused repo-wide. It does not -- ci.yml's keys carry a precision axis and a per-commit component this one never had, and the two shapes diverged without the claim being revisited. Found in passing and in scope through C1.10: one actions/upload-artifact@v4 against six at @v6, where the allow-list pins @v6 and refuses even @v5 by name. All seven uses across the four workflows now match it. M1.D.14 needs no work: the budget raise is already in the tree at 20 minutes with its margin written at the site. Measured, not inferred: the repository cache stands at 9.94 GiB of its 10 GB ceiling over 31 entries, of which 13 entries and 8.81 GB -- 82 % -- are one single commit's matrix run. Two consecutive commits cannot coexist, so eviction is reached in ONE commit rather than in a handful, which is the mechanism behind the cold restores of M1.D.8 and which no key policy reaches. Reported, not acted on.
M1.D.16 re-posed rather than implemented, which is what the brief asks. The written remedy is not merely written: measured on the tree, a `changes` job already diffs base against head in bash and gates all thirteen cells on its verdict -- stronger than the paths-ignore the entry describes, and failing for the same reason. On a pull_request event the run is about the merge result, so the diff runs from the PR's base; a documentation-only commit on a branch whose earlier commits touched code still yields code=true. Narrowing it to the last commit is a one-line change and a wrong one: the matrix is required per head sha, so a skip would let a merge proceed on a sha whose verdict was inherited rather than produced, possibly from a red run. The honest question is whether this tree's code is identical to one already verified green -- a content question needing a digest and a way to read the earlier verdict. Left to Guy with its cost stated; the bound is now written at the site so it reddens when it falls. Separately, ci.yml carried six lines of French prose, which CLAUDE.md records with its owner named as whoever next opens the file. Measured at exactly six, corroborating the record, and rendered into English. The load-bearing halves were kept rather than paraphrased away: the bash step exists to avoid an action outside the §7.3 allow-list, ci-gate is the single required check, and `skipped` counting as green is what makes the doc allow-list load-bearing. Verified: ci.yml parses, six jobs intact, build-and-test still gated on changes, every steps.<id> reference resolves, and the French measurement re-run on the result returns zero.
The two measurements the arbitration requires before any application, and one of them decides against the lever that was chosen. Cold-time aggregation, widened because the 82 logs of the previous gate are all ubuntu-24.04-arm/ReleaseSafe and carry no per-OS time: 130 successful cells over ten runs, measured on job wall-clock rather than on build+test. In optimising modes the three operating systems sit in the same cold band, 34.7 to 43.5 minutes -- windows is not the outlier the premise assumed. Cold ubuntu ReleaseSafe at 41.0 exceeds warm windows ReleaseSafe at 7.6 by a factor of 5.4, so caching only the four windows cells would drop the wall onto ~41 minutes of cold linux against ~43.5 today. By the switch rule stated with the arbitration, lever (b) falls and the route is (a). Lever (a) needs the composition of the archive, which nobody has read. The decomposition is restored on the surviving final-measure step -- it lived on the post-build step this milestone deleted, and removing it with the step was a loss. M1.D.19, fifteenth occurrence, on this branch: hang signature once, sibling class absent, zero assertions, 312/314 steps, 2255/2283 tests, 45.8 min, conclusion failure not cancelled, sibling precision cell green. The hung executable is fd40064d4ae2024a593b818f42cecad5, a sixth distinct identity matching none of the five recorded. Re-run at the same sha: 13/13 green.
The composition measurement, on all thirteen cells: .zig-cache/o is 96.7 to 98.2 per cent of the archive everywhere, the rest being z, h, b, c and tmp together. On-disk totals 2.55 to 5.49 GB, compressing to the 564-785 MB entries measured earlier. There is no subtree to exclude. The hypothesis behind lever (a) was that linked test binaries form a separable bulk; they do not form a separable subtree -- they live inside o, one hash directory each, mixed with every other compilation output, and dropping any leaves a manifest in h referencing an object that is gone. That is the file_hash FileNotFound corruption this workflow already documents at its save step. The arithmetic is sharper than two lineages: 8.81 GB for one matrix lineage plus 1.72 GB for the rest is 10.53 GB, so ONE lineage and the rest already exceed the 10 GB cap before any question of holding two. Stated with its arithmetic rather than proposed: the largest component of the rest is setup-zig's own cache at 1.16 GB, which was measured being evicted anyway. Reclaiming it gives L <= 4.72 GB, which is seven cells at the measured size -- exactly the seven optimising cells -- and puts the wall on the slowest cold Debug cell at 16.3 min against 43.5 today. Whether that action's caching can be turned off is a property of another repository. Second occurrence of the scheduler park class, with its dump. Neither flake class: hang signature absent, sibling class absent, zero assertions, 10.6 min. Structurally identical to the first -- pending_count 0, chunk_count 13 distributed 4/3/3/3, parks_entered 0 on all four workers, steals_s 0, shutdown false -- and on the f32 leg where the first was f64, so the class is not precision-bound. Two witnesses now exist to check any answer against; reading the scheduler is the next session's work.
The action does not cache a toolchain: it caches .zig-cache itself, the same directory this workflow manages, its tarball being cached separately. Every job that also manages that directory was therefore carrying two layers of one directory, restored one over the other and saved twice. Measured on the job logs already in hand, and the key is worse than supposed. It is weldengine-setup-zig-zigcache-v1-<job>-zig-<arch>-<os>- <version>--<run>-<n>: it carries the JOB name, the architecture and the Zig version, and carries neither the optimize mode nor the precision nor the cpu pin. Three prefixes exist for thirteen cells -- the five ubuntu-24.04 cells share one, the four windows-2025 cells another, the four ubuntu-24.04-arm cells the third. So the tree zig build works on has been a mixture of Debug, ReleaseSafe, ReleaseFast, f32 and f64 outputs from sibling cells: a first-order candidate for the 129-of-132 recompilation, for the 2.55-5.49 GB spread of the archive, and for the f32/f64 asymmetry that was never about precision but about which lineage the shared layer happened to carry. use-cache: false at the five sites whose job manages this directory, four in ci.yml and one in bench.yml. nightly-fuzz.yml is left alone on a measured motive: it has no cache step of its own, so nothing is duplicated there and the argument does not reach it. The comment claiming the action's cache was global and left at its default is replaced rather than left beside its correction -- the same family as the stale justification found in bench.yml. Point 3 applied with it: the per-sha save is conditioned on a push event. On a pull_request, github.sha is the merge commit, which changes whenever either side moves, so a lineage written there names a sha no later run can ask for. Reads are untouched; pull requests keep matching through the prefix ladder.
Both applications verified rather than inferred. The setup-zig overlay is gone: every one of the thirteen cells carried two of its cache lines before and zero after, and the action states it -- "use-cache is false; nothing to save". Point 3 holds: zero matrix cells saved on this pull request run, where thirteen would have. R is measured down by 1.34 GB. The six setup-zig-zigcache entries were runtime_smoke_test 448 MB, bench_ecs_smoke 411 on linux and 352 on windows, vertical_slice_smoke 133 MB, and -- measured, not rounded -- build_and_test at 188 and 184 BYTES. Thirteen cells share one key per operating system and race to save it; one wins and the rest fail, so the matrix half of that layer stored nothing while costing a restore in every cell. L did not measurably shrink and the deltas are not attributable. On-disk totals over twelve comparable cells went 43.32 to 42.14 GB, -2.7 per cent, with movement in both directions and large. Two changes landed together and the after-run restores from a different cache state, so a cell that matched a fresh lineage may now match a staler one. The two big falls are on the two cells that were largest before, which is consistent with those having carried the most foreign content; consistent is not established and is not claimed. The o share reproduces at 96.5-98.1 per cent. Structural consequence: pull request runs no longer save, so the compressed size of one lineage can no longer be measured from this branch. It is measurable on the first push to main carrying these changes, and the cut waits on that number rather than being sized on a state that no longer exists.
Two modifications, no comment added to either workflow. The save condition gains one branch alongside main. With point 3 applied, no pull request lineage is refreshed at all, so a milestone living on one branch across four sessions restores older at every gate and drifts away from its own cache -- the symptom arrived on the first run, where ubuntu-24.04/ReleaseSafe/f64 was still going when the next push superseded it. One branch writes; every other pull request stays silent, which was the object. Second benefit: L becomes measurable from the branch, so the cut no longer waits on a push to main. The full form of point 3 returns at the merge of this milestone, with the cut sized. The key gains a version component, zig-v2-, on the key and on both restore levels at every site that caches .zig-cache -- eight lines in ci.yml, two in bench.yml. The lineages currently in place were written WITH the setup-zig overlay, so they hold a mixture of Debug, ReleaseSafe, ReleaseFast, f32 and f64 outputs; restoring them re-imports exactly what the previous gate removed, and natural expiry will not clear them since they are accessed on every run. One run starts cold, after which a lineage describes what the file actually does. Without it the next measurement of L would still describe the state before. The block asserting "SAVED ONLY FROM A PUSH, never from a pull request" is removed rather than left beside its correction: this commit makes it false. Nine lines.
Measured on run 34886074430: Save Zig cache (final) was SKIPPED on every completed cell while the measure step above it succeeded, and no zig-v2 entry appeared. On a pull_request event github.ref_name derives from refs/pull/<n>/merge and is "81/merge"; the branch name lives in github.head_ref. The clause therefore could not match on a pull request, and on a push it was unreachable since this workflow only triggers push on main -- dead in both directions.
R: setup-zig-zigcache entries now number zero against six totalling 1.34 GB, so that cost is fully reclaimed. What remains is 189 MB of tarballs, 247 MB of non-matrix v2 lineages, and 1.23 GB of v1 leftovers that age out -- R in steady state is about 0.44 GB, not 1.72. L: thirteen fresh entries total 8127 MB against 8.81 GB before, within per-cell variation. Removing the overlay did not shrink a lineage's compressed archive; it was duplicated storage and a correctness problem, never a bloat of o/. And the fact that decides the cut: the optimising cells are SMALLER than the Debug ones, 577 MB mean against 681. Caching the seven optimising cells and leaving the six Debug cold gives 2L + R = 8.33 GB, 1.67 under the ceiling, and puts the wall on the slowest cold Debug cell at a 16.3-minute median against ~43.5 today. By mode, not by OS and not by per-cell size. Two red cells on the cold run, two classes, neither from this gate: f64 carries the hang signature twice with zero assertions and a seventh distinct hung-executable identity; f32 carries the sibling class once, with win32_thread_safety_test.test.concurrent createWindow + destroyWindow failing without output. Per job each carries one class and not the other, so the recorded exclusivity survives; the run-level co-occurrence is new.
The cut, by mode. matrix.mode != 'Debug' gates the restore as well as the save: with the restore left running, the six Debug lineages would be accessed every run and would never reach the seven-day expiry, so restricting writes alone would not reclaim their 4088 MB. Sized on measurement rather than on symmetry. The optimising cells are SMALLER than the Debug ones -- 577 MB mean against 681 -- so caching the seven gives 2L + R = 2 * 3.94 + 0.44 = 8.33 GB against a 10 GB ceiling, 1.67 of margin, and puts the wall on the slowest cold Debug cell at a 16.3-minute median against ~43.5 today. By OS was refuted on wall-clock; per-cell was refuted by o/ at 97 per cent everywhere. Nothing depends on the skipped restore beyond the timing report, whose two uses of its outputs carry a fallback; a Debug cell reports cache_matched_key=none, which is honest rather than a defect. Journalled with it: M1.D.29 with the provenance to replay it -- run 34887367465, windows-2025/ReleaseSafe/f32, hang signature absent, sibling class once, and win32_thread_safety_test.test.concurrent createWindow + destroyWindow failing without output. First time one of these classes yields a test name rather than a binary identity.
13/13 green and the matrix wall falls from ~43.5 to 16.8 minutes. The slowest cold Debug cell is windows-2025 at 16.8 against a 35-minute budget, so the cut holds with margin and Debug needs no second look; the cached cells run 1.0 to 8.3. The prediction was a 16.3-minute median and the measured maximum is 16.8, which is the figure a wall is made of. The ceiling is not respected yet and the reason is transitional: the repository stands at 13.51 GB over 23 entries because the six Debug lineages, 4449 MB, are stale but present -- never written or read again, and not yet at the seven-day expiry. Self-correcting rather than a defect, since eviction is LRU and nothing accesses them any more; the v1 leftovers of the previous gate are already at zero by that same mechanism. Steady state stays 2 * 4039 MB + 0.44 GB = 8.33 GB.
Run 34898572095 on 505a63d, a briefs-only commit. Two red cells, both windows-2025/ReleaseSafe, at cached-cell durations -- so the build ran. They are two different classes, not two occurrences of one test. f32 carries the hang signature once with no test failed and two tests lost, hung executable 1dddaf0a77dab4b512e2547e0aedc439. f64 carries the sibling class once, with win32_thread_safety_test.test.concurrent createWindow + destroyWindow failing without output. The two classes also swapped precision relative to the previous run, so neither is bound to one. The win32 binary identity 513b5cd2dc9c83702db9e4e9ada6b9dd is the same as the previous run's occurrence, where it fell on the other precision. An identical content hash across precisions means the artifact does not depend on -Dphysics_f64, so the precision label carries no information for it: one binary failed in two consecutive runs. Re-run at the same sha: 13/13 green. Known flake class by the entry's own criterion. What the re-run does not settle: attempt 1 matched lineage 76dfc07 and attempt 2 matched 16cdc80, which attempt 1 had just saved. Both variables moved together, so the re-run establishes non-determinism at this sha and nothing about the lineage hypothesis. A forced-cold run at the same sha is what separates them.
Totals re-measured at the opening: ci.yml 579 comment lines in 60 blocks against 525 of program, bench.yml 73 in 9. The 60 against 61 is a grouping edge and no exit criterion depends on it; the named block at l.230 is 72 lines. First pass, mechanical: 25 blocks and 352 lines open on a milestone identifier, 61 per cent of the comment mass. One more than previously counted, the extra being "E5 / C0.8 end-to-end" at l.832. Second pass over the remaining 35 blocks and 227 lines: 12 instances at 9 distinct sites are external guards that stay, 20 blocks and 147 lines are design bound for the corpus, 3 blocks are narrative. Reported rather than quietly compressed: the block explaining use-cache false exists four times, identical, written by the script that applied the previous gate at every call site. It is heap 1 by substance but heap 1 is kept word for word and the extraction exception is three lines, so a five-line block repeated four times is neither. It goes up for arbitration. Nothing deleted in this gate: heap 2 has no other home yet. Also journalled: the same binary identity on both precision legs means that artifact does not depend on -Dphysics_f64 yet is compiled, cached and executed twice. The measurement that decides whether the case is isolated -- counting how many of the 132 test binaries share a hash across one windows ReleaseSafe pair -- needs no new run and belongs to the next S1 gate.
ci.yml goes from 579 comment lines in 60 blocks to 65 in 16; bench.yml from 73 to 27. Program lines are untouched in both -- 525 and 58, identical before and after -- so no step, condition or key moved. Heap 3 deleted without destination: 25 blocks opening on a milestone or gate identifier, three narratives, and the block claiming a subtree of linked test binaries could be excluded from the saved path, which this milestone measured false at o between 96.7 and 98.2 per cent. Heap 2 deleted now that it has a home in engine-platform.md, section CI du depot moteur (normatif): 19 blocks and 147 lines of design and dimensioning. A one-line pointer at the head of the file names that section, with the rule that a change of design goes to the document first. Heap 1 kept word for word, plus four external guards extracted at three lines each under the named reserve: the Windows runners ship no software Vulkan driver; a workflow_dispatch workflow absent from the default branch cannot be dispatched, measured as HTTP 404; the allow-list note on the two cache sub-actions, already three lines and kept verbatim; and the bench's permanent absence of a pass threshold. The four duplicated use-cache paragraphs become one line at each site rather than a paragraph at the first: the guard belongs where the reader acts. Reported rather than resolved: two milestone identifiers survive inside the single block classified heap 1 and kept verbatim. Neither opens a block, so the first criterion holds, but section 12 admits none at all and removing them would be the in-place reformulation this gate forbids. And three bench.yml blocks are heap 2 with no home, so they stay.
Zero identifiers across the three workflows, and the diff carries only comment lines -- checked by filtering the hunks for any non-comment change and finding none. Program lines stand at 525, 58 and 44. The two identifiers inside the block kept word for word were attributions rather than guards: removing them leaves both sentences identical for the rest, and the guard beside them -- version 0.16.x taken literally by the action and resolving to a 404 on the mirrors -- is untouched. nightly-fuzz.yml carried a fourteen-line header opening on a milestone, four identifiers, and an account of a sentence that used to stand there and was false. Deleted, with what no reading of the file provides extracted at three lines: scheduled runs fire only from the default branch, and a workflow_dispatch workflow must also exist there before it can be dispatched, measured as HTTP 404. The three bench.yml blocks stay, deliberately. The owner document was delivered at 907 lines and sha256 33672b04; the copy available here is the earlier one at 887 and bed07c1d. Verifying them is therefore impossible, and deleting on the strength of a statement rather than a reading is what the instruction forbids. The precision measurement cannot be taken from the existing logs: a cell carries 15 zig-cache/o hashes, not 132, the form appearing only on a failed command. The build graph answers more strongly because it derives rather than samples -- physics_f64 is plumbed at exactly three sites, so every test binary whose closure does not reach forge_3d is identical between the two legs by construction. The per-binary count is NOT established by that read and is not inferred from it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The primary key carries the commit sha, so no save is ever overwritten and a run restores the previous lineage then saves the whole of `.zig-cache`, which has no collector. A lineage is therefore a superset of its predecessor and grows monotonically: 577 MB per cell measured cold, then 700, 713 and 734 over three consecutive runs. Convergence does not save it — at 750 MB per cell, `2 x 7 x 0.75 + 0.57 = 11.1 GB` against a 10 GB ceiling. No choice of cell count survives a monotone growth; it only moves the date. The key gains the ISO week, computed once in `changes` and propagated so the thirteen cells of a run share one value. Every rung of the restore ladder carries it, which is what cuts the lineage: measured over the ladder, 26 of 26 entries written in the preceding week are reachable without it and 0 with it, while inside one week 7 of 7 optimising cells still restore their own — the `build.zig.zon` rung included. A lineage lives seven days and starts from zero, so its size is bounded by what a week accumulates. The cost is one cold run per week. The `v2` prefix stays: it invalidates on a change of shape, the week bounds in time, and they are different axes. `bench.yml`'s ubuntu leg and `ci.yml`'s `runtime-smoke-test` rendered the same key byte for byte, and the post step said so — `Cache hit occurred on the primary key, not saving cache`. The key carries every axis that changes the content produced and the job identity is one of them. Rendering every key of the three workflows over the full matrix: 1 collision before, 0 after, 16 distinct primary keys before and 17 after. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The timing report emitted `cache_key=`, a hand copy of the build-and-test primary key. It lied twice in two commits on this branch: 95e66ea added the `v2` epoch to the four key lines and left it behind, 685575b added the ISO week and left it behind again, so it named a string GitHub will never hold, three lines above a `cache_matched_key` that contradicted it. Deleted rather than resynchronised, because resynchronising rebuilds the same trap at the next change of key. `cache_matched_key` carries what was actually served, which is the useful fact and the one the cache debt entry reads; `grep -rn cache_key` over the tree finds no other reader, script or gate. A cell went red with 314 of 314 steps succeeded, no test lost and no assertion fired, because `Upload CI timing artifact` got a 403 from the artifact service. A diagnostic artefact must not decide the verdict of the cell it measures, so that step — and only that step, checked by enumerating every step carrying the field — is `continue-on-error`. The collected-test total stays a hard failure in `zig build test`: that number is an observable of the product, an artifact upload is an observable of the platform. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`ComponentRef` carried `{ chunk_ptr, slot }` on the table arm and the
entity alone on the sparse one, and the table arm's `refBytes` cast the
pointer and read the slot WITHOUT comparing the entity. A handle that
survived a despawn therefore read whichever row `Archetype.removeSwap`
had moved into that slot — silently, with no diagnostic and no error.
The handle becomes `{ entity, component_id, mutable }` for both storages
and every access re-resolves through `World.componentBytes`, which
already answers for both backends from an `EntityId` and already asks the
two questions the table arm never asked. A stale handle now fails with
`BridgeError.StaleComponentRef`, surfaced as a spanned runtime failure
with its own `RuntimeErrorKind` rather than folded into
`UnsupportedExpr`: the expression is supported and the handle is not.
That is `etch-reference-part1.md` §5.3 a — a ref designates a pair and is
re-resolved at every access — and it is what makes §5.3's corollary true:
a ref held by a timer, a `branch`, a `spawn`, a `race`/`sync` branch or
across an `await` is safe and at worst fails loudly. `cloneLocalsInto`
copies a `Value` verbatim into those snapshots, so the handle outlives
the tick by construction and the safety could not rest on a temporal
argument about deferred structural ops.
MEASURED by counter-factual, the chunk anchor restored with the two new
tests in place: the ref to the despawned entity returned
`.{ .float_ = 22 }` — the successor's value — and the write through a
survivor whose row had moved was LOST, the entity still reading 22 where
99 was written. Two distinct failure modes, so the pair is not redundant.
E0223 lands with it, refusing a rule-arena handle captured by a construct
that outlives the rule body (`etch-resolver-types.md` §8.2), checked at
the REFERENCE so the criterion is what the body uses and not what its
scope holds. The predicate is conservative, and the reason is measured:
`let items = [1, 2, 3]` resolves to `array_fixed` and is rule-arena,
while `get(Inv).items` resolves to `array_dyn` and is persistent, so the
resolved type does not carry the zone. A first version keyed on
`array_dyn` alone refused the SAFE case and admitted the UNSAFE one, both
at once. The widening refuses two safe captures — a literal string, a
persistent resource collection — pinned in `escape_false_refusal` so the
frontier is visible; measured cost on the suite: zero. A false refusal is
a compile error the author reads, a missed escape is a use-after-free
nobody sees.
`etch-memory-model.md` §11 owns the provenance analysis that makes the
answer exact; this pass does not compute it.
Test floor re-derived FROM THE SUITE, never from the closure:
`2275/2294 tests passed (19 skipped)` on macOS, 314/314 steps, windows
two lower by the guard's own `only_on = .windows` table. Green at f32 and
f64, Debug and ReleaseSafe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Verdict. `M1.D.5` delivered as documentation, its declared exclusion's cause completed from one Zig 0.16 removal to two, the repair itself still due. `M1.D.6` delivered — 33 tests, coverage 131 to 138 of 203, each verified by mutation — and open on what the instrument does not see. `M1.D.4` re-posed, its written mechanism refuted on source, content and gate. `M1.D.26` re-derived by producer with nothing engraved. `M1.D.15` (a) measured and given an observer; (c) found already arbitrated out in the tree. Two of my own claims were wrong. A NUMBER: the bindgen gate is `M1.D.37`, not `M1.D.35`, and the false one stood in two files because I wrote it twice in one act. A CAUSE, and it is the one worth carrying: I reported a widget block as breaking the grammar's positional-before-named rule when it carries a trailing comma the grammar permits. I took a diagnostic's message for its cause, then generalised the side to the whole class — so six divergences went back to unattributed. The standing result is one finding on four unrelated subjects: a static instrument cannot be complete and an empirical one settles it in one run. Five revisions of a coverage oracle still wrong against an `anytype` parameter; a builder sweep returning zero for an enum with twelve produced variants; `@embedFile` at the grammar failing 11 of 15 blocks; and the smallest form, believing a report instead of producing the observation. Every static reading erred by over-reporting the gap, so none shipped a false green and none could be believed. Also new: a counter-factual on what one asserts cannot move. Swallowing the 32 codes declared unreachable predicted nothing would change, and nothing did. Residuals named where a reader lands on them; the two defects found in passing live at the plan as `M1.D.38` and `M1.D.39` rather than here. S3 delivered 34 tests and ZERO production lines — `src/` gains 29 lines, all comment. Floor re-derived from the suite 2313 to 2348, windows 2346 by the guard's own arithmetic, conservation agreeing independently at 2348 at every gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seven fingerprints verified at 16 hex before any read, all matching weld-spec/, with a control on an eighth file returning a different digest. Two of the seven had moved since the M1.D drop and they are the two S4 needs current; 33 copies of the plan exist across 21 distinct states, so only the digest identifies. M1.D.30's count under the normative unit. Fichier racine binds the root_source_file, so the two arms are a declared module root plus the single file entering a directory from outside its subtree, which is what render/gal/root.zig illustrates. 44 candidates under src/, 25 conforming, 19 not, in two classes the entry merges: 14 module roots not named root.zig, and 5 executable roots not named main.zig carrying pub fn main. The other readings measure something else: 28 counts directories whose files are imported one by one, 69 counts executables the rule sends to main.zig. The lint rule the entry specifies catches none of its own three sites. b.addModule has four real call sites, rooted at core/root.zig, render/root.zig, foundation/root.zig and assets/shaders/embed.zig. forge/module.zig is a b.createModule (build.zig:179); math/math.zig and simd/simd.zig occur in build.zig zero times. The written predicate flags one file tree-wide, outside src/, and none of the three. Third instance of a remedy measured not to reach its subject, after M1.D.16 and M1.D.4. Arm A and the cache.zig discriminant disagree on exactly one file: plugin_loader/desc.zig is a declared module root and is re-exported by plugin_loader/root.zig:16. src/modules/forge/ has no root.zig and three declared module roots side by side (sync.zig:166, module.zig:180, sensor_events.zig:824), so renaming module.zig leaves two beside it. simd's internal imports, which the entry declares non mesurés, measured at zero: foundation/root.zig:11 is the only reference in all of src/. The engine-directory-structure.md claim holds in substance, not letter — the document renders a tree, so the literal path returns zero corpus-wide and :444 carries it. M1.D.25's premise moved and this branch moved it: 15 diagnostics on 10 files against 732/519/146, measured with zig-out/bin/weld_lint, which visits 221 of 249 files there. The exclusion is spelling-dependent and its only direct caller is dead code. M1.D.28's figure is not reproducible and M1.A, its referral target, has closed. M1.D.11's ten is the set that installs, not the site set: 42 mains, 10 installing. M1.D.1 is out of scope by the brief's own line, its deliverable being a new capability. M1.D.12's deferral condition is met by interfaces/PhysicsModule.zig. M1.D.7's ratio is arithmetic over a capacity the tree derives by search. M1.D.2's premise is contradicted at 52 646 ns against a 62 000 gate nothing enforces. M1.D.3's 7-58 % on Fedora has no witness in the tree. No rename. It waits on a discriminant that owes a number: a rename leaves the fingerprint unchanged under a different path, and until fingerprint --check can tell a move from an edit, the only mechanical fix is the one tools/weld_lint/main.zig:317-320 forbids in writing. Floor re-derived FROM THE SUITE: 316/316 steps, 2329/2348 passed, exit 0. zig build lint exit 0, conservation OK at 2348. zig fmt --check exit 0. 154 lines added, all markdown; zero production lines changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.40. `fingerprint --check` reported every absent baseline path as MISSING and printed one remedy for it — undo the code edit that produced it — which names an act a deliberate `git mv` has not performed, while the same text forbids regenerating the baseline. Both exits were closed for a rename. The discriminant costs nothing: `census.fingerprint` takes `source` and never the path, so a displacement leaves the digest bit-identical. A baseline path that vanished while an unlisted file of the same run carries that exact digest is a rename, and no token moved. `census.classify` is the split, pure and testable: `.moved` (same path, other digest), `.renamed` (gone, exactly one unlisted file at that digest), `.ambiguous` (gone, several), `.missing` (gone, none). Only a resolved rename does not fail. The pairing must be UNIQUE to be a verdict — digests are unique across this tree today, measured at 336 of 336, but that is a property of the tree and not of the function, and two empty files collide at e3b0c442, the sha256 of nothing this milestone's own register names as a disguise. The trailer is now one remedy per outcome. A single text over three of them is the same defect one level up: it would name an act two of the three readers have not performed. Seven witnesses, and two counter-factuals rather than one, because the first prediction was wrong and is corrected rather than adjusted. Removing the digest LOOKUP reddens the rename case AND the ambiguous case — ambiguity is that same lookup's other outcome, not a neighbour — and the panic it raises truncates the run, so two tests go unobserved. Keeping the lookup and refusing to RESOLVE a unique pairing isolates the decision: red on the rename alone, green on the other six including ambiguity, all reached. census.zig restored bit-identical after each. End to end on the binary: rename only exits 0 RENAMED; rename plus one changed token exits 1 MISSING; an edit under the original name exits 1 MOVED; an added comment stays green; two unlisted candidates exit 1 AMBIGUOUS. Floor re-derived FROM THE SUITE, not from the closure, which is what the conservation message prescribes: `zig build test --summary all` reports 2336/2355 on macOS, and the closure agrees independently at 2355. Windows 2353 by the guard's own only_on table. 316/316 steps, exit 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.30, two of its three named sites. `engine-zig-conventions.md` § *Fichier racine* makes `root.zig` the root of every module and sub-module and cites `render/gal/root.zig` as the sub-module case; `math/math.zig` and `simd/simd.zig` were that shape under the directory's own name. Measured before touching either. Neither appears in build.zig at all: they are entered only from src/foundation/root.zig:8 and :11, one line each, and the resolved-import referrer set of each is exactly that file. No sibling imports either by name. Both already carried the canonical root shape — doc header, private import layer, doc-commented re-exports, comptime pin block — so nothing but the file name moves. Their headers name the DIRECTORY and stay true. build.zig:443 named `simd.zig` in prose and is corrected; a path-anchored selector cannot see that class, which is how it was missed at G1. The five build.zig occurrences of src/foundation/simd are tests/ and bench/ roots, none of them this root. Residual references to the old spellings outside briefs/: zero. Inside briefs/: eight files, NOT edited — a brief is a dated record, and that includes the two m1.E-*.tsv baselines under briefs/artifacts/. `fingerprint --check` now reports both as RENAMED with the digest unchanged, which is what M1.D.40 was for and what the previous code called MISSING. src/modules/forge/module.zig is NOT renamed. Measured: that directory has no root.zig and build.zig declares THREE modules over it — sync.zig:166, module.zig:180, sensor_events.zig:824 — published as three names to different consumers. Renaming one leaves two declared roots beside the new root.zig, which moves the defect rather than closing it. Reported, not arbitrated. 316/316 steps, 2336/2355 passed, exit 0. lint exit 0, conservation OK at 2355. fmt exit 0. Added: 191 code, 45 comment across the gate; both renames carry a zero-line diff, git recording them as pure renames. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.40 delivered and two of M1.D.30's three sites renamed. The record carries what the gate measured rather than what it intended. The lot was not opened, third time this milestone: announced 7b6e8734 on no copy, weld-spec carrying the announced line count at 640 with e80c0e2e. G2 did not depend on it. The correction that matters: at G1 I called the fingerprint step a blocker a rename would turn red. Measured here, it reports 54 diverged, of which 20 were already diverged at the branch base by content identity, and nothing runs it in CI or a hook. The mechanism was exact and the consequence was never measured. Two counter-factuals rather than one, because the first prediction was wrong: removing the digest lookup reddens the rename case AND the ambiguous one, and its panic truncates the run so two tests went unobserved rather than green. The second mutation isolates the decision from the mechanism. A tooling fact: zig build truncates a failing step's captured output — 50 MOVED lines printed against a summary of 54, where the binary run directly prints 54. forge/module.zig measured and not moved: no root.zig in that directory and three declared module roots published under three names, so renaming one leaves two beside it. Three readings, none arbitrated here. One over-match of my own inside this gate's measurement: a bare-basename sweep credited forge's sync.zig with a referrer that imports gal/vulkan/sync.zig. Floor 2348 -> 2355 from the suite, windows 2353. 316/316, lint 0, fmt 0. Decount by diff-density: 191 code, 45 comment (31 doc), density 19.07%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.25, both defects it does not carry. The exclusion was spelling-dependent and the defect was wider than the perimeter. `inPerimeter` verdicts on the first real segment, so for /Users/.../tests that segment is `Users` and the excluded subtree came back inside: `lint tests` exited 0 where `lint $(pwd)/tests` exited 1 with 15 diagnostics on the same files. Measured while fixing it, the same absolute argument also made `fingerprint` write a machine-local path into the baseline — the hazard census.normalizePath already answers for separators — and `census` emit rows nobody can key on. One contract broken in three subcommands. Refused at the walk root rather than repaired downstream: the repo root is not knowable from a path, so any normalisation here would be a guess. `scan.isRepoRelative` plus one check in `scan.collectZigFiles`, the single choke point every call site passes through. `walkRoots` reports it rather than propagating, because a returned error reaches the user as a stack trace and the thing worth saying is which spelling to use. Witness end to end: `lint tests` 0; `lint $(pwd)/tests` 2 with the spelling named; `lint ./src/foundation` 0; census and fingerprint on an absolute root both 2. Nine assertions on the predicate, including the non-vacuity pair that a bare colon is not a drive letter. The only direct inPerimeter caller was unreachable and is removed: main.zig reported each `pending` entry under `if (pending.len != 0)` while `pending` is empty and noPathOutsideCoverage asserts it stays empty. Thirty lines cut. matchesPending went with them, a pub one-line wrapper over hasPathPrefix whose own doc named that block as its caller. Test removal declared: no assertion is lost. matchesPending's six assertions across three tests are re-pointed at hasPathPrefix, the primitive they were always exercising, under the same names. What a re-opener owes is written at `pending` — the reporting loop must come back with the entry. collectPaths is deleted with it; walkRoots serves lint, census and fingerprint from one path and main.zig is 12 lines shorter net. doc_comments caught a defect in this change: the new function was inserted between collectZigFiles' doc comment and its declaration. Found by the suite, not by re-reading. Both docs now sit against their own declarations. Floor re-derived FROM THE SUITE 2355 -> 2358, windows 2356. 316/316 steps, 2339/2358 passed, exit 0. lint 0, conservation OK at 2358. fmt 0. Decount: added 70 code, 39 comment (32 doc), density 35.78%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Fourth fingerprint mismatch, not opened: 973a680a on no copy while weld-spec carries the announced line count at 642 under ba6ae827. The three G3 rows were read at G1 under the verified 0bc203ca and are byte-identical at the same line numbers, and the lot's changes name 30, 40, 41, 42. M1.D.25 — 15 diagnostics on 10 files against 732/519/146, the instrument enumerating 221 of 249 there. Both defects the entry does not carry are closed: the spelling-dependent exclusion, which also made fingerprint write machine-local baseline paths and census emit unkeyable rows, and the unreachable pending report. Test removal declared, no assertion lost. M1.D.28 — 703 nested undocumented pub across 111 files, measured with the rule's own predicate through its own plumbing, probe reverted bit-identical. 512 matches no perimeter: src 669, +tests 687, all 703, modules+core 504. The restriction is a named suppression rather than an omission, and the referral target M1.A has closed, so the deliverable has no holder. M1.D.11 — the ten is the set that INSTALLS, re-measured: 42 column-0 pub fn main of which 7 reference float_env, and 3 of 4 src/ thread spawns in production, all installing. So 35 mains install nothing and the entry's "c'est la garde qui est différée, pas la conformité" is false at the predicate's own scope. The boundary is literally src/: all 7 are under it, and the 18 bench/*.zig reference float_env zero times including the float-heavy physics benches, while their two siblings under src/foundation/simd/bench do install. The guard is not written here because it would redden 35 sites on its first run, which is the mechanism M1.D.28 records one entry above. doc_comments caught a defect in this gate's own change, found by the suite. Floor 2355 -> 2358 from the suite, windows 2356. 316/316, lint 0, fmt 0. Decount: 70 code, 39 comment (32 doc), density 35.78%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.1, what remains after its deliverable is removed as out of perimeter — a first exercising implementation is a new capability. The header of api_stub_test.zig reads "a silent addition, removal or rename of a callback breaks the test". The file calls all 79 callbacks BY NAME and holds zero occurrences of @typeinfo or std.meta.fields, so a removal or a rename stops it compiling and an ADDITION is never called. Two thirds true on the file the repository treats as the freeze's documentation. A count assertion over the seven surfaces closes it: 24 / 8 / 6 / 2 / 8 / 17 / 14. The counter-factual's GREEN branch carries the proof: a ninth stub-defaulted field on WeldMemoryAPI, reusing an existing stub so the mutation compiles, reddens ONLY the count test (expected 8, found 9) while the by-name "WeldMemoryAPI: all stubbed" test stays green — which is exactly the hole. So nothing in the repository detected a silent addition before this; no size pin on the C surface fires. The by-name half is genuinely exhaustive, audited rather than assumed: every field of all seven sub-APIs is called, zero uncalled. Only the addition clause was false and the header is now true as written. CLAUDE.md:117 said the tree has exactly ONE site handing a plugin a table. Measured, four: loader.zig:158, :202, :268, :287. The ordering argument is untouched and now precise — one, the entry at :202, hands the table before the version check at :208/:215, the other three are post-check lifecycle callbacks. Two faults of my own, both in this gate's instruments. The field count came from a grep whose class [a-z_]+ has no digits, so draw_vec3_edit never matched and WeldEditorAPI read 16 where it holds 17 — the same character-class defect recorded at S1/G4 for forge_3d_tests, caught only because the assertion was written against the compiler. And the first counter-factual named a stub that does not exist, failing to compile for a reason unrelated to what it tested. Floor re-derived FROM THE SUITE 2358 -> 2359, windows 2357. 316/316 steps, 2340/2359 passed, exit 0. lint 0, conservation OK at 2359. fmt 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.7's tree side. bench/results/ecs_hybrid_crossover.md reads "chunk compaction is INTRA-chunk only and `archetype.zig` releases no chunk, so the count follows the cumulative number of adds and never the live population". The first clause holds. The second does not: releaseChunkIfEmpty frees a chunk at zero occupancy (archetype.zig:381) and World.reclaimChunk performs the renumbering repair (world.zig:1173), both delivered at S2/G2 of this same milestone, AFTER those numbers were taken. A head note on the M1.B/G11 precedent rather than a refresh: the figures are the record of the run that produced them. What is corrected is the mechanism sentence, because M1.D.7's oracle would otherwise inherit a claim the tree contradicts. What reclaim does NOT do is compact a chunk that stabilises above zero, which is the shape this report measures. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.1 is out of perimeter for its deliverable, a new capability. Its two remaining defects are closed: the freeze test that claimed to catch an addition and could not, and CLAUDE.md's one-site claim where four sites hand the table. The counter-factual's green branch carries the proof — a ninth stub-defaulted field reddens only the count test while the by-name test passes. M1.D.12's deferral condition is met by interfaces/PhysicsModule.zig, and its cost figure measures work a move does not do: one @import in the whole tree, so the move is one git mv plus one line, not eleven rerouted sites. Not moved — where the engine's world scalar lives is the class of decision ruled outside a rename's mandate for forge/ at G2. M1.D.7: the capacity is derived by search and not by arithmetic, so a ratio can be right about the number and wrong about the method; the denominator an oracle needs has zero call sites. A committed report it would cite carries a head note. Two faults of my own, both in this gate's instruments: a character class without digits, the same defect recorded at S1/G4, and a counter-factual that died of its own compile error before testing anything. Floor 2358 -> 2359 from the suite, windows 2357. 316/316, lint 0, fmt 0. Decount: 19 code, 10 comment on the .zig files, density 34.48%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.3's engine side. threading.zig read "Used by the job system scheduler (worker pinning)". Measured: setAffinity has ZERO production callers. Every reference in the tree is its own declaration, its own inline test, core/root.zig:57's re-export comment, or tests/platform/threading_test.zig, and src/core/jobs/ names affinity or pinning zero times on a whole-word match. The Windows SetThreadAffinityMask arm and the Linux pthread_setaffinity_np arm live entirely inside this file, and the macOS arm is a documented no-op. The header now states that, and the consequence a bench protocol meets: the mechanism exists, nothing calls it, and pinning is reachable only on Linux and Windows where no orchestrator runs today. lint caught the first draft of this comment naming a milestone identifier, which engine-zig-conventions.md §12 admits in no file. 316/316 steps, 2340/2359 passed, exit 0. lint 0, conservation OK at 2359. fmt 0. Floor unchanged, which is expected for a comment-only change and is stated because it was measured. Decount: 0 code, 9 comment (9 doc). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
M1.D.2's band is misattributed in both halves, verified at the source rather than inherited. M0.8 holds zero S1 mentions and zero microsecond figures; M0.9 mentions S1 five times and holds zero occurrences of the band. Both endpoints are M0.1, and that brief diagnoses each where it reports it: 69.2 is a cold-start first run with followers at 41.7-42.2, and 89.1-91.5 is --workers=14 with "the S1 bench is an undersized workload for 14 workers" stated in the same paragraph, while the same document measures --workers=4 at 51.5 / 52.3 / 52.5. The gate itself is a double derivation, 62 = 57.2 + 5 where 57.2 = 54.5 x 1.05, every term descending from the 2026-05-09 spike figure. M1.D.3: the engine claimed a mechanism it does not have, corrected in place. The position asked for on an unenforced gate: NEITHER a measurement debt nor a CI debt. The first licenses re-basing a derived constant nothing consults. The second licenses CI enforcement, which cannot supply the protocol that makes the number mean anything, and which M1.1.9 already retired four wall-clock assertions over. What it is: an authority defect. The wrapper enforces the measurement's CONDITIONS and reports its VALUE, so enforcement is correctly placed; the constant calls itself the live gate while its only possible enforcer declines to act on it, and the producer the entry asks for already exists in that same orphaned script. Recommendation recorded, decision Guy's. M1.D.37 reproduced live by ordinary work: the comment-only edit reddened the bindgen gate. Content identical throughout, unstaged 2339/2359 with one failure, staged 2340/2359 green — isolating the cause to the index comparison. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The journal and the five rubrics. No program line: 188 markdown lines, zero .zig files touched. FIVE premises were false AT DEPOSIT — M1.D.30's lint predicate reaching none of its own three sites, M1.D.28's 512 which the same predicate read at 1384/730 at the commit that wrote it, M1.D.11's claim that only the guard was deferred against 35 entries that install nothing, M1.D.2's band attributed to two briefs of which one holds zero S1 mentions, and M1.D.3's Fedora figure with no witness in the tree. TWO more were made false afterwards: M1.D.25's 732/519/146, exact at M1.E and reduced to 15/10 by twenty-two commits of this branch, and M1.D.12's "no second consumer", satisfied by interfaces/PhysicsModule.zig at M1.1.15.2. The distinction separates an entry that was wrong from an entry the world moved under. FOUR OF THE NINE COUNTED A DIFFERENT SET FROM THE ONE THEY NAMED, and that is the class rather than staleness: M1.D.11's ten counts the sites that install, M1.D.12's eleven counts alias occurrences a move never touches, M1.D.30's three is derivable from no reading, M1.D.2's band counts a cold first run and a --workers=14 measurement where it names the machine at rest. In each the number is correct about something, which is why it survived review — a wrong figure invites arithmetic, a figure over the wrong set invites agreement. SIX faulty selectors of mine in one session, of which this record carried FOUR: G1's glob off by one and G5's -i pinning matching spinning lived in session messages and not in the brief until now, which is the milestone's own subject applied to its own journal. What caught five of the six was an instrument fired beside the selector in the same execution on a case known to exist; the sixth was caught by refusing a grep where a compiler could answer. The C-ABI freeze's green branch is the whole proof: a ninth stub-defaulted field reddens only the count test while the by-name test passes, so nothing in the repository saw a silent addition to a frozen ABI. Residuals named where a reader lands on them: M1.D.41's sixteen sites, M1.D.42's forge case, and the four S4 entries that stay open with their deliverable stated. Floor 2313 -> 2348 -> 2359 across S3 and S4, re-derived at every gate. 316/316 steps, 2340/2359 passed, lint 0, fmt 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
R1 is widened BY DERIVATION from `Value`'s rule-arena variants, not by adding the arm the report named: `.closure` and `.struct_t` were missing too, and treating the named case would have left both. `Value.optional` is a per-body store handle WHATEVER its payload, so `?int` escapes exactly as `?string` and refusing every optional is exact rather than over-refusal. R2 gives both arms one `ComponentDesc`. The `orelse` arm is structurally unreachable — measured, the registry has exactly one entry-append site and it always derives the digest — so its direction is free and it now REFUSES: an unknown layout is not a matching layout. Same arbitration carried to the two other `orelse` arms of this lot. R3 takes OPTION A, arbitrated by Guy on measurement: pre-validate every declared schema before the first mutation. `schemaDigestOf` does not hash `default_bytes`, and `compileTypeDecl` splits exactly there — 70 lines that mutate nothing outside their locals against 64 that materialise defaults and allocate immortal blocks the digest never reads. So the pass needs no cached intermediate and no double allocation. It also closes R2's site: the `TagSet` refusal fires AFTER Pass A, so refusing it where it is met strands every type the program declared. Two per-site fixes covered neither; one pass covers both, and the counter-factual reddens both tests. What it does NOT close is named: an `OutOfMemory` mid-pass still half-registers. R4 sweeps the class rather than its two named instances: `setBodyTransform` carries the same partial commit as `moveKinematic`. R5's fix is to make both walks read the CURRENT visited set and continue past a silent field; on `main` `reasonOf` follows only two forms, so the asymmetry is a defect of M1.D's own widening. R6's uniqueness becomes two-sided, counted and not consumed. AN INTERNAL ADVERSARIAL REVIEW THEN CONFIRMED SEVEN FINDINGS, ALL AGAINST CODE WRITTEN THE SAME DAY. `setBodyTransform`'s new early return made `sync_in` count a pose write and a wake that no longer happened, under a comment declaring the wake composed "unconditionally" — closed AT THE SEAM, which normalises first through the one predicate and counts the refusal apart, leaving the frozen signature alone. Both forge doc contracts still named a stale handle as the only no-op. `Interpreter.init` does not exist; the entry point is `Interpreter.compile`. `engine-etch-*` names no file in the corpus — a fabricated citation, removed. `schemaDigestOf` hashes neither `storage` nor `requires` either, so two of `schemaDigestFor`'s three inputs were inert and the pass allocated `@requires` names for nothing. `.ambiguous.count` had changed meaning while all three consumers still declared the old one. And the stated reason for excluding the builtin time resources was false: nothing reserves those names. Two more found by me. `reasonOfIn` kept an `else` where `carriesMarkedIn` is exhaustive, which would let the next divergence compile silently — the R5 class rejoined; and R1's "adjacent case" test captured an int, clean because an int is POD, the CONTRARY reason to the uncovered one. It stands as a non-vacuity control and the boundary is declared in writing instead. Three tooling incidents, self-reported. A background `zig build … | tail` reported exit 0 while the build failed with 1. Counts taken while another build ran gave 2371/2372/2369 with phantom failures. And a review subagent wrote `tests/etch/zz_probe_verify_test.zig` into the tree and registered it in `build.zig`: the symptom is a collected total that CLIMBS while nothing of mine changed. Workflow stopped, `build.zig` reverted, all ten tests verified mine. Floor re-derived FROM THE SUITE once, at the end, measured three times for that reason: 2350/2369 on macOS, windows two lower. `zig build lint` conservation OK. Forge green at f32 and f64, Debug and ReleaseSafe; full suite green at Debug and ReleaseSafe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
THE JOURNAL AND THE FIVE RUBRICS. Four sessions, 97 commits, 245 `.zig` files and 4 `.md`. Sixteen entries closed by the milestone itself — three in S1, six in S2, seven in S4 — two already closed before it, twenty-nine of forty-seven still open, and SEVEN of those forty-seven minted during it. A debt table that grows while it is being emptied is what measuring produces when the measuring is real. THE MILESTONE'S OWN DESCRIPTION WAS FALSE AND IS CORRECTED WHERE IT LIVES. `CLAUDE.md` called it "a documentation and instrumentation milestone: no program line is delivered". Measured at close: 245 `.zig` files changed, floor 2290/2288 to 2369/2367, and two rewrites under frozen surfaces. True when written; the world moved under it. The brief's frozen Scope never said it — it refuses a new CAPABILITY, which six fixes and a pre-validation pass are not — so this is a `CLAUDE.md` correction and not a deviation. SEVEN INTERNAL REFUSALS, ALL AGAINST CODE WRITTEN THE SAME DAY, and that is the result of this gate more than the six corrections. An adversarial review — five reviewers by dimension, each finding handed to a verifier charged with refuting it — refused the G6 closure seven times. The two that carry: `setBodyTransform` gained an early return while `sync_in` counted `poses_applied` for a write that no longer happened, under a comment declaring the wake unconditional; and both frozen doc contracts in `world.zig` still described a stale handle as the only no-op. The costliest class in this repository, committed inside the correction that was fighting it. TWO FABRICATIONS OF MINE, both found by the review and neither by me. `Interpreter.init`, which does not exist — the entry point is `Interpreter.compile`; and `engine-etch-*`, cited as the pre-validation pass's sole normative justification while naming no file in a corpus `CLAUDE.md` enumerates exhaustively and forbids guessing at. THE SUBAGENT CONTAMINATION, AND THE SYMPTOM THAT CAUGHT IT. A review agent wrote `tests/etch/zz_probe_verify_test.zig` into the tree and registered it in `build.zig`. What exposed it was a NUMBER THAT MOVED: the collected total climbed 2369 → 2373 → 2375 across runs in which I had added no test. An instrument that counts more than it was given is a contamination, never a progress — and it reads differently from cache contention, which makes the total VARY in both directions with phantom failures. The rule had been in memory since M1.1.1 and did not fire: a rule in memory does not execute itself, only an observable symptom triggers it. The symptom is now written beside it. Two more tooling incidents, self-reported: a piped background `zig build` reported exit 0 for a build that failed with 1, and a counter-factual on a comptime function compiled clean under `zig build` alone, which does not analyse it — repassed through `zig build test` it gave "switch must handle all possibilities". A SECOND NUMBERING COLLISION IS REPORTED AND NOT ARBITRATED. The plan numbers `M1.D.17` the Etch reload debt closed at G6; `CLAUDE.md` carries a different debt under that number, which the plan carries under none — measured on the delivered lot, zero occurrences of `buildSchemaRemap` or `.sav` in 646 lines. M1.E corrected a first such collision; this is a second. The table belongs to the corpus. FLOOR DERIVED ONCE, AT THE END, and measured three times for the reason above: `2350/2369` on macOS with the closure arriving at 2369 independently, 2367 on windows. Entry floor was 2290/2288, so the milestone adds +79 tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A one-line correction to the milestone row written moments earlier: it named `b18f5c10`, which is S2's close, for S4's. Verified against `git log`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
guysenpai
marked this pull request as ready for review
September 19, 2026 11:11
A SECOND external NO-GO, on two P1 the first had not reached. Both were closed by the same realisation: the type checker was treating an ABSENCE of information as a guarantee. P1-a. The `.optional` and `.some_lit` arms return `.unknown` whenever the payload is not a builtin, and `isRuleArenaType` answered false for it — so an optional carrying a struct reached a captured body with the program type-checking ENTIRELY clean, zero diagnostics, while the optional store is reset at the rule body boundary. The cost was an abort reachable from ordinary code. I had named that case an accepted adjacent one, on the ground that `.unknown` "is the statement that the type is unknown". It is not: the tag carries two meanings — the fallback after a diagnostic, and a deferral emitted with no diagnostic at all — and the reasoning silently assumed the first. That is the exact limit of the green twin as we had just completed it: naming the adjacent case is not enough, it must be shown SAFE and not merely outside the treated one. Both options were measured before the arbitration. Preserving the lifetime information needs a recursive payload — `optional` carries a `BuiltinType`, not a `ResolvedType` — across 105 sites in 7 files, against a deferral documented as deliberate. The conservative refusal has ONE production reader and costs one false refusal, then zero once a separable third gap is closed: a fixed array had no method arm at all, so `items.len()` fell to `.unknown` where the dynamic array, map and set arms each answer `int`. That arm lands here too. P1-b is a missing capability and not a fix. `openEscapeWindow` has three callers and `EscapeSite` declares six variants, five produced — `async_frame` had its slot reserved and no producer, so no widening of the predicate could ever have reached it. `etch-memory-model.md` names that site explicitly, in a correction dated 2026-09-10; the contract existed and the implementation did not. Reproduced as an abort on the array store, with the type checker accepting the program first. The review's witness is better built than ours: the async rule alone passes, and it is the neighbouring SYNCHRONOUS rule whose body-end reset invalidates the suspended local. A test exercising one rule masks the class by construction, so every test here carries that neighbour. The upper bound ships — every rule-arena local in scope at a suspending `await`, read afterwards or not — because the refined rule is not liveness but a syntactic walk of the following statements, which an indirect read through a closure or a branch crosses unseen. Its measured cost is two false refusals, each verified genuinely safe rather than assumed so, one of them by rebuilding the program with a neighbouring rule and watching it pass. AND REFUSING `self` IS WARRANTED, NOT CONSERVATIVE. The measurement showed the rule also reaches the `self` of an `async fn` on a struct, so the deciding program was written: a method reading `self.base` AFTER its `await`, with a neighbour, ABORTS on the struct store. The existing test survived only because it read `self.base` before suspending. The consequence is named rather than hidden — an async fn on a struct receiver that suspends is now refused — and that test becomes a free `async fn`, its replaced assertion named at the site. Counter-factuals: removing the predicate reddens P1-a; disabling the refusal reddens both P1-b tests while the green twin stays green, which is what shows the refusal targets rule-arena storage and not suspension. Floor re-derived FROM THE SUITE once, at the end, measured twice: 2354/2373 on macOS with the closure agreeing independently, 2371 on windows. Green at Debug and ReleaseSafe. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
THE JOURNAL AND THE FIVE RUBRICS. Four sessions, 100 commits, 245 `.zig` files and 4 `.md`. Measured on the delivered lot: 47 entries, 18 closed of which SIXTEEN by this milestone (3 in S1, 6 in S2, 7 in S4), two closed before it, 29 open, and 7 of the 47 minted during it. The milestone's own premise did not survive it. It was described as delivering no program line; at close it had changed 245 `.zig` files, moved the floor from 2290/2288 to 2373/2371, and rewritten two paths under frozen surfaces. Corrected where it lives rather than left standing. TWO EXTERNAL NO-GOs REOPENED THE CLOSURE. The first, six defects: a type predicate missing three of the seven rule-arena shapes, a hot reload reusing a component id without confronting its schema and confronting it per declaration, a kinematic move deriving its angular velocity from a rotation the store normalises or drops, a reason walk and its predicate reading different visited sets, and a rename check establishing uniqueness on one side only. The second, two P1 of a class the first had not reached, and the class is what matters: the type checker was treating an ABSENCE of information as a guarantee. An unresolved type reached a capture unrefused with the program clean of every diagnostic, at the cost of an abort from ordinary code; and a rule-arena local living across an `await` opened no escape window at all, `EscapeSite` having declared the variant and never produced its producer. Between them, an internal adversarial review refused a closure seven more times, every finding against code written the same day — two of them this repository's costliest class, committed inside the correction that was fighting it. THE STANDING LESSON, AND IT OUTLIVES THE MILESTONE. A green fix with its counter-factual establishes its own case and nothing more. The two reviews found EIGHT defects in fixes delivered green, THREE of them in entries marked closed. Every one of those fixes had a counter-factual and every counter-factual was correct: it showed the fix had power over the case it treated, and said nothing about the neighbouring one. The green twin's missing half — naming the adjacent case — was instituted at the first NO-GO. The second showed that naming is not enough either: `.unknown` had been named an accepted adjacent case WITH a reason, and the reason was false. An adjacent case is shown safe; it is not declared safe. The form that showing takes is the one the last gate used without being asked. When the measurement revealed the refusal also reached the `self` of an `async fn` on a struct — a case the arbitration had not seen — the deciding program was written rather than the case filed as an assumed cost. It aborts. The refusal was warranted, and the pre-existing test survived only because it read `self` before suspending. Also recorded: the subagent that wrote into the tree, caught by a collected total that CLIMBED while nothing of mine changed; two fabrications of mine, a symbol that does not exist and a spec file that names nothing in the corpus; and the pipeline-exit-code family reaching FOUR in one milestone, the fourth arriving after the first three were written into this brief — a rule recorded does not execute itself. Floor derived once, at the end, measured twice with no concurrent build: 2354/2373 on macOS with the closure agreeing independently, 2371 on windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A THIRD external NO-GO, and a fourth kind of defect: the predicate was right and
the SET it walked was wrong. `refuseArenaLocalsAcrossAwait` iterates
`ctx.locals`; a loop variable is an `int`, so it answers false on it, while the
`ForFrame` retains a handle to a temporary that is nobody's local. That is the
unit error this milestone documented four times already — `M1.D.11` counting the
installing set, `M1.D.12` alias occurrences, `M1.D.2` a cold machine, `M1.D.30`
three sites derivable from no reading — with the fifth instance inside the fix
written to close the fourth.
ENUMERATED FIELD BY FIELD RATHER THAN GIVEN AN ARM. `AsyncFrame` has seven
variants; exactly two retain something that can be a per-body store handle —
`ForFrame.iter`, whose `.array`/`.map` forms carry a `handle: u32`, and
`CallFrame.scope`, already covered since G8's `self` is that field. The other
five carry offsets, cursors, NodeIds and StringIds. A read-only verification pass
confirmed the enumeration cell by cell and found, beyond the frames, that the
runtime unit is frames plus locals plus result plus captured filter values.
THE REFUSAL'S SHAPE WAS DECIDED BY MEASUREMENT, NOT BY PREFERENCE. The resolved
type does not carry the storage zone, measured cell by cell: an array literal and
a local holding one resolve `.array_fixed` and no resource path produces that
type, since a resource fixed-array field is not a collection field at all and its
read is `undefined_symbol`; but `.array_dyn` carries both a resource slice and
`let xs: int[] = [1, 2]`, and `.map_t` carries both a resource map and a local
map literal. A first form refusing everything but `.range` cost a CAPABILITY —
no resource collection iterable in an async rule — which is not a false refusal.
So the rule covers `.array_fixed`, the half a type can decide, at zero measured
false refusals; the rest is named and pinned.
TWO LEAKS THE FIRST COST MEASUREMENT MISSED. `conc_loop_depth` resets at three
boundaries and the new counter reset at none: measured, `for x in [..] { branch {
await ... } }` produced a false refusal, a branch body running on a child task
with its own frame stack, and a timer body produced a second diagnostic on a
program already refused by E0901. Both closed at the same three boundaries,
re-measured at zero. A counter that does not know the boundaries of its subject.
The diagnostic names no variable, because naming one would be false: `x` is the
element. It names the iteration retained across the suspension.
What remains is pinned rather than left silent. A NAMED local of an ambiguous
type is covered — by the sibling rule, not this one. An UNNAMED literal of an
ambiguous type is not, and is asserted at zero so the day the resolved type
carries the zone that test fails and names what to tighten. Two sites outside the
frames are recorded with their measurements: `AsyncTask.result` parks a race
branch's return in the husk and re-raises it ticks later with no bounds check
where `forAdvance` has one, measured reachable; and the wake filter stabilises
strings only.
One self-report: the first counter-factual measured nothing. Replacing the
predicate body with `return false` left a parameter unused, so 34 steps failed to
COMPILE and no test reddened — which reads exactly like a fix with no power.
Floor derived once, at the end, measured twice with no concurrent build:
2357/2376 on macOS, closure agreeing independently, 2374 on windows.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A FOURTH external NO-GO, and the same unit error one level up — the second time a fix written to close one commits another of its kind. The gate before walked the named locals instead of what the frame retains; this one armed on a keyword instead of on every point that suspends. `refuseArenaLocalsAcrossAwait` had a single call site and the iterator check sat in the same block, both gated by the `await` node, while `race` and `sync` park the parent with no `await` anywhere in its own statements. ENUMERATED AT THE INTERPRETER, NOT PRESUMED. Every parent suspension originates at a `return .suspended`; there are eleven. Seven are in `driveLoop` and are the verdict propagating upward rather than new sources. Three are `stepBodyStmt`'s `await` target families — a `TaskHandle`, `wait`/`wait_unscaled`, and the two event forms. One is `beginRaceSync`, parking the parent on `children_any`/`children_all`. `branch`/`spawn` detach, so the parent runs on. The missing source was exactly one, and it is the one that does not carry the keyword. `await_suspendable` turned out not to be await-specific at all: its own doc calls it the async driver's frame-driven spine, a property of the POSITION, so the race/sync arm reuses it unchanged. What is await-specific is `is_head`, E0904's requirement that the await be the statement's full right-hand side — and `race`/`sync` are statements by construction. So both checks now live in ONE predicate named on the property, called from the two arms, with a single place where the question is asked. Adding two branches to the existing condition would have left the next review to find the third. The refusal is conservative by necessity rather than by preference, and that is written at the site: `beginRaceSync` returns `.advanced` when no branch is admitted, so whether a `race`/`sync` suspends at all depends on a runtime guard. Cost measured before proposing: ZERO false refusals, suite green at 316/316. Counter-tests red before (`0` where `1` is required) and green after, for `sync` and for the loop variant, each carrying the neighbouring synchronous rule that makes the refusal non-arbitrary. Green twin: the same `sync` in the same place with a POD local instead of an array, accepted — without it a rule refusing every `race`/`sync` outright would pass both counter-tests. Counter-factual: removing the arming reddens both and leaves the twin green. One defect caught by an assertion rather than by reasoning: the predicate took a `NodeId` and the race/sync arm handed it a statement, so `exprSpan` fired its `assert(id.category == .expr)`. It takes the span now, each caller computing it with the function for its own category. Floor derived once, at the end, measured twice with no concurrent build: 2360/2379 on macOS, closure agreeing independently, 2377 on windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
THE JOURNAL AND THE FIVE RUBRICS. Four sessions, 103 commits, 245 `.zig` files and 4 `.md`. Measured on the delivered lot: 49 entries, 18 closed of which SIXTEEN by this milestone, two closed before it, 31 open, and 9 of the 49 minted during it — the last two being the storage zone absent from `ResolvedType` and a parked async result re-raised with no bounds check. The milestone's own premise did not survive it. Described as delivering no program line, it changed 245 `.zig` files, moved the floor from 2290/2288 to 2379/2377, and rewrote two paths under frozen surfaces. Corrected where it lives. FOUR EXTERNAL NO-GOs. The first, six defects. The second, two of a class the first had not reached: the type checker was treating an absence of information as a guarantee. The third, the predicate right and the walked SET wrong — named locals instead of what the frame retains. The fourth, inside the fix written for the third: both checks armed on the `await` keyword instead of on every point that suspends the parent, `race` and `sync` suspending with no `await` in the parent's own statements. Between them an internal adversarial review refused a closure seven more times, every finding against code written the same day. TWO RESULTS OUTLIVE THE MILESTONE, and the second is the one four reviews paid for. A green fix with its counter-factual establishes its own case and nothing more. Eight defects were found in fixes delivered green, three in entries marked closed. Naming the adjacent case is not enough either: one had been named safe, with a reason, and the reason was false. An adjacent case is shown safe; it is not declared safe. And six unit errors — counting a set different from the one named — of which TWO were committed inside the fix written to close the previous one. That is not bad luck: a unit error is the one class a green counter-factual cannot expose, since the fix genuinely has power over the members it does reach. What ended the series was enumerating the set AT THE CODE — seven `AsyncFrame` variants read field by field, then eleven `return .suspended` sites classified into seven propagations, three `await` target families and one `beginRaceSync` — and never better reasoning about the reported instance. The second enumeration establishes that no further source exists, and a reader can check that. Also recorded: the subagent that wrote into the tree, caught by a collected total that CLIMBED while nothing of mine changed; two fabrications of mine, a symbol that does not exist and a spec file that names nothing in the corpus; and the pipeline-exit-code family reaching FIVE, the last of which was read correctly before committing — the only one that cost nothing, and it arrived after the other four were written into this brief. Floor derived once, at the end, measured twice with no concurrent build: 2360/2379 on macOS with the closure agreeing independently, 2377 on windows. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The squash title read "twenty-two entries closed". Measured on the delivered lot: nineteen `[CLOS — …]` marks, of which SIXTEEN are this milestone's — the other three being another milestone's, one closed before this one, and a template line in the file's own model. The title counted MARKS instead of CLOSURES, which is precisely what six entries of that same table were corrected for. It is the seventh instance of the class, it was raised once and re-issued unchanged before being corrected by a count that had not been done, and it is recorded beside the other six: what is at issue is the class, not whose hand committed it. My own control measurement carried a trace of the same thing — a count of "twenty" that swept in a `[CLOSED]`, which is a different token. Title corrected to `sixteen`: what the milestone closed, not what the table carries. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
guysenpai
added a commit
that referenced
this pull request
Sep 23, 2026
The two cache corrections and their measured cost on run 35926601770, the two known windows classes red at b3fd951, the tag split and its four counter-factuals, the sync-for shrink check, and (A) with its seventeen witnesses and twenty counter-factuals, predicted before they ran. B3 carries its answer. CLAUDE.md read PR #81 as unmerged in two rows, and drew from that a conclusion now false; both corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
guysenpai
added a commit
that referenced
this pull request
Sep 24, 2026
The token measured in CI, the PR #81 cache deleted, the tool and its fourteen counter-factuals, the cost of the changes job, and the gain predicted for this very commit before it is pushed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the M1.D debt milestone. Do not merge or tag without Guy's own decision — this PR is ready for review, nothing more.
What it delivers
Sixteen entries closed by the milestone itself (3 in S1, 6 in S2, 7 in S4); two were already closed before it; 31 of 49 remain open, and 9 of those 49 were minted during it — the last two
M1.D.47(the storage zone absent fromResolvedType) andM1.D.48(a parked async result re-raised with no bounds check). A debt table that grows while it is being emptied is what measuring produces when the measuring is real.The milestone's own description was false and is corrected where it lives.
CLAUDE.mdcalled it "a documentation and instrumentation milestone: no program line is delivered". Measured at close: 103 commits, 245.zigfiles, floor 2290/2288 → 2379/2377 (+89 tests), and two rewrites under frozen surfaces (M1.D.21Tier 0,M1.D.31Forge).Four external NO-GOs
The fourth (one defect, the same unit error one level up) — both checks were armed on the
awaitnode rather than on the property that matters, this point suspends the parent:raceandsyncpark the parent with noawaitin its own statements. Enumerated again at the interpreter — every suspension originates at areturn .suspended, eleven of them, of which seven propagate (driveLoop), three areawaittarget families, and one isbeginRaceSync. One predicate now carries both checks, armed on that set. Zero false refusals.The third (one defect, a fourth kind) — the predicate was right and the SET it walked was wrong:
refuseArenaLocalsAcrossAwaititerates the named locals, while aforloop'sForFrameretains a store handle to a value that is nobody's local. That is the unit error this milestone had already documented four times, the fifth instance landing inside the fix written to close the fourth. Closed by enumerating the seven frame variants field by field rather than adding an arm — exactly two retain, one already covered — and the refusal's shape was decided by measuring the type/zone cells one by one, because a first form cost a capability (no resource collection iterable in an async rule) rather than a false refusal.The first two NO-GOs, and a class between them
The first (six defects) — a type predicate missing three of the seven rule-arena shapes; a hot reload reusing a component id without confronting its schema, and confronting it per declaration; a kinematic move deriving its angular velocity from a rotation the store normalises or drops; a reason-walk and its predicate reading different visited sets; a rename check establishing uniqueness on one side only.
The second (two P1 of a class the first had not reached) — and the class is what matters: the type checker was treating an ABSENCE of information as a guarantee. An unresolved type reached a capture unrefused, with the program clean of every diagnostic, at the cost of an abort from ordinary code; and a rule-arena local living across an
awaitopened no escape window,EscapeSitehaving declared the variant and never produced its producer, whileetch-memory-model.mdhad named that site in a correction dated 2026-09-10.Between them, an internal adversarial review refused a closure seven more times, every finding against code written the same day — two of them this repository's costliest class, committed inside the correction that was fighting it.
Two standing lessons
A green fix with its counter-factual establishes its own case and nothing more. The reviews found eight defects in fixes delivered green, three of them in entries marked closed. Every one had a counter-factual, and every counter-factual was correct — it showed the fix had power over the case it treated, and said nothing about the neighbouring one. Naming the adjacent case is not enough either: one had been named safe, with a reason, and the reason was false. An adjacent case is shown safe; it is not declared safe.
Seven unit errors — counting a set different from the one named — of which TWO were committed inside the fix written to close the previous one, and the seventh in this very title, which counted closure marks instead of closures. That is not bad luck: a unit error is the one class a green counter-factual cannot expose, since the fix genuinely has power over the members it does reach. What ended the series was enumerating the set at the code — seven
AsyncFramevariants read field by field, then elevenreturn .suspendedsites classified into seven propagations, threeawaittarget families and onebeginRaceSync— never better reasoning about the reported instance. The second enumeration establishes that no further source exists, and a reader can check that.What is reported, not fixed
M1.D.43–M1.D.46, minted at the first NO-GO: theOutOfMemorypath the pre-validation does not cover; tag identity inexpressible in the schema digest;storageandrequiresunhashed; builtin names unreserved, whose collision panics.async fnon a struct receiver that suspends is refused (exact whenselfis read after the await, over-refusal when before); and everystringis treated as rule-arena, the resolved type not distinguishing persistent from run.M1.D.17the Etch reload debt closed here, whileCLAUDE.mdcarries a different debt under that number which the plan carries under none.Measurements
Floor derived once, at the end, measured twice with no concurrent build:
2360/2379macOS, closure agreeing independently at 2379; 2377 windows. Headb71017e. Green at Debug and ReleaseSafe, the latter fromzig build's own exit code.zig build lintconservation OK.Proposed squash message