Skip to main content

xlog_prob/
epistemic_production.rs

1//! Production GPU exact-path adapter for accepted epistemic evidence.
2//!
3//! This module is intentionally thin. It gates probabilistic execution on
4//! accepted world-view evidence, then routes into the existing GPU-native exact
5//! provenance path instead of using the bounded epistemic fixture circuit.
6
7#[cfg(feature = "host-io")]
8use std::collections::BTreeMap;
9use std::collections::BTreeSet;
10use std::sync::Arc;
11#[cfg(feature = "host-io")]
12use std::sync::{Mutex, MutexGuard};
13
14use xlog_core::{symbol, Result, XlogError};
15use xlog_cuda::CudaKernelProvider;
16use xlog_ir::EirEpistemicMode;
17#[cfg(feature = "host-io")]
18use xlog_logic::ast::ProbEngine;
19use xlog_logic::ast::{Atom, Evidence, Program, Term};
20use xlog_logic::parse_program;
21use xlog_runtime::{EpistemicGpuBatchExecutionResult, EpistemicGpuExecutionResult};
22
23use crate::compilation::{encode_cnf_gpu, GpuPirGraph, GpuPirRoots};
24#[cfg(feature = "host-io")]
25use crate::epistemic::EpistemicAssumptionKind;
26use crate::epistemic::EpistemicEvidenceTerm;
27use crate::epistemic::{
28    AcceptedWorldViewEvidence, CircuitUpdate, CircuitUpdateMode, EpistemicAssumption,
29    EpistemicCircuit,
30};
31#[cfg(feature = "host-io")]
32use crate::exact::ExactProgramOrigin;
33#[cfg(feature = "host-io")]
34use crate::exact::{ExactCircuitWitness, ExactResult, ExactResultWithGrads, ProbVarInfo};
35use crate::exact::{ExactDdnnfProgram, GpuConfig};
36use crate::pir::{PirNode, PirNodeId};
37#[cfg(feature = "host-io")]
38use crate::provenance::AggregateLiftStatus;
39use crate::provenance::Value;
40use crate::provenance::{extract_from_program, Provenance};
41
42macro_rules! epistemic_prob_trace_transaction {
43    ($adapter:ident, $body:block) => {{
44        let trace_before = $adapter.trace;
45        let result: Result<_> = (|| $body)();
46        match result {
47            Ok(value) => Ok(value),
48            Err(err) => {
49                $adapter.trace = trace_before;
50                Err(err)
51            }
52        }
53    }};
54}
55
56macro_rules! checked_prob_trace_counter_inc {
57    ($adapter:ident, $field:ident) => {{
58        $adapter.trace.$field = EpistemicProbProductionAdapter::checked_trace_counter_add(
59            $adapter.trace.$field,
60            1,
61            stringify!($field),
62        )?;
63    }};
64}
65
66/// Production capability status for probabilistic adapter paths.
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
68pub enum EpistemicProbProductionCapabilityStatus {
69    /// Existing GPU-native production path is available.
70    Available,
71    /// Required GPU-native production path is not implemented.
72    Blocked,
73}
74
75/// Capability report for the probabilistic production adapter.
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub struct EpistemicProbProductionCapabilities {
78    /// Exact/provenance compilation through `ExactDdnnfProgram`.
79    pub gpu_exact_provenance: EpistemicProbProductionCapabilityStatus,
80    /// GPU PIR upload and CNF encoding path.
81    pub gpu_pir_cnf: EpistemicProbProductionCapabilityStatus,
82    /// Bounded compile-plus-evaluate knowledge-compilation path.
83    pub gpu_knowledge_compilation: EpistemicProbProductionCapabilityStatus,
84    /// GPU query and gradient evaluation path.
85    pub gpu_exact_query_and_gradient: EpistemicProbProductionCapabilityStatus,
86    /// Whether the bounded fixture circuit may satisfy production metrics.
87    pub fixture_circuit_allowed: bool,
88    /// Blocker reason for knowledge-compilation production coverage, or empty when available.
89    pub gpu_knowledge_compilation_blocker: &'static str,
90}
91
92/// Return a static inventory of implemented probabilistic backend stages.
93///
94/// This does not probe CUDA availability, reflect Cargo feature selection, or
95/// assert that every epistemic execution route produces a compatible evidence
96/// record.
97pub fn production_capabilities() -> EpistemicProbProductionCapabilities {
98    EpistemicProbProductionCapabilities {
99        gpu_exact_provenance: EpistemicProbProductionCapabilityStatus::Available,
100        gpu_pir_cnf: EpistemicProbProductionCapabilityStatus::Available,
101        gpu_knowledge_compilation: EpistemicProbProductionCapabilityStatus::Available,
102        gpu_exact_query_and_gradient: EpistemicProbProductionCapabilityStatus::Available,
103        fixture_circuit_allowed: false,
104        gpu_knowledge_compilation_blocker: "",
105    }
106}
107
108/// Trace counters proving the production adapter stayed on the GPU exact path.
109#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
110pub struct EpistemicProbProductionTrace {
111    /// Number of source compiles routed through `ExactDdnnfProgram`.
112    pub gpu_exact_source_compiles: u64,
113    /// Number of parsed-program compiles routed through `ExactDdnnfProgram`.
114    pub gpu_exact_program_compiles: u64,
115    /// Number of evaluations routed through an already compiled conditioned circuit.
116    pub gpu_conditioned_circuit_reuses: u64,
117    /// Actual GPU circuit-compiler invocations performed while preparing this handle.
118    pub gpu_conditioned_circuit_preparation_compiles: u64,
119    /// Successful exact-circuit materializations performed while preparing this handle.
120    pub gpu_conditioned_circuit_materializations: u64,
121    /// Verified disk-cache restorations used while preparing this handle.
122    pub gpu_conditioned_circuit_disk_cache_restores: u64,
123    /// GPU circuit-cache hits used while preparing this handle.
124    pub gpu_conditioned_circuit_gpu_cache_hits: u64,
125    /// Process-local immutable generation of the exact circuit used by this evaluation.
126    pub gpu_conditioned_circuit_generation: u64,
127    /// Device-cache slot held by the exact circuit used by this evaluation.
128    pub gpu_conditioned_circuit_cache_slot: u64,
129    /// Number of accepted world-view evidence objects consumed as a gate.
130    pub accepted_world_view_evidence_consumed: u64,
131    /// Number of accepted Gelfond-1991 compatibility-mode GPU world-view
132    /// evidence objects consumed as a gate.
133    pub accepted_g91_world_view_evidence_consumed: u64,
134    /// Number of accepted FAEEL GPU world-view evidence objects consumed as a gate.
135    pub accepted_faeel_world_view_evidence_consumed: u64,
136    /// Number of accepted epistemic assumptions consumed from world-view evidence.
137    pub accepted_evidence_assumptions_consumed: u64,
138    /// Number of accepted nonzero-arity epistemic assumptions consumed from GPU evidence.
139    pub accepted_gpu_nonzero_arity_evidence_assumptions_consumed: u64,
140    /// Maximum accepted GPU evidence tuple arity consumed by this adapter.
141    pub accepted_gpu_max_evidence_arity_consumed: u32,
142    /// GPU tuple-key column reads consumed from accepted world-view evidence.
143    pub accepted_gpu_tuple_key_column_reads_consumed: u64,
144    /// GPU final-tuple row filters consumed from accepted world-view evidence.
145    pub accepted_gpu_final_tuple_row_filters_consumed: u64,
146    /// Negated GPU final-tuple row filters consumed from accepted world-view evidence.
147    pub accepted_gpu_final_tuple_negated_row_filters_consumed: u64,
148    /// Row-specific GPU model-slot capacity consumed from accepted world-view evidence.
149    pub accepted_gpu_row_specific_membership_row_capacity_consumed: u64,
150    /// Fallback GPU row-filter capacity consumed outside bounded model-slot windows.
151    pub accepted_gpu_row_filter_fallback_row_capacity_consumed: u64,
152    /// Reduced integrity-constraint relations checked by accepted GPU evidence.
153    pub accepted_gpu_constraint_relations_checked_consumed: u64,
154    /// Constraint row-count metadata reads consumed from accepted GPU evidence.
155    pub accepted_gpu_constraint_row_count_device_reads_consumed: u64,
156    /// Number of accepted GPU batch evidence records consumed as a gate.
157    pub accepted_gpu_batch_evidence_consumed: u64,
158    /// Number of accepted GPU batch components consumed as individual evidence records.
159    pub accepted_gpu_batch_component_evidence_consumed: u64,
160    /// Number of accepted evidence applications that updated caller-owned incremental circuits.
161    ///
162    /// This is fixture coverage only and is intentionally excluded from production path events.
163    pub accepted_incremental_circuit_updates: u64,
164    /// Number of GPU exact query evaluations routed through `ExactDdnnfProgram`.
165    pub gpu_exact_query_evaluations: u64,
166    /// Number of source GPU exact query evaluations routed through `ExactDdnnfProgram`.
167    pub gpu_source_exact_query_evaluations: u64,
168    /// Number of parsed-program GPU exact query evaluations routed through `ExactDdnnfProgram`.
169    pub gpu_program_exact_query_evaluations: u64,
170    /// Number of GPU gradient evaluations routed through `ExactDdnnfProgram`.
171    pub gpu_exact_gradient_evaluations: u64,
172    /// Number of source GPU gradient evaluations routed through `ExactDdnnfProgram`.
173    pub gpu_source_exact_gradient_evaluations: u64,
174    /// Number of parsed-program GPU gradient evaluations routed through `ExactDdnnfProgram`.
175    pub gpu_program_exact_gradient_evaluations: u64,
176    /// Number of source-conditioned GPU gradient evaluations routed through `ExactDdnnfProgram`.
177    pub gpu_source_conditioned_gradient_evaluations: u64,
178    /// Number of parsed-program-conditioned GPU gradient evaluations routed through `ExactDdnnfProgram`.
179    pub gpu_program_conditioned_gradient_evaluations: u64,
180    /// Number of accepted PIR graphs uploaded through the existing GPU PIR layout.
181    pub gpu_pir_graph_uploads: u64,
182    /// Number of source accepted PIR graphs uploaded through the existing GPU PIR layout.
183    pub gpu_source_pir_graph_uploads: u64,
184    /// Number of parsed-program accepted PIR graphs uploaded through the existing GPU PIR layout.
185    pub gpu_program_pir_graph_uploads: u64,
186    /// Number of accepted PIR root sets encoded through the existing GPU CNF encoder.
187    pub gpu_cnf_encodes: u64,
188    /// Number of source accepted PIR root sets encoded through the existing GPU CNF encoder.
189    pub gpu_source_cnf_encodes: u64,
190    /// Number of parsed-program accepted PIR root sets encoded through the existing GPU CNF encoder.
191    pub gpu_program_cnf_encodes: u64,
192    /// Number of accepted compile-and-evaluate runs through the GPU exact path.
193    pub gpu_knowledge_compilation_end_to_end_runs: u64,
194    /// GPU exact/provenance/PIR/CNF/knowledge-compilation events that occurred inside accepted evidence gates.
195    pub accepted_gpu_production_path_events: u64,
196    /// Number of accepted source compile-and-evaluate runs through the GPU exact path.
197    pub gpu_source_knowledge_compilation_end_to_end_runs: u64,
198    /// Number of accepted parsed-program compile-and-evaluate runs through the GPU exact path.
199    pub gpu_program_knowledge_compilation_end_to_end_runs: u64,
200    /// Number of accepted assumptions compiled as exact evidence facts.
201    pub gpu_conditioned_evidence_facts: u64,
202    /// Number of accepted world-view evidence objects compiled into conditioned exact evidence.
203    pub accepted_conditioned_world_view_evidence_consumed: u64,
204    /// Number of source-conditioned accepted world-view evidence objects compiled as exact evidence.
205    pub accepted_source_conditioned_world_view_evidence_consumed: u64,
206    /// Number of parsed-program-conditioned accepted world-view evidence objects compiled as exact evidence.
207    pub accepted_program_conditioned_world_view_evidence_consumed: u64,
208    /// Number of accepted nonzero-arity assumptions compiled as exact evidence facts.
209    pub gpu_conditioned_nonzero_arity_evidence_facts: u64,
210    /// Maximum accepted exact evidence tuple arity observed across conditioned paths.
211    pub gpu_conditioned_max_evidence_arity: u32,
212    /// Number of false accepted assumptions compiled as exact evidence facts.
213    pub gpu_conditioned_negative_evidence_facts: u64,
214    /// Number of source-conditioned accepted assumptions compiled as exact evidence facts.
215    pub gpu_source_conditioned_evidence_facts: u64,
216    /// Number of source-conditioned nonzero-arity assumptions compiled as exact evidence facts.
217    pub gpu_source_conditioned_nonzero_arity_evidence_facts: u64,
218    /// Maximum source-conditioned accepted exact evidence tuple arity observed.
219    pub gpu_source_conditioned_max_evidence_arity: u32,
220    /// Number of parsed-program-conditioned accepted assumptions compiled as exact evidence facts.
221    pub gpu_program_conditioned_evidence_facts: u64,
222    /// Number of parsed-program-conditioned nonzero-arity assumptions compiled as exact evidence facts.
223    pub gpu_program_conditioned_nonzero_arity_evidence_facts: u64,
224    /// Maximum parsed-program-conditioned accepted exact evidence tuple arity observed.
225    pub gpu_program_conditioned_max_evidence_arity: u32,
226    /// Number of false source-conditioned assumptions compiled as exact evidence facts.
227    pub gpu_source_conditioned_negative_evidence_facts: u64,
228    /// Number of false parsed-program-conditioned assumptions compiled as exact evidence facts.
229    pub gpu_program_conditioned_negative_evidence_facts: u64,
230    /// Number of true `know` assumptions compiled as exact evidence facts.
231    pub gpu_conditioned_know_evidence_facts: u64,
232    /// Number of true `possible` assumptions compiled as exact evidence facts.
233    pub gpu_conditioned_possible_evidence_facts: u64,
234    /// Number of false `know` assumptions compiled as exact evidence facts.
235    pub gpu_conditioned_not_known_evidence_facts: u64,
236    /// Number of false `possible` assumptions compiled as exact evidence facts.
237    pub gpu_conditioned_not_possible_evidence_facts: u64,
238    /// Number of source-conditioned true `know` assumptions compiled as exact evidence facts.
239    pub gpu_source_conditioned_know_evidence_facts: u64,
240    /// Number of source-conditioned true `possible` assumptions compiled as exact evidence facts.
241    pub gpu_source_conditioned_possible_evidence_facts: u64,
242    /// Number of source-conditioned false `know` assumptions compiled as exact evidence facts.
243    pub gpu_source_conditioned_not_known_evidence_facts: u64,
244    /// Number of source-conditioned false `possible` assumptions compiled as exact evidence facts.
245    pub gpu_source_conditioned_not_possible_evidence_facts: u64,
246    /// Number of parsed-program-conditioned true `know` assumptions compiled as exact evidence facts.
247    pub gpu_program_conditioned_know_evidence_facts: u64,
248    /// Number of parsed-program-conditioned true `possible` assumptions compiled as exact evidence facts.
249    pub gpu_program_conditioned_possible_evidence_facts: u64,
250    /// Number of parsed-program-conditioned false `know` assumptions compiled as exact evidence facts.
251    pub gpu_program_conditioned_not_known_evidence_facts: u64,
252    /// Number of parsed-program-conditioned false `possible` assumptions compiled as exact evidence facts.
253    pub gpu_program_conditioned_not_possible_evidence_facts: u64,
254}
255
256impl EpistemicProbProductionTrace {
257    fn checked_gpu_production_path_events(&self) -> Result<u64> {
258        Self::checked_production_event_sum(
259            "gpu_production_path_events",
260            &[
261                self.gpu_exact_source_compiles,
262                self.gpu_exact_program_compiles,
263                self.gpu_conditioned_circuit_reuses,
264                self.gpu_exact_query_evaluations,
265                self.gpu_source_exact_query_evaluations,
266                self.gpu_program_exact_query_evaluations,
267                self.gpu_exact_gradient_evaluations,
268                self.gpu_source_exact_gradient_evaluations,
269                self.gpu_program_exact_gradient_evaluations,
270                self.gpu_source_conditioned_gradient_evaluations,
271                self.gpu_program_conditioned_gradient_evaluations,
272                self.gpu_pir_graph_uploads,
273                self.gpu_source_pir_graph_uploads,
274                self.gpu_program_pir_graph_uploads,
275                self.gpu_cnf_encodes,
276                self.gpu_source_cnf_encodes,
277                self.gpu_program_cnf_encodes,
278                self.gpu_knowledge_compilation_end_to_end_runs,
279                self.gpu_source_knowledge_compilation_end_to_end_runs,
280                self.gpu_program_knowledge_compilation_end_to_end_runs,
281            ],
282        )
283    }
284
285    fn checked_production_event_sum(counter: &str, values: &[u64]) -> Result<u64> {
286        values.iter().try_fold(0u64, |acc, value| {
287            acc.checked_add(*value)
288                .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
289                    construct: "epistemic probabilistic production trace accounting".to_string(),
290                    context: format!(
291                        "GPU probability production counter {counter} overflowed while adding \
292                         {value} to {acc}"
293                    ),
294                })
295        })
296    }
297
298    fn require_pir_cnf_accounting_pair(
299        construct: &'static str,
300        pir_graph_uploads: u64,
301        cnf_encodes: u64,
302        path: &'static str,
303    ) -> Result<()> {
304        if pir_graph_uploads != cnf_encodes {
305            return Err(XlogError::UnsupportedEpistemicConstruct {
306                construct: construct.to_string(),
307                context: format!(
308                    "PIR/CNF production accounting must match for {path} path, got \
309                     pir_graph_uploads={} cnf_encodes={}",
310                    pir_graph_uploads, cnf_encodes
311                ),
312            });
313        }
314        Ok(())
315    }
316
317    fn require_pir_cnf_accounting(&self) -> Result<()> {
318        let construct = "epistemic probabilistic production metric gate";
319        Self::require_pir_cnf_accounting_pair(
320            construct,
321            self.gpu_pir_graph_uploads,
322            self.gpu_cnf_encodes,
323            "aggregate",
324        )?;
325        Self::require_pir_cnf_accounting_pair(
326            construct,
327            self.gpu_source_pir_graph_uploads,
328            self.gpu_source_cnf_encodes,
329            "source",
330        )?;
331        Self::require_pir_cnf_accounting_pair(
332            construct,
333            self.gpu_program_pir_graph_uploads,
334            self.gpu_program_cnf_encodes,
335            "program",
336        )
337    }
338
339    /// Require internally consistent GPU tuple-membership evidence counters.
340    pub fn require_accepted_gpu_tuple_evidence_trace(&self) -> Result<()> {
341        if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
342            > self.accepted_evidence_assumptions_consumed
343        {
344            return Err(XlogError::UnsupportedEpistemicConstruct {
345                construct: "epistemic probabilistic production metric gate".to_string(),
346                context: format!(
347                    "accepted nonzero-arity evidence assumptions cannot exceed accepted \
348                     evidence assumptions: nonzero={} total={}",
349                    self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
350                    self.accepted_evidence_assumptions_consumed
351                ),
352            });
353        }
354        if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed == 0
355            && self.accepted_gpu_max_evidence_arity_consumed > 0
356        {
357            return Err(XlogError::UnsupportedEpistemicConstruct {
358                construct: "epistemic probabilistic production metric gate".to_string(),
359                context: format!(
360                    "accepted max evidence arity {} requires at least one accepted \
361                     nonzero-arity GPU evidence assumption",
362                    self.accepted_gpu_max_evidence_arity_consumed
363                ),
364            });
365        }
366        if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed > 0
367            && self.accepted_gpu_max_evidence_arity_consumed == 0
368        {
369            return Err(XlogError::UnsupportedEpistemicConstruct {
370                construct: "epistemic probabilistic production metric gate".to_string(),
371                context: format!(
372                    "accepted nonzero-arity GPU evidence requires accepted max evidence arity, \
373                     got nonzero_assumptions={} max_arity=0",
374                    self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
375                ),
376            });
377        }
378        if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed == 0
379            && self.accepted_gpu_tuple_key_column_reads_consumed != 0
380        {
381            return Err(XlogError::UnsupportedEpistemicConstruct {
382                construct: "epistemic probabilistic production metric gate".to_string(),
383                context: format!(
384                    "accepted tuple-key reads require accepted nonzero-arity GPU evidence, got \
385                     nonzero_assumptions=0 tuple_key_reads={}",
386                    self.accepted_gpu_tuple_key_column_reads_consumed
387                ),
388            });
389        }
390        if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed > 0
391            && self.accepted_gpu_tuple_key_column_reads_consumed == 0
392        {
393            return Err(XlogError::UnsupportedEpistemicConstruct {
394                construct: "epistemic probabilistic production metric gate".to_string(),
395                context: format!(
396                    "accepted nonzero-arity GPU evidence requires tuple-key device column reads, \
397                     got nonzero_assumptions={} tuple_key_reads=0",
398                    self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
399                ),
400            });
401        }
402        if self.accepted_gpu_final_tuple_negated_row_filters_consumed
403            > self.accepted_gpu_final_tuple_row_filters_consumed
404        {
405            return Err(XlogError::UnsupportedEpistemicConstruct {
406                construct: "epistemic probabilistic production metric gate".to_string(),
407                context: format!(
408                    "accepted negated final-tuple row filters cannot exceed total row filters: \
409                     negated={} total={}",
410                    self.accepted_gpu_final_tuple_negated_row_filters_consumed,
411                    self.accepted_gpu_final_tuple_row_filters_consumed
412                ),
413            });
414        }
415        if self.accepted_gpu_final_tuple_row_filters_consumed == 0
416            && (self.accepted_gpu_row_specific_membership_row_capacity_consumed != 0
417                || self.accepted_gpu_row_filter_fallback_row_capacity_consumed != 0)
418        {
419            return Err(XlogError::UnsupportedEpistemicConstruct {
420                construct: "epistemic probabilistic production metric gate".to_string(),
421                context: format!(
422                    "accepted row-specific/fallback tuple capacity requires accepted GPU row \
423                     filters, got row_filters=0 row_specific_capacity={} fallback_capacity={}",
424                    self.accepted_gpu_row_specific_membership_row_capacity_consumed,
425                    self.accepted_gpu_row_filter_fallback_row_capacity_consumed
426                ),
427            });
428        }
429        if self.accepted_gpu_final_tuple_row_filters_consumed > 0
430            && self.accepted_gpu_row_specific_membership_row_capacity_consumed == 0
431        {
432            return Err(XlogError::UnsupportedEpistemicConstruct {
433                construct: "epistemic probabilistic production metric gate".to_string(),
434                context: format!(
435                    "accepted GPU final-tuple row filters require row-specific model-slot \
436                     capacity, got row_filters={} row_specific_capacity=0",
437                    self.accepted_gpu_final_tuple_row_filters_consumed
438                ),
439            });
440        }
441        if self.accepted_gpu_constraint_row_count_device_reads_consumed
442            > self.accepted_gpu_constraint_relations_checked_consumed
443        {
444            return Err(XlogError::UnsupportedEpistemicConstruct {
445                construct: "epistemic probabilistic production metric gate".to_string(),
446                context: format!(
447                    "accepted constraint row-count device reads cannot exceed checked reduced \
448                     constraint relations, got reads={} checked={}",
449                    self.accepted_gpu_constraint_row_count_device_reads_consumed,
450                    self.accepted_gpu_constraint_relations_checked_consumed
451                ),
452            });
453        }
454        Ok(())
455    }
456
457    /// Require internally consistent accepted GPU world-view evidence counters.
458    pub fn require_accepted_gpu_world_view_evidence_trace(&self) -> Result<()> {
459        let mode_count = self
460            .accepted_g91_world_view_evidence_consumed
461            .checked_add(self.accepted_faeel_world_view_evidence_consumed)
462            .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
463                construct: "epistemic probabilistic production metric gate".to_string(),
464                context: "accepted GPU world-view mode counters overflowed".to_string(),
465            })?;
466        if self.accepted_world_view_evidence_consumed != 0
467            && mode_count != self.accepted_world_view_evidence_consumed
468        {
469            return Err(XlogError::UnsupportedEpistemicConstruct {
470                construct: "epistemic probabilistic production metric gate".to_string(),
471                context: format!(
472                    "accepted GPU world-view evidence must be classified by epistemic mode, got \
473                     evidence={} gelfond_1991={} faeel={}",
474                    self.accepted_world_view_evidence_consumed,
475                    self.accepted_g91_world_view_evidence_consumed,
476                    self.accepted_faeel_world_view_evidence_consumed
477                ),
478            });
479        }
480        if self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
481            > self.accepted_evidence_assumptions_consumed
482        {
483            return Err(XlogError::UnsupportedEpistemicConstruct {
484                construct: "epistemic probabilistic production metric gate".to_string(),
485                context: format!(
486                    "accepted nonzero-arity GPU evidence assumptions cannot exceed accepted \
487                     assumptions, got nonzero={} assumptions={}",
488                    self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
489                    self.accepted_evidence_assumptions_consumed
490                ),
491            });
492        }
493        if self.accepted_world_view_evidence_consumed != 0
494            && self.accepted_evidence_assumptions_consumed
495                < self.accepted_world_view_evidence_consumed
496        {
497            return Err(XlogError::UnsupportedEpistemicConstruct {
498                construct: "epistemic probabilistic production metric gate".to_string(),
499                context: format!(
500                    "accepted GPU world-view evidence requires at least one accepted epistemic \
501                     assumption per evidence record, got evidence={} assumptions={}",
502                    self.accepted_world_view_evidence_consumed,
503                    self.accepted_evidence_assumptions_consumed
504                ),
505            });
506        }
507        if self.accepted_gpu_batch_component_evidence_consumed
508            < self.accepted_gpu_batch_evidence_consumed
509        {
510            return Err(XlogError::UnsupportedEpistemicConstruct {
511                construct: "epistemic probabilistic production metric gate".to_string(),
512                context: format!(
513                    "accepted GPU batch component evidence must cover accepted batch evidence, \
514                     got batches={} components={}",
515                    self.accepted_gpu_batch_evidence_consumed,
516                    self.accepted_gpu_batch_component_evidence_consumed
517                ),
518            });
519        }
520        if self.accepted_gpu_batch_component_evidence_consumed
521            > self.accepted_world_view_evidence_consumed
522        {
523            return Err(XlogError::UnsupportedEpistemicConstruct {
524                construct: "epistemic probabilistic production metric gate".to_string(),
525                context: format!(
526                    "accepted GPU batch component evidence cannot exceed accepted world-view \
527                     evidence, got components={} evidence={}",
528                    self.accepted_gpu_batch_component_evidence_consumed,
529                    self.accepted_world_view_evidence_consumed
530                ),
531            });
532        }
533        if self.accepted_conditioned_world_view_evidence_consumed
534            > self.accepted_world_view_evidence_consumed
535        {
536            return Err(XlogError::UnsupportedEpistemicConstruct {
537                construct: "epistemic probabilistic production metric gate".to_string(),
538                context: format!(
539                    "accepted conditioned world-view evidence cannot exceed accepted world-view \
540                     evidence, got conditioned={} evidence={}",
541                    self.accepted_conditioned_world_view_evidence_consumed,
542                    self.accepted_world_view_evidence_consumed
543                ),
544            });
545        }
546        Ok(())
547    }
548
549    fn require_conditioned_counter_sum(
550        counter: &'static str,
551        aggregate: u64,
552        source: u64,
553        program: u64,
554    ) -> Result<()> {
555        let expected = source.checked_add(program).ok_or_else(|| {
556            XlogError::UnsupportedEpistemicConstruct {
557                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
558                context: format!(
559                    "conditioned evidence counter {counter} overflowed while adding source={} \
560                     program={}",
561                    source, program
562                ),
563            }
564        })?;
565        if aggregate != expected {
566            return Err(XlogError::UnsupportedEpistemicConstruct {
567                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
568                context: format!(
569                    "conditioned evidence counter {counter} must equal source+program, got \
570                     aggregate={} source={} program={}",
571                    aggregate, source, program
572                ),
573            });
574        }
575        Ok(())
576    }
577
578    fn require_gpu_path_counter_sum(
579        counter: &'static str,
580        aggregate: u64,
581        source: u64,
582        program: u64,
583    ) -> Result<()> {
584        let expected = source.checked_add(program).ok_or_else(|| {
585            XlogError::UnsupportedEpistemicConstruct {
586                construct: "epistemic probabilistic production metric gate".to_string(),
587                context: format!(
588                    "GPU production path counter {counter} overflowed while adding source={} \
589                     program={}",
590                    source, program
591                ),
592            }
593        })?;
594        if aggregate != expected {
595            return Err(XlogError::UnsupportedEpistemicConstruct {
596                construct: "epistemic probabilistic production metric gate".to_string(),
597                context: format!(
598                    "GPU production path accounting must match source+program for {counter}, \
599                     got aggregate={} source={} program={}",
600                    aggregate, source, program
601                ),
602            });
603        }
604        Ok(())
605    }
606
607    fn require_gpu_path_accounting(&self) -> Result<()> {
608        Self::require_gpu_path_counter_sum(
609            "exact_query_evaluations",
610            self.gpu_exact_query_evaluations,
611            self.gpu_source_exact_query_evaluations,
612            self.gpu_program_exact_query_evaluations,
613        )?;
614        Self::require_gpu_path_counter_sum(
615            "exact_gradient_evaluations",
616            self.gpu_exact_gradient_evaluations,
617            self.gpu_source_exact_gradient_evaluations,
618            self.gpu_program_exact_gradient_evaluations,
619        )?;
620        Self::require_gpu_path_counter_sum(
621            "pir_graph_uploads",
622            self.gpu_pir_graph_uploads,
623            self.gpu_source_pir_graph_uploads,
624            self.gpu_program_pir_graph_uploads,
625        )?;
626        Self::require_gpu_path_counter_sum(
627            "cnf_encodes",
628            self.gpu_cnf_encodes,
629            self.gpu_source_cnf_encodes,
630            self.gpu_program_cnf_encodes,
631        )?;
632        Self::require_gpu_path_counter_sum(
633            "knowledge_compilation_end_to_end_runs",
634            self.gpu_knowledge_compilation_end_to_end_runs,
635            self.gpu_source_knowledge_compilation_end_to_end_runs,
636            self.gpu_program_knowledge_compilation_end_to_end_runs,
637        )
638    }
639
640    /// Require internally consistent conditioned exact-evidence counters.
641    pub fn require_conditioned_evidence_trace(&self) -> Result<()> {
642        Self::require_conditioned_counter_sum(
643            "accepted_world_view_evidence",
644            self.accepted_conditioned_world_view_evidence_consumed,
645            self.accepted_source_conditioned_world_view_evidence_consumed,
646            self.accepted_program_conditioned_world_view_evidence_consumed,
647        )?;
648        Self::require_conditioned_counter_sum(
649            "evidence_facts",
650            self.gpu_conditioned_evidence_facts,
651            self.gpu_source_conditioned_evidence_facts,
652            self.gpu_program_conditioned_evidence_facts,
653        )?;
654        Self::require_conditioned_counter_sum(
655            "nonzero_arity_evidence_facts",
656            self.gpu_conditioned_nonzero_arity_evidence_facts,
657            self.gpu_source_conditioned_nonzero_arity_evidence_facts,
658            self.gpu_program_conditioned_nonzero_arity_evidence_facts,
659        )?;
660        Self::require_conditioned_counter_sum(
661            "negative_evidence_facts",
662            self.gpu_conditioned_negative_evidence_facts,
663            self.gpu_source_conditioned_negative_evidence_facts,
664            self.gpu_program_conditioned_negative_evidence_facts,
665        )?;
666        Self::require_conditioned_counter_sum(
667            "know_evidence_facts",
668            self.gpu_conditioned_know_evidence_facts,
669            self.gpu_source_conditioned_know_evidence_facts,
670            self.gpu_program_conditioned_know_evidence_facts,
671        )?;
672        Self::require_conditioned_counter_sum(
673            "possible_evidence_facts",
674            self.gpu_conditioned_possible_evidence_facts,
675            self.gpu_source_conditioned_possible_evidence_facts,
676            self.gpu_program_conditioned_possible_evidence_facts,
677        )?;
678        Self::require_conditioned_counter_sum(
679            "not_known_evidence_facts",
680            self.gpu_conditioned_not_known_evidence_facts,
681            self.gpu_source_conditioned_not_known_evidence_facts,
682            self.gpu_program_conditioned_not_known_evidence_facts,
683        )?;
684        Self::require_conditioned_counter_sum(
685            "not_possible_evidence_facts",
686            self.gpu_conditioned_not_possible_evidence_facts,
687            self.gpu_source_conditioned_not_possible_evidence_facts,
688            self.gpu_program_conditioned_not_possible_evidence_facts,
689        )?;
690
691        if (self.gpu_conditioned_evidence_facts != 0
692            && self.accepted_conditioned_world_view_evidence_consumed == 0)
693            || (self.gpu_source_conditioned_evidence_facts != 0
694                && self.accepted_source_conditioned_world_view_evidence_consumed == 0)
695            || (self.gpu_program_conditioned_evidence_facts != 0
696                && self.accepted_program_conditioned_world_view_evidence_consumed == 0)
697        {
698            return Err(XlogError::UnsupportedEpistemicConstruct {
699                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
700                context: format!(
701                    "conditioned exact evidence facts require accepted conditioned world-view \
702                     evidence, got facts={} evidence={} source_facts={} source_evidence={} \
703                     program_facts={} program_evidence={}",
704                    self.gpu_conditioned_evidence_facts,
705                    self.accepted_conditioned_world_view_evidence_consumed,
706                    self.gpu_source_conditioned_evidence_facts,
707                    self.accepted_source_conditioned_world_view_evidence_consumed,
708                    self.gpu_program_conditioned_evidence_facts,
709                    self.accepted_program_conditioned_world_view_evidence_consumed
710                ),
711            });
712        }
713
714        if self.gpu_conditioned_evidence_facts
715            < self.accepted_conditioned_world_view_evidence_consumed
716            || self.gpu_source_conditioned_evidence_facts
717                < self.accepted_source_conditioned_world_view_evidence_consumed
718            || self.gpu_program_conditioned_evidence_facts
719                < self.accepted_program_conditioned_world_view_evidence_consumed
720        {
721            return Err(XlogError::UnsupportedEpistemicConstruct {
722                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
723                context: format!(
724                    "conditioned exact evidence facts must cover each accepted conditioned \
725                     world-view evidence record, got facts={} evidence={} source_facts={} \
726                     source_evidence={} program_facts={} program_evidence={}",
727                    self.gpu_conditioned_evidence_facts,
728                    self.accepted_conditioned_world_view_evidence_consumed,
729                    self.gpu_source_conditioned_evidence_facts,
730                    self.accepted_source_conditioned_world_view_evidence_consumed,
731                    self.gpu_program_conditioned_evidence_facts,
732                    self.accepted_program_conditioned_world_view_evidence_consumed
733                ),
734            });
735        }
736
737        if self.gpu_conditioned_nonzero_arity_evidence_facts > self.gpu_conditioned_evidence_facts
738            || self.gpu_source_conditioned_nonzero_arity_evidence_facts
739                > self.gpu_source_conditioned_evidence_facts
740            || self.gpu_program_conditioned_nonzero_arity_evidence_facts
741                > self.gpu_program_conditioned_evidence_facts
742        {
743            return Err(XlogError::UnsupportedEpistemicConstruct {
744                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
745                context: format!(
746                    "conditioned nonzero-arity facts cannot exceed conditioned evidence facts: \
747                     nonzero={} total={} source_nonzero={} source_total={} program_nonzero={} \
748                     program_total={}",
749                    self.gpu_conditioned_nonzero_arity_evidence_facts,
750                    self.gpu_conditioned_evidence_facts,
751                    self.gpu_source_conditioned_nonzero_arity_evidence_facts,
752                    self.gpu_source_conditioned_evidence_facts,
753                    self.gpu_program_conditioned_nonzero_arity_evidence_facts,
754                    self.gpu_program_conditioned_evidence_facts
755                ),
756            });
757        }
758        if self.gpu_conditioned_negative_evidence_facts > self.gpu_conditioned_evidence_facts
759            || self.gpu_source_conditioned_negative_evidence_facts
760                > self.gpu_source_conditioned_evidence_facts
761            || self.gpu_program_conditioned_negative_evidence_facts
762                > self.gpu_program_conditioned_evidence_facts
763        {
764            return Err(XlogError::UnsupportedEpistemicConstruct {
765                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
766                context: format!(
767                    "conditioned negative facts cannot exceed conditioned evidence facts: \
768                     negative={} total={} source_negative={} source_total={} program_negative={} \
769                     program_total={}",
770                    self.gpu_conditioned_negative_evidence_facts,
771                    self.gpu_conditioned_evidence_facts,
772                    self.gpu_source_conditioned_negative_evidence_facts,
773                    self.gpu_source_conditioned_evidence_facts,
774                    self.gpu_program_conditioned_negative_evidence_facts,
775                    self.gpu_program_conditioned_evidence_facts
776                ),
777            });
778        }
779
780        let operator_fact_count = self
781            .gpu_conditioned_know_evidence_facts
782            .checked_add(self.gpu_conditioned_possible_evidence_facts)
783            .and_then(|sum| sum.checked_add(self.gpu_conditioned_not_known_evidence_facts))
784            .and_then(|sum| sum.checked_add(self.gpu_conditioned_not_possible_evidence_facts))
785            .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
786                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
787                context: "conditioned operator evidence fact counters overflowed".to_string(),
788            })?;
789        if operator_fact_count != self.gpu_conditioned_evidence_facts {
790            return Err(XlogError::UnsupportedEpistemicConstruct {
791                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
792                context: format!(
793                    "conditioned operator evidence facts must equal total evidence facts, got \
794                     operators={} total={}",
795                    operator_fact_count, self.gpu_conditioned_evidence_facts
796                ),
797            });
798        }
799
800        let source_operator_fact_count = self
801            .gpu_source_conditioned_know_evidence_facts
802            .checked_add(self.gpu_source_conditioned_possible_evidence_facts)
803            .and_then(|sum| sum.checked_add(self.gpu_source_conditioned_not_known_evidence_facts))
804            .and_then(|sum| {
805                sum.checked_add(self.gpu_source_conditioned_not_possible_evidence_facts)
806            })
807            .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
808                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
809                context: "source conditioned operator evidence fact counters overflowed"
810                    .to_string(),
811            })?;
812        if source_operator_fact_count != self.gpu_source_conditioned_evidence_facts {
813            return Err(XlogError::UnsupportedEpistemicConstruct {
814                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
815                context: format!(
816                    "source conditioned operator evidence facts must equal source evidence \
817                     facts, got operators={} total={}",
818                    source_operator_fact_count, self.gpu_source_conditioned_evidence_facts
819                ),
820            });
821        }
822
823        let program_operator_fact_count = self
824            .gpu_program_conditioned_know_evidence_facts
825            .checked_add(self.gpu_program_conditioned_possible_evidence_facts)
826            .and_then(|sum| sum.checked_add(self.gpu_program_conditioned_not_known_evidence_facts))
827            .and_then(|sum| {
828                sum.checked_add(self.gpu_program_conditioned_not_possible_evidence_facts)
829            })
830            .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
831                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
832                context: "program conditioned operator evidence fact counters overflowed"
833                    .to_string(),
834            })?;
835        if program_operator_fact_count != self.gpu_program_conditioned_evidence_facts {
836            return Err(XlogError::UnsupportedEpistemicConstruct {
837                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
838                context: format!(
839                    "program conditioned operator evidence facts must equal program evidence \
840                     facts, got operators={} total={}",
841                    program_operator_fact_count, self.gpu_program_conditioned_evidence_facts
842                ),
843            });
844        }
845
846        let expected_max_arity = self
847            .gpu_source_conditioned_max_evidence_arity
848            .max(self.gpu_program_conditioned_max_evidence_arity);
849        if self.gpu_conditioned_max_evidence_arity != expected_max_arity {
850            return Err(XlogError::UnsupportedEpistemicConstruct {
851                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
852                context: format!(
853                    "conditioned max evidence arity must equal max(source, program), got \
854                     aggregate={} source={} program={}",
855                    self.gpu_conditioned_max_evidence_arity,
856                    self.gpu_source_conditioned_max_evidence_arity,
857                    self.gpu_program_conditioned_max_evidence_arity
858                ),
859            });
860        }
861        if (self.gpu_conditioned_nonzero_arity_evidence_facts == 0)
862            != (self.gpu_conditioned_max_evidence_arity == 0)
863        {
864            return Err(XlogError::UnsupportedEpistemicConstruct {
865                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
866                context: format!(
867                    "conditioned max evidence arity must be nonzero exactly when nonzero-arity \
868                     facts are present, got nonzero={} max_arity={}",
869                    self.gpu_conditioned_nonzero_arity_evidence_facts,
870                    self.gpu_conditioned_max_evidence_arity
871                ),
872            });
873        }
874        if (self.gpu_source_conditioned_nonzero_arity_evidence_facts == 0)
875            != (self.gpu_source_conditioned_max_evidence_arity == 0)
876        {
877            return Err(XlogError::UnsupportedEpistemicConstruct {
878                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
879                context: format!(
880                    "source conditioned max evidence arity must be nonzero exactly when \
881                     source nonzero-arity facts are present, got nonzero={} max_arity={}",
882                    self.gpu_source_conditioned_nonzero_arity_evidence_facts,
883                    self.gpu_source_conditioned_max_evidence_arity
884                ),
885            });
886        }
887        if (self.gpu_program_conditioned_nonzero_arity_evidence_facts == 0)
888            != (self.gpu_program_conditioned_max_evidence_arity == 0)
889        {
890            return Err(XlogError::UnsupportedEpistemicConstruct {
891                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
892                context: format!(
893                    "program conditioned max evidence arity must be nonzero exactly when \
894                     program nonzero-arity facts are present, got nonzero={} max_arity={}",
895                    self.gpu_program_conditioned_nonzero_arity_evidence_facts,
896                    self.gpu_program_conditioned_max_evidence_arity
897                ),
898            });
899        }
900        if (self.accepted_evidence_assumptions_consumed != 0
901            || self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed != 0
902            || self.accepted_gpu_max_evidence_arity_consumed != 0)
903            && (self.gpu_conditioned_evidence_facts > self.accepted_evidence_assumptions_consumed
904                || self.gpu_conditioned_nonzero_arity_evidence_facts
905                    > self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
906                || self.gpu_conditioned_max_evidence_arity
907                    > self.accepted_gpu_max_evidence_arity_consumed)
908        {
909            return Err(XlogError::UnsupportedEpistemicConstruct {
910                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
911                context: format!(
912                    "conditioned evidence facts must be bounded by accepted GPU evidence, got \
913                     facts={}/{} nonzero={}/{} max_arity={}/{}",
914                    self.gpu_conditioned_evidence_facts,
915                    self.accepted_evidence_assumptions_consumed,
916                    self.gpu_conditioned_nonzero_arity_evidence_facts,
917                    self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
918                    self.gpu_conditioned_max_evidence_arity,
919                    self.accepted_gpu_max_evidence_arity_consumed
920                ),
921            });
922        }
923        Ok(())
924    }
925
926    /// Require that this trace is eligible for production probability metrics.
927    ///
928    /// This gate proves accepted-evidence admission and fixture containment for
929    /// this adapter path. It does not establish that every epistemic execution
930    /// route produces a compatible evidence record or that accepted assumptions
931    /// conditioned the probabilistic model.
932    pub fn require_production_metric_eligibility(&self) -> Result<()> {
933        let capabilities = production_capabilities();
934        if capabilities.fixture_circuit_allowed {
935            return Err(XlogError::UnsupportedEpistemicConstruct {
936                construct: "epistemic probabilistic production metric gate".to_string(),
937                context: "bounded EpistemicCircuit fixtures are not allowed for production metrics"
938                    .to_string(),
939            });
940        }
941        if capabilities.gpu_exact_provenance != EpistemicProbProductionCapabilityStatus::Available {
942            return Err(XlogError::UnsupportedEpistemicConstruct {
943                construct: "epistemic probabilistic production metric gate".to_string(),
944                context: "GPU exact/provenance production capability is not available".to_string(),
945            });
946        }
947        if capabilities.gpu_pir_cnf != EpistemicProbProductionCapabilityStatus::Available {
948            return Err(XlogError::UnsupportedEpistemicConstruct {
949                construct: "epistemic probabilistic production metric gate".to_string(),
950                context: "GPU PIR/CNF production capability is not available".to_string(),
951            });
952        }
953        if capabilities.gpu_knowledge_compilation
954            != EpistemicProbProductionCapabilityStatus::Available
955        {
956            return Err(XlogError::UnsupportedEpistemicConstruct {
957                construct: "epistemic probabilistic production metric gate".to_string(),
958                context: capabilities.gpu_knowledge_compilation_blocker.to_string(),
959            });
960        }
961        if capabilities.gpu_exact_query_and_gradient
962            != EpistemicProbProductionCapabilityStatus::Available
963        {
964            return Err(XlogError::UnsupportedEpistemicConstruct {
965                construct: "epistemic probabilistic production metric gate".to_string(),
966                context: "GPU exact query/gradient production capability is not available"
967                    .to_string(),
968            });
969        }
970        if self.accepted_world_view_evidence_consumed == 0 {
971            return Err(XlogError::UnsupportedEpistemicConstruct {
972                construct: "epistemic probabilistic production metric gate".to_string(),
973                context: "production probability metrics require accepted world-view evidence"
974                    .to_string(),
975            });
976        }
977        let gpu_production_path_events = self.checked_gpu_production_path_events()?;
978        if gpu_production_path_events == 0 {
979            return Err(XlogError::UnsupportedEpistemicConstruct {
980                construct: "epistemic probabilistic production metric gate".to_string(),
981                context: "production probability metrics require an existing GPU exact/provenance/PIR/CNF/knowledge-compilation counter"
982                    .to_string(),
983            });
984        }
985        if self.accepted_gpu_production_path_events == 0 {
986            return Err(XlogError::UnsupportedEpistemicConstruct {
987                construct: "epistemic probabilistic production metric gate".to_string(),
988                context: "production probability metrics require GPU exact/provenance/PIR/CNF/knowledge-compilation work inside an accepted world-view evidence gate"
989                    .to_string(),
990            });
991        }
992        if self.accepted_gpu_production_path_events > gpu_production_path_events {
993            return Err(XlogError::UnsupportedEpistemicConstruct {
994                construct: "epistemic probabilistic production metric gate".to_string(),
995                context: format!(
996                    "accepted GPU probability production events cannot exceed total GPU production events: accepted={} total={}",
997                    self.accepted_gpu_production_path_events, gpu_production_path_events
998                ),
999            });
1000        }
1001        if self.accepted_gpu_production_path_events < self.accepted_world_view_evidence_consumed {
1002            return Err(XlogError::UnsupportedEpistemicConstruct {
1003                construct: "epistemic probabilistic production metric gate".to_string(),
1004                context: format!(
1005                    "accepted GPU probability production events must cover each accepted \
1006                     world-view evidence record, got accepted_events={} evidence={}",
1007                    self.accepted_gpu_production_path_events,
1008                    self.accepted_world_view_evidence_consumed
1009                ),
1010            });
1011        }
1012        self.require_accepted_gpu_world_view_evidence_trace()?;
1013        self.require_accepted_gpu_tuple_evidence_trace()?;
1014        self.require_conditioned_evidence_trace()?;
1015        self.require_pir_cnf_accounting()?;
1016        self.require_gpu_path_accounting()?;
1017        Ok(())
1018    }
1019
1020    fn require_conditioned_evidence_metric_witness(&self) -> Result<()> {
1021        if self.accepted_conditioned_world_view_evidence_consumed == 0
1022            || self.gpu_conditioned_evidence_facts == 0
1023        {
1024            return Err(XlogError::UnsupportedEpistemicConstruct {
1025                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
1026                context:
1027                    "production probability metrics require accepted world-view evidence compiled as exact evidence facts"
1028                        .to_string(),
1029            });
1030        }
1031        Ok(())
1032    }
1033
1034    /// Require the stricter metric subset for accepted world-view evidence conditioning.
1035    ///
1036    /// General production eligibility proves fixture containment plus GPU exact/PIR/CNF/
1037    /// knowledge-compilation reuse. This gate additionally proves at least one accepted
1038    /// world view was compiled into exact evidence facts rather than only used as a
1039    /// production-path admission gate.
1040    pub fn require_conditioned_evidence_metric_eligibility(&self) -> Result<()> {
1041        self.require_production_metric_eligibility()?;
1042        self.require_conditioned_evidence_metric_witness()?;
1043        if self.gpu_conditioned_nonzero_arity_evidence_facts > 0
1044            && self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed == 0
1045        {
1046            return Err(XlogError::UnsupportedEpistemicConstruct {
1047                construct: "epistemic probabilistic conditioned evidence metric gate".to_string(),
1048                context: format!(
1049                    "conditioned nonzero-arity evidence facts require accepted GPU nonzero-arity \
1050                     assumptions, got conditioned_nonzero={} accepted_nonzero={}",
1051                    self.gpu_conditioned_nonzero_arity_evidence_facts,
1052                    self.accepted_gpu_nonzero_arity_evidence_assumptions_consumed
1053                ),
1054            });
1055        }
1056        Ok(())
1057    }
1058}
1059
1060/// Device-side PIR/CNF evidence produced after accepted epistemic gating.
1061#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
1062pub struct EpistemicProbPirCnfEvidence {
1063    /// Number of host provenance PIR nodes uploaded to the GPU PIR layout.
1064    pub pir_nodes: usize,
1065    /// Number of roots supplied to GPU CNF encoding.
1066    pub root_count: usize,
1067    /// GPU CNF variable capacity emitted by `encode_cnf_gpu`.
1068    pub cnf_var_cap: u32,
1069    /// GPU CNF clause capacity emitted by `encode_cnf_gpu`.
1070    pub cnf_clause_cap: u32,
1071    /// GPU CNF literal capacity emitted by `encode_cnf_gpu`.
1072    pub cnf_lit_cap: u32,
1073}
1074
1075/// One accepted GPU epistemic execution record used for probabilistic production gating.
1076#[derive(Clone, Copy)]
1077pub struct EpistemicProbGpuExecutionEvidence<'a> {
1078    /// Accepted GPU execution result whose world-view boundary must be validated.
1079    pub result: &'a EpistemicGpuExecutionResult,
1080    /// Epistemic assumptions represented by the accepted world view.
1081    pub assumptions: &'a [EpistemicAssumption],
1082}
1083
1084/// Accepted GPU batch execution evidence used for probabilistic production gating.
1085pub struct EpistemicProbGpuBatchExecutionEvidence<'a> {
1086    /// Accepted GPU batch execution result whose aggregate trace and timing must be validated.
1087    pub batch: &'a EpistemicGpuBatchExecutionResult,
1088    /// Epistemic assumptions represented by each accepted component world view.
1089    pub assumptions_by_component: &'a [&'a [EpistemicAssumption]],
1090}
1091
1092#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1093enum EpistemicProbPirCnfPath {
1094    Source,
1095    Program,
1096}
1097
1098/// Thin adapter from accepted epistemic evidence to the existing GPU exact path.
1099pub struct EpistemicProbProductionAdapter {
1100    config: GpuConfig,
1101    trace: EpistemicProbProductionTrace,
1102}
1103
1104/// One accepted-evidence exact circuit whose independent fact weights may change.
1105///
1106/// Clones share a single lock covering both host probability metadata and the
1107/// device-resident weight tables. Evaluation and updates are therefore serialized
1108/// for the same prepared circuit while unrelated circuits remain independent.
1109/// If a failed device update cannot be rolled back, the shared circuit is
1110/// permanently invalidated and every later operation through every clone fails.
1111#[derive(Clone)]
1112pub struct PreparedConditionedProgram {
1113    #[cfg(feature = "host-io")]
1114    state: Arc<Mutex<PreparedConditionedState>>,
1115}
1116
1117/// Authoritative identity and preparation count for one conditioned circuit.
1118///
1119/// `circuit_generation` is process-local and opaque. Together with `cache_slot`
1120/// it identifies the exact state and device-cache handle retained by a prepared
1121/// program; callers should compare values only within that handle's lifetime.
1122#[cfg(feature = "host-io")]
1123#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1124pub struct ConditionedCircuitWitness {
1125    /// Actual GPU circuit-compiler invocations performed while preparing this handle.
1126    pub preparation_compiles: u64,
1127    /// Successful exact-circuit materializations performed while preparing this handle.
1128    pub materializations: u64,
1129    /// Verified disk-cache restorations used while preparing this handle.
1130    pub disk_cache_restores: u64,
1131    /// GPU circuit-cache hits used while preparing this handle.
1132    pub gpu_cache_hits: u64,
1133    /// Opaque process-local generation assigned to the retained exact state.
1134    pub circuit_generation: u64,
1135    /// Device-cache slot retained by the exact state.
1136    pub cache_slot: u32,
1137}
1138
1139#[cfg(feature = "host-io")]
1140fn source_has_only_gpu_count_lift_queries(provenance: &Provenance) -> bool {
1141    !provenance.queries.is_empty()
1142        && provenance.evidence.is_empty()
1143        && provenance.choice_probs.is_empty()
1144        && provenance.queries.iter().all(|query| {
1145            provenance.aggregate_lifting.iter().any(|entry| {
1146                entry.status == AggregateLiftStatus::Fired
1147                    && entry.operator == "count"
1148                    && entry.deterministic_rows == 0
1149                    && entry.predicate == query.predicate
1150            })
1151        })
1152}
1153
1154#[cfg(feature = "host-io")]
1155struct PreparedConditionedState {
1156    exact: ExactDdnnfProgram,
1157    evaluation_trace: EpistemicProbProductionTrace,
1158    initial_circuit: ExactCircuitWitness,
1159    successful_reuses: u64,
1160}
1161
1162#[cfg(feature = "host-io")]
1163#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1164struct PreparedCircuitSnapshot {
1165    circuit: ExactCircuitWitness,
1166    successful_reuses: u64,
1167}
1168
1169#[cfg(feature = "host-io")]
1170impl PreparedConditionedState {
1171    fn ensure_usable(&self) -> Result<()> {
1172        self.exact.ensure_usable()
1173    }
1174
1175    fn snapshot(&self) -> Result<PreparedCircuitSnapshot> {
1176        self.ensure_usable()?;
1177        let circuit = self.exact.circuit_witness()?;
1178        if circuit.circuit_generation != self.initial_circuit.circuit_generation
1179            || circuit.cache_slot != self.initial_circuit.cache_slot
1180        {
1181            return Err(XlogError::Compilation(
1182                "Prepared conditioned circuit identity changed after preparation".to_string(),
1183            ));
1184        }
1185        Ok(PreparedCircuitSnapshot {
1186            circuit,
1187            successful_reuses: self.successful_reuses,
1188        })
1189    }
1190
1191    fn record_successful_reuse(&mut self) -> Result<PreparedCircuitSnapshot> {
1192        let before = self.snapshot()?;
1193        self.successful_reuses = self.successful_reuses.checked_add(1).ok_or_else(|| {
1194            XlogError::Compilation(
1195                "Prepared conditioned circuit reuse counter overflowed".to_string(),
1196            )
1197        })?;
1198        let after = self.snapshot()?;
1199        debug_assert_eq!(
1200            before.circuit.circuit_generation,
1201            after.circuit.circuit_generation
1202        );
1203        debug_assert_eq!(before.circuit.cache_slot, after.circuit.cache_slot);
1204        Ok(after)
1205    }
1206}
1207
1208#[cfg(feature = "host-io")]
1209impl PreparedConditionedProgram {
1210    fn new(
1211        exact: ExactDdnnfProgram,
1212        preparation_trace: EpistemicProbProductionTrace,
1213    ) -> Result<Self> {
1214        let initial_circuit = exact.circuit_witness()?;
1215        validate_single_circuit_materialization(initial_circuit)?;
1216        if initial_circuit.compiler_invocations > 1 {
1217            return Err(XlogError::Compilation(format!(
1218                "Prepared conditioned circuit invoked the GPU compiler {} times",
1219                initial_circuit.compiler_invocations
1220            )));
1221        }
1222        Ok(Self {
1223            state: Arc::new(Mutex::new(PreparedConditionedState {
1224                exact,
1225                evaluation_trace: reuse_trace_template(preparation_trace),
1226                initial_circuit,
1227                successful_reuses: 0,
1228            })),
1229        })
1230    }
1231
1232    fn lock_state(&self) -> Result<MutexGuard<'_, PreparedConditionedState>> {
1233        self.state.lock().map_err(|_| {
1234            XlogError::Execution(
1235                "Prepared conditioned state mutex is poisoned and permanently invalid".to_string(),
1236            )
1237        })
1238    }
1239
1240    fn apply_fact_probability_update(
1241        &self,
1242        apply: impl FnOnce(&mut ExactDdnnfProgram) -> Result<()>,
1243    ) -> Result<()> {
1244        let mut state = self.lock_state()?;
1245        let before = state.snapshot()?;
1246        let update_result = apply(&mut state.exact);
1247        if let Err(update_error) = update_result {
1248            if state.ensure_usable().is_err() {
1249                return Err(update_error);
1250            }
1251            let after = state.snapshot()?;
1252            if before != after {
1253                return Err(XlogError::Compilation(
1254                    "Failed fact probability update changed the prepared circuit identity or compile ledger"
1255                        .to_string(),
1256                ));
1257            }
1258            return Err(update_error);
1259        }
1260        let after = state.snapshot()?;
1261        if before != after {
1262            return Err(XlogError::Compilation(
1263                "Fact probability update changed the prepared circuit identity or compile ledger"
1264                    .to_string(),
1265            ));
1266        }
1267        Ok(())
1268    }
1269
1270    /// Evaluate the prepared conditioned circuit without recompiling it.
1271    #[cfg(feature = "host-io")]
1272    pub fn evaluate(&self) -> Result<(ExactResult, EpistemicProbProductionTrace)> {
1273        let mut state = self.lock_state()?;
1274        let before = state.snapshot()?;
1275        let result = state.exact.evaluate()?;
1276        let after = state.record_successful_reuse()?;
1277        let trace = query_reuse_trace(state.evaluation_trace, before, after)?;
1278        trace.require_conditioned_evidence_metric_eligibility()?;
1279        Ok((result, trace))
1280    }
1281
1282    /// Evaluate probabilities and gradients without recompiling the circuit.
1283    #[cfg(feature = "host-io")]
1284    pub fn evaluate_with_grads(
1285        &self,
1286    ) -> Result<(ExactResultWithGrads, EpistemicProbProductionTrace)> {
1287        let mut state = self.lock_state()?;
1288        let before = state.snapshot()?;
1289        let result = state.exact.evaluate_gpu_with_grads()?;
1290        let after = state.record_successful_reuse()?;
1291        let trace = gradient_reuse_trace(state.evaluation_trace, before, after)?;
1292        trace.require_conditioned_evidence_metric_eligibility()?;
1293        Ok((result, trace))
1294    }
1295
1296    /// Return the current CNF-variable metadata, including updated fact priors.
1297    pub fn prob_var_map(&self) -> Result<Vec<ProbVarInfo>> {
1298        let state = self.lock_state()?;
1299        state.snapshot()?;
1300        state.exact.checked_prob_var_map()
1301    }
1302
1303    /// Return the immutable exact-state identity and lifetime preparation count.
1304    pub fn circuit_witness(&self) -> Result<ConditionedCircuitWitness> {
1305        let state = self.lock_state()?;
1306        conditioned_circuit_witness(state.snapshot()?)
1307    }
1308
1309    /// Atomically update independent probabilistic fact weights.
1310    ///
1311    /// A failed device write is rolled back before this returns. If that rollback
1312    /// also fails, the shared prepared circuit is permanently invalidated so that
1313    /// neither this handle nor any clone can observe potentially partial weights.
1314    #[cfg(feature = "host-io")]
1315    pub fn set_fact_probabilities(&self, updates: &BTreeMap<u32, f64>) -> Result<()> {
1316        self.apply_fact_probability_update(|exact| exact.set_fact_probabilities(updates))
1317    }
1318
1319    #[cfg(all(test, feature = "host-io"))]
1320    fn set_fact_probabilities_with_device_failures(
1321        &self,
1322        updates: &BTreeMap<u32, f64>,
1323        fail_after_successful_writes: Option<usize>,
1324        fail_after_successful_rollback_writes: Option<usize>,
1325    ) -> Result<()> {
1326        self.apply_fact_probability_update(|exact| {
1327            exact.set_fact_probabilities_with_device_failures_for_test(
1328                updates,
1329                fail_after_successful_writes,
1330                fail_after_successful_rollback_writes,
1331            )
1332        })
1333    }
1334}
1335
1336#[cfg(feature = "host-io")]
1337fn conditioned_circuit_witness(
1338    snapshot: PreparedCircuitSnapshot,
1339) -> Result<ConditionedCircuitWitness> {
1340    validate_single_circuit_materialization(snapshot.circuit)?;
1341    Ok(ConditionedCircuitWitness {
1342        preparation_compiles: snapshot.circuit.compiler_invocations,
1343        materializations: snapshot.circuit.materializations,
1344        disk_cache_restores: snapshot.circuit.disk_cache_restores,
1345        gpu_cache_hits: snapshot.circuit.gpu_cache_hits,
1346        circuit_generation: snapshot.circuit.circuit_generation,
1347        cache_slot: snapshot.circuit.cache_slot,
1348    })
1349}
1350
1351#[cfg(feature = "host-io")]
1352fn validate_single_circuit_materialization(circuit: ExactCircuitWitness) -> Result<()> {
1353    let origins = circuit
1354        .compiler_invocations
1355        .checked_add(circuit.disk_cache_restores)
1356        .and_then(|count| count.checked_add(circuit.gpu_cache_hits))
1357        .ok_or_else(|| {
1358            XlogError::Compilation(
1359                "Prepared conditioned circuit materialization ledger overflowed".to_string(),
1360            )
1361        })?;
1362    if circuit.materializations != 1 || origins != 1 {
1363        return Err(XlogError::Compilation(format!(
1364            "Prepared conditioned circuit requires one materialization from one compile/cache event, got materializations={} compiler_invocations={} disk_cache_restores={} gpu_cache_hits={}",
1365            circuit.materializations,
1366            circuit.compiler_invocations,
1367            circuit.disk_cache_restores,
1368            circuit.gpu_cache_hits
1369        )));
1370    }
1371    Ok(())
1372}
1373
1374#[cfg(feature = "host-io")]
1375fn reuse_trace_template(
1376    mut preparation_trace: EpistemicProbProductionTrace,
1377) -> EpistemicProbProductionTrace {
1378    preparation_trace.gpu_exact_query_evaluations = 0;
1379    preparation_trace.gpu_source_exact_query_evaluations = 0;
1380    preparation_trace.gpu_program_exact_query_evaluations = 0;
1381    preparation_trace.gpu_exact_gradient_evaluations = 0;
1382    preparation_trace.gpu_source_exact_gradient_evaluations = 0;
1383    preparation_trace.gpu_program_exact_gradient_evaluations = 0;
1384    preparation_trace.gpu_source_conditioned_gradient_evaluations = 0;
1385    preparation_trace.gpu_program_conditioned_gradient_evaluations = 0;
1386    preparation_trace.gpu_pir_graph_uploads = 0;
1387    preparation_trace.gpu_source_pir_graph_uploads = 0;
1388    preparation_trace.gpu_program_pir_graph_uploads = 0;
1389    preparation_trace.gpu_cnf_encodes = 0;
1390    preparation_trace.gpu_source_cnf_encodes = 0;
1391    preparation_trace.gpu_program_cnf_encodes = 0;
1392    preparation_trace.gpu_knowledge_compilation_end_to_end_runs = 0;
1393    preparation_trace.gpu_source_knowledge_compilation_end_to_end_runs = 0;
1394    preparation_trace.gpu_program_knowledge_compilation_end_to_end_runs = 0;
1395    preparation_trace.accepted_gpu_production_path_events = 0;
1396    preparation_trace
1397}
1398
1399#[cfg(feature = "host-io")]
1400fn query_reuse_trace(
1401    mut trace: EpistemicProbProductionTrace,
1402    before: PreparedCircuitSnapshot,
1403    after: PreparedCircuitSnapshot,
1404) -> Result<EpistemicProbProductionTrace> {
1405    apply_authoritative_reuse_witness(&mut trace, before, after)?;
1406    trace.gpu_exact_query_evaluations = trace.gpu_conditioned_circuit_reuses;
1407    trace.gpu_source_exact_query_evaluations = trace.gpu_conditioned_circuit_reuses;
1408    trace.accepted_gpu_production_path_events = trace.checked_gpu_production_path_events()?;
1409    Ok(trace)
1410}
1411
1412#[cfg(feature = "host-io")]
1413fn gradient_reuse_trace(
1414    mut trace: EpistemicProbProductionTrace,
1415    before: PreparedCircuitSnapshot,
1416    after: PreparedCircuitSnapshot,
1417) -> Result<EpistemicProbProductionTrace> {
1418    apply_authoritative_reuse_witness(&mut trace, before, after)?;
1419    trace.gpu_exact_gradient_evaluations = trace.gpu_conditioned_circuit_reuses;
1420    trace.gpu_source_exact_gradient_evaluations = trace.gpu_conditioned_circuit_reuses;
1421    trace.gpu_source_conditioned_gradient_evaluations = trace.gpu_conditioned_circuit_reuses;
1422    trace.accepted_gpu_production_path_events = trace.checked_gpu_production_path_events()?;
1423    Ok(trace)
1424}
1425
1426#[cfg(feature = "host-io")]
1427fn apply_authoritative_reuse_witness(
1428    trace: &mut EpistemicProbProductionTrace,
1429    before: PreparedCircuitSnapshot,
1430    after: PreparedCircuitSnapshot,
1431) -> Result<()> {
1432    if before.circuit.circuit_generation != after.circuit.circuit_generation
1433        || before.circuit.cache_slot != after.circuit.cache_slot
1434    {
1435        return Err(XlogError::Compilation(
1436            "Prepared conditioned circuit identity changed during evaluation".to_string(),
1437        ));
1438    }
1439    trace.gpu_exact_source_compiles = after
1440        .circuit
1441        .compiler_invocations
1442        .checked_sub(before.circuit.compiler_invocations)
1443        .ok_or_else(|| {
1444            XlogError::Compilation(
1445                "Prepared conditioned compiler invocation ledger regressed".to_string(),
1446            )
1447        })?;
1448    trace.gpu_exact_program_compiles = 0;
1449    trace.gpu_conditioned_circuit_reuses = after
1450        .successful_reuses
1451        .checked_sub(before.successful_reuses)
1452        .ok_or_else(|| {
1453            XlogError::Compilation(
1454                "Prepared conditioned circuit reuse counter regressed".to_string(),
1455            )
1456        })?;
1457    let witness = conditioned_circuit_witness(after)?;
1458    trace.gpu_conditioned_circuit_preparation_compiles = witness.preparation_compiles;
1459    trace.gpu_conditioned_circuit_materializations = witness.materializations;
1460    trace.gpu_conditioned_circuit_disk_cache_restores = witness.disk_cache_restores;
1461    trace.gpu_conditioned_circuit_gpu_cache_hits = witness.gpu_cache_hits;
1462    trace.gpu_conditioned_circuit_generation = witness.circuit_generation;
1463    trace.gpu_conditioned_circuit_cache_slot = u64::from(witness.cache_slot);
1464    if trace.gpu_exact_source_compiles != 0
1465        || trace.gpu_exact_program_compiles != 0
1466        || trace.gpu_conditioned_circuit_reuses != 1
1467    {
1468        return Err(XlogError::Compilation(format!(
1469            "Prepared conditioned evaluation must not compile and must reuse one circuit, got source_compiles={} program_compiles={} reuses={}",
1470            trace.gpu_exact_source_compiles,
1471            trace.gpu_exact_program_compiles,
1472            trace.gpu_conditioned_circuit_reuses
1473        )));
1474    }
1475    Ok(())
1476}
1477
1478#[cfg(feature = "host-io")]
1479#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1480enum EpistemicProbConditionedEvidencePath {
1481    Source,
1482    Program,
1483}
1484
1485impl EpistemicProbProductionAdapter {
1486    fn checked_trace_counter_add(current: u64, delta: u64, counter: &str) -> Result<u64> {
1487        current
1488            .checked_add(delta)
1489            .ok_or_else(|| XlogError::UnsupportedEpistemicConstruct {
1490                construct: "epistemic probabilistic production trace accounting".to_string(),
1491                context: format!(
1492                    "accepted GPU probability trace counter {counter} overflowed while adding \
1493                    {delta} to {current}"
1494                ),
1495            })
1496    }
1497
1498    #[cfg(feature = "host-io")]
1499    fn record_gpu_exact_query_evaluation(&mut self, program: &ExactDdnnfProgram) -> Result<()> {
1500        checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
1501        match program.origin() {
1502            ExactProgramOrigin::Source => {
1503                checked_prob_trace_counter_inc!(self, gpu_source_exact_query_evaluations);
1504            }
1505            ExactProgramOrigin::Program => {
1506                checked_prob_trace_counter_inc!(self, gpu_program_exact_query_evaluations);
1507            }
1508        }
1509        Ok(())
1510    }
1511
1512    #[cfg(feature = "host-io")]
1513    fn record_gpu_exact_gradient_evaluation(&mut self, program: &ExactDdnnfProgram) -> Result<()> {
1514        self.record_gpu_exact_gradient_evaluation_for_origin(program.origin())
1515    }
1516
1517    #[cfg(feature = "host-io")]
1518    fn record_gpu_exact_gradient_evaluation_for_origin(
1519        &mut self,
1520        origin: ExactProgramOrigin,
1521    ) -> Result<()> {
1522        checked_prob_trace_counter_inc!(self, gpu_exact_gradient_evaluations);
1523        match origin {
1524            ExactProgramOrigin::Source => {
1525                checked_prob_trace_counter_inc!(self, gpu_source_exact_gradient_evaluations);
1526            }
1527            ExactProgramOrigin::Program => {
1528                checked_prob_trace_counter_inc!(self, gpu_program_exact_gradient_evaluations);
1529            }
1530        }
1531        Ok(())
1532    }
1533
1534    /// Create a production adapter with a GPU exact inference configuration.
1535    pub fn new(config: GpuConfig) -> Self {
1536        Self {
1537            config,
1538            trace: EpistemicProbProductionTrace::default(),
1539        }
1540    }
1541
1542    /// Return current production-path trace counters.
1543    pub fn trace(&self) -> EpistemicProbProductionTrace {
1544        self.trace
1545    }
1546
1547    /// Apply accepted world-view evidence to a caller-owned incremental circuit fixture.
1548    ///
1549    /// This records accepted evidence after the typed `Gpu`/`RejectUnsupported` plan boundary,
1550    /// but it is not a production metric event. Production metric eligibility still requires
1551    /// observed GPU exact/provenance/PIR/CNF/knowledge-compilation path events.
1552    pub fn apply_accepted_world_view_to_circuit(
1553        &mut self,
1554        circuit: &mut EpistemicCircuit,
1555        evidence: AcceptedWorldViewEvidence,
1556    ) -> Result<CircuitUpdate> {
1557        epistemic_prob_trace_transaction!(self, {
1558            self.consume_accepted_evidence(&evidence)?;
1559            let update = circuit.apply_accepted_world_view(evidence)?;
1560            if update.mode == CircuitUpdateMode::IncrementalEvidence {
1561                self.trace.accepted_incremental_circuit_updates = Self::checked_trace_counter_add(
1562                    self.trace.accepted_incremental_circuit_updates,
1563                    1,
1564                    "accepted_incremental_circuit_updates",
1565                )?;
1566            }
1567            Ok(update)
1568        })
1569    }
1570
1571    /// Apply accepted GPU epistemic execution evidence to a caller-owned incremental circuit.
1572    pub fn apply_accepted_world_view_to_circuit_with_gpu_execution_result(
1573        &mut self,
1574        circuit: &mut EpistemicCircuit,
1575        provider: &CudaKernelProvider,
1576        result: &EpistemicGpuExecutionResult,
1577        assumptions: Vec<EpistemicAssumption>,
1578    ) -> Result<CircuitUpdate> {
1579        let evidence =
1580            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
1581        self.apply_accepted_world_view_to_circuit(circuit, evidence)
1582    }
1583
1584    /// Apply accepted split/batch GPU epistemic execution evidence to an incremental circuit.
1585    pub fn apply_accepted_world_views_to_circuit_for_gpu_batch_execution_result(
1586        &mut self,
1587        circuit: &mut EpistemicCircuit,
1588        provider: &CudaKernelProvider,
1589        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1590    ) -> Result<Vec<CircuitUpdate>> {
1591        epistemic_prob_trace_transaction!(self, {
1592            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
1593                provider,
1594                evidence,
1595                "epistemic probabilistic incremental circuit batch production",
1596            )?;
1597
1598            let mut updates = Vec::with_capacity(accepted.len());
1599            for evidence in accepted {
1600                updates.push(self.apply_accepted_world_view_to_circuit(circuit, evidence)?);
1601            }
1602            Ok(updates)
1603        })
1604    }
1605
1606    fn accepted_world_views_from_gpu_batch_execution_evidence(
1607        &mut self,
1608        provider: &CudaKernelProvider,
1609        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1610        construct: &str,
1611    ) -> Result<Vec<AcceptedWorldViewEvidence>> {
1612        if evidence.batch.results.is_empty() {
1613            return Err(XlogError::UnsupportedEpistemicConstruct {
1614                construct: construct.to_string(),
1615                context: "probabilistic batch gating requires at least one accepted GPU component"
1616                    .to_string(),
1617            });
1618        }
1619        if evidence.assumptions_by_component.len() != evidence.batch.results.len() {
1620            return Err(XlogError::UnsupportedEpistemicConstruct {
1621                construct: construct.to_string(),
1622                context: format!(
1623                    "assumption group count {} does not match GPU batch component count {}",
1624                    evidence.assumptions_by_component.len(),
1625                    evidence.batch.results.len()
1626                ),
1627            });
1628        }
1629        let batch_trace = evidence.batch.trace;
1630        if batch_trace.component_count != evidence.batch.results.len()
1631            || batch_trace.gpu_runtime_component_executions != evidence.batch.results.len()
1632            || batch_trace.tracked_dtoh_calls != 0
1633            || batch_trace.tracked_htod_calls != 0
1634            || batch_trace.tracked_data_plane_htod_calls != 0
1635            || batch_trace.per_candidate_host_round_trips != 0
1636            || batch_trace.violated_constraint_relations != 0
1637            || !batch_trace.aggregate_kernel_timing.is_recorded()
1638        {
1639            return Err(XlogError::UnsupportedEpistemicConstruct {
1640                construct: construct.to_string(),
1641                context: format!(
1642                    "accepted GPU batch evidence requires complete GPU component execution and \
1643                     zero observed hot-path transfers outside bounded launch metadata plus \
1644                     aggregate CUDA-event timing, got components={}/{}, dtoh_calls={}, \
1645                     htod_calls={}, data_plane_htod_calls={}, launch_metadata_htod_calls={}, \
1646                     round_trips={}, constraint_violations={}, aggregate_timing_recorded={}",
1647                    batch_trace.gpu_runtime_component_executions,
1648                    batch_trace.component_count,
1649                    batch_trace.tracked_dtoh_calls,
1650                    batch_trace.tracked_htod_calls,
1651                    batch_trace.tracked_data_plane_htod_calls,
1652                    batch_trace.tracked_launch_metadata_htod_calls,
1653                    batch_trace.per_candidate_host_round_trips,
1654                    batch_trace.violated_constraint_relations,
1655                    batch_trace.aggregate_kernel_timing.is_recorded()
1656                ),
1657            });
1658        }
1659        evidence.batch.require_trace_matches_components(construct)?;
1660
1661        let mut accepted = Vec::with_capacity(evidence.batch.results.len());
1662        for (result, assumptions) in evidence
1663            .batch
1664            .results
1665            .iter()
1666            .zip(evidence.assumptions_by_component.iter())
1667        {
1668            accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
1669                provider,
1670                result,
1671                (*assumptions).to_vec(),
1672            )?);
1673        }
1674
1675        self.trace.accepted_gpu_batch_evidence_consumed = Self::checked_trace_counter_add(
1676            self.trace.accepted_gpu_batch_evidence_consumed,
1677            1,
1678            "accepted_gpu_batch_evidence_consumed",
1679        )?;
1680        self.trace.accepted_gpu_batch_component_evidence_consumed =
1681            Self::checked_trace_counter_add(
1682                self.trace.accepted_gpu_batch_component_evidence_consumed,
1683                accepted.len() as u64,
1684                "accepted_gpu_batch_component_evidence_consumed",
1685            )?;
1686
1687        Ok(accepted)
1688    }
1689
1690    #[cfg(feature = "host-io")]
1691    fn record_conditioned_evidence_counts(
1692        &mut self,
1693        counts: EpistemicProbConditionedEvidenceCounts,
1694        path: EpistemicProbConditionedEvidencePath,
1695    ) -> Result<()> {
1696        macro_rules! add_counter {
1697            ($field:ident, $delta:expr) => {
1698                self.trace.$field =
1699                    Self::checked_trace_counter_add(self.trace.$field, $delta, stringify!($field))?;
1700            };
1701        }
1702
1703        add_counter!(accepted_conditioned_world_view_evidence_consumed, 1);
1704        add_counter!(gpu_conditioned_evidence_facts, counts.total as u64);
1705        add_counter!(
1706            gpu_conditioned_nonzero_arity_evidence_facts,
1707            counts.nonzero_arity as u64
1708        );
1709        self.trace.gpu_conditioned_max_evidence_arity = self
1710            .trace
1711            .gpu_conditioned_max_evidence_arity
1712            .max(counts.max_arity);
1713        add_counter!(
1714            gpu_conditioned_negative_evidence_facts,
1715            counts.negative as u64
1716        );
1717        match path {
1718            EpistemicProbConditionedEvidencePath::Source => {
1719                add_counter!(accepted_source_conditioned_world_view_evidence_consumed, 1);
1720                add_counter!(gpu_source_conditioned_evidence_facts, counts.total as u64);
1721                add_counter!(
1722                    gpu_source_conditioned_nonzero_arity_evidence_facts,
1723                    counts.nonzero_arity as u64
1724                );
1725                self.trace.gpu_source_conditioned_max_evidence_arity = self
1726                    .trace
1727                    .gpu_source_conditioned_max_evidence_arity
1728                    .max(counts.max_arity);
1729                add_counter!(
1730                    gpu_source_conditioned_negative_evidence_facts,
1731                    counts.negative as u64
1732                );
1733                add_counter!(
1734                    gpu_source_conditioned_know_evidence_facts,
1735                    counts.know as u64
1736                );
1737                add_counter!(
1738                    gpu_source_conditioned_possible_evidence_facts,
1739                    counts.possible as u64
1740                );
1741                add_counter!(
1742                    gpu_source_conditioned_not_known_evidence_facts,
1743                    counts.not_known as u64
1744                );
1745                add_counter!(
1746                    gpu_source_conditioned_not_possible_evidence_facts,
1747                    counts.not_possible as u64
1748                );
1749            }
1750            EpistemicProbConditionedEvidencePath::Program => {
1751                add_counter!(accepted_program_conditioned_world_view_evidence_consumed, 1);
1752                add_counter!(gpu_program_conditioned_evidence_facts, counts.total as u64);
1753                add_counter!(
1754                    gpu_program_conditioned_nonzero_arity_evidence_facts,
1755                    counts.nonzero_arity as u64
1756                );
1757                self.trace.gpu_program_conditioned_max_evidence_arity = self
1758                    .trace
1759                    .gpu_program_conditioned_max_evidence_arity
1760                    .max(counts.max_arity);
1761                add_counter!(
1762                    gpu_program_conditioned_negative_evidence_facts,
1763                    counts.negative as u64
1764                );
1765                add_counter!(
1766                    gpu_program_conditioned_know_evidence_facts,
1767                    counts.know as u64
1768                );
1769                add_counter!(
1770                    gpu_program_conditioned_possible_evidence_facts,
1771                    counts.possible as u64
1772                );
1773                add_counter!(
1774                    gpu_program_conditioned_not_known_evidence_facts,
1775                    counts.not_known as u64
1776                );
1777                add_counter!(
1778                    gpu_program_conditioned_not_possible_evidence_facts,
1779                    counts.not_possible as u64
1780                );
1781            }
1782        }
1783        add_counter!(gpu_conditioned_know_evidence_facts, counts.know as u64);
1784        add_counter!(
1785            gpu_conditioned_possible_evidence_facts,
1786            counts.possible as u64
1787        );
1788        add_counter!(
1789            gpu_conditioned_not_known_evidence_facts,
1790            counts.not_known as u64
1791        );
1792        add_counter!(
1793            gpu_conditioned_not_possible_evidence_facts,
1794            counts.not_possible as u64
1795        );
1796        Ok(())
1797    }
1798
1799    fn record_accepted_gpu_production_path_events_since(
1800        &mut self,
1801        events_before: u64,
1802    ) -> Result<()> {
1803        let events_after = self.trace.checked_gpu_production_path_events()?;
1804        let delta = events_after.checked_sub(events_before).ok_or_else(|| {
1805            XlogError::UnsupportedEpistemicConstruct {
1806                construct: "epistemic probabilistic production trace accounting".to_string(),
1807                context: format!(
1808                    "accepted GPU probability production events decreased from {events_before} to \
1809                     {events_after}"
1810                ),
1811            }
1812        })?;
1813        self.trace.accepted_gpu_production_path_events = Self::checked_trace_counter_add(
1814            self.trace.accepted_gpu_production_path_events,
1815            delta,
1816            "accepted_gpu_production_path_events",
1817        )?;
1818        Ok(())
1819    }
1820
1821    /// Compile source through the existing GPU-native exact/provenance path.
1822    pub fn compile_source_with_accepted_world_view(
1823        &mut self,
1824        source: &str,
1825        evidence: &AcceptedWorldViewEvidence,
1826    ) -> Result<ExactDdnnfProgram> {
1827        epistemic_prob_trace_transaction!(self, {
1828            self.require_accepted_evidence(evidence)?;
1829            let production_events_before = self.trace.checked_gpu_production_path_events()?;
1830            let program = ExactDdnnfProgram::compile_source_with_gpu(source, self.config)?;
1831            require_gpu_exact_backend(&program, "epistemic probabilistic source exact compile")?;
1832            checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
1833            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
1834            self.record_accepted_evidence(evidence)?;
1835            Ok(program)
1836        })
1837    }
1838
1839    /// Compile source through the GPU exact path after accepted GPU epistemic execution.
1840    pub fn compile_source_with_gpu_execution_result(
1841        &mut self,
1842        source: &str,
1843        provider: &CudaKernelProvider,
1844        result: &EpistemicGpuExecutionResult,
1845        assumptions: Vec<EpistemicAssumption>,
1846    ) -> Result<ExactDdnnfProgram> {
1847        let evidence =
1848            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
1849        self.compile_source_with_accepted_world_view(source, &evidence)
1850    }
1851
1852    /// Compile source once per accepted GPU epistemic execution result.
1853    pub fn compile_source_for_gpu_execution_results(
1854        &mut self,
1855        source: &str,
1856        provider: &CudaKernelProvider,
1857        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
1858    ) -> Result<Vec<ExactDdnnfProgram>> {
1859        epistemic_prob_trace_transaction!(self, {
1860            if evidence_records.is_empty() {
1861                return Err(XlogError::UnsupportedEpistemicConstruct {
1862                    construct: "epistemic probabilistic source exact compile batch".to_string(),
1863                    context:
1864                        "batched source exact compile requires at least one accepted GPU result"
1865                            .to_string(),
1866                });
1867            }
1868
1869            let mut accepted = Vec::with_capacity(evidence_records.len());
1870            for record in evidence_records {
1871                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
1872                    provider,
1873                    record.result,
1874                    record.assumptions.to_vec(),
1875                )?);
1876            }
1877
1878            let mut programs = Vec::with_capacity(accepted.len());
1879            for evidence in &accepted {
1880                programs.push(self.compile_source_with_accepted_world_view(source, evidence)?);
1881            }
1882            Ok(programs)
1883        })
1884    }
1885
1886    /// Compile source once per accepted split/batch GPU epistemic component.
1887    pub fn compile_source_for_gpu_batch_execution_result(
1888        &mut self,
1889        source: &str,
1890        provider: &CudaKernelProvider,
1891        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1892    ) -> Result<Vec<ExactDdnnfProgram>> {
1893        epistemic_prob_trace_transaction!(self, {
1894            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
1895                provider,
1896                evidence,
1897                "epistemic probabilistic source exact compile batch production",
1898            )?;
1899
1900            let mut programs = Vec::with_capacity(accepted.len());
1901            for evidence in &accepted {
1902                programs.push(self.compile_source_with_accepted_world_view(source, evidence)?);
1903            }
1904            Ok(programs)
1905        })
1906    }
1907
1908    /// Compile a parsed program through the existing GPU-native exact/provenance path.
1909    pub fn compile_program_with_accepted_world_view(
1910        &mut self,
1911        program: &Program,
1912        evidence: &AcceptedWorldViewEvidence,
1913    ) -> Result<ExactDdnnfProgram> {
1914        epistemic_prob_trace_transaction!(self, {
1915            self.require_accepted_evidence(evidence)?;
1916            let production_events_before = self.trace.checked_gpu_production_path_events()?;
1917            let exact = ExactDdnnfProgram::compile_from_program(program, self.config)?;
1918            require_gpu_exact_backend(
1919                &exact,
1920                "epistemic probabilistic parsed-program exact compile",
1921            )?;
1922            checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
1923            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
1924            self.record_accepted_evidence(evidence)?;
1925            Ok(exact)
1926        })
1927    }
1928
1929    /// Compile a parsed program through the GPU exact path after accepted GPU epistemic execution.
1930    pub fn compile_program_with_gpu_execution_result(
1931        &mut self,
1932        program: &Program,
1933        provider: &CudaKernelProvider,
1934        result: &EpistemicGpuExecutionResult,
1935        assumptions: Vec<EpistemicAssumption>,
1936    ) -> Result<ExactDdnnfProgram> {
1937        let evidence =
1938            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
1939        self.compile_program_with_accepted_world_view(program, &evidence)
1940    }
1941
1942    /// Compile a parsed program once per accepted GPU epistemic execution result.
1943    pub fn compile_program_for_gpu_execution_results(
1944        &mut self,
1945        program: &Program,
1946        provider: &CudaKernelProvider,
1947        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
1948    ) -> Result<Vec<ExactDdnnfProgram>> {
1949        epistemic_prob_trace_transaction!(self, {
1950            if evidence_records.is_empty() {
1951                return Err(XlogError::UnsupportedEpistemicConstruct {
1952                    construct: "epistemic probabilistic parsed-program exact compile batch"
1953                        .to_string(),
1954                    context: "batched parsed-program exact compile requires at least one accepted GPU result"
1955                        .to_string(),
1956                });
1957            }
1958
1959            let mut accepted = Vec::with_capacity(evidence_records.len());
1960            for record in evidence_records {
1961                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
1962                    provider,
1963                    record.result,
1964                    record.assumptions.to_vec(),
1965                )?);
1966            }
1967
1968            let mut programs = Vec::with_capacity(accepted.len());
1969            for evidence in &accepted {
1970                programs.push(self.compile_program_with_accepted_world_view(program, evidence)?);
1971            }
1972            Ok(programs)
1973        })
1974    }
1975
1976    /// Compile a parsed program once per accepted split/batch GPU epistemic component.
1977    pub fn compile_program_for_gpu_batch_execution_result(
1978        &mut self,
1979        program: &Program,
1980        provider: &CudaKernelProvider,
1981        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
1982    ) -> Result<Vec<ExactDdnnfProgram>> {
1983        epistemic_prob_trace_transaction!(self, {
1984            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
1985                provider,
1986                evidence,
1987                "epistemic probabilistic parsed-program exact compile batch production",
1988            )?;
1989
1990            let mut programs = Vec::with_capacity(accepted.len());
1991            for evidence in &accepted {
1992                programs.push(self.compile_program_with_accepted_world_view(program, evidence)?);
1993            }
1994            Ok(programs)
1995        })
1996    }
1997
1998    /// Compile source and evaluate queries through the existing GPU exact path after one accepted gate.
1999    #[cfg(feature = "host-io")]
2000    pub fn compile_and_evaluate_source_with_accepted_world_view(
2001        &mut self,
2002        source: &str,
2003        evidence: &AcceptedWorldViewEvidence,
2004    ) -> Result<ExactResult> {
2005        epistemic_prob_trace_transaction!(self, {
2006            self.require_accepted_evidence(evidence)?;
2007            let production_events_before = self.trace.checked_gpu_production_path_events()?;
2008            let program = ExactDdnnfProgram::compile_source_with_gpu(source, self.config)?;
2009            require_gpu_exact_backend(
2010                &program,
2011                "epistemic probabilistic source exact compile/evaluate",
2012            )?;
2013            checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2014            let result = program.evaluate()?;
2015            checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
2016            checked_prob_trace_counter_inc!(self, gpu_source_exact_query_evaluations);
2017            checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2018            checked_prob_trace_counter_inc!(self, gpu_source_knowledge_compilation_end_to_end_runs);
2019            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2020            self.record_accepted_evidence(evidence)?;
2021            Ok(result)
2022        })
2023    }
2024
2025    /// Compile source and evaluate queries after accepted GPU epistemic execution.
2026    #[cfg(feature = "host-io")]
2027    pub fn compile_and_evaluate_source_with_gpu_execution_result(
2028        &mut self,
2029        source: &str,
2030        provider: &CudaKernelProvider,
2031        result: &EpistemicGpuExecutionResult,
2032        assumptions: Vec<EpistemicAssumption>,
2033    ) -> Result<ExactResult> {
2034        let evidence =
2035            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
2036        self.compile_and_evaluate_source_with_accepted_world_view(source, &evidence)
2037    }
2038
2039    /// Compile and evaluate source once per accepted GPU epistemic execution result.
2040    #[cfg(feature = "host-io")]
2041    pub fn compile_and_evaluate_source_for_gpu_execution_results(
2042        &mut self,
2043        source: &str,
2044        provider: &CudaKernelProvider,
2045        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2046    ) -> Result<Vec<ExactResult>> {
2047        epistemic_prob_trace_transaction!(self, {
2048            if evidence_records.is_empty() {
2049                return Err(XlogError::UnsupportedEpistemicConstruct {
2050                    construct: "epistemic probabilistic production batch".to_string(),
2051                    context:
2052                        "batched knowledge compilation requires at least one accepted GPU result"
2053                            .to_string(),
2054                });
2055            }
2056
2057            let mut accepted = Vec::with_capacity(evidence_records.len());
2058            for record in evidence_records {
2059                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2060                    provider,
2061                    record.result,
2062                    record.assumptions.to_vec(),
2063                )?);
2064            }
2065
2066            let mut results = Vec::with_capacity(accepted.len());
2067            for evidence in &accepted {
2068                results.push(
2069                    self.compile_and_evaluate_source_with_accepted_world_view(source, evidence)?,
2070                );
2071            }
2072            Ok(results)
2073        })
2074    }
2075
2076    /// Compile and evaluate source once per accepted split/batch GPU epistemic component.
2077    #[cfg(feature = "host-io")]
2078    pub fn compile_and_evaluate_source_for_gpu_batch_execution_result(
2079        &mut self,
2080        source: &str,
2081        provider: &CudaKernelProvider,
2082        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2083    ) -> Result<Vec<ExactResult>> {
2084        epistemic_prob_trace_transaction!(self, {
2085            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2086                provider,
2087                evidence,
2088                "epistemic probabilistic batch production",
2089            )?;
2090
2091            let mut results = Vec::with_capacity(accepted.len());
2092            for evidence in &accepted {
2093                results.push(
2094                    self.compile_and_evaluate_source_with_accepted_world_view(source, evidence)?,
2095                );
2096            }
2097            Ok(results)
2098        })
2099    }
2100
2101    /// Compile source with accepted zero-arity epistemic assumptions as exact evidence.
2102    #[cfg(feature = "host-io")]
2103    pub fn compile_and_evaluate_conditioned_source_with_accepted_world_view(
2104        &mut self,
2105        source: &str,
2106        evidence: &AcceptedWorldViewEvidence,
2107    ) -> Result<ExactResult> {
2108        epistemic_prob_trace_transaction!(self, {
2109            let program = parse_program(source)?;
2110            let provenance = extract_from_program(&program)?;
2111            self.compile_and_evaluate_conditioned_program_with_path(
2112                &program,
2113                &provenance,
2114                evidence,
2115                EpistemicProbConditionedEvidencePath::Source,
2116                "epistemic probabilistic conditioned source exact compile/evaluate",
2117            )
2118        })
2119    }
2120
2121    /// Compile source with accepted GPU epistemic assumptions as exact evidence.
2122    #[cfg(feature = "host-io")]
2123    pub fn compile_and_evaluate_conditioned_source_with_gpu_execution_result(
2124        &mut self,
2125        source: &str,
2126        provider: &CudaKernelProvider,
2127        result: &EpistemicGpuExecutionResult,
2128        assumptions: Vec<EpistemicAssumption>,
2129    ) -> Result<ExactResult> {
2130        epistemic_prob_trace_transaction!(self, {
2131            let auto_derived = assumptions.is_empty();
2132            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2133                provider,
2134                result,
2135                assumptions,
2136            )?;
2137            let program = parse_program(source)?;
2138            let provenance = extract_from_program(&program)?;
2139            let filtered_evidence;
2140            let evidence = if auto_derived {
2141                filtered_evidence =
2142                    evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2143                &filtered_evidence
2144            } else {
2145                &evidence
2146            };
2147            self.compile_and_evaluate_conditioned_program_with_path(
2148                &program,
2149                &provenance,
2150                evidence,
2151                EpistemicProbConditionedEvidencePath::Source,
2152                "epistemic probabilistic conditioned source exact compile/evaluate",
2153            )
2154        })
2155    }
2156
2157    /// Compile accepted epistemic evidence and an exact probabilistic source once.
2158    ///
2159    /// The returned handle reuses the conditioned circuit and permits atomic
2160    /// updates only for independent probabilistic fact variables.
2161    #[cfg(feature = "host-io")]
2162    pub fn prepare_conditioned_source_with_gpu_execution_result(
2163        &mut self,
2164        source: &str,
2165        provider: &CudaKernelProvider,
2166        result: &EpistemicGpuExecutionResult,
2167        assumptions: Vec<EpistemicAssumption>,
2168    ) -> Result<PreparedConditionedProgram> {
2169        epistemic_prob_trace_transaction!(self, {
2170            let auto_derived = assumptions.is_empty();
2171            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2172                provider,
2173                result,
2174                assumptions,
2175            )?;
2176            let program = parse_program(source)?;
2177            if program.directives.prob_engine_or_default() != ProbEngine::ExactDdnnf {
2178                return Err(XlogError::UnsupportedEpistemicConstruct {
2179                    construct: "reusable conditioned circuit".to_string(),
2180                    context: "reusable conditioned programs require the exact Decision-DNNF engine; Monte Carlo programs cannot expose mutable CNF fact weights"
2181                        .to_string(),
2182                });
2183            }
2184            let provenance = extract_from_program(&program)?;
2185            if source_has_only_gpu_count_lift_queries(&provenance) {
2186                return Err(XlogError::UnsupportedEpistemicConstruct {
2187                    construct: "reusable conditioned circuit".to_string(),
2188                    context:
2189                        "GPU count-lift exact programs do not expose mutable CNF fact variables"
2190                            .to_string(),
2191                });
2192            }
2193            let filtered_evidence;
2194            let evidence = if auto_derived {
2195                filtered_evidence =
2196                    evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2197                &filtered_evidence
2198            } else {
2199                &evidence
2200            };
2201            self.require_accepted_evidence(evidence)?;
2202            let production_events_before = self.trace.checked_gpu_production_path_events()?;
2203            let (conditioned_program, evidence_counts) =
2204                condition_program_with_accepted_evidence_using_provenance(
2205                    &program,
2206                    &provenance,
2207                    evidence,
2208                )?;
2209            let exact = ExactDdnnfProgram::compile_from_program(&conditioned_program, self.config)?;
2210            if exact.uses_gpu_native_count_lift() {
2211                return Err(XlogError::UnsupportedEpistemicConstruct {
2212                    construct: "reusable conditioned circuit".to_string(),
2213                    context: "GPU count-lift exact programs do not expose mutable CNF fact weights"
2214                        .to_string(),
2215                });
2216            }
2217            require_gpu_exact_backend(
2218                &exact,
2219                "epistemic probabilistic reusable conditioned source exact compile",
2220            )?;
2221            checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2222            self.record_conditioned_evidence_counts(
2223                evidence_counts,
2224                EpistemicProbConditionedEvidencePath::Source,
2225            )?;
2226            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2227            self.record_accepted_evidence(evidence)?;
2228            PreparedConditionedProgram::new(exact, self.trace)
2229        })
2230    }
2231
2232    /// Compile conditioned source once per accepted GPU epistemic execution result.
2233    #[cfg(feature = "host-io")]
2234    pub fn compile_and_evaluate_conditioned_source_for_gpu_execution_results(
2235        &mut self,
2236        source: &str,
2237        provider: &CudaKernelProvider,
2238        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2239    ) -> Result<Vec<ExactResult>> {
2240        epistemic_prob_trace_transaction!(self, {
2241            if evidence_records.is_empty() {
2242                return Err(XlogError::UnsupportedEpistemicConstruct {
2243                    construct: "epistemic probabilistic conditioned production batch".to_string(),
2244                    context: "batched conditioned knowledge compilation requires at least one accepted GPU result"
2245                        .to_string(),
2246                });
2247            }
2248
2249            let mut accepted = Vec::with_capacity(evidence_records.len());
2250            for record in evidence_records {
2251                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2252                    provider,
2253                    record.result,
2254                    record.assumptions.to_vec(),
2255                )?);
2256            }
2257
2258            let program = parse_program(source)?;
2259            let provenance = extract_from_program(&program)?;
2260            let mut results = Vec::with_capacity(accepted.len());
2261            for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2262                let filtered_evidence;
2263                let evidence = if record.assumptions.is_empty() {
2264                    filtered_evidence =
2265                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2266                    &filtered_evidence
2267                } else {
2268                    evidence
2269                };
2270                results.push(self.compile_and_evaluate_conditioned_program_with_path(
2271                    &program,
2272                    &provenance,
2273                    evidence,
2274                    EpistemicProbConditionedEvidencePath::Source,
2275                    "epistemic probabilistic conditioned source exact compile/evaluate",
2276                )?);
2277            }
2278            Ok(results)
2279        })
2280    }
2281
2282    /// Compile conditioned source once per accepted split/batch GPU epistemic component.
2283    #[cfg(feature = "host-io")]
2284    pub fn compile_and_evaluate_conditioned_source_for_gpu_batch_execution_result(
2285        &mut self,
2286        source: &str,
2287        provider: &CudaKernelProvider,
2288        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2289    ) -> Result<Vec<ExactResult>> {
2290        epistemic_prob_trace_transaction!(self, {
2291            let auto_derived_by_component = evidence
2292                .assumptions_by_component
2293                .iter()
2294                .map(|assumptions| assumptions.is_empty())
2295                .collect::<Vec<_>>();
2296            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2297                provider,
2298                evidence,
2299                "epistemic probabilistic batch production",
2300            )?;
2301
2302            let program = parse_program(source)?;
2303            let provenance = extract_from_program(&program)?;
2304            let mut results = Vec::with_capacity(accepted.len());
2305            for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2306                let filtered_evidence;
2307                let evidence = if *auto_derived {
2308                    filtered_evidence =
2309                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2310                    &filtered_evidence
2311                } else {
2312                    evidence
2313                };
2314                results.push(self.compile_and_evaluate_conditioned_program_with_path(
2315                    &program,
2316                    &provenance,
2317                    evidence,
2318                    EpistemicProbConditionedEvidencePath::Source,
2319                    "epistemic probabilistic conditioned source exact compile/evaluate",
2320                )?);
2321            }
2322            Ok(results)
2323        })
2324    }
2325
2326    /// Compile source with accepted epistemic assumptions as exact evidence and evaluate gradients.
2327    #[cfg(feature = "host-io")]
2328    pub fn compile_and_evaluate_conditioned_source_with_grads_with_accepted_world_view(
2329        &mut self,
2330        source: &str,
2331        evidence: &AcceptedWorldViewEvidence,
2332    ) -> Result<ExactResultWithGrads> {
2333        epistemic_prob_trace_transaction!(self, {
2334            let program = parse_program(source)?;
2335            let provenance = extract_from_program(&program)?;
2336            self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2337                &program,
2338                &provenance,
2339                evidence,
2340                EpistemicProbConditionedEvidencePath::Source,
2341                "epistemic probabilistic conditioned source exact gradient",
2342            )
2343        })
2344    }
2345
2346    /// Compile source with accepted GPU epistemic assumptions as exact evidence and evaluate gradients.
2347    #[cfg(feature = "host-io")]
2348    pub fn compile_and_evaluate_conditioned_source_with_grads_with_gpu_execution_result(
2349        &mut self,
2350        source: &str,
2351        provider: &CudaKernelProvider,
2352        result: &EpistemicGpuExecutionResult,
2353        assumptions: Vec<EpistemicAssumption>,
2354    ) -> Result<ExactResultWithGrads> {
2355        epistemic_prob_trace_transaction!(self, {
2356            let auto_derived = assumptions.is_empty();
2357            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2358                provider,
2359                result,
2360                assumptions,
2361            )?;
2362            let program = parse_program(source)?;
2363            let provenance = extract_from_program(&program)?;
2364            let filtered_evidence;
2365            let evidence = if auto_derived {
2366                filtered_evidence =
2367                    evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2368                &filtered_evidence
2369            } else {
2370                &evidence
2371            };
2372            self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2373                &program,
2374                &provenance,
2375                evidence,
2376                EpistemicProbConditionedEvidencePath::Source,
2377                "epistemic probabilistic conditioned source exact gradient",
2378            )
2379        })
2380    }
2381
2382    /// Compile conditioned source gradients once per accepted GPU epistemic execution result.
2383    #[cfg(feature = "host-io")]
2384    pub fn compile_and_evaluate_conditioned_source_with_grads_for_gpu_execution_results(
2385        &mut self,
2386        source: &str,
2387        provider: &CudaKernelProvider,
2388        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2389    ) -> Result<Vec<ExactResultWithGrads>> {
2390        epistemic_prob_trace_transaction!(self, {
2391            if evidence_records.is_empty() {
2392                return Err(XlogError::UnsupportedEpistemicConstruct {
2393                    construct: "epistemic probabilistic conditioned gradient production batch"
2394                        .to_string(),
2395                    context: "batched conditioned gradient compilation requires at least one accepted GPU result"
2396                        .to_string(),
2397                });
2398            }
2399
2400            let mut accepted = Vec::with_capacity(evidence_records.len());
2401            for record in evidence_records {
2402                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2403                    provider,
2404                    record.result,
2405                    record.assumptions.to_vec(),
2406                )?);
2407            }
2408
2409            let program = parse_program(source)?;
2410            let provenance = extract_from_program(&program)?;
2411            let mut results = Vec::with_capacity(accepted.len());
2412            for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2413                let filtered_evidence;
2414                let evidence = if record.assumptions.is_empty() {
2415                    filtered_evidence =
2416                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2417                    &filtered_evidence
2418                } else {
2419                    evidence
2420                };
2421                results.push(
2422                    self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2423                        &program,
2424                        &provenance,
2425                        evidence,
2426                        EpistemicProbConditionedEvidencePath::Source,
2427                        "epistemic probabilistic conditioned source exact gradient",
2428                    )?,
2429                );
2430            }
2431            Ok(results)
2432        })
2433    }
2434
2435    /// Compile conditioned source gradients once per accepted split/batch GPU epistemic component.
2436    #[cfg(feature = "host-io")]
2437    pub fn compile_and_evaluate_conditioned_source_with_grads_for_gpu_batch_execution_result(
2438        &mut self,
2439        source: &str,
2440        provider: &CudaKernelProvider,
2441        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2442    ) -> Result<Vec<ExactResultWithGrads>> {
2443        epistemic_prob_trace_transaction!(self, {
2444            let auto_derived_by_component = evidence
2445                .assumptions_by_component
2446                .iter()
2447                .map(|assumptions| assumptions.is_empty())
2448                .collect::<Vec<_>>();
2449            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2450                provider,
2451                evidence,
2452                "epistemic probabilistic batch production",
2453            )?;
2454
2455            let program = parse_program(source)?;
2456            let provenance = extract_from_program(&program)?;
2457            let mut results = Vec::with_capacity(accepted.len());
2458            for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2459                let filtered_evidence;
2460                let evidence = if *auto_derived {
2461                    filtered_evidence =
2462                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2463                    &filtered_evidence
2464                } else {
2465                    evidence
2466                };
2467                results.push(
2468                    self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2469                        &program,
2470                        &provenance,
2471                        evidence,
2472                        EpistemicProbConditionedEvidencePath::Source,
2473                        "epistemic probabilistic conditioned source exact gradient",
2474                    )?,
2475                );
2476            }
2477            Ok(results)
2478        })
2479    }
2480
2481    #[cfg(feature = "host-io")]
2482    fn compile_and_evaluate_conditioned_program_with_path(
2483        &mut self,
2484        program: &Program,
2485        provenance: &Provenance,
2486        evidence: &AcceptedWorldViewEvidence,
2487        path: EpistemicProbConditionedEvidencePath,
2488        backend_context: &'static str,
2489    ) -> Result<ExactResult> {
2490        self.require_accepted_evidence(evidence)?;
2491        let production_events_before = self.trace.checked_gpu_production_path_events()?;
2492        let (program, evidence_counts) = condition_program_with_accepted_evidence_using_provenance(
2493            program, provenance, evidence,
2494        )?;
2495        let exact = ExactDdnnfProgram::compile_from_program(&program, self.config)?;
2496        require_gpu_exact_backend(&exact, backend_context)?;
2497        match path {
2498            EpistemicProbConditionedEvidencePath::Source => {
2499                checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2500            }
2501            EpistemicProbConditionedEvidencePath::Program => {
2502                checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
2503            }
2504        }
2505        self.record_conditioned_evidence_counts(evidence_counts, path)?;
2506        let result = exact.evaluate()?;
2507        checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
2508        checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2509        match path {
2510            EpistemicProbConditionedEvidencePath::Source => {
2511                checked_prob_trace_counter_inc!(self, gpu_source_exact_query_evaluations);
2512                checked_prob_trace_counter_inc!(
2513                    self,
2514                    gpu_source_knowledge_compilation_end_to_end_runs
2515                );
2516            }
2517            EpistemicProbConditionedEvidencePath::Program => {
2518                checked_prob_trace_counter_inc!(self, gpu_program_exact_query_evaluations);
2519                checked_prob_trace_counter_inc!(
2520                    self,
2521                    gpu_program_knowledge_compilation_end_to_end_runs
2522                );
2523            }
2524        }
2525        self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2526        self.record_accepted_evidence(evidence)?;
2527        Ok(result)
2528    }
2529
2530    #[cfg(feature = "host-io")]
2531    fn compile_and_evaluate_conditioned_program_with_grads_with_path(
2532        &mut self,
2533        program: &Program,
2534        provenance: &Provenance,
2535        evidence: &AcceptedWorldViewEvidence,
2536        path: EpistemicProbConditionedEvidencePath,
2537        backend_context: &'static str,
2538    ) -> Result<ExactResultWithGrads> {
2539        self.require_accepted_evidence(evidence)?;
2540        let production_events_before = self.trace.checked_gpu_production_path_events()?;
2541        let (program, evidence_counts) = condition_program_with_accepted_evidence_using_provenance(
2542            program, provenance, evidence,
2543        )?;
2544        let exact = ExactDdnnfProgram::compile_from_program(&program, self.config)?;
2545        require_gpu_exact_backend(&exact, backend_context)?;
2546        match path {
2547            EpistemicProbConditionedEvidencePath::Source => {
2548                checked_prob_trace_counter_inc!(self, gpu_exact_source_compiles);
2549            }
2550            EpistemicProbConditionedEvidencePath::Program => {
2551                checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
2552            }
2553        }
2554        self.record_conditioned_evidence_counts(evidence_counts, path)?;
2555        let result = exact.evaluate_gpu_with_grads()?;
2556        let origin = match path {
2557            EpistemicProbConditionedEvidencePath::Source => ExactProgramOrigin::Source,
2558            EpistemicProbConditionedEvidencePath::Program => ExactProgramOrigin::Program,
2559        };
2560        self.record_gpu_exact_gradient_evaluation_for_origin(origin)?;
2561        checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2562        match path {
2563            EpistemicProbConditionedEvidencePath::Source => {
2564                checked_prob_trace_counter_inc!(self, gpu_source_conditioned_gradient_evaluations);
2565                checked_prob_trace_counter_inc!(
2566                    self,
2567                    gpu_source_knowledge_compilation_end_to_end_runs
2568                );
2569            }
2570            EpistemicProbConditionedEvidencePath::Program => {
2571                checked_prob_trace_counter_inc!(self, gpu_program_conditioned_gradient_evaluations);
2572                checked_prob_trace_counter_inc!(
2573                    self,
2574                    gpu_program_knowledge_compilation_end_to_end_runs
2575                );
2576            }
2577        }
2578        self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2579        self.record_accepted_evidence(evidence)?;
2580        Ok(result)
2581    }
2582
2583    /// Compile a parsed program with accepted epistemic assumptions as exact evidence.
2584    #[cfg(feature = "host-io")]
2585    pub fn compile_and_evaluate_conditioned_program_with_accepted_world_view(
2586        &mut self,
2587        program: &Program,
2588        evidence: &AcceptedWorldViewEvidence,
2589    ) -> Result<ExactResult> {
2590        epistemic_prob_trace_transaction!(self, {
2591            let provenance = extract_from_program(program)?;
2592            self.compile_and_evaluate_conditioned_program_with_path(
2593                program,
2594                &provenance,
2595                evidence,
2596                EpistemicProbConditionedEvidencePath::Program,
2597                "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2598            )
2599        })
2600    }
2601
2602    /// Compile a parsed program with accepted GPU epistemic assumptions as exact evidence.
2603    #[cfg(feature = "host-io")]
2604    pub fn compile_and_evaluate_conditioned_program_with_gpu_execution_result(
2605        &mut self,
2606        program: &Program,
2607        provider: &CudaKernelProvider,
2608        result: &EpistemicGpuExecutionResult,
2609        assumptions: Vec<EpistemicAssumption>,
2610    ) -> Result<ExactResult> {
2611        epistemic_prob_trace_transaction!(self, {
2612            let auto_derived = assumptions.is_empty();
2613            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2614                provider,
2615                result,
2616                assumptions,
2617            )?;
2618            let provenance = extract_from_program(program)?;
2619            let filtered_evidence;
2620            let evidence = if auto_derived {
2621                filtered_evidence =
2622                    evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2623                &filtered_evidence
2624            } else {
2625                &evidence
2626            };
2627            self.compile_and_evaluate_conditioned_program_with_path(
2628                program,
2629                &provenance,
2630                evidence,
2631                EpistemicProbConditionedEvidencePath::Program,
2632                "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2633            )
2634        })
2635    }
2636
2637    /// Compile conditioned parsed program once per accepted GPU epistemic execution result.
2638    #[cfg(feature = "host-io")]
2639    pub fn compile_and_evaluate_conditioned_program_for_gpu_execution_results(
2640        &mut self,
2641        program: &Program,
2642        provider: &CudaKernelProvider,
2643        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2644    ) -> Result<Vec<ExactResult>> {
2645        epistemic_prob_trace_transaction!(self, {
2646            if evidence_records.is_empty() {
2647                return Err(XlogError::UnsupportedEpistemicConstruct {
2648                    construct: "epistemic probabilistic conditioned production batch".to_string(),
2649                    context: "batched conditioned program compilation requires at least one accepted GPU result"
2650                        .to_string(),
2651                });
2652            }
2653
2654            let mut accepted = Vec::with_capacity(evidence_records.len());
2655            for record in evidence_records {
2656                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2657                    provider,
2658                    record.result,
2659                    record.assumptions.to_vec(),
2660                )?);
2661            }
2662
2663            let provenance = extract_from_program(program)?;
2664            let mut results = Vec::with_capacity(accepted.len());
2665            for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2666                let filtered_evidence;
2667                let evidence = if record.assumptions.is_empty() {
2668                    filtered_evidence =
2669                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2670                    &filtered_evidence
2671                } else {
2672                    evidence
2673                };
2674                results.push(self.compile_and_evaluate_conditioned_program_with_path(
2675                    program,
2676                    &provenance,
2677                    evidence,
2678                    EpistemicProbConditionedEvidencePath::Program,
2679                    "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2680                )?);
2681            }
2682            Ok(results)
2683        })
2684    }
2685
2686    /// Compile conditioned parsed program once per accepted split/batch GPU epistemic component.
2687    #[cfg(feature = "host-io")]
2688    pub fn compile_and_evaluate_conditioned_program_for_gpu_batch_execution_result(
2689        &mut self,
2690        program: &Program,
2691        provider: &CudaKernelProvider,
2692        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2693    ) -> Result<Vec<ExactResult>> {
2694        epistemic_prob_trace_transaction!(self, {
2695            let auto_derived_by_component = evidence
2696                .assumptions_by_component
2697                .iter()
2698                .map(|assumptions| assumptions.is_empty())
2699                .collect::<Vec<_>>();
2700            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2701                provider,
2702                evidence,
2703                "epistemic probabilistic batch production",
2704            )?;
2705
2706            let provenance = extract_from_program(program)?;
2707            let mut results = Vec::with_capacity(accepted.len());
2708            for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2709                let filtered_evidence;
2710                let evidence = if *auto_derived {
2711                    filtered_evidence =
2712                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2713                    &filtered_evidence
2714                } else {
2715                    evidence
2716                };
2717                results.push(self.compile_and_evaluate_conditioned_program_with_path(
2718                    program,
2719                    &provenance,
2720                    evidence,
2721                    EpistemicProbConditionedEvidencePath::Program,
2722                    "epistemic probabilistic conditioned parsed-program exact compile/evaluate",
2723                )?);
2724            }
2725            Ok(results)
2726        })
2727    }
2728
2729    /// Compile a parsed program with accepted epistemic assumptions as exact evidence and evaluate gradients.
2730    #[cfg(feature = "host-io")]
2731    pub fn compile_and_evaluate_conditioned_program_with_grads_with_accepted_world_view(
2732        &mut self,
2733        program: &Program,
2734        evidence: &AcceptedWorldViewEvidence,
2735    ) -> Result<ExactResultWithGrads> {
2736        epistemic_prob_trace_transaction!(self, {
2737            let provenance = extract_from_program(program)?;
2738            self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2739                program,
2740                &provenance,
2741                evidence,
2742                EpistemicProbConditionedEvidencePath::Program,
2743                "epistemic probabilistic conditioned parsed-program exact gradient",
2744            )
2745        })
2746    }
2747
2748    /// Compile a parsed program with accepted GPU epistemic assumptions as exact evidence and evaluate gradients.
2749    #[cfg(feature = "host-io")]
2750    pub fn compile_and_evaluate_conditioned_program_with_grads_with_gpu_execution_result(
2751        &mut self,
2752        program: &Program,
2753        provider: &CudaKernelProvider,
2754        result: &EpistemicGpuExecutionResult,
2755        assumptions: Vec<EpistemicAssumption>,
2756    ) -> Result<ExactResultWithGrads> {
2757        epistemic_prob_trace_transaction!(self, {
2758            let auto_derived = assumptions.is_empty();
2759            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
2760                provider,
2761                result,
2762                assumptions,
2763            )?;
2764            let provenance = extract_from_program(program)?;
2765            let filtered_evidence;
2766            let evidence = if auto_derived {
2767                filtered_evidence =
2768                    evidence_with_provenance_backed_assumptions(&evidence, &provenance)?;
2769                &filtered_evidence
2770            } else {
2771                &evidence
2772            };
2773            self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2774                program,
2775                &provenance,
2776                evidence,
2777                EpistemicProbConditionedEvidencePath::Program,
2778                "epistemic probabilistic conditioned parsed-program exact gradient",
2779            )
2780        })
2781    }
2782
2783    /// Compile conditioned parsed-program gradients once per accepted GPU epistemic execution result.
2784    #[cfg(feature = "host-io")]
2785    pub fn compile_and_evaluate_conditioned_program_with_grads_for_gpu_execution_results(
2786        &mut self,
2787        program: &Program,
2788        provider: &CudaKernelProvider,
2789        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2790    ) -> Result<Vec<ExactResultWithGrads>> {
2791        epistemic_prob_trace_transaction!(self, {
2792            if evidence_records.is_empty() {
2793                return Err(XlogError::UnsupportedEpistemicConstruct {
2794                    construct: "epistemic probabilistic conditioned gradient production batch"
2795                        .to_string(),
2796                    context: "batched conditioned program gradient compilation requires at least one accepted GPU result"
2797                        .to_string(),
2798                });
2799            }
2800
2801            let mut accepted = Vec::with_capacity(evidence_records.len());
2802            for record in evidence_records {
2803                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2804                    provider,
2805                    record.result,
2806                    record.assumptions.to_vec(),
2807                )?);
2808            }
2809
2810            let provenance = extract_from_program(program)?;
2811            let mut results = Vec::with_capacity(accepted.len());
2812            for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
2813                let filtered_evidence;
2814                let evidence = if record.assumptions.is_empty() {
2815                    filtered_evidence =
2816                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2817                    &filtered_evidence
2818                } else {
2819                    evidence
2820                };
2821                results.push(
2822                    self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2823                        program,
2824                        &provenance,
2825                        evidence,
2826                        EpistemicProbConditionedEvidencePath::Program,
2827                        "epistemic probabilistic conditioned parsed-program exact gradient",
2828                    )?,
2829                );
2830            }
2831            Ok(results)
2832        })
2833    }
2834
2835    /// Compile conditioned parsed-program gradients once per accepted split/batch GPU epistemic component.
2836    #[cfg(feature = "host-io")]
2837    pub fn compile_and_evaluate_conditioned_program_with_grads_for_gpu_batch_execution_result(
2838        &mut self,
2839        program: &Program,
2840        provider: &CudaKernelProvider,
2841        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2842    ) -> Result<Vec<ExactResultWithGrads>> {
2843        epistemic_prob_trace_transaction!(self, {
2844            let auto_derived_by_component = evidence
2845                .assumptions_by_component
2846                .iter()
2847                .map(|assumptions| assumptions.is_empty())
2848                .collect::<Vec<_>>();
2849            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2850                provider,
2851                evidence,
2852                "epistemic probabilistic batch production",
2853            )?;
2854
2855            let provenance = extract_from_program(program)?;
2856            let mut results = Vec::with_capacity(accepted.len());
2857            for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
2858                let filtered_evidence;
2859                let evidence = if *auto_derived {
2860                    filtered_evidence =
2861                        evidence_with_provenance_backed_assumptions(evidence, &provenance)?;
2862                    &filtered_evidence
2863                } else {
2864                    evidence
2865                };
2866                results.push(
2867                    self.compile_and_evaluate_conditioned_program_with_grads_with_path(
2868                        program,
2869                        &provenance,
2870                        evidence,
2871                        EpistemicProbConditionedEvidencePath::Program,
2872                        "epistemic probabilistic conditioned parsed-program exact gradient",
2873                    )?,
2874                );
2875            }
2876            Ok(results)
2877        })
2878    }
2879
2880    /// Compile a parsed program and evaluate queries through the existing GPU exact path.
2881    #[cfg(feature = "host-io")]
2882    pub fn compile_and_evaluate_program_with_accepted_world_view(
2883        &mut self,
2884        program: &Program,
2885        evidence: &AcceptedWorldViewEvidence,
2886    ) -> Result<ExactResult> {
2887        epistemic_prob_trace_transaction!(self, {
2888            self.require_accepted_evidence(evidence)?;
2889            let production_events_before = self.trace.checked_gpu_production_path_events()?;
2890            let exact = ExactDdnnfProgram::compile_from_program(program, self.config)?;
2891            require_gpu_exact_backend(
2892                &exact,
2893                "epistemic probabilistic parsed-program exact compile/evaluate",
2894            )?;
2895            checked_prob_trace_counter_inc!(self, gpu_exact_program_compiles);
2896            let result = exact.evaluate()?;
2897            checked_prob_trace_counter_inc!(self, gpu_exact_query_evaluations);
2898            checked_prob_trace_counter_inc!(self, gpu_program_exact_query_evaluations);
2899            checked_prob_trace_counter_inc!(self, gpu_knowledge_compilation_end_to_end_runs);
2900            checked_prob_trace_counter_inc!(
2901                self,
2902                gpu_program_knowledge_compilation_end_to_end_runs
2903            );
2904            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
2905            self.record_accepted_evidence(evidence)?;
2906            Ok(result)
2907        })
2908    }
2909
2910    /// Compile a parsed program and evaluate queries after accepted GPU epistemic execution.
2911    #[cfg(feature = "host-io")]
2912    pub fn compile_and_evaluate_program_with_gpu_execution_result(
2913        &mut self,
2914        program: &Program,
2915        provider: &CudaKernelProvider,
2916        result: &EpistemicGpuExecutionResult,
2917        assumptions: Vec<EpistemicAssumption>,
2918    ) -> Result<ExactResult> {
2919        let evidence =
2920            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
2921        self.compile_and_evaluate_program_with_accepted_world_view(program, &evidence)
2922    }
2923
2924    /// Compile and evaluate a parsed program once per accepted GPU epistemic execution result.
2925    #[cfg(feature = "host-io")]
2926    pub fn compile_and_evaluate_program_for_gpu_execution_results(
2927        &mut self,
2928        program: &Program,
2929        provider: &CudaKernelProvider,
2930        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
2931    ) -> Result<Vec<ExactResult>> {
2932        epistemic_prob_trace_transaction!(self, {
2933            if evidence_records.is_empty() {
2934                return Err(XlogError::UnsupportedEpistemicConstruct {
2935                    construct: "epistemic probabilistic parsed-program production batch"
2936                        .to_string(),
2937                    context: "batched parsed-program knowledge compilation requires at least one accepted GPU result"
2938                        .to_string(),
2939                });
2940            }
2941
2942            let mut accepted = Vec::with_capacity(evidence_records.len());
2943            for record in evidence_records {
2944                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
2945                    provider,
2946                    record.result,
2947                    record.assumptions.to_vec(),
2948                )?);
2949            }
2950
2951            let mut results = Vec::with_capacity(accepted.len());
2952            for evidence in &accepted {
2953                results.push(
2954                    self.compile_and_evaluate_program_with_accepted_world_view(program, evidence)?,
2955                );
2956            }
2957            Ok(results)
2958        })
2959    }
2960
2961    /// Compile and evaluate a parsed program once per accepted split/batch GPU epistemic component.
2962    #[cfg(feature = "host-io")]
2963    pub fn compile_and_evaluate_program_for_gpu_batch_execution_result(
2964        &mut self,
2965        program: &Program,
2966        provider: &CudaKernelProvider,
2967        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
2968    ) -> Result<Vec<ExactResult>> {
2969        epistemic_prob_trace_transaction!(self, {
2970            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
2971                provider,
2972                evidence,
2973                "epistemic probabilistic batch production",
2974            )?;
2975
2976            let mut results = Vec::with_capacity(accepted.len());
2977            for evidence in &accepted {
2978                results.push(
2979                    self.compile_and_evaluate_program_with_accepted_world_view(program, evidence)?,
2980                );
2981            }
2982            Ok(results)
2983        })
2984    }
2985
2986    /// Encode source through the existing GPU PIR and CNF production path.
2987    pub fn encode_source_pir_cnf_with_accepted_world_view(
2988        &mut self,
2989        source: &str,
2990        provider: &Arc<CudaKernelProvider>,
2991        evidence: &AcceptedWorldViewEvidence,
2992    ) -> Result<EpistemicProbPirCnfEvidence> {
2993        epistemic_prob_trace_transaction!(self, {
2994            self.require_accepted_evidence(evidence)?;
2995            let program = parse_program(source)?;
2996            let base_provenance = extract_from_program(&program)?;
2997            self.encode_program_pir_cnf_with_base_provenance(
2998                &program,
2999                &base_provenance,
3000                provider,
3001                evidence,
3002                EpistemicProbPirCnfPath::Source,
3003            )
3004        })
3005    }
3006
3007    /// Encode source PIR/CNF after accepted GPU epistemic execution.
3008    pub fn encode_source_pir_cnf_with_gpu_execution_result(
3009        &mut self,
3010        source: &str,
3011        provider: &Arc<CudaKernelProvider>,
3012        result: &EpistemicGpuExecutionResult,
3013        assumptions: Vec<EpistemicAssumption>,
3014    ) -> Result<EpistemicProbPirCnfEvidence> {
3015        epistemic_prob_trace_transaction!(self, {
3016            let auto_derived = assumptions.is_empty();
3017            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
3018                provider,
3019                result,
3020                assumptions,
3021            )?;
3022            let program = parse_program(source)?;
3023            let base_provenance = extract_from_program(&program)?;
3024            let filtered_evidence;
3025            let evidence = if auto_derived {
3026                filtered_evidence =
3027                    evidence_with_provenance_backed_assumptions(&evidence, &base_provenance)?;
3028                &filtered_evidence
3029            } else {
3030                &evidence
3031            };
3032            self.encode_program_pir_cnf_with_base_provenance(
3033                &program,
3034                &base_provenance,
3035                provider,
3036                evidence,
3037                EpistemicProbPirCnfPath::Source,
3038            )
3039        })
3040    }
3041
3042    /// Encode source PIR/CNF once per accepted GPU epistemic execution result.
3043    pub fn encode_source_pir_cnf_for_gpu_execution_results(
3044        &mut self,
3045        source: &str,
3046        provider: &Arc<CudaKernelProvider>,
3047        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3048    ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3049        epistemic_prob_trace_transaction!(self, {
3050            if evidence_records.is_empty() {
3051                return Err(XlogError::UnsupportedEpistemicConstruct {
3052                    construct: "epistemic probabilistic source PIR/CNF production batch"
3053                        .to_string(),
3054                    context:
3055                        "batched source PIR/CNF encoding requires at least one accepted GPU result"
3056                            .to_string(),
3057                });
3058            }
3059
3060            let mut accepted = Vec::with_capacity(evidence_records.len());
3061            for record in evidence_records {
3062                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3063                    provider,
3064                    record.result,
3065                    record.assumptions.to_vec(),
3066                )?);
3067            }
3068
3069            let program = parse_program(source)?;
3070            let base_provenance = extract_from_program(&program)?;
3071            let mut results = Vec::with_capacity(accepted.len());
3072            for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
3073                let filtered_evidence;
3074                let evidence = if record.assumptions.is_empty() {
3075                    filtered_evidence =
3076                        evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3077                    &filtered_evidence
3078                } else {
3079                    evidence
3080                };
3081                results.push(self.encode_program_pir_cnf_with_base_provenance(
3082                    &program,
3083                    &base_provenance,
3084                    provider,
3085                    evidence,
3086                    EpistemicProbPirCnfPath::Source,
3087                )?);
3088            }
3089            Ok(results)
3090        })
3091    }
3092
3093    /// Encode source PIR/CNF once per accepted split/batch GPU epistemic component.
3094    pub fn encode_source_pir_cnf_for_gpu_batch_execution_result(
3095        &mut self,
3096        source: &str,
3097        provider: &Arc<CudaKernelProvider>,
3098        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3099    ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3100        epistemic_prob_trace_transaction!(self, {
3101            let auto_derived_by_component = evidence
3102                .assumptions_by_component
3103                .iter()
3104                .map(|assumptions| assumptions.is_empty())
3105                .collect::<Vec<_>>();
3106            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3107                provider.as_ref(),
3108                evidence,
3109                "epistemic probabilistic source PIR/CNF batch production",
3110            )?;
3111
3112            let program = parse_program(source)?;
3113            let base_provenance = extract_from_program(&program)?;
3114            let mut results = Vec::with_capacity(accepted.len());
3115            for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
3116                let filtered_evidence;
3117                let evidence = if *auto_derived {
3118                    filtered_evidence =
3119                        evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3120                    &filtered_evidence
3121                } else {
3122                    evidence
3123                };
3124                results.push(self.encode_program_pir_cnf_with_base_provenance(
3125                    &program,
3126                    &base_provenance,
3127                    provider,
3128                    evidence,
3129                    EpistemicProbPirCnfPath::Source,
3130                )?);
3131            }
3132            Ok(results)
3133        })
3134    }
3135
3136    /// Encode a parsed program through the existing GPU PIR and CNF production path.
3137    pub fn encode_program_pir_cnf_with_accepted_world_view(
3138        &mut self,
3139        program: &Program,
3140        provider: &Arc<CudaKernelProvider>,
3141        evidence: &AcceptedWorldViewEvidence,
3142    ) -> Result<EpistemicProbPirCnfEvidence> {
3143        epistemic_prob_trace_transaction!(self, {
3144            self.require_accepted_evidence(evidence)?;
3145            let base_provenance = extract_from_program(program)?;
3146            self.encode_program_pir_cnf_with_base_provenance(
3147                program,
3148                &base_provenance,
3149                provider,
3150                evidence,
3151                EpistemicProbPirCnfPath::Program,
3152            )
3153        })
3154    }
3155
3156    /// Encode parsed-program PIR/CNF after accepted GPU epistemic execution.
3157    pub fn encode_program_pir_cnf_with_gpu_execution_result(
3158        &mut self,
3159        program: &Program,
3160        provider: &Arc<CudaKernelProvider>,
3161        result: &EpistemicGpuExecutionResult,
3162        assumptions: Vec<EpistemicAssumption>,
3163    ) -> Result<EpistemicProbPirCnfEvidence> {
3164        epistemic_prob_trace_transaction!(self, {
3165            let auto_derived = assumptions.is_empty();
3166            let evidence = AcceptedWorldViewEvidence::from_gpu_execution_result(
3167                provider,
3168                result,
3169                assumptions,
3170            )?;
3171            let base_provenance = extract_from_program(program)?;
3172            let filtered_evidence;
3173            let evidence = if auto_derived {
3174                filtered_evidence =
3175                    evidence_with_provenance_backed_assumptions(&evidence, &base_provenance)?;
3176                &filtered_evidence
3177            } else {
3178                &evidence
3179            };
3180            self.encode_program_pir_cnf_with_base_provenance(
3181                program,
3182                &base_provenance,
3183                provider,
3184                evidence,
3185                EpistemicProbPirCnfPath::Program,
3186            )
3187        })
3188    }
3189
3190    /// Encode parsed-program PIR/CNF once per accepted GPU epistemic execution result.
3191    pub fn encode_program_pir_cnf_for_gpu_execution_results(
3192        &mut self,
3193        program: &Program,
3194        provider: &Arc<CudaKernelProvider>,
3195        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3196    ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3197        epistemic_prob_trace_transaction!(self, {
3198            if evidence_records.is_empty() {
3199                return Err(XlogError::UnsupportedEpistemicConstruct {
3200                    construct: "epistemic probabilistic parsed-program PIR/CNF production batch"
3201                        .to_string(),
3202                    context:
3203                        "batched parsed-program PIR/CNF encoding requires at least one accepted GPU result"
3204                            .to_string(),
3205                });
3206            }
3207
3208            let mut accepted = Vec::with_capacity(evidence_records.len());
3209            for record in evidence_records {
3210                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3211                    provider,
3212                    record.result,
3213                    record.assumptions.to_vec(),
3214                )?);
3215            }
3216
3217            let base_provenance = extract_from_program(program)?;
3218            let mut results = Vec::with_capacity(accepted.len());
3219            for (record, evidence) in evidence_records.iter().zip(accepted.iter()) {
3220                let filtered_evidence;
3221                let evidence = if record.assumptions.is_empty() {
3222                    filtered_evidence =
3223                        evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3224                    &filtered_evidence
3225                } else {
3226                    evidence
3227                };
3228                results.push(self.encode_program_pir_cnf_with_base_provenance(
3229                    program,
3230                    &base_provenance,
3231                    provider,
3232                    evidence,
3233                    EpistemicProbPirCnfPath::Program,
3234                )?);
3235            }
3236            Ok(results)
3237        })
3238    }
3239
3240    /// Encode parsed-program PIR/CNF once per accepted split/batch GPU epistemic component.
3241    pub fn encode_program_pir_cnf_for_gpu_batch_execution_result(
3242        &mut self,
3243        program: &Program,
3244        provider: &Arc<CudaKernelProvider>,
3245        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3246    ) -> Result<Vec<EpistemicProbPirCnfEvidence>> {
3247        epistemic_prob_trace_transaction!(self, {
3248            let auto_derived_by_component = evidence
3249                .assumptions_by_component
3250                .iter()
3251                .map(|assumptions| assumptions.is_empty())
3252                .collect::<Vec<_>>();
3253            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3254                provider.as_ref(),
3255                evidence,
3256                "epistemic probabilistic parsed-program PIR/CNF batch production",
3257            )?;
3258
3259            let base_provenance = extract_from_program(program)?;
3260            let mut results = Vec::with_capacity(accepted.len());
3261            for (auto_derived, evidence) in auto_derived_by_component.iter().zip(accepted.iter()) {
3262                let filtered_evidence;
3263                let evidence = if *auto_derived {
3264                    filtered_evidence =
3265                        evidence_with_provenance_backed_assumptions(evidence, &base_provenance)?;
3266                    &filtered_evidence
3267                } else {
3268                    evidence
3269                };
3270                results.push(self.encode_program_pir_cnf_with_base_provenance(
3271                    program,
3272                    &base_provenance,
3273                    provider,
3274                    evidence,
3275                    EpistemicProbPirCnfPath::Program,
3276                )?);
3277            }
3278            Ok(results)
3279        })
3280    }
3281
3282    /// Evaluate GPU exact query probabilities after accepted world-view evidence was consumed.
3283    #[cfg(feature = "host-io")]
3284    pub fn evaluate(
3285        &mut self,
3286        program: &ExactDdnnfProgram,
3287        evidence: &AcceptedWorldViewEvidence,
3288    ) -> Result<ExactResult> {
3289        epistemic_prob_trace_transaction!(self, {
3290            self.require_accepted_evidence(evidence)?;
3291            let production_events_before = self.trace.checked_gpu_production_path_events()?;
3292            require_gpu_exact_backend(program, "epistemic probabilistic exact query evaluation")?;
3293            let result = program.evaluate()?;
3294            self.record_gpu_exact_query_evaluation(program)?;
3295            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
3296            self.record_accepted_evidence(evidence)?;
3297            Ok(result)
3298        })
3299    }
3300
3301    /// Evaluate GPU exact query probabilities after accepted GPU epistemic execution.
3302    #[cfg(feature = "host-io")]
3303    pub fn evaluate_with_gpu_execution_result(
3304        &mut self,
3305        program: &ExactDdnnfProgram,
3306        provider: &CudaKernelProvider,
3307        result: &EpistemicGpuExecutionResult,
3308        assumptions: Vec<EpistemicAssumption>,
3309    ) -> Result<ExactResult> {
3310        let evidence =
3311            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
3312        self.evaluate(program, &evidence)
3313    }
3314
3315    /// Evaluate GPU exact query probabilities once per accepted GPU epistemic execution result.
3316    #[cfg(feature = "host-io")]
3317    pub fn evaluate_for_gpu_execution_results(
3318        &mut self,
3319        program: &ExactDdnnfProgram,
3320        provider: &CudaKernelProvider,
3321        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3322    ) -> Result<Vec<ExactResult>> {
3323        epistemic_prob_trace_transaction!(self, {
3324            if evidence_records.is_empty() {
3325                return Err(XlogError::UnsupportedEpistemicConstruct {
3326                    construct: "epistemic probabilistic query evaluation production batch"
3327                        .to_string(),
3328                    context: "batched query evaluation requires at least one accepted GPU result"
3329                        .to_string(),
3330                });
3331            }
3332
3333            let mut accepted = Vec::with_capacity(evidence_records.len());
3334            for record in evidence_records {
3335                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3336                    provider,
3337                    record.result,
3338                    record.assumptions.to_vec(),
3339                )?);
3340            }
3341
3342            let mut results = Vec::with_capacity(accepted.len());
3343            for evidence in &accepted {
3344                results.push(self.evaluate(program, evidence)?);
3345            }
3346            Ok(results)
3347        })
3348    }
3349
3350    /// Evaluate GPU exact query probabilities once per accepted split/batch GPU epistemic component.
3351    #[cfg(feature = "host-io")]
3352    pub fn evaluate_for_gpu_batch_execution_result(
3353        &mut self,
3354        program: &ExactDdnnfProgram,
3355        provider: &CudaKernelProvider,
3356        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3357    ) -> Result<Vec<ExactResult>> {
3358        epistemic_prob_trace_transaction!(self, {
3359            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3360                provider,
3361                evidence,
3362                "epistemic probabilistic query evaluation batch production",
3363            )?;
3364
3365            let mut results = Vec::with_capacity(accepted.len());
3366            for evidence in &accepted {
3367                results.push(self.evaluate(program, evidence)?);
3368            }
3369            Ok(results)
3370        })
3371    }
3372
3373    /// Evaluate GPU exact gradients after accepted world-view evidence was consumed.
3374    #[cfg(feature = "host-io")]
3375    pub fn evaluate_gpu_with_grads(
3376        &mut self,
3377        program: &ExactDdnnfProgram,
3378        evidence: &AcceptedWorldViewEvidence,
3379    ) -> Result<ExactResultWithGrads> {
3380        epistemic_prob_trace_transaction!(self, {
3381            self.require_accepted_evidence(evidence)?;
3382            let production_events_before = self.trace.checked_gpu_production_path_events()?;
3383            require_gpu_exact_backend(
3384                program,
3385                "epistemic probabilistic exact gradient evaluation",
3386            )?;
3387            let result = program.evaluate_gpu_with_grads()?;
3388            self.record_gpu_exact_gradient_evaluation(program)?;
3389            self.record_accepted_gpu_production_path_events_since(production_events_before)?;
3390            self.record_accepted_evidence(evidence)?;
3391            Ok(result)
3392        })
3393    }
3394
3395    /// Evaluate GPU exact gradients after accepted GPU epistemic execution.
3396    #[cfg(feature = "host-io")]
3397    pub fn evaluate_gpu_with_grads_with_gpu_execution_result(
3398        &mut self,
3399        program: &ExactDdnnfProgram,
3400        provider: &CudaKernelProvider,
3401        result: &EpistemicGpuExecutionResult,
3402        assumptions: Vec<EpistemicAssumption>,
3403    ) -> Result<ExactResultWithGrads> {
3404        let evidence =
3405            AcceptedWorldViewEvidence::from_gpu_execution_result(provider, result, assumptions)?;
3406        self.evaluate_gpu_with_grads(program, &evidence)
3407    }
3408
3409    /// Evaluate GPU exact gradients once per accepted GPU epistemic execution result.
3410    #[cfg(feature = "host-io")]
3411    pub fn evaluate_gpu_with_grads_for_gpu_execution_results(
3412        &mut self,
3413        program: &ExactDdnnfProgram,
3414        provider: &CudaKernelProvider,
3415        evidence_records: &[EpistemicProbGpuExecutionEvidence<'_>],
3416    ) -> Result<Vec<ExactResultWithGrads>> {
3417        epistemic_prob_trace_transaction!(self, {
3418            if evidence_records.is_empty() {
3419                return Err(XlogError::UnsupportedEpistemicConstruct {
3420                    construct: "epistemic probabilistic gradient evaluation production batch"
3421                        .to_string(),
3422                    context:
3423                        "batched gradient evaluation requires at least one accepted GPU result"
3424                            .to_string(),
3425                });
3426            }
3427
3428            let mut accepted = Vec::with_capacity(evidence_records.len());
3429            for record in evidence_records {
3430                accepted.push(AcceptedWorldViewEvidence::from_gpu_execution_result(
3431                    provider,
3432                    record.result,
3433                    record.assumptions.to_vec(),
3434                )?);
3435            }
3436
3437            let mut results = Vec::with_capacity(accepted.len());
3438            for evidence in &accepted {
3439                results.push(self.evaluate_gpu_with_grads(program, evidence)?);
3440            }
3441            Ok(results)
3442        })
3443    }
3444
3445    /// Evaluate GPU exact gradients once per accepted split/batch GPU epistemic component.
3446    #[cfg(feature = "host-io")]
3447    pub fn evaluate_gpu_with_grads_for_gpu_batch_execution_result(
3448        &mut self,
3449        program: &ExactDdnnfProgram,
3450        provider: &CudaKernelProvider,
3451        evidence: EpistemicProbGpuBatchExecutionEvidence<'_>,
3452    ) -> Result<Vec<ExactResultWithGrads>> {
3453        epistemic_prob_trace_transaction!(self, {
3454            let accepted = self.accepted_world_views_from_gpu_batch_execution_evidence(
3455                provider,
3456                evidence,
3457                "epistemic probabilistic gradient evaluation batch production",
3458            )?;
3459
3460            let mut results = Vec::with_capacity(accepted.len());
3461            for evidence in &accepted {
3462                results.push(self.evaluate_gpu_with_grads(program, evidence)?);
3463            }
3464            Ok(results)
3465        })
3466    }
3467
3468    fn consume_accepted_evidence(&mut self, evidence: &AcceptedWorldViewEvidence) -> Result<()> {
3469        self.require_accepted_evidence(evidence)?;
3470        self.record_accepted_evidence(evidence)?;
3471        Ok(())
3472    }
3473
3474    fn require_accepted_evidence(&self, evidence: &AcceptedWorldViewEvidence) -> Result<()> {
3475        if evidence.world_count() == 0 {
3476            return Err(XlogError::UnsupportedEpistemicConstruct {
3477                construct: "accepted world-view evidence".to_string(),
3478                context: "probabilistic production path requires a non-empty accepted world view"
3479                    .to_string(),
3480            });
3481        }
3482        if evidence.gpu_epistemic_mode().is_none() {
3483            return Err(XlogError::UnsupportedEpistemicConstruct {
3484                construct: "accepted world-view evidence".to_string(),
3485                context: "probabilistic production path requires GPU execution evidence; CPU \
3486                     world-view evidence is oracle-only"
3487                    .to_string(),
3488            });
3489        }
3490        Ok(())
3491    }
3492
3493    fn record_accepted_evidence(&mut self, evidence: &AcceptedWorldViewEvidence) -> Result<()> {
3494        self.trace.accepted_world_view_evidence_consumed = Self::checked_trace_counter_add(
3495            self.trace.accepted_world_view_evidence_consumed,
3496            1,
3497            "accepted_world_view_evidence_consumed",
3498        )?;
3499        match evidence.gpu_epistemic_mode() {
3500            Some(EirEpistemicMode::G91) => {
3501                self.trace.accepted_g91_world_view_evidence_consumed =
3502                    Self::checked_trace_counter_add(
3503                        self.trace.accepted_g91_world_view_evidence_consumed,
3504                        1,
3505                        "accepted_g91_world_view_evidence_consumed",
3506                    )?;
3507            }
3508            Some(EirEpistemicMode::Faeel) => {
3509                self.trace.accepted_faeel_world_view_evidence_consumed =
3510                    Self::checked_trace_counter_add(
3511                        self.trace.accepted_faeel_world_view_evidence_consumed,
3512                        1,
3513                        "accepted_faeel_world_view_evidence_consumed",
3514                    )?;
3515            }
3516            None => {}
3517        }
3518        self.trace.accepted_evidence_assumptions_consumed = Self::checked_trace_counter_add(
3519            self.trace.accepted_evidence_assumptions_consumed,
3520            evidence.assumption_count() as u64,
3521            "accepted_evidence_assumptions_consumed",
3522        )?;
3523        self.trace
3524            .accepted_gpu_nonzero_arity_evidence_assumptions_consumed =
3525            Self::checked_trace_counter_add(
3526                self.trace
3527                    .accepted_gpu_nonzero_arity_evidence_assumptions_consumed,
3528                evidence.nonzero_arity_assumption_count() as u64,
3529                "accepted_gpu_nonzero_arity_evidence_assumptions_consumed",
3530            )?;
3531        if evidence.max_assumption_arity() > u32::MAX as usize {
3532            return Err(XlogError::ResourceExhausted {
3533                context: "accepted GPU probability evidence max arity".to_string(),
3534                estimated_bytes: evidence.max_assumption_arity() as u64,
3535                budget_bytes: u32::MAX as u64,
3536            });
3537        }
3538        self.trace.accepted_gpu_max_evidence_arity_consumed = self
3539            .trace
3540            .accepted_gpu_max_evidence_arity_consumed
3541            .max(evidence.max_assumption_arity() as u32);
3542        self.trace.accepted_gpu_tuple_key_column_reads_consumed = Self::checked_trace_counter_add(
3543            self.trace.accepted_gpu_tuple_key_column_reads_consumed,
3544            evidence.gpu_tuple_key_column_reads() as u64,
3545            "accepted_gpu_tuple_key_column_reads_consumed",
3546        )?;
3547        self.trace.accepted_gpu_final_tuple_row_filters_consumed = Self::checked_trace_counter_add(
3548            self.trace.accepted_gpu_final_tuple_row_filters_consumed,
3549            evidence.gpu_final_tuple_row_filters() as u64,
3550            "accepted_gpu_final_tuple_row_filters_consumed",
3551        )?;
3552        self.trace
3553            .accepted_gpu_final_tuple_negated_row_filters_consumed =
3554            Self::checked_trace_counter_add(
3555                self.trace
3556                    .accepted_gpu_final_tuple_negated_row_filters_consumed,
3557                evidence.gpu_final_tuple_negated_row_filters() as u64,
3558                "accepted_gpu_final_tuple_negated_row_filters_consumed",
3559            )?;
3560        self.trace
3561            .accepted_gpu_row_specific_membership_row_capacity_consumed =
3562            Self::checked_trace_counter_add(
3563                self.trace
3564                    .accepted_gpu_row_specific_membership_row_capacity_consumed,
3565                evidence.gpu_row_specific_membership_row_capacity() as u64,
3566                "accepted_gpu_row_specific_membership_row_capacity_consumed",
3567            )?;
3568        self.trace
3569            .accepted_gpu_row_filter_fallback_row_capacity_consumed =
3570            Self::checked_trace_counter_add(
3571                self.trace
3572                    .accepted_gpu_row_filter_fallback_row_capacity_consumed,
3573                evidence.gpu_row_filter_fallback_row_capacity() as u64,
3574                "accepted_gpu_row_filter_fallback_row_capacity_consumed",
3575            )?;
3576        self.trace
3577            .accepted_gpu_constraint_relations_checked_consumed = Self::checked_trace_counter_add(
3578            self.trace
3579                .accepted_gpu_constraint_relations_checked_consumed,
3580            evidence.gpu_checked_constraint_relations() as u64,
3581            "accepted_gpu_constraint_relations_checked_consumed",
3582        )?;
3583        self.trace
3584            .accepted_gpu_constraint_row_count_device_reads_consumed =
3585            Self::checked_trace_counter_add(
3586                self.trace
3587                    .accepted_gpu_constraint_row_count_device_reads_consumed,
3588                evidence.gpu_constraint_row_count_device_reads() as u64,
3589                "accepted_gpu_constraint_row_count_device_reads_consumed",
3590            )?;
3591        Ok(())
3592    }
3593
3594    fn encode_program_pir_cnf_with_base_provenance(
3595        &mut self,
3596        program: &Program,
3597        base_provenance: &Provenance,
3598        provider: &Arc<CudaKernelProvider>,
3599        evidence: &AcceptedWorldViewEvidence,
3600        path: EpistemicProbPirCnfPath,
3601    ) -> Result<EpistemicProbPirCnfEvidence> {
3602        self.require_accepted_evidence(evidence)?;
3603        let conditioned_provenance = if evidence.assumptions().is_empty() {
3604            None
3605        } else {
3606            let conditioned_program = condition_program_with_available_evidence_using_provenance(
3607                program,
3608                base_provenance,
3609                evidence,
3610            )?;
3611            Some(extract_from_program(&conditioned_program)?)
3612        };
3613        let provenance = conditioned_provenance.as_ref().unwrap_or(base_provenance);
3614        self.encode_provenance_pir_cnf_with_accepted_world_view(
3615            provenance, provider, evidence, path,
3616        )
3617    }
3618
3619    fn encode_provenance_pir_cnf_with_accepted_world_view(
3620        &mut self,
3621        provenance: &Provenance,
3622        provider: &Arc<CudaKernelProvider>,
3623        evidence: &AcceptedWorldViewEvidence,
3624        path: EpistemicProbPirCnfPath,
3625    ) -> Result<EpistemicProbPirCnfEvidence> {
3626        self.require_accepted_evidence(evidence)?;
3627        let production_events_before = self.trace.checked_gpu_production_path_events()?;
3628        let roots = production_pir_roots(provenance)?;
3629        if roots.is_empty() {
3630            return Err(XlogError::UnsupportedEpistemicConstruct {
3631                construct: "accepted probabilistic PIR/CNF production path".to_string(),
3632                context: "GPU PIR/CNF evidence requires at least one query, evidence, or probabilistic variable root".to_string(),
3633            });
3634        }
3635        let gpu_pir = GpuPirGraph::from_host(&provenance.pir, provider)?;
3636        checked_prob_trace_counter_inc!(self, gpu_pir_graph_uploads);
3637        match path {
3638            EpistemicProbPirCnfPath::Source => {
3639                checked_prob_trace_counter_inc!(self, gpu_source_pir_graph_uploads);
3640            }
3641            EpistemicProbPirCnfPath::Program => {
3642                checked_prob_trace_counter_inc!(self, gpu_program_pir_graph_uploads);
3643            }
3644        }
3645        let gpu_roots = GpuPirRoots::from_host(&roots, provider)?;
3646        let encoding = encode_cnf_gpu(&gpu_pir, &gpu_roots, provider)?;
3647        checked_prob_trace_counter_inc!(self, gpu_cnf_encodes);
3648        match path {
3649            EpistemicProbPirCnfPath::Source => {
3650                checked_prob_trace_counter_inc!(self, gpu_source_cnf_encodes);
3651            }
3652            EpistemicProbPirCnfPath::Program => {
3653                checked_prob_trace_counter_inc!(self, gpu_program_cnf_encodes);
3654            }
3655        }
3656        let pir_cnf_evidence = EpistemicProbPirCnfEvidence {
3657            pir_nodes: provenance.pir.len(),
3658            root_count: roots.len(),
3659            cnf_var_cap: encoding.cnf.var_cap,
3660            cnf_clause_cap: encoding.cnf.clause_cap,
3661            cnf_lit_cap: encoding.cnf.lit_cap,
3662        };
3663        self.record_accepted_gpu_production_path_events_since(production_events_before)?;
3664        self.record_accepted_evidence(evidence)?;
3665        Ok(pir_cnf_evidence)
3666    }
3667}
3668
3669fn require_gpu_exact_backend(program: &ExactDdnnfProgram, construct: &'static str) -> Result<()> {
3670    if !program.uses_gpu_production_backend() {
3671        return Err(XlogError::UnsupportedEpistemicConstruct {
3672            construct: construct.to_string(),
3673            context:
3674                "production probability metrics require a compiled GPU-native Decision-DNNF exact/provenance/PIR/CNF backend; \
3675                      empty roots and count-lift-only evaluation cannot satisfy accepted epistemic probability reuse"
3676                    .to_string(),
3677        });
3678    }
3679    Ok(())
3680}
3681
3682#[cfg(feature = "host-io")]
3683#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
3684struct EpistemicProbConditionedEvidenceCounts {
3685    total: usize,
3686    nonzero_arity: usize,
3687    max_arity: u32,
3688    negative: usize,
3689    know: usize,
3690    possible: usize,
3691    not_known: usize,
3692    not_possible: usize,
3693}
3694
3695fn condition_program_with_available_evidence_using_provenance(
3696    program: &Program,
3697    base_provenance: &Provenance,
3698    evidence: &AcceptedWorldViewEvidence,
3699) -> Result<Program> {
3700    if evidence.assumptions().is_empty() {
3701        return Ok(program.clone());
3702    }
3703
3704    let mut program = program.clone();
3705    let mut applied = 0usize;
3706    for assumption in evidence.assumptions() {
3707        validate_conditioned_assumption_shape(assumption)?;
3708        let Some(atom) = conditioned_evidence_atom_for_assumption(base_provenance, assumption)
3709        else {
3710            return Err(XlogError::UnsupportedEpistemicConstruct {
3711                construct: "accepted probabilistic PIR/CNF evidence conditioning".to_string(),
3712                context: format!(
3713                    "accepted {} PIR/CNF evidence for {}/{} has no provenance formula; partial \
3714                     world-view evidence cannot satisfy production conditioning metrics",
3715                    assumption.evidence_literal(),
3716                    assumption.predicate,
3717                    assumption.arity
3718                ),
3719            });
3720        };
3721        program.evidence.push(Evidence {
3722            atom,
3723            value: assumption.value,
3724        });
3725        applied += 1;
3726    }
3727
3728    if applied == 0 {
3729        return Err(XlogError::UnsupportedEpistemicConstruct {
3730            construct: "accepted probabilistic PIR/CNF evidence conditioning".to_string(),
3731            context: "PIR/CNF encoding requires at least one accepted epistemic assumption to match existing probabilistic provenance"
3732                .to_string(),
3733        });
3734    }
3735
3736    Ok(program)
3737}
3738
3739#[cfg(feature = "host-io")]
3740fn condition_program_with_accepted_evidence_using_provenance(
3741    program: &Program,
3742    provenance: &Provenance,
3743    evidence: &AcceptedWorldViewEvidence,
3744) -> Result<(Program, EpistemicProbConditionedEvidenceCounts)> {
3745    if evidence.assumptions().is_empty() {
3746        return Err(XlogError::UnsupportedEpistemicConstruct {
3747            construct: "accepted probabilistic evidence conditioning".to_string(),
3748            context: "conditioned exact path requires at least one accepted epistemic assumption"
3749                .to_string(),
3750        });
3751    }
3752
3753    let mut counts = EpistemicProbConditionedEvidenceCounts::default();
3754    for assumption in evidence.assumptions() {
3755        validate_conditioned_assumption_shape(assumption)?;
3756        record_conditioned_assumption_counts(&mut counts, assumption);
3757    }
3758    let mut program = program.clone();
3759    for assumption in evidence.assumptions() {
3760        let Some(atom) = conditioned_evidence_atom_for_assumption(provenance, assumption) else {
3761            return Err(XlogError::UnsupportedEpistemicConstruct {
3762                construct: "accepted probabilistic evidence conditioning".to_string(),
3763                context: format!(
3764                    "accepted {} exact evidence for {}/{} has no provenance formula; \
3765                     vacuous evidence cannot satisfy production conditioning metrics",
3766                    assumption.evidence_literal(),
3767                    assumption.predicate,
3768                    assumption.arity
3769                ),
3770            });
3771        };
3772        program.evidence.push(Evidence {
3773            atom,
3774            value: assumption.value,
3775        });
3776    }
3777
3778    Ok((program, counts))
3779}
3780
3781fn validate_conditioned_assumption_shape(assumption: &EpistemicAssumption) -> Result<()> {
3782    if assumption.arity == 0 {
3783        if !assumption.terms.is_empty() {
3784            return Err(XlogError::UnsupportedEpistemicConstruct {
3785                construct: "accepted probabilistic evidence conditioning".to_string(),
3786                context: format!(
3787                    "zero-arity exact evidence must not carry tuple terms, got {}/{}",
3788                    assumption.predicate, assumption.arity
3789                ),
3790            });
3791        }
3792    } else if assumption.terms.len() != assumption.arity {
3793        return Err(XlogError::UnsupportedEpistemicConstruct {
3794            construct: "accepted probabilistic evidence conditioning".to_string(),
3795            context: format!(
3796                "nonzero exact evidence conditioning requires {} concrete tuple terms, got {} for {}/{}",
3797                assumption.arity,
3798                assumption.terms.len(),
3799                assumption.predicate,
3800                assumption.arity
3801            ),
3802        });
3803    }
3804    Ok(())
3805}
3806
3807#[cfg(feature = "host-io")]
3808fn record_conditioned_assumption_counts(
3809    counts: &mut EpistemicProbConditionedEvidenceCounts,
3810    assumption: &EpistemicAssumption,
3811) {
3812    counts.total += 1;
3813    if assumption.arity > 0 {
3814        counts.nonzero_arity += 1;
3815        counts.max_arity = counts.max_arity.max(assumption.arity as u32);
3816    }
3817    if !assumption.value {
3818        counts.negative += 1;
3819    }
3820    match (assumption.kind, assumption.value) {
3821        (EpistemicAssumptionKind::Know, true) => counts.know += 1,
3822        (EpistemicAssumptionKind::Possible, true) => counts.possible += 1,
3823        (EpistemicAssumptionKind::Know, false) => counts.not_known += 1,
3824        (EpistemicAssumptionKind::Possible, false) => counts.not_possible += 1,
3825    }
3826}
3827
3828fn evidence_term_variants(term: &EpistemicEvidenceTerm) -> Vec<(Value, Term)> {
3829    match term {
3830        EpistemicEvidenceTerm::Integer(value) => vec![(Value::I64(*value), Term::Integer(*value))],
3831        EpistemicEvidenceTerm::String(value) => {
3832            let symbol_id = symbol::intern(value);
3833            vec![
3834                (Value::String(value.clone()), Term::String(value.clone())),
3835                (Value::Symbol(symbol_id), Term::Symbol(symbol_id)),
3836            ]
3837        }
3838        EpistemicEvidenceTerm::Symbol(value) => {
3839            let string_value = symbol::resolve(*value);
3840            vec![
3841                (Value::Symbol(*value), Term::Symbol(*value)),
3842                (
3843                    Value::String(string_value.clone()),
3844                    Term::String(string_value),
3845                ),
3846            ]
3847        }
3848    }
3849}
3850
3851fn conditioned_evidence_atom_for_assumption(
3852    provenance: &Provenance,
3853    assumption: &EpistemicAssumption,
3854) -> Option<Atom> {
3855    if assumption.terms.is_empty() {
3856        if provenance
3857            .query_formula(&assumption.predicate, &[])
3858            .is_some()
3859        {
3860            return Some(Atom {
3861                predicate: assumption.predicate.clone(),
3862                terms: Vec::new(),
3863            });
3864        }
3865        return None;
3866    }
3867
3868    let variants = assumption
3869        .terms
3870        .iter()
3871        .map(evidence_term_variants)
3872        .collect::<Vec<_>>();
3873    let mut values = Vec::with_capacity(variants.len());
3874    let mut terms = Vec::with_capacity(variants.len());
3875    conditioned_evidence_atom_from_variants(
3876        provenance,
3877        assumption,
3878        &variants,
3879        0,
3880        &mut values,
3881        &mut terms,
3882    )
3883}
3884
3885fn conditioned_evidence_atom_from_variants(
3886    provenance: &Provenance,
3887    assumption: &EpistemicAssumption,
3888    variants: &[Vec<(Value, Term)>],
3889    index: usize,
3890    values: &mut Vec<Value>,
3891    terms: &mut Vec<Term>,
3892) -> Option<Atom> {
3893    if index == variants.len() {
3894        if provenance
3895            .query_formula(&assumption.predicate, values)
3896            .is_some()
3897        {
3898            return Some(Atom {
3899                predicate: assumption.predicate.clone(),
3900                terms: terms.clone(),
3901            });
3902        }
3903        return None;
3904    }
3905
3906    for (value, term) in &variants[index] {
3907        values.push(value.clone());
3908        terms.push(term.clone());
3909        if let Some(atom) = conditioned_evidence_atom_from_variants(
3910            provenance,
3911            assumption,
3912            variants,
3913            index + 1,
3914            values,
3915            terms,
3916        ) {
3917            return Some(atom);
3918        }
3919        values.pop();
3920        terms.pop();
3921    }
3922    None
3923}
3924
3925fn assumption_has_provenance_formula(
3926    provenance: &Provenance,
3927    assumption: &EpistemicAssumption,
3928) -> bool {
3929    conditioned_evidence_atom_for_assumption(provenance, assumption).is_some()
3930}
3931
3932fn evidence_with_provenance_backed_assumptions(
3933    evidence: &AcceptedWorldViewEvidence,
3934    provenance: &Provenance,
3935) -> Result<AcceptedWorldViewEvidence> {
3936    let assumptions = evidence
3937        .assumptions()
3938        .iter()
3939        .filter(|assumption| assumption_has_provenance_formula(provenance, assumption))
3940        .cloned()
3941        .collect::<Vec<_>>();
3942    if assumptions.is_empty() {
3943        return Err(XlogError::UnsupportedEpistemicConstruct {
3944            construct: "accepted probabilistic PIR/CNF evidence conditioning".to_string(),
3945            context: "PIR/CNF encoding requires at least one accepted epistemic assumption to match existing probabilistic provenance"
3946                .to_string(),
3947        });
3948    }
3949    Ok(evidence.with_assumptions(assumptions))
3950}
3951
3952fn production_pir_roots(provenance: &Provenance) -> Result<Vec<PirNodeId>> {
3953    let mut roots = BTreeSet::new();
3954
3955    for (atom, value) in &provenance.evidence {
3956        if let Some(id) = provenance.query_formula(&atom.predicate, &atom.args) {
3957            roots.insert(id);
3958        } else if *value {
3959            return Err(XlogError::Execution(format!(
3960                "Exact inference error: evidence atom is never derivable: {}",
3961                atom.predicate
3962            )));
3963        }
3964    }
3965
3966    for atom in &provenance.queries {
3967        if let Some(id) = provenance.query_formula(&atom.predicate, &atom.args) {
3968            roots.insert(id);
3969        }
3970    }
3971
3972    for (idx, node) in provenance.pir.nodes().iter().enumerate() {
3973        if matches!(
3974            node,
3975            PirNode::Decision { .. } | PirNode::Lit { .. } | PirNode::NegLit { .. }
3976        ) {
3977            roots.insert(PirNodeId::from_u32(idx as u32));
3978        }
3979    }
3980
3981    Ok(roots.into_iter().collect())
3982}
3983
3984#[cfg(all(test, feature = "host-io"))]
3985mod prepared_conditioned_poison_tests {
3986    use super::*;
3987
3988    #[test]
3989    fn rollback_failure_permanently_invalidates_prepared_state_and_all_clones() {
3990        let _gpu_guard = crate::test_gpu_lock::lock();
3991        match xlog_cuda::CudaDevice::new(0) {
3992            Ok(_) => {}
3993            Err(error) if std::env::var("XLOG_REQUIRE_CUDA").as_deref() == Ok("1") => {
3994                panic!("XLOG_REQUIRE_CUDA=1 but CUDA runtime initialization failed: {error}")
3995            }
3996            Err(error) => {
3997                eprintln!("Skipping test: CUDA runtime unavailable: {error}");
3998                return;
3999            }
4000        }
4001
4002        let exact = ExactDdnnfProgram::compile_source(
4003            "0.5::rain().\n\
4004             query(rain()).\n",
4005        )
4006        .expect("compile prepared exact program");
4007        let prepared =
4008            PreparedConditionedProgram::new(exact, EpistemicProbProductionTrace::default())
4009                .expect("prepare exact circuit");
4010        let rain_var = prepared
4011            .prob_var_map()
4012            .expect("read fact map before injected failure")
4013            .iter()
4014            .enumerate()
4015            .find_map(|(var, info)| {
4016                matches!(info, ProbVarInfo::Fact { atom, .. } if atom.predicate == "rain")
4017                    .then_some(var as u32)
4018            })
4019            .expect("rain fact has a CNF variable");
4020        let clone_before_failure = prepared.clone();
4021
4022        let error = prepared
4023            .set_fact_probabilities_with_device_failures(
4024                &BTreeMap::from([(rain_var, 0.9)]),
4025                Some(1),
4026                Some(1),
4027            )
4028            .expect_err("rollback failure must be reported");
4029        let message = error.to_string();
4030        assert!(message.contains("device update failed"), "{message}");
4031        assert!(message.contains("rollback also failed"), "{message}");
4032        assert!(
4033            message.contains("injected fact probability device-write failure"),
4034            "{message}"
4035        );
4036        assert!(
4037            message.contains("injected fact probability rollback failure"),
4038            "{message}"
4039        );
4040
4041        let clone_after_failure = prepared.clone();
4042        for (operation, result) in [
4043            ("evaluate", prepared.evaluate().map(|_| ())),
4044            ("gradient", prepared.evaluate_with_grads().map(|_| ())),
4045            ("prob_var_map", prepared.prob_var_map().map(|_| ())),
4046            (
4047                "set_fact_probabilities",
4048                prepared.set_fact_probabilities(&BTreeMap::from([(rain_var, 0.4)])),
4049            ),
4050            (
4051                "clone-before evaluate",
4052                clone_before_failure.evaluate().map(|_| ()),
4053            ),
4054            (
4055                "clone-before prob_var_map",
4056                clone_before_failure.prob_var_map().map(|_| ()),
4057            ),
4058            (
4059                "clone-after gradient",
4060                clone_after_failure.evaluate_with_grads().map(|_| ()),
4061            ),
4062            (
4063                "clone-after set",
4064                clone_after_failure.set_fact_probabilities(&BTreeMap::from([(rain_var, 0.4)])),
4065            ),
4066        ] {
4067            let later = result
4068                .err()
4069                .unwrap_or_else(|| panic!("{operation} reused poisoned state"));
4070            let later_message = later.to_string();
4071            assert!(
4072                later_message.contains("permanently invalid"),
4073                "{operation}: {later_message}"
4074            );
4075            assert!(
4076                later_message.contains("rollback also failed"),
4077                "{operation}: {later_message}"
4078            );
4079        }
4080    }
4081}