diff --git a/src/v1/compile.dag b/src/v1/compile.dag index 0fce979b1cc..5ad77f4807c 100644 --- a/src/v1/compile.dag +++ b/src/v1/compile.dag @@ -341,9 +341,7 @@ fn test_reference_debt() -> List { test_reference_row(module_name: "test.claim.spark.serving_arm_launch_witness_test", referrer: "w_all_serving_arm_launch_claims_hold", target: "test.claim.spark.serving_arm_launch_witness_test.w_every_rank_names_this_fleets_leg_and_hca", occurrences: 1), test_reference_row(module_name: "test.claim.spark.serving_arm_launch_witness_test", referrer: "w_all_serving_arm_launch_claims_hold", target: "test.claim.spark.serving_arm_launch_witness_test.w_the_engine_argv_states_the_profiles_batching_bounds", occurrences: 1), test_reference_row(module_name: "test.claim.spark.serving_arm_launch_witness_test", referrer: "w_all_serving_arm_launch_claims_hold", target: "test.claim.spark.serving_arm_launch_witness_test.w_the_group_b_arm_plans_exactly_four_ranks", occurrences: 1), - test_reference_row(module_name: "test.claim.spark.serving_arm_launch_witness_test", referrer: "w_all_serving_arm_launch_claims_hold", target: "test.claim.spark.serving_arm_launch_witness_test.w_the_utilisation_argv_is_the_profiles_value_at_full_precision", occurrences: 1), - test_reference_row(module_name: "v2.test.manual.cross_language_add_python_to_typescript", referrer: "", target: "v2.test.manual.typescript_effect_io_emit.ts_effect_io_emit_holds", occurrences: 1), - test_reference_row(module_name: "v2.test.manual.cross_language_add_python_to_typescript", referrer: "cross_language_add_python_to_typescript_chain_status_holds", target: "v2.test.manual.typescript_effect_io_emit.ts_effect_io_emit_holds", occurrences: 1) + test_reference_row(module_name: "test.claim.spark.serving_arm_launch_witness_test", referrer: "w_all_serving_arm_launch_claims_hold", target: "test.claim.spark.serving_arm_launch_witness_test.w_the_utilisation_argv_is_the_profiles_value_at_full_precision", occurrences: 1) ] } diff --git a/src/v1/stage0/src/v1_compiler_compile.rs b/src/v1/stage0/src/v1_compiler_compile.rs index 4ef039e1ab5..2c31d2f89ec 100644 --- a/src/v1/stage0/src/v1_compiler_compile.rs +++ b/src/v1/stage0/src/v1_compiler_compile.rs @@ -483,7 +483,7 @@ pub fn test_reference_debt() -> Rc>> { occurrences: 1, scope: TestReferenceRowScope::FixtureControlRow, dissolution: test_reference_debt_dissolution(), -}), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_absent_shape_refuses_silhouette".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_catalog_evidence_cannot_buy_placement_clearance".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_evidence_spendability_discriminates".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_mounting_axis_needs_no_shape_or_envelope".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_naming_is_alias_with_sku_unread".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_proof_load_receipt_is_load_bearing".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_axis_is_not_yet_locatable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_refuses_lift_role_on_axis".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_relayed_reading_makes_envelope_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_search_summary_envelope_is_not_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_source_reading_survives_conversion".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_absent_shape_refuses_silhouette".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_catalog_evidence_cannot_buy_placement_clearance".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_evidence_spendability_discriminates".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_mounting_axis_needs_no_shape_or_envelope".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_naming_is_alias_with_sku_unread".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_proof_load_receipt_is_load_bearing".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_axis_is_not_yet_locatable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_refuses_lift_role_on_axis".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_relayed_reading_makes_envelope_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_search_summary_envelope_is_not_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_source_reading_survives_conversion".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "".to_string(), "test.claim.materialization_provider_witness.incomplete_v1_shape_artifact_refuses_naming_the_diagnostic_union".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "".to_string(), "test.claim.materialization_provider_witness.red_declared_input_miss_stale_artifact_refuses_as_wrong_artifact".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "witness_model_refusal_controls_remain_distinct".to_string(), "test.claim.materialization_provider_witness.incomplete_v1_shape_artifact_refuses_naming_the_diagnostic_union".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "witness_model_refusal_controls_remain_distinct".to_string(), "test.claim.materialization_provider_witness.red_declared_input_miss_stale_artifact_refuses_as_wrong_artifact".to_string(), 1), test_reference_row("test.claim.native_witness_transition_receipt_witness".to_string(), "".to_string(), "v2.test.execution.native_selected_witness_bundle.native_selected_witness_bundle_cutover_evidence_holds".to_string(), 1), test_reference_row("test.claim.native_witness_transition_receipt_witness".to_string(), "cited_evidence_declaration_is_an_executing_witness".to_string(), "v2.test.execution.native_selected_witness_bundle.native_selected_witness_bundle_cutover_evidence_holds".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_a_socket_planned_rank_maps_no_device_and_cannot_lock_memory".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_an_unrun_subject_refuses_normal_serving_and_the_intent_changes_the_answer".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_every_planned_rank_maps_the_verbs_device_and_can_lock_memory".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_every_rank_keeps_the_transport_evidence_producer_on".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_every_rank_names_this_fleets_leg_and_hca".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_the_engine_argv_states_the_profiles_batching_bounds".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_the_group_b_arm_plans_exactly_four_ranks".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_the_utilisation_argv_is_the_profiles_value_at_full_precision".to_string(), 1), test_reference_row("v2.test.manual.cross_language_add_python_to_typescript".to_string(), "".to_string(), "v2.test.manual.typescript_effect_io_emit.ts_effect_io_emit_holds".to_string(), 1), test_reference_row("v2.test.manual.cross_language_add_python_to_typescript".to_string(), "cross_language_add_python_to_typescript_chain_status_holds".to_string(), "v2.test.manual.typescript_effect_io_emit.ts_effect_io_emit_holds".to_string(), 1)]) +}), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_absent_shape_refuses_silhouette".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_catalog_evidence_cannot_buy_placement_clearance".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_evidence_spendability_discriminates".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_mounting_axis_needs_no_shape_or_envelope".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_naming_is_alias_with_sku_unread".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_proof_load_receipt_is_load_bearing".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_axis_is_not_yet_locatable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_refuses_lift_role_on_axis".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_relayed_reading_makes_envelope_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_search_summary_envelope_is_not_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "".to_string(), "test.claim.climbing_hold_catalog_witness.witness_source_reading_survives_conversion".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_absent_shape_refuses_silhouette".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_catalog_evidence_cannot_buy_placement_clearance".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_evidence_spendability_discriminates".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_mounting_axis_needs_no_shape_or_envelope".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_naming_is_alias_with_sku_unread".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_proof_load_receipt_is_load_bearing".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_axis_is_not_yet_locatable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_real_row_refuses_lift_role_on_axis".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_relayed_reading_makes_envelope_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_search_summary_envelope_is_not_spendable".to_string(), 1), test_reference_row("test.claim.climbing_hold_witness_roster".to_string(), "climbing_hold_witness_outcomes".to_string(), "test.claim.climbing_hold_catalog_witness.witness_source_reading_survives_conversion".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "".to_string(), "test.claim.materialization_provider_witness.incomplete_v1_shape_artifact_refuses_naming_the_diagnostic_union".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "".to_string(), "test.claim.materialization_provider_witness.red_declared_input_miss_stale_artifact_refuses_as_wrong_artifact".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "witness_model_refusal_controls_remain_distinct".to_string(), "test.claim.materialization_provider_witness.incomplete_v1_shape_artifact_refuses_naming_the_diagnostic_union".to_string(), 1), test_reference_row("test.claim.materialization_provider_consumer_hand_rust_witness".to_string(), "witness_model_refusal_controls_remain_distinct".to_string(), "test.claim.materialization_provider_witness.red_declared_input_miss_stale_artifact_refuses_as_wrong_artifact".to_string(), 1), test_reference_row("test.claim.native_witness_transition_receipt_witness".to_string(), "".to_string(), "v2.test.execution.native_selected_witness_bundle.native_selected_witness_bundle_cutover_evidence_holds".to_string(), 1), test_reference_row("test.claim.native_witness_transition_receipt_witness".to_string(), "cited_evidence_declaration_is_an_executing_witness".to_string(), "v2.test.execution.native_selected_witness_bundle.native_selected_witness_bundle_cutover_evidence_holds".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_a_socket_planned_rank_maps_no_device_and_cannot_lock_memory".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_an_unrun_subject_refuses_normal_serving_and_the_intent_changes_the_answer".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_every_planned_rank_maps_the_verbs_device_and_can_lock_memory".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_every_rank_keeps_the_transport_evidence_producer_on".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_every_rank_names_this_fleets_leg_and_hca".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_the_engine_argv_states_the_profiles_batching_bounds".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_the_group_b_arm_plans_exactly_four_ranks".to_string(), 1), test_reference_row("test.claim.spark.serving_arm_launch_witness_test".to_string(), "w_all_serving_arm_launch_claims_hold".to_string(), "test.claim.spark.serving_arm_launch_witness_test.w_the_utilisation_argv_is_the_profiles_value_at_full_precision".to_string(), 1)]) } pub fn test_reference_import_referrer() -> String { diff --git a/src/v2/compiler/03_name_resolve.dag b/src/v2/compiler/03_name_resolve.dag index 2f1edc5e5b0..e6f83993eb3 100644 --- a/src/v2/compiler/03_name_resolve.dag +++ b/src/v2/compiler/03_name_resolve.dag @@ -4,6 +4,7 @@ import v2.std.language_model { LanguageModel } import v2.compiler.symbol_index_fill { symbol_index_fill_module_roots } import v2.compiler.normalized_tree { NormalizedTree, normalized_tree_roots_to_nodes } +import v2.std.declaration_marker { TestCodeIndex, test_code_index_add_module, test_code_index_empty } import v2.std.symbol_index { SymbolIndex, empty_symbol_index } import v2.compiler.resolve { DeclaredBinding, @@ -102,9 +103,12 @@ type Admission { // Shared by every subject admitted against the same language and root collection. // The Outcome stays with the caller so validation diagnostics retain their original // per-subject refusal boundary when the context is constructed before admission. +// `test_code` is every root's test-marker channel keyed by the paths resolution binds to, built in +// the same pass that names the roots, so no root can be resolvable while its markers are unread. type ValidatedModuleRoots { roots: FreeMonoid by_name: Map + test_code: TestCodeIndex } type ResolutionContext { @@ -147,7 +151,7 @@ type AdmissionState | AdmissionRejected { diagnostics: NonEmptyDiagnostics } type ModuleRootValidateState - = ModuleRootsValid { seen: Map, diagnostics: Diagnostics } + = ModuleRootsValid { seen: Map, test_code: TestCodeIndex, diagnostics: Diagnostics } | ModuleRootsDuplicate { diagnostics: Diagnostics } | ModuleRootsProjectionRejected { diagnostics: NonEmptyDiagnostics } @@ -225,14 +229,14 @@ fn admit_export_symbol( fn validate_module_roots(roots: FreeMonoid) -> Outcome { match fold_list( xs: roots, - empty: ModuleRootsValid { seen: empty_map(), diagnostics: v2.std.diagnostic.None }, + empty: ModuleRootsValid { seen: empty_map(), test_code: test_code_index_empty(), diagnostics: v2.std.diagnostic.None }, cons: fn(acc, root) { match acc { ModuleRootsDuplicate { diagnostics: d } => ModuleRootsDuplicate { diagnostics: d } ModuleRootsProjectionRejected { diagnostics: d } => ModuleRootsProjectionRejected { diagnostics: d } - ModuleRootsValid { seen: prior, diagnostics: acc_diag } => + ModuleRootsValid { seen: prior, test_code: prior_test_code, diagnostics: acc_diag } => if well_formed(n: root.root) { match qualified_name_from_module_node(root: root.root) { Rejected { diagnostics: d } => @@ -245,6 +249,11 @@ fn validate_module_roots(roots: FreeMonoid) -> Outcome ModuleRootsValid { seen: map_insert(m: prior, key: name, value: root), + test_code: test_code_index_add_module( + index: prior_test_code, + module_qn: name, + channel: root.test_markers + ), diagnostics: merged_diag } Present { value: _ } => @@ -262,8 +271,8 @@ fn validate_module_roots(roots: FreeMonoid) -> Outcome - Accepted { value: ValidatedModuleRoots { roots: roots, by_name: by_name }, diagnostics: d } + ModuleRootsValid { seen: by_name, test_code: test_code, diagnostics: d } => + Accepted { value: ValidatedModuleRoots { roots: roots, by_name: by_name, test_code: test_code }, diagnostics: d } ModuleRootsDuplicate { diagnostics: d } => Rejected { diagnostics: rejected_with_pending( @@ -566,7 +575,10 @@ fn admission_namespace_base(canonical_symbols: PointwisePower) -> Namesp bindings: empty_map(), canonical_symbols: canonical_symbols, symbol_index: empty_symbol_index(), - module_qn: Empty + module_qn: Empty, + test_code: test_code_index_empty(), + declared_in: Empty, + imported_origins: empty_map() } } @@ -606,7 +618,9 @@ fn admitted_subject_from_bindings( base: Namespace, subject_module_root: NormalizedTree, symbol_index: SymbolIndex, - module_qn: QualifiedName + module_qn: QualifiedName, + origins: Map, + test_code: TestCodeIndex ) -> AdmittedSubject { AdmittedSubject { namespace: Namespace { @@ -616,7 +630,10 @@ fn admitted_subject_from_bindings( ), canonical_symbols: base.canonical_symbols, symbol_index: symbol_index, - module_qn: module_qn + module_qn: module_qn, + test_code: test_code, + declared_in: module_qn, + imported_origins: origins }, subject_root: subject_module_root } @@ -681,14 +698,16 @@ fn namespace_for_subject_root( Rejected { diagnostics: rejected_with_pending(pending: validate_diag, rejected: d) } - AdmissionAccepted { bindings: b, origins: _ } => + AdmissionAccepted { bindings: b, origins: o } => Accepted { value: admitted_subject_from_bindings( bindings: b, base: base, subject_module_root: subject_module_root, symbol_index: shared.symbol_index, - module_qn: admission.subject.name + module_qn: admission.subject.name, + origins: o, + test_code: shared.roots.test_code ), diagnostics: validate_diag } @@ -702,14 +721,16 @@ fn namespace_for_subject_root( index: index, active_roots: active_roots ) { - AdmissionAccepted { bindings: b, origins: _ } => + AdmissionAccepted { bindings: b, origins: o } => Accepted { value: admitted_subject_from_bindings( bindings: b, base: base, subject_module_root: subject_module_root, symbol_index: shared.symbol_index, - module_qn: admission.subject.name + module_qn: admission.subject.name, + origins: o, + test_code: shared.roots.test_code ), diagnostics: validate_diag } diff --git a/src/v2/compiler/03_normalize.dag b/src/v2/compiler/03_normalize.dag index dec642c9a77..16e92d6be19 100644 --- a/src/v2/compiler/03_normalize.dag +++ b/src/v2/compiler/03_normalize.dag @@ -38,6 +38,7 @@ import v2.compiler.body_lowering_fold { body_lower_is_deferred_lower_at_normalize } import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_tree } +import v2.compiler.test_marker_capture { test_marker_capture } import v2.compiler.namespace_graft { module_header_containment_graft, namespace_graft_is_graft_candidate @@ -217,7 +218,12 @@ fn normalize(parse_tree: ParseTree) -> Outcome { Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: grafted, diagnostics: d1 } => if well_formed(n: grafted) { - admit_normalized_tree(root: grafted, diagnostics: d1) + match test_marker_capture(tree: parse_tree) { + Rejected { diagnostics: r } => + Rejected { diagnostics: rejected_with_pending(pending: d1, rejected: r) } + Accepted { value: markers, diagnostics: _ } => + admit_normalized_tree(root: grafted, test_markers: markers, diagnostics: d1) + } } else { Rejected { diagnostics: rejected_with_pending( diff --git a/src/v2/compiler/03_resolve.dag b/src/v2/compiler/03_resolve.dag index 15cbaac19a1..4e38692a218 100644 --- a/src/v2/compiler/03_resolve.dag +++ b/src/v2/compiler/03_resolve.dag @@ -2,6 +2,14 @@ module v2.compiler.resolve import v2.std.language_model { LanguageModel } import v2.compiler.normalized_tree { NormalizedTree } +import v2.std.declaration_marker { + ReachesNoTestCode, + ReachesTestMarkedDeclaration, + TestCodeIndex, + test_code_index_add_module, + test_code_index_empty, + test_code_reach +} import std.disposition { Disposition, Scaffold, SingleAuthority } import std.decl_ref { DeclarationRef, WholeDeclaration } import v2.extdeps.languages.dag { @@ -10,7 +18,8 @@ import v2.extdeps.languages.dag { dag_node_is_module_root_conj, dag_resolve_preserve_module_metadata_subtree, dag_surface_module_header_metadata_edge, - dag_surface_operator_canonicalization_lookup + dag_surface_operator_canonicalization_lookup, + qualified_name_from_module_node } import std.algebra { Cons, Empty, FreeMonoid } import v2.std.algebra { length, list_snoc_item } @@ -19,7 +28,8 @@ import v2.std.collection { PointwisePower, empty_map, map_get, - map_insert + map_insert, + map_lookup } import v2.std.optional { Absent, @@ -33,6 +43,7 @@ import v2.std.diagnostic { Correction, CorrectionNotModeled, Diagnostic, + Diagnostics, node_locus, Outcome, UserInputBoundary, @@ -86,11 +97,19 @@ import std.occurrence_identity { NodeOccurrenceIdentity, OccurrenceId } type ResolvedTree = Node +// `test_code`, `declared_in` and `imported_origins` exist for one decision: whether a reference binds +// to test code (owner ruling 2026-09-16/17). Root-scope bindings come from exactly two sources: the +// subject's own declarations, which live under `declared_in`, and admitted imports, whose origin +// module `imported_origins` records. So a root hit is judged by the same qualified path a +// symbol-index hit answers with. type Namespace { bindings: Map canonical_symbols: PointwisePower symbol_index: SymbolIndex module_qn: QualifiedName + test_code: TestCodeIndex + declared_in: QualifiedName + imported_origins: Map } type Scope @@ -125,7 +144,10 @@ fn empty_namespace() -> Namespace { bindings: empty_map(), canonical_symbols: empty_canonical_symbol_set(), symbol_index: empty_symbol_index(), - module_qn: Empty + module_qn: Empty, + test_code: test_code_index_empty(), + declared_in: Empty, + imported_origins: empty_map() } } @@ -231,14 +253,33 @@ fn add_bind_atom_binder(n: Node, acc: Map) -> Map Namespace { + let bindings = namespace_bindings_augment_from_module_atoms( + root: tree.root, + bindings: empty_map() + ) + let declared_in = namespace_tree_module_qn(tree: tree) Namespace { - bindings: namespace_bindings_augment_from_module_atoms( - root: tree.root, - bindings: empty_map() - ), + bindings: bindings, canonical_symbols: lm.canonical_symbols, symbol_index: empty_symbol_index(), - module_qn: Empty + module_qn: Empty, + test_code: test_code_index_add_module( + index: test_code_index_empty(), + module_qn: declared_in, + channel: tree.test_markers + ), + declared_in: declared_in, + imported_origins: empty_map() + } +} + +// A single-tree namespace has no module path of its own (module_qn stays Empty, as before), but its +// test-code index still needs the path its declarations live under. A root that names no module +// keys them under Empty, which is the same key both sides of the lookup use. +fn namespace_tree_module_qn(tree: NormalizedTree) -> QualifiedName { + match qualified_name_from_module_node(root: tree.root) { + Accepted { value: qn, diagnostics: _ } => qn + Rejected { diagnostics: _ } => Empty } } @@ -301,13 +342,21 @@ fn resolve_ctx_with_under_module_root(ctx: ResolveContext, under_module_root: Bo } } -fn lookup_chain(s: Scope, name: Symbol) -> Outcome { +// Which scope answered a name, in the one walk that finds it. A local binder shadows the module +// scope, so only a ROOT hit can be a reference to a module-level declaration, and the test-code wall +// (resolve_atom_bound) reads that distinction from here rather than re-walking the chain. +type ScopeBinding + = BoundInFrame { canonical: Symbol } + | BoundAtRoot { canonical: Symbol } + | ScopeUnbound + +fn lookup_chain(s: Scope, name: Symbol) -> Outcome { match s { ScopeFrame { locals: m, outer: o } => match v2.std.collection.map_get(m, name) { Accepted { value: opt, diagnostics: d_here } => match opt { Present { value: v } => - Accepted { value: optional_present(value: v), diagnostics: d_here } + Accepted { value: BoundInFrame { canonical: v }, diagnostics: d_here } Absent => match lookup_chain(s: o, name: name) { Accepted { value: found, diagnostics: d_outer } => @@ -326,8 +375,8 @@ fn lookup_chain(s: Scope, name: Symbol) -> Outcome { ScopeRoot { module: mod } => match v2.std.collection.map_get(mod.bindings, name) { Accepted { value: opt, diagnostics: d } => match opt { - Present { value: v } => Accepted { value: optional_present(value: v), diagnostics: d } - Absent => Accepted { value: optional_absent(), diagnostics: d } + Present { value: v } => Accepted { value: BoundAtRoot { canonical: v }, diagnostics: d } + Absent => Accepted { value: ScopeUnbound, diagnostics: d } } Rejected { diagnostics: ds } => Rejected { diagnostics: ds } } @@ -408,7 +457,7 @@ fn symbol_index_node_identity(node: Node, fallback: Symbol) -> Symbol { } type SymbolIndexAtomLookup - = SymbolIndexAtomHit { canonical: Symbol } + = SymbolIndexAtomHit { canonical: Symbol, path: QualifiedName } | SymbolIndexAtomAmbiguous | SymbolIndexAtomUnbound @@ -421,9 +470,10 @@ fn lookup_symbol_index_atom_identity( position: symbol_index_lookup_position(ctx: ctx), name: name ) { - LexicalHit { node: node, path: _ } => + LexicalHit { node: node, path: path } => SymbolIndexAtomHit { - canonical: symbol_index_node_identity(node: node, fallback: name) + canonical: symbol_index_node_identity(node: node, fallback: name), + path: path } LexicalAmbiguous { candidates: _ } => SymbolIndexAtomAmbiguous LexicalUnbound => @@ -433,9 +483,10 @@ fn lookup_symbol_index_atom_identity( index: ctx.namespace.symbol_index, name: name ) { - GlobalBareHit { node: node, path: _ } => + GlobalBareHit { node: node, path: path } => SymbolIndexAtomHit { - canonical: symbol_index_node_identity(node: node, fallback: name) + canonical: symbol_index_node_identity(node: node, fallback: name), + path: path } GlobalBareLookupAmbiguous => SymbolIndexAtomAmbiguous GlobalBareLookupUnbound => SymbolIndexAtomUnbound @@ -479,7 +530,11 @@ fn qualified_head_bound_on_chain(ctx: ResolveContext, path: QualifiedName) -> Ou Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: found, diagnostics: d } => Accepted { - value: (match found { Present { value: _ } => true Absent => false }), + value: (match found { + BoundInFrame { canonical: _ } => true + BoundAtRoot { canonical: _ } => true + ScopeUnbound => false + }), diagnostics: d } } @@ -508,6 +563,17 @@ fn try_resolve_qualified_name_node(ctx: ResolveContext, n: Node) -> Optional + optional_present( + value: Rejected { + diagnostics: rejected_with_pending( + pending: diagnostics_merge(outer: pending, inner: chain_pending), + rejected: diagnostics_singleton(d: test_code_referenced_diagnostic(reason: ^resolve_reason_test_code_referenced, n: n)) + ) + } + ) + ReachesNoTestCode => match resolved_node.kind { TypeNode { connective: Atom { identity: declared } } => optional_present( @@ -527,6 +593,7 @@ fn try_resolve_qualified_name_node(ctx: ResolveContext, n: Node) -> Optional optional_present( value: Rejected { @@ -544,6 +611,56 @@ fn try_resolve_qualified_name_node(ctx: ResolveContext, n: Node) -> Optional QualifiedName { + match map_lookup(m: namespace.imported_origins, key: name) { + Present { value: origin } => origin + Absent => namespace.declared_in + } +} + +fn test_code_referenced_diagnostic(reason: Symbol, n: Node) -> Diagnostic { + Diagnostic { + reason: reason, + at: node_locus(node: n), + correction: Unavailable { reason: UserInputBoundary } + } +} + +// THE WALL (owner ruling 2026-09-16/17): `test` segregates test code from serving code, and no code +// may reference a test-marked declaration, a test fn in the same module included. It is decided here, +// where the reference binds, from the path it bound to, and it refuses with the reference's own locus. +// TWO ENFORCEMENT SITES, ONE DECISION. This function is reached by the doors whose accepted result is +// a canonical atom -- the root scope and the symbol index. The qualified-path door +// (try_resolve_qualified_name_node) cannot route through it, because its accepted arm must first read +// the resolved node's kind and carry the chain's own pending diagnostics, so it refuses inline +// instead. Both sites decide from ONE authority, test_code_reach over ctx.namespace.test_code, and +// raise the same reason through the same test_code_referenced_diagnostic: a change to the RULE is a +// change to that fold, not to either site. What a later door must not do is bind a module-level name +// without asking test_code_reach at all -- the per-door reds in +// v2.test.claim.name_resolve.test_code_reference_wall are what hold that, one per door. +fn resolve_atom_bound( + ctx: ResolveContext, + n: Node, + canonical: Symbol, + path: QualifiedName, + pending: Diagnostics +) -> Outcome { + match test_code_reach(index: ctx.namespace.test_code, path: path) { + ReachesNoTestCode => + Accepted { + value: canonical_atom(identity: canonical, occurrence_id: n.occurrence_id), + diagnostics: pending + } + ReachesTestMarkedDeclaration => + Rejected { + diagnostics: rejected_with_pending( + pending: pending, + rejected: diagnostics_singleton(d: test_code_referenced_diagnostic(reason: ^resolve_reason_test_code_referenced, n: n)) + ) + } + } +} + fn resolve_atom(ctx: ResolveContext, n: Node, identity: Symbol) -> Outcome { if dag_node_is_int_literal_atom(node: n) { Accepted { value: n, diagnostics: None } @@ -554,18 +671,23 @@ fn resolve_atom(ctx: ResolveContext, n: Node, identity: Symbol) -> Outcome } else { match lookup_chain(s: ctx.scope, name: identity) { Accepted { value: found, diagnostics: pending } => match found { - Present { value: canonical } => + BoundInFrame { canonical: canonical } => Accepted { value: canonical_atom(identity: canonical, occurrence_id: n.occurrence_id), diagnostics: pending } - Absent => + BoundAtRoot { canonical: canonical } => + resolve_atom_bound( + ctx: ctx, + n: n, + canonical: canonical, + path: qualified_name_snoc(qn: root_binding_origin(namespace: ctx.namespace, name: identity), segment: identity), + pending: pending + ) + ScopeUnbound => match lookup_symbol_index_atom_identity(ctx: ctx, name: identity) { - SymbolIndexAtomHit { canonical: canonical } => - Accepted { - value: canonical_atom(identity: canonical, occurrence_id: n.occurrence_id), - diagnostics: pending - } + SymbolIndexAtomHit { canonical: canonical, path: path } => + resolve_atom_bound(ctx: ctx, n: n, canonical: canonical, path: path, pending: pending) SymbolIndexAtomAmbiguous => Rejected { diagnostics: rejected_with_pending( diff --git a/src/v2/compiler/normalized_tree.dag b/src/v2/compiler/normalized_tree.dag index 7ceb60c2183..8e5731399dc 100644 --- a/src/v2/compiler/normalized_tree.dag +++ b/src/v2/compiler/normalized_tree.dag @@ -17,12 +17,19 @@ import v2.std.diagnostic { import std.algebra { Empty, FreeMonoid } import v2.std.algebra { fold_list, list_snoc_item } import v2.std.node { Node } +import v2.std.declaration_marker { TestMarkerChannel, test_marker_channel_empty } // A NormalizedTree is the ADMITTED product of normalize: a root whose own lowering left no wrapper // behind. It was an alias for Node until BL-1, which is why retention evidence reached resolve as a // bare Node and was dropped there. Sealing the carrier makes the drop unwritable. +// +// `test_markers` is the authored `test` marker's channel (v2.std.declaration_marker), sealed +// beside the root rather than inside it: `root` is byte-identical for a `test fn` and a plain `fn`, +// and every consumer about Node structure reads `root` alone. Name resolution is the channel's +// consumer, and refuses references to what it marks. type NormalizedTree sole_constructor { root: Node, + test_markers: TestMarkerChannel, } // Rung: ACCEPTED REFINEMENT WITH EXECUTING REFUSAL, not structural impossibility. The invalid state @@ -39,7 +46,11 @@ fn normalized_tree_retention_diagnostic(root: Node) -> Diagnostic { } } -fn admit_normalized_tree(root: Node, diagnostics: Diagnostics) -> Outcome { +fn admit_normalized_tree( + root: Node, + test_markers: TestMarkerChannel, + diagnostics: Diagnostics +) -> Outcome { if body_lowering_diagnostics_carry_wrapper_retention(d: diagnostics) { Rejected { diagnostics: rejected_with_pending( @@ -48,7 +59,7 @@ fn admit_normalized_tree(root: Node, diagnostics: Diagnostics) -> Outcome) -> FreeMono ) } +// THE UNMARKED DOOR, AND ITS NAME SAYS SO. Its roots arrive as already-lowered Nodes, from which the +// authored `test` marker cannot be recovered (lowering erases it by design), so every root is admitted +// with an empty marker channel. That is a statement about the caller's input, not a default: a caller +// holding source goes through v2.compiler.normalize, which captures the channel from the parse tree. +// // The plural door: the same decision per element, refusing as a whole so a partially admitted list // has no representation. // @@ -71,7 +87,7 @@ fn normalized_tree_roots_to_nodes(roots: FreeMonoid) -> FreeMono // would accumulate N+1 copies of one set. The decision is still per element (the same verdict each // time, reading only the shared diagnostics), the refusal carries its pending set exactly once via // admit_normalized_tree, and the accepted diagnostics attach once at the end. -fn admit_normalized_roots( +fn admit_unmarked_normalized_roots( roots: FreeMonoid, diagnostics: Diagnostics ) -> Outcome> { @@ -82,7 +98,7 @@ fn admit_normalized_roots( match acc { Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: admitted, diagnostics: _ } => - match admit_normalized_tree(root: root, diagnostics: diagnostics) { + match admit_normalized_tree(root: root, test_markers: test_marker_channel_empty(), diagnostics: diagnostics) { Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: one, diagnostics: _ } => Accepted { diff --git a/src/v2/compiler/test_marker_capture.dag b/src/v2/compiler/test_marker_capture.dag index 1010ad558bc..077c338d2bb 100644 --- a/src/v2/compiler/test_marker_capture.dag +++ b/src/v2/compiler/test_marker_capture.dag @@ -1,6 +1,6 @@ module v2.compiler.test_marker_capture -import v2.compiler.parse { ParseArtifact } +import v2.compiler.parse { ParseTree } import v2.extdeps.languages.dag { dag_binding_branded_atom_identity, parse_production_captured_child_optional, @@ -33,13 +33,18 @@ import v2.std.node_query { NamedChildAmbiguous, NamedChildFound, NamedChildMissi // would make a marked declaration read as unmarked, which is the absent-reads-as-false class the // channel exists to close. // -// CONSUMER, a declared frontier. The consumer is the refusal of references to test code at name -// resolution (v2.compiler.resolve resolve_atom_bound), reached through v2.compiler.normalize, which -// seals this channel beside the normalized root. TRIGGER: gunbc#11580 merging, the change that wires -// both. Until then the only executing reader is v2.test.claim.parse.test_marker_channel. -fn test_marker_capture(artifact: ParseArtifact) -> Outcome { +// CONSUMER: v2.compiler.normalize runs this over the same parse tree it lowers and seals the result +// beside the root in NormalizedTree, where name resolution (v2.compiler.resolve resolve_atom_bound) +// reads it and refuses references to what it marks. The frontier gunbc#11573 declared here is closed +// by that wiring. +// +// THE SUBJECT IS THE PARSE TREE, NOT THE ARTIFACT AROUND IT. gunbc#11573 took a whole ParseArtifact +// while reading only its `tree`; normalize, the consumer that landed, is handed a ParseTree and never +// the artifact, so the door now names what it actually reads rather than obliging every caller to +// carry a span index the capture does not use. +fn test_marker_capture(tree: ParseTree) -> Outcome { let no_rows: List = [] - match test_marker_capture_walk(n: artifact.tree, acc: outcome_accepted(value: no_rows)) { + match test_marker_capture_walk(n: tree, acc: outcome_accepted(value: no_rows)) { Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: rows, diagnostics: d } => Accepted { value: TestMarkerChannel { marked: rows }, diagnostics: d } diff --git a/src/v2/std/declaration_marker.dag b/src/v2/std/declaration_marker.dag index 405d14267fb..af66678ec55 100644 --- a/src/v2/std/declaration_marker.dag +++ b/src/v2/std/declaration_marker.dag @@ -1,12 +1,12 @@ module v2.std.declaration_marker import v2.std.algebra { contains, length } -import v2.std.collection { List } +import v2.std.collection { Absent, List, Map, Present, empty_map, map_insert, map_lookup } import v2.std.node { Symbol } +import v2.std.qualified_name { QualifiedName, qualified_name_snoc } // The authored `test` marker segregates test code from serving code (owner ruling 2026-09-16/17), and -// its consumer is a declared frontier: name resolution will refuse a reference to a marked declaration -// (TRIGGER: gunbc#11580 merging, the change named in v2.compiler.test_marker_capture). What it must not +// name resolution CONSUMES it: a reference to a marked declaration is refused there. What it must not // touch is the semantic tree -- a marked declaration's semantic graph and content hash are identical // to an unmarked one's -- so it rides this channel beside the tree rather than as a child edge. It // borrows the SHAPE of the DESIGN section 4c annotation channel (captured beside the semantic result, @@ -30,6 +30,13 @@ type TestMarkerChannel { marked: List } +// The channel of a module that declares no test code. Its consumers are the fixture doors that admit +// already-lowered roots, whose markers cannot be recovered (v2.compiler.normalized_tree +// admit_unmarked_normalized_roots and the fixture callers of admit_normalized_tree). +fn test_marker_channel_empty() -> TestMarkerChannel { + TestMarkerChannel { marked: [] } +} + fn test_marker_channel_marks(channel: TestMarkerChannel, name: Symbol) -> Bool { contains(xs: channel.marked, item: TestMarkedDeclaration { name: name }, eq: fn(a, b) { a.name == b.name }) } @@ -37,3 +44,43 @@ fn test_marker_channel_marks(channel: TestMarkerChannel, name: Symbol) -> Bool { fn test_marker_channel_count(channel: TestMarkerChannel) -> Int { length(xs: channel.marked) } + +// THE RESOLUTION-SIDE READING OF THE CHANNEL: the compilation's marked declarations as the qualified +// paths a reference binds to. The key is the path v2.compiler.symbol_index_fill indexes (module path, +// then one segment per named member), so a binding answered by the symbol index is judged by the path +// it answered with and nothing else. +// +// ITEM-SCOPED, NOT MODULE-SCOPED. Test code is the declarations the author marked, and nothing else: +// an unmarked helper that happens to live in a module with tests is ordinary code, and a module-level +// rule ("any test in the module makes all of it test code") is wrong in both directions -- it refuses +// references to ordinary helpers and says nothing finer about the marked ones. +type TestCodeIndex { + marked_paths: Map +} + +type TestCodeReach + = ReachesNoTestCode + | ReachesTestMarkedDeclaration + +fn test_code_index_empty() -> TestCodeIndex { + TestCodeIndex { marked_paths: empty_map() } +} + +fn test_code_index_add_module( + index: TestCodeIndex, + module_qn: QualifiedName, + channel: TestMarkerChannel +) -> TestCodeIndex { + TestCodeIndex { + marked_paths: fold(channel.marked, init: index.marked_paths, f: fn(acc, row) { + map_insert(m: acc, key: qualified_name_snoc(qn: module_qn, segment: row.name), value: true) + }) + } +} + +fn test_code_reach(index: TestCodeIndex, path: QualifiedName) -> TestCodeReach { + match map_lookup(m: index.marked_paths, key: path) { + Present { value: _ } => ReachesTestMarkedDeclaration + Absent => ReachesNoTestCode + } +} diff --git a/src/v2/test/claim/body_lowering/arrow_body_form_witness_test.dag b/src/v2/test/claim/body_lowering/arrow_body_form_witness_test.dag index e134244d021..4e1769e5bd8 100644 --- a/src/v2/test/claim/body_lowering/arrow_body_form_witness_test.dag +++ b/src/v2/test/claim/body_lowering/arrow_body_form_witness_test.dag @@ -1,6 +1,7 @@ module v2.test.claim.body_lowering.arrow_body_form_witness import std.occurrence_identity { OccurrenceSynthetic } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_tree } import v2.compiler.resolve { resolve } import v2.extdeps.languages.dag { @@ -123,7 +124,7 @@ fn arrow_body_form_zero_arrow_fixture() -> Optional { // arm FAILS the witness rather than skipping it — an unadmittable fixture is a defect in // the fixture, not a reason to report green. fn abf_admitted_add_arrow_tree() -> Outcome { - admit_normalized_tree(root: dag_add_arrow_with_body_node(), diagnostics: None) + admit_normalized_tree(test_markers: test_marker_channel_empty(), root: dag_add_arrow_with_body_node(), diagnostics: None) } test fn arrow_body_form_eval_value_vertical_holds() -> Bool { diff --git a/src/v2/test/claim/body_lowering/infer_transform_binary_infix_witness_helpers.dag b/src/v2/test/claim/body_lowering/infer_transform_binary_infix_witness_helpers.dag index aa9e655551b..e75deaa29f6 100644 --- a/src/v2/test/claim/body_lowering/infer_transform_binary_infix_witness_helpers.dag +++ b/src/v2/test/claim/body_lowering/infer_transform_binary_infix_witness_helpers.dag @@ -6,6 +6,7 @@ import v2.compiler.infer { inferred_facts_witness_for_node } import v2.compiler.resolve { resolve } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { admit_normalized_tree } import v2.extdeps.languages.dag { dag_int_literal_fixture_one, @@ -52,7 +53,7 @@ fn infer_transform_witness_resolved_add_arrow() -> Optional { match wave1_gate1_normalized_add_module() { Absent => Absent Present { value: tree } => - match admit_normalized_tree(root: tree, diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: tree, diagnostics: None) { Rejected { diagnostics: _ } => Absent Accepted { value: normalized, diagnostics: _ } => match resolve(tree: normalized, lm: dag_language_model()) { diff --git a/src/v2/test/claim/body_lowering/wave1_gate1_normalize_add_helpers.dag b/src/v2/test/claim/body_lowering/wave1_gate1_normalize_add_helpers.dag index defe594985b..234d752f4c4 100644 --- a/src/v2/test/claim/body_lowering/wave1_gate1_normalize_add_helpers.dag +++ b/src/v2/test/claim/body_lowering/wave1_gate1_normalize_add_helpers.dag @@ -1,6 +1,7 @@ module v2.test.claim.body_lowering.wave1_gate1_normalize_add_helpers import v2.compiler.normalize { normalize } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { admit_normalized_tree } import v2.compiler.parse { parse_module } import v2.compiler.resolve { resolve } @@ -65,7 +66,7 @@ fn wave1_gate1_normalized_add_resolves_holds() -> Bool { match wave1_gate1_normalized_add_module() { Absent => false Present { value: tree } => - match admit_normalized_tree(root: tree, diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: tree, diagnostics: None) { Rejected { diagnostics: _ } => false Accepted { value: normalized, diagnostics: _ } => match resolve(tree: normalized, lm: dag_language_model()) { @@ -100,7 +101,7 @@ fn wave1_gate1_resolved_add_arrow_transform_holds() -> Bool { match wave1_gate1_normalized_add_module() { Absent => false Present { value: tree } => - match admit_normalized_tree(root: tree, diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: tree, diagnostics: None) { Rejected { diagnostics: _ } => false Accepted { value: normalized, diagnostics: _ } => match resolve(tree: normalized, lm: dag_language_model()) { diff --git a/src/v2/test/claim/claim_pipeline/resolve_test.dag b/src/v2/test/claim/claim_pipeline/resolve_test.dag index b656571cde9..3d8a46b157b 100644 --- a/src/v2/test/claim/claim_pipeline/resolve_test.dag +++ b/src/v2/test/claim/claim_pipeline/resolve_test.dag @@ -2,6 +2,7 @@ module v2.test.claim_pipeline.resolve import std.occurrence_identity { OccurrenceSynthetic } import v2.compiler.normalize { normalize } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { admit_normalized_tree } import v2.compiler.resolve { resolve } import v2.extdeps.languages.dag { @@ -67,7 +68,7 @@ data spine_resolve_reject_module_subject: Node = Node { // self-bound every Atom node anywhere in the tree -- including this // reference -- so it resolved without ever consulting canonical_symbols. test fn spine_resolve_rejects_noncanonical_root_atom() -> Bool { - match admit_normalized_tree(root: spine_resolve_reject_module_subject, diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: spine_resolve_reject_module_subject, diagnostics: None) { Accepted { value: normalized, diagnostics: _ } => match resolve(tree: normalized, lm: dag_language_model_surface_empty_prelude()) { Accepted { value: _, diagnostics: _ } => false diff --git a/src/v2/test/claim/long/door_real_module_probe_test.dag b/src/v2/test/claim/long/door_real_module_probe_test.dag index 398523369e9..12c10896eae 100644 --- a/src/v2/test/claim/long/door_real_module_probe_test.dag +++ b/src/v2/test/claim/long/door_real_module_probe_test.dag @@ -1,6 +1,6 @@ module v2.test.long.door_real_module_probe -import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_roots } +import v2.compiler.normalized_tree { NormalizedTree, admit_unmarked_normalized_roots } import v2.std.diagnostic { Accepted, None, Outcome, Rejected } import v2.compiler.name_resolve { resolve_with_admission_policy } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } @@ -83,7 +83,7 @@ fn quad_subject_with_import_use() -> Node { } fn quad_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: quad_subject_with_import_use(), tail: Cons { diff --git a/src/v2/test/claim/manual/body_lowering_normalize_add_test.dag b/src/v2/test/claim/manual/body_lowering_normalize_add_test.dag index 1e7b1574481..2329bbc9b3a 100644 --- a/src/v2/test/claim/manual/body_lowering_normalize_add_test.dag +++ b/src/v2/test/claim/manual/body_lowering_normalize_add_test.dag @@ -8,6 +8,7 @@ import v2.compiler.body_lowering_fold { body_lower_try_infix_transform, body_lower_unwrap_captured } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_tree } import v2.compiler.normalize { normalize } import v2.compiler.resolve { resolve } @@ -359,7 +360,7 @@ fn body_lowering_tree_contains_atom(root: Node, wanted: Symbol) -> Bool { test fn body_lowering_fixture_resolves() -> Bool { let lm = dag_language_model() - match admit_normalized_tree(root: dag_add_arrow_with_body_fixture, diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: dag_add_arrow_with_body_fixture, diagnostics: None) { Rejected { diagnostics: _ } => false Accepted { value: admitted, diagnostics: _ } => match resolve(tree: admitted, lm: lm) { @@ -729,7 +730,7 @@ test fn body_lowering_normalized_arrow_root_resolves() -> Bool { match body_lower_find_arrow_in_module(root: tree.root) { Absent => false Present { value: arrow } => - match admit_normalized_tree(root: arrow, diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: arrow, diagnostics: None) { Rejected { diagnostics: _ } => false Accepted { value: admitted_arrow, diagnostics: _ } => match resolve(tree: admitted_arrow, lm: lm) { diff --git a/src/v2/test/claim/manual/cross_language_add_python_to_typescript_test.dag b/src/v2/test/claim/manual/cross_language_add_python_to_typescript_test.dag index c6d4cdbaa2e..af3c176e13b 100644 --- a/src/v2/test/claim/manual/cross_language_add_python_to_typescript_test.dag +++ b/src/v2/test/claim/manual/cross_language_add_python_to_typescript_test.dag @@ -3,9 +3,6 @@ module v2.test.manual.cross_language_add_python_to_typescript import v2.test.manual.python_grammar_claim { python_grammar_parse_fixture } -import v2.test.manual.typescript_effect_io_emit { - ts_effect_io_emit_holds -} import v2.test.manual.ingest_bridge { ingest_bridge_realized } @@ -144,7 +141,6 @@ test fn cross_language_add_python_to_typescript_chain_status_holds() -> Bool { python_core == python_emitted_add_fn_node() && cross_language_compile_on_real_tree_round_trip_holds(parse_tree: python_parse_tree) - && ts_effect_io_emit_holds() Rejected { diagnostics: _ } => false } Rejected { diagnostics: _ } => false diff --git a/src/v2/test/claim/manual/program_assembly_multi_file_test.dag b/src/v2/test/claim/manual/program_assembly_multi_file_test.dag index 92b7c052008..30f0829b0a3 100644 --- a/src/v2/test/claim/manual/program_assembly_multi_file_test.dag +++ b/src/v2/test/claim/manual/program_assembly_multi_file_test.dag @@ -1,7 +1,7 @@ module v2.test.manual.program_assembly_multi_file import std.occurrence_identity { OccurrenceSynthetic } -import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_roots } +import v2.compiler.normalized_tree { NormalizedTree, admit_unmarked_normalized_roots } import extdeps.communication.medium { Lossless, Medium } import v2.compiler.name_resolve { Admission, @@ -115,7 +115,7 @@ fn pa_subject_with_import_use() -> Node { } fn pa_cross_file_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: pa_graft_module_root(root: pa_subject_with_import_use()), tail: Cons { @@ -134,7 +134,7 @@ fn pa_cross_file_roots() -> Outcome> { } fn pa_duplicate_module_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: pa_graft_module_root( root: pa_module_root( diff --git a/src/v2/test/claim/manual/resolve_compile_anchor_test.dag b/src/v2/test/claim/manual/resolve_compile_anchor_test.dag index eb560955492..97181837627 100644 --- a/src/v2/test/claim/manual/resolve_compile_anchor_test.dag +++ b/src/v2/test/claim/manual/resolve_compile_anchor_test.dag @@ -1,7 +1,8 @@ module v2.test.manual.resolve_compile_anchor import std.occurrence_identity { OccurrenceSynthetic } -import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_roots, admit_normalized_tree } +import v2.std.declaration_marker { test_marker_channel_empty } +import v2.compiler.normalized_tree { NormalizedTree, admit_unmarked_normalized_roots, admit_normalized_tree } import v2.compiler.name_resolve { Admission, Import, @@ -60,7 +61,7 @@ fn service_atom_conj_tree() -> Node { } fn anchor_resolve_service_atom_via_canonical_symbols() -> Outcome { - match admit_normalized_tree(root: service_atom_conj_tree(), diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: service_atom_conj_tree(), diagnostics: None) { Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: tree, diagnostics: _ } => resolve(tree: tree, lm: dag_language_model_void()) @@ -68,7 +69,7 @@ fn anchor_resolve_service_atom_via_canonical_symbols() -> Outcome } fn anchor_resolve_empty_prelude_service_atom() -> Outcome { - match admit_normalized_tree(root: service_atom_conj_tree(), diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: service_atom_conj_tree(), diagnostics: None) { Rejected { diagnostics: r } => Rejected { diagnostics: r } Accepted { value: tree, diagnostics: _ } => resolve(tree: tree, lm: dag_language_model_surface_empty_prelude()) @@ -77,6 +78,7 @@ fn anchor_resolve_empty_prelude_service_atom() -> Outcome { fn anchor_resolve_multi_edge_conj_via_canonical_symbols() -> Outcome { match admit_normalized_tree( + test_markers: test_marker_channel_empty(), root: Node { kind: TypeNode { connective: Conj }, children: [ @@ -112,6 +114,7 @@ fn anchor_resolve_multi_edge_conj_via_canonical_symbols() -> Outcome Outcome { match admit_normalized_tree( + test_markers: test_marker_channel_empty(), root: Node { kind: TypeNode { connective: Conj }, children: [ @@ -260,7 +263,7 @@ fn resolve_subject_name() -> QualifiedName { } fn resolve_roots_single_import() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: resolve_subject_module_root_with_import_use(), tail: Cons { diff --git a/src/v2/test/claim/name_resolve/admission_fail_closed_test.dag b/src/v2/test/claim/name_resolve/admission_fail_closed_test.dag index 96f9dc5c01e..7eaf3d8390a 100644 --- a/src/v2/test/claim/name_resolve/admission_fail_closed_test.dag +++ b/src/v2/test/claim/name_resolve/admission_fail_closed_test.dag @@ -18,6 +18,7 @@ import v2.compiler.name_resolve { module_root_find, validate_module_roots } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_tree } import v2.std.cross_tree.resolution { source_root_index_empty } import v2.extdeps.languages.dag { @@ -127,7 +128,7 @@ fn fc_with_roots( } fn fc_admitted(n: Node) -> Outcome { - admit_normalized_tree(root: n, diagnostics: None) + admit_normalized_tree(test_markers: test_marker_channel_empty(), root: n, diagnostics: None) } fn fc_duplicate_roots() -> Outcome> { diff --git a/src/v2/test/claim/name_resolve/malformed_imported_root_test.dag b/src/v2/test/claim/name_resolve/malformed_imported_root_test.dag index 983108aac81..81714c0706c 100644 --- a/src/v2/test/claim/name_resolve/malformed_imported_root_test.dag +++ b/src/v2/test/claim/name_resolve/malformed_imported_root_test.dag @@ -9,6 +9,7 @@ import v2.compiler.name_resolve { ImportVisible, admit_import_entry } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_tree } import v2.std.cross_tree.resolution { source_root_index_empty } import v2.std.diagnostic { Accepted, None, Outcome, Rejected, bind_outcome, outcome_accepted } @@ -63,7 +64,7 @@ fn malformed_entry_name() -> QualifiedName { } fn roots_with_malformed_entry() -> Outcome> { - bind_outcome(o: admit_normalized_tree(root: malformed_root_node(), diagnostics: None), f: fn(a) { + bind_outcome(o: admit_normalized_tree(test_markers: test_marker_channel_empty(), root: malformed_root_node(), diagnostics: None), f: fn(a) { outcome_accepted(value: Cons { head: a, tail: Empty }) }) } diff --git a/src/v2/test/claim/name_resolve/one_member_cost_probe_test.dag b/src/v2/test/claim/name_resolve/one_member_cost_probe_test.dag index 614d7eabb3a..daf6fd0debd 100644 --- a/src/v2/test/claim/name_resolve/one_member_cost_probe_test.dag +++ b/src/v2/test/claim/name_resolve/one_member_cost_probe_test.dag @@ -7,6 +7,7 @@ import v2.compiler.name_resolve { resolve_with_admission } import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_tree } +import v2.std.declaration_marker { test_marker_channel_empty } import v2.compiler.parse { parse_module } import v2.compiler.resolve { ResolvedTree } import v2.compiler.tokenize { tokenize } @@ -72,6 +73,7 @@ fn probe_one_member_qn() -> QualifiedName { fn probe_roots_for_export(export_sym: Symbol) -> Outcome> { bind_outcome( o: admit_normalized_tree( + test_markers: test_marker_channel_empty(), root: probe_one_member_root_export(export_sym: export_sym), diagnostics: None ), diff --git a/src/v2/test/claim/name_resolve/test_code_reference_wall_test.dag b/src/v2/test/claim/name_resolve/test_code_reference_wall_test.dag new file mode 100644 index 00000000000..173d11360b3 --- /dev/null +++ b/src/v2/test/claim/name_resolve/test_code_reference_wall_test.dag @@ -0,0 +1,492 @@ +module v2.test.name_resolve.test_code_reference_wall + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// THE WALL AT ONE INTERFACE: name resolution (v2.compiler.name_resolve resolve_with_admission, the +// multi-root door the native compile uses), handed normalized module roots as SUPPLIED VALUES. Each +// claim reports the head refusal reason or ACCEPTED, so a red that refuses for some OTHER reason (an +// unbound name, a malformed root) does not pass for the wall. +// +// The owner ruling (2026-09-16/17): a test-marked declaration may be referenced by NOTHING, a test fn +// in the same module included. The wall is ITEM-scoped: an unmarked declaration is ordinary code even +// in a module that declares tests (a whole-module rule is wrong in both directions, the lesson of the +// v1 wall in gunbc#11505). The shapes below are the ones v1's reviewers found one per round, each +// with its red or its control: same-module and cross-module references, a QUALIFIED path to a test +// fn, precedence of a module's own declaration over an imported one of the same name, and a +// reference from a parameter default -- which v2 cannot express at all (it refuses at parse). +// +// WHY THE ROOTS ARE SUPPLIED (DESIGN section 3). Producing two roots from source costs two tokenize, +// parse and normalize passes (about 120k eval steps for two one-line modules) before resolution +// starts, and resolution itself is about 67k, so a from-source claim exceeds the floor's 72,300-step +// new-witness budget by roughly three times while its assertions inspect only the resolution verdict. +// The pairing obligation is discharged by `supplied_root_is_what_normalize_emits_holds`: the real +// front end, run on the source text below, emits a root whose content hash equals the supplied one +// and a marker channel that marks exactly the supplied names -- so a fixture that drifted from the +// producer turns that claim red rather than leaving these green over a tree nothing produces. +// +// The fixtures are expression-bodied (`fn f() -> T = g()`), because the member shape they encode is +// what normalize emits for that form. A block body holding a call is not a usable fixture today: +// `{ g() }` lowers to a Transform over the brace token with the call gone (tracked as its own work +// item), so it hands resolution no reference at all. + +fn wall_atom(identity: Symbol) -> Node { + Node { kind: TypeNode { connective: Atom { identity: identity } }, children: [], occurrence_id: OccurrenceSynthetic } +} + +fn wall_conj(children: List) -> Node { + Node { kind: TypeNode { connective: Conj }, children: children, occurrence_id: OccurrenceSynthetic } +} + +// `name: () -> Bool = body`, in the shape normalize emits for an expression-bodied, zero-parameter fn. +fn wall_member(name: Symbol, body: Node) -> Edge { + Edge { + label: Named { name: name }, + target: Node { + kind: TypeNode { connective: Arrow }, + children: [ + Edge { label: Positional, target: wall_conj(children: []) }, + Edge { label: Positional, target: wall_atom(identity: ^bool_node_symbol) }, + Edge { label: Positional, target: wall_atom(identity: ^bool_node_symbol) }, + Edge { label: Named { name: ^arrow_body_edge }, target: body } + ], + occurrence_id: OccurrenceSynthetic + } + } +} + +// `name: (param: Bool) -> Bool = param` -- a parameter that shares a module-level name. +fn wall_member_returning_its_param(name: Symbol, param: Symbol) -> Edge { + Edge { + label: Named { name: name }, + target: Node { + kind: TypeNode { connective: Arrow }, + children: [ + Edge { + label: Positional, + target: wall_conj(children: [Edge { label: Named { name: param }, target: wall_atom(identity: ^bool_node_symbol) }]) + }, + Edge { label: Positional, target: wall_atom(identity: ^bool_node_symbol) }, + Edge { label: Positional, target: wall_atom(identity: ^bool_node_symbol) }, + Edge { label: Named { name: ^arrow_body_edge }, target: wall_atom(identity: param) } + ], + occurrence_id: OccurrenceSynthetic + } + } +} + +// `module wall.` with `members`, grafted as normalize grafts a two-segment module. The +// leaf body is the graft's body conj: its identity projection first, the producer marker +// namespace_graft_module_body_marker_node (v2.compiler.namespace_graft namespace_graft_build_body_conj, +// gunbc#11694), then the members. +fn wall_module_body(members: List) -> Node { + wall_conj(children: concat( + [Edge { label: Named { name: ^grammar_production_identity_node_projection }, target: namespace_graft_module_body_marker_node() }], + members + )) +} + +fn wall_module_root(leaf_segment: Symbol, members: List) -> Node { + wall_conj(children: [ + Edge { label: Named { name: ^grammar_production_identity_node_projection }, target: wall_atom(identity: ^dag_surface_module) }, + Edge { + label: Named { name: ^grammar_production_captured_node_projection }, + target: wall_conj(children: [ + Edge { + label: Named { name: ^wall }, + target: wall_conj(children: [Edge { label: Named { name: leaf_segment }, target: wall_module_body(members: members) }]) + } + ]) + } + ]) +} + +fn wall_channel(marked: List) -> TestMarkerChannel { + TestMarkerChannel { + marked: fold(marked, init: [], f: fn(acc, name) { list_snoc_item(xs: acc, item: TestMarkedDeclaration { name: name }) }) + } +} + +fn wall_tree(root: Node, marked: List) -> Outcome { + admit_normalized_tree(root: root, test_markers: wall_channel(marked: marked), diagnostics: None) +} + +fn wall_verdict(outcome: Outcome) -> String { + match outcome { + Accepted { value: _, diagnostics: _ } => "ACCEPTED" + Rejected { diagnostics: d } => symbol_lexeme(sym: d.head.reason) + } +} + +// Resolves module wall. as the only root: the door for the same-module halves, +// which need no second module and pay for none. +fn wall_resolve_alone(subject_segment: Symbol, subject: Outcome) -> String { + match subject { + Rejected { diagnostics: _ } => "SUBJECT_NOT_ADMITTED" + Accepted { value: s, diagnostics: _ } => + wall_verdict(outcome: resolve_with_admission( + lm: dag_language_model(), + roots: Cons { head: s, tail: Empty }, + admission: Admission { + subject: ResolutionSubject { name: Cons { head: ^wall, tail: Cons { head: subject_segment, tail: Empty } } }, + imports: Empty + } + )) + } +} + +// Resolves module wall. with one peer root beside it. +fn wall_resolve(subject_segment: Symbol, subject: Outcome, peer: Outcome) -> String { + match subject { + Rejected { diagnostics: _ } => "SUBJECT_NOT_ADMITTED" + Accepted { value: s, diagnostics: _ } => + match peer { + Rejected { diagnostics: _ } => "PEER_NOT_ADMITTED" + Accepted { value: p, diagnostics: _ } => + wall_verdict(outcome: resolve_with_admission( + lm: dag_language_model(), + roots: Cons { head: s, tail: Cons { head: p, tail: Empty } }, + admission: Admission { + subject: ResolutionSubject { name: Cons { head: ^wall, tail: Cons { head: subject_segment, tail: Empty } } }, + imports: Empty + } + )) + } + } +} + +// module wall.peer -- `fn shared_fixture() -> Bool = true`, `test fn peer_leaf() -> Bool = shared_fixture()` +fn peer_test_module() -> Outcome { + wall_tree( + root: wall_module_root(leaf_segment: ^peer, members: [ + wall_member(name: ^shared_fixture, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^peer_leaf, body: wall_atom(identity: ^shared_fixture)), + wall_member(name: ^qualified_user, body: wall_qualified(segments: [^wall, ^peer, ^peer_leaf])) + ]), + marked: [^peer_leaf] + ) +} + +// The smallest module that carries every producer shape the supplied roots rely on, one member per +// fixture builder: wall_member with a `true` body (`shared_fixture`), wall_member_returning_its_param +// (`helper`, the one-parameter domain), and wall_member with a name-reference body carrying the test +// marker (`peer_leaf`). Three members because the builders have three distinct bodies; the front +// end's cost grows with the source and this claim pays for one real tokenize, parse and normalize. +// SINCE gunbc#11683 THERE IS NO SUPPLIED NODE HERE THAT NO SOURCE PRODUCES. A bare dotted body chain +// now lowers to the qualified-name spine, so wall_qualified became producible the day that landed -- +// and a supplied builder whose producer has moved is exactly what the pairing obligation exists to +// catch. The fourth member of the paired source and fixture below (`qualified_user`) joins it to the +// real front end, so the whole-root content_hash comparison reds if that lowering moves again. +fn inhabitance_module() -> Outcome { + wall_tree( + root: wall_module_root(leaf_segment: ^peer, members: [ + wall_member(name: ^shared_fixture, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member_returning_its_param(name: ^helper, param: ^leaf), + wall_member(name: ^peer_leaf, body: wall_atom(identity: ^shared_fixture)) + ]), + marked: [^peer_leaf] + ) +} + +data inhabitance_module_source: String = "module wall.peer\nfn shared_fixture() -> Bool = true\nfn helper(leaf: Bool) -> Bool = leaf\ntest fn peer_leaf() -> Bool = shared_fixture()\nfn qualified_user() -> Bool = wall.peer.peer_leaf\n" + +// module wall.peer -- `fn shared_fixture() -> Bool = true`, no test code. +fn peer_serving_module() -> Outcome { + wall_tree( + root: wall_module_root(leaf_segment: ^peer, members: [wall_member(name: ^shared_fixture, body: wall_atom(identity: ^dag_token_kw_true))]), + marked: [] + ) +} + +// A one-member serving module wall.serving whose only fn's body is `body`. +fn serving_module_with_body(body: Node) -> Outcome { + wall_tree(root: wall_module_root(leaf_segment: ^serving, members: [wall_member(name: ^uses_peer, body: body)]), marked: []) +} + +// INHABITANCE, THE ROUTE THE SUPPLIED ROOTS STAND ON: the real front end, on the source text the +// inhabitance fixture encodes (built with the same wall_member and wall_module_root every claim below +// uses), emits the same root (by content hash, which does not read occurrence ids) and a +// channel marking exactly `peer_leaf` -- one claim per half, both reading the one shared front-end +// value below. They are the two things every claim below reads. +// ONE PRODUCER, TWO READERS, AND NO WARM-SHARE ROW. Both inhabitance claims call this one function, +// so the source literal and the producer are shared; the VALUE is not. Claim frames are isolated, so +// each claim recomputes this front-end run. A row enrolling it would have to be admitted by a +// controlled row-present against row-absent measurement on the required floor, and the restored floor +// publishes no claim-cost table, no shared-fill ledger and no receipt to make one -- so the row that +// stood here is deleted rather than argued from the value being portable, which establishes only that +// it CAN be served, never that serving is cheaper. +// WHEN THE ROOT CLAIM REDS: render BOTH trees with their EDGE LABELS and compare those. A read by +// child index is what made the graft-marker drift (#11694, a leading edge on the module body) look +// like a change inside the member Arrow, and cost two lanes to find. +fn inhabitance_normalized() -> Outcome { + let lm = dag_language_model() + match tokenize(text: inhabitance_module_source, file: ^wall_peer_file, rules: lm.lex) { + Rejected { diagnostics: d } => Rejected { diagnostics: d } + Accepted { value: ts, diagnostics: _ } => + match parse_module(tokens: ts, grammar: lm.grammar) { + Rejected { diagnostics: d } => Rejected { diagnostics: d } + Accepted { value: artifact, diagnostics: _ } => normalize(parse_tree: artifact.tree) + } + } +} + +test fn supplied_root_is_what_normalize_emits_holds() -> Bool { + match inhabitance_normalized() { + Rejected { diagnostics: _ } => false + Accepted { value: emitted, diagnostics: _ } => + match inhabitance_module() { + Rejected { diagnostics: _ } => false + Accepted { value: supplied, diagnostics: _ } => content_hash(n: emitted.root) == content_hash(n: supplied.root) + } + } +} + +test fn supplied_channel_is_what_normalize_emits_holds() -> Bool { + match inhabitance_normalized() { + Rejected { diagnostics: _ } => false + Accepted { value: emitted, diagnostics: _ } => + (test_marker_channel_count(channel: emitted.test_markers) == 1) + && test_marker_channel_marks(channel: emitted.test_markers, name: ^peer_leaf) + } +} + +// RED: a test fn calling another test fn in its own module -- the case the ruling names explicitly. +test fn test_fn_calling_a_test_fn_is_refused_holds() -> Bool { + wall_resolve_alone( + subject_segment: ^same, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^same, members: [ + wall_member(name: ^leaf, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^rollup, body: wall_atom(identity: ^leaf)) + ]), + marked: [^leaf, ^rollup] + ) + ) == "resolve_reason_test_code_referenced" +} + +// RED: serving code calling a test fn in its own module. +test fn serving_fn_calling_a_test_fn_is_refused_holds() -> Bool { + wall_resolve_alone( + subject_segment: ^same, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^same, members: [ + wall_member(name: ^leaf, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^helper, body: wall_atom(identity: ^leaf)) + ]), + marked: [^leaf] + ) + ) == "resolve_reason_test_code_referenced" +} + +// RED: serving code calling a test fn another module declares. +test fn serving_code_calling_another_modules_test_fn_is_refused_holds() -> Bool { + wall_resolve( + subject_segment: ^serving, + subject: serving_module_with_body(body: wall_atom(identity: ^peer_leaf)), + peer: peer_test_module() + ) == "resolve_reason_test_code_referenced" +} + +// CONTROL: the intended shape, a test fn calling an ordinary fn, resolves. +test fn test_fn_calling_an_ordinary_fn_resolves_holds() -> Bool { + wall_resolve_alone( + subject_segment: ^same, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^same, members: [ + wall_member(name: ^helper, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^uses_helper, body: wall_atom(identity: ^helper)) + ]), + marked: [^uses_helper] + ) + ) == "ACCEPTED" +} + +// CONTROL: a parameter that shares a test fn's name binds to the parameter, not to the test fn. +test fn a_local_binder_shadowing_a_test_fn_resolves_holds() -> Bool { + wall_resolve_alone( + subject_segment: ^same, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^same, members: [ + wall_member(name: ^leaf, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member_returning_its_param(name: ^helper, param: ^leaf) + ]), + marked: [^leaf] + ) + ) == "ACCEPTED" +} + +// CONTROL, ITEM SCOPE: an unmarked declaration of a module that declares tests is ordinary code, and +// serving code may reference it. +test fn an_ordinary_declaration_of_a_test_module_resolves_holds() -> Bool { + wall_resolve( + subject_segment: ^serving, + subject: serving_module_with_body(body: wall_atom(identity: ^shared_fixture)), + peer: peer_test_module() + ) == "ACCEPTED" +} + +// `wall.peer.peer_leaf` as a qualified-path node, the spine qualified_name_from_node reads. +fn wall_qualified(segments: List) -> Node { + fold_list_node(xs: segments, item_node: fn(sym) { wall_atom(identity: sym) }) +} + +// RED: a QUALIFIED path to another module's test fn is refused at the qualified-path door +// (v2.compiler.resolve try_resolve_qualified_name_node), which binds by the whole path rather than a +// bare name. v2 lowering does not yet carry a qualified path in a fn BODY (`= wall.peer.peer_leaf` +// lowers to the atom `wall`; tracked as its own defect), so this supplies the node the door reads. +test fn a_qualified_path_to_a_test_fn_is_refused_holds() -> Bool { + wall_resolve( + subject_segment: ^serving, + subject: serving_module_with_body(body: wall_qualified(segments: [^wall, ^peer, ^peer_leaf])), + peer: peer_test_module() + ) == "resolve_reason_test_code_referenced" +} + +// CONTROL, PRECEDENCE: a module's own declaration beats a same-named declaration elsewhere. The +// subject declares an ordinary `peer_leaf`; the peer's `peer_leaf` is a test fn. The subject's +// reference binds to its own, so it resolves. +test fn a_modules_own_declaration_beats_a_same_named_test_fn_holds() -> Bool { + wall_resolve( + subject_segment: ^serving, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^serving, members: [ + wall_member(name: ^peer_leaf, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^uses_peer, body: wall_atom(identity: ^peer_leaf)) + ]), + marked: [] + ), + peer: peer_test_module() + ) == "ACCEPTED" +} + +data default_reference_source: String = "module m\nfn f(x: T = g()) -> T = x\n" + +// A reference from a parameter DEFAULT cannot be written in v2: the grammar has no default, and the +// source refuses at parse, before resolution could miss it. If this ever parses, the default has +// become a place a reference can hide, and it needs its own red. +test fn a_parameter_default_is_refused_at_parse_holds() -> Bool { + let lm = dag_language_model() + match tokenize(text: default_reference_source, file: ^wall_default_file, rules: lm.lex) { + Rejected { diagnostics: _ } => false + Accepted { value: ts, diagnostics: _ } => + match parse_module(tokens: ts, grammar: lm.grammar) { + Rejected { diagnostics: _ } => true + Accepted { value: _, diagnostics: _ } => false + } + } +} + +// Resolves module wall. under the IMPORT-SCOPED policy with `wall.peer` imported, so +// the peer's names bind at the subject's root scope as admitted imports and the wall reads their +// origin from Namespace.imported_origins (v2.compiler.resolve root_binding_origin). +fn wall_resolve_importing_peer(subject_segment: Symbol, subject: Outcome, peer: Outcome) -> String { + match subject { + Rejected { diagnostics: _ } => "SUBJECT_NOT_ADMITTED" + Accepted { value: s, diagnostics: _ } => + match peer { + Rejected { diagnostics: _ } => "PEER_NOT_ADMITTED" + Accepted { value: p, diagnostics: _ } => + wall_verdict(outcome: resolve_with_admission_policy( + lm: dag_language_model(), + roots: Cons { head: s, tail: Cons { head: p, tail: Empty } }, + admission: Admission { + subject: ResolutionSubject { name: Cons { head: ^wall, tail: Cons { head: subject_segment, tail: Empty } } }, + imports: Cons { + head: Import { target: Cons { head: ^wall, tail: Cons { head: ^peer, tail: Empty } }, visibility: ImportVisible }, + tail: Empty + } + }, + index: source_root_index_empty(), + active_roots: Empty, + policy: ImportScoped + )) + } + } +} + +// RED, THE IMPORT DOOR: a test fn reached through an admitted import is refused. Its origin comes from +// the admission's imported_origins, not the subject's own declarations. +test fn an_imported_test_fn_is_refused_holds() -> Bool { + wall_resolve_importing_peer( + subject_segment: ^serving, + subject: serving_module_with_body(body: wall_atom(identity: ^peer_leaf)), + peer: peer_test_module() + ) == "resolve_reason_test_code_referenced" +} + +// THE SHADOW CASE THE WALL NEVER SEES (review 69014 on gunbc#11580). The review read a defect here: +// a module that BOTH imports a name and declares it would bind locally while Namespace.imported_origins +// still held the PEER's path, so root_binding_origin would hand the wall a path the reference never +// bound to -- refusing an ordinary local shadowed by an imported test fn, and, silently, ACCEPTING a +// reference to a local test fn shadowed by an ordinary import. The reading of root_binding_origin is +// right. THE STATE IS UNREACHABLE: admission refuses that module first, in BOTH directions, so the +// wall is never asked. AND NOTHING CAN MANUFACTURE THE COLLISION AROUND THAT ADMISSION: across the +// whole corpus there are eight constructions of Namespace.imported_origins, and seven build it EMPTY +// (v2.compiler.resolve empty_namespace and build_program_namespace, v2.compiler.name_resolve +// admission_namespace_base, and the four test fixtures that construct a Namespace directly). The one +// non-empty construction is admitted_subject_from_bindings, whose origins come only from an +// AdmissionAccepted, and the only writer into that map is admit_named_exports -- the same fold that +// refuses the collision. So a fixture cannot hand resolution an origin map that admission never saw. +// These three rows are that measurement, and they are why this PR carries no +// shadow-aware origin lookup -- a lookup guarding a state admission has already made unwritable would +// be validation restating a constraint the model carries (DESIGN section 5, correctness by +// construction over validation), and its red would not be authorable. + +// RED: a subject that declares `peer_leaf` AND imports a peer exporting `peer_leaf` is refused at +// ADMISSION as an ambiguous export -- the direction where the local declaration is ordinary and the +// peer's is a test fn. +test fn a_local_declaration_shadowing_an_imported_test_fn_is_refused_at_admission_holds() -> Bool { + wall_resolve_importing_peer( + subject_segment: ^serving, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^serving, members: [ + wall_member(name: ^peer_leaf, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^uses_peer, body: wall_atom(identity: ^peer_leaf)) + ]), + marked: [] + ), + peer: peer_test_module() + ) == "resolve_ambiguous_export" +} + +// RED, THE OTHER DIRECTION, and the one the review called silent: the subject's own declaration is +// TEST-MARKED and the peer's is ordinary. Admission refuses this too, so no reference to test code is +// accepted without a diagnostic -- the arm DESIGN section 5 forbids is closed upstream of the wall. +test fn a_local_test_fn_shadowing_an_imported_ordinary_declaration_is_refused_at_admission_holds() -> Bool { + wall_resolve_importing_peer( + subject_segment: ^serving, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^serving, members: [ + wall_member(name: ^shared_fixture, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^uses_peer, body: wall_atom(identity: ^shared_fixture)) + ]), + marked: [^shared_fixture] + ), + peer: peer_test_module() + ) == "resolve_ambiguous_export" +} + +// CONTROL for the two above: the refusal is caused by the SHADOW and not by the shape of these +// fixtures. The same subject and the same import, with a locally declared name the peer does not +// export, resolves. Without this row the two reds could both be passing on a malformed module. +test fn a_local_declaration_the_peer_does_not_export_resolves_holds() -> Bool { + wall_resolve_importing_peer( + subject_segment: ^serving, + subject: wall_tree( + root: wall_module_root(leaf_segment: ^serving, members: [ + wall_member(name: ^only_local, body: wall_atom(identity: ^dag_token_kw_true)), + wall_member(name: ^uses_peer, body: wall_atom(identity: ^only_local)) + ]), + marked: [] + ), + peer: peer_test_module() + ) == "ACCEPTED" +} + +// CONTROL for the import door: the same import, referencing the peer's ordinary declaration, resolves. +test fn an_imported_ordinary_declaration_resolves_holds() -> Bool { + wall_resolve_importing_peer( + subject_segment: ^serving, + subject: serving_module_with_body(body: wall_atom(identity: ^shared_fixture)), + peer: peer_test_module() + ) == "ACCEPTED" +} diff --git a/src/v2/test/claim/name_resolve_cross_tree_resolution_test.dag b/src/v2/test/claim/name_resolve_cross_tree_resolution_test.dag index ee00f6d73f8..90a6b9b4b0e 100644 --- a/src/v2/test/claim/name_resolve_cross_tree_resolution_test.dag +++ b/src/v2/test/claim/name_resolve_cross_tree_resolution_test.dag @@ -1,7 +1,7 @@ module v2.test.claim.name_resolve_cross_tree_resolution import std.occurrence_identity { OccurrenceSynthetic } -import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_roots } +import v2.compiler.normalized_tree { NormalizedTree, admit_unmarked_normalized_roots } import v2.compiler.name_resolve { Admission, Import, @@ -157,7 +157,7 @@ fn ct_both_trees() -> SourceRootSet { } fn ct_dag_same_tree_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: ct_graft_module_root( root: ct_subject_with_import_use( @@ -195,7 +195,7 @@ fn ct_dag_same_tree_admission() -> Admission { } fn ct_v2_same_tree_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: ct_graft_module_root( root: ct_subject_with_import_use( @@ -237,7 +237,7 @@ fn ct_v2_same_tree_admission() -> Admission { } fn ct_cross_tree_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: ct_graft_module_root( root: ct_subject_with_import_use( @@ -291,7 +291,7 @@ fn ct_v2_to_dag_index() -> SourceRootIndex { } fn ct_dag_to_v2_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: ct_graft_module_root( root: ct_subject_with_import_use( diff --git a/src/v2/test/claim/normalized_tree_admission_test.dag b/src/v2/test/claim/normalized_tree_admission_test.dag index 29382c69bfa..dfeb62841f4 100644 --- a/src/v2/test/claim/normalized_tree_admission_test.dag +++ b/src/v2/test/claim/normalized_tree_admission_test.dag @@ -2,7 +2,8 @@ module v2.test.claim.normalized_tree_admission import v2.compiler.body_lowering_fold { body_lower_wrapper_retained_shell } import std.algebra { Cons, Empty, FreeMonoid } -import v2.compiler.normalized_tree { admit_normalized_roots, admit_normalized_tree } +import v2.std.declaration_marker { test_marker_channel_empty } +import v2.compiler.normalized_tree { admit_unmarked_normalized_roots, admit_normalized_tree } import v2.std.diagnostic { Accepted, Diagnostic, @@ -56,6 +57,7 @@ fn is_rejected(o: Outcome) -> Bool { test fn a_retained_root_is_refused_at_the_carrier_door() -> Bool { is_rejected(o: admit_normalized_tree( + test_markers: test_marker_channel_empty(), root: probe_shell(), diagnostics: Some { diagnostics: NonEmptyDiagnostics { head: retention_diagnostic(), tail: [] } @@ -65,6 +67,7 @@ test fn a_retained_root_is_refused_at_the_carrier_door() -> Bool { test fn retention_is_found_past_the_diagnostic_head_RED() -> Bool { is_rejected(o: admit_normalized_tree( + test_markers: test_marker_channel_empty(), root: probe_shell(), diagnostics: Some { diagnostics: NonEmptyDiagnostics { @@ -76,11 +79,12 @@ test fn retention_is_found_past_the_diagnostic_head_RED() -> Bool { } test fn a_clean_root_is_admitted_positive_control() -> Bool { - (is_rejected(o: admit_normalized_tree(root: probe_shell(), diagnostics: None)) == false) + (is_rejected(o: admit_normalized_tree(test_markers: test_marker_channel_empty(), root: probe_shell(), diagnostics: None)) == false) } test fn an_unrelated_diagnostic_does_not_refuse_RED() -> Bool { (is_rejected(o: admit_normalized_tree( + test_markers: test_marker_channel_empty(), root: probe_shell(), diagnostics: Some { diagnostics: NonEmptyDiagnostics { head: unrelated_diagnostic(), tail: [] } @@ -90,7 +94,7 @@ test fn an_unrelated_diagnostic_does_not_refuse_RED() -> Bool { test fn the_production_retention_producer_is_refused_by_the_door() -> Bool { match body_lower_wrapper_retained_shell(shell: probe_shell()) { - Accepted { value: v, diagnostics: d } => is_rejected(o: admit_normalized_tree(root: v, diagnostics: d)) + Accepted { value: v, diagnostics: d } => is_rejected(o: admit_normalized_tree(test_markers: test_marker_channel_empty(), root: v, diagnostics: d)) Rejected { diagnostics: _ } => false } } @@ -100,7 +104,7 @@ fn two_probe_roots() -> FreeMonoid { } test fn plural_admission_does_not_duplicate_shared_diagnostics_RED() -> Bool { - match admit_normalized_roots( + match admit_unmarked_normalized_roots( roots: two_probe_roots(), diagnostics: Some { diagnostics: NonEmptyDiagnostics { head: unrelated_diagnostic(), tail: [] } @@ -118,7 +122,7 @@ test fn plural_admission_does_not_duplicate_shared_diagnostics_RED() -> Bool { } test fn plural_admission_refuses_a_retained_batch() -> Bool { - match admit_normalized_roots( + match admit_unmarked_normalized_roots( roots: two_probe_roots(), diagnostics: Some { diagnostics: NonEmptyDiagnostics { head: retention_diagnostic(), tail: [] } diff --git a/src/v2/test/claim/parse/parse_binding_fidelity_test.dag b/src/v2/test/claim/parse/parse_binding_fidelity_test.dag index 80421802907..264f6f60924 100644 --- a/src/v2/test/claim/parse/parse_binding_fidelity_test.dag +++ b/src/v2/test/claim/parse/parse_binding_fidelity_test.dag @@ -1,7 +1,8 @@ module v2.test.parse.parse_binding_fidelity import std.occurrence_identity { OccurrenceSynthetic } -import v2.compiler.normalized_tree { NormalizedTree, admit_normalized_roots, admit_normalized_tree } +import v2.std.declaration_marker { test_marker_channel_empty } +import v2.compiler.normalized_tree { NormalizedTree, admit_unmarked_normalized_roots, admit_normalized_tree } import v2.compiler.name_resolve { Admission, Import, @@ -135,7 +136,7 @@ fn pbf_subject_with_import_use() -> Node { } fn pbf_cross_file_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: pbf_graft_module_root(root: pbf_subject_with_import_use()), tail: Cons { @@ -200,7 +201,7 @@ fn pbf_unbound_atom_tree() -> Node { } fn pbf_resolve_unbound_symbol_rejects() -> Bool { - match admit_normalized_tree(root: pbf_unbound_atom_tree(), diagnostics: None) { + match admit_normalized_tree(test_markers: test_marker_channel_empty(), root: pbf_unbound_atom_tree(), diagnostics: None) { Rejected { diagnostics: _ } => false Accepted { value: admitted_tree, diagnostics: _ } => match resolve( @@ -239,7 +240,7 @@ fn pbf_subject_with_ambiguous_import_use() -> Node { } fn pbf_ambiguous_import_roots() -> Outcome> { - admit_normalized_roots( + admit_unmarked_normalized_roots( roots: Cons { head: pbf_graft_module_root(root: pbf_subject_with_ambiguous_import_use()), tail: Cons { diff --git a/src/v2/test/claim/parse/test_marker_channel_test.dag b/src/v2/test/claim/parse/test_marker_channel_test.dag index 7be446266a7..a37a0c3a538 100644 --- a/src/v2/test/claim/parse/test_marker_channel_test.dag +++ b/src/v2/test/claim/parse/test_marker_channel_test.dag @@ -28,7 +28,7 @@ fn test_marker_parsed(src: String, file: Symbol) -> Outcome { fn test_marker_capture_of(src: String, file: Symbol) -> Outcome { match test_marker_parsed(src: src, file: file) { Rejected { diagnostics: d } => Rejected { diagnostics: d } - Accepted { value: artifact, diagnostics: _ } => test_marker_capture(artifact: artifact) + Accepted { value: artifact, diagnostics: _ } => test_marker_capture(tree: artifact.tree) } } diff --git a/src/v2/test/claim/parse/weather_g0_prefix_parse_probe_test.dag b/src/v2/test/claim/parse/weather_g0_prefix_parse_probe_test.dag index 1c604d89417..00262838c81 100644 --- a/src/v2/test/claim/parse/weather_g0_prefix_parse_probe_test.dag +++ b/src/v2/test/claim/parse/weather_g0_prefix_parse_probe_test.dag @@ -3,6 +3,7 @@ module v2.test.parse.weather_g0_prefix_parse_probe import std.occurrence_identity { OccurrenceSynthetic } import std.algebra { Cons, Empty } import v2.compiler.parse { parse_module } +import v2.std.declaration_marker { test_code_index_empty } import v2.compiler.resolve { Namespace, ResolveContext, @@ -160,7 +161,10 @@ fn float_literal_resolve_ctx() -> ResolveContext { bindings: empty_map(), canonical_symbols: empty_canonical_symbol_set(), symbol_index: empty_symbol_index(), - module_qn: qualified_name_from_dotted_string(dotted: "m") + module_qn: qualified_name_from_dotted_string(dotted: "m"), + test_code: test_code_index_empty(), + declared_in: qualified_name_from_dotted_string(dotted: "m"), + imported_origins: empty_map() } ResolveContext { scope: scope_from_namespace(namespace: namespace), diff --git a/src/v2/test/claim/resolve/namespace_only_policy_test.dag b/src/v2/test/claim/resolve/namespace_only_policy_test.dag index 6c1d2ba7d3d..c130cd1496f 100644 --- a/src/v2/test/claim/resolve/namespace_only_policy_test.dag +++ b/src/v2/test/claim/resolve/namespace_only_policy_test.dag @@ -1,6 +1,7 @@ module v2.test.resolve.namespace_only_policy import std.occurrence_identity { OccurrenceSynthetic } +import v2.std.declaration_marker { test_code_index_empty } import v2.compiler.resolve { ResolveContext, Namespace, @@ -44,7 +45,10 @@ fn policy_pilot_namespace_with_index( bindings: empty_map(), canonical_symbols: empty_canonical_symbol_set(), symbol_index: symbol_index, - module_qn: module_qn + module_qn: module_qn, + test_code: test_code_index_empty(), + declared_in: module_qn, + imported_origins: empty_map() } } diff --git a/src/v2/test/claim/resolve/qualified_module_projection_resolve_test.dag b/src/v2/test/claim/resolve/qualified_module_projection_resolve_test.dag index f6d454294a9..93eb3b5c7d3 100644 --- a/src/v2/test/claim/resolve/qualified_module_projection_resolve_test.dag +++ b/src/v2/test/claim/resolve/qualified_module_projection_resolve_test.dag @@ -1,6 +1,7 @@ module v2.test.resolve.qualified_module_projection_resolve import std.occurrence_identity { OccurrenceSynthetic } +import v2.std.declaration_marker { test_code_index_empty } import v2.compiler.resolve { Namespace, ResolveContext, @@ -96,7 +97,10 @@ fn qmpr_namespace(index: SymbolIndex) -> Namespace { bindings: empty_map(), canonical_symbols: empty_canonical_symbol_set(), symbol_index: index, - module_qn: qmpr_consumer_qn + module_qn: qmpr_consumer_qn, + test_code: test_code_index_empty(), + declared_in: qmpr_consumer_qn, + imported_origins: empty_map() } } diff --git a/src/v2/workflow/floor_pure_producer_share.dag b/src/v2/workflow/floor_pure_producer_share.dag index 3883ecc0c05..b8e63b08661 100644 --- a/src/v2/workflow/floor_pure_producer_share.dag +++ b/src/v2/workflow/floor_pure_producer_share.dag @@ -496,6 +496,7 @@ import v2.std.collection { List } // v2.test.claim.namespace_xl0.qualified_site_enumerator_differential: the rows there name the two // site WALKS and share the one-module ingest the walks read, exactly as the sibling rows do. Both // values are Nodes; no closure. +// // AND THE FINAL ROW: // DAG CANONICAL-SYMBOL MAP EARNS ITS ROW ON THE ENROLMENT-MARGIN CPU THE EVAL-STEP GATE // CANNOT SEE. Sibling floor run 35340819603 (#11580 merging the resolve-cost head that