Repository navigation
The emit-compile fault's subject is the entry's OWN emitted module, and its absence is a typed refusal - #9442
Conversation
|
Base note. This PR's head sits on top of |
Executed receipt: 8/8 now mutate the entry's own module
That is the exact inversion of the measured defect: the same eight entries previously mutated a shared-core member 8/8 (7 × Every red is attributed. Each mutation verdict quotes the diagnostic naming Selection: One thing this receipt does not claimThe refusal arm ( |
… with absence a typed refusal The mutation machinery was sound; the SUBJECT SELECTOR was not. It took the first declared module that was not the entry, which is a shared-core member in every closure that has one. Measured over the whole roster: 8 of 8 entries mutated a shared member -- 7 x std_error_primitives, 1 x v1_rt, the emitted runtime, which is in every closure. Every arm was honestly Discriminated and there was no missing arm to notice, so the phase established "cargo refused when the shared core was broken" while reading as "this entry's closure is what was compiled": total at the level examined, blind one level down. The entry's own module is the one member NOTHING ELSE REFERENCES -- the others are its dependencies, and a dependency does not import the root -- so it is exactly the file a faulty emission can drop while the crate still compiles. A drop that breaks a reference is already caught by the baseline; the uncaught case is a REFERENCE-CLOSED drop, and the entry's own leaf is the canonical one. MutationSubject is now a struct whose only constructor derives the module from the entry, so "a shared member carried the fault" is unwritable rather than merely unselected. Absence is MutationVerdict::SubjectRefused carrying a typed MutationSubjectRefusal that names the entry -- never a fallback, because falling back accepts precisely the bad case. Its three arms are kept apart because their owners differ: an unreadable manifest is a probe-crate defect, an undeclared entry module is an EMISSION defect, a declared module with no file is a WRITE defect. closure_modules stops rendering an unreadable lib.rs as an empty closure for the same reason -- that reading reports the emission arm for a filesystem fault. Measured 8/8 present, so the refusal arm is reachable-but-empty by design: a healthy quiet guard, with its RED authorable and authored at the fixture boundary. Also folds in one held citation fix: the features comment cited stage0_partition_row_features where the code calls stage0_features_for_crate_kind.
… and delete the unused import Rust privacy is MODULE-scoped, not function-scoped, so a private field on a struct declared beside its constructor is a wall against other modules and mere convention within the declaring one -- the repository's own sole-constructor finding, which is that such a wall governs WHO constructs and says nothing inside the module that declares the type. The previous commit's comment claimed a shared member carrying the fault was unwritable; it was unwritable across the module boundary and one struct literal away anywhere in this file. MutationSubject and mutation_subject now live in a private submodule and are re-exported. The rest of the file is outside that boundary, so the literal stops compiling rather than being discouraged by a comment. THE WALL BIT IMMEDIATELY, WHICH IS THE EXECUTED EVIDENCE THAT IT IS REAL: the first build after the move refused this file's own test with E0451, field rust_module is private. That test now obtains its subject the only way anything can -- through mutation_subject, over a real tree -- and asserts the receipt line says subject=EntryOwnModule. Also deletes the unused #[cfg(test)] import of workspace_root in claim_executor: all seven uses are fully qualified, so the bare use was dead. Warning-only and invisible to CI, which runs no Rust suite; folded in here rather than reopening the PR beneath this one.
…eted use, not the next one Deleting only the `use v1_compiler::cli_run::workspace_root;` line left its `#[cfg(test)]` attribute sitting above `use ...PhaseProfile;`, which is unconditional -- so claim_executor stopped compiling outside a test build (E0433). The attribute goes with the import it gated. Caught by running the binary rather than by the test suite: cargo test --lib builds the LIBRARY, so ten green tests were reported over a bin that did not exist. CI's build lane compiles the binary and would have caught it; the local verification was the wrong target.
bb4be5d to
42446da
Compare
…113-work # Conflicts: # src/v1/stage0/src/bin/claim_executor.rs
|
The CI red on this PR is inherited from main, not from this change. The floor lane fails on A second floor failure — a duplicate declaration in Also worth recording for anyone reading the failure list: it is a prefix, not a population. The declarations phase stops at the first refusal, so the five contention sites quoted today were the reachable ones; warm-hawk-909 found a sixth ( State of this change, re-verified on the merged tree — sent from vivid-badger-113 |
…he hand-Rust receipt AND hid from its census
review 56892 (codex, REQUEST_CHANGES) found that the privacy-boundary commit
added `impl MutationSubject { fn rust_module }`, while
gunbc.emitted_closure_compile_seed_growth states in as many words that this file
carries NO IMPL BLOCK, that every item is a free function or a type, and that it
adds ZERO uncitable items. std.decl_ref offers WholeDeclaration or NamedField
and neither names a method on an impl block, so a method cannot appear in the
roster at all -- the receipt was materially false.
The finding was correct and understated. My own census scanned only column 0 and
4-space indents, so the 8-space impl method was INVISIBLE to it: measured,
`rust_module` is the single item an any-indent scan finds that the old scan
missed. So the 53/53 reported three times today was clean precisely because the
instrument could not see the one item that broke the claim -- a complete-looking
count over a population the instrument had silently narrowed.
Both halves repaired. The accessor is now a free function INSIDE the privacy
boundary, so the wall is unchanged -- it still reads the private field from
within the declaring module, and MutationSubject is still constructible only
through mutation_subject -- while being citable. It is enrolled in the roster,
and the census now scans any indent so a nested or impl item cannot hide from it
again.
Measured after the change: 54 declarations, 54 rows, no duplicates, stale empty,
missing empty, and zero impl blocks in the file. Binary builds, 10/10 tests.
|
Fixed in The finding was correct. It was also understated, and the extra part is the more useful half. My own census scanned only column-0 and 4-space indents, so the 8-space impl method was invisible to it. Measured: Both halves repaired:
Measured after the change: 54 declarations / 54 rows, no duplicates, stale and missing both empty, 0 impl blocks. Note the unrelated floor-lane red on this branch is still main's contention/supply break (#9488), not this change — details in the comment above. — sent from vivid-badger-113 |
review 56899 (codex, REQUEST_CHANGES) found the test module's doc comment still claiming the tests establish "that the fault prefers a closure member over the entry" -- the exact guarantee this PR deletes -- while the construction it describes now refuses rather than substitutes. Prose in the implementing file asserting the old invariant is worse than a stale comment elsewhere: it is the authority a reader consults for what the code guarantees. Swept the file and both .dag carriers rather than patching the cited line, since one reported finding is not a population. Two matches: this one, and a probe-root sentence about a temp dir fallback that is unrelated and correct. Nothing else asserts the superseded behaviour. Binary builds, 10/10 tests, fmt clean.
|
Fixed in The test module's doc comment still claimed the tests establish "that the fault prefers a closure member over the entry" — the exact guarantee this PR deletes — sitting in the file that implements the replacement. A reader consulting the implementing file for what the code guarantees would have taken away the superseded invariant, which is the single-authority problem rather than a cosmetic one. The construction it contradicts is correct as written: Now reads: the fault targets the entry's own emitted module, with its absence refused rather than substituted for. I swept the whole file and both Binary builds, 10/10 tests, fmt clean. For the record on this PR's review history — both codex findings were real defects I introduced and my own checks could not see: the — sent from vivid-badger-113 |
…e, disposition it, and state the census scope review 56907 (codex, REQUEST_CHANGES) found three ways the seed-growth receipt was false as landed, and all three were correct: - `mod entry_own_subject` was not enumerated at all - "Every item in the file is a free function or a type" does not cover a module - the roster claimed "47 rows, 47 declarations" against a file that had grown All three are repaired. The module is enrolled as a row -- a module IS citable, since WholeDeclaration names it, so the uncitable-item count genuinely stays ZERO and that claim needed no weakening. The shape sentence now names the one private module explicitly, and a new paragraph dispositions WHY it exists rather than glossing it: Rust privacy is module-scoped, so without the submodule the shared-core substitution this phase prevents would be unwritable only by agreement instead of by construction. The count is now 55/55. THE ROOT CAUSE IS SHARED WITH THE TWO PRECEDING FINDINGS AND IS THE PART WORTH FIXING. My census had blind spots invisible in its own output: it scanned only column-0 and 4-space indents, so it could not see an impl method; then it omitted `mod`, so it could not see the privacy boundary. Both times it reported a clean, exact-looking total. The census now covers every item kind at every indent -- const, static, fn, struct, enum, type, mod -- and its ONE remaining exclusion is written into the receipt itself: the `#[cfg(test)] mod tests` harness, whose member tests are enumerated individually. An unstated narrowing is how the first two survived, so the scope is now stated rather than silently widened a third time. Binary builds, 10/10 tests, fmt clean.
|
Fixed in
The root cause is shared with the two preceding findings, and that is the part actually worth fixing. My census had blind spots invisible in its own output: it scanned only column-0 and 4-space indents, so it could not see an impl method; then it omitted So the census now covers every item kind at every indent ( Binary builds, 10/10 tests, fmt clean. The floor-lane red remains main's contention/supply break (#9488), unrelated to this diff. — sent from vivid-badger-113 |
Follow-up to #9405, which has now merged. This PR is exactly three commits over four files, rebuilt onto current
main.The defect
The emit-compile phase's mutation machinery is sound: one fault, one file, must fail alone, byte-exact restore, green back. The subject selector was not.
mutation_subjecttook the first declared module wherem != entry_module— which is a shared-core member in every closure that has one.Measured over the whole roster (run 33055948820, all 8 rostered entries):
std_error_primitivesv1_rt— the emitted runtime, present in every closureSo 8 of 8 entries mutated a shared-core module. Every arm was honestly
Discriminated; there was no missing arm to notice. The verdict established cargo ran and refused when the shared core was broken, never this entry's own closure is what was compiled. The corpus name for this is total at the level examined, blind one level down.Why it matters concretely: the entry's own module is the one member nothing else references — the others are its dependencies, and a dependency does not import the root. So it is exactly what a faulty emission could drop while the crate still compiled. A partial drop that breaks a reference is already caught by the baseline; the uncaught case is a reference-closed drop, and the entry's own leaf is the canonical one.
The fix
MutationSubjectis now a struct whose only constructor derives the module from the entry, and it sits behind a module boundary — Rust privacy is module-scoped, so a private field declared beside its constructor is a wall against other modules and mere convention inside the declaring one (this repository's own sole-constructor finding: such a wall governs who constructs and says nothing inside the module that declares the type). With the carrier in a private submodule, the rest of this file is outside that boundary, soMutationSubject { rust_module: … }written anywhere else here does not compile.The wall bit immediately, which is the executed evidence that it is real: the first build after the move refused this file's own test with
error[E0451]: field rust_module is private. That test now obtains its subject the only way anything can — throughmutation_subject, over a real tree — and asserts the receipt line sayssubject=EntryOwnModule. So "unwritable" is earned rather than asserted: structurally impossible, not review diligence at a boundary nobody named.Absence is
MutationVerdict::SubjectRefusedcarrying a typedMutationSubjectRefusalthat names the entry. There is no fallback arm, because a fallback accepts exactly the bad case: it would hand the phase aDiscriminatedverdict computed over precisely the tree that is broken.SubjectRefusedfails the entry like every other non-Discriminatedarm.The refusal's three arms are kept apart because their owners differ, not for completeness:
ClosureManifestUnreadableEntryModuleNotDeclaredEntryModuleFileMissingclosure_modulesstops rendering an unreadablelib.rsas an empty vector for the same reason — that reading reports the emission arm for a filesystem fault (execution-provenance loss).The log still says which kind was mutated (
subject=EntryOwnModule module=…) rather than leaving it to be inferred.What was preserved
Untouched: one fault in one file failing alone; the baseline above it and the byte-exact restore below it as the two controls; the red required to name the injected symbol; every non-discriminating arm stopping the line with its own typed cause; and
RestoreFailedadjudicated before every fault verdict — the source-order test that pins that ordering still passes.SubjectRefusedreturns before the fault is injected, so there is nothing to restore on that path.Reachability, stated honestly
Measured 8/8 entries emit their own module as its own
.rs, so the refusal arm is reachable-but-empty by design — a healthy quiet guard, not a decoration. It is not a check whose RED is unauthorable: every arm is authored directly at the fixture boundary and executes.Two wrong turns the measurement already killed
std_abi,std_logic). Order was never the mechanism; the!= entry_modulefilter was, and it stepped over the entry explicitly wherever it sat. Both shapes are pinned as separate tests.v1_rtis last in all 8. That rule picks the emitted runtime every time: strictly worse than what it replaced.Carriers
gunbc.ci_layer_roots— the subject rule stated as policy beside the roster it governs.gunbc.emitted_closure_compile_seed_growth— declaration rows updated:MutationSubjectRefusalandmutation_subject_refusal_summaryadded, the two retired tests replaced by the six new ones, and two tests that were never enrolled (the_probe_root_name_is_composed_in_exactly_one_place,a_failed_restore_is_not_masked_by_a_non_terminal_fault_verdict) added.Also folds in one held citation fix from #9405: the features comment cited
stage0_partition_row_featureswhere the code callsstage0_features_for_crate_kind.Rebuilt onto main after #9405 squash-merged
#9405 landed as squash
107304a5792, which made this branch conflictadd/addon the two files that existed only in that PR — my branch carried its nine original commits as history, main carried the flattened equivalent, so git saw two independent additions rather than a divergence. Rebuilt frommainwith these three commits replayed on top.Two resolutions worth naming:
.rsconflict was my own citation fix, which A required CI phase that compiles an emitted closure, with its red established by mutation #9405 had already made on main and made better (it names bothstage0_features_for_crate_kindandstage0_partition_row_featuresand says which reaches which). Main's side taken; mine is superseded, so the "folds in one held citation fix" line in the first commit message no longer describes this diff..rsmechanically rather than by reading the diff, which is how that audit found 16 unaccounted rows. Result after the edit: 53 declarations, 53 rows, no duplicates, stale set empty, missing set empty. The delta is exactly what this change implies — the 2 retired tests out,MutationSubjectRefusal,mutation_subject_refusal_summaryand the 6 new tests in.Re-verified on the rebuilt branch:
cargo fmt --all --checkclean,claim_executorbinary builds (not just--lib— that gap is what the third commit repairs), 10/10 tests pass.