diff --git a/src/v1/stage0/src/namespace_wave_admission.rs b/src/v1/stage0/src/namespace_wave_admission.rs index 5ee8d1fbe8e..6eab3da435d 100644 --- a/src/v1/stage0/src/namespace_wave_admission.rs +++ b/src/v1/stage0/src/namespace_wave_admission.rs @@ -1799,13 +1799,491 @@ pub struct TransitionAdmission { /// with the transition present at the base there is no delta left for these to admit, so deleting /// them removes nothing that could still fire. /// -/// THE ROSTER IS EMPTY AGAIN, which is its resting state. The #11182 relocation rows that an -/// earlier revision of this block described as surviving are no longer here either; that claim -/// was already stale on main, where the array held one row, and it is repaired now because this -/// is the roster's own next touch. The distinction the paragraph above draws still holds and is -/// why it is kept: a consumed row goes because its transition is PRESENT AT THE BASE, not because -/// the array was being emptied. -pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[]; +/// THIRTY-NINTH DISSOLUTION (2026-09-14). The one `gunbc#11193 artifact_store_fs anchor leaf` +/// row is deleted, and the block that described it goes with it. +/// +/// CONSUMED BY ITS OWN MERGE, the same shape as the thirty-eighth. gunbc#11347 landed the source +/// change and the admission row together, so once it reached main the transition was present at +/// the base: `dag/extdeps/realization/artifact_store_fs.dag` line 3 on origin/main carries +/// `import extdeps.filesystem.filesystem_io { Filesystem }`, checked by identity, and the floor on +/// this branch reported the row as `1 consumed admission(s) due for correction or deletion` +/// naming it. +/// +/// THIS BRANCH CARRIED THE ROW FORWARD ONE MERGE BEFORE DELETING IT, and that was correct both +/// times rather than an oversight corrected: at the first merge the row was live at that base and +/// preserving another lane's row is what the conflict rule requires; at this one it is consumed +/// and the debt is due on the roster's next touch, which is this change. +/// +/// NO EXECUTED VERDICT CHANGES. With the import at the base there is no delta left for the row to +/// admit. +/// +/// gunbc#11138 string_eq collapse (2026-09-12). The 37 rows below admit the relocation this +/// change makes, one per call site the required floor enumerated. +/// +/// +/// THAT RETIREMENT ALSO LANDED ON MAIN, in gunbc#11356, which deleted the same single +/// `gunbc#11193 artifact_store_fs anchor leaf` row AND REMOVED THE BLOCK THAT DESCRIBED IT, so +/// main now names neither the row nor the check that retired it. The entry above is kept rather +/// than dropped as a duplicate because it is the only place in this file that NAMES the retired +/// row and records the identity check that admitted the deletion -- the history main +/// intentionally dropped along with the row. One retirement, recorded once, by the side that +/// wrote down what it was. +/// +/// NOT THE `two rows` RETIREMENT, and an earlier wording of this paragraph conflated them. Main's +/// surviving two-rows prose is the THIRTY-SEVENTH dissolution, the `gunbc#11156` pair discharged +/// by #11156 merging -- a different retirement, a different trigger, a different population. It +/// says nothing about the #11193 row either way, so it was never evidence that main had failed to +/// say which row went. +/// +/// THE ROSTER RETURNED TO EMPTY ON MAIN, which is its resting state, AND THIS BRANCH REFILLS IT. +/// Main's correction is kept because it is true and this branch's earlier wording was not: the +/// #11182 relocation rows an older revision of this block described as surviving are gone, that +/// claim was already stale on main where the array held one row, and gunbc#11274 retired them. +/// This branch does not restore them and does not re-assert them. What follows the header below +/// is a DIFFERENT population -- the 37 `string_eq` rows this change owes -- so the array is +/// non-empty here for a reason stated at its own site rather than because emptiness was undone. +/// The distinction main draws still holds and is why it is kept: a consumed row goes because its +/// transition is PRESENT AT THE BASE, not because the array was being emptied. + +/// WHAT THE CHANGE DID. `fn string_eq(a: String, b: String) -> Bool { a == b }` was declared +/// byte-identical in every `v2.lens` module that needed it. This change deletes those bodies -- +/// the delta is read from the diff, `git diff origin/main...HEAD -- '*.dag' | grep '^-fn +/// [a-z_]*string_eq'`, not from a count transcribed here -- and lands an authority in +/// `v2.std.text`, beside `char_eq`, its exact peer: both are equality folds over that module's +/// own carrier, and `char_eq` is already the `eq` argument to `list_starts_with` exactly as +/// `string_eq` is the `eq` argument to `contains`. +/// +/// WHY `TargetChanged` IS THE CORRECT CLASSIFICATION. The spelling `string_eq` is authored on +/// both sides at every one of the 37 sites below, and what changed is which declaration it +/// admits: base `{}`, head `{v2.std.text}`. A name answered by the +/// consumer's own copy is now answered by the shared one. That is a relocation, not an +/// `AuthoredReferenceResolution`. +/// +/// WHAT MAKES IT SAFE TO ADMIT, adjudicated rather than asserted. EVERY DELETED BODY WAS +/// BYTE-IDENTICAL -- `a == b`, same signature -- so every call site denotes exactly the function +/// it denoted at the base. A body differing anywhere would have made this a semantic change +/// wearing a relocation's name, which is what this adjudication exists to rule out, so each was +/// compared before the collapse rather than assumed equal from the shared spelling. +/// +/// THE AUTHORITY IS LANDED; SINGLE AUTHORITY IS NOT YET REACHED, and the gap is larger than what +/// this change deletes. +/// +/// THE SURVIVOR POPULATION IS NAMED BY ITS INSTRUMENT, NOT ENUMERATED HERE (§6), because an +/// enumeration in this file is a transcription that rots -- and the first attempt at one was +/// already wrong, short by six, assembled by a NARROWER search than the command it was filed +/// under. Re-derive with: +/// +/// grep -rnE '^fn [a-z_]*string_eq[a-z_]*\(' --include=*.dag dag/ src/v2 +/// +/// Every hit whose body is `a == b` over `(a: String, b: String) -> Bool` is one home for this +/// concept. `v2.std.text` is the authority; every other hit is a fork of it. +/// +/// WHAT THAT COMMAND SHOWS THAT THE DELETION DID NOT REACH: survivors under NICKNAMED spellings, +/// byte-identical to the authority but invisible to a search for the exact name. That is §3's +/// NICKNAME surviving precisely because a name-shaped search does not find it -- which is why the +/// frontier below is adjudicated by that command and not by a roll call in this file. +/// +/// NO SURVIVOR STATES ITS OWN RETENTION. Two earlier wordings of this header were wrong here in +/// opposite directions: the first claimed every survivor was declared, the second claimed +/// `v2.lens.enforcement.grammar_coverage` `grammar_coverage_string_eq` was the one that was. The +/// second is now moot because that clone is gone: its stated retention was that the module +/// declared no imports, so the one import the collapse needs would move it into its own import +/// closure and strand `dedupe_snoc`, `tokenize` and `parse_module`. That is a real obstacle and +/// it is not a dissolution trigger -- it named source work this change can express -- so the +/// module now declares its own import surface and calls the authority. EVERY HIT THE COMMAND +/// STILL FINDS IS UNDECLARED RESIDUE: no reason recorded, no retention stated, nothing at its +/// declaration saying why it survives. The claim that any of it is declared is exactly the kind +/// of statement this header exists to refuse -- it told a reader asking `is this residue tracked` +/// YES, in the authority they consult first. +/// +/// DECLARED FRONTIER (§3c), with a trigger that adjudicates itself against the tree rather than +/// against a list this file keeps: the frontier closes when the command above returns exactly ONE +/// declaration, in `v2.std.text`. A trigger adjudicated against an enumeration would have been +/// satisfiable while the concept stayed forked, because the enumeration was wrong -- the §4b(1) +/// inflation this phrasing exists to avoid. +/// +/// WHY THE REST IS NOT IN THIS CHANGE: each further consumer produces its own `TargetChanged` +/// delta needing an adjudicated row, and the `dag/` files would be the first `dag/` modules +/// importing `v2.std.text` for this name -- legal under acyclicity, a different reach question, +/// and one that deserves its own evidence. +/// +/// TRIGGER for the 37 rows: they go when #11138 merges, at which point the base carries the +/// shared declaration, the deltas stop being producible, and CONSUMED comes due on the roster's +/// next touch -- adjudicated by the declaring-module join, not by this sentence. +const STRING_EQ_COLLAPSE_LABEL: &str = "gunbc#11138 string_eq collapse to v2.std.text"; + +pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[ + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.complexity_linearity_audit", + in_declaration: "migration_roster_contains", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.effect_reach", + in_declaration: "callee_text_is_host_sink", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.effect_reach", + in_declaration: "data_init_belongs_to_modules", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.effect_reach", + in_declaration: "flow_eq", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.effect_reach", + in_declaration: "path_literal_from_lexeme", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.effect_reach", + in_declaration: "sink_kind_for_callee", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.enforcement.vocab", + in_declaration: "scope_roster_covers", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.fact_cardinality", + in_declaration: "add_unseen_key", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "callee_text_is_known_carrier", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "carrier_for_callee_text", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "carrier_homes_in_closure", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "classification_has_literal_path", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "decls_with_qualified_name", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "live_read_carrier_eq", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "module_facts_for_path", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "modules_of_closure_paths", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "path_pattern_eq", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "path_pattern_from_lexeme", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.live_read_classification", + in_declaration: "runtime_read_carrier_module_names", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.manufactured_dependency_census", + in_declaration: "edge_is_manufactured", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.manufactured_dependency_census", + in_declaration: "snoc_unseen", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.module_graph", + in_declaration: "add_unseen", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.module_graph", + in_declaration: "bfs_absorb_neighbor", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.module_graph", + in_declaration: "path_matches_touched", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.module_graph", + in_declaration: "snoc_unseen_list", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.production_qualification_origin_probe", + in_declaration: "decl_contains_atom", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.production_qualification_origin_probe", + in_declaration: "decl_contains_callee", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.production_qualification_origin_probe", + in_declaration: "maybe_snoc_callee_text", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.production_qualification_origin_probe", + in_declaration: "node_contains_atom_text", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.production_qualification_origin_probe", + in_declaration: "site_row_already_present", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.production_qualification_origin_probe", + in_declaration: "structural_red_control_live_fixture_mint_site_discovered", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.reference_deps", + in_declaration: "reference_corpus_paths_live", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.reference_deps", + in_declaration: "reference_fact_eq", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.reference_deps", + in_declaration: "reference_import_facts_at_path", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.reference_deps", + in_declaration: "reference_neighbor_paths_from_facts", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.reference_deps", + in_declaration: "reference_paths_from_import_edges", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: STRING_EQ_COLLAPSE_LABEL, + subject: AdmissionSubject::Binding { + module: "v2.lens.reference_deps", + in_declaration: "reference_paths_from_module_declarations", + spelling: "string_eq", + expected_candidates: &["v2.std.text"], + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, +]; /// The denominators a green must name (DESIGN §5): a run that cannot say what it covered is an /// instrument failure wearing coverage's clothes. diff --git a/src/v2/lens/complexity_linearity_audit.dag b/src/v2/lens/complexity_linearity_audit.dag index 81c6b972821..905115a2259 100644 --- a/src/v2/lens/complexity_linearity_audit.dag +++ b/src/v2/lens/complexity_linearity_audit.dag @@ -3,6 +3,7 @@ module v2.lens.complexity_linearity_audit import std.roster_frontier { FrontierRow, frontier_row_path, frontier_units } import std.dissolution { DissolutionCondition, unbound_dissolution } +import v2.std.text { string_eq } data complexity_linearity_debt_row_reason: String = "closed-coproduct wildcard arm classified migration-debt (not kernel-permanent): the match is over a closed coproduct and the wildcard hides arms a total match would surface" data complexity_linearity_debt_row_dissolve: DissolutionCondition = unbound_dissolution(description: "the site's wildcard arm migrates to a total match; row deletes (roster-wide, the construction justification dissolves to SubstrateMandatoryTag)") @@ -48,10 +49,6 @@ type ComplexityLinearityWildcardFact { rostered: Bool } -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn complexity_linearity_wildcard_facts_live() -> List { complexity_linearity_wildcard_facts() } diff --git a/src/v2/lens/effect_reach.dag b/src/v2/lens/effect_reach.dag index 0dcdbc4fed9..440aa5646e0 100644 --- a/src/v2/lens/effect_reach.dag +++ b/src/v2/lens/effect_reach.dag @@ -61,7 +61,7 @@ import v2.std.node { Symbol, fold_node } -import v2.std.text { String } +import v2.std.text { String, string_eq } // This consumer's subject is DIRECTORY-GRAIN: it names roots and no single modules. data no_declared_pool_files: List = [] @@ -77,10 +77,6 @@ data empty_string_list: List = [] data empty_symbol_list: List = [] data empty_node_list: List = [] -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn callee_text_is_host_sink(text: String) -> Bool { contains(xs: effect_reach_host_sink_callee_symbols_v0, item: text, eq: string_eq) } diff --git a/src/v2/lens/enforcement/grammar_coverage.dag b/src/v2/lens/enforcement/grammar_coverage.dag index 6bc7efd994a..b7a78d7bb81 100644 --- a/src/v2/lens/enforcement/grammar_coverage.dag +++ b/src/v2/lens/enforcement/grammar_coverage.dag @@ -1,5 +1,18 @@ module v2.lens.enforcement.grammar_coverage +import extdeps.filesystem.filesystem_io { Filesystem } +import v2.compiler.parse { parse_module } +import v2.compiler.tokenize { tokenize } +import v2.extdeps.languages.dag { dag_language_model } +import v2.lens.coverage { dedupe_snoc } +import v2.std.algebra { fold_list, length, list_append } +import v2.std.collection { List } +import v2.std.diagnostic { Accepted, Rejected } +import v2.std.integer { Int } +import v2.std.logic { Bool } +import v2.std.node { Symbol, symbol_identity_digest } +import v2.std.text { String, string_eq } + type GrammarCoverageParseVerdict = ParsedClean @@ -49,10 +62,6 @@ data grammar_coverage_file_anchor: Symbol = ^grammar_coverage_file_anchor data grammar_coverage_reject_probe: Symbol = ^grammar_coverage_reject_probe -fn grammar_coverage_string_eq(a: String, b: String) -> Bool { - a == b -} - fn grammar_coverage_tree_root_for_path(path: String) -> String { if path.starts_with(prefix: "dag/") { "dag" @@ -73,7 +82,7 @@ fn grammar_coverage_distinct_rel_paths(facts: List) dedupe_snoc( acc: acc, item: fact.rel_path, - eq: grammar_coverage_string_eq + eq: string_eq ) } ) @@ -332,7 +341,7 @@ fn grammar_coverage_roster_contains_path( xs: roster, empty: false, cons: fn(acc, p) { - acc || grammar_coverage_string_eq(a: p, b: path) + acc || string_eq(a: p, b: path) } ) } diff --git a/src/v2/lens/enforcement/lens_module_gate.dag b/src/v2/lens/enforcement/lens_module_gate.dag index 75cd56ae517..5a52e31449b 100644 --- a/src/v2/lens/enforcement/lens_module_gate.dag +++ b/src/v2/lens/enforcement/lens_module_gate.dag @@ -32,7 +32,7 @@ import v2.std.collection { List } import v2.std.integer { Int } import v2.std.logic { Bool } import v2.std.live_tree { LiveTreeDisposition, ReadsLiveTree } -import v2.std.text { String } +import v2.std.text { String, string_eq } data live_tree_disposition: LiveTreeDisposition = ReadsLiveTree @@ -87,12 +87,8 @@ type VerdictRemedyPair { remedy: LensInvariantRemedy } -fn lens_module_gate_string_eq(a: String, b: String) -> Bool { - a == b -} - fn lens_module_gate_string_member(xs: List, x: String) -> Bool { - contains(xs: xs, item: x, eq: lens_module_gate_string_eq) + contains(xs: xs, item: x, eq: string_eq) } fn lens_module_gate_verdict_authority_eq(a: LensVerdictAuthority, b: LensVerdictAuthority) -> Bool { diff --git a/src/v2/lens/enforcement/vocab.dag b/src/v2/lens/enforcement/vocab.dag index afa56ed34d0..468ee0cf049 100644 --- a/src/v2/lens/enforcement/vocab.dag +++ b/src/v2/lens/enforcement/vocab.dag @@ -1,6 +1,7 @@ module v2.lens.enforcement.vocab import v2.std.algebra { contains } +import v2.std.text { string_eq } type SubjectRoster { @@ -150,10 +151,6 @@ fn narrowing_reason_same_variant(a: NarrowingReason, b: NarrowingReason) -> Bool } } -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn qualified_name_eq(a: QualifiedName, b: QualifiedName) -> Bool { a == b } diff --git a/src/v2/lens/fact_cardinality.dag b/src/v2/lens/fact_cardinality.dag index e6d7830f48d..00fd93ad53d 100644 --- a/src/v2/lens/fact_cardinality.dag +++ b/src/v2/lens/fact_cardinality.dag @@ -1,4 +1,5 @@ module v2.lens.fact_cardinality +import v2.std.text { string_eq } type FactCardinalityTree @@ -15,10 +16,6 @@ data fact_cardinality_cross_tree_coexistence_baseline: Int = 43 data no_coexistence_keys: FreeMonoid = Empty -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn add_unseen_key(acc: FreeMonoid, key: String) -> FreeMonoid { if contains(xs: acc, item: key, eq: string_eq) { acc diff --git a/src/v2/lens/fn_index_depth_agreement.dag b/src/v2/lens/fn_index_depth_agreement.dag index 4666e93f0db..e027cf12ebc 100644 --- a/src/v2/lens/fn_index_depth_agreement.dag +++ b/src/v2/lens/fn_index_depth_agreement.dag @@ -10,7 +10,7 @@ import v2.std.logic { Bool } import v2.std.node { Edge, Node, NodeFold, Symbol, fold_node, node_subtree_count } import v2.std.node_query { call_callee_target, node_is_call } import v2.std.diagnostic { Accepted, Rejected } -import v2.std.text { String } +import v2.std.text { String, string_eq } import v2.std.fn_index { FnArrowDecl, atom_identities_in_node, @@ -102,12 +102,8 @@ fn legacy_atoms(node: Node) -> List { } } -fn agreement_string_eq(a: String, b: String) -> Bool { - a == b -} - fn decl_named(decls: List, name: String) -> Bool { - any(xs: decls, predicate: fn(d) { agreement_string_eq(a: d.name, b: name) }) + any(xs: decls, predicate: fn(d) { string_eq(a: d.name, b: name) }) } fn param_collides_with_a_declaration( diff --git a/src/v2/lens/live_read_classification.dag b/src/v2/lens/live_read_classification.dag index 3a67789b708..98842e66f8d 100644 --- a/src/v2/lens/live_read_classification.dag +++ b/src/v2/lens/live_read_classification.dag @@ -27,6 +27,7 @@ import v2.lens.module_graph { module_declaration_facts_live, path_matches_touched } +import v2.std.text { string_eq } // This consumer's subject is DIRECTORY-GRAIN: it names roots and no single modules. data no_declared_pool_files: List = [] @@ -43,10 +44,6 @@ data empty_string_list: List = [] data empty_symbol_list: List = [] data empty_node_list: List = [] -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn carrier_home_module(home: LiveReadCarrierHome) -> String { home.module } diff --git a/src/v2/lens/manufactured_dependency_census.dag b/src/v2/lens/manufactured_dependency_census.dag index 6b8f0ca3295..3bd4e8ff2d9 100644 --- a/src/v2/lens/manufactured_dependency_census.dag +++ b/src/v2/lens/manufactured_dependency_census.dag @@ -8,7 +8,7 @@ import v2.std.algebra { contains, fold_list, length, list_reverse, list_snoc_ite import v2.std.collection { List, Map, empty_map, map_insert, map_lookup } import v2.std.optional { Absent, Present } import v2.std.logic { Bool } -import v2.std.text { String } +import v2.std.text { String, string_eq } import v2.lens.module_graph { ImportResolutionFact, import_resolution_facts_live, @@ -68,10 +68,6 @@ type ManufacturedDependencyTally { modules_with_manufactured_edges: Int } -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn snoc_unseen(acc: List, item: String) -> List { if contains(xs: acc, item: item, eq: string_eq) { acc diff --git a/src/v2/lens/module_graph.dag b/src/v2/lens/module_graph.dag index 991e35ceaf6..6a4939af812 100644 --- a/src/v2/lens/module_graph.dag +++ b/src/v2/lens/module_graph.dag @@ -21,7 +21,7 @@ import v2.std.optional { } import v2.std.diagnostic { Outcome, outcome_accepted } import v2.std.logic { Bool } -import v2.std.text { String } +import v2.std.text { String, string_eq } type ModuleDeclarationFact { module: String @@ -197,10 +197,6 @@ fn reference_derived_resolution_facts_flagged_pending_reference_producer( ) } -fn string_eq(a: String, b: String) -> Bool { - a == b -} - data no_paths: FreeMonoid = Empty data no_import_facts: List = [] diff --git a/src/v2/lens/module_impact_query.dag b/src/v2/lens/module_impact_query.dag index 71607d0ddc8..a71fdc5b938 100644 --- a/src/v2/lens/module_impact_query.dag +++ b/src/v2/lens/module_impact_query.dag @@ -10,7 +10,7 @@ import v2.std.algebra { import std.algebra { Cons } import v2.std.collection { List, Map, empty_map, map_insert } import v2.std.optional { Absent, Optional, Present, optional_present } -import v2.std.text { String } +import v2.std.text { String, string_eq } import v2.lens.common.construction_justification { ConstructionJustification, WallAfterGrounding, @@ -176,10 +176,6 @@ data impact_no_module: Optional = Absent data impact_no_trigger: Optional = Absent -fn impact_string_eq(a: String, b: String) -> Bool { - a == b -} - fn impact_module_eq(a: ModuleIdentity, b: ModuleIdentity) -> Bool { a.name == b.name } @@ -393,7 +389,7 @@ fn impact_append_import_module( existing: List, module_name: String ) -> List { - if contains(xs: existing, item: module_name, eq: impact_string_eq) { + if contains(xs: existing, item: module_name, eq: string_eq) { existing } else { list_snoc_item(xs: existing, item: module_name) @@ -436,7 +432,7 @@ fn impact_provenance_of_edge_indexed( if contains( xs: impact_imports_for_path(import_index: import_index, path: edge.path), item: edge.target_module, - eq: impact_string_eq + eq: string_eq ) { ImportDerivedEdge } else { diff --git a/src/v2/lens/production_qualification_origin_probe.dag b/src/v2/lens/production_qualification_origin_probe.dag index 90d44dfee02..25e52059a80 100644 --- a/src/v2/lens/production_qualification_origin_probe.dag +++ b/src/v2/lens/production_qualification_origin_probe.dag @@ -44,7 +44,7 @@ import v2.std.node { TypeNode, fold_node, } -import v2.std.text { String } +import v2.std.text { String, string_eq } // Production-qualification origin PROBE (session keen-lark-681, wise-ram-22 recut): NOT a // repository-wide census. fn_arrow_decl_facts_live(pool_roots:) now answers over the roots its @@ -142,10 +142,6 @@ data direct_rust_door_inferred_tree_atom: String = "direct_rust_door_inferred_tr // CompilerDerived is declared but UNWRITABLE at skeleton grain: callee identity proves a qualification boundary was called, not that the InferredTree argument came from production infer(assemble(...)). Until call/dataflow evidence connects arguments, non-fixture mint surfaces classify UnknownOrigin and fail admission. data ingest_mint_entry_name_suffix: String = "generate_provenanced_rust_candidate_from_ingest" -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn production_qualification_origin_eq( left: ProductionQualificationOrigin, right: ProductionQualificationOrigin diff --git a/src/v2/lens/reference_deps.dag b/src/v2/lens/reference_deps.dag index 5b6ba61a997..b921ac1acb5 100644 --- a/src/v2/lens/reference_deps.dag +++ b/src/v2/lens/reference_deps.dag @@ -8,6 +8,7 @@ import v2.lens.module_graph { map_lookup_where_rejected_unreachable, no_paths, m import v2.std.algebra { contains, fold_list, list_reverse } import std.algebra { Cons, Empty, FreeMonoid } import v2.compiler.name_resolve { Admission, Import, ImportVisible, ResolutionSubject, resolve_diagnostics } +import v2.std.text { string_eq } type ReferenceResolutionFact { @@ -85,10 +86,6 @@ data empty_reference_facts: List = [] data empty_reference_refusals: List = [] -fn string_eq(a: String, b: String) -> Bool { - a == b -} - fn symbol_eq(a: Symbol, b: Symbol) -> Bool { a == b } diff --git a/src/v2/std/text.dag b/src/v2/std/text.dag index 613db913a33..af18b8dedc5 100644 --- a/src/v2/std/text.dag +++ b/src/v2/std/text.dag @@ -67,6 +67,42 @@ fn char_eq(a: Char, b: Char) -> Bool { a == b } +// THE AUTHORITY FOR STRING EQUALITY, AND WHAT IT DOES NOT YET REACH. The byte-identical copies +// this change reaches across v2.lens collapse here. That is the whole of what this change does, +// and it is NOT one string_eq corpus-wide: byte-identical forks survive elsewhere, several of +// them under names that do not spell string_eq exactly. +// +// THE CENSUS IS THE INSTRUMENT, NOT A LIST. Re-derive the residue rather than reading a count that +// rots the moment anyone adds or removes a copy. ONE COMMAND, and it is the SAME ONE the roster +// header in src/v1/stage0/src/namespace_wave_admission.rs names -- two spellings of one census +// would be the second authority DESIGN section 3 forbids, and the narrower one UNDER-REPORTS: +// grep -rnE '^fn [a-z_]*string_eq[a-z_]*\(' --include=*.dag dag/ src/v2 +// A LIST OR A NUMBER WRITTEN HERE WOULD BE STALE ON THE NEXT MERGE and would be cited as coverage +// after it stopped being true, which is why neither appears in this annotation. +// +// AN EARLIER WORDING OF THIS NOTE NAMED THE NARROW PATTERN '^fn string_eq' AND CALLED +// grammar_coverage_string_eq THE renamed exception. BOTH WERE FALSE. The narrow pattern misses +// every renamed fork, and grammar_coverage was not the only one -- the command above finds +// several. That clone no longer exists: it was retained here on the ground that its module +// declared no imports, and the retention was rejected because naming that module's own imports is +// source work this change can express, which is not a dissolution trigger but a task. So +// v2.lens.enforcement.grammar_coverage now names its import surface and calls this declaration. +// EVERY FORK THE COMMAND STILL FINDS IS UNDECLARED RESIDUE: no reason recorded, no retention +// stated, nothing at its declaration saying why it is still there. +// +// TRIGGER, per fork rather than for the set: a fork collapses when a change touches its module, +// or earlier if that module's import closure already reaches v2.std.text. There is no single event +// that retires the whole residue, which is why this is a per-fork trigger and not a date. +// +// WHAT WILL ENCOUNTER IT: the DESIGN section 3 single-authority reviewer, a standing criterion +// declared in gunbc.design_argument and derived into reviewers by gunbc.roadmap.roadmap_review_criteria, +// which asks whether a change gives one concept a second name or a second home. It runs on changes +// to this repository. This annotation exists so that reviewer meets a DECLARED residue with a +// working census rather than rediscovering an undeclared one with a command that under-reports it. +fn string_eq(a: String, b: String) -> Bool { + a == b +} + fn string_split_step(state: StringSplitState, delimiter: String) -> StringSplitState { if list_starts_with(xs: state.rest, prefix: delimiter, eq: char_eq) { StringSplitState {