fuel_tensor/reproducibility.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! Strict reproducibility mode (ROADMAP item 13(b)).
3//!
4//! A *policy* surface over substrate that already exists: every registered
5//! kernel declares `PrecisionGuarantee::bit_stable_on_same_hardware`, and
6//! `fuel_dispatch`'s `PrecisionFloorFilter` is a HARD filter that refuses any
7//! candidate whose claim does not meet a `PrecisionRequirement`. What was
8//! missing is a way for a caller to reach it: the production realize path
9//! (`pipelined_bridge::build_optimized_graph`) never set
10//! `PlanOptions::precision_requirement`, so the default chain's floor was
11//! always unconstrained.
12//!
13//! Under strict mode the planner refuses every non-bit-stable arm. A node
14//! whose only arms are non-bit-stable on the pinned device falls back to an
15//! admissible off-device sibling when one is feasible; otherwise planning
16//! fails with `Error::FilterRejected { filter: "precision-floor", .. }` —
17//! loudly, at graph-build time, never by silently picking a non-reproducible
18//! kernel.
19//!
20//! "Bit-stable" here is the declared claim: repeat runs on the SAME hardware
21//! produce identical bytes. It is not a cross-hardware guarantee (see
22//! `docs/architecture/05-backend-contract.md`).
23//!
24//! # Scope
25//!
26//! The mode is read where the plan is BUILT, on the realize caller's thread.
27//! A scoped guard ([`strict_reproducibility`]) covers one thread and nests;
28//! [`set_global_strict_reproducibility`] covers the process. Strict wins if
29//! either is on.
30
31use std::cell::Cell;
32use std::marker::PhantomData;
33use std::sync::atomic::{AtomicBool, Ordering};
34
35use fuel_dispatch::PrecisionRequirement;
36
37static GLOBAL_STRICT: AtomicBool = AtomicBool::new(false);
38
39std::thread_local! {
40 static SCOPE_DEPTH: Cell<usize> = const { Cell::new(0) };
41}
42
43/// RAII guard returned by [`strict_reproducibility`]. Strict mode stays on for
44/// this thread until every outstanding guard is dropped. Not `Send`: the
45/// scope belongs to the thread that opened it.
46#[must_use = "strict mode ends when the guard is dropped"]
47pub struct StrictReproducibilityGuard {
48 _not_send: PhantomData<*const ()>,
49}
50
51/// Enter strict reproducibility mode on the current thread until the returned
52/// guard is dropped. Nests.
53pub fn strict_reproducibility() -> StrictReproducibilityGuard {
54 SCOPE_DEPTH.with(|d| d.set(d.get() + 1));
55 StrictReproducibilityGuard {
56 _not_send: PhantomData,
57 }
58}
59
60impl Drop for StrictReproducibilityGuard {
61 fn drop(&mut self) {
62 SCOPE_DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
63 }
64}
65
66/// Turn strict mode on or off for the whole process. Composes with scoped
67/// guards: either one being on makes [`is_strict_reproducibility`] true.
68pub fn set_global_strict_reproducibility(on: bool) {
69 GLOBAL_STRICT.store(on, Ordering::Relaxed);
70}
71
72/// Is strict reproducibility in force on the current thread right now?
73pub fn is_strict_reproducibility() -> bool {
74 GLOBAL_STRICT.load(Ordering::Relaxed) || SCOPE_DEPTH.with(|d| d.get() > 0)
75}
76
77/// The precision floor the realize path must hand to the planner.
78pub(crate) fn precision_requirement() -> PrecisionRequirement {
79 if is_strict_reproducibility() {
80 PrecisionRequirement::BIT_STABLE
81 } else {
82 PrecisionRequirement::default()
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn off_by_default_is_unconstrained() {
92 assert!(!is_strict_reproducibility());
93 assert!(precision_requirement().is_unconstrained());
94 }
95
96 #[test]
97 fn scope_requires_bit_stable_and_restores_on_drop() {
98 {
99 let _g = strict_reproducibility();
100 assert!(is_strict_reproducibility());
101 assert_eq!(precision_requirement(), PrecisionRequirement::BIT_STABLE);
102 }
103 assert!(!is_strict_reproducibility());
104 assert!(precision_requirement().is_unconstrained());
105 }
106
107 #[test]
108 fn scopes_nest() {
109 let outer = strict_reproducibility();
110 {
111 let _inner = strict_reproducibility();
112 }
113 assert!(is_strict_reproducibility(), "inner drop must not end outer");
114 drop(outer);
115 assert!(!is_strict_reproducibility());
116 }
117
118 #[test]
119 fn scope_is_thread_local() {
120 let _g = strict_reproducibility();
121 let other = std::thread::spawn(is_strict_reproducibility)
122 .join()
123 .unwrap();
124 assert!(!other, "a scope must not leak to other threads");
125 }
126}