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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
//! Bounded-model-checking proofs over the case tables.
//!
//! Ticket: R-062 (P-64). Run with `cargo kani -p isomesh`. Compiled only under
//! `cfg(kani)`, so this file is invisible to every other build — `cargo tree -p
//! isomesh -e normal` is unchanged at two packages and hard rule 3 is not
//! engaged.
//!
//! # What is proved, and what is deliberately not
//!
//! `CLAUDE.md` rule 5: *"wrong case tables produce meshes that look fine and are
//! subtly non-manifold."* That risk is **combinatorics over eight sign bits** —
//! 256 states — and bounded model checking settles 256 states exhaustively where
//! a property test samples them.
//!
//! What is **not** proved is vertex placement. Bit-blasting IEEE 754 to SAT is
//! the adversarial case for a model checker, and eight nondeterministic `f32`
//! corners is 256 bits of unconstrained float. Placement stays under proptest
//! and the golden hashes. The honest scope of this file is *"the table cannot be
//! indexed wrongly"*, not *"the mesh is correct"*.
//!
//! # The four properties
//!
//! 1. **Shape.** `count ≤ MAX_TRIANGLES` and `centroids ≤ MAX_CENTROIDS`, so the
//! fixed-size arrays a caller stack-allocates cannot overflow. `D-021` is
//! what happens when a bound like this is a *sampled* maximum rather than a
//! derived one.
//! 2. **Every code is nameable.** Each corner code in a live triangle is either
//! a cube edge below [`CENTROID_BASE`] or a centroid index below this case's
//! own `centroids` count. A centroid code past the count names a vertex the
//! extractor never created.
//! 3. **Every named edge is cut.** This is the load-bearing one and it is a
//! property of the *pair* (table, sign pattern) rather than of the table
//! alone. `extraction.rs` places a vertex for whatever edge the table names,
//! by interpolating between that edge's two corner values — so a triangle
//! naming an **uncut** edge asks for a crossing that does not exist, which is
//! a vertex at a meaningless position rather than a bounds error. It is
//! exactly the failure rule 5 describes: a mesh that looks fine.
//! 4. **No degenerate triangle.** Three distinct codes, so no triangle is a
//! zero-area sliver by construction. `validate::self_intersection` counts
//! these at run time; here they are impossible.
//!
//! Property 4 is stated over codes rather than positions on purpose: two
//! distinct edges can carry the *same* position when the crossing sits on a
//! shared corner, and that is a placement question this file does not touch.
use ;
/// Is edge `e` cut by this sign pattern?
///
/// The same test `extraction.rs` makes implicitly when it interpolates: the two
/// corner values must straddle zero, which over sign bits is "the bits differ".
/// All four properties, for one case and one already-built triangulation.
///
/// Shared by the three harnesses so the *statement* of the properties exists
/// once. Three copies of an assertion is three things to drift, and a proof
/// whose properties drifted from the ones it claims is worse than no proof.
/// **C1** — the shipped `CASES` table, all 256 patterns.
///
/// This is the table `extract` reads at mask zero, so it is the one a consumer
/// actually meets. Reading `CASES[case]` rather than recomputing it is
/// deliberate: the property is about the **static** the crate ships, and a proof
/// about a recomputation would not catch a `build_cases` that diverged from what
/// it stored.
/// Every `(case, joined)` triangulation, evaluated at **compile time**.
///
/// # Why a table and not symbolic execution of the constructor
///
/// The first version of this file pointed Kani straight at
/// `triangulate(segment_links(case, joined))` with both arguments
/// nondeterministic. **CBMC ran out of memory** — 10,230,639 steps of program
/// expression, 909,347 verification conditions, 550,658 after simplification,
/// 885 s of symbolic execution before it died on a 32 GB box. The shipped
/// `CASES` harness beside it verifies in **2.05 s**.
///
/// That gap is not the sign-bit space, which is 256 states and trivial. It is
/// `segment_links`' **walk**: a data-dependent traversal of the twelve-edge link
/// structure, where every step's successor depends on the previous step's value,
/// so symbolic execution cannot merge paths and unrolls the whole product.
///
/// So the work is split between the two engines that are each good at half of
/// it. **`const` evaluation runs the real constructor on all 65,536 inputs** —
/// exhaustive by construction, and the same evaluator that builds the shipped
/// `CASES`. **Kani then proves the four properties over the stored results**
/// with a nondeterministic index, which is a lookup and verifies in seconds.
/// Composed, that is a proof over the entire input space: nothing is sampled and
/// nothing is assumed about the walk.
///
/// # The mask alphabet, and what is and is not being assumed
///
/// The mask ranges over all **64** values [`super::table::face_bit`] can
/// produce: `1 << (axis * 2 + side)` with `axis < 3` and `side < 2` occupies bits
/// 0 through 5, so bits 6 and 7 are outside the alphabet and no caller can set
/// them. That is a restriction to the **type**, not to well-formedness — the
/// proof still ranges over every mask that is *not* in
/// [`super::table::AMBIGUOUS_FACES`]`[case]`, which is the part that could
/// actually be wrong, and `joined_mask` returning a bit for a non-ambiguous face
/// is exactly the defect this harness would catch.
///
/// 256 × 256 was the first attempt and **rustc refused it**: *"constant
/// evaluation is taking a long time"* at 65,536 entries. 16,384 evaluates.
static ALL_MASKS: = build_all_masks;
///
/// `long_running_const_eval` is allowed here and nowhere else. It is a **compile
/// -time budget lint, not a correctness one** — rustc's default step limit is
/// tuned for accidental infinite loops, and 16,384 twelve-edge walks is a
/// bounded, terminating computation that simply exceeds it. The alternative is
/// symbolic execution of the same walk, which is what ran out of 32 GB.
const
/// **C3** — the interior-ambiguity path: every case against every mask.
///
/// 256 sign patterns × 64 face masks = **16,384** triangulations, every one of
/// them produced by the real `segment_links` + `triangulate` under `const`
/// evaluation, every one of them checked here.
/// **The control: the properties must be able to fail.**
///
/// Four `SUCCESS` verdicts over 65,536 table entries are worth nothing if the
/// assertions cannot fire — `M-44`'s rule, and a proof is exactly where it is
/// easiest to violate, because a vacuous proof and a real one print the same
/// word. This harness corrupts one entry the way `golden::tests`' sabotage arm
/// corrupts one triangle (`M-337`'s model) and requires the check to fail.
///
/// It is `#[kani::should_panic]`, so Kani's own verdict is `SUCCESSFUL` exactly
/// when the assertion **does** fire. A property that had drifted into a tautology
/// would make this harness fail, which is the direction that matters.