diff --git a/dag/gunbc/compiler_frontend_program_status.dag b/dag/gunbc/compiler_frontend_program_status.dag index 5c752035b9a..e75af908443 100644 --- a/dag/gunbc/compiler_frontend_program_status.dag +++ b/dag/gunbc/compiler_frontend_program_status.dag @@ -45,6 +45,9 @@ import v2.workflow.legacy_baseline_capture { legacy_baseline_capture_capability, capture_blocked_reason, } +import v2.workflow.legacy_baseline_persisted_observation { + persisted_legacy_baseline_outstanding, +} import gunbc.required_ci_phase_roster { RequiredCiPhase, NamespaceWaveAdmissionPhase, @@ -166,7 +169,6 @@ fn observe_outstanding(subject: NonEmptyStr, outstanding: List) -> Miles // milestone -- stages_awaiting joins it. type MissingInstrument = PhaseCargoExecutionFact - | PersistedLegacyBaselineObservation | DeclaringIdentitySpellingCensus | RepairInputOriginRosterProducer | ExactOccurrenceResidualCensus @@ -178,7 +180,6 @@ type MissingInstrument fn missing_instrument_label(i: MissingInstrument) -> String { match i { PhaseCargoExecutionFact => "a per-phase cargo-execution fact on gunbc.required_ci_phase_roster" - PersistedLegacyBaselineObservation => "an admitted CompleteLegacyObservation persisted against a named base" DeclaringIdentitySpellingCensus => "a census of occurrences not spelled at their declaring identity (XL-3's population)" RepairInputOriginRosterProducer => "a repair-input origin roster producer: source-declaration carriers plus rendered target-vocabulary carriers, separately typed, over one base, before eligibility or repair disposition (XL-0's population)" ExactOccurrenceResidualCensus => "the exact occurrence and import-declaration residual an XL-2 rehearsal produces (XL-5's population)" @@ -254,7 +255,6 @@ type InstrumentObstacle fn missing_instrument_obstacle(i: MissingInstrument) -> InstrumentObstacle { match i { PhaseCargoExecutionFact => NotBuilt - PersistedLegacyBaselineObservation => NotBuilt DeclaringIdentitySpellingCensus => NotBuilt RepairInputOriginRosterProducer => NotBuilt ExactOccurrenceResidualCensus => NotBuilt @@ -402,11 +402,10 @@ fn stage_subject_outstanding(stage: NamespaceCutStage) -> List { // THE BLOCKED ARM IS OUTSTANDING, NOT NOT-DERIVABLE, since F-0: the capability fold IS the // milestone's readable population while a capture cannot complete -- each blocked reason is a // named, observed piece of outstanding work, and reporting it unanswerable hid real known -// work behind the missing-instrument label. The AVAILABLE arm stays NotDerivable on purpose: -// v2.workflow.legacy_baseline_capture rules out a receipts roster in its own words (a plain -// row is not a relabel-safe durable form, and the question is re-asked per base), so once a -// capture CAN complete, whether one HAS completed against the CURRENT base has no population -// here until the persisted-observation instrument exists. +// work behind the missing-instrument label. The AVAILABLE arm reads the persist outstanding +// fold: v2.workflow.legacy_baseline_persisted_observation holds a capture by its own +// GitObjectId, never a receipts roster. Production pin stays PreCutBaseUnpinned until ACT-0 +// names B; the AVAILABLE arm is outstanding until then. That is not ACT-0's BaselineCaptureReceipt. // THE THREE DELETION MILESTONES, DERIVED FROM THE SUBJECT ROSTER SINCE F-0 -- at DECLARED-ROW // grain, stated at exactly that strength. gunbc.namespace_cut_subject_roster carries every // authority scheduled to disappear as string-identity probes (not authored citations, which @@ -484,10 +483,12 @@ fn milestone_status(m: ProgramMilestone) -> MilestoneStanding { ) ) CaptureAvailable => - NotDerivable { - why: "a capture can now complete, but no capture has been taken against the current pre-cut base. Any movement of that base invalidates a prior enrolment, so this is asked per base rather than accumulated -- and the capture module itself rules out a receipts roster as a relabel-unsafe durable form." as NonEmptyStr, - cause: needs(i: PersistedLegacyBaselineObservation) - } + standing_from_evidence( + e: observe_outstanding( + subject: "namespace Step 0.5 / XL-1: baseline capture against the current pre-cut base" as NonEmptyStr, + outstanding: persisted_legacy_baseline_outstanding() + ) + ) } NamespaceFirstSemanticWave => NotDerivable { @@ -720,7 +721,6 @@ fn join_names(names: List) -> String { // --------------------------------------------------------------------------------------------- data all_missing_instruments: List = [ PhaseCargoExecutionFact, - PersistedLegacyBaselineObservation, DeclaringIdentitySpellingCensus, RepairInputOriginRosterProducer, ExactOccurrenceResidualCensus, @@ -742,16 +742,10 @@ fn milestone_missing_instruments(m: ProgramMilestone) -> List } } -// AN INSTRUMENT CAN BE AWAITED CONDITIONALLY: PersistedLegacyBaselineObservation is the -// CaptureAvailable arm's contract on NamespaceBaselineObservationComplete, and while capture is -// BLOCKED that arm is not live, so the awaited-by join over live standings counts it zero. Zero -// here is not death -- deleting the row would delete the very contract the capability's -// transition lands on -- so the conditional citation is declared once, and the liveness witness -// admits exactly this roster's members beside the live join. A row in this list whose citing -// arm is deleted outright IS dead, and pruning it means editing both the arm and this row. -data conditionally_awaited_instruments: List = [ - PersistedLegacyBaselineObservation, -] +// Conditional await remains for instruments whose citing arm is not live on every standing. +// PersistedLegacyBaselineObservation retired: the persist producer exists and the baseline +// milestone reads its outstanding fold directly. +data conditionally_awaited_instruments: List = [] fn milestones_awaiting(i: MissingInstrument) -> List { fold(program_milestones, init: [], f: fn(acc, m) { diff --git a/dag/gunbc/namespace/emit_rust_reference_derived_rows_bridge_seed_growth.dag b/dag/gunbc/namespace/emit_rust_reference_derived_rows_bridge_seed_growth.dag new file mode 100644 index 00000000000..99f1e71f312 --- /dev/null +++ b/dag/gunbc/namespace/emit_rust_reference_derived_rows_bridge_seed_growth.dag @@ -0,0 +1,55 @@ +module gunbc.emit_rust_reference_derived_rows_bridge_seed_growth + +import std.decl_ref { DeclarationRef, WholeDeclaration } +import std.types { String } +import gunbc.roadmap_model { RoadmapNodeId } +import gunbc.seed_growth { SeedGrowthJustification } + +data emit_rust_reference_derived_rows_bridge_seed_growth_justification: SeedGrowthJustification = SeedGrowthJustification { + hand_authored_declarations: [ + DeclarationRef { + module_path: "v1_compiler.cli_run.emit_host", + decl_name: "Xl1PrimaryRootTap", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_compiler.cli_run.emit_host", + decl_name: "compile_xl1_primary_root_tap", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_compiler.cli_run.emit_host", + decl_name: "ObservedOccurrenceBindingHalves", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_compiler.cli_run.emit_host", + decl_name: "observed_occurrence_transport_and_bindings", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_interpreter", + decl_name: "reference_derived_candidate_rows_value", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_interpreter", + decl_name: "reference_derived_candidate_disposition_value", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_interpreter", + decl_name: "occurrence_transport_value", + field: WholeDeclaration + }, + DeclarationRef { + module_path: "v1_interpreter", + decl_name: "xl1_primary_root_tap_value", + field: WholeDeclaration + } + ], + reason: "WHY A HOST BRIDGE RATHER THAN A .dag CONSUMER CALLING THE PRODUCER DIRECTLY. The rows are produced by v1.compiler.emit_rust emit_rust_reference_derived_rows over a ResolvedGraph. The required floor and every dag/src/v2 workflow resolve --source-root dag --source-root src/v2 only. Measured: no module under those roots imports a v1 module, so a consumer there cannot name that function. Adding --source-root src/v1 lets the spelling resolve; calling it from the interpreter still needs a ResolvedGraph, and compile_to_resolved over an authored source vector hits the Node.ident wall (no default for an omitted optional field).\n\nWHY PRIMARYROOT, MEASURED. gunbc run / claim_executor compile_to_resolved only the entry's reference-derived closure (resolve_entry_with_index). The one existing path that compile_to_resolved every indexed module under a root is gunbc compile without --entry (CompileSubject::PrimaryRoot). That transaction emits bytes and never called this arm. compile_dag_reference_occurrence_binding_census compiles a caller-supplied (paths, contents) vector and does not encode OccurrenceTransport (no containment, declarations, or index entries), so ValidatedOccurrenceTransport cannot mint from it. This widening keeps ONE arm and ONE encoding: PrimaryRoot(source_roots[0]) with the rest as pool, then encode repair rows AND the seed-observed OccurrenceTransport (per-module sidecars concatenated as stored; never reconstructed on the v2 side). Binding rows over that same transport travel in the same encoding. If occurrence_transport_validate cannot mint, capture refuses LegacyBaselineObservedTransportRefused rather than fabricating containment.\n\nWHY IT IS ADMITTED AGAINST THE v1 FREEZE: gunbc.v1_maintenance_standing v1_seed_standing admits by PURPOSE (fierce-lark-661, PrimaryRoot widening 2026-09-12). The v1 oracle is the differential referent for the XL-6 qualification sweep. HAND-ITEM DELTA is the identities in hand_authored_declarations: the emit_host host (Xl1PrimaryRootTap, compile_xl1_primary_root_tap) plus the ObservedOccurrenceBindingHalves extraction that compile_dag_reference_occurrence_binding_census now shares, plus the four v1_interpreter encoders. The dispatch arm is ExistingSeedItemModified inside eval_builtin_inner. v1_interpreter_dispatch_generated.rs is generated from gunbc.v1_interpreter_primitive_surface.", + owning_dissolution_lane: "v1-interpreter-delete" as RoadmapNodeId, + trigger: "Delete this arm with v1.compiler.emit_rust and the interpreter. A producer existing is not the dissolve; the arm is listed in that deletion population from the day it lands.", + current_boundary: "src/v1/stage0/src/cli_run/emit_host.rs compile_xl1_primary_root_tap (Xl1PrimaryRootTap, ObservedOccurrenceBindingHalves, observed_occurrence_transport_and_bindings); src/v1/stage0/src/v1_interpreter.rs free_call.emit_rust_reference_derived_rows_bridge arm and its encoders (repair rows, seed-observed OccurrenceTransport, binding rows over that transport); dag/gunbc/v1/v1_interpreter_primitive_surface.dag roster row; src/v1/04_method.dag builtin signature; dag/std/primitives.dag spelling roster; sole consumer v2.workflow.legacy_repair_tap persist_named_base_from_primary_root_tap" +} diff --git a/dag/gunbc/namespace/namespace_cut_stage.dag b/dag/gunbc/namespace/namespace_cut_stage.dag index c6ae5212fb3..14c1a7133e5 100644 --- a/dag/gunbc/namespace/namespace_cut_stage.dag +++ b/dag/gunbc/namespace/namespace_cut_stage.dag @@ -41,7 +41,7 @@ fn namespace_cut_stage_label(s: NamespaceCutStage) -> NonEmptyStr { match s { StageF0 => "F-0: truthful namespace control plane -- stage chain, subject roster, derived wave-wall enrolment" as NonEmptyStr StageXL0Denominator => "XL-0: repair-input origin denominator -- source-declaration carriers plus rendered target-vocabulary carriers, separately typed, over one base, before eligibility or repair disposition" as NonEmptyStr - StageXL1BaselineCapture => "XL-1: complete baseline capture -- what the legacy resolver actually selected over one exact base, persisted before anything is deleted" as NonEmptyStr + StageXL1BaselineCapture => "XL-1: capture capability -- the capture transaction can mint a joint binding+repair observation over one exact base; persistence against a named base is the baseline milestone, not this stage" as NonEmptyStr StageXL2RootDeletionRehearsal => "XL-2: root-deletion rehearsal -- the cut executed in a throwaway tree, its failure roster captured as the census" as NonEmptyStr StageXL3DeclaringIdentitySpelling => "XL-3: declaring-identity spelling -- every reference spelled as the fully qualified declaring identity" as NonEmptyStr StageXL4ReferenceDerivedGraph => "XL-4: reference-derived graph -- dependency edges derived from resolved reference targets, never declared" as NonEmptyStr diff --git a/dag/gunbc/namespace/reference_derived_candidate.dag b/dag/gunbc/namespace/reference_derived_candidate.dag new file mode 100644 index 00000000000..bd3f3e5eb0e --- /dev/null +++ b/dag/gunbc/namespace/reference_derived_candidate.dag @@ -0,0 +1,22 @@ +module gunbc.reference_derived_candidate + +import std.types { String } + +// THE EMIT-RUST REFERENCE-DERIVED CANDIDATE, ONE HOME. v1.compiler.emit_rust produces rows of this +// shape; v2.workflow.legacy_repair_tap consumes the same types through the host bridge. Reachability +// of ResolvedGraph explains the bridge, not a second copy of the coproduct (review 64840). + +type ReferenceDerivedCandidateDisposition + = CandidateSurvived { provider_module: String } + | CandidateOwnModule + | CandidateVariantDelegatedToParent { parent_enum: String } + | CandidateVariantParentUnresolved + | CandidateRegistryAbsent + | CandidateLeafAmbiguous + | CandidateExportProofFailed { provider_module: String } + +type ReferenceDerivedCandidateRow { + module_name: String + name: String + disposition: ReferenceDerivedCandidateDisposition +} diff --git a/dag/gunbc/seed_growth_admission.dag b/dag/gunbc/seed_growth_admission.dag index 6233be7fa84..051a86e9b39 100644 --- a/dag/gunbc/seed_growth_admission.dag +++ b/dag/gunbc/seed_growth_admission.dag @@ -17,6 +17,7 @@ import gunbc.declaration_lookup_index_seed_growth { declaration_lookup_index_see import gunbc.emitted_closure_compile_seed_growth { emitted_closure_compile_seed_growth_justification } import gunbc.evaluation_budget_falsifier_seed_growth { evaluation_budget_falsifier_seed_growth_justification } import gunbc.namespace_structural_observation_bridge_seed_growth { namespace_structural_observation_bridge_seed_growth_justification } +import gunbc.emit_rust_reference_derived_rows_bridge_seed_growth { emit_rust_reference_derived_rows_bridge_seed_growth_justification } import gunbc.parsed_import_statement_bridge_seed_growth { parsed_import_statement_bridge_seed_growth_justification } import gunbc.namespace_wave_admission { namespace_wave_admission_seed_growth_justification } import gunbc.parse_refusal_location_seed_growth { parse_refusal_location_seed_growth_justification } @@ -244,6 +245,7 @@ fn seed_growth_justification_roster() -> List { emitted_closure_compile_seed_growth_justification, evaluation_budget_falsifier_seed_growth_justification, namespace_structural_observation_bridge_seed_growth_justification, + emit_rust_reference_derived_rows_bridge_seed_growth_justification, parsed_import_statement_bridge_seed_growth_justification, namespace_wave_admission_seed_growth_justification, qualified_pipe_callee_seed_growth_justification, diff --git a/dag/gunbc/v1/v1_interpreter_primitive_surface.dag b/dag/gunbc/v1/v1_interpreter_primitive_surface.dag index 3d252c3ec0f..e574c902f8e 100644 --- a/dag/gunbc/v1/v1_interpreter_primitive_surface.dag +++ b/dag/gunbc/v1/v1_interpreter_primitive_surface.dag @@ -1195,6 +1195,15 @@ fn v1_interpreter_authored_roster_arms() -> List List { "compile_dag_rust_emit_check", "parsed_import_statements", "namespace_structural_observation_admissions", + "emit_rust_reference_derived_rows_bridge", "witness_layer_roots_compile_clean_check", "witness_layer_roots_compile_clean_emit_check", "install_or_consume_floor_compile_clean_gate_receipt", diff --git a/dag/test/claim/compiler_frontend_program_status_witness_test.dag b/dag/test/claim/compiler_frontend_program_status_witness_test.dag index 1e2eb0fcf06..f4470696701 100644 --- a/dag/test/claim/compiler_frontend_program_status_witness_test.dag +++ b/dag/test/claim/compiler_frontend_program_status_witness_test.dag @@ -72,6 +72,9 @@ import v2.workflow.legacy_baseline_capture { legacy_baseline_capture_capability, capture_blocked_reason, } +import v2.workflow.legacy_baseline_persisted_observation { + persisted_legacy_baseline_outstanding, +} import v2.compiler.self_host.stage0_crate_layout { emitter_produced_divergent_registrations } import gunbc.compiler_frontend_program_status { milestone_missing_instruments, @@ -586,9 +589,8 @@ test fn xl0_is_not_derivable_and_awaits_the_repair_input_origin_producer() -> Bo // THE SAME QUESTION. XL-1 used to delegate to NamespaceBaselineObservationComplete outright, which // made "the capture transaction can succeed" and "a capture has been taken against THIS base" one // row. They separate exactly on the CaptureAvailable arm: the stage clears (its deliverable is the -// capability) while the milestone becomes NOT-DERIVABLE (no persisted observation against the -// current base). This arm asserts the contract on whichever arm is live, so it does not red when -// the capability legitimately becomes available -- it reds if the two are re-fused. +// capability) while the milestone reads persisted_legacy_baseline_outstanding (production pin +// unpinned until ACT-0 names a base). This arm asserts the contract on whichever arm is live. test fn xl1_follows_the_capability_while_the_baseline_milestone_follows_the_base() -> Bool { match legacy_baseline_capture_capability() { CaptureBlocked { phase: p, cause: c } => @@ -597,7 +599,9 @@ test fn xl1_follows_the_capability_while_the_baseline_milestone_follows_the_base expected: capture_blocked_reason(c: CaptureBlocked { phase: p, cause: c })) CaptureAvailable => standing_is(want: ClassClear, s: stage_status(s: StageXL1BaselineCapture)) - && standing_is(want: ClassNotDerivable, s: milestone_status(m: NamespaceBaselineObservationComplete)) + && standing_agrees_with_population( + s: milestone_status(m: NamespaceBaselineObservationComplete), + expected: persisted_legacy_baseline_outstanding()) } } @@ -655,9 +659,8 @@ test fn the_wave_admission_milestone_is_wired_to_the_phase_roster() -> Bool { } // THE BASELINE MILESTONE'S TWO ARMS, CHECKED WITHOUT PINNING TODAY'S CAPABILITY. While capture is -// blocked the milestone must carry exactly the capability fold's reasons; when capture becomes -// available the contract is the NotDerivable arm, and this witness accepts it rather than redding -// on that legitimate transition (the backward contract this file has been corrected for twice). +// blocked the milestone must carry exactly the capability fold's reasons; when capture is available +// it must carry the persist outstanding fold. test fn the_baseline_milestone_follows_the_capture_capability() -> Bool { match legacy_baseline_capture_capability() { CaptureBlocked { phase: p, cause: c } => @@ -665,7 +668,9 @@ test fn the_baseline_milestone_follows_the_capture_capability() -> Bool { s: milestone_status(m: NamespaceBaselineObservationComplete), expected: capture_blocked_reason(c: CaptureBlocked { phase: p, cause: c })) CaptureAvailable => - standing_is(want: ClassNotDerivable, s: milestone_status(m: NamespaceBaselineObservationComplete)) + standing_agrees_with_population( + s: milestone_status(m: NamespaceBaselineObservationComplete), + expected: persisted_legacy_baseline_outstanding()) } } diff --git a/dag/test/claim/legacy_baseline_capture_witness_test.dag b/dag/test/claim/legacy_baseline_capture_witness_test.dag index c65a142d3bf..67730175df2 100644 --- a/dag/test/claim/legacy_baseline_capture_witness_test.dag +++ b/dag/test/claim/legacy_baseline_capture_witness_test.dag @@ -1,8 +1,8 @@ module test.claim.legacy_baseline_capture_witness -import std.types { String, Bool, Int, List, SourceSpan } +import std.types { String, Bool, Int, List, SourceSpan, NonEmptyStr } import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } -import std.content_hash { Fnv1a64Structural, structural_content_hash } +import std.content_hash { structural_content_hash } import std.decl_ref { decl_ref } import extdeps.git.object_store { GitObjectId, git_sha1_object_id } import std.occurrence_identity { @@ -15,11 +15,20 @@ import std.occurrence_identity { DeclarationOccurrence, ReferenceOccurrence, OccurrenceTransport, - ValidatedOccurrenceTransport, + OccurrenceTransportValidation, OccurrenceTransportValidated, OccurrenceTransportRefused, occurrence_transport_validate } +import v2.workflow.legacy_repair_observation { + RepairSite, + RepairSiteRoster, + LegacyRepairObservation, + LegacyRepairObservationRow, + LegacyRepairObservationSubject, + repair_site_roster_identity, + repair_subject_field_label +} import v2.workflow.legacy_binding_observation { LegacyBindingObservation, LegacyBindingObservationRow, @@ -27,9 +36,7 @@ import v2.workflow.legacy_binding_observation { ImportScopedPolicy } import v2.workflow.legacy_baseline_capture { - CheckoutMaterialization, materialization_receipt, - TreeDerivedSubjectReceipt, tree_derived_subject, capture_legacy_baseline, LegacyBaselineCaptured, @@ -37,14 +44,18 @@ import v2.workflow.legacy_baseline_capture { LegacyBaselineWorktreeMismatch, LegacyBaselineSubjectMismatch, LegacyBaselineObservationIncomplete, + LegacyBaselineRepairIncomplete, + LegacyBaselineRepairRosterMismatch, + LegacyBaselineRepairRosterMalformed, + LegacyBaselineRepairSubjectDiverged, LegacyBaselineExecutionRefused, + LegacyBaselineObservedTransportRefused, subject_field_label, - RepairCensusPhase, - RepairObservationEnvelopeAbsent, legacy_baseline_capture_capability, CaptureBlocked, CaptureAvailable } +import v2.workflow.legacy_repair_observation { repair_subject_field_label } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly @@ -90,6 +101,36 @@ fn lbc_subject(source_set: String, artifact: String) -> LegacyBindingObservation } } +fn lbc_repair_site() -> RepairSite { + RepairSite { module_name: "std.logic" as NonEmptyStr, name: "Bool" as NonEmptyStr } +} + +fn lbc_repair_roster() -> RepairSiteRoster { + RepairSiteRoster { sites: [lbc_repair_site()] } +} + +fn lbc_repair_subject(source_set: String, artifact: String) -> LegacyRepairObservationSubject { + LegacyRepairObservationSubject { + semantic_source_digest: structural_content_hash(digest: "1111111111111111"), + source_set_digest: structural_content_hash(digest: source_set), + compiler_artifact_digest: structural_content_hash(digest: artifact), + repairer_identity: decl_ref(module_path: "v1.compiler.emit_rust", decl_name: "reference_derived_census"), + repair_site_roster_digest: repair_site_roster_identity(roster: lbc_repair_roster()), + resolution_registry_digest: structural_content_hash(digest: "5555555555555555") + } +} + +type LbcRepairOutcome + = LbcRepairDeclined + | LbcRepairApplied + +fn lbc_repair_observation(sites: List, source_set: String, artifact: String) -> LegacyRepairObservation { + LegacyRepairObservation { + subject: lbc_repair_subject(source_set: source_set, artifact: artifact), + rows: sites |> map(s => LegacyRepairObservationRow { site: s, outcome: LbcRepairDeclined }) + } +} + fn lbc_observation(subject: LegacyBindingObservationSubject, ids: List) -> LegacyBindingObservation { LegacyBindingObservation { subject: subject, @@ -148,7 +189,11 @@ fn lbc_run( expected_artifact: String, observed_artifact: String, rows: List, - expected_refs: List + expected_refs: List, + repair_sites: List, + repair_roster: RepairSiteRoster, + repair_source_set: String, + repair_artifact: String ) -> LbcOutcome { match lbc_oid(hex: requested) { Absent => LbcFixtureRefused @@ -178,14 +223,25 @@ fn lbc_run( subject: lbc_subject(source_set: observed_source_set, artifact: observed_artifact), ids: rows ), - transport: t + transport: t, + repair_observation: lbc_repair_observation( + sites: repair_sites, + source_set: repair_source_set, + artifact: repair_artifact + ), + repair_roster: repair_roster ) { LegacyBaselineCaptured { capture: _ } => "captured" LegacyBaselineHeadMismatch { requested: _, materialized: _ } => "head-mismatch" LegacyBaselineWorktreeMismatch { commit_tree: _, observed_tree: _ } => "worktree-mismatch" LegacyBaselineSubjectMismatch { field: f } => concat("subject-mismatch:", subject_field_label(f: f) as String) LegacyBaselineObservationIncomplete { completeness: _ } => "observation-incomplete" + LegacyBaselineRepairRosterMalformed { sites: _ } => "repair-roster-malformed" + LegacyBaselineRepairRosterMismatch { subject_digest: _, roster_digest: _ } => "repair-roster-mismatch" + LegacyBaselineRepairSubjectDiverged { field: f } => concat("repair-subject-diverged:", repair_subject_field_label(f: f) as String) + LegacyBaselineRepairIncomplete { completeness: _ } => "repair-incomplete" LegacyBaselineExecutionRefused { phase: _, cause: _ } => "execution-refused" + LegacyBaselineObservedTransportRefused { refusal: _ } => "observed-transport-refused" } } } @@ -206,7 +262,10 @@ test fn a_materialized_head_that_is_not_the_requested_commit_refuses_first() -> subject_tree: lbc_tree_b(), expected_source_set: "2222222222222222", observed_source_set: "7777777777777777", expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", - rows: [10], expected_refs: [10] + rows: [10], expected_refs: [10], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" ) { LbcFixtureRefused => false LbcComputed { verdict: v } => v == "head-mismatch" @@ -222,7 +281,10 @@ test fn a_dirty_worktree_refuses_before_the_subject_is_compared() -> Bool { subject_tree: lbc_tree_b(), expected_source_set: "2222222222222222", observed_source_set: "7777777777777777", expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", - rows: [10], expected_refs: [10] + rows: [10], expected_refs: [10], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" ) { LbcFixtureRefused => false LbcComputed { verdict: v } => v == "worktree-mismatch" @@ -237,7 +299,10 @@ test fn an_observation_of_a_different_source_set_refuses_as_subject_mismatch() - subject_tree: lbc_tree_a(), expected_source_set: "2222222222222222", observed_source_set: "7777777777777777", expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", - rows: [10], expected_refs: [10] + rows: [10], expected_refs: [10], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" ) { LbcFixtureRefused => false LbcComputed { verdict: v } => v == "subject-mismatch:source_set_digest" @@ -253,7 +318,10 @@ test fn an_observation_from_a_different_compiler_artifact_refuses_as_subject_mis subject_tree: lbc_tree_a(), expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", expected_artifact: "3333333333333333", observed_artifact: "8888888888888888", - rows: [10], expected_refs: [10] + rows: [10], expected_refs: [10], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" ) { LbcFixtureRefused => false LbcComputed { verdict: v } => v == "subject-mismatch:compiler_artifact_digest" @@ -270,36 +338,125 @@ test fn an_observation_missing_an_expected_occurrence_refuses_as_incomplete() -> subject_tree: lbc_tree_a(), expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", - rows: [10], expected_refs: [10, 11] + rows: [10], expected_refs: [10, 11], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" ) { LbcFixtureRefused => false LbcComputed { verdict: v } => v == "observation-incomplete" } } -// EVERY GATE PASSING STILL DOES NOT PRODUCE A BASELINE, and that is the declared hole rather than a -// defect: the repair observation has no admission envelope, so the accepted arm is unreachable. An -// empty captured baseline here would be the fabricated output the whole shape exists to refuse. -test fn a_fully_agreeing_capture_still_refuses_because_the_repair_envelope_is_absent() -> Bool { +// EVERY GATE PASSING MINTS A BASELINE: binding complete and repair roster answered exactly. +test fn a_fully_agreeing_capture_mints_the_baseline() -> Bool { + match lbc_run( + requested: lbc_commit_a(), observed_head: lbc_commit_a(), + commit_tree: lbc_tree_a(), observed_tree: lbc_tree_a(), + subject_tree: lbc_tree_a(), + expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", + expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", + rows: [10, 11], expected_refs: [10, 11], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" + ) { + LbcFixtureRefused => false + LbcComputed { verdict: v } => v == "captured" + } +} + +test fn a_repair_observation_missing_a_roster_site_refuses_as_repair_incomplete() -> Bool { + match lbc_run( + requested: lbc_commit_a(), observed_head: lbc_commit_a(), + commit_tree: lbc_tree_a(), observed_tree: lbc_tree_a(), + subject_tree: lbc_tree_a(), + expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", + expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", + rows: [10, 11], expected_refs: [10, 11], + repair_sites: [], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" + ) { + LbcFixtureRefused => false + LbcComputed { verdict: v } => v == "repair-incomplete" + } +} + +test fn a_repair_observation_of_a_different_source_set_refuses_as_repair_subject_diverged() -> Bool { + match lbc_run( + requested: lbc_commit_a(), observed_head: lbc_commit_a(), + commit_tree: lbc_tree_a(), observed_tree: lbc_tree_a(), + subject_tree: lbc_tree_a(), + expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", + expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", + rows: [10, 11], expected_refs: [10, 11], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "9999999999999999", repair_artifact: "3333333333333333" + ) { + LbcFixtureRefused => false + LbcComputed { verdict: v } => v == "repair-subject-diverged:source_set_digest" + } +} + +test fn a_repair_observation_from_a_different_compiler_artifact_refuses_as_repair_subject_diverged() -> Bool { + match lbc_run( + requested: lbc_commit_a(), observed_head: lbc_commit_a(), + commit_tree: lbc_tree_a(), observed_tree: lbc_tree_a(), + subject_tree: lbc_tree_a(), + expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", + expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", + rows: [10, 11], expected_refs: [10, 11], + repair_sites: [lbc_repair_site()], + repair_roster: lbc_repair_roster(), + repair_source_set: "2222222222222222", repair_artifact: "9999999999999999" + ) { + LbcFixtureRefused => false + LbcComputed { verdict: v } => v == "repair-subject-diverged:compiler_artifact_digest" + } +} + +test fn a_roster_that_names_one_site_twice_refuses_as_repair_roster_malformed() -> Bool { + match lbc_run( + requested: lbc_commit_a(), observed_head: lbc_commit_a(), + commit_tree: lbc_tree_a(), observed_tree: lbc_tree_a(), + subject_tree: lbc_tree_a(), + expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", + expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", + rows: [10, 11], expected_refs: [10, 11], + repair_sites: [lbc_repair_site()], + repair_roster: RepairSiteRoster { sites: [lbc_repair_site(), lbc_repair_site()] }, + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" + ) { + LbcFixtureRefused => false + LbcComputed { verdict: v } => v == "repair-roster-malformed" + } +} + +test fn a_roster_whose_identity_is_not_the_subject_digest_refuses_as_repair_roster_mismatch() -> Bool { match lbc_run( requested: lbc_commit_a(), observed_head: lbc_commit_a(), commit_tree: lbc_tree_a(), observed_tree: lbc_tree_a(), subject_tree: lbc_tree_a(), expected_source_set: "2222222222222222", observed_source_set: "2222222222222222", expected_artifact: "3333333333333333", observed_artifact: "3333333333333333", - rows: [10, 11], expected_refs: [10, 11] + rows: [10, 11], expected_refs: [10, 11], + repair_sites: [lbc_repair_site()], + repair_roster: RepairSiteRoster { + sites: [RepairSite { module_name: "std.types" as NonEmptyStr, name: "Int" as NonEmptyStr }] + }, + repair_source_set: "2222222222222222", repair_artifact: "3333333333333333" ) { LbcFixtureRefused => false - LbcComputed { verdict: v } => v == "execution-refused" + LbcComputed { verdict: v } => v == "repair-roster-mismatch" } } -// The capability a consumer reads agrees with what the operation actually does. Two readings of one -// fact that could drift apart, so they are joined here rather than each asserted alone. -test fn the_reported_capability_is_blocked_at_the_repair_census() -> Bool { +test fn the_reported_capability_is_available_once_the_named_base_tap_entry_exists() -> Bool { match legacy_baseline_capture_capability() { - CaptureAvailable => false - CaptureBlocked { phase: _, cause: _ } => true + CaptureAvailable => true + CaptureBlocked { phase: _, cause: _ } => false } } diff --git a/dag/test/claim/legacy_baseline_persisted_observation_witness_test.dag b/dag/test/claim/legacy_baseline_persisted_observation_witness_test.dag new file mode 100644 index 00000000000..d4787746686 --- /dev/null +++ b/dag/test/claim/legacy_baseline_persisted_observation_witness_test.dag @@ -0,0 +1,231 @@ +module test.claim.legacy_baseline_persisted_observation_witness + +import std.types { String, Bool, List, NonEmptyStr, SourceSpan } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } +import std.content_hash { structural_content_hash } +import std.decl_ref { decl_ref } +import extdeps.git.object_store { git_sha1_object_id } +import std.occurrence_identity { + OccurrenceId, + OccurrenceIndex, + OccurrenceIndexEntry, + OccurrenceProjection, + OccurrenceContainmentPath, + LexicalValueOccurrence, + DeclarationOccurrence, + ReferenceOccurrence, + OccurrenceTransport, + OccurrenceTransportValidated, + OccurrenceTransportRefused, + occurrence_transport_validate +} +import v2.workflow.legacy_binding_observation { + LegacyBindingObservation, + LegacyBindingObservationRow, + LegacyBindingObservationSubject, + ImportScopedPolicy +} +import v2.workflow.legacy_repair_observation { + RepairSite, + RepairSiteRoster, + LegacyRepairObservation, + LegacyRepairObservationRow, + LegacyRepairObservationSubject, + repair_site_roster_identity +} +import v2.workflow.legacy_baseline_capture { + materialization_receipt, + tree_derived_subject, + capture_legacy_baseline, + LegacyBaselineCaptured, + LegacyBaselineHeadMismatch, + LegacyBaselineWorktreeMismatch, + LegacyBaselineSubjectMismatch, + LegacyBaselineObservationIncomplete, + LegacyBaselineRepairRosterMalformed, + LegacyBaselineRepairRosterMismatch, + LegacyBaselineRepairSubjectDiverged, + LegacyBaselineRepairIncomplete, + LegacyBaselineExecutionRefused, + LegacyBaselineObservedTransportRefused +} +import v2.workflow.legacy_baseline_persisted_observation { + persist_legacy_baseline, + PersistAdmitted, + PersistRefusedNotCaptured, + persisted_against_requested, + persisted_enrollment_outstanding, + persisted_legacy_baseline_outstanding, + PreCutBaseUnpinned, + PreCutBasePinned, + current_pre_cut_base_pin +} + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +type LbpBinding + = LbpBound + | LbpUnbound + +type LbpRepair + = LbpDeclined + | LbpApplied + +fn lbp_span() -> SourceSpan { + SourceSpan { file: "legacy-baseline-persist-fixture.dag", start: 1, end: 2 } +} + +fn lbp_path() -> OccurrenceContainmentPath { + OccurrenceContainmentPath { ancestors: [OccurrenceId { value: 900 }], terminal: OccurrenceId { value: 10 } } +} + +fn lbp_commit_a() -> String { "1007efb256a20749f77c3b1295eed144fddeb9fd" } +fn lbp_commit_b() -> String { "531308acfd891b399709711a8c03955aa7bbafca" } +fn lbp_tree() -> String { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" } + +fn lbp_site() -> RepairSite { + RepairSite { module_name: "std.logic" as NonEmptyStr, name: "Bool" as NonEmptyStr } +} + +fn lbp_roster() -> RepairSiteRoster { + RepairSiteRoster { sites: [lbp_site()] } +} + +fn lbp_subject() -> LegacyBindingObservationSubject { + LegacyBindingObservationSubject { + semantic_source_digest: structural_content_hash(digest: "1111111111111111"), + source_set_digest: structural_content_hash(digest: "2222222222222222"), + compiler_artifact_digest: structural_content_hash(digest: "3333333333333333"), + resolver_identity: decl_ref(module_path: "v1.compiler.infer_env", decl_name: "lookup_binding_by_name"), + resolver_policy: ImportScopedPolicy, + occurrence_transport_digest: structural_content_hash(digest: "4444444444444444"), + declaration_index_digest: structural_content_hash(digest: "5555555555555555") + } +} + +test fn persist_refuses_a_capture_that_never_minted() -> Bool { + match git_sha1_object_id(hex: lbp_commit_a()) { + Absent => false + Present { value: a } => match git_sha1_object_id(hex: lbp_commit_b()) { + Absent => false + Present { value: b } => + match persist_legacy_baseline( + outcome: LegacyBaselineHeadMismatch { requested: a, materialized: b } + ) { + PersistRefusedNotCaptured => true + PersistAdmitted { persisted: _ } => false + } + } + } +} + +fn lbp_minted_capture_persisted() -> Bool { + match git_sha1_object_id(hex: lbp_commit_a()) { + Absent => false + Present { value: a } => match git_sha1_object_id(hex: lbp_tree()) { + Absent => false + Present { value: t } => + match occurrence_transport_validate(transport: OccurrenceTransport { + index: OccurrenceIndex { entries: [ + OccurrenceIndexEntry { + projection: OccurrenceProjection { + occurrence: OccurrenceId { value: 900 }, + authored_name: "root", + diagnostic_span: lbp_span() + }, + containment: OccurrenceContainmentPath { ancestors: [], terminal: OccurrenceId { value: 900 } } + }, + OccurrenceIndexEntry { + projection: OccurrenceProjection { + occurrence: OccurrenceId { value: 10 }, + authored_name: "r", + diagnostic_span: lbp_span() + }, + containment: lbp_path() + } + ] }, + declarations: [DeclarationOccurrence { + occurrence: OccurrenceId { value: 900 }, + containment: OccurrenceContainmentPath { ancestors: [], terminal: OccurrenceId { value: 900 } }, + category: LexicalValueOccurrence, + diagnostic_span: lbp_span() + }], + references: [ReferenceOccurrence { + occurrence: OccurrenceId { value: 10 }, + containment: lbp_path(), + category: LexicalValueOccurrence, + diagnostic_span: lbp_span() + }] + }) { + OccurrenceTransportRefused { refusal: _ } => false + OccurrenceTransportValidated { transport: tr } => + match capture_legacy_baseline( + materialization: materialization_receipt( + requested: a, observed_head: a, observed_tree: t, commit_tree: t + ), + tree_subject: tree_derived_subject(tree: t, subject: lbp_subject()), + observation: LegacyBindingObservation { + subject: lbp_subject(), + rows: [LegacyBindingObservationRow { occurrence: OccurrenceId { value: 10 }, outcome: LbpBound }] + }, + transport: tr, + repair_observation: LegacyRepairObservation { + subject: LegacyRepairObservationSubject { + semantic_source_digest: structural_content_hash(digest: "1111111111111111"), + source_set_digest: structural_content_hash(digest: "2222222222222222"), + compiler_artifact_digest: structural_content_hash(digest: "3333333333333333"), + repairer_identity: decl_ref(module_path: "v1.compiler.emit_rust", decl_name: "reference_derived_census"), + repair_site_roster_digest: repair_site_roster_identity(roster: lbp_roster()), + resolution_registry_digest: structural_content_hash(digest: "5555555555555555") + }, + rows: [LegacyRepairObservationRow { site: lbp_site(), outcome: LbpDeclined }] + }, + repair_roster: lbp_roster() + ) { + LegacyBaselineCaptured { capture: c } => + match persist_legacy_baseline(outcome: LegacyBaselineCaptured { capture: c }) { + PersistRefusedNotCaptured => false + PersistAdmitted { persisted: p } => + persisted_against_requested(persisted: p, requested: a) + && match git_sha1_object_id(hex: lbp_commit_b()) { + Absent => false + Present { value: b } => + !persisted_against_requested(persisted: p, requested: b) + && (persisted_enrollment_outstanding(pin: PreCutBasePinned { base: a }, held: Present { value: p }) |> count) == 0 + && (persisted_enrollment_outstanding(pin: PreCutBasePinned { base: b }, held: Present { value: p }) |> count) == 1 + } + } + LegacyBaselineHeadMismatch { requested: _, materialized: _ } => false + LegacyBaselineWorktreeMismatch { commit_tree: _, observed_tree: _ } => false + LegacyBaselineSubjectMismatch { field: _ } => false + LegacyBaselineObservationIncomplete { completeness: _ } => false + LegacyBaselineRepairRosterMalformed { sites: _ } => false + LegacyBaselineRepairRosterMismatch { subject_digest: _, roster_digest: _ } => false + LegacyBaselineRepairSubjectDiverged { field: _ } => false + LegacyBaselineRepairIncomplete { completeness: _ } => false + LegacyBaselineExecutionRefused { phase: _, cause: _ } => false + LegacyBaselineObservedTransportRefused { refusal: _ } => false + } + } + } + } +} + +test fn persist_binds_only_to_the_capture_base_commit() -> Bool { + lbp_minted_capture_persisted() +} + +test fn live_outstanding_is_the_enrollment_fold_with_unpinned_production_pin() -> Bool { + match current_pre_cut_base_pin() { + PreCutBasePinned { base: _ } => false + PreCutBaseUnpinned => + let live = persisted_legacy_baseline_outstanding() + let via = persisted_enrollment_outstanding( + pin: PreCutBaseUnpinned, + held: none + ) + (live |> count) == 1 + && (via |> count) == 1 + && all(live, s => any(via, t => s == t)) + } +} diff --git a/dag/test/claim/legacy_repair_observation_witness_test.dag b/dag/test/claim/legacy_repair_observation_witness_test.dag index d89abcf3be8..d3f1c9a2e05 100644 --- a/dag/test/claim/legacy_repair_observation_witness_test.dag +++ b/dag/test/claim/legacy_repair_observation_witness_test.dag @@ -37,7 +37,16 @@ import v2.workflow.legacy_repair_observation { repair_site_roster_identity, legacy_repair_subject_applicability, legacy_repair_completeness, - admit_complete_repair_observation + admit_complete_repair_observation, + repair_subject_field_label, + RepairSemanticSourceDigestField, + RepairSourceSetDigestField, + RepairCompilerArtifactDigestField, + RepairerIdentityModulePathField, + RepairerIdentityDeclNameField, + RepairerIdentityFieldField, + RepairSiteRosterDigestField, + ResolutionRegistryDigestField } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly @@ -261,7 +270,8 @@ test fn an_observation_taken_on_another_base_refuses_against_a_proven_roster() - ), proven: p ) { - RepairObservationSubjectDiverged { field: f } => f == "semantic_source_digest" + RepairObservationSubjectDiverged { field: f } => + f == RepairSemanticSourceDigestField RepairObservationAdmitted { admitted: _ } => false RepairObservationRefused { completeness: _ } => false } @@ -328,7 +338,7 @@ test fn a_site_equals_itself() -> Bool { // against. fn lro_diverged_field(other: LegacyRepairObservationSubject) -> String { match legacy_repair_subject_applicability(left: lro_base_subject(), right: other) { - LegacyRepairSubjectDiverged { field: f } => f + LegacyRepairSubjectDiverged { field: f } => repair_subject_field_label(f: f) as String LegacyRepairSubjectApplicable => "" } } @@ -349,7 +359,7 @@ test fn a_moved_semantic_source_refuses() -> Bool { repairer_identity: base.repairer_identity, repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: base.resolution_registry_digest - }) == "semantic_source_digest" + }) == (repair_subject_field_label(f: RepairSemanticSourceDigestField) as String) } test fn a_moved_source_set_refuses() -> Bool { @@ -361,7 +371,7 @@ test fn a_moved_source_set_refuses() -> Bool { repairer_identity: base.repairer_identity, repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: base.resolution_registry_digest - }) == "source_set_digest" + }) == (repair_subject_field_label(f: RepairSourceSetDigestField) as String) } test fn a_moved_compiler_artifact_refuses() -> Bool { @@ -373,7 +383,7 @@ test fn a_moved_compiler_artifact_refuses() -> Bool { repairer_identity: base.repairer_identity, repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: base.resolution_registry_digest - }) == "compiler_artifact_digest" + }) == (repair_subject_field_label(f: RepairCompilerArtifactDigestField) as String) } test fn a_moved_repairer_module_refuses() -> Bool { @@ -385,7 +395,7 @@ test fn a_moved_repairer_module_refuses() -> Bool { repairer_identity: decl_ref(module_path: "std.observation", decl_name: "OccurrenceId"), repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: base.resolution_registry_digest - }) == "repairer_identity.module_path" + }) == (repair_subject_field_label(f: RepairerIdentityModulePathField) as String) } test fn a_moved_repairer_decl_refuses() -> Bool { @@ -397,7 +407,7 @@ test fn a_moved_repairer_decl_refuses() -> Bool { repairer_identity: decl_ref(module_path: "std.occurrence_identity", decl_name: "OccurrenceIndex"), repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: base.resolution_registry_digest - }) == "repairer_identity.decl_name" + }) == (repair_subject_field_label(f: RepairerIdentityDeclNameField) as String) } test fn a_moved_repairer_field_refuses() -> Bool { @@ -409,7 +419,7 @@ test fn a_moved_repairer_field_refuses() -> Bool { repairer_identity: decl_field_ref(module_path: "std.occurrence_identity", decl_name: "OccurrenceId", field_name: "value"), repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: base.resolution_registry_digest - }) == "repairer_identity.field" + }) == (repair_subject_field_label(f: RepairerIdentityFieldField) as String) } test fn a_moved_roster_refuses() -> Bool { @@ -421,7 +431,7 @@ test fn a_moved_roster_refuses() -> Bool { repairer_identity: base.repairer_identity, repair_site_roster_digest: lro_digest(label: "dddddddddddddddd"), resolution_registry_digest: base.resolution_registry_digest - }) == "repair_site_roster_digest" + }) == (repair_subject_field_label(f: RepairSiteRosterDigestField) as String) } test fn a_moved_resolution_registry_refuses() -> Bool { @@ -433,7 +443,7 @@ test fn a_moved_resolution_registry_refuses() -> Bool { repairer_identity: base.repairer_identity, repair_site_roster_digest: base.repair_site_roster_digest, resolution_registry_digest: lro_digest(label: "eeeeeeeeeeeeeeee") - }) == "resolution_registry_digest" + }) == (repair_subject_field_label(f: ResolutionRegistryDigestField) as String) } // ── THE DUPLICATE-DENOMINATOR ARMS (review 56949) ── diff --git a/dag/test/claim/legacy_repair_tap_live_bridge_witness_test.dag b/dag/test/claim/legacy_repair_tap_live_bridge_witness_test.dag new file mode 100644 index 00000000000..f4d89f46a8e --- /dev/null +++ b/dag/test/claim/legacy_repair_tap_live_bridge_witness_test.dag @@ -0,0 +1,82 @@ +module test.claim.legacy_repair_tap_live_bridge_witness + +import std.types { String, Bool, List } +import v2.std.live_tree { LiveTreeDisposition, ReadsLiveTree } +import std.content_hash { structural_content_hash } +import std.decl_ref { decl_ref } +import extdeps.git.object_store { git_sha1_object_id } +import v2.workflow.legacy_binding_observation { + LegacyBindingObservationSubject, + ImportScopedPolicy +} +import v2.workflow.legacy_baseline_capture { + materialization_receipt, + tree_derived_subject +} +import v2.workflow.legacy_baseline_persisted_observation { + PersistAdmitted, + PersistRefusedNotCaptured +} +import v2.workflow.legacy_repair_tap { + Xl1PrimaryRootObserved, + Xl1PrimaryRootRefused, + xl1_live_repair_tap_census, + Xl1LiveRepairTapRows, + Xl1LiveRepairTapUnavailable, + persist_named_base_from_primary_root_tap +} + +// Discriminating RED for the PrimaryRoot tap (review 64801): empty source_roots must refuse +// inside the seed arm, not mint an Observed encoding. Executes emit_rust_reference_derived_rows_bridge. +data live_tree_disposition: LiveTreeDisposition = ReadsLiveTree + +test fn empty_source_roots_refuse_the_xl1_primary_root_tap() -> Bool { + match emit_rust_reference_derived_rows_bridge([]) { + Xl1PrimaryRootRefused { cause: c } => string_contains(s: c, pattern: "empty") + Xl1PrimaryRootObserved { + primary_root: _, + repair_rows: _, + occurrence_transport: _, + binding_rows: _ + } => false + } +} + +test fn empty_source_roots_do_not_tally_as_zero_rows() -> Bool { + match xl1_live_repair_tap_census([]) { + Xl1LiveRepairTapUnavailable { cause: c } => string_contains(s: c, pattern: "empty") + Xl1LiveRepairTapRows { count: _ } => false + } +} + +fn lrt_live_subject() -> LegacyBindingObservationSubject { + LegacyBindingObservationSubject { + semantic_source_digest: structural_content_hash(digest: "1111111111111111"), + source_set_digest: structural_content_hash(digest: "2222222222222222"), + compiler_artifact_digest: structural_content_hash(digest: "3333333333333333"), + resolver_identity: decl_ref(module_path: "v1.compiler.infer_env", decl_name: "lookup_binding_by_name"), + resolver_policy: ImportScopedPolicy, + occurrence_transport_digest: structural_content_hash(digest: "4444444444444444"), + declaration_index_digest: structural_content_hash(digest: "5555555555555555") + } +} + +test fn empty_source_roots_refuse_named_base_persist_through_the_tap() -> Bool { + match git_sha1_object_id(hex: "1007efb256a20749f77c3b1295eed144fddeb9fd") { + Absent => false + Present { value: a } => match git_sha1_object_id(hex: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") { + Absent => false + Present { value: t } => + match persist_named_base_from_primary_root_tap( + materialization: materialization_receipt( + requested: a, observed_head: a, observed_tree: t, commit_tree: t + ), + tree_subject: tree_derived_subject(tree: t, subject: lrt_live_subject()), + source_roots: [] + ) { + PersistRefusedNotCaptured => true + PersistAdmitted { persisted: _ } => false + } + } + } +} diff --git a/dag/test/claim/legacy_repair_tap_persisted_capture_witness_test.dag b/dag/test/claim/legacy_repair_tap_persisted_capture_witness_test.dag new file mode 100644 index 00000000000..29c433a1b22 --- /dev/null +++ b/dag/test/claim/legacy_repair_tap_persisted_capture_witness_test.dag @@ -0,0 +1,177 @@ +module test.claim.legacy_repair_tap_persisted_capture_witness + +import std.types { String, Bool, List, NonEmptyStr, SourceSpan } +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } +import std.content_hash { structural_content_hash } +import std.decl_ref { decl_ref } +import extdeps.git.object_store { git_sha1_object_id } +import std.occurrence_identity { + OccurrenceId, + OccurrenceIndex, + OccurrenceIndexEntry, + OccurrenceProjection, + OccurrenceContainmentPath, + LexicalValueOccurrence, + DeclarationOccurrence, + ReferenceOccurrence, + OccurrenceTransport, + OccurrenceTransportValidated, + OccurrenceTransportRefused, + occurrence_transport_validate +} +import v2.workflow.legacy_binding_observation { + LegacyBindingObservation, + LegacyBindingObservationRow, + LegacyBindingObservationSubject, + ImportScopedPolicy +} +import v2.workflow.legacy_baseline_capture { + materialization_receipt, + tree_derived_subject +} +import v2.workflow.legacy_baseline_persisted_observation { + PersistAdmitted, + PersistRefusedNotCaptured, + persisted_against_requested +} +import gunbc.reference_derived_candidate { + ReferenceDerivedCandidateRow, + CandidateOwnModule, + CandidateRegistryAbsent +} +import v2.workflow.legacy_repair_tap { + persist_capture_from_bridge_rows, + repair_roster_from_bridge_rows, + never_emitted_declared_modules, + repair_emitted_module_names, + xl1_primary_root_cut_subjects +} + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +type LrtBinding + = LrtBound + | LrtUnbound + +fn lrt_span() -> SourceSpan { + SourceSpan { file: "legacy-repair-tap-persist-fixture.dag", start: 1, end: 2 } +} + +fn lrt_path() -> OccurrenceContainmentPath { + OccurrenceContainmentPath { ancestors: [OccurrenceId { value: 900 }], terminal: OccurrenceId { value: 10 } } +} + +fn lrt_commit() -> String { "1007efb256a20749f77c3b1295eed144fddeb9fd" } +fn lrt_tree() -> String { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" } + +fn lrt_rows() -> List { + [ + ReferenceDerivedCandidateRow { + module_name: "std.logic", + name: "Bool", + disposition: CandidateOwnModule + } + ] +} + +fn lrt_subject() -> LegacyBindingObservationSubject { + LegacyBindingObservationSubject { + semantic_source_digest: structural_content_hash(digest: "1111111111111111"), + source_set_digest: structural_content_hash(digest: "2222222222222222"), + compiler_artifact_digest: structural_content_hash(digest: "3333333333333333"), + resolver_identity: decl_ref(module_path: "v1.compiler.infer_env", decl_name: "lookup_binding_by_name"), + resolver_policy: ImportScopedPolicy, + occurrence_transport_digest: structural_content_hash(digest: "4444444444444444"), + declaration_index_digest: structural_content_hash(digest: "5555555555555555") + } +} + +test fn roster_from_bridge_rows_is_the_same_row_tautology() -> Bool { + let roster = repair_roster_from_bridge_rows(rows: lrt_rows()) + (roster.sites |> count) == 1 + && (roster.sites |> any(s => s.module_name == ("std.logic" as NonEmptyStr) && s.name == ("Bool" as NonEmptyStr))) +} + +test fn persist_capture_from_bridge_rows_admits_a_complete_same_row_observation() -> Bool { + match git_sha1_object_id(hex: lrt_commit()) { + Absent => false + Present { value: a } => match git_sha1_object_id(hex: lrt_tree()) { + Absent => false + Present { value: t } => + match occurrence_transport_validate(transport: OccurrenceTransport { + index: OccurrenceIndex { entries: [ + OccurrenceIndexEntry { + projection: OccurrenceProjection { + occurrence: OccurrenceId { value: 900 }, + authored_name: "root", + diagnostic_span: lrt_span() + }, + containment: OccurrenceContainmentPath { ancestors: [], terminal: OccurrenceId { value: 900 } } + }, + OccurrenceIndexEntry { + projection: OccurrenceProjection { + occurrence: OccurrenceId { value: 10 }, + authored_name: "r", + diagnostic_span: lrt_span() + }, + containment: lrt_path() + } + ] }, + declarations: [DeclarationOccurrence { + occurrence: OccurrenceId { value: 900 }, + containment: OccurrenceContainmentPath { ancestors: [], terminal: OccurrenceId { value: 900 } }, + category: LexicalValueOccurrence, + diagnostic_span: lrt_span() + }], + references: [ReferenceOccurrence { + occurrence: OccurrenceId { value: 10 }, + containment: lrt_path(), + category: LexicalValueOccurrence, + diagnostic_span: lrt_span() + }] + }) { + OccurrenceTransportRefused { refusal: _ } => false + OccurrenceTransportValidated { transport: tr } => + match persist_capture_from_bridge_rows( + materialization: materialization_receipt( + requested: a, observed_head: a, observed_tree: t, commit_tree: t + ), + tree_subject: tree_derived_subject(tree: t, subject: lrt_subject()), + observation: LegacyBindingObservation { + subject: lrt_subject(), + rows: [LegacyBindingObservationRow { occurrence: OccurrenceId { value: 10 }, outcome: LrtBound }] + }, + transport: tr, + rows: lrt_rows() + ) { + PersistRefusedNotCaptured => false + PersistAdmitted { persisted: p } => persisted_against_requested(persisted: p, requested: a) + } + } + } + } +} + +test fn empty_name_row_is_dropped_from_the_roster() -> Bool { + let rows = [ + ReferenceDerivedCandidateRow { + module_name: "", + name: "Bool", + disposition: CandidateRegistryAbsent + } + ] + (repair_roster_from_bridge_rows(rows: rows).sites |> count) == 0 +} + +test fn never_emitted_is_declared_modules_absent_from_the_emitter_walk() -> Bool { + let emitted = repair_emitted_module_names(rows: lrt_rows()) + let never = never_emitted_declared_modules( + declared_modules: ["std.logic", "std.not.emitted"], + emitted_modules: emitted + ) + (never |> any(m => m == "std.not.emitted")) && !(never |> any(m => m == "std.logic")) +} + +test fn xl1_capture_subject_is_the_xl6_cut_roster_join() -> Bool { + xl1_primary_root_cut_subjects() |> any(_ => true) +} diff --git a/src/v1/04_method.dag b/src/v1/04_method.dag index c1c0eec0323..d3a0729a15f 100644 --- a/src/v1/04_method.dag +++ b/src/v1/04_method.dag @@ -332,6 +332,7 @@ data builtin_function_registry: Map = { "shell_materialize_operation_argv": BuiltinSignature { params: [BuiltinParam { name: "operation", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "workspace_dir", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "files", ty: ContainerOf { source: Named { name: "List" }, element: NamedTemplate { name: "String" } } }, BuiltinParam { name: "environment", ty: ContainerOf { source: Named { name: "List" }, element: NamedTemplate { name: "String" } } }], returns: type_variable_node(id: "argv_materialization_result") }, "shell_transport_operation_rows": BuiltinSignature { params: [], returns: list_of_type_variable(id: "shell_transport_operation_row_elem") }, "namespace_structural_observation_admissions": BuiltinSignature { params: [BuiltinParam { name: "file", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "source", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "neighbour_name", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "branch_binder_name", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "later_name", ty: NamedTemplate { name: "String" } }, BuiltinParam { name: "homonym_name", ty: NamedTemplate { name: "String" } }], returns: list_of_type_variable(id: "ordinary_compile_structural_admission_elem") }, + "emit_rust_reference_derived_rows_bridge": BuiltinSignature { params: [BuiltinParam { name: "source_roots", ty: ContainerOf { source: Named { name: "List" }, element: NamedTemplate { name: "String" } } }], returns: type_variable_node(id: "xl1_primary_root_tap") }, "extdeps_shape_transport_policy_facts_for_qualified_name": BuiltinSignature { params: [BuiltinParam { name: "module", ty: NamedTemplate { name: "String" } }], returns: type_variable_node(id: "extdeps_module_facts_record") }, "extdeps_qualified_name_resolves_in_derived_module_set": BuiltinSignature { params: [BuiltinParam { name: "module", ty: NamedTemplate { name: "String" } }], returns: bool_type }, "extdeps_external_authority_facts_for_qualified_name": BuiltinSignature { params: [BuiltinParam { name: "module", ty: NamedTemplate { name: "String" } }], returns: type_variable_node(id: "extdeps_external_authority_module_facts_record") }, diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 20269f66951..02344dc783a 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -12,6 +12,17 @@ import std.repair_input_origin { import std.primitive_projection { primitive_identity_runtime_name, primitive_projection_row_for_declaration } +import gunbc.reference_derived_candidate { + ReferenceDerivedCandidateDisposition, + CandidateSurvived, + CandidateOwnModule, + CandidateVariantDelegatedToParent, + CandidateVariantParentUnresolved, + CandidateRegistryAbsent, + CandidateLeafAmbiguous, + CandidateExportProofFailed, + ReferenceDerivedCandidateRow +} import extdeps.languages.rust.capabilities { phantom_opaque_carrier_derive_traits } @@ -4884,25 +4895,6 @@ fn local_coproduct_variant_names(items: List, source_indices: Map { + ReferenceOccurrenceBindingCensus::Refused { cause } + } + ObservedOccurrenceBindingHalves::Ready { + denominator, + observations, + .. + } => ReferenceOccurrenceBindingCensus::Observed { + source_digest, + compiler_digest, + denominator, + observations, + }, + } +} + +pub(crate) enum ObservedOccurrenceBindingHalves { + Ready { + transport: Rc, + denominator: Vec, + observations: Vec, + }, + Refused { + cause: String, + }, +} + +/// Seed-observed occurrence transport (per-module sidecars concatenated as stored) plus the +/// occurrence-grain binding walk over that same transport. Callers must not rebuild containment. +pub(crate) fn observed_occurrence_transport_and_bindings( + graph: &v1_compiler_compile::ResolvedGraph, +) -> ObservedOccurrenceBindingHalves { use crate::std_occurrence_binding_candidates as candidates; use crate::std_occurrence_identity as identity; let mut entries = Vec::new(); @@ -754,7 +787,7 @@ pub fn compile_dag_reference_occurrence_binding_census( index.clone() } other => { - return ReferenceOccurrenceBindingCensus::Refused { + return ObservedOccurrenceBindingHalves::Refused { cause: format!("reference binding census: candidate index refused: {other:?}"), } } @@ -786,8 +819,8 @@ pub fn compile_dag_reference_occurrence_binding_census( .get(&reference.occurrence.value) .cloned() else { - return ReferenceOccurrenceBindingCensus::Refused { - cause: format!( + return ObservedOccurrenceBindingHalves::Refused { + cause: format!( "reference binding census: occurrence {} is in the references view with no \ recorded consumer module; the walk that fills both changed under this instrument", reference.occurrence.value @@ -795,7 +828,7 @@ pub fn compile_dag_reference_occurrence_binding_census( }; }; let Some(authored_name) = names.get(&reference.occurrence.value).cloned() else { - return ReferenceOccurrenceBindingCensus::Refused { + return ObservedOccurrenceBindingHalves::Refused { cause: format!( "reference binding census: occurrence {} is in the references view with no \ entry in the occurrence index, so it has no authored spelling", @@ -841,7 +874,7 @@ pub fn compile_dag_reference_occurrence_binding_census( .iter() .find(|module| module.type_env.module_path == consumer_module) else { - return ReferenceOccurrenceBindingCensus::Refused { + return ObservedOccurrenceBindingHalves::Refused { cause: format!( "reference binding census: consumer module '{consumer_module}' \ carries occurrence {} but is absent from the resolved graph, so \ @@ -884,9 +917,8 @@ pub fn compile_dag_reference_occurrence_binding_census( disposition, }); } - ReferenceOccurrenceBindingCensus::Observed { - source_digest, - compiler_digest, + ObservedOccurrenceBindingHalves::Ready { + transport, denominator, observations, } @@ -1363,3 +1395,140 @@ pub fn transport_script_position_facts_for_path( } facts } + +/// Host body of the one XL-1 builtin `emit_rust_reference_derived_rows_bridge`. +/// Not a builtin spelling, CLI flag, or second compile entry: only that interpreter arm calls it. +#[derive(Debug, Clone)] +pub(crate) enum Xl1PrimaryRootTap { + Refused { + cause: String, + }, + Observed { + primary_root: String, + repair_rows: Rc>>, + occurrence_transport: Rc, + binding_rows: Vec, + }, +} + +pub(crate) fn compile_xl1_primary_root_tap(source_roots: &[String]) -> Xl1PrimaryRootTap { + if source_roots.is_empty() { + return Xl1PrimaryRootTap::Refused { + cause: "xl1 primary-root tap: source_roots is empty".to_string(), + }; + } + let root = source_roots[0].clone(); + let request = CompileRequest { + subject: CompileSubject::PrimaryRoot(root.clone()), + source_roots: source_roots.to_vec(), + primary_precedence: false, + render_targets: vec![crate::v1_compiler_artifact::RenderTarget::Rust], + }; + if let Err(cause) = request.primary_root_agrees_with_precedence() { + return Xl1PrimaryRootTap::Refused { cause }; + } + let (budget, budget_source) = crate::memory_governor::read_host_budget_bytes(); + let admission = crate::memory_governor::whole_corpus_compile_admission(budget, &budget_source); + if let Some(diagnostic) = + crate::memory_governor::whole_corpus_compile_refusal_diagnostic(&admission) + { + return Xl1PrimaryRootTap::Refused { cause: diagnostic }; + } + let root_abs = if std::path::Path::new(&root).is_absolute() { + std::path::PathBuf::from(&root) + } else { + process_workspace_root().join(&root) + }; + if repo_relative_path(&root_abs).is_err() { + return Xl1PrimaryRootTap::Refused { + cause: format!( + "primary source root is outside the workspace root: {} is not under {}", + root_abs.display(), + process_workspace_root().display() + ), + }; + } + let index = match try_process_shared_index(source_roots) { + Ok(idx) => idx, + Err(cause) => { + return Xl1PrimaryRootTap::Refused { + cause: format!("xl1 primary-root tap: source-discovery: {cause}"), + } + } + }; + let root_prefix = workspace_relative_entry_path(&root); + let mut seen: std::collections::HashMap> = + std::collections::HashMap::new(); + let mut entry_sources: Vec> = Vec::new(); + for (module_path, source) in index.source_files.iter() { + let rel = workspace_relative_entry_path(&source.path); + if rel == root_prefix || rel.starts_with(&format!("{root_prefix}/")) { + seen.insert(module_path.clone(), source.clone()); + entry_sources.push(source.clone()); + } + } + if entry_sources.is_empty() { + return Xl1PrimaryRootTap::Refused { + cause: format!("no indexed module has a source file under the primary root '{root}'"), + }; + } + entry_sources.sort_by(|a, b| a.path.cmp(&b.path)); + let import_closure = + resolve_transitively_bfs_legacy(entry_sources, &index.source_files, seen.into()); + let closure = match extend_sources_to_both_closure_fixpoint(import_closure, &index) { + Ok(c) => c, + Err(e) => { + return Xl1PrimaryRootTap::Refused { + cause: format!("xl1 primary-root tap: closure-load: {e}"), + } + } + }; + let closure_modules: HashSet = closure + .iter() + .filter_map(|s| extract_module_path(&s.content)) + .collect(); + let mut census_only: Vec> = index + .source_files + .iter() + .filter(|(module_path, _)| !closure_modules.contains(*module_path)) + .map(|(_, source)| source.clone()) + .collect(); + census_only.sort_by(|a, b| a.path.cmp(&b.path)); + let options = Rc::new(v1_compiler_compile::CompilePipelineOptions { + analyze_complexity: false, + census_only_sources: Rc::new(census_only.into()), + }); + let resolved = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { + v1_compiler_compile::compile_to_resolved_with_options( + Rc::new(closure.clone().into()), + options, + ) + })) { + Ok(value) => value, + Err(_) => { + return Xl1PrimaryRootTap::Refused { + cause: "xl1 primary-root tap: frontend panicked before producing a graph" + .to_string(), + } + } + }; + let Some(graph) = resolved.graph.clone() else { + return Xl1PrimaryRootTap::Refused { + cause: "xl1 primary-root tap: frontend produced no resolved graph".to_string(), + }; + }; + let repair_rows = crate::v1_compiler_emit_rust::emit_rust_reference_derived_rows(graph.clone()); + match observed_occurrence_transport_and_bindings(graph.as_ref()) { + ObservedOccurrenceBindingHalves::Refused { cause } => Xl1PrimaryRootTap::Refused { cause }, + ObservedOccurrenceBindingHalves::Ready { + transport, + observations, + .. + } => Xl1PrimaryRootTap::Observed { + primary_root: root, + repair_rows, + occurrence_transport: transport, + binding_rows: observations, + }, + } +} diff --git a/src/v1/stage0/src/emitted_population.rs b/src/v1/stage0/src/emitted_population.rs index dbb8326518e..d425ebb7835 100644 --- a/src/v1/stage0/src/emitted_population.rs +++ b/src/v1/stage0/src/emitted_population.rs @@ -33,6 +33,7 @@ // src/gunbc_cli_dispatch_generated.rs // src/gunbc_cli_dispatch_surface.rs // src/gunbc_namespace_reference_derived_closure_admission.rs +// src/gunbc_reference_derived_candidate.rs // src/gunbc_rust_decl_type_overlay.rs // src/gunbc_rust_source_type_bindings.rs // src/gunbc_stage0_crate_layout_generated.rs diff --git a/src/v1/stage0/src/gunbc_reference_derived_candidate.rs b/src/v1/stage0/src/gunbc_reference_derived_candidate.rs new file mode 100644 index 00000000000..7c0467fde85 --- /dev/null +++ b/src/v1/stage0/src/gunbc_reference_derived_candidate.rs @@ -0,0 +1,29 @@ +// Generated by v1 compiler -- do not edit. +// Source module: gunbc.reference_derived_candidate + +use self::ReferenceDerivedCandidateDisposition::*; +use crate::v1_rt; +use crate::v1_rt::{VecCompat, VecJoin}; +use crate::NonEmptyBTreeSet; +use crate::NonEmptyVec; +use im::{vector as vec, HashMap, OrdSet as BTreeSet, Vector as Vec}; +use std::rc::Rc; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum ReferenceDerivedCandidateDisposition { + CandidateSurvived { provider_module: String }, + CandidateOwnModule, + CandidateVariantDelegatedToParent { parent_enum: String }, + CandidateVariantParentUnresolved, + CandidateRegistryAbsent, + CandidateLeafAmbiguous, + CandidateExportProofFailed { provider_module: String }, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct ReferenceDerivedCandidateRow { + pub module_name: String, + pub name: String, + pub disposition: Rc, +} diff --git a/src/v1/stage0/src/lib.rs b/src/v1/stage0/src/lib.rs index 3303bac5780..f0907648b2c 100644 --- a/src/v1/stage0/src/lib.rs +++ b/src/v1/stage0/src/lib.rs @@ -136,6 +136,17 @@ pub mod gunbc_namespace_reference_derived_closure_admission; suspicious_double_ref_op, clippy::all )] +pub mod gunbc_reference_derived_candidate; +#[allow( + unused_imports, + unused_variables, + unused_mut, + unused_parens, + dead_code, + non_shorthand_field_patterns, + suspicious_double_ref_op, + clippy::all +)] pub mod gunbc_rust_decl_type_overlay; #[allow( unused_imports, diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index f4e4056a0ad..4062c3856ca 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -8,7 +8,6 @@ use self::DataRefResolution::*; use self::DataReferenceUnresolvableCause::*; use self::IterOwnedReceiverCloneDisposition::*; use self::ParamDefaultResolution::*; -use self::ReferenceDerivedCandidateDisposition::*; use self::WitnessCtorPathVerdict::*; pub use crate::extdeps_cargo_version::render_cargo_package_header_prefix; pub use crate::extdeps_languages_rust_capabilities::phantom_opaque_carrier_derive_traits; @@ -40,6 +39,10 @@ pub use crate::gunbc_cli_dispatch_surface::{ CliArmRealization, CliBootstrapDagOperationBinding, CliBootstrapExecutionClass, CliOperandRow, CliOptionArity, CliOptionRow, CliOptionValue, CliSubcommandRow, }; +use crate::gunbc_reference_derived_candidate::ReferenceDerivedCandidateDisposition::*; +pub use crate::gunbc_reference_derived_candidate::{ + ReferenceDerivedCandidateDisposition, ReferenceDerivedCandidateRow, +}; pub use crate::gunbc_rust_decl_type_overlay::rust_decl_type_container_overlay_is_admitted; pub use crate::gunbc_stage0_crate_layout_generated::generated_pub_mod_block; pub use crate::gunbc_stage0_crate_partition_generated::generated_partition_crate_rows; @@ -9482,25 +9485,6 @@ pub fn local_coproduct_variant_names( }) } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -#[serde(tag = "_variant")] -pub enum ReferenceDerivedCandidateDisposition { - CandidateSurvived { provider_module: String }, - CandidateOwnModule, - CandidateVariantDelegatedToParent { parent_enum: String }, - CandidateVariantParentUnresolved, - CandidateRegistryAbsent, - CandidateLeafAmbiguous, - CandidateExportProofFailed { provider_module: String }, -} - -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct ReferenceDerivedCandidateRow { - pub module_name: String, - pub name: String, - pub disposition: Rc, -} - pub fn reference_derived_candidate_disposition( name: String, this_module_name: String, diff --git a/src/v1/stage0/src/v1_compiler_infer_method.rs b/src/v1/stage0/src/v1_compiler_infer_method.rs index 74a06990a32..bff330db774 100644 --- a/src/v1/stage0/src/v1_compiler_infer_method.rs +++ b/src/v1/stage0/src/v1_compiler_infer_method.rs @@ -956,6 +956,20 @@ pub fn builtin_function_registry() -> Rc>> }), })]), returns: list_of_type_variable("ordinary_compile_structural_admission_elem".to_string()), + })); + __m.insert("emit_rust_reference_derived_rows_bridge".to_string(), Rc::new(BuiltinSignature { + params: Rc::new(vec![Rc::new(BuiltinParam { + name: "source_roots".to_string(), + ty: Rc::new(AlgebraTypeTemplate::ContainerOf { + source: Rc::new(ContainerSource::Named { + name: "List".to_string(), + }), + element: Rc::new(AlgebraTypeTemplate::NamedTemplate { + name: "String".to_string(), + }), + }), + })]), + returns: type_variable_node("xl1_primary_root_tap".to_string()), })); __m.insert("extdeps_shape_transport_policy_facts_for_qualified_name".to_string(), Rc::new(BuiltinSignature { params: Rc::new(vec![Rc::new(BuiltinParam { diff --git a/src/v1/stage0/src/v1_interpreter.rs b/src/v1/stage0/src/v1_interpreter.rs index a3ffc7242d7..84e366e22ed 100644 --- a/src/v1/stage0/src/v1_interpreter.rs +++ b/src/v1/stage0/src/v1_interpreter.rs @@ -12092,6 +12092,66 @@ fn namespace_structural_observation_admissions_value( ) } +fn reference_derived_candidate_disposition_value( + disposition: &crate::v1_compiler_emit_rust::ReferenceDerivedCandidateDisposition, + ctx: &InterpContext, +) -> Value { + use crate::v1_compiler_emit_rust::ReferenceDerivedCandidateDisposition as D; + let variant = |name: &str, fields: Vec<(Symbol, Value)>| Value::Variant { + type_name: ctx.sym("ReferenceDerivedCandidateDisposition"), + variant_name: ctx.sym(name), + fields: Rc::new(sorted_fields(fields)), + }; + match disposition { + D::CandidateSurvived { provider_module } => variant( + "CandidateSurvived", + vec![( + ctx.sym("provider_module"), + str_value(provider_module.clone()), + )], + ), + D::CandidateOwnModule => variant("CandidateOwnModule", vec![]), + D::CandidateVariantDelegatedToParent { parent_enum } => variant( + "CandidateVariantDelegatedToParent", + vec![(ctx.sym("parent_enum"), str_value(parent_enum.clone()))], + ), + D::CandidateVariantParentUnresolved => variant("CandidateVariantParentUnresolved", vec![]), + D::CandidateRegistryAbsent => variant("CandidateRegistryAbsent", vec![]), + D::CandidateLeafAmbiguous => variant("CandidateLeafAmbiguous", vec![]), + D::CandidateExportProofFailed { provider_module } => variant( + "CandidateExportProofFailed", + vec![( + ctx.sym("provider_module"), + str_value(provider_module.clone()), + )], + ), + } +} + +fn reference_derived_candidate_rows_value( + rows: &im::Vector>, + ctx: &InterpContext, +) -> Value { + list_value( + rows.iter() + .map(|row| Value::Record { + type_name: ctx.sym("ReferenceDerivedCandidateRow"), + fields: Rc::new(sorted_fields(vec![ + (ctx.sym("module_name"), str_value(row.module_name.clone())), + (ctx.sym("name"), str_value(row.name.clone())), + ( + ctx.sym("disposition"), + reference_derived_candidate_disposition_value( + row.disposition.as_ref(), + ctx, + ), + ), + ])), + }) + .collect::>(), + ) +} + fn compile_diagnostic_census_value( census: crate::cli_run::CompileDiagnosticCensus, ctx: &InterpContext, @@ -12258,6 +12318,211 @@ fn multi_module_compile_fixture_value( } } +fn occurrence_id_value( + id: crate::std_occurrence_identity::OccurrenceId, + ctx: &InterpContext, +) -> Value { + Value::Record { + type_name: ctx.sym("OccurrenceId"), + fields: Rc::new(sorted_fields(vec![( + ctx.sym("value"), + Value::Int(id.value), + )])), + } +} + +fn authored_source_span_value(span: &crate::std_types::SourceSpan, ctx: &InterpContext) -> Value { + Value::Record { + type_name: ctx.sym("SourceSpan"), + fields: Rc::new(sorted_fields(vec![ + (ctx.sym("file"), str_value(span.file.clone())), + (ctx.sym("start"), Value::Int(span.start)), + (ctx.sym("end"), Value::Int(span.end)), + ])), + } +} + +fn occurrence_containment_path_value( + path: &crate::std_occurrence_identity::OccurrenceContainmentPath, + ctx: &InterpContext, +) -> Value { + Value::Record { + type_name: ctx.sym("OccurrenceContainmentPath"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("ancestors"), + list_value( + path.ancestors + .iter() + .copied() + .map(|id| occurrence_id_value(id, ctx)) + .collect::>(), + ), + ), + (ctx.sym("terminal"), occurrence_id_value(path.terminal, ctx)), + ])), + } +} + +fn occurrence_transport_value( + transport: &crate::std_occurrence_identity::OccurrenceTransport, + ctx: &InterpContext, +) -> Value { + let projection = |p: &crate::std_occurrence_identity::OccurrenceProjection| Value::Record { + type_name: ctx.sym("OccurrenceProjection"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("occurrence"), + occurrence_id_value(p.occurrence, ctx), + ), + (ctx.sym("authored_name"), str_value(p.authored_name.clone())), + ( + ctx.sym("diagnostic_span"), + authored_source_span_value(p.diagnostic_span.as_ref(), ctx), + ), + ])), + }; + let index_entry = |e: &crate::std_occurrence_identity::OccurrenceIndexEntry| Value::Record { + type_name: ctx.sym("OccurrenceIndexEntry"), + fields: Rc::new(sorted_fields(vec![ + (ctx.sym("projection"), projection(e.projection.as_ref())), + ( + ctx.sym("containment"), + occurrence_containment_path_value(e.containment.as_ref(), ctx), + ), + ])), + }; + let declaration = |d: &crate::std_occurrence_identity::DeclarationOccurrence| Value::Record { + type_name: ctx.sym("DeclarationOccurrence"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("occurrence"), + occurrence_id_value(d.occurrence, ctx), + ), + ( + ctx.sym("containment"), + occurrence_containment_path_value(d.containment.as_ref(), ctx), + ), + ( + ctx.sym("category"), + occurrence_category_value(&d.category, ctx), + ), + ( + ctx.sym("diagnostic_span"), + authored_source_span_value(d.diagnostic_span.as_ref(), ctx), + ), + ])), + }; + let reference = |r: &crate::std_occurrence_identity::ReferenceOccurrence| Value::Record { + type_name: ctx.sym("ReferenceOccurrence"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("occurrence"), + occurrence_id_value(r.occurrence, ctx), + ), + ( + ctx.sym("containment"), + occurrence_containment_path_value(r.containment.as_ref(), ctx), + ), + ( + ctx.sym("category"), + occurrence_category_value(&r.category, ctx), + ), + ( + ctx.sym("diagnostic_span"), + authored_source_span_value(r.diagnostic_span.as_ref(), ctx), + ), + ])), + }; + Value::Record { + type_name: ctx.sym("OccurrenceTransport"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("index"), + Value::Record { + type_name: ctx.sym("OccurrenceIndex"), + fields: Rc::new(sorted_fields(vec![( + ctx.sym("entries"), + list_value( + transport + .index + .entries + .iter() + .map(|e| index_entry(e.as_ref())) + .collect::>(), + ), + )])), + }, + ), + ( + ctx.sym("declarations"), + list_value( + transport + .declarations + .iter() + .map(|d| declaration(d.as_ref())) + .collect::>(), + ), + ), + ( + ctx.sym("references"), + list_value( + transport + .references + .iter() + .map(|r| reference(r.as_ref())) + .collect::>(), + ), + ), + ])), + } +} + +fn xl1_primary_root_tap_value( + tap: crate::cli_run::Xl1PrimaryRootTap, + ctx: &InterpContext, +) -> Value { + let variant = |name: &str, fields: Vec<(Symbol, Value)>| Value::Variant { + type_name: ctx.sym("Xl1PrimaryRootTap"), + variant_name: ctx.sym(name), + fields: Rc::new(sorted_fields(fields)), + }; + match tap { + crate::cli_run::Xl1PrimaryRootTap::Refused { cause } => variant( + "Xl1PrimaryRootRefused", + vec![(ctx.sym("cause"), str_value(cause))], + ), + crate::cli_run::Xl1PrimaryRootTap::Observed { + primary_root, + repair_rows, + occurrence_transport, + binding_rows, + } => variant( + "Xl1PrimaryRootObserved", + vec![ + (ctx.sym("primary_root"), str_value(primary_root)), + ( + ctx.sym("repair_rows"), + reference_derived_candidate_rows_value(repair_rows.as_ref(), ctx), + ), + ( + ctx.sym("occurrence_transport"), + occurrence_transport_value(occurrence_transport.as_ref(), ctx), + ), + ( + ctx.sym("binding_rows"), + list_value( + binding_rows + .into_iter() + .map(|row| reference_occurrence_binding_census_row_value(row, ctx)) + .collect::>(), + ), + ), + ], + ), + } +} + fn occurrence_category_value( category: &crate::std_occurrence_identity::OccurrenceCategory, ctx: &InterpContext, @@ -12278,6 +12543,96 @@ fn occurrence_category_value( } } +fn reference_occurrence_binding_census_row_value( + row: crate::cli_run::ReferenceOccurrenceBindingRow, + ctx: &InterpContext, +) -> Value { + let source_value = |source: crate::cli_run::UnlistedImportBindingSource| Value::Variant { + type_name: ctx.sym("UnlistedImportBindingSource"), + variant_name: ctx.sym(match source { + crate::cli_run::UnlistedImportBindingSource::ListedImport => "ListedImport", + crate::cli_run::UnlistedImportBindingSource::PoolCoincidence => "PoolCoincidence", + crate::cli_run::UnlistedImportBindingSource::DefinerResolvable => "DefinerResolvable", + crate::cli_run::UnlistedImportBindingSource::AmbiguousLeaf => "AmbiguousLeaf", + }), + fields: Rc::new(vec![]), + }; + let disposition = match row.disposition { + crate::cli_run::ReferenceOccurrenceBindingDisposition::Bound { + declaration_occurrence, + provider_module, + binding_source, + } => Value::Variant { + type_name: ctx.sym("ReferenceOccurrenceBindingDisposition"), + variant_name: ctx.sym("ReferenceOccurrenceBound"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("declaration_occurrence"), + Value::Int(declaration_occurrence), + ), + (ctx.sym("provider_module"), str_value(provider_module)), + (ctx.sym("binding_source"), source_value(binding_source)), + ])), + }, + crate::cli_run::ReferenceOccurrenceBindingDisposition::Unresolved => Value::Variant { + type_name: ctx.sym("ReferenceOccurrenceBindingDisposition"), + variant_name: ctx.sym("ReferenceOccurrenceUnresolved"), + fields: Rc::new(vec![]), + }, + crate::cli_run::ReferenceOccurrenceBindingDisposition::Ambiguous { candidates } => { + Value::Variant { + type_name: ctx.sym("ReferenceOccurrenceBindingDisposition"), + variant_name: ctx.sym("ReferenceOccurrenceAmbiguous"), + fields: Rc::new(sorted_fields(vec![( + ctx.sym("candidates"), + list_value(candidates.into_iter().map(Value::Int).collect::>()), + )])), + } + } + crate::cli_run::ReferenceOccurrenceBindingDisposition::Refused { cause } => { + Value::Variant { + type_name: ctx.sym("ReferenceOccurrenceBindingDisposition"), + variant_name: ctx.sym("ReferenceOccurrenceBindingRefused"), + fields: Rc::new(sorted_fields(vec![(ctx.sym("cause"), str_value(cause))])), + } + } + }; + Value::Record { + type_name: ctx.sym("ReferenceOccurrenceBindingRow"), + fields: Rc::new(sorted_fields(vec![ + ( + ctx.sym("occurrence"), + Value::Int(row.denominator.occurrence), + ), + ( + ctx.sym("consumer_file"), + str_value(row.denominator.consumer_file), + ), + ( + ctx.sym("consumer_module"), + str_value(row.denominator.consumer_module), + ), + ( + ctx.sym("authored_name"), + str_value(row.denominator.authored_name), + ), + ( + ctx.sym("category"), + occurrence_category_value(&row.denominator.category, ctx), + ), + ( + ctx.sym("file_reference_ordinal"), + Value::Int(row.denominator.file_reference_ordinal), + ), + ( + ctx.sym("span_start"), + Value::Int(row.denominator.span_start), + ), + (ctx.sym("disposition"), disposition), + ])), + } +} + fn reference_occurrence_binding_census_value( census: crate::cli_run::ReferenceOccurrenceBindingCensus, ctx: &InterpContext, @@ -18680,6 +19035,14 @@ macro_rules! v1_builtin_arms { ))) }, + arm "free_call.emit_rust_reference_derived_rows_bridge" { "emit_rust_reference_derived_rows_bridge" } => { + let source_roots = expect_str_list($positional.first().copied(), $name)?; + Ok(Some(xl1_primary_root_tap_value( + crate::cli_run::compile_xl1_primary_root_tap(&source_roots), + $ctx, + ))) + }, + arm "free_call.compile_dag_rust_emit_check" { "compile_dag_rust_emit_check" } => { let source = expect_str($positional.first().copied(), $name)?; let file_path = expect_str($positional.get(1).copied(), $name)?; diff --git a/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs b/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs index 6b99ee5437a..db86dd950a1 100644 --- a/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs +++ b/src/v1/stage0/src/v1_interpreter_dispatch_generated.rs @@ -97,6 +97,7 @@ pub enum EvalBuiltinArm { FreeCallDocGraphDocCount, FreeCallParsedImportStatements, FreeCallNamespaceStructuralObservationAdmissions, + FreeCallEmitRustReferenceDerivedRowsBridge, FreeCallCompileDagRustEmitCheck, FreeCallCompileDagDiagnosticCensus, FreeCallCompileDagMultiModuleFixture, @@ -236,6 +237,7 @@ pub fn lookup_eval_builtin_inner(spelling: &str) -> Option { "doc_graph_doc_count" => Some(EvalBuiltinArm::FreeCallDocGraphDocCount), "parsed_import_statements" => Some(EvalBuiltinArm::FreeCallParsedImportStatements), "namespace_structural_observation_admissions" => Some(EvalBuiltinArm::FreeCallNamespaceStructuralObservationAdmissions), + "emit_rust_reference_derived_rows_bridge" => Some(EvalBuiltinArm::FreeCallEmitRustReferenceDerivedRowsBridge), "compile_dag_rust_emit_check" => Some(EvalBuiltinArm::FreeCallCompileDagRustEmitCheck), "compile_dag_diagnostic_census" => Some(EvalBuiltinArm::FreeCallCompileDagDiagnosticCensus), "compile_dag_multi_module_fixture" => Some(EvalBuiltinArm::FreeCallCompileDagMultiModuleFixture), @@ -373,6 +375,7 @@ macro_rules! eval_builtin_inner_arm { ("free_call.doc_graph_doc_count") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallDocGraphDocCount }; ("free_call.parsed_import_statements") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallParsedImportStatements }; ("free_call.namespace_structural_observation_admissions") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallNamespaceStructuralObservationAdmissions }; + ("free_call.emit_rust_reference_derived_rows_bridge") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallEmitRustReferenceDerivedRowsBridge }; ("free_call.compile_dag_rust_emit_check") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallCompileDagRustEmitCheck }; ("free_call.compile_dag_diagnostic_census") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallCompileDagDiagnosticCensus }; ("free_call.compile_dag_multi_module_fixture") => { $crate::v1_interpreter_dispatch_generated::EvalBuiltinArm::FreeCallCompileDagMultiModuleFixture }; diff --git a/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag b/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag index d383a465190..37f3cc600c5 100644 --- a/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag +++ b/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag @@ -1,14 +1,6 @@ module v1.tests.claim.reference_derived_disposition_census_witness_test import v1.compiler.emit_rust { - ReferenceDerivedCandidateDisposition, - CandidateSurvived, - CandidateOwnModule, - CandidateRegistryAbsent, - CandidateExportProofFailed, - CandidateVariantDelegatedToParent, - CandidateVariantParentUnresolved, - ReferenceDerivedCandidateRow, reference_derived_row_diagnostics, ReferenceDerivedCensus, reference_derived_candidate_disposition, @@ -18,6 +10,16 @@ import v1.compiler.emit_rust { emit_rust_reference_derived_census, build_module_index } +import gunbc.reference_derived_candidate { + ReferenceDerivedCandidateDisposition, + CandidateSurvived, + CandidateOwnModule, + CandidateRegistryAbsent, + CandidateExportProofFailed, + CandidateVariantDelegatedToParent, + CandidateVariantParentUnresolved, + ReferenceDerivedCandidateRow +} import v1.compiler.infer_items { ItemInfo, FnItem } import v1.std.core { ErrorNode, SourceSpan, no_span, diagnostic_to_message, is_error_diagnostic diff --git a/src/v2/workflow/legacy_baseline_capture.dag b/src/v2/workflow/legacy_baseline_capture.dag index 361ec2a7daa..14e75571d2a 100644 --- a/src/v2/workflow/legacy_baseline_capture.dag +++ b/src/v2/workflow/legacy_baseline_capture.dag @@ -1,9 +1,35 @@ module v2.workflow.legacy_baseline_capture import std.types { String, List, Int, Bool, NonEmptyStr } -import std.occurrence_identity { ValidatedOccurrenceTransport } -import extdeps.git.object_store { GitObjectId, git_object_id_eq, git_object_id_wire_hex } -import v2.workflow.legacy_repair_observation { CompleteLegacyRepairObservation } +import std.content_hash { Fnv1a64Structural } +import std.occurrence_identity { + ValidatedOccurrenceTransport, + OccurrenceTransport, + OccurrenceTransportRefusal, + OccurrenceTransportValidated, + OccurrenceTransportRefused, + occurrence_transport_validate +} +import extdeps.git.object_store { GitObjectId, git_object_id_eq } +import v2.workflow.legacy_repair_observation { + CompleteLegacyRepairObservation, + LegacyRepairObservation, + LegacyRepairObservationSubject, + RepairSite, + RepairSiteRoster, + RepairRosterProven, + RepairRosterRepeatedSite, + RepairRosterMismatch, + prove_repair_roster, + admit_complete_repair_observation, + RepairObservationAdmitted, + RepairObservationSubjectDiverged, + RepairObservationRefused, + LegacyRepairSubjectField, + RepairSemanticSourceDigestField, + RepairSourceSetDigestField, + RepairCompilerArtifactDigestField +} import std.observation_completeness { ObservationCompleteness } import v2.workflow.legacy_binding_observation { LegacyBindingObservation, @@ -63,24 +89,15 @@ fn materialization_receipt( } } -// THIS TYPE HAS NO CONSTRUCTOR AND THAT IS THE ENTIRE POINT. A complete BINDING observation must -// not stand in for a complete REPAIR observation: O_X(B) records which binding the legacy resolver -// selected, R_X(B) which use-line repair decisions it made -- separate facts that may share one -// capture envelope. The repair census has a producer -- reference_derived_census over the retained -// per-candidate disposition rows -- but no admission envelope with an independent denominator, and -// that denominator is an open question in the census owner's subject, not a missing field here. -// -// Declaring the field with an unconstructable type made the accepted arm UNREACHABLE rather than -// reachable-with-a-stub. A placeholder would admit a capture whose repair half was never taken -- -// fabricated plausible output at the exact seam the cut is authorised against. -// -// THAT PLACEHOLDER IS NOW GONE AND THE REAL CARRIER IS IMPORTED. It was a constructor-less, -// field-less declaration standing in for v2.workflow.legacy_repair_observation before that -// authority existed, and this module's annotation committed to its deletion by whichever change -// landed second. #9440 landed first, so the deletion rides here -- in the same change that merges -// it, never as a follow-up, because declaration names bind closure-globally and two declarations of -// one name on main is a collision, not a shadowing. THE ACCEPTED ARM IS NOW CONSTRUCTIBLE FOR THE -// FIRST TIME. +// A complete BINDING observation must not stand in for a complete REPAIR observation: O_X(B) +// records which binding the legacy resolver selected, R_X(B) which use-line repair decisions it +// made -- separate facts that may share one capture envelope. The repair census producer remains +// v1.compiler.emit_rust reference_derived_census; this module does not reconstruct it. What this +// phase consumes is the admission envelope that already lives in +// v2.workflow.legacy_repair_observation: a RepairSiteRoster stated before answering, proven against +// the observation subject, then joined. The envelope is fed here, not re-scoped away, and not +// replaced by XL-0's pre-eligibility origin roster, whose grain/superset/subset disagree with +// repair sites. // // WHY THE DELETION COULD NOT WAIT FOR A FOLLOW-UP: neither author can observe this collision by // compiling their own branch. Both were green against main independently; the breakage exists only @@ -97,9 +114,8 @@ fn materialization_receipt( // the emitter, and neither envelope may name it. // NO PUBLIC CONSTRUCTOR. Every field is either a proven equality or a carrier obtainable only by -// having done the work: the observation is `sole_constructor` and minted only by the admission, the -// repair observation has no constructor at all, and the commit and tree are constructor-validated -// git object ids. +// having done the work: both observations are `sole_constructor` and minted only by their +// admissions, and the commit and tree are constructor-validated git object ids. // // AND THERE IS NO RELABELING CONSTRUCTOR. Nothing here projects a capture into a plainer record, // because a projection carrying (base, identity) as ordinary fields IS a relabeling constructor: it @@ -123,8 +139,7 @@ type LegacyBaselineCapturePhase | RepairCensusPhase type LegacyBaselineCaptureRefusal - = RepairObservationEnvelopeAbsent - | ObserverNeverReachedDecision + = ObserverNeverReachedDecision {} // THE SUBJECT FIELD THAT DISAGREED IS NAMED RATHER THAN COUNTED, because the seven digests have // different owners and different repairs: a source-set mismatch means the tree was not the one @@ -152,10 +167,18 @@ type LegacyBaselineCaptureOutcome | LegacyBaselineWorktreeMismatch { commit_tree: GitObjectId, observed_tree: GitObjectId } | LegacyBaselineSubjectMismatch { field: LegacyObservationSubjectField } | LegacyBaselineObservationIncomplete { completeness: ObservationCompleteness } + | LegacyBaselineRepairRosterMalformed { sites: List } + | LegacyBaselineRepairRosterMismatch { + subject_digest: Fnv1a64Structural, + roster_digest: Fnv1a64Structural + } + | LegacyBaselineRepairSubjectDiverged { field: LegacyRepairSubjectField } + | LegacyBaselineRepairIncomplete { completeness: ObservationCompleteness } | LegacyBaselineExecutionRefused { phase: LegacyBaselineCapturePhase, cause: LegacyBaselineCaptureRefusal } + | LegacyBaselineObservedTransportRefused { refusal: OccurrenceTransportRefusal } // THE SUBJECT THE MATERIALIZED TREE ENTITLES A CAPTURE TO CLAIM. Condition 4 asks that the digests // were DERIVED from that tree -- a fact about the run, not about any value reachable here -- so the @@ -192,6 +215,28 @@ fn first_subject_disagreement( } } +// THE REPAIR HALF MUST JOIN THE SAME TREE SUBJECT THE BINDING HALF JOINED. prove_repair_roster +// and admit_complete_repair_observation compare the observation to itself (the roster is proven +// against repair_observation.subject, then admission compares that subject to the proven one), so +// LegacyBaselineRepairSubjectDiverged is unreachable from those calls alone. The three digests +// the tree receipt already carries -- semantic source, source set, compiler artifact -- are the +// facts that say WHICH BASE was observed. A repair observation whose digests disagree is from +// another tree or another compiler and must not mint as taken over this materialization. +fn first_repair_base_disagreement( + tree: LegacyBindingObservationSubject, + repair: LegacyRepairObservationSubject +) -> LegacyRepairSubjectField? { + if !(tree.semantic_source_digest == repair.semantic_source_digest) { + Present { value: RepairSemanticSourceDigestField } + } else if !(tree.source_set_digest == repair.source_set_digest) { + Present { value: RepairSourceSetDigestField } + } else if !(tree.compiler_artifact_digest == repair.compiler_artifact_digest) { + Present { value: RepairCompilerArtifactDigestField } + } else { + none + } +} + // THE CAPTURE MINTS THE OBSERVATION ITSELF -- it takes the raw observation and the transport and // calls the admission, rather than accepting an already-admitted carrier. That is condition 6, and // the signature is the whole of it: a capture that ACCEPTED a CompleteLegacyObservation could only @@ -203,11 +248,36 @@ fn first_subject_disagreement( // BEFORE the next comparison and before any promotion. Head before worktree, worktree before // subject, subject before admission, admission before the repair census -- so a dirty worktree can // never be reported as a subject disagreement, nor an incomplete observation as a repair gap. +fn capture_legacy_baseline_from_observed_transport( + materialization: CheckoutMaterialization, + tree_subject: TreeDerivedSubjectReceipt, + observation: LegacyBindingObservation, + observed_transport: OccurrenceTransport, + repair_observation: LegacyRepairObservation, + repair_roster: RepairSiteRoster +) -> LegacyBaselineCaptureOutcome { + match occurrence_transport_validate(transport: observed_transport) { + OccurrenceTransportRefused { refusal: r } => + LegacyBaselineObservedTransportRefused { refusal: r } + OccurrenceTransportValidated { transport: t } => + capture_legacy_baseline( + materialization: materialization, + tree_subject: tree_subject, + observation: observation, + transport: t, + repair_observation: repair_observation, + repair_roster: repair_roster + ) + } +} + fn capture_legacy_baseline( materialization: CheckoutMaterialization, tree_subject: TreeDerivedSubjectReceipt, observation: LegacyBindingObservation, - transport: ValidatedOccurrenceTransport + transport: ValidatedOccurrenceTransport, + repair_observation: LegacyRepairObservation, + repair_roster: RepairSiteRoster ) -> LegacyBaselineCaptureOutcome { if !git_object_id_eq(left: materialization.requested, right: materialization.observed_head) { LegacyBaselineHeadMismatch { @@ -227,10 +297,31 @@ fn capture_legacy_baseline( Absent => match admit_complete_observation(observation: observation, transport: transport) { ObservationRefused { completeness: c } => LegacyBaselineObservationIncomplete { completeness: c } - ObservationAdmitted { admitted: _ } => - LegacyBaselineExecutionRefused { - phase: RepairCensusPhase, - cause: RepairObservationEnvelopeAbsent + ObservationAdmitted { admitted: binding } => + match first_repair_base_disagreement(tree: tree_subject.subject, repair: repair_observation.subject) { + Present { value: f } => LegacyBaselineRepairSubjectDiverged { field: f } + Absent => + match prove_repair_roster(subject: repair_observation.subject, roster: repair_roster) { + RepairRosterRepeatedSite { sites: s } => LegacyBaselineRepairRosterMalformed { sites: s } + RepairRosterMismatch { subject_digest: sd, roster_digest: rd } => + LegacyBaselineRepairRosterMismatch { subject_digest: sd, roster_digest: rd } + RepairRosterProven { proven: proven } => + match admit_complete_repair_observation(observation: repair_observation, proven: proven) { + RepairObservationSubjectDiverged { field: f } => + LegacyBaselineRepairSubjectDiverged { field: f } + RepairObservationRefused { completeness: c } => + LegacyBaselineRepairIncomplete { completeness: c } + RepairObservationAdmitted { admitted: repair } => + LegacyBaselineCaptured { + capture: LegacyBaselineCapture { + base_commit: materialization.requested, + base_tree: materialization.observed_tree, + observation: binding, + repair_observation: repair + } + } + } + } } } } @@ -238,19 +329,23 @@ fn capture_legacy_baseline( } // THE MILESTONE'S POPULATION, AND IT IS DELIBERATELY NOT A ROSTER OF ROWS. There is no committed -// list of captures, because a captured baseline has no relabel-safe durable form yet and a plain -// row would be one. What a consumer can read is whether the capture operation is currently CAPABLE -// of producing an accepted capture, and today it is not: the repair envelope is absent, so every -// execution refuses at RepairCensusPhase. +// list of captures: a plain (base, identity) row is a relabeling constructor. Persistence stores +// the capture carrier itself (v2.workflow.legacy_baseline_persisted_observation). // -// Any movement of the pre-cut base after capture invalidates enrolment, so this is a standing -// question re-asked per base, not a fact that accumulates -- a second reason there is no roster. +// CAPABILITY IS WHETHER A LIVE CAPTURE OF A NAMED BASE CAN BE TAKEN, not whether the fold can mint +// given caller-supplied rows. Fixtures already drive capture_legacy_baseline to LegacyBaselineCaptured. +// The executing producer is v2.workflow.legacy_repair_tap persist_named_base_from_primary_root_tap: +// it materializes CheckoutMaterialization.requested (a GitObjectId) through +// emit_rust_reference_derived_rows_bridge into LegacyRepairObservation + RepairSiteRoster and the +// tap's binding rows. CaptureAvailable is not ACT-0's BaselineCaptureReceipt and is not a +// corpus-oracle claim. CaptureBlocked remains the typed arm for a later producer loss; +// ObserverNeverReachedDecision is the remaining refuse cause. type LegacyBaselineCaptureCapability = CaptureBlocked { phase: LegacyBaselineCapturePhase, cause: LegacyBaselineCaptureRefusal } | CaptureAvailable fn legacy_baseline_capture_capability() -> LegacyBaselineCaptureCapability { - CaptureBlocked { phase: RepairCensusPhase, cause: RepairObservationEnvelopeAbsent } + CaptureAvailable } fn capture_blocked_reason(c: LegacyBaselineCaptureCapability) -> List { @@ -273,7 +368,6 @@ fn capture_phase_label(p: LegacyBaselineCapturePhase) -> String { fn capture_refusal_label(cause: LegacyBaselineCaptureRefusal) -> String { match cause { - RepairObservationEnvelopeAbsent => "R_X(B) has no admission envelope with an independent denominator" - ObserverNeverReachedDecision => "the observer never reached its decision stage" + ObserverNeverReachedDecision {} => "the observer never reached its decision stage" } } diff --git a/src/v2/workflow/legacy_baseline_persisted_observation.dag b/src/v2/workflow/legacy_baseline_persisted_observation.dag new file mode 100644 index 00000000000..f744dc3ade3 --- /dev/null +++ b/src/v2/workflow/legacy_baseline_persisted_observation.dag @@ -0,0 +1,103 @@ +module v2.workflow.legacy_baseline_persisted_observation + +import std.types { String, List, Bool } +import extdeps.git.object_store { GitObjectId, git_object_id_eq } +import v2.workflow.legacy_baseline_capture { + LegacyBaselineCapture, + LegacyBaselineCaptureOutcome, + LegacyBaselineCaptured, + LegacyBaselineHeadMismatch, + LegacyBaselineWorktreeMismatch, + LegacyBaselineSubjectMismatch, + LegacyBaselineObservationIncomplete, + LegacyBaselineRepairRosterMalformed, + LegacyBaselineRepairRosterMismatch, + LegacyBaselineRepairSubjectDiverged, + LegacyBaselineRepairIncomplete, + LegacyBaselineExecutionRefused, + LegacyBaselineObservedTransportRefused +} + +// PERSISTENCE IS THE CAPTURE CARRIER, NOT A RECEIPTS ROSTER. A row of (base, identity) is a +// relabeling constructor: it lets an identity captured at B be presented beside B+1. +// persist_legacy_baseline is the only mint, and it accepts only LegacyBaselineCaptured. Lookup +// compares the requested GitObjectId to capture.base_commit; a different id cannot be written onto +// a held capture. +// +// THIS MODULE DOES NOT CLAIM A CORPUS ORACLE AND DOES NOT PIN THE PRE-CUT BASE. Pinning B is +// ACT-0's operator decision. Production is PreCutBaseUnpinned; persisted_legacy_baseline_outstanding +// reports outstanding until that pin. A fixture capture may be joined to PreCutBasePinned inside +// a witness via persisted_enrollment_outstanding; that join is not the live pin. Consumers: +// persist_legacy_baseline, persist_named_base_from_primary_root_tap, NamespaceBaselineObservationComplete +// (outstanding fold), ACT-0 BaselineCaptureReceipt (later digest of a re-run), XL-2 via XL-1 +// capability, and the discriminating witnesses. + +type PersistedLegacyBaseline sole_constructor { + capture: LegacyBaselineCapture +} + +type PersistAdmission + = PersistAdmitted { persisted: PersistedLegacyBaseline } + | PersistRefusedNotCaptured + +fn persist_legacy_baseline( + outcome: LegacyBaselineCaptureOutcome +) -> PersistAdmission { + match outcome { + LegacyBaselineCaptured { capture: c } => + PersistAdmitted { persisted: PersistedLegacyBaseline { capture: c } } + LegacyBaselineHeadMismatch { requested: _, materialized: _ } => PersistRefusedNotCaptured + LegacyBaselineWorktreeMismatch { commit_tree: _, observed_tree: _ } => PersistRefusedNotCaptured + LegacyBaselineSubjectMismatch { field: _ } => PersistRefusedNotCaptured + LegacyBaselineObservationIncomplete { completeness: _ } => PersistRefusedNotCaptured + LegacyBaselineRepairRosterMalformed { sites: _ } => PersistRefusedNotCaptured + LegacyBaselineRepairRosterMismatch { subject_digest: _, roster_digest: _ } => PersistRefusedNotCaptured + LegacyBaselineRepairSubjectDiverged { field: _ } => PersistRefusedNotCaptured + LegacyBaselineRepairIncomplete { completeness: _ } => PersistRefusedNotCaptured + LegacyBaselineExecutionRefused { phase: _, cause: _ } => PersistRefusedNotCaptured + LegacyBaselineObservedTransportRefused { refusal: _ } => PersistRefusedNotCaptured + } +} + +fn persisted_against_requested( + persisted: PersistedLegacyBaseline, + requested: GitObjectId +) -> Bool { + git_object_id_eq(left: persisted.capture.base_commit, right: requested) +} + +type PreCutBasePin + = PreCutBaseUnpinned + | PreCutBasePinned { base: GitObjectId } + +fn current_pre_cut_base_pin() -> PreCutBasePin { + PreCutBaseUnpinned +} + +fn persisted_enrollment_outstanding( + pin: PreCutBasePin, + held: PersistedLegacyBaseline? +) -> List { + match pin { + PreCutBaseUnpinned => + ["pre-cut base is unpinned; enrolment cannot bind a capture to an unnamed HEAD"] + PreCutBasePinned { base: b } => + match held { + Absent => + ["no LegacyBaselineCapture is held whose base_commit equals the pinned pre-cut base"] + Present { value: p } => + if persisted_against_requested(persisted: p, requested: b) { + [] + } else { + ["held capture.base_commit is not the pinned pre-cut base; relabel refused"] + } + } + } +} + +fn persisted_legacy_baseline_outstanding() -> List { + persisted_enrollment_outstanding( + pin: current_pre_cut_base_pin(), + held: none + ) +} diff --git a/src/v2/workflow/legacy_repair_observation.dag b/src/v2/workflow/legacy_repair_observation.dag index ef6f81bf795..bc66553d809 100644 --- a/src/v2/workflow/legacy_repair_observation.dag +++ b/src/v2/workflow/legacy_repair_observation.dag @@ -356,9 +356,32 @@ type CompleteLegacyRepairObservation sole_constructor { observation: LegacyRepairObservation } +type LegacyRepairSubjectField + = RepairSemanticSourceDigestField + | RepairSourceSetDigestField + | RepairCompilerArtifactDigestField + | RepairerIdentityModulePathField + | RepairerIdentityDeclNameField + | RepairerIdentityFieldField + | RepairSiteRosterDigestField + | ResolutionRegistryDigestField + +fn repair_subject_field_label(f: LegacyRepairSubjectField) -> NonEmptyStr { + match f { + RepairSemanticSourceDigestField => "semantic_source_digest" as NonEmptyStr + RepairSourceSetDigestField => "source_set_digest" as NonEmptyStr + RepairCompilerArtifactDigestField => "compiler_artifact_digest" as NonEmptyStr + RepairerIdentityModulePathField => "repairer_identity.module_path" as NonEmptyStr + RepairerIdentityDeclNameField => "repairer_identity.decl_name" as NonEmptyStr + RepairerIdentityFieldField => "repairer_identity.field" as NonEmptyStr + RepairSiteRosterDigestField => "repair_site_roster_digest" as NonEmptyStr + ResolutionRegistryDigestField => "resolution_registry_digest" as NonEmptyStr + } +} + type LegacyRepairAdmission = RepairObservationAdmitted { admitted: CompleteLegacyRepairObservation } - | RepairObservationSubjectDiverged { field: String } + | RepairObservationSubjectDiverged { field: LegacyRepairSubjectField } | RepairObservationRefused { completeness: ObservationCompleteness } // THE OBSERVATION'S OWN SUBJECT MUST BE THE PROVEN ONE, AND THAT IS WHY THE CARRIER HOLDS BOTH. @@ -407,28 +430,28 @@ fn admit_over_proven_subject( // spelled its own. type LegacyRepairSubjectApplicability = LegacyRepairSubjectApplicable - | LegacyRepairSubjectDiverged { field: String } + | LegacyRepairSubjectDiverged { field: LegacyRepairSubjectField } fn legacy_repair_subject_applicability( left: LegacyRepairObservationSubject, right: LegacyRepairObservationSubject ) -> LegacyRepairSubjectApplicability { if left.semantic_source_digest.digest != right.semantic_source_digest.digest { - LegacyRepairSubjectDiverged { field: "semantic_source_digest" } + LegacyRepairSubjectDiverged { field: RepairSemanticSourceDigestField } } else if left.source_set_digest.digest != right.source_set_digest.digest { - LegacyRepairSubjectDiverged { field: "source_set_digest" } + LegacyRepairSubjectDiverged { field: RepairSourceSetDigestField } } else if left.compiler_artifact_digest.digest != right.compiler_artifact_digest.digest { - LegacyRepairSubjectDiverged { field: "compiler_artifact_digest" } + LegacyRepairSubjectDiverged { field: RepairCompilerArtifactDigestField } } else if left.repairer_identity.module_path != right.repairer_identity.module_path { - LegacyRepairSubjectDiverged { field: "repairer_identity.module_path" } + LegacyRepairSubjectDiverged { field: RepairerIdentityModulePathField } } else if left.repairer_identity.decl_name != right.repairer_identity.decl_name { - LegacyRepairSubjectDiverged { field: "repairer_identity.decl_name" } + LegacyRepairSubjectDiverged { field: RepairerIdentityDeclNameField } } else if !decl_field_eq(a: left.repairer_identity.field, b: right.repairer_identity.field) { - LegacyRepairSubjectDiverged { field: "repairer_identity.field" } + LegacyRepairSubjectDiverged { field: RepairerIdentityFieldField } } else if left.repair_site_roster_digest.digest != right.repair_site_roster_digest.digest { - LegacyRepairSubjectDiverged { field: "repair_site_roster_digest" } + LegacyRepairSubjectDiverged { field: RepairSiteRosterDigestField } } else if left.resolution_registry_digest.digest != right.resolution_registry_digest.digest { - LegacyRepairSubjectDiverged { field: "resolution_registry_digest" } + LegacyRepairSubjectDiverged { field: ResolutionRegistryDigestField } } else { LegacyRepairSubjectApplicable } diff --git a/src/v2/workflow/legacy_repair_tap.dag b/src/v2/workflow/legacy_repair_tap.dag new file mode 100644 index 00000000000..54048b73810 --- /dev/null +++ b/src/v2/workflow/legacy_repair_tap.dag @@ -0,0 +1,213 @@ +module v2.workflow.legacy_repair_tap + +import std.types { String, List, Bool, Int, NonEmptyStr, list_length } +import std.decl_ref { decl_ref } +import std.occurrence_identity { + ValidatedOccurrenceTransport, + OccurrenceTransport, + OccurrenceId +} +import v2.workflow.legacy_repair_observation { + RepairSite, + RepairSiteRoster, + LegacyRepairObservation, + LegacyRepairObservationRow, + LegacyRepairObservationSubject, + repair_site_roster_identity +} +import v2.workflow.legacy_binding_observation { + LegacyBindingObservation, + LegacyBindingObservationRow, + LegacyBindingObservationSubject +} +import v2.workflow.legacy_baseline_capture { + CheckoutMaterialization, + TreeDerivedSubjectReceipt, + capture_legacy_baseline, + capture_legacy_baseline_from_observed_transport +} +import tools.reference_occurrence_binding_census { + ReferenceOccurrenceBindingRow, + ReferenceOccurrenceBindingDisposition +} +import gunbc.reference_derived_candidate { + ReferenceDerivedCandidateDisposition, + ReferenceDerivedCandidateRow +} +import gunbc.namespace_cut_subject_roster { + NamespaceCutSubjectIdentity, + subjects_deleted_at +} +import gunbc.namespace_cut_stage { StageXL6AtomicCutover } +import v2.workflow.legacy_baseline_persisted_observation { + persist_legacy_baseline, + PersistAdmission, + PersistRefusedNotCaptured +} + +// XL-1 LIVE REPAIR TAP. Sole consumer of the seed builtin emit_rust_reference_derived_rows_bridge. +// Roster-from-same-rows is a declared tautology (parent 2026-09-12): checkable, not structurally +// independent of answering. The arm is never enrolled on a required-floor path; one offline run +// per pinned base stores the observation. Deleted with v1.compiler.emit_rust / the interpreter. + +type Xl1PrimaryRootTap + = Xl1PrimaryRootObserved { + primary_root: String + repair_rows: List + occurrence_transport: OccurrenceTransport + binding_rows: List + } + | Xl1PrimaryRootRefused { cause: String } + +fn xl1_primary_root_cut_subjects() -> List { + subjects_deleted_at(stage: StageXL6AtomicCutover) +} + +fn repair_site_from_row(row: ReferenceDerivedCandidateRow) -> RepairSite? { + if row.module_name == "" || row.name == "" { + none + } else { + Present { + value: RepairSite { + module_name: row.module_name as NonEmptyStr, + name: row.name as NonEmptyStr + } + } + } +} + +fn append_site_from_row( + acc: List, + row: ReferenceDerivedCandidateRow +) -> List { + match repair_site_from_row(row: row) { + Absent => acc + Present { value: site } => concat(acc, [site]) + } +} + +fn repair_roster_from_bridge_rows(rows: List) -> RepairSiteRoster { + RepairSiteRoster { sites: fold(rows, init: [], f: append_site_from_row) } +} + +fn append_observation_row( + acc: List>, + row: ReferenceDerivedCandidateRow +) -> List> { + match repair_site_from_row(row: row) { + Absent => acc + Present { value: site } => concat(acc, [LegacyRepairObservationRow { site: site, outcome: row.disposition }]) + } +} + +fn repair_observation_from_bridge_rows( + rows: List, + tree: LegacyBindingObservationSubject +) -> LegacyRepairObservation { + let roster = repair_roster_from_bridge_rows(rows: rows) + LegacyRepairObservation { + subject: LegacyRepairObservationSubject { + semantic_source_digest: tree.semantic_source_digest, + source_set_digest: tree.source_set_digest, + compiler_artifact_digest: tree.compiler_artifact_digest, + repairer_identity: decl_ref(module_path: "v1.compiler.emit_rust", decl_name: "emit_rust_reference_derived_rows"), + repair_site_roster_digest: repair_site_roster_identity(roster: roster), + resolution_registry_digest: tree.declaration_index_digest + }, + rows: fold(rows, init: [], f: append_observation_row) + } +} + +fn persist_capture_from_bridge_rows( + materialization: CheckoutMaterialization, + tree_subject: TreeDerivedSubjectReceipt, + observation: LegacyBindingObservation, + transport: ValidatedOccurrenceTransport, + rows: List +) -> PersistAdmission { + persist_legacy_baseline( + outcome: capture_legacy_baseline( + materialization: materialization, + tree_subject: tree_subject, + observation: observation, + transport: transport, + repair_observation: repair_observation_from_bridge_rows(rows: rows, tree: tree_subject.subject), + repair_roster: repair_roster_from_bridge_rows(rows: rows) + ) + ) +} + +fn binding_observation_from_tap_rows( + subject: LegacyBindingObservationSubject, + rows: List +) -> LegacyBindingObservation { + LegacyBindingObservation { + subject: subject, + rows: rows |> map(r => LegacyBindingObservationRow { + occurrence: OccurrenceId { value: r.occurrence }, + outcome: r.disposition + }) + } +} + +// THE NAMED-BASE CAPTURE ENTRY. CheckoutMaterialization.requested is the GitObjectId the capture +// will bind; the tap is the only producer of live repair rows and of the occurrence transport those +// rows were taken with. Caller-supplied binding observations are not this entry: they can mint +// without the tap. persist_capture_from_bridge_rows is the fixture injection (validated transport +// plus rows, no live builtin). Empty source_roots refuse inside the seed arm. +fn persist_named_base_from_primary_root_tap( + materialization: CheckoutMaterialization, + tree_subject: TreeDerivedSubjectReceipt, + source_roots: List +) -> PersistAdmission { + match emit_rust_reference_derived_rows_bridge(source_roots) { + Xl1PrimaryRootRefused { cause: _ } => PersistRefusedNotCaptured + Xl1PrimaryRootObserved { + repair_rows: rows, + occurrence_transport: ot, + binding_rows: bindings, + primary_root: _ + } => + persist_legacy_baseline( + outcome: capture_legacy_baseline_from_observed_transport( + materialization: materialization, + tree_subject: tree_subject, + observation: binding_observation_from_tap_rows(subject: tree_subject.subject, rows: bindings), + observed_transport: ot, + repair_observation: repair_observation_from_bridge_rows(rows: rows, tree: tree_subject.subject), + repair_roster: repair_roster_from_bridge_rows(rows: rows) + ) + ) + } +} + +fn append_unique_module(acc: List, n: String) -> List { + if n == "" || (acc |> any(x => x == n)) { + acc + } else { + concat(acc, [n]) + } +} + +fn repair_emitted_module_names(rows: List) -> List { + fold(rows, init: [], f: (acc, row) => append_unique_module(acc: acc, n: row.module_name)) +} + +fn never_emitted_declared_modules( + declared_modules: List, + emitted_modules: List +) -> List { + declared_modules |> filter(d => !(emitted_modules |> any(e => e == d))) +} + +type Xl1LiveRepairTapCensus + = Xl1LiveRepairTapRows { count: Int } + | Xl1LiveRepairTapUnavailable { cause: String } + +fn xl1_live_repair_tap_census(source_roots: List) -> Xl1LiveRepairTapCensus { + match emit_rust_reference_derived_rows_bridge(source_roots) { + Xl1PrimaryRootRefused { cause: c } => Xl1LiveRepairTapUnavailable { cause: c } + Xl1PrimaryRootObserved { repair_rows: rows, primary_root: _, occurrence_transport: _, binding_rows: _ } => + Xl1LiveRepairTapRows { count: list_length(items: rows) } + } +}