Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions dag/gunbc/declaration_index_seed_growth.dag
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ data declaration_index_seed_growth_justification: SeedGrowthJustification = Seed
decl_name: "collect_reference_occurrences",
field: WholeDeclaration
},
DeclarationRef {
module_path: "v1_compiler.declaration_index",
decl_name: "authored_type_references_from_transport",
field: WholeDeclaration
},
DeclarationRef {
module_path: "v1_compiler.declaration_index",
decl_name: "record_from_module",
Expand Down Expand Up @@ -400,3 +405,5 @@ data declaration_index_fixture_exemption_classification_stall: GuaranteeStall =
data declaration_index_site_grain_roster_note: String = "THE SUPPRESSION ROSTERS MOVED FROM TARGET GRAIN TO SITE GRAIN (gunbc#9328). Recorded here rather than silently amended, for the reason the two rows above are: the grain of an exemption roster is the whole content of whether it is a contract or a hole, and this carrier had disclosed the previous grain as if it were sound.\n\nWHAT WAS HERE. All three rosters -- PRE_EXISTING_CITATION_DEBT, PLANTED_CONTROL_CITATIONS, FIXTURE_CARRIER_CITATION_EXEMPTIONS -- were keyed (cited module, declaration, field). citation_in_roster read the CITED symbol only, so a row exempted that target corpus-wide and permanently. A patch could author a BRAND NEW dangling DeclarationRef naming any enrolled target, from a module that had never cited it, and the wall stayed silent -- a fail-open inside the mechanism built to refuse exactly that class, and decidable from the patch alone.\n\nOCCUPIED, NOT MERELY REACHABLE, measured over DAG_PARSE_SWEEP_ROOTS: the 70 target-keyed rows covered 87 refusing sites, and seven targets were already cited from more than one module -- gunbc.host_effect host_effect_apply from three, std.bytes builtin_function_registry from three, extdeps.network.mac parse_mac_address from two, four more from two apiece. Every extra site was suppressed by a row authored about a different module.\n\nWHAT LANDED. A row is (citing module, citing declaration, cited module, declaration, field) and exempts THE SITE THAT AUTHORED IT. Both inverse arms read that one identity through a single refusing_sites set, because a suppression arm and a staleness arm keyed differently is the desynchronization this carrier already records once. The rosters are re-derived from the measurement rather than hand-extended: 42 debt, 41 fixture, 4 control, 87 sites, corpus clean.\n\nTHE FIRST DERIVATION WAS TAKEN OVER THE WRONG DENOMINATOR, and it is recorded because it is this carrier's own recurring class arriving a third time. The sweep's roots are src/v1, dag and src/v2; the first measurement used only the last two, so five sites in modules the narrow walk never read were absent from the rosters and the required run refused them. A roster derived from a subset of the subject it governs is not a smaller roster, it is a wrong one.\n\nHAND-ITEM DELTA: +5, enumerated in the roster above rather than counted -- citation_site, refusing_sites and site_owned in declaration_index.rs, and two discriminating tests, a_new_citation_of_an_enrolled_target_from_another_module_still_refuses and a_roster_row_exempts_its_own_citer_and_no_other. No file is added, no impl block is introduced, and every one of the five is citable as a WholeDeclaration. The trigger is unchanged and now names 60: these dissolve with the index, not separately.\n\nRUNG: unchanged at MECHANICALLY PREVENTABLE. This is a repair of an open direction in an existing wall, not a climb -- the invalid state stays writable and safety still depends on the phase executing. The red is authorable and authored at the FIXTURE boundary: both tests above go GREEN under the target-keyed form, which is the state they exist to forbid.\n\nTHE DECLARATION WAS ADDED AFTER REVIEW AND IT IS THE SAME REPAIR ONE LEVEL IN (review 56227). The first cut keyed a row on the citing MODULE, which left two citations of one target inside one module sharing a row -- so a new dangling citation authored BESIDE an enrolled one stayed suppressed. That was DISCLOSED as residue rather than closed, and the objection was that a residue whose closing identity is already available is not a residue. It was available: record_from_module already iterates top-level items, so the enclosing declaration name costs one string at extraction, and it is a NAME reachable from the containment tree rather than the offset DESIGN section 3 forbids. Closed, with a_second_citation_of_an_enrolled_target_in_another_declaration_still_refuses as the discriminating red -- it reports zero findings under the module grain.\n\nWHAT IS NOT REACHED, stated because a closed residue must not be reported as a total one: two citations of one target inside ONE DECLARATION still share a row. Only a position separates those, and a position is what this grain exists not to be, so this is a CEILING rather than a stall. The next rung would be an occurrence ordinal within the declaration -- representable in the record, needed by no measured site today."

data declaration_index_reference_channel_selectivity_note: String = "THE REFERENCE CHANNEL BECAME SELECTIVE BY NODE KIND (gunbc, this change). Recorded here rather than only in the Rust doc comment, because the previous behaviour was DECLARED SOUND on this carrier's own construction -- record_from_module collected every authored name in a module's tree and the field's doc argued the over-collection was harmless -- and a refuted argument has to be retired where it was made.\n\nTHE ARGUMENT AND WHY IT IS WRONG. It read: the over-collection is SYMMETRIC across the two trees v1_compiler.namespace_wave_admission compares, so a spelling that denotes nothing on both sides contributes no delta. A symmetric COLLECTOR does not give a symmetric VERDICT. The supplier set the wall computes for a row is a function of the CORPUS, not of the site, so deleting an unrelated declaration moves it under every site that merely spells the same word -- and a field label spells words.\n\nTHE SPECIMEN, MEASURED RATHER THAN PREDICTED. On gunbc#9106 a witness module deleted a helper fn live_tree_declined_entries and kept twelve RECORD FIELD LABELS of that spelling. Twelve labels, twelve enclosing declarations, twelve NewUnresolvedness rows, one-to-one, against a correct cut. The delta was TRUE about the declaration and FALSE about every site it named: a label binds to nothing and needs no supplier at all.\n\nWHAT LANDED, IN THE SHAPE THE CITED COLLECTOR ON THE SAME WALK ALREADY USED -- decide by node kind, never by name. Two kinds stop being references. First, a record literal's FIELD LABELS: ExprRecordLit's children are its field initializers and nothing else, so the label is decidable from the parent's kind with no guessing, and the initializer's VALUE is still walked because that is where a reference lives. Second, a field projection's MEMBER name: f.widget names a field of a value, not a declaration. The whole dotted spelling is still recorded, which is what module_prefix_of needs to keep a module-qualified reference such as probe.home.widget resolving, and the wall keys on the last segment either way. A name-based suppression list was refused: it would be the same defect one layer up.\n\nWHAT IS NOT REPAIRED, stated because a partial repair reported as a total one is worse than none. A record TYPE declaration's field labels, a named call argument's label, a parameter binder and a coproduct's variant names are STILL collected as references, and each can fabricate the same refusal from a different position. Measured on a fixture rather than assumed: a type declaring a field named tag contributes tag, and a call passing an argument labelled tag contributes tag. They are not swept in here because the parent kinds carrying them also carry children that ARE real references -- a refinement's base type expression is a Connective Conj child with a real type name -- so a parent-kind rule for them cannot be lifted from this one and needs its own fixture. Excluding them by guessing would risk the opposite defect, which is strictly worse: a wall that stops seeing genuine unresolvedness is a decoration.\n\nEVIDENCE, BOTH DIRECTIONS, AT THE FIXTURE BOUNDARY, in the wave wall's own fixture file. RED: deleting_a_declaration_a_record_field_label_merely_spells_carries_no_delta, which reports exactly the specimen's NewUnresolvedness under the previous collector and nothing under this one. GREEN, and this is the half that matters: deleting_a_declaration_a_body_still_references_is_still_unresolvedness and deleting_a_declaration_a_qualified_spelling_reaches_is_still_unresolvedness both require the wall to KEEP refusing a deletion that a real reference reaches, one bare and one dotted. The second is the control on the projection half specifically, because a repair that had dropped the dotted spelling instead of the member name would green the red and silence that arm with it.\n\nRUNG: unchanged at MECHANICALLY PREVENTABLE. This is a repair of a fabricated-refusal direction in an existing wall, not a climb. HAND-ITEM DELTA: plus one, collect_reference_occurrences, enumerated in the roster above; record_from_module's inline walk is replaced by a call to it rather than duplicated, and no other declaration is added. The three test arms live in the wave wall's fixture file, whose carrier gunbc.namespace_wave_admission enumerates lib declarations rather than test arms."

data declaration_index_authored_reference_channels_note: String = "TWO AUTHORED REFERENCES THE INDEX COULD NOT REACH, AND THE FALSE GREEN THEY PRODUCED (gunbc, this change). Recorded beside the selectivity note above rather than only in the Rust doc comment, because the two are the SAME FUNCTION moving in OPPOSITE DIRECTIONS -- that one removed fabricated references, this one recovers missing ones -- and a reader who finds only one will conclude the channel is being narrowed or widened as a policy rather than corrected against what the source authors.\n\nWHAT WAS MISSING. collect_reference_occurrences walks a Node through seven child slots. Two authored references are reachable through NEITHER. A VARIANT PATTERN HEAD is a raw String on MatchPattern, not a Node, so a module whose only use of an imported coproduct is naming its variants in match arms contributed nothing. A DECLARED FIELD TYPE is parked by v1.02_parse field_to_child_node in the inferred slot, and every authored-name reader correctly declines to read a slot whose contract says DERIVED.\n\nWHAT THE CONSEQUENCE WAS. v1_compiler.namespace_wave_admission membership_bound_through answered NO about an import whose name is still referenced in the very tree it examined, and the wall reported the live import as UnusedSubjectMembershipRemoved. That is a GREEN, not a refusal, so nothing stops -- and the verdict's natural next action is to delete the import the wall failed to see.\n\nTHE CONSTRUCTION, AND IT IS THE SECOND ONE AUTHORED FOR THIS DEFECT. The first read both facts back off the final Node. An operator ruling narrowed the permitted construction to consuming the parser's existing OccurrenceTransport, and the RATIONALE is what decides the shape rather than the letter: the parser already stamps the fact exactly, so a Node-reading projection is a SECOND AUTHORITY free to diverge from the first. Measured, that is exact for the declared field type -- stamp_parsed_inferred stamps a Resolved inferred node as ParsedOccurrenceReference TypeOccurrence, and the stamp is on the SLOT, so the generic-over-the-form property the first construction gained is precisely the property the transport already owned. The first construction was reimplementing stamp_parsed_inferred from its own output. The seam is one argument wide: CensusFillParse already carries occurrence_transport and both callers already hold one at the line they call record_from_module, so the fact was PRODUCED AND DISCARDED at a return boundary rather than absent.\n\nWHY THE PATTERN HEAD STILL READS AN AUTHORED STRING, and this is a scope finding rather than an exception taken. The rationale has NO REFERENT for that position: MatchPattern.VariantPattern.name is a String, stamp_parsed_pattern stamps field_bindings only, ConstructorOccurrence is stamped NOWHERE in v1_compiler_parse, and occurrence ids are minted per Node so a String can never carry one. The parser mints nothing there, so there is no first authority to be second to -- reading the authored String is not re-derivation, it is the only derivation, and a prohibition whose stated reason does not apply is not extended by its letter. The transport repair for that half is BLOCKED ON A RULING, NOT ON A RISK: the obvious objection was that a new stamp shifts every id allocated after it in a sequential allocator, and that objection is answered -- v2.std.node content_hash folds node kind, edge labels and child hashes and NOT the occurrence id, and v2.workflow.legacy_binding_delta states outright that an OccurrenceId is not a stable cross-compile name BECAUSE the counter is consumed in DFS order, naming inserted tokens as exactly the edit that shifts ids. The corpus does not merely lack a dependency on id stability, it declares that dependency illegitimate. What remains is that stamping a new occurrence is a parser change, which is an authority question.\n\nA PEER FIELD, NOT A WIDENED referenced, as the ruling directs, and the reason survives the ruling: the two sets have different authorities and different precision, and fusing them would hide which is which behind one name. authored_type_references carries the transport's answer; referenced remains the index's own walk. The consumer takes the union, so nothing downstream needs to know which channel supplied a row, and the walk can shrink toward zero as more positions gain transport entries.\n\nTHE FILTER THAT IS LOAD-BEARING RATHER THAN TIDINESS. Only references enclosed by a declaration THIS MODULE DECLARES are taken. The transport stamps an IMPORT MEMBER NAME as a TypeOccurrence enclosed by the import target -- measured, import probe.other { gadget } yields the row (probe.other, gadget) -- so consuming every TypeOccurrence makes each import bound-through by its own member and UnusedSubjectMembershipRemoved becomes UNREACHABLE. A disposition going permanently quiet is strictly worse than the false green this change closes: one wrong verdict against a wall that can no longer fire. It was caught by a PRE-EXISTING arm, not by review and not by any arm authored here.\n\nEVIDENCE, SEVEN ARMS AT THE FIXTURE BOUNDARY, ON THE REMOVAL SIDE DELIBERATELY, WITH A THREE-WAY MUTATION RECEIPT RE-TAKEN AGAINST THIS CONSTRUCTION. The add side cannot test this at all: gunbc#9490 made an import claim answer membership outright for ADD, so an add-side fixture goes green with the repair AND with it reverted -- measured, that arm stayed green under both channel mutations. Deleting the pattern-head read fails 2; yielding nothing from the transport fails 3; deleting the import-member filter fails 2, one of them the pre-existing unused-removal arm; unmutated, 27 pass. The scope question was settled by execution: a type alias RHS reproduces the same false green and is enrolled, a function return type does not reproduce and is recorded as a measured negative rather than enrolled, because an arm there would pass either way.\n\nRUNG: unchanged at MECHANICALLY PREVENTABLE. A repair of a false-green direction in an existing wall, the mirror of the selectivity note's false-refusal repair. HAND-ITEM DELTA: plus one, authored_type_references_from_transport, enumerated in the roster above; the pattern-head block sits inside collect_reference_occurrences which the roster already enumerates, and record_from_module gains one parameter rather than a declaration."
1 change: 1 addition & 0 deletions src/v1/stage0/src/cli_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18412,6 +18412,7 @@ pub fn run_dag_parse_sweep(workspace: &Path, roots: &[&str]) -> Result<DagParseS
module,
&source_indices,
&rel,
&fill.occurrence_transport,
));
}
records.lock().expect("record lock").extend(built);
Expand Down
Loading
Loading