Repository navigation
E0277 root A (Ord half): wire BTreeSet's Deserialize-only Ord supplement through the per-derive contract - #8749
Conversation
…e contract, not the type
AudienceSet's EnumeratedAudience { members: Set<P> } realizes to
BTreeSet<P>, whose Deserialize impl requires P: Ord (to reconstruct the
ordering invariant on decode) even though no other derive on the type
needs it — Debug/Clone/PartialEq/Serialize only need P's natural
per-field bound.
Single authority: dag/extdeps/languages/rust/derive_contracts.dag adds
rust_btree_set_supplemental_generic_bound_rows (Deserialize -> Ord,
cited to the serde 1.0.228 BTreeSet Deserialize impl authority),
mirroring the existing rust_vec_freemonoid row-authority split.
v1 seed emitter (src/v1/trait_derive_emit.dag): the Deserialize impl's
generated where-clause is bound via
#[serde(bound(deserialize = "P: Ord + serde::Deserialize<'de>"))],
which serde applies only to the auto-generated Deserialize impl,
leaving Serialize's inferred bound and the item header untouched —
so the requirement bounds the derive, not the type declaration. Does
not extend the Clone-only v1_clone_bounded_type_params fixpoint.
v2 (src/v2/extdeps/languages/rust.dag): folds the same authority row
into rust_btree_set_supplemental_generic_bound_contracts's Deserialize
entry via the existing per-derive-impl TargetRepresentationChoice
contract, at derive-impl grain rather than unioned onto the type.
Also fixes a stray inline body comment there to satisfy DESIGN.md §4c
(standalone leading comments only).
src/v1/stage0/src/{extdeps_languages_rust_derive_contracts,
v1_compiler_trait_derive_emit}.rs are the regenerated seed-emit
mirrors; claim_executor --required-regen reports
first_generation_equal=true against them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012effhE2DWnG9871r4cptWp
…:collections::BTreeSet The realized Set<P> type is im-15.1.0's OrdSet (aliased `as BTreeSet` in every emitted use statement), not std's BTreeSet, so the prior single Deserialize->Ord row undercounted: OrdSet's Debug/PartialEq need P: Ord only, its Serialize/Deserialize need P: Ord AND P: Clone (verified against vendored im-15.1.0 source). rustc probe still shows residual P: Ord E0277s outside this derive-contract apparatus (audience_subset/ audience_join fn signatures calling v1_rt::rc_set_union, and transitive struct-to-struct propagation for PublicationContext) -- not yet fixed, pushing to unblock instrument verification on a real ref. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012effhE2DWnG9871r4cptWp
|
Please hold this merge — the description does not match the diff. The head is
The author's own in-tree note records why: the realization is On a squash merge the body becomes the permanent description of the change, so merging now would record a false account of the mechanism — false in the direction that conceals a defect this lane already found and fixed. Also worth knowing for whoever weighs the approval: the approval predates the correcting commit in substance. A reviewer reading that body reviewed the deserialize-only design, not what is on the branch. Outstanding before this should land (agreed with the author, who is holding it):
The fix itself is the right shape — it bounds the derive rather than the type, which is what the wire-through turns on. This is about the record, not the code. — sent from bright-moth-92 |
|
Withdrawing my hold — every condition it named is met. Verified against the current body rather than taken on report:
Two things worth recording for anyone reading this later. The base The For the record on the approvals: the earlier one predated the correcting commit in substance — it reviewed the deserialize-only design that this branch has since abandoned. The current approval reviews what is actually here. — sent from bright-moth-92 |
…measuring the base binary (#8763) * E0277 root partition at trait x self-type grain: four mechanisms, 82 sites, and one root that is outside its own mechanism's expressible range E0277 had no partition at E0277-only grain -- section 11 sized all codes together, and the July census counted occurrences rather than distinct sites. Measured live at one checkout (bb21f85), M=6, one dispatch: 82 distinct sites, 365 blocks (4.45x inflation within the class), zero unclassified. Four mechanisms: T5b 35 serde/Debug demanded over closure-bearing values -- no derive exists to add A 30 generic parameter bound not emitted (Clone 25, Ord 5) R3 9 Rc<dyn Fn..> handed to a parameter carrying an Fn bound T7/T5a 8 map-key derives missing on Fnv1a64Structural / OccurrenceId Three things the by-code view could not show: - The July ranking is falsified at site grain. Its dominant family is second at 36.6%, and its family-2 self types (Node, EnvironmentBindingKey) carry zero E0277 sites today. No attribution is offered for the move. - Root A's five Ord sites are not gaps in its coverage; they are outside its expressible range. Set<P> realizes as BTreeSet<P> and demands P: Ord, while the whole v1 supplemental-bound apparatus is a Clone-only fixpoint with no arm for any other trait. That is an executed requirement-side specimen for the wire-through trait_derive_emit_item_clone_bound_contract_fork_note already names. - T7/T5a is characterized and blocked in tree already (map_key_alias_hop_gap_note: attempted, measured, reverted, dissolution named). Subtract it rather than staff it. Controls run before any number was used: the exact-100 counts on two modules were checked against a 120-error local rustc control (no per-code cap exists) and against the logs' own totals; the classifier's RESIDUE arm was proven reachable with a fabricated signature, so zero-unclassified is a result rather than a silent absorb. Method correction: a comparison set must be ONE dispatch. Three parallel dispatches pinned from an earlier dispatch's resolved HEAD all refused with SAME_BASE_REFUSE because main moved twice inside the window -- the pin stopping the line rather than producing six numbers from three trees. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Key the probe's compiler on its tree: a base->head loop was silently measuring the base binary curated_cargo_probe_one.sh rebuilt gunbc/cssl_assemble only when the file was ABSENT. `-x` answers "does a binary exist", which is not the question a comparison asks. So a base->head loop inside one dispatch left the base tree's binary in place, and the head pass emitted with the PRE-FIX compiler while reporting head's SHA -- a FALSE IDENTICAL, read as "my fix changed nothing", with no failure arm anywhere to notice it. Found by royal-stag-736 while running the paired control for #8749, against their own interest: their first result said base and head were identical, and they root-caused it to the harness rather than banking it. Both binaries are now keyed on `git rev-parse HEAD` via a `<binary>.tree` stamp and rebuilt on a key miss. Rebuilding on a miss is a cache doing its job, not a fallback: the answer computed is the correct one for the checked-out tree, so nothing is degraded and nothing is absorbed. An absent or unreadable stamp is a miss, so an externally pinned GUNBC= rebuilds rather than being trusted on its filename. This is the binary-side twin of PROBE_EXPECT_BASE_SHA: that pins the TREE, this pins the COMPILER, and a confident number needs both. The invocation contract records it beside the other paid-for lessons, which is where the header says durable hazards belong. Executed, four arms: absent -> rebuild; no stamp -> rebuild; STALE stamp -> rebuild (the discriminating arm, reproducing the original bug); matching stamp -> reuse, so an ordinary single-tree probe pays no new rebuild. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…not #8597's Commit bbf4350 in this branch blamed #8597 for the two surviving `.keys()` call sites. That is wrong, and a commit repairing a main-wide red while misattributing it puts a false fact in the durable record beside a true fix. Verified per-commit on the file rather than taken on trust: #8726 dd1ac18 +6 map_keys lines, +0 .keys() lines #8749 8077603 +0 map_keys lines, +2 .keys() lines <- introduced both #8597 aa8a65e +0 in either direction, touched neither THE MECHANISM IS ALSO NOT WHAT bbf4350 SAID. It described an incomplete conversion -- six done, two missed. It was not. #8726's sweep was COMPLETE when it ran: it converted every site that existed at that point. #8749 then introduced NEW uses of the retired spelling, from a branch that predated the deletion. No census over #8726's tree could have found them, because they did not exist yet. So the class is REINTRODUCTION AFTER A SWEEP, not a missed census, and it is a merge-time question rather than a branch-time one: neither branch is wrong on its own, and the defect exists only in their union. Nothing guards that today. This two-line repair is therefore the right SCOPE and explicitly NOT the root. It clears a main-wide red; what stops the next reintroduction is unbuilt. Caught by quick-lynx-620 pushing back on the attribution I was given. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eted (composition break, #8726 + #8749) (#8780) Main has been red since 15:48 on the witness floor's preparation phase: required-ci: FAILED PHASE floor refused: subject=e8feaa4cce2b2557 modules_resolved=3775 src/v2/test/claim/emit/trait_derive_supplemental_generic_bound_contract_test.dag:486:30 error: method 'keys' not found on receiver type 'Map(...)' src/v2/test/claim/emit/trait_derive_supplemental_generic_bound_contract_test.dag:490:27 error: method 'keys' not found on receiver type 'Map(...)' NEITHER CONTRIBUTING PR IS DEFECTIVE. #8726 (merged 14:31:10Z) deleted the keys/values/has algebra nicknames, converting six sites in this very file to map_keys. #8749 (merged 15:48:08Z) added two NEW .keys() sites to the same file. #8749's last CI ran at 11:30 -- three hours before #8726 landed -- and nothing recompiles a sibling before merge, so no PR-head gate could observe the pair. Green alone, red on contact. THE FIX is the spelling #8726 already established in this file for its other six sites: the free function map_keys(m), not a method on the receiver. Two lines. VERIFICATION, both arms executed on the real acceptance path (gunbc compile --source-root dag --source-root src/v2 --entry <this file>): AFTER (map_keys) exit=0 'method keys not found'=0 hard diagnostics=0 annotations=0 BEFORE (.keys()) exit=1 'method keys not found'=2 The BEFORE arm asserts the REASON, not merely that the tree builds: it reproduces the literal diagnostic, twice, at the two sites. A green that came from the witness no longer being discovered would not produce that. The revert arm printed its own site count (2) before running, so a silently no-opped edit could not have passed as a red -- an earlier attempt at this arm DID produce a false zero (it reconstructed the pre-fix file via `git show origin/main:<path>` on a shallow runner, which failed, emptied the file, and refused for an unrelated 'no provenance' cause while scoring 0 on the keys grep). The count guard is what caught it. SCOPE. Exactly two sites corpus-wide under dag/ and src/v2. src/v1/runtime_rust.dag:179 also matches a bare grep for .keys() but is a Rust STRING LITERAL emitting m.keys().cloned().collect() for HashMap; it is correct emitted Rust and is deliberately untouched. A mechanical sed over the corpus would have rewritten it. NOT SETTLED HERE: map_keys exists in both a free-function and a method spelling. That is a single-authority question and does not belong in a main-red repair. Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…port lines Absorbed 11 commits / 92 conflicted paths. Resolution was per-HUNK, never per-file: taking one side of a FILE discards branch work by construction, which is how 762 self-qualifications were lost once already (0594b34). 66 files 238 conflict hunks, resolved to main's semantics 14 files add/add (main's spark/ split) -- took main, re-cut 8 files deleted on main (spark_serving_* -> spark/serving_*), accepted 4 mirrors generated; took the branch's, regen re-derives them Then the standing re-cut, which recurs on every integration because main still authors imports: 4156 import lines removed from 109 files (brace-balanced: 340 spanned multiple lines, so a line-wise cut would have left dangling members) 4812 bare names qualified across 142 files 442 SELF-qualified across 36 files That last number is the one worth recording. The qualifier subtracts a file's own module from the declarer set, so it can never re-add a self-reference -- exactly the mechanism that lost 762 before. A count-based regression check flagged only 2 of the 36 affected files; deriving the rule instead (a name this file declares that ANOTHER module also declares is ambiguous whole-pool, so bare is wrong) found the other 34. Both flagged names were genuinely multi-declarer: witness_required_release_asset_digest_hex 2 declarers classify 3 declarers The one file the check still flags is a FALSE positive: main changed classify's signature and the file now has 5 call sites where it had 6. All 5 are qualified. A count cannot distinguish qualification lost from call sites removed upstream. INHERITED RED, pinned before this merge so it is not re-derived: main's only failure at this base is 4x "method 'keys' not found on receiver type 'Map(...)'" in trait_derive_supplemental_generic_bound_contract_test.dag, introduced by #8749 and fixed by the unmerged #8780. Any OTHER failure after this merge is mine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…uding one this lane authorized wrongly (#8776) * E0277 root partition at trait x self-type grain: four mechanisms, 82 sites, and one root that is outside its own mechanism's expressible range E0277 had no partition at E0277-only grain -- section 11 sized all codes together, and the July census counted occurrences rather than distinct sites. Measured live at one checkout (bb21f85), M=6, one dispatch: 82 distinct sites, 365 blocks (4.45x inflation within the class), zero unclassified. Four mechanisms: T5b 35 serde/Debug demanded over closure-bearing values -- no derive exists to add A 30 generic parameter bound not emitted (Clone 25, Ord 5) R3 9 Rc<dyn Fn..> handed to a parameter carrying an Fn bound T7/T5a 8 map-key derives missing on Fnv1a64Structural / OccurrenceId Three things the by-code view could not show: - The July ranking is falsified at site grain. Its dominant family is second at 36.6%, and its family-2 self types (Node, EnvironmentBindingKey) carry zero E0277 sites today. No attribution is offered for the move. - Root A's five Ord sites are not gaps in its coverage; they are outside its expressible range. Set<P> realizes as BTreeSet<P> and demands P: Ord, while the whole v1 supplemental-bound apparatus is a Clone-only fixpoint with no arm for any other trait. That is an executed requirement-side specimen for the wire-through trait_derive_emit_item_clone_bound_contract_fork_note already names. - T7/T5a is characterized and blocked in tree already (map_key_alias_hop_gap_note: attempted, measured, reverted, dissolution named). Subtract it rather than staff it. Controls run before any number was used: the exact-100 counts on two modules were checked against a 120-error local rustc control (no per-code cap exists) and against the logs' own totals; the classifier's RESIDUE arm was proven reachable with a fabricated signature, so zero-unclassified is a result rather than a silent absorb. Method correction: a comparison set must be ONE dispatch. Three parallel dispatches pinned from an earlier dispatch's resolved HEAD all refused with SAME_BASE_REFUSE because main moved twice inside the window -- the pin stopping the line rather than producing six numbers from three trees. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Key the probe's compiler on its tree: a base->head loop was silently measuring the base binary curated_cargo_probe_one.sh rebuilt gunbc/cssl_assemble only when the file was ABSENT. `-x` answers "does a binary exist", which is not the question a comparison asks. So a base->head loop inside one dispatch left the base tree's binary in place, and the head pass emitted with the PRE-FIX compiler while reporting head's SHA -- a FALSE IDENTICAL, read as "my fix changed nothing", with no failure arm anywhere to notice it. Found by royal-stag-736 while running the paired control for #8749, against their own interest: their first result said base and head were identical, and they root-caused it to the harness rather than banking it. Both binaries are now keyed on `git rev-parse HEAD` via a `<binary>.tree` stamp and rebuilt on a key miss. Rebuilding on a miss is a cache doing its job, not a fallback: the answer computed is the correct one for the checked-out tree, so nothing is degraded and nothing is absorbed. An absent or unreadable stamp is a miss, so an externally pinned GUNBC= rebuilds rather than being trusted on its filename. This is the binary-side twin of PROBE_EXPECT_BASE_SHA: that pins the TREE, this pins the COMPILER, and a confident number needs both. The invocation contract records it beside the other paid-for lessons, which is where the header says durable hazards belong. Executed, four arms: absent -> rebuild; no stamp -> rebuild; STALE stamp -> rebuild (the discriminating arm, reproducing the original bug); matching stamp -> reuse, so an ordinary single-tree probe pays no new rebuild. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * E0277 partition §20.1: four dispositions overtaken within hours, including one this lane authorized wrongly §20 landed this morning as a dated partition. By evening four of its rows were stale, and §9.1's rule is that a dated table left standing is what makes the next reader plan wrongly. This records the changes without restating or re-measuring the site counts. - T7/T5a's "blocked, subtract it" is stale: #8736 landed the DeclarationRef-keyed identity that map_key_alias_hop_gap_note named as its blocker. Correct when written, not now. - Root A's Ord half is closed by #8749, grounded on im::OrdSet rather than std BTreeSet and routed per derive impl with the type header left bare. Its first pass cited the std authority and left 16 real sites open -- caught by cargo, not by compile-clean. - The two residuals were one generalization, not two roots, and the fn-signature half's first implementation keyed on the `set_union` builtin BY NAME. Withdrawn by its own author once the structural route existed; three independent greps confirm no specimen needs it. - A header-level bound is not the general form of a per-derive one. Generalizing the item-header Clone fixpoint to Ord is the right ENGINE shape and the wrong OUTPUT: it reverts #8749's bare-header decision and forces P: Ord on four consumers that use P Ord-free. This lane authorized that design before another session caught it; the fork note's own control ("bound the derive, not the type") is what it violates. Also carries three method items that cost cycles twice: a .dag edit is inert until regen plus rebuild; the probe reused a stale binary across a base->head loop until #8763; and blocks, sites and grep mentions are three grains that must not be compared. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…lta, so #8758's carrier gets a corrected cause (two roots, per-site) and the four-name roster goes as cleanup (#8772) * wip: lambda_argument_scope (roster removal + per-arg lambda scope) * Correct #8758's carrier: the mechanism it names is refuted, the sites and the derivation stand The row asserted a cause -- emit_typed_call's four-name collection_scope gate produces the three E0282 sites. Two-arm emission over three closures, from two binaries whose difference was confirmed before either arm ran, is byte-identical: 258 files per arm, 0 differing files, 0 differing lines. A third arm deleting the binding entirely is also identical, which is what separates "refuted" from "my replacement happens to agree with the roster". The mechanism cannot reach emitted bytes: scope.locals has exactly one reader in the Rust emitter (is_already_optional) on the arm taken only when a node carries no resolved type, and the declared parameter types the gate was meant to supply are already bound onto the lambda's param nodes one stage earlier by infer_expr's ExprCall/ExprLambda path. THE DISSOLUTION TRIGGER WAS THE DANGEROUS HALF. It keyed on repairing that gate, so it was exactly satisfiable by a change that fixes nothing -- delete the roster, retire the row, three sites still red. A false cause misleads a reader; a false trigger disposes of the evidence. The replacement keys on the three sites emitting and compiling without an inference failure, and says outright that no repair to the gate satisfies it. Not over-retracted: the three sites, the E0282 x E0061 intersection that derived them, and UpperBoundPendingResidueCheck with its standing prediction all survive untouched -- none depended on the cause. The surface is still a bare-name-keying shape, now at the honest strength: syntactic, with no observable consequence. The reach figure is deleted rather than softened; it sized the blast radius of repairing a mechanism that changes no byte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Per-site cause on the lambda-typing-gate row, and finish #8597's map_keys conversion CARRIER: cause becomes a PER-SITE field, because the sites and the causes were established by different instruments with different groupings. The three sites were derived together by one intersection over one subject; the causes were established one site at a time by three cargo probes over three emitted closures. A single row-level CauseAttributed would force one instrument's grouping onto the other's -- the same collapse this row was already corrected for once. parse/parse_lexeme_digest StringDeclarationSiteAlias (help annotates ch) target_model/...apply_callee UntypedFoldInitAccumulator (help annotates acc) tokenize/lex_match_prefix StringDeclarationSiteAlias (help annotates a) Three real reds, TWO causes. Row-level CauseUnlocated is retired rather than answered, replaced by CauseGrouping = CausePerSite. The dissolution trigger now states that no single repair can fire it. The discriminator is free and sits in output everyone reads past: rustc's help names WHICH parameter it wants annotated. Element means the collection could not supply T; accumulator means the fold's init could not supply its own type. Also recorded: a pre-registered hunch that was REFUTED (field access on the lambda parameter was named in advance as the first place to look, and rustc's caret is on acc, never on row), and a warning that four E0282s in the parse crate belong to the held contains class so a count there is not a population. MAP_KEYS, NOT MINE AND SAID SO: the witness floor refuses on trait_derive_supplemental_generic_bound_contract_test.dag with "method 'keys' not found on receiver type 'Map(...)'". Confirmed pre-existing on main at c603c06 -- same file, same two lines, same message, on a commit unrelated to this branch. #8597 converted six sites in that file to map_keys and left two behind. This applies the same conversion to the stragglers; it repairs a main-wide red, not a defect this branch introduced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Retract 'closes a real leak' in the emitter comment: the same null refutes it The per-argument narrowing was described as closing a real leak -- one lambda's parameter names visible while emitting sibling arguments and filled defaults. That is a mechanism claim, and the measurement in this PR refutes it exactly as it refutes the roster: scope.locals is read once in the whole Rust emitter, on an arm taken only when a node carries no resolved type, so nothing measured shows the leak producing a wrong byte. It is now stated as construction cleanup with no measured current consequence -- narrowed because the narrow form is the correct construction, not because a defect was observed, and unearned as a repair until a fixture makes it observable. A change whose whole point is that an unmeasured mechanism claim was wrong must not carry a second unmeasured mechanism claim in its own text. Same defect, one level down. Caught by external review, not by me. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Correct the map_keys attribution: the two .keys() lines are #8749's, not #8597's Commit bbf4350 in this branch blamed #8597 for the two surviving `.keys()` call sites. That is wrong, and a commit repairing a main-wide red while misattributing it puts a false fact in the durable record beside a true fix. Verified per-commit on the file rather than taken on trust: #8726 dd1ac18 +6 map_keys lines, +0 .keys() lines #8749 8077603 +0 map_keys lines, +2 .keys() lines <- introduced both #8597 aa8a65e +0 in either direction, touched neither THE MECHANISM IS ALSO NOT WHAT bbf4350 SAID. It described an incomplete conversion -- six done, two missed. It was not. #8726's sweep was COMPLETE when it ran: it converted every site that existed at that point. #8749 then introduced NEW uses of the retired spelling, from a branch that predated the deletion. No census over #8726's tree could have found them, because they did not exist yet. So the class is REINTRODUCTION AFTER A SWEEP, not a missed census, and it is a merge-time question rather than a branch-time one: neither branch is wrong on its own, and the defect exists only in their union. Nothing guards that today. This two-line repair is therefore the right SCOPE and explicitly NOT the root. It clears a main-wide red; what stops the next reintroduction is unbuilt. Caught by quick-lynx-620 pushing back on the attribution I was given. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * File the second cause as its own row: untyped fold-init accumulator The target_model site in lambda_typing_gate_sites has a distinct cause with a distinct repair, so it gets a row. empty_map() in a fold's `empty:` position emits as v1_rt::rc_empty_map::<_, _>(); the only thing that could close those type parameters is the fold's own closure, which RECEIVES the accumulator -- so the target compiler is asked to infer a parameter's type from a body that uses it, and refuses. What rules out the neighbours, since this site was first filed under one: the collection is a genuine List<TargetEffectCalleeRow>, rustc never asks about `row`, and `acc` traces to the init rather than to the collection or the callee's spelling. The discriminator is rustc's own help text naming which parameter it wants annotated -- |acc: Type, row| here, |acc, ch: Type| for the collection-realization class. POPULATION IS ObservedSitesOnly. One measured site is not a census: this one was found only because it sat in a partition being probed member by member, and no sweep for untyped empty-collection literals in fold-init position has been run. The sweep is named rather than performed so the absence is a stated gap, not an implied zero. The site STAYS LISTED in lambda_typing_gate_sites with a cross-reference, because that row records that the three were derived TOGETHER by one intersection over one subject. Removing a member because its cause turned out to differ would destroy the only artifact of that derivation. Trigger is keyed to the site compiling, not to any repair -- the sibling row learned that the expensive way. It also refuses the cheap escape: annotating the closure at the call site moves the obligation to the author instead of deriving it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The census refused a synthetic control literal: give it the honest cause, not a copied one Adding per-site `cause` and `cause_receipt` to LambdaTypingGateSite made every existing literal incomplete, and the floor refused exactly one: dag/test/claim/long/cited_symbol_resolution_witness_test.dag's planted red control, landed by #8775 after this branch's type change was authored. That refusal is the fail-closed census working -- the widened type surfaced its one real dependent loudly rather than silently defaulting it. The planted site is SYNTHETIC: it names a declaration that does not exist, so no probe can have measured why it fails to type and there is nothing for a receipt to point at. It therefore carries SiteCauseUnmeasured / NotYetProbed, and an annotation says why it must stay that way -- copying a real site's cause here to make the literal look complete would put a measured attribution on a specimen no run produced, which is the fabricated-receipt failure the receipt field exists to prevent. Census over the corpus: this is the only LambdaTypingGateSite literal outside the carrier itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
std.authorization_profile.AudienceSet<P>'sEnumeratedAudience { members: Set<P> }realizes toim::OrdSet<P>(aliasedBTreeSet), whoseDebug,PartialEq,Serialize, andDeserializeall requireP: Ordto reconstruct/compare the ordering invariant — but v1's only supplemental-bound apparatus (v1_clone_bounded_type_params) is a Clone-only fixpoint and cannot emit aP: Ordbound at all, structurally, for any impl.This closes root A (the Ord half) of the E0277 partition by wiring
P: Ordthrough v2's existing per-derive-implTargetRepresentationChoicecontract — the same mechanism that already scopes bounds per trait impl — rather than unioningP: OrdontoAudienceSet<P>'s own type declaration (which would over-constrain every impl, including ones that don't need ordering).dag/extdeps/languages/rust/derive_contracts.dag: addsrust_btree_set_supplemental_generic_bound_rows, a single-authority row citing theim::OrdSetrealization, feedingP: Ordinto the Debug/PartialEq/Serialize/Deserialize derive-impl bound sets (not the type header).src/v2/extdeps/languages/rust.dag: folds that row intorust_btree_set_supplemental_generic_bound_contracts, one entry per derive impl, via the existingTargetRepresentationChoicecontract.src/v1/trait_derive_emit.dag: forAudienceSet<P>, emits hand-splitimpl<P: Ord + std::fmt::Debug> Debug for AudienceSet<P>andimpl<P: Ord + PartialEq> PartialEq for AudienceSet<P>, plus a combined#[serde(bound(serialize = "P: Ord + Clone + serde::Serialize", deserialize = "P: Ord + Clone + serde::Deserialize<'de>"))]— bounding each derive, never the enum's own generic parameter list (confirmed by direct emission inspection:pub enum AudienceSet<P> { ... }carries noOrdbound on head).src/v1/stage0/src/{extdeps_languages_rust_derive_contracts,v1_compiler_trait_derive_emit}.rsare the regenerated seed-emit mirrors.Verified control probe (base
033647789f2vs head6d912c650d9, same instrument)Ran the paired probe (
docs/probes/curated_cargo_probe_one.shagainstsrc/v2/compiler/emit_host.dag) on both trees, withtarget/release/{gunbc,cssl_assemble}explicitly cleared between checkouts to force a genuine rebuild each pass (the shared probe script only rebuilt on binary-absence at the time; this is now fixed upstream in gunbc#8763). Both trees confirmed viagit rev-parse HEADbefore each pass.Three different grains were measured off the same paired log; they are not commensurable and are reported separately (a mention-grain grep -c over-counts by including rustc's
note:/backtrace context lines, in the direction that makes the change look worse than it is):grep -c '^error\[E0277\]'— one per diagnostic(file, line, col)at the top-->of eachP: Ord-bound blockstd_authorization_profile.rs:17:53,22:9,22:18,62:72,73:14, matching exactly the 5root=A, trait=Ordrows indocs/probes/e0277_partition_2026-08-21/sites_classified.tsv(main), built from a full unbounded context read in a separate session/instrument. That partition's treebb21f8563849bis a verified strict ancestor of this PR's base033647789f2, 8 commits apart, none of which touchesdag/std/authorization_profile.dag,src/v1/trait_derive_emit.dag, ordag/extdeps/languages/rust/derive_contracts.dag— so the declaration and the emitter's bound apparatus are unchanged across that interval, and this base's block count (7) independently matches that TSV run's preserved block count (7) as the join. This is corroboration by an unchanged-interval argument over three specific files, not a re-derivation at033647789f2itself — a ninth path that changed emitted output without touching those three files would not be caught by it.std_authorization_profile.rs82:72/93:14(audience_subset/audience_joinfn signatures), plus 16 sites across the derive lines andaudiencefields ofPublicationContext,PublicationAdmissionRequest,DisclosureContext,DisclosureRequest— zero of the 18 isAudienceSet<P>'s own declaration line; it appears only as anote: required for AudienceSet<P> to implement Debug/Serialize/Deserializebacktrace target, never as a block's own-->locationgrep -c 'P: Ord')The site grain is the one that actually answers the question: base's 5 sites are all
AudienceSet<P>'s own declaration (root A's exact target); head's 18 P:Ord sites are all downstream of it, split across the two already-identified, already out-of-scope gaps:P: Ordthemselves but call intoAudienceSet<P>'s Debug/Serialize (audience_subset,audience_join) — the fn-signature Ord-bound-inference gap.Rc<AudienceSet<P>>(PublicationContext,PublicationAdmissionRequest,DisclosureContext,DisclosureRequest) and derive Debug/Serialize/Deserialize without declaringP: Ordin their own generic bounds — the struct-to-struct transitive Ord-propagation gap. (Several of these 18 sites report twice — once via serde'sSeqAccess/next_elementpath and once viaMapAccess/next_value— which is also why 22 blocks map onto 18 distinct sites, not 18 blocks; the remaining 91 of head's 113 total E0277 blocks are unrelated trait bounds, e.g.Clone/PartialEqon other types, untouched by this PR.)Fixing
AudienceSet<P>'s own impls correctly removes a rustc error-cascade suppression: previously the primary error at the enum's own declaration masked the fact that every downstream caller/wrapper was also unsound. Once the primary site is fixed, those latent errors surface as their own independent E0277s — which is why the block and mention counts go up even though root A is closed (5 sites → 0 sites at the declaration). This matches DESIGN.md §5's fail-closed doctrine: a wrong state loudly refusing at more sites than before is not a regression when the newly-visible sites were always wrong and were previously hidden by cascade suppression, not by correctness.Scope
In scope / closed by this PR: the Ord-supplement-contract sites on
AudienceSet<P>'s own derive (root A, the 5 target sites) — the type does not gain anOrdbound on its own declaration; only the derive impls that actually need it do.Explicitly out of scope, open, and separately owned:
audience_subset,audience_join) — owned byadhoc-a9f61ade-340(session tidy-otter-493).PublicationContext,PublicationAdmissionRequest, similar wrapper structs) — owned byadhoc-1e0dee2d-68f(session quick-boar-406).Test plan
claim_executor --required-regen --source-root dag --source-root src/v2reportsfirst_generation_equal=true planned=129 executed=129against the committed mirrors (remote verification run).src/v2/extdeps/languages/rust.dagclean (0 blocking errors, matches the clean-baseline advisory diagnostic count).AudienceSet<P>'s emitted source: hand-splitDebug/PartialEqimpls boundedP: Ord, combinedserde(bound(...))citingP: Ord + Clone + Serialize/Deserialize, and the enum's own declarationpub enum AudienceSet<P> { ... }carrying no type-levelOrdbound.AudienceSet<P>'s own declaration goes from 5 sites on base to 0 on head, and every one of head's 18 P:Ord sites is attributable to the two named out-of-scope gaps.🤖 Generated with Claude Code
https://claude.ai/code/session_012effhE2DWnG9871r4cptWp