Skip to content

Latest commit

 

History

History
1146 lines (1025 loc) · 75.6 KB

VALIDATION.md

File metadata and controls

1146 lines (1025 loc) · 75.6 KB

Kernel validation

For original test reuse, see the DRAW bridge: unchanged Tcl tests, assertion helpers and result rules execute against both kernels. Its three passing upstream AABB cases and explicit capability/data gaps are separate from the 66-solid corpus below. Implementation provenance is in SOURCE_MAP.md; remaining release requirements are in PRODUCTION_READINESS.md.

Current evidence

The mathematical foundation includes exact 2D/3D orientation and insphere, 2,417 independent 2D rational fixtures in all six permutations, 1,648 spatial predicate fixtures, 963 certified linear-intersection fixtures, 448 quadratic-root fixtures, 1,092 curved-intersection fixtures, 1,059 curve and 791 surface spline fixtures, 95 general polynomial-root, 284 spline/plane, 118 spline/quadric, 554 proximity, 684 complete linear-set, 636 exact Bézier curve, 745 tensor-patch and 723 knot-editing fixtures, 10,000 integer-oracle predicate cases and 256 generated prism invariant cases. These tests do not depend on OCCT or an application and run in native debug and release CI. These deterministic generated tests are separate from the twenty-one coverage-guided fuzz targets and daily retained-corpus campaigns.

Exact root-to-root ordering was accepted at revision de1d1d43: 122 debug and 122 release tests on Linux/macOS/Windows, Rust 1.85, WASM compilation and all sixteen then-existing fuzz targets passed. Its local roots campaign completed 600.06 seconds of mutation with 10,483 mutations. Full kernel parity remains incomplete. The new point-to-spline minimum-set capability adds 30 independent complete-minimum cases, 94 whole image-polynomial equations, a source-pinned native bridge and a seventeenth fuzz target; its clean-revision platform/native/fuzz acceptance passed at d1206b15. The spline/line and spline/segment capability adds 60 complete independent preimages, 79 closed clipping sets, 851 affine root orderings, an eighteenth fuzz target and a source-pinned native bridge (23 matches, eight reviewed differences on macOS and Linux); acceptance passed at 30c5a247. Generic B-rep validation adds 54 complete independent issue reports, a nineteenth fuzz target and a source-pinned BRepCheck_Analyzer bridge (44 matches, eight reviewed differences on macOS and Linux); acceptance passed at dff912e5.

compare_intersections.py executes native OCCT IntAna_IntConicQuad and Rust's line/plane primitive on 72 shared well-conditioned cases, comparing intersection type, affine parameter and point coordinates. The test budget is 1e-10 + 2e-12*abs(expected). Local OCCT 7.9.3 used at most 0.000128 of that budget. CI runs the same comparison against its recorded distribution runtime. Exact parallelism intentionally differs from OCCT's angular-tolerance policy; near-degenerate/extreme cases use the independent exact oracles instead.

compare_proximity.py captures 370 point/line/segment/plane/triangle inputs through native B-rep and lower-level affine distance APIs. Exact rational Rust witnesses pass independent analytic formulas and supporting-plane certificates before native comparison. Local OCCT 7.9.3 gives 316 B-rep matches, 54 B-rep nonresults, and 120 affine matches with six numerical differences; those two observation sets overlap. All 412 native witness pairs are also checked for shape ownership and distance. The reviewed differences are version/input/value pinned, and never weaken the independent Rust checks. Linux OCCT 7.6.3 has the same 316 B-rep matches and 54 separately reviewed nonresults; all 126 affine distances match. Rust's complete rational results are byte-identical between the two platforms. The 554 Fraction fixtures add full-exponent, near-degenerate and unrepresentable cases outside this well-scaled native corpus. No general B-rep distance or unchanged upstream extrema-test coverage is implied.

compare_linear_sets.py checks all 25 ordered linear primitive pairings over 433 native inputs. The initial native geometries were captured before Rust implementation. All exact results equal an independent boundary-crossing oracle. Local OCCT 7.9.3 and Linux OCCT 7.6.3 each yield 384 complete combined COMMON/SECTION matches, 46 empty results for unbounded intersections, and three extra-edge/off-line-point observations. All 433 Rust result rows are identical between platforms. The reviews pin each native result; COMMON's intentional omission of lower-dimensional contacts is counted separately. The 684 exact fixtures include five/six-vertex polygons, full-exponent and subnormal geometry, invalid inputs and unrepresentable constructions. Rust and Python boundary oracles differ from production affine/halfspace enumeration. Every defining-point permutation, operand order and minimal construction bound is checked, and linear_sets continuously mutates the corpus. General face splitting, B-rep Boolean operations and topology/history remain pending.

compare_curved.py first captures independent native observations, then checks Rust against 174 cases of polynomial roots, line/sphere, line/cylinder and coplanar XY line/circle intersections. Repeated polynomial roots retain their multiplicity; exactly duplicate native hit parameters are merged only when comparing geometric hit counts. Cases include exact tangencies and degree reduction. Local OCCT 7.9.3 used at most 0.000078 of the same comparison budget. Its source/runtime versions remain separate. Full-exponent, near-tangent, arbitrary-plane circle and closed-segment behavior is tested by independent polynomial-sign/axial-projection oracles, not inferred from this native corpus.

compare_splines.py captures 456 native OCCT observations before evaluating Rust positions and first/second derivatives. It covers degree 1..25, rational/polynomial Bézier curves, clamped/unclamped/periodic B-splines and explicit left/right derivatives at repeated knots and seams. The original Geom_BSplineCurve_Test.cxx cubic fixture is included. This is a native API comparison, not execution of those original C++ GoogleTest assertions. compare_surfaces.py adds 210 native rational surface jets, including mixed partials, all U/V periodicity combinations and degree 25 in both directions.

The 1,850 independent Python Fraction fixtures use basis-function recursion and closed quotient formulas; production differentiates homogeneous pole interpolation and uses recursive quotient rules. They cover subnormal spans, huge/tiny weights, extreme periodic wrapping, position versus derivative overflow and exact side/quadrant continuity decisions. All preexisting 385 curve fixture rows were preserved byte-for-byte when expanding the corpus.

The enlarged native corpus exposed degree-25 numerical discrepancies. On local OCCT 7.9.3, curves have 427 matches and 29 reviewed divergent cases; surfaces have 169 matches and 41 reviewed divergent cases. Each review pins version, input and the complete native jet, and recomputes the independent exact jet before accepting the Rust result. The budget remains 1e-10 + 2e-12*abs(expected). These observations do not establish that OCCT promises that error bound.

On Linux OCCT 7.6.3, the complete curve corpus has 426 matches and 30 reviewed differences (the 29 periodic cases plus the original case below); surfaces have 169 matches and 41 reviewed differences. Rust observations are identical on macOS and Linux. Native numerical differences remain explicit and version-pinned.

Ubuntu's OCCT 7.6.3 has one reviewed numerical divergence, not a matching case: d25_r1_s3_5, second derivative X, is -0.47077685134240305 instead of the exact value enclosed by [-0.47077685157054794, -0.4707768515705479]. The difference is 2.2602 times the unchanged native comparison budget; OCCT 7.9.3 stays within that budget. The independent basis/quotient calculation agrees with Rust. This records an observed numerical difference, not a claim that OCCT promises our error bound.

occt-spline-divergences.json pins the input hash, native version/value bits, exact rational answer and original CI evidence. The comparison recomputes the independent rational answer and checks Rust against its minimal enclosure before accepting that specific review. Changed inputs, native results, versions or incorrect Rust outputs still fail. Reports count matched, reviewed and unexpected cases separately. In the original 214-case subset, OCCT 7.6.3 has 213 matching, 1 reviewed divergence, 0 unexpected. Use compare_splines.py --strict-native to fail on reviewed differences too. The ordinary exact tests and fuzz comparisons have no such exception.

compare_spline_plane.py checks 214 native GeomAPI_IntCS observations against complete independent exact certificates. Local OCCT 7.9.3 has 155 matching cases and 59 reviewed differences. Extra near-tangent native points, missing overlap intervals, periodic endpoint conventions and numerical discrepancies are documented separately. Every review pins version, input, complete native values and independently recomputed certificate; it never exempts a Rust result from exact checks. --strict-native fails on reviewed differences too. SymPy is hash-pinned and test-only; Cargo tests use checked-in exact certificates without requiring Python or native OCCT. Linux OCCT 7.6.3 has 158 matches and 56 separately reviewed differences in the combined 214-case corpus. All Rust certificates agree across macOS and Linux. The additional 82 cases exercise explicit parameter ranges, including shifted periods, with native observations reviewed independently for each version.

The first implementation has deterministic analytic tests plus a recorded, independently evaluated OCCT 7.9.3 corpus. The live comparison was run on Apple Silicon macOS with Rust 1.96.0 and the installed OCCT 7.9.3 SDK.

fixtures/prisms.txt contains 66 solids in 11 families: boxes, triangles, concave profiles, polygonal frames, cylinders, tubes, four-hole plates, mixed polygon/circle holes, round profiles with square holes, collinear boundary segments, and concave profiles with circular holes. Each family has six variations covering scale, reversed profile winding, reversed offsets, arbitrary plane orientation, spatial translation and large local coordinates.

The independent OCCT executable constructs real B-reps with MakeWire/MakeFace/ MakePrism, verifies them with BRepCheck_Analyzer, and evaluates:

  • volume, surface area and centroid;
  • exact geometric axis-aligned bounds without tessellation;
  • central inertia tensor in world axes;
  • unique vertex, edge and face counts;
  • 2,292 inside/boundary/outside point classifications, including caps, seams, hole rims, random interior/exterior samples and out-of-height samples.

Both executables consume the same input file. The expected values in fixtures/occt-baseline.tsv come from OCCT, never from the Rust result. fixtures/occt-baseline.json records the oracle version and comparison summary.

The numerical acceptance budget is absolute + 2e-9 * abs(expected), with absolute 1e-7 for volume/area/coordinates and 1e-6 for inertia. Topology counts and classifications must match exactly. This is a test budget for this corpus, not a universal geometric error guarantee. The greatest observed error was approximately 0.000255 of that budget.

OCCT's default global-origin inertia accumulation lost precision on translated small parts. The oracle therefore centers a geometry copy before calculating the central tensor; it uses the original solid for all other queries. This does not change central inertia or relax the comparison tolerance. Separate analytic box/tube tests and translation-invariance tests check the Rust tensor.

Reproduce

The usual tests require only Rust:

cargo fmt --all --check
cargo test --workspace --locked
cargo test --workspace --locked --release
python3 rust/tools/generate_predicate_fixtures.py --check
python3 rust/tools/generate_spatial_fixtures.py --check
python3 rust/tools/generate_proximity_fixtures.py --check
python3 rust/tools/generate_linear_sets_fixtures.py --check
python3 rust/tools/generate_curved_fixtures.py --check
python3 rust/tools/generate_spline_fixtures.py --check
python3 rust/tools/generate_bezier_editing_fixtures.py --check
python3 rust/tools/generate_surface_editing_fixtures.py --check
python3 rust/tools/generate_surface_fixtures.py --check
target/math-oracle-venv/bin/python rust/tools/generate_spline_linear_fixtures.py --check
target/math-oracle-venv/bin/python rust/tools/generate_closed_clip_fixtures.py --check
target/math-oracle-venv/bin/python rust/tools/generate_affine_parameter_fixtures.py --check
target/math-oracle-venv/bin/python rust/tools/generate_brep_fixtures.py --check
target/math-oracle-venv/bin/python rust/tools/generate_tessellation_fixtures.py --check
target/math-oracle-venv/bin/python rust/tools/generate_step_fixtures.py --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo check --workspace --lib --locked --target wasm32-unknown-unknown
cargo run --locked --example plate

The live comparison requires a C++17 compiler and OCCT's modeling SDK:

python3 rust/tools/compare_occt.py --occt-root /path/to/occt
python3 rust/tools/compare_intersections.py --occt-root /path/to/occt
python3 rust/tools/compare_proximity.py --occt-root /path/to/occt
python3 rust/tools/compare_linear_sets.py --occt-root /path/to/occt
python3 rust/tools/compare_curved.py --occt-root /path/to/occt
python3 rust/tools/compare_splines.py --occt-root /path/to/occt
python3 rust/tools/compare_bezier_editing.py --occt-root /path/to/occt
python3 rust/tools/compare_surface_editing.py --occt-root /path/to/occt
python3 rust/tools/compare_surfaces.py --occt-root /path/to/occt

On macOS the default SDK is /opt/homebrew/opt/opencascade; on Linux it is /usr. OCCT_ROOT and CXX can override discovery. This helper currently supports Unix-style SDK layouts; Windows still runs all ordinary Rust and recorded-corpus tests. It does not install software or change noBS-CAD.

Results and optional native executables go in ignored target/occt-oracle/ and target/intersection-oracle/, target/curved-oracle/, target/spline-oracle/, target/surface-oracle/, target/bezier-editing-oracle/, target/surface-editing-oracle/. The live oracle does not link any rendering or data-exchange toolkit.

To intentionally refresh fixture inputs or reference data:

python3 rust/tools/generate_fixtures.py
python3 rust/tools/compare_occt.py --occt-root /path/to/occt --write-baseline

Review all changes to fixture inputs, expected results, version metadata and tolerances together. Never update a baseline merely to make a failing test pass. The generator uses a fixed seed and writes inputs only.

Spline/quadric comparisons

compare_spline_quadric.py captures 92 sphere/cylinder observations with the same headless GeomAPI_IntCS helper. OCCT 7.9.3 and Linux OCCT 7.6.3 each have 66 direct matches and 26 reviewed differences, primarily missing overlap intervals and later periodic events. Every Rust result is independently recomputed, including complete point counts, minimal enclosures, contact orders and overlap endpoints. Review hashes and native budgets use the same fail-closed checks as the plane bridge. The ordinary 118 exact fixtures also exercise dense degree-25 equations, order-50 contacts and extreme radii/axis magnitudes.

Exact Bézier extraction and editing

The bridge captures 546 native inputs before running Rust and compares all 1,672 returned arcs' control data, domains and degrees. Independent exact Cox basis polynomials plus affine substitutions must reproduce every Rust homogeneous control exactly. The native comparison permits common weight normalization and the documented floating budget. OCCT 7.9.3 has 506 matching cases and 40 reviewed degree-25 edit differences; Linux OCCT 7.6.3 has 508 matches and 38 separately pinned differences. All 546 complete exact Rust outputs are byte-identical between the platforms. Source GoogleTest inputs are reused, not executed unchanged.

The 636 exact fixtures add subnormal/adjacent knots, full-exponent geometry and weights, multi-period intervals and shifted knots below a floating ULP. Separate tests retain cuts 2^-2048 apart, prove edit commutation, check distinct one-sided derivatives, invalid rational parameters and traversal exhaustion. Fuzzing compares complete coefficients as well as exact jets and minimal bounds. No fixture or review exempts Rust from the exact mathematical contract.

Exact edited-curve intersections

All 402 existing spline/plane/sphere/cylinder fixtures run on the original binary64 curve, exact conversion, rational refinement, and exact removal back to the original. Independent Cox coefficients verify the refined homogeneous function, and every contact count, enclosure, order and overlap must equal the independent original certificate. The native bridges likewise check all four representations against independently recomputed certificates for the same 214 plane and 92 quadric inputs. Existing reviewed OCCT differences remain separate from native matches; these are not 1,224 distinct native geometries.

The 274 new Python Fraction fixtures manufacture known-factor polynomials, verify the complete implicit equation in Bernstein/power form, and provide exact rational contacts and minimal binary64 bounds (or explicit conversion failure). They cover degrees through 25, contact orders through 50, rational trims, roots separated by 2^-2048, mixed representable/unrepresentable results, huge/subnormal parameter domains, contained arcs and periodic crossings. Ordinary tests also check exact seam-origin removal, malformed rational input, atomic work-limit failure and huge control values cancelling to a finite contact.

See the exact result contract. Enclosure failure does not discard the exact contacts. The fourteenth fuzz target checks complete known-factor, secant and periodic answers after exact edits, including independent full polynomial identity and output-bound checks.

Exact curve knot refinement and removal

The native bridge retains all operation flags and complete curve representations for 667 inputs, including 665 captures made before Rust implementation and two supplemental nonconstant seam cases. The 723 ordinary fixtures independently solve every homogeneous Cox coefficient equation; selected cases also use a separate Greville collocation reconstruction. Rust's coefficient solver checks the entire unclamped raw support and full periodic function, so inactive end controls and seam correspondence cannot disappear behind point samples.

Debug/release tests cover rational cuts separated by 2^-2048, exact derivative overflow, discontinuities, positive-weight rejection, output preflight, periodic origin changes and a retained degree-25 solver timeout. Linux release CI runs the second exact equation oracle over every fixture, including failed removal. The thirteenth sanitizer target mutates edit sequences and independently solves removal feasibility. Native differences remain separate from parity matches. No new unchanged upstream DRAW passes are claimed; surface knot editing, general degree elevation and topology remain out of this milestone's scope.

python3 rust/tools/generate_knot_editing_fixtures.py --check
python3 rust/tools/compare_knot_editing.py --occt-root /path/to/occt

Exact tensor patches and isocurves

The 691-case native bridge captures independently before Rust execution and compares all 4,023 patches and 324 isocurves. The complete rational homogeneous outputs must agree with independent Cox tensor polynomials and binomial affine substitutions. The macOS OCCT 7.9.3 capture has 637 matches and 54 reviewed degree-25 Segment differences. Linux OCCT 7.6.3 has 635 matches and 56 separately pinned differences. All complete exact Rust outputs are byte-identical on the two platforms. All counts, degrees and original U/V domains agree. Native differences cannot exempt Rust from the exact oracle.

The 745 ordinary cases retain every complete homogeneous control using a lossless shared-denominator text format. They include all native input families, subnormal/adjacent knots, extreme homogeneous values, multiple turns, parameter rectangles whose interior knots round to the same float, and seeded rational surfaces. Full degree-25 x 25 native operations are recomputed in the bridge; Cargo fixtures retain extraction and composed edits for all four periodicity combinations. Exact boundary curves, mixed derivatives, axis commutation, rational cuts 2^-512 apart, invalid raw rational parameters and Cartesian budget exhaustion have additional tests. The twelfth fuzz target checks complete tensor coefficient identities, exact jets, enclosures and operation sequences.

Representation and numeric limits

  • Only finite normal extrusions of simple polygon/circle profiles are supported. No partial arcs, freeform surfaces, taper, oblique extrusion, general trimming, Boolean edits, closed cavities or multiple disconnected regions per solid.
  • Holes must be strictly inside, non-touching, disjoint and non-nested. Material islands can become separate solids; this crate does not discover sketch loops.
  • Linear tolerance defaults to 1e-7 mm, angular tolerance to 1e-12 rad. Callers may supply validated tolerances. Inputs are revalidated if boundaries built under one tolerance are assembled with another.
  • Coordinates that cannot resolve the requested tolerance are rejected using a 16-ULP-scale budget; geometry is not rescaled to bypass this check. This is a conservative solid-construction guard. The separate exact predicates accept all finite f64 inputs, and implemented linear/curved intersections use certified coordinate/parameter enclosures. Solid distance, area and moment calculations remain ordinary floating-point arithmetic.
  • Boundary validation is quadratic; input is bounded to 4,096 total profile edges and 128 holes. This is an initial implementation limit.
  • Topology is immutable and body-local. Indices and FaceOrigin do not claim persistent naming through arbitrary feature edits or Booleans.
  • The topology validator certifies the contract in BREP_VALIDATION.md for line/arc edges on planes and cylinders. It does not check 2D loop self-intersection or face/face intersection, and it is not a healer or importer.
  • Mass properties are geometric at unit density; density and material metadata belong to the application. No strength or manufacturing result is implied.

These comparisons establish the implemented prism subset. They do not establish parity with the fork-point OCCT development revision or all of OCCT. Kernel readiness requires the mathematical, topology/history, interchange and operational gates in PRODUCTION_READINESS.md. Application migration is separate, deferred work.

The Bézier second oracle also has an exhaustive gate:

RUSTY_VERIFY_ALL_BEZIER_ORACLES=1 cargo test --locked --release \
  --test bezier_editing exact_controls_match_independent_polynomials_and_original_parameter_jets

Linux release CI verifies all 636 Bézier and 745 tensor fixtures against both the independent Python expectations and the separate Rust coefficient/jet checker. Shared integer denominators reduce checker replay cost without changing its equations or assertions. Retained fuzz inputs and failed startup campaigns are documented in the regression record.

Exact surface knot representations

generate_surface_knot_fixtures.py --check independently regenerates 1,756 complete U/V knot edits, success flags and homogeneous grids using Cox power coefficient equations over full raw support. Ordinary Rust tests consume all fixtures. The original 791 surface jet fixtures additionally verify the retained exact representation and reusable differentiated de Boor evaluation. The Linux job also sets RUSTY_VERIFY_ALL_SURFACE_KNOT_ORACLES=1 to run every surface-knot fixture through the separate Rust coefficient/feasibility solver. compare_surface_knots.py compares 1,748 complete native observations; native round-trip differences remain separate from matches. Six deliberate-corruption bridge tests protect control, weight, flag, input-set and versioned-review comparisons.

The surface_knots sanitizer target checks every transverse coefficient, independent exact removal feasibility, whole patch polynomials, quotient jets, isocurves, periodic wrapping, malformed data and operation sequences. Its retained degree-25 timeout reproducer is also an ordinary Cargo regression. The fifteen-target daily workflow retains evolving corpora and artifacts.

General degree-elevation acceptance

All 142 curve and 125 tensor fixture grids are reconstructed with Python Fraction/Cox equations and independently with the Rust integer equation solver. RUSTY_VERIFY_ALL_DEGREE_ORACLES=1 cargo test --release --test degree_elevation checks every second-oracle result, including unclamped inactive controls.

The source-pinned OCCT SDK is built from commit 3d097a0328e71b826377d4814ab05ec3c3d23871 with exception checks enabled. The native comparison runner reports 187 matches, 46 reviewed native exceptions and 34 reviewed invalid grids. Fingerprints cover every input, exact output, native output/diagnostic and source revision; crashes remain failures. Deliberate-corruption tests reject altered controls, flags, domains, case sets, stale captures and wrong runtime libraries. See degree elevation for the native comparison commands.

Revision 27647fadbb82ca8e516b66b606687d65144e0cf7 passed all sixteen Linux sanitizer targets, each with a full 60-second mutation budget after replay, and a separate 600-second local degree-elevation mutation campaign. Its platform gate passed 120 tests in debug and release on Linux, macOS and Windows, Rust 1.85, WebAssembly compilation and all five Linux second-oracle checks. The retained periodic tensor timeout is covered by ordinary tests as well as fuzzing. The acceptance evidence pins the code revision, workflow runs, observed limits and remaining scope.

Exact ordering across algebraic equations

generate_root_comparison_fixtures.py --check verifies 130 equation pairs using irreducible-factor identity and continued-fraction isolation. Cargo checks all pairwise root comparisons in both directions, including exact ties, degree-25 clusters, unrepresentable roots and shifts below binary64 resolution. The existing 95 real-root fixtures also check every within-equation ordering. The roots sanitizer harness constructs independent one- and two-root factor equations to check cross-equation equality and ordering throughout campaigns. This foundation does not yet implement rational-function image comparison or complete curved-distance minima.

Complete spline/linear preimages

generate_spline_linear_fixtures.py --check reproduces 60 complete line and segment preimages from independent Cox coefficients, QQ factorization, VAS isolation and rational sample-point clipping. Cargo proves every returned parameter's membership in the independent irreducible equation and its isolator, and checks line parameters. It also repeats the 43 binary64-representable cases through the binary64 entry points and every case after exact knot insertion and elevation. The first 31 inputs match the separate SymPy-inequality preimages captured with the pre-implementation native observations. Closed clipping (79 inequality sets) and affine root ordering (851 comparisons) have separate generated fixtures. The spline_linear fuzz target checks constructed complete answers. compare_spline_linear.py then compares native IntTools_EdgeEdge observations. See the bridge. No platform acceptance is claimed yet.

Value identity

generate_identity_fixtures.py --check pins the derivation encoding and FNV-1a-128 digest with 17 vectors, and computes every entity id (46,494, regions included, circles seamless) of 546 extrusions from an independent Python enumeration: 34 explicit cases (3–12 sides, circles, 0–3 holes, both directions, clockwise input, labels absent, present, permuted, moved and inserted, the eight box_at sign combinations and rigid copies) and 512 mirroring the invariants corpus. identity.rs locates every Rust entity from geometry alone and requires its id, role, ordinal and parents to match, before and after every rigid motion. The identity fuzz target recomputes ids with its own encoder.

There is no native bridge for value identity: OCCT has no value ids. A TopoDS_Shape is the same shape only while it holds the same TShape pointer and location, so no native observation can confirm or refute an id.

Operation history

generate_history_fixtures.py --check writes the complete relation list of every value-identity case from the independent enumeration: each construction's Generated relations, each rigid motion's Modified relations, and their composition (114,270 relations since the seamless cell model; region relations are listed beside the corpus digests). history.rs requires Rust's canonical relation lists to match, and every history to pass the independent checker, before and after composition, and to replay at its recorded algorithm level. The history fuzz target mutates produced histories. compare_history.py maps source-pinned BRepTools_History/BRepPrimAPI_MakePrism observations (captured before implementation) to Rust relations by geometry. OCCT's seams and seam vertices are classified structure-only by rule, the solid generated from the face maps to the region, and every case's synthesized OCCT counts must equal native's; see identity and history. Two derived DRAW cases check generated, modified and isdeleted on both backends, and a third checks a seamless pcylinder through the count synthesizer.

Arc prisms (S5): generate_identity_fixtures.arc_cases() writes thirteen prisms of profiles with arcs (fillets, a notch, arcs over half a turn, a two-arc lens, holes with arcs, reversed input, labels, a tilted frame, transforms, a small body far away) and their ids from identity_reference.py (identity-arc-*.txt|tsv); identity.rs requires the kernel's ids, validity and rigid motions to match. Their native MakePrism observations were captured before any kernel arc code (fixtures/occt-arc-prism-preimplementation), and compare_history.py --family arc matches all thirteen: every Generated, FirstShape and LastShape query, counts, face areas and centroids, the body's volume and centroid and each transform step. arc_profiles.rs covers invalid paths, reversal and labels, classification, the closed-form mass inside the certified enclosure, the height split and stacked fuse, and the builder against the neutral generator's arc prisms.

Sheets, wires and acorns (S6): generate_brep_fixtures.sheet_models() adds eighteen models cut from the neutral prisms (free faces, an open box, closed shells without a solid, wires, a free edge, a vertex and three mutations); the independent validator learned two-sided faces, wire edges and acorn vertices, and brep-classes.tsv gives every valid case's class. brep_validation.rs requires the kernel's issue lists (170 cases, 78 valid), classes and certified measures (containing the native BRepGProp rows of the pre-implementation capture). compare_brep.py --family sheet reproduces that capture and compares verdicts, synthesized counts, enclosures and measures: 17 matches, 1 reviewed difference (the open box's shifted pcurve), 15 counts and 15 measures verified. generate_identity_fixtures.sheet_cases() writes eleven face and wire bodies (polygons, a disc, arc paths, holes, labels, clockwise input, tilted frames, rigid copies) and their ids from identity_reference.sheet_entities; identity.rs requires the kernel's ids, classes, validity, counts and rigid motions to match. The derived DRAW case faces_and_edges (mkface on a plane and a cylinder, mkedge on a line and a circle, mkplane of a profile wire with arcs) passes on both backends.

Analytic surface intersections (S7a)

generate_analytic_intersection_fixtures.py --check writes 67 surface pairs with an exact and a near case of every degeneracy class and their canonical results from analytic_intersection_reference.py (exact rationals, 80-digit mpmath, a different method from the kernel's closed forms), and each surface's stored normal. analytic_intersections.rs requires the kernel to store the same normals, to contain every reference number in its enclosures, to be symmetric, to keep enclosures within four units in the last place, to return curves on both surfaces and to move items with translations. compare_analytic_intersections.py reproduces the pre-implementation IntAna_QuadQuadGeo capture and compares: 63 matches, 4 reviewed differences (near-degenerate configurations IntAna snaps), the kernel inside the reference on all 67 and within 1e-9 of OCCT on the 43 matching cases with items (ANALYTIC_INTERSECTIONS.md).

S7b.1: generate_procedural_intersection_fixtures.py --check writes 20 cylinder/cylinder and cylinder/sphere pairs (every class exact and near) and their rows from procedural_intersection_reference.py; procedural_intersections.rs requires the kernel's procedural curves to contain the reference's loop ranges, ends, ring and node points, to put a loop's middle within 1e-12, to be independent of argument order and to keep sampled points on both surfaces. compare_procedural_intersections.py reproduces the pre-implementation GeomInt_IntSS capture: 17 matches, 3 reviewed differences, the kernel inside the reference on all 20. S7b.2 adds 15 cylinder/cone and sphere/cone cases and a second capture taken before any kernel cone code: 31 matches and 4 reviewed differences over the 35, the kernel inside the reference on all 35, loop ends narrowed to a few units in the last place. S7b.3a adds 58 torus cases (a plane or a sphere in every class, the special and coaxial circles) and a third capture taken before any kernel torus code: 86 matches and 7 reviewed differences over the 93, the kernel inside the reference on all 93, the stored normals checked bit for bit (procedural-intersection-frames.tsv), and every circle and sampled curve point on both surfaces.

S7b.3b: generate_torus_curve_fixtures.py --check writes 24 torus/cylinder and torus/cone pairs and 14 pairs of tori (S7b.3b.2) and their rows from torus_curve_reference.py (80-digit meridian roots, critical meridians from a resultant, tangencies from Groebner bases); torus_curves.rs requires the stored normals, every reference fold, tangency and ring point inside the kernel's enclosures, the same components and winding numbers, order independence and points along every track on both surfaces. compare_torus_curves.py reproduces two pre-implementation GeomInt_IntSS captures (one per sub-step): 28 matches and 10 reviewed differences, the kernel inside the reference on all 38.

S7b.4: generate_ruled_curve_fixtures.py --check writes 12 pairs of two cones and of a cone's apex on a sphere or a cylinder, and their rows from ruled_curve_reference.py; ruled_curves.rs requires the stored normals, every reference fold, apex, line and ring point inside the kernel's enclosures, the same components, winding numbers and crossings of infinity, order independence and finite points along every track on both surfaces. compare_ruled_curves.py reproduces the pre-implementation capture: 9 matches and 3 reviewed differences, the kernel inside the reference on all 12.

S7c.1: generate_curve_surface_fixtures.py --check writes 36 lines and circles against every analytic surface and their rows from curve_surface_reference.py; curve_surface.rs requires the stored normals, the reference's classes, contacts and point counts, every reference number inside the kernel's enclosures (a circle's angle modulo a turn), an arc's result equal to its circle's, and every point the curve's point at its parameter. compare_curve_surface.py reproduces the GeomAPI_IntCS pre-implementation capture: 29 matches and 7 reviewed differences (missed containment), the kernel inside the reference on all 36.

S7c.2: the same generator adds 35 ellipses, hyperbolas and splines (against tori and cones), curve_surface.rs checks each conic's stored axes bit for bit besides the normals, and compare_curve_surface.py reproduces the second pre-implementation capture: 30 matches and 5 reviewed differences, the kernel inside the reference on all 71 cases.

S7d.1: generate_curve_curve_fixtures.py --check writes 41 pairs of lines, circles, ellipses and hyperbolas and their rows from curve_curve_reference.py; curve_curve.rs requires every frame's stored normal and axes, the reference's classes, contacts and counts, every reference number inside the kernel's enclosures, and swapped curves to swap the parameters (overlapping enclosures) with the same contacts.

S8a (SPLIT.md): generate_split_fixtures.py --check writes 26 prisms and planes and each side's volume, area and centre from split_reference.py; split.rs requires each prism's stored axes, every side's sums of the kernel's enclosures to contain the reference's, complete, checked and repeatable histories; compare_split.py reproduces the BRepAlgoAPI_Splitter pre-implementation capture (26 within 2e-8 of the reference, two reviewed count differences against the kernel), the 13 cases of S8a.1 inside the reference and the 13 oblique ones listed as pending S8a.2. compare_curve_curve.py reproduces the IntTools_EdgeEdge pre-implementation capture: 41 matches, the kernel inside the reference on all 41.

S8b: the same generator adds 17 prisms of spline profiles (split-spline-cases.txt, their sides from slicing exact Bézier pieces, checked against polygons and Green's theorem in exact Fractions); split.rs requires the kernel's sums to contain the reference's on all of them, their histories to check (spline edges and walls against their parents' supports) and spline pieces to move, tessellate and round-trip through .brep; compare_split.py reproduces occt-split-spline-preimplementation (10 within 2e-8, seven reviewed BRepGProp errors on spline faces, one reviewed count difference at a tangency), the kernel inside the reference on all 103 split cases.

S7d.2: the same generator adds 13 splines against conics; curve_curve.rs checks their rows and overlaps too, and compare_curve_curve.py reproduces the second capture: 11 matches and 2 reviewed differences, the kernel inside the reference on all 54 cases.

S9a (BOOLEAN.md), before any kernel code: generate_boolean_fixtures.py --check writes 45 Booleans of two prisms in one frame (15 fuses, 17 cuts, 13 commons; both frames, the tool's origin offset) and each result's solid count, volume, area, centre and slab profiles from boolean_reference.py, after checking the reference against Green's theorem, exact Fraction clipping and boundary classes of polygons, closed-form lenses, hand results and fuse = A + B - common, cut = A - common (all within 1.2e-38); compare_boolean.py reproduces the BRepAlgoAPI_Fuse/Cut/Common pre-implementation capture: every result valid with the reference's solid count, all 45 within 2e-8 of the reference (6.1e-15 at worst), no review. With S9a.1 and S9a.2's stacks, boolean_probe puts every result inside the reference with the reference's solid count (42 cases; 5 empty, 6 stacks) and refuses the 3 degenerate ones, every count equal to OCCT's after unifying; booleans.rs checks the same and every history. With S9a.2's spline profiles it does the same on the 46 spline cases (45 inside, the degenerate one refused), four tangencies' counts reviewed. S9a.2's spline profiles, before their kernel code: the same generator writes 46 Booleans of prisms whose profiles hold S8b's splines (boolean-spline-cases.txt; 14 fuses, 16 cuts, 16 commons, 18 tilted) from boolean_reference.SplinePair (meetings by exact square-free Bernstein root isolation and by Bezier subdivision with Newton, no resultants; atoms by Green's theorem over the classified pieces), checked against S9a's slicing, exact Green's theorem and Bernstein products, Gauss-Legendre quadrature, mp.polyroots, the volume identities, straight splines against their polygon and 8 hand results (all within 3.7e-39), and chords extrapolated (2.1e-4, within their own error estimate); compare_boolean.py --splines reproduces the capture occt-boolean-spline-preimplementation: every result valid with the reference's solid count, 37 within 2e-8 and 9 reviewed (BRepGProp's integration of faces bounded by B-spline edges, up to 8.0e-4 on the three-span wave; Green's theorem over OCCT's own cap edges agrees with the reference within 4.5e-8), and the kernel unsupported on all 46.

S9b (BOOLEAN.md), before any kernel code: generate_polyhedral_fixtures.py --check writes 45 Booleans of polyhedral prisms in frames with different axes (15 of each operation) from polyhedral_reference.py (exact convex cells and half-space clipping in Fractions), after checking it against S9a's slicing reference on the 21 polygon cases of S9a (2.3e-17), the area identity of fuse and common (3e-41) and closed forms of boxes; compare_polyhedral.py reproduces the BRepAlgoAPI capture: every result valid with the reference's solid count, all 45 within 7.9e-16, no review. With S9b.1 the kernel puts 41 results inside the reference and refuses the 4 degenerate ones; two count differences are reviewed (OCCT's imprints of a touching edge and vertex); polyhedral_booleans.rs checks every history.

S9c.1 (BOOLEAN.md), before any kernel code: generate_curved_boolean_fixtures.py --check writes 44 Booleans of prisms whose profiles hold arcs and circles, in frames with different axes (14 fuses, 13 cuts, 17 commons; 35 solid, 2 empty, 7 degenerate with their reasons) from curved_boolean_reference.py (slices parallel to both axes, each section a union of parallelograms, breakpoints as roots of exact polynomials, Gauss-Legendre between them; faces swept in their own parameters for the areas), after checking it against closed forms (Steinmetz solids, an oblique cylinder between planes, a quarter cylinder, a box corner in a cylinder, coaxial and parallel cylinders, a cylinder cut obliquely; 9.2e-41 in exact frames, 1.9e-16 in turned ones, whose stored axes are not orthonormal), the volume and area identities, face classes against closed-form face areas and a second slicing direction (all within 2e-40), Monte-Carlo estimates (within 2.7 standard errors) and S9a's and S9b's references on their 90 fixtures (every solid count, all 25 printed digits for S9b's, 2.4e-17 for S9a's frame coordinates). Only frames whose stored axes the kernel gives bit for bit are used (ROT's x differs in its last bit on macOS arm64). compare_curved_boolean.py reproduces the capture occt-boolean-curved-preimplementation: every result valid with the reference's solid count, all 44 within 8.6e-9 (BRepGProp on faces bounded by ellipses), no review, and the kernel unsupported on all 44 (before its code). With S9c.1's kernel: 42 matches (31 results inside the reference, 7 declared degenerate refused, 6 of S9c.2's cylinders unsupported) and 2 reviewed differences (occt-boolean-curved-divergences.json: the Steinmetz fuse's and common's counts, OCCT's seam edges on their faces), no failure.

The GeomInt_IntSS captures were taken on macOS arm64; IntPatch's walking lines differ on Linux near degeneracies (the first Linux run changed cc_near_figure_inside). A run on another platform reproduces that platform's reviewed record instead (platform-<name>/ beside the capture: its observations, digest and review), each run writes what it observed (native-observed.txt) for the review, and differences from the reference are fingerprinted per platform (the cross-platform allowances below).

Tessellation (T-a)

generate_tessellation_fixtures.py --check writes 28 bodies (prisms of polygons, circles and arc paths with holes, a box, cones, spheres and tori with poles, bands, an inner half and a wedge, face bodies) with a coarse and a fine setting, and what tessellation_reference.py derives from each case alone: the class, the Euler characteristic, a face body's loops, exact area and volume. tessellation.rs meshes all 56 and requires the certified bounds within the request, 12 samples of every triangle within its bound of its face's whole surface (closed-form distances independent of the kernel's), closedness, opposite orientations, the Euler characteristic, the volume within the deflection times the areas, determinism and convergence; and the contract on the 54 certified data/occ solids without spline geometry. compare_tessellation.py reproduces the pre-implementation BRepMesh_IncrementalMesh capture and the .brep texts it read, runs the reference's full check on the kernel's meshes (all 56 pass) and on OCCT's welded meshes: 42 matches and 14 reviewed differences (OCCT beyond the request on seven rows, degenerate triangles at poles; TESSELLATION.md).

Tessellation of splines (T-b)

generate_tessellation_fixtures.py --check also writes twelve spline bodies (prisms with quadratic, cubic and rational spline walls, a wave with a spline and a circular hole, a sharp rational corner, a far translate, degree-1 spline edges and pcurves on a stadium's cylinder; a plane face in a periodic spline ring; a box under a spline graph; a trimmed bicubic sheet and a rational biquadratic sheet), each checked valid by the reference validator, and what tessellation_reference.py derives from each case alone. tessellation.rs meshes all 24 (areas, volumes, the Euler characteristic, closedness, determinism, triangle centroids within their bounds of the surface by a projection evaluated by Cox-de Boor in the test), the 17 valid B-rep fixture cases with spline geometry against their certified mass enclosures, and every one of the 59 certified data/occ solids, the five with spline geometry among them (Motor-c.brep 378's blends with cusp corners since the corner turn; the test's projection adds a compass search where Gauss-Newton stalls at a cusp). tessellation/spline.rs tests that the cells enclose the exact points and partials and that their bounds hold, on rational and nonrational surfaces up to degree 8, and that the corner turn bounds the widest angle between exact normals sampled on fans, segments and triangles at and beside a cusp corner (rational or not), shrinking with them. compare_tessellation.py --family spline reproduces the pre-implementation capture and the .brep texts, runs the reference's full check on the kernel's meshes (all 24 pass) and on OCCT's: 21 matches and 3 reviewed differences (OCCT beyond the request on the dome and the trimmed sheet at the fine setting, its recorded deflection understating the dome's at both; TESSELLATION.md).

Height split and stacked fuse

generate_split_merge_fixtures.py --check writes 174 scenarios from the independent enumeration in split_merge_reference.py: every explicit identity prism split, fused back, composed and its upper piece split again; stacked fuses of separate constructions (increasing and decreasing, circles, labelled holes, rigid copies, either call order, which gives the same ids); 13 rejected splits and fuses (heights at, outside or within the tolerance of an end; gaps, overlaps, opposite directions, other profiles, labels or frames, and bodies sharing ids); and 128 corpus prisms split at xorshift heights and fused back. split_merge.rs requires every relation, composition, output body id and entity row to match, every history to pass the independent checker and every output to pass Topology::check; law tests check volume conservation, exhaustive resolution, fused properties equal to the original prism's, ids kept through rigid motion and replay at the recorded level. The split_merge fuzz target mutates produced histories. compare_split_merge.py maps source-pinned BRepAlgoAPI_Splitter and BRepAlgoAPI_Fuse plus ShapeUpgrade_UnifySameDomain observations (captured before implementation) to the Rust relations by geometry; see identity and history.

Attributes through operations

generate_attribute_fixtures.py --check writes 33 scenarios: every explicit split/fuse scenario of M3 whose steps succeed, each initial body first translated, with 48 attribute keys (the 24 policy combinations, each with values that agree across split pieces and values that differ between separately built bodies) on about a quarter of the entities each. The independent attribute_reference.py gives every step's outcomes and every produced body's attributes; every relation kind meets every applicable policy variant (kept, dropped, recomputed, copied, and conflicts from both unequal and missing values). attribute_outcomes.rs requires them all to match and checks the error contracts and determinism; every operation also runs the independent attributes::check in debug builds. The attributes fuzz target runs random policies and values through transform, split and fuse. There is no native bridge: OCCT has no attribute propagation at kernel level (its attributes live in OCAF labels, outside the modelling algorithms).

Generic B-rep validation

generate_brep_fixtures.py --check rebuilds 152 cell-complex cases (63 valid): 54 converted by rule from an independent seamed prism builder and its mutations, twenty-two cell-model cases for the model's own failure modes, the near-frequency bound and enclosures (gaps just inside and outside the resolution; missing, out-of-range and unsound bounds), twelve cones (six valid, six mutations of the pole, the winding, the angle and a ring pcurve), fifteen spheres (seven valid, the whole sphere among them, and eight mutations) and thirteen tori (seven valid: the whole torus, both halves, a segment, two wedges and a far copy; six mutations) and twenty-one spline cells (R4: C1 and broken knots on edges, pcurves and faces, periodic seams, degenerate splines, ranges, a reversed pcurve and a far, small rational corner) and ten spline models with native rows (six valid, as natively); for the sixteen valid spline cases, volume, area, centroid and inertia by nested Gauss–Legendre quadrature (brep-spline-mass.tsv), which the kernel's certified mass enclosures must contain, with complete issue lists from the separate mpmath reference validators (brep_reference.py, cell_reference.py). brep_validation.rs requires Rust's sorted report to equal each list exactly. The brep_validation fuzz target mutates valid prisms and cavities into specific invalid complexes. compare_brep.py compares native BRepCheck_Analyzer verdicts and status classes on the seamed encodings, sets statuses on native seams aside as structure-only and checks the synthesized counts of every valid case. See the bridge.

Enclosures (M5): every fixture carries bounds that the independent reference declares; Rust's report equals the reference's on all 152 cases. Measured bounds of the 63 valid cases lie between the reference's certain gap and its declared bound (brep-enclosure-lows.tsv, within a stated frame-rounding allowance). enclosures.rs requires every prism of the identity corpus to be enclosed within its resolution and no continued entity's bound to fall through a transform, split and fuse. The same bridge reproduces OCCT's stored tolerances and measured deviations (BRepLib_ValidateEdge), captured before implementation, and requires the kernel's bounds to be at least OCCT's measurements and at most its tolerances on the 21 cases valid on both sides. See enclosures. compare_brep.py --family spline does the same for the spline models, and also requires the kernel's mass enclosures to contain BRepGProp's properties, captured before any kernel code integrated spline surfaces (10 matches, 3 reviewed differences; the three F8 models captured before the certified quadrature). The allowance is OCCT's error estimate plus 1e-8 relative, and 2e-8 for the sheet bridge's lone spline wall: F8's enclosures are within 1e-12 of each property's scale, so it absorbs OCCT's own integration error (1.7e-9 on the bulge's area, 1.8e-8 on its wall's), not the kernel's width. Against the independent reference the spline masses allow 1e-20 of each property's scale, the reference's own verified quadrature error.

OCCT .brep interop

brep_io_reference.py is a separately written reader of the format (from dox/specification/brep_format.md and the pinned BRepTools_ShapeSet and TopTools_LocationSet sources, without Rust). For every data/occ file, generate_brep_io_fixtures.py --check records the geometry records the kernel cannot represent, by name and count. For every solid the root reaches through compounds, it records whether its structure is representable, and OCCT's distinct subshape counts of the original, seamed solid. occt_brep.rs requires Rust's import to agree file by file: the same unsupported geometry, the same solids, a cell topology exactly for the representable ones (60 of 77: one more with cones, fourteen with spheres, twelve of them whole spheres and two with loops through a pole, and ten with tori since S3, six more with B-spline edges, pcurves and surfaces since S4; horn and spindle tori are NonRingToroidalSurface, and periodic spline surfaces and seams on spline surfaces are unsupported) and synthesized counts equal to the original counts. 59 of them are certified; occt_brep.rs pins the one the validator does not certify yet with its issue kind (a sphere loop that passes both poles between two kept seam pairs, seam_edge); Motor-c.brep 378, a hole with spline pcurves in a wound cylinder face, certifies since S8d.2's signed ray. Every one of the 564 identity cases (546 prisms, six cones, six spheres and six tori) and the 13 arc prisms of S5 writes, reads back and imports to the same counts with bit-identical vertices, twice. Malformed text gives typed errors.

compare_brep_io.py builds occt_brep_io_oracle.cpp (BRepTools::Read, BRepCheck_Analyzer, TopExp::MapShapes, BRepGProp) against the pinned SDK. It first certifies the independent reader against OCCT: the solids of every corpus file, and their counts, must be exactly the reader's (77). Then native OCCT reads everything the kernel writes. Each of the 577 identity and arc-prism writes must be one valid solid whose counts equal the synthesized counts and whose volume, area and centroid equal the kernel's mass properties (exact for prisms, arc prisms' closed forms, certified midpoints for cones, spheres and tori). Each of the 59 certified corpus solids, written back, must be one valid solid with the original's counts, volume, area and centroid. The worst property difference observed is 6.6e-14 relative (macOS, since S3), against a bound of 1e-11. The native observations of the unmodified corpus are pinned in fixtures/occt-brep-io-capture and must reproduce on every run. They were captured after the implementation; NOTES.md there records that order break and what it does and does not affect. test_brep_io_oracle.py checks that capture drift, malformed native output and property differences are caught.

Since S6 the reader also imports free shells, faces, wires, edges and vertices (brep-io-expected.tsv lists the reader's verdicts on the 6,223 free shapes of the corpus). occt_brep.rs requires every representable one to import with the reader's counts and round-trip, except the hammer's 31 faces the validator rejects, pinned with their issue kinds; terrain and MAT exceed MAX_POLES, and face2 and shell1 use unsupported constructs. compare_brep_io.py compares the 6,188 imported free shapes with the native capture (fixtures/occt-free-shape-capture, taken before the import existed): OCCT's counts, certified measures containing OCCT's area or length and centre, and every one written back read natively valid with the same counts and properties; so are the eleven face and wire bodies.

The brep_io fuzz target mutates written prisms, cones and upstream files token by token and line by line: no panic, typed errors, valid imports, and round trips of every writable import to identical counts and vertices.

Cones (S3)

  • generate_primitive_fixtures.py --check writes 22 cones (primitive-cases.txt) and their expectations from primitive_reference.py alone: OCCT's counts, volume, area, centre and inertia by exact disc integrals in mpmath, and every face, edge and vertex. tests/cones.rs requires the kernel's cone builder to equal them within 1e-12 of the case's scale (the rounding of the stored frame, angle and slant), with a clean validation report.
  • compare_primitives.py builds occt_primitive_oracle.cpp against the pinned SDK: BRepPrimAPI_MakeCone, BRepCheck_Analyzer, BRepGProp and every subshape. All 22 equal the reference (worst 4.9e-15), and the capture taken before any kernel cone code must reproduce. test_primitive_oracle.py checks that every difference class is caught.
  • compare_revolve_history.py compares the kernel's cone histories with BRepPrimAPI_MakeRevol of the meridian through BRepTools_History, by the correspondences its docstring lists: 21 matches and one reviewed difference (nearly_cylinder, a surface of revolution natively, occt-revolve-history-divergences.json). test_revolve_history.py checks the failure classes. The capture's order is recorded under R11 of REVIEW_NOTES.md.
  • Spheres follow the same pattern: 22 spheres and zones in sphere-cases.txt against primitive_reference.py (tests/spheres.rs), compare_primitives.py --family sphere (22 matches, worst 6.7e-15) and compare_revolve_history.py --family sphere (22 matches, no difference), both captured before any kernel sphere code; six identity spheres; the derived case psphere_counts; and the original case bugs/modalg_6/bug27264_2 (a restored whole sphere) passing on both backends.
  • Tori follow it too: 22 whole tori, v-segments and wedges in torus-cases.txt against primitive_reference.py (tests/tori.rs), compare_primitives.py --family torus (21 matches, worst 3.2e-15, and one reviewed difference: OCCT's inner_half is inside out, its volume and inertia negated) and compare_revolve_history.py --family torus (22 matches, no difference), both captured before any kernel torus code; six identity tori; and the derived case ptorus_counts.
  • The identity and history fixtures add six cones (cone_entities); the .brep round trips and the native interop bridge include them; the derived DRAW case pcone_counts passes on both backends; and the brep_validation, identity, history and brep_io fuzz targets build and mutate cones.

STEP import (STEP-a, STEP-b)

generate_step_fixtures.py --check writes 22 small STEP files authored for the track (fixtures/step): boxes in AP203, AP214 and AP242, in metres and inches and with every orientation flag flipped; an L prism, a plate with a hole, a box with a void, cylinders (one tilted), a half cylinder, an apex cone, frusta with the semi-angle in radians and degrees, a sphere, a hemisphere, a torus, a quarter-torus elbow, two solids in one file, an open box as a surface model and a hand-written corner tetrahedron exercising the syntax. step_reference.py is written without Rust: its own Part 21 parser gives each body's class and OCCT's counts from the file, and closed forms of the construction parameters (mpmath, 60 digits) its volume, area and centre (step-expected.tsv, identical on Python 3.9 and 3.12). step::part21's unit tests cover every parameter kind, complex instances, comments, several data sections, the string directives and every syntax error; tests/step.rs requires all 23 bodies to import as the reference says (class, OCCT's counts, enclosures containing its measures within 1e-12 relative, the files' uncertainty as resolution, External ids), deterministically, and every construct outside STEP-a to be named: ELLIPSE, PCurveNotDerived, PeriodicFaceWithoutSeam, VERTEX_LOOP, UnitsUndetermined, AssemblyPlacement, the schema error, and a moved vertex as an import failure with vertex_off_curve.

compare_step.py builds occt_step_oracle.cpp against a pinned SDK with TKDESTEP (build_pinned_occt.py --toolkit TKDESTEP) and reads each file with STEPControl_Reader. The native observations were captured before the importer existed (fixtures/occt-step-preimplementation): all 22 files match the reference (counts and verdicts exactly, measures within 7.6e-15), and every run must reproduce them. The kernel's bodies must contain the reference's measures within 1e-12 and OCCT's within 1e-9, with OCCT's counts: 22 matches, 0 reviewed differences, 0 failures. test_step_oracle.py checks that wrong counts, verdicts, measures, centres and bodies on either side are caught.

STEP-b adds seven files (generate_step_fixtures.py's STEP_B): a half-ellipse sheet on the plane of its axes; a cylinder cut by an oblique plane (its top an ellipse on a plane whose axes are not the ellipse's, its wall bounded by the section); a sheet and a prism bounded by a two-span cubic, the prism's side a B-spline surface with the file's line pcurves and its curves also carrying pcurves on the caps; a two-span patch sheet with line and B-spline pcurves; a patch trimmed by a curve whose pcurve is a quadratic B-spline (its 3D curve the exact composition, of degree 9); and a cylinder of rational quarter-arc half circles and half-cylinder surfaces, all complex instances. step_reference.py measures them by closed forms, exact rational integrals (the profile's area and centroid by Green's theorem on its Bézier pieces in Fractions) or Gauss-Legendre quadrature at 40 digits (the profile's arc length, the patches' areas and centres, each error estimate below 1e-30; the trimmed patch agrees with a nested tanh-sinh quadrature to 17 digits). It also checks every file's geometry with its own evaluation (de Boor's algorithm, rational in homogeneous form): every edge meets its vertices and lies on its faces' surfaces, through the file's pcurve on a spline surface at the same fraction of both ranges, within 1.1e-16 of the case's size over all 29 files (20 spline uses). The native capture (fixtures/occt-step-b-preimplementation) was taken while step/spline.rs did not exist and the importer rejected all seven files: OCCT's counts and validity agree with the reference; its default BRepGProp integration misses three bodies' measures (the oblique cylinder by 3.5e-6, the two-span patch by 5.7e-7, the rational cylinder by 2.0e-3), which its adaptive integration reproduces.

tests/step.rs requires all 30 bodies to import as the reference says (a sheet of one face with a free face's synthesized counts, S6: no shell). The rational cylinder was refused by edge_not_c1, pcurve_not_c1 and face_not_c1 until U10 (b): R4 certified C1 of the homogeneous curve, which the quarter-arc form is not at its double knots; it now tests the rational curve, which is C1 there, so the cylinder imports valid with OCCT's counts and the reference's measures and its .brep text reads back, while the same file with its knots at 0, 1 and 3 (G1 joints) is refused by exactly those three kinds. The plate's and the prism's splines rewritten as complex rational instances import as the plain ones; the plate bounded by a rational third of a circle (weights 1, 1/2, 1) contains the circular segment's closed form; BEZIER_CURVE, EdgeRangeInverted, PCurveNotDerived (a pcurve on another surface) and PCurveAgainstEdge are named, and a pcurve bent off its edge is an import failure with pcurve_off_edge. compare_step.py gives 23 matches, 6 reviewed differences (occt-step-divergences.json: four one-face sheets counted as free faces, three BRepGProp measures, the rational cylinder's among them: the kernel refused that body until U10 (b) and now imports it, its enclosures containing the reference and so missing OCCT's default measures) and 0 failures; a kernel body its validator refuses needs a review fingerprinted by its issue kinds (rust_invalid:), while an unsupported one or one outside the reference fails. The step fuzz target mutates all 29 fixtures (and requires every unmutated one to import valid since U10 (b)) with STEP-b's entity names among its tokens; its .brep round trip skips a body written with an ellipse, which the .brep reader does not read yet. Its first 60-second smoke run found the .brep writer writing a line pcurve on a spline surface at unit speed where the pcurve is not its edge's length (fuzz/regressions/step); fixed, the four spline bodies round-trip (tests/step.rs) and a second smoke run (3,518 mutation executions after replaying 397 inputs) found nothing.

A local survey of the public dataset's 336 .stp and .step files (U1: local only, nothing recorded from their contents) found no panic: 464 bodies of 114 files import and validate; 896 are rejected, each by its first construct outside STEP-a (B-spline curves 367 with their rational form, B-spline surfaces 210 with their rational and quasi-uniform forms, periodic faces without a seam 106, extrusion and revolution surfaces 165, PCurveNotDerived 35, ellipses 11, a negative major radius and a vertex loop); 11 fail validation (void shells written the wrong way round, faces of inconsistent orientation, data beyond their uncertainty, all of which OCCT's reader repairs with ShapeFix); and 22 files are refused: 17 of schemas outside AP203, AP214 and AP242, five malformed (a duplicate entity number, two dangling references, a corrupted record, an apostrophe not doubled inside a string, which OCCT's lexer accepts when no , or ) follows it).

With STEP-b the same survey (U1: counts only; the base reproduces the numbers above) finds no panic: 550 bodies of 131 files import and validate; 760 are rejected by their first construct outside STEP-a and STEP-b (PCurveNotDerived 458: B-spline and elliptic edges on cylinders, cones, spheres and tori that no rule derives, and spline-surface edges without the face's pcurve; periodic faces without a seam 106; extrusion surfaces 104; revolution surfaces 62; quasi-uniform surfaces 15 and curves 10; non-ring tori 3; the vertex loop and the negative major radius); 61 fail validation, STEP-a's 11 and 50 new: 21 through R4's C1 rule (rational quarter-arc forms: edge_not_c1, pcurve_not_c1, face_not_c1), 21 with a file's pcurve off its edge (not its edge's parameter, which OCCT's SameParameter repairs), 7 with loops winding the wrong way and one degenerate curve; the 22 refused files are unchanged. The survey's first run named 11 bodies EdgeRangeInverted: an edge ending at a closed spline's joint was located at the start; the end vertex now takes the far end (step::spline's unit test).

With U10 (b) (R4 tests C1 of the rational curve) the same survey (U1: counts only; the base at b48e9acf reproduces the numbers above but one file, bm2_ec_t4-A, past 600 seconds on a loaded host both times) finds 551 bodies importing and 60 failing validation: of the 21 R4 refused, one (a sheet of trj4_k1_top-tu-214, its rational cubic edge and pcurve C1 as rational curves at a knot of multiplicity 3) now imports. The 21 were not quarter-arc circles, as the paragraph above had them: 18 are nonrational splines whose knots of multiplicity equal to the degree are corners or speed jumps, which no C1 test passes: eleven bodies of degree-8 surfaces (their one-sided tangents 5.95e-5 rad apart), five of cubic and degree-9 curves (at worst 7.4e-10 to 1.1e-6 rad), one of cubic curves up to 4.6e-4 rad and one quintic-by-cubic surface whose speeds jump by a factor 1.88 along one tangent; the other two of trj4_k1_top-tu-214 are rational cubics whose one-sided derivatives at the knot are parallel with speeds a few ulps apart, G1 only and refused (U3). Every other row is as before.

Cross-platform allowances

Every capture compared across hosts is listed here, with its bound and why it needs one. A new allowance is added to this table in the change that introduces it. Structure, counts, verdicts and issue lists are always exact; only numbers carry an allowance.

Capture Compared Allowance Reason
occt-enclosure-preimplementation/native.txt (compare_brep.py) OCCT's measured deviations and vertex gaps on each run 2^-46 × the case's largest coordinate or radius, or 1e-9 relative; stored tolerances exact OCCT evaluates with the platform's libm; the first Linux run differed from the macOS capture by up to 1.4e-15 in 36 rounding-level measurements, all on rotated cases
occt-brep-io-capture/native.txt (compare_brep_io.py) OCCT's volume, area and centroid of the upstream corpus on each run 1e-11 relative (centroids to the cube root of the volume); verdicts and counts exact BRepGProp integrates with platform trigonometry; the worst difference observed is 9.5e-15 on Linux against the macOS capture
occt-primitive-preimplementation/native.txt (compare_primitives.py) OCCT's counts, properties, faces, edges and vertices of the 22 cones on each run the bridge's own 1e-9 of the case's size (squared or cubed for areas and volumes, size^5 for inertia); verdicts and counts exact BRepGProp and the subshape points use platform trigonometry
occt-revolve-history-capture/native.txt (compare_revolve_history.py) every number of each case's native block on each run 2^-40 × the case's size or the value; every word otherwise exact the signatures use platform trigonometry (circle points, face centres)
occt-sphere-preimplementation/native.txt (compare_primitives.py --family sphere) OCCT's counts, properties, faces, edges and vertices of the 22 spheres on each run the bridge's own 1e-9 of the case's size, as for the cones as for the cones
occt-sphere-revolve-capture/native.txt (compare_revolve_history.py --family sphere) every number of each case's native block on each run 2^-40 × the case's size or the value as for the cones
occt-torus-preimplementation/native.txt (compare_primitives.py --family torus) OCCT's counts, properties, faces, edges and vertices of the 22 tori on each run the bridge's own 1e-9 of the case's size, as for the cones as for the cones
occt-torus-revolve-capture/native.txt (compare_revolve_history.py --family torus) every number of each case's native block on each run 2^-40 × the case's size or the value as for the cones
occt-spline-preimplementation/native.txt (compare_brep.py --family spline) OCCT's statuses, counts, tolerances, vertex gaps and use deviations of the ten spline models on each run tolerances, statuses and counts exact; measurements within 2^-46 of the case's size or 1e-9 relative, as for M5 OCCT evaluates splines and trigonometry with platform arithmetic; every valid model's measurement is rounding, at most 9.2e-16
occt-split-preimplementation (compare_split.py) the native pieces' volumes, areas and centres per side against the reference 2e-8 relative BRepGProp's error on pieces with elliptic faces reached 8.8e-9 in the capture (disc_through_caps); planar pieces agree to 1e-15
occt-boolean-preimplementation (compare_boolean.py) the native results' solid counts and their volumes', areas' and centres' totals against the reference 2e-8 relative (centres: of the case's size); counts and validity exact split's allowance for BRepGProp on curved faces; the capture's worst was 6.1e-15 (lens_common)
occt-boolean-curved-preimplementation (compare_curved_boolean.py) the same, on S9c.1's arcs in any position as S9a's: 2e-8 relative; counts and validity exact BRepGProp on faces bounded by ellipses and cylinders' plane sections reached 8.6e-9 (across_hole_common)
occt-tessellation-preimplementation/native.txt (compare_tessellation.py) OCCT's weld gap, own deflections, measured distances, area and volume of the 56 meshes on each run 1e-9 relative or 1e-15 absolute; statuses and every count exact BRepMesh and the probe's projections evaluate with platform trigonometry
occt-spline-tessellation-preimplementation/native.txt (compare_tessellation.py --family spline) OCCT's rows of the twelve spline bodies' 24 meshes on each run 1e-9 relative or 1e-15 absolute per measurement, as for T-a's; statuses and counts exact; another platform reproduces its own reviewed record (platform-<name>/); the kernel's .brep texts, its inputs, are the capture's exactly BRepMesh evaluates splines with platform arithmetic
occt-procedural-*-preimplementation, occt-torus-curve-preimplementation, occt-torus-pair-preimplementation, occt-ruled-curve-preimplementation (compare_procedural_intersections.py, compare_torus_curves.py, compare_ruled_curves.py) the native lines' counts, points and samples on each run 1e-9 relative per number on the capture's platform; another platform reproduces its own reviewed record (platform-<name>/) exactly in counts IntPatch walks and approximates lines with platform arithmetic; near degeneracies its pieces differ
occt-step-preimplementation/native.txt (compare_step.py) OCCT's bodies of the 22 STEP fixtures on each run 1e-9 relative per volume, area and centre coordinate; statuses, classes, counts and verdicts exact; no platform record STEPControl_Reader and BRepGProp evaluate with platform trigonometry; the macOS capture agrees with the closed forms within 7.6e-15
occt-step-b-preimplementation/native.txt (compare_step.py) OCCT's bodies of STEP-b's seven fixtures on each run as for STEP-a's: 1e-9 relative per measure; statuses, classes, counts and verdicts exact; no platform record the same evaluation of splines and ellipses; BRepGProp's fixed-order integration errs by up to 2.0e-3 against the reference (reviewed), but repeats its own arithmetic

Two captures' inputs were written with macOS's libm, before the generators (and, with R13, the kernel) rounded their trigonometry correctly. Their inputs are now the same on every host, so these bounds are the captures' history, not a platform's:

Capture Compared Allowance Reason
occt-brep-preimplementation/inputs.txt (compare_brep.py) regenerated native inputs against the captured ones 2^-50 absolute per number the capture used macOS libm trigonometry; generation uses correctly rounded trigonometry, which moved a few frame and vertex components of two regular polygons by at most 1.2e-16
occt-tessellation-preimplementation/inputs.txt (compare_tessellation.py) the kernel's regenerated .brep texts and settings against the captured ones 2^-50 per number relative to its size (at least 1); every other token exact the capture's texts were written with macOS's libm; the kernel's correctly rounded frames and rotated points differ from them in 77 of 17,662 tokens, by at most 4.4e-16 relative, and are the same on every host (the spline family's texts are the capture's exactly)

Kernel constructions carry no allowance (R13 and R14 of the review of 18 October 2026): every binary64 the kernel constructs through a transcendental function or hypot is correctly rounded (cr.rs), so its fixtures are the same bits on every host. correctly-rounded.tsv, construction-bits.tsv, prism-properties.tsv and every other kernel fixture are compared bitwise on macOS, Linux and Windows; the allowances above are for native OCCT observations and for captures written before R13.

Native bridges that compare against reviewed differences use no numeric allowance. A review fingerprints the exact native output, so a platform whose output differs in the last bits gets its own review with a platform note (for example occt-split-merge-divergences.json), never a looser bound.