1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Deterministic per-boolean exact-predicate budget (issue #1109).
//!
//! Every predicate over an implicit (intersection) point runs a cascade:
//! `interval filter → fixed-width exact → BigRational` (`predicates.rs`). The
//! interval filter resolves generic geometry for free, but on genuinely
//! near-coplanar / grazing operands its sign straddles zero, so the predicate
//! falls through to the exact tiers — the fixed-width rungs climb to ~1340 bits
//! and a few spill into BigRational (~5000× the interval tier). Boolean-heavy
//! CAD models (Tekla half-space end-clips, Revit flush openings) are full of
//! such faces, so a single hard element runs the exact path on a huge fraction
//! of the O(intersection-pairs) predicate set. The pure-Rust exact kernel has no
//! operand cap (the old BSP polygon cap was deleted in #1024), so those elements
//! grind to completion regardless of cost and stall the geometry stream at 95%
//! (issue #1109).
//!
//! This is a **deterministic** guardrail: it counts **interval-filter failures**
//! (every predicate that needed the expensive exact tier) per boolean and trips
//! when the count crosses a cap. The count is a pure function of the (snap-grid,
//! integer) operands, so the trip point is IDENTICAL on native x86_64 / aarch64
//! and on wasm32 — the server and the browser client degrade the SAME hard
//! element to the SAME fallback. That preserves the cross-target parity the
//! pure-Rust kernel exists to guarantee.
//!
//! A wall-clock budget would NOT preserve parity: the fast native server would
//! finish the exact cut while the slower wasm client tripped the timer, yielding
//! different geometry for the same model. The exact-evaluation COUNT is the right
//! metric precisely because it is platform-independent.
//!
//! On trip the boolean bails; [`crate::csg`] records `OperandTooLarge` and
//! returns the host un-cut, which routes void subtraction to the deterministic
//! #635 AABB box-cut fallback ("a square hole is dramatically less wrong than a
//! missing void").
use Cell;
use ;
/// Default per-boolean exact-evaluation cap for the interactive profile.
///
/// Calibrated against the model corpus: the worst healthy boolean (a dense steel
/// element) needs ~15k exact evaluations; almost all are well under 5k. This cap
/// is **33× that worst case**, so it never false-trips a legitimate cut (a false
/// trip degrades a real cut to an AABB box — wrong geometry — which is worse than
/// finishing slowly). It only engages on the pathological near-coplanar pattern
/// of #1109 (Tekla half-space clips / Revit flush cuts), where the exact-tier
/// count runs orders of magnitude higher and would otherwise never finish. The
/// coplanar fast path (the companion perf fix) keeps hard-but-sound models well
/// under this cap; this is the safety net that turns the indefinite 95% hang
/// into a finite load. `set_cap` (or `IFC_LITE_CSG_BUDGET`) tunes it;
/// `set_cap(None)` lifts it entirely for the server/offline-export profile,
/// where "exact but slow" is acceptable.
pub const DEFAULT_CAP: u64 = 500_000;
/// Global cap. `0` ⇒ unbounded (run exact to completion). Any other value is the
/// per-boolean escalation cap. Read once per boolean into a thread-local so each
/// rayon worker counts its own operation independently and deterministically.
static CAP: AtomicU64 = new;
/// Highest single-boolean escalation count seen since the last [`reset_peak`].
/// Diagnostics / cap calibration only — never read on the hot path.
static PEAK: AtomicU64 = new;
thread_local!
/// Effective cap, honouring the `IFC_LITE_CSG_BUDGET` env override (read once):
/// `0` ⇒ unbounded, any other value ⇒ that cap. Lets the server/CLI and
/// calibration runs pick a profile without code changes. `set_cap` still wins.
/// Set the global per-boolean escalation cap. `None` = unbounded (exact to
/// completion — the server/CLI/offline-export profile); `Some(n)` = trip after
/// `n` BigRational escalations (the interactive viewer/wasm profile). The
/// default is [`DEFAULT_CAP`], so the viewer is bounded out of the box.
/// The active cap, as configured (`None` ⇒ unbounded).
/// Begin a boolean operation: reset the per-op escalation counter and snapshot
/// the cap. Call once at every public boolean entry in [`crate::csg`].
/// Highest single-boolean escalation count observed since process start (or the
/// last [`reset_peak`]). For cap calibration / diagnostics.
/// Reset the global peak escalation counter.
/// Record one exact-tier predicate evaluation (an interval-filter failure).
/// Called from the `.or_else(|| fixed::…)` arms of [`crate::kernel::predicates`]
/// — the point where a predicate leaves the cheap interval filter for the
/// expensive fixed-width / BigRational path.
/// Whether the current boolean has exceeded its escalation budget. Checked at
/// loop boundaries in the arrangement so the bail is timely and graceful.
/// Escalations counted so far in the current boolean (diagnostics / cap
/// calibration).