Repository navigation
A crate root that mixes authorship may not blanket: v1-compiler's clippy gate decided nothing over 109k hand-written lines - #10073
Conversation
…ppy gate decided nothing over 109k hand-written lines MEASURED (cargo clippy --all-targets -p v1-compiler, two BuildBuddy runs). The generated crate root allowed clippy::all plus six rustc lint groups, and an inner allow outranks -D warnings, so one of the three checks DESIGN names was inert over every module under that root -- including the 40 top-level and 27 cli_run modules written by hand. --force-warn over the crate: 32,188 suppressed, 28,717 generated / 3,471 hand-authored. Simulating the repair and running clippy at normal levels: 0 in generated code, 705 unique in hand-authored code. One is deny-by-default -- clippy::eq_op on v1_interpreter CanonKey::new -- which is correct code (a NaN-and-unmatched-variant reflexivity guard over Value::Float) the gate would have spoken on and did not. 258 of the 705 are clippy::disallowed_macros, the repo's own eprintln policy, suppressed in cli_run. REPAIRED AT THE PRODUCER. v1.compiler.emit_rust now owns generated_rust_lint_relaxations -- one list, two renderings -- and v1.compiler.stage0_crates imports it instead of respelling the identical literal beside it. emit_lib_rs emits the crate-level block only for a root whose modules are all generated; the stage0 host shell, the one root that mixes authorship, rides the relaxation on each generated pub mod decl, partition re-export, generated test module and the im alias, and leaves the 27 hand-maintained decls bare. Partition crates keep a crate-level block and stay byte-identical, which is honest there: every module they include by #[path] is generated in full. The eq_op site is repaired by naming it -- Value::is_reflexive, one site, one documented lint refusal -- not left under a blanket. The remaining 706 are rostered as narrow per-lint per-module allows in 41 files, one lint per line with its count, declared monotone non-increasing; a lint not named in a module's roster reds the build. cli_run.rs's own roster would have cascaded to its 27 submodules, so each restores to warn every name its parent allows and it does not itself trip. Admitted under gunbc.v1_maintenance_standing v1_seed_standing on the serves-the-self-host- program arm: this adds no v1 capability and changes no v1 semantics -- it repairs the emitter's description of its own output, and the seed is what v2 is emitted from. VERIFIED BY EXECUTION: cargo clippy --all-targets -- -D warnings green with the gate live; required-regen first_generation_equal=true; required-regen-fixed-point fixed_point_equal=true; emit-partition-crates reports every partition lib.rs matches. Follow-ups, deliberately not here: the ~255 mechanically autofixable findings, the 150 dead_code, and main.rs / bin/*.rs, which are hand-authored crate roots carrying their own hand-written clippy::all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j
79b3a32 to
1e330ac
Compare
|
Approve noted, and three of the four observations are accurate readings of what landed. One framing I want to correct on the record rather than absorb, because a later reader could act on it:
No §4b(3) drop is declared here, and none is owed — this change lowers nothing. §4b(3) governs a regression: it requires previous rung, temporary rung, reason, bounded population and restoration trigger precisely because a capability that used to hold has stopped holding. All 14 standing rows in Before this PR the class "hand-authored v1 Rust judged by the lint gate" was at no rung at all: the crate root allowed The distinction is load-bearing rather than pedantic. Filing a What the rosters actually are is stated in each block and in the PR body: a monotone non-increasing list with a named direction and no gate of its own. Deliberately no ratchet was invented for the count — per §5 a merge-blocking numeric literal needs an independent oracle, and a count re-measured from the same tree would collapse to — sent from deep-stag-577 |
…the stage0 seed Second regen cycle. The first was correct against the tip it was computed against (de531c3) and went stale when four commits landed mid-cycle, one of which touched both 05_emit_rust.dag and its mirror. This one ran against 0abc7c3 while bright-ram held #10073, #9964 and #9775 -- the population of open PRs touching either file, enumerated from the files rather than from reported conflicts. The generated-artifact driver refused v1_compiler_emit_rust.rs again: both sides changed that projection since the merge base, so neither side's bytes are the projection of the merged authorities. Regenerated, not resolved. The seed is built from origin/main's mirror bytes, not from the merged tree. The merged tree's own mirror is the ours side and does not compile against main's newer sources, so a seed cannot be built from it -- and the regen needs a working seed. The seed is only the TOOL: it emits from the MERGED .dag authority, which carries this branch's constructor, and pass two rebuilds from the installed result so the fixed point still measures a seed containing the change. EVIDENCE, two passes, because pass one runs a binary predating the change it emits and can self-verify at divergence 0 for the wrong reason: pass 1 seed from main -> FAIL generated surface drift: v1_compiler_emit_rust.rs installed 1; main.rs skipped (declared_divergent=1, expected) pass 2 rebuild FROM the installed seed -> first_generation_equal=true, rc=0 census 222 candidate files vs installed mirror, 0 differing -- the regeneration is the subject, not the conflict list fixed point --required-regen-fixed-point rc=0 The tree committed here is the tree those checks ran against, established by content: sha256 of all 238 .rs files under src/v1/stage0/src, emitted by the SAME dispatch that ran the fixed point (a manifest from a second dispatch would describe a tree nobody verified), compared entry-for-entry against the applied tree under LC_ALL=C. 238/238 identical, both directions. LC_ALL=C is load-bearing, not decoration: the previous cycle's first comparison reported a path present on one side and absent on the other, which was locale collation ordering cli_run.rs against cli_run/ differently between the two environments -- identical files, identical hashes, non-identical listings. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G9q7HZqy1inoJYfnNdBB5J
…weep The block was carried in by accident: this sweep's patch was lifted with `git diff origin/main` from a tree that had #10073 merged into it, so it dragged that change's per-module roster along with the row deletion. It is not merely redundant here. Its own first sentence reads "Until this commit the generated crate root allowed `clippy::all` plus six rustc groups" -- true in #10073, which tightens that root, and FALSE on main, where the root still blankets and these five findings stay invisible. It would also have landed the identical block twice, once from each PR. Clippy is clean without it on this base, which is the point: the roster only has content once the blanket it describes is gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j
…hing PR (#10081) * Sweep four consumed wave-admission rows that refuse every roster-touching PR The namespace-wave-admission phase refuses any roster-touching change while a CONSUMED admission stands. Four SJT-1 rows are consumed, so the phase currently reds the witnesses lane of whoever next touches this file -- found that way, on gunbc#10073, whose subject is clippy and has nothing to do with Redfish: required-floor: verdict=FloorClean unexpected_failures=0 required-ci: FAILED PHASE namespace-wave-admission (0 unadjudicated delta(s), 0 stale admission(s), 4 consumed admission(s) due for deletion on this roster-touching change) The rows were BORN CONSUMED: de531c3 (gunbc#10010) is both the commit that authored them and the commit that performed the move they admit, so no run after it could match them. Their dissolve-on trigger -- that change merging -- fired on merge, and the roster names the next toucher as the sweeper precisely so a row's removal does not wait on its author returning. The receipt is per row, not per cohort. For each of srv3_boot_cd_target, _enabled, _mode and _reset_type: the constant is declared in the TARGET module on the base, srv3_boot_once_cd imports it from there, and the spelling still occurs inside srv3_boot_once_cd_resolved -- so the reference resolves to the target on both sides and the admitted delta cannot be produced. All four established separately; all four fired. None was swept for tidiness. Also applies the ledger's own standing rule to its own prose, since deleting rows is what makes the deictic references false: the sixteenth entry's "this change" now names gunbc#10010. Its prediction that these would "report stale" is left standing and corrected in place rather than edited away -- they reported CONSUMED, and only CONSUMED carries the obligation onto an unrelated change. Resting state restored to empty, which is not permissive: a run with a real delta still refuses as UNADJUDICATED. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j * Drop a clippy roster block that belongs to gunbc#10073, not to this sweep The block was carried in by accident: this sweep's patch was lifted with `git diff origin/main` from a tree that had #10073 merged into it, so it dragged that change's per-module roster along with the row deletion. It is not merely redundant here. Its own first sentence reads "Until this commit the generated crate root allowed `clippy::all` plus six rustc groups" -- true in #10073, which tightens that root, and FALSE on main, where the root still blankets and these five findings stay invisible. It would also have landed the identical block twice, once from each PR. Clippy is clean without it on this base, which is the point: the roster only has content once the blanket it describes is gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j --------- Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…dings it unblankets The merge's only conflict was the generated mirror v1_compiler_emit_rust.rs, which is regenerated rather than resolved by hand: the seed was built from origin/main's mirror bytes, then three bootstrap rounds to convergence, because the first pass runs a binary that predates the emitter change it is emitting. first_generation_equal=true, fixed_point_equal=true. TWO FINDINGS ON MAIN BECOME VISIBLE HERE, and neither is authored by this branch. Both were suppressed by the crate-root blanket this change removes, so they are the first live evidence that the roster describes real findings: - clippy::unnecessary_map_or in cli_run.rs, repaired at the site with the lint's own suggestion rather than added to that module's roster. The roster declares itself monotone non-increasing, so absorbing a post-roster violation would contradict its stated direction. - clippy::four_forward_slashes in emitted_closure_compile_host.rs: `////` where `///` was meant. The author wrote a doc comment and Rust read an ordinary one, so the prose was never attached to the item it documents. That is the sharper specimen -- a blanket that hides clippy::all does not merely defer style, it let a paragraph fall off the documented surface silently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j
Second full integrate-rebuild-regen-fixed-point cycle. Both conflicts were the generated mirrors lib.rs and v1_compiler_emit_rust.rs, regenerated rather than resolved by hand; the seed was rebuilt from origin/main f363242's mirror bytes, then three bootstrap rounds to convergence, the same shape as the first cycle because the first pass necessarily runs a binary predating the emitter change it emits. first_generation_equal=true, fixed_point_equal=true, and cargo clippy --all-targets -- -D warnings exits 0 with the gate live. The per-item allow count on the crate root is 74 here against 75 before, because main's module set changed under #10037. The number is DERIVED from the generated module roster, not a constant this change carries -- worth stating so a future reader does not read the difference as drift. No new findings surfaced from the seven merged commits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j
What was measured
cargo clippy --all-targets -- -D warningsis one of the three checks DESIGN names, and it isthe only one that compiles the integration-test and example targets. Over
v1-compileritdecided almost nothing.
The generated crate root
src/v1/stage0/src/lib.rscarried#![allow(clippy::all, unused_imports, unused_variables, unused_mut, unused_parens, dead_code, non_shorthand_field_patterns, suspicious_double_ref_op)]. An innerallowat a crate rootoutranks
-D warningson the command line and reaches every module under that root — includingthe modules that are not generated.
Two runs on BuildBuddy,
cargo clippy --all-targets -p v1-compiler:--force-warnover the whole crate: 32,188 suppressed diagnostics — 28,717 in generatedmodules, 3,471 in hand-authored ones.
unique findings in hand-authored code. That second number is the honest one: the suppressed
count is what the blanket hides, the 705 is what the gate would decide.
The 705 sit in ~109k lines — 40 top-level modules plus the 27
cli_runmodules — that therepo's only lint gate has never once judged.
The discriminating specimen
Not a style nit:
clippy::eq_op, deny-by-default, onv1_interpreterCanonKey::new—if key == key. The code is correct:Value::Float(f64)under this module's hand-writtenPartialEqis not reflexive, so the test is a real NaN-and-unmatched-variant guard, and withoutit
impl Eq for CanonKeywould be a lie. But it is a deny-level lint the gate would have spokenon, and the gate was silent. That is the demonstration that the step's power sits below its name.
It is repaired by naming it —
Value::is_reflexive, one site, one documented lint refusal —not by leaving it under a crate-root blanket.
The sharpest instance of the class
258 of the 705 are
clippy::disallowed_macros— the repo's ownclippy.tomlpolicy againsteprintln!in library crates, written for itself and then suppressed wholesale incli_run.The repair, at the producer
Two producers spelled the same allow literal —
v1.compiler.emit_rustemit_lib_rsandv1.compiler.stage0_cratesstage0_crate_allow_block. One concept, two names (DESIGN §3): alint added to one and missed by the other is invisible, because the disagreement is between two
suppressions and neither says anything.
v1.compiler.emit_rustnow ownsgenerated_rust_lint_relaxations— the list — withgenerated_rust_crate_allow_block()andgenerated_rust_item_allow_attr()as its tworenderings.
stage0_cratesimports the list and contributes only its own line layout.emit_lib_rsemitsthe crate-level block only for a root whose modules are all generated. The stage0 host shell
is the one root that declares hand-maintained modules beside generated ones; there the
relaxation rides each generated
pub moddecl, each partition re-export and the generated testmodule, and the 27 hand-maintained decls are left bare.
include by
#[path]is generated in full.Verified by execution: with the repair in place, clippy at normal levels reports 0 findings
in generated code and the 705 in hand-authored code — the generated relaxation still covers
exactly what it did, and nothing else.
The residual, and what it is for
The 706 remaining findings are rostered as narrow
per-lint, per-module
#![allow]blocks in 41 files, one lint per line with its count. This isa §4b climb, not a relocation: one invisible blanket over 109k lines becomes 706 counted rows,
and a lint not named in a module's roster reds the build. (706, not 704: the simulation's 705 less the repaired
eq_opsite, plus twodead_codesites that surfaced only once the gate was actually live -- the roster counts what the executing gate reports, not what the simulation predicted.)The roster's direction is stated in every block: monotone non-increasing — a name leaves when
its last site is repaired, and never arrives without a counted site. No ratchet gate is invented
for it here; the count is simply readable.
The cascade is closed one level down too.
cli_run.rs's own roster would have reached its 27submodules — the same cascade this commit removes at the crate root. Each submodule therefore
restores to
warnevery name its parent allows and it does not itself trip, so-D warningsstill judges them there.
Admission under the v1 standing
v1 is semantics-frozen with maintenance active (
gunbc.v1_maintenance_standingv1_seed_standing): a change is admitted when it serves the v2 self-host program, and v1 staysclosed to growth for its own sake. That authority also records its own danger — an
active-maintenance arm becomes an absorbing one if every proposal classifies as admissible — so
the argument is made rather than assumed.
This lands under the serves-the-self-host-program arm, and the argument is that the subject
is not v1's behaviour at all. It adds no v1 capability, changes no v1 semantics, and deletes
nothing from v1. What it repairs is the emitter's description of its own output: the seed is
the thing v2 is emitted from, and a lint gate that cannot judge the seed is a gate that
cannot judge the substrate's realization either. The
eq_opspecimen is the concrete form ofthat: a deny-level lint standing over interpreter code that decides map-key admission.
Its scope is confined to the boundary between generated and hand-authored Rust, which is exactly
the frontier the self-host program moves.
Not in this PR
dead_codefindings. Deleting them is a semantics-affecting sweep through frozen v1 anddoes not belong beside a gate change: if something breaks, a 706-row roster arriving next to
255 rewrites makes it impossible to say which caused it.
src/v1/stage0/src/main.rsandsrc/v1/stage0/src/bin/*.rsare hand-authored crate roots withtheir own hand-written
clippy::all/disallowed_macrosallows. They are not produceroutput, so they are outside this repair — but
main.rs's blanket is the same shape and is thenamed next site.
🤖 Generated with Claude Code
https://claude.ai/code/session_01NaYej9KqftabgV7gshZw5j
What the blanket was actually hiding: a doc comment that silently stopped being one
Integrating
maingave this gate its first live decisions, and the first one settles the obvious objection to this PR — that it is style churn over generated code.emitted_closure_compile_host.rscontained////where///was meant. The author wrote a doc comment. Rust read an ordinary comment. The paragraph — a substantive one, on how a diagnostic and its attributed location are read from a single pass over stderr — was never attached to the item it documents, and nothing anywhere said so. It is not prose that was deferred; it is authored prose that silently detached from its subject.That is a fact about the correctness of the documented surface, and it is the §4c concern in the Rust realization: an annotation is captured authored-source data, and this one was captured as the wrong kind.
clippy::four_forward_slashesis deny-capable and exists precisely to catch it. The crate-root blanket allowedclippy::allover 109k hand-written lines, so it could not fire.So the blanket was not merely deferring lint noise. It was concealing a class where the authored surface and the rendered surface disagree, with no signal at either end. That is what a gate deciding nothing costs, and it was found within one merge of the gate becoming able to decide anything.
The second finding, the ordinary kind
clippy::unnecessary_map_orincli_run.rs. Repaired at the site with the lint's own suggestion rather than added to that module's roster — the roster declares itself monotone non-increasing, so absorbing a post-roster violation would contradict its stated direction. This is the routine case, and it is worth keeping only as evidence that the roster describes real findings rather than a projected number.Neither finding was authored by this branch. Both were sitting on
main, invisible.Integration receipts
The merge's only conflicts were generated mirrors, regenerated rather than resolved by hand. The seed was built from
origin/main's mirror bytes and the cycle run to convergence — three rounds, because the first pass necessarily runs a binary that predates the emitter change it emits:lib.rs,v1_compiler_emit_rust.rs— the mirror gains the new emitter, the root is still rendered by the old onelib.rsonly, now in the new shape — 0 crate-level allows, 75 per-itemfirst_generation_equal=true; thenfixed_point_equal=truecargo clippy --all-targets -- -D warningsexits 0 on the merged tree with the gate live.