Upstream keeps one cache per surface object and builds its tree lazily: a
cache made during a Boolean operation has no tree, and its continuity arrays
stay empty until a GetTree. GetDomainWithContinuity and LiftCurve read those
arrays without GetTree, so their answer depends on that history (gen0266:
the face caches were made while reading the .smb file).
Surface now carries a cache slot (no cache / cache without tree / cache with
tree) shared by its evaluation copies; the trimmed cache makers honour and
record it, BuildTreeBase marks it built, ComputeUVPoint records the cache its
global fallback makes, and the continuity readers take their cache from
continuity_surface_cache. GetTree users build a missing tree (solve caches,
offset solve contexts, the tracer constructor).
Difftest: the offset_geometry_creation export carries each face surface's
cache state and the runner seeds it; the upstream:cache-history deferral and
OP_LIFT_OFF_DOMAIN are removed (all 4 cases pass). surface.surface_p1 DomCont
gains a cache history and 96 domhist cases (15 fail without the model).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Restore supported concrete face kinds from native input records, preserve owners and NURBS, and validate complete record framing. Add real cylinder/torus fixtures and signed/zero offset cases. Keep the documented revolution self-intersection hang guard separate from importer limitations.
Native baseline: 631/874 passed; follow-up: 713/898 passed, 185 deferred, zero failed. All 631 former passes remain passing; 58 old deferrals and 24 new cases compare successfully at the unchanged tolerance. Six targeted import/guard/parser tests pass.
Co-Authored-By: GPT-6.1 Sol Fast <noreply@openai.com>
Review follow-up on the 6 pass->defer LiftCurve cases (#149 at da779c51).
The shared importer brings every SmBSplineSurface subclass in as its B-spline
part, so sm_ExtractIsoCurve ran the B-spline CreateIsoParametricCurve on the
Rust side while the C++ ran the subclass override (gen0683: circle 14021 vs
B-spline 14033).
- shim: Export appends, per B-rep and face, the binary WriteToDB record
(version 33) of a surface that is exactly an SmSurfOfRevolution.
- ffi: split_revolutions parses those records.
- runner: read_revolutions replaces such a face's surface by
SurfOfRevolution::read_from_db of the record (owner kept) and marks it
exact; put_curve exports every SmBSplineCurve kind (type + NURB) as the
fixture's put_curve does; the non-local FaceuseOffset HANG-26 stop is keyed
on the face's subclass type, as the shim's, not on exactness.
offset.offset_geometry_creation: 861 cases, 552 pass (was 542), 0 fail, 309
deferred. 10 harness:analytic-geometry-export deferrals pass: the revolution
lifts gen0009, gen0148, gen0520, gen0683 and gen0070, gen0178, gen0187,
gen0597, gen0698, gen0767. 9 relabel to intersect.surface_drop_curve.
gen0119 / gen0707 (SmSurfOfExtrusion) and gen0376 (SmSphere) stay deferred:
the Rust SurfaceKind has no extrusion or sphere variant. No other case changed.
fmt, clippy x2 clean; solidcore-ffi tests 95 ok.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xbnf2bFY8cTu4zUgAv9s85
- VertexOffset walks no loops (IsLaminaVertex is GetEdges + IsLamina): the shim
and runner drop the all-loop-edge-use guard for it and keep its per-edge checks,
so wire / network vertices are compared (8 generated cases now compare its
result; 4 new built-in cases on the wire network and a single wire).
- HaveTangentGaps accepts n = 0 (upstream evaluates once at 0/0); new case
cone_have_tangent_gaps_no_samples.
- OffsetBrep / OffsetExecutive docs: the per-method contract a library-side
adapter must keep (the difftest runner's choices).
- Module header: the stale sSolutions2[0] read is in ExtendTrimEdges (cpp:1610)
and defined upstream; unreachable, refused by the port.
866 cases: 433 pass (430 compared + 3 guard agreements), 0 fail, 433 deferred;
perturb 433/433; FUZZ-PASS 2000; seeds 4066/2119/0/1947; green 208, failed=0;
valgrind clean on the 13 changed cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBgcxze64BBVRNjGewaEuN
- GetCreateExtendedSurface: OffsetExecutive<O> gains get_create_extended_surface
(&mut executive); the runner's Exec wraps #175's OffsetExecutive (handles folded
into its typed ids) and seeds its extension cache with each face/store surface
mapped to itself before every op, as the shim seeds m_vSurfExtSurf.
OffsetExecutive::insert_extended_surface added for that seeding (noted in
offset.offset_executive_p1's notes).
- NormalizedEvaluate / CreateUVTrimCurve: OffsetBrep methods over
topology::edgeuse::p3 (exact upstream arguments at every call site).
- #117's &mut Brep / kernel signatures: the seam, tangent-sector and
convex-sector OffsetBrep methods and have_tangent_gaps take the B-rep mutably.
- HANG-17 now refers to main's HANG-16.
Counts and notes follow once the remaining flips are settled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBgcxze64BBVRNjGewaEuN
- CreateOffsetSurface dispatches through Surface::create_offset_surface.
- SetAllowExtension(FALSE) on the analytic offset copies.
- The offset-surface rail builds the SmOffsetSurface and defers at
SmCrvOnSurf (UNPORTED(curve.crv_on_surf), main's label).
- Hang guards renamed HANG-21/22 -> HANG-26/27 (main's #62 took 21/22);
the HANG-27 bound is chosen for the fuzz time budget, not the
termination boundary (~1e250).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBgcxze64BBVRNjGewaEuN
- Code behind stubs ported as upstream runs it: HaveTangentGaps' and
TrimExtendedEdge's unchecked Evaluate/EvaluateNormal/NormalizedEvaluate/
ClosestPoint statuses, ExtendTrimEdges' pOtherUVCurve (passed on and trimmed
in place without an other extended surface), the mate read inside the &&.
- Every stub carries all upstream arguments (literals, header defaults, the
kernel and the B-rep / executive it is called on).
- Shim status -6 stops a script where the Rust defers anyway: non-local
FaceuseOffset on a face imported as its B-spline part (HANG-21, offset
self-intersection of an SmSurfOfRevolution), EdgeuseOffset with
|dist| > 1e6 (HANG-22, bound for the fuzz time budget); runner mirrors.
- Runner surface encoder refuses empty knot vectors (fuzz panic).
- rustfmt on the include!-ed runner/FFI/importer files (lesson 25).
861/327/0/534 unchanged, SENSITIVE 327/327.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBgcxze64BBVRNjGewaEuN
M1: FaceuseOffset dispatches CreateOffsetSurface on the surface kind (plane,
surface of revolution, B-spline overrides, else the base) and passes
m_dThisApproxTol3d/10; plane faces are offset instead of deferring.
M2: the SM_CAST_PTR(SmBSplineCurve, ..) edge curves keep their kind, so IsArc,
IsLine, IsClosed, CalculateBoundingBox, Trim, Copy and DropPoint take the
kind's override; only new SmBSplineCurve(*p) and the static B-spline routines
see the NURB part. create_sphere_from_arcs takes &[Curve].
M3: CreateSphereFromArcs' Unported propagates.
M4: one shared trim interval per Trim sequence (knot snaps reach the next trim).
M5: the hang guards are gone; the shim seeds m_vSurfExtSurf before every op so
CreateExtendedSurface never runs in the C++ while the Rust defers at the same
call. HANG-19 withdrawn in favour of PR #175's HANG-16; HANG-17 moved to Hang.
M6: the rail evaluations use bNonZeroTangents = FALSE.
M7: temporaries the solver compares (the extended UV curve, the torus arc) go
to the store so their solutions name an object; --seeds 4000 is clean.
S1: UNDEFINED_UPSTREAM marks the module's own null dereferences; ignore_soft
swallows everything else; the runner reports it as -2, never as 1007.
S2-S3: short-circuit IsArc; null extensions are undefined; ExtendTrimEdges takes
an Option offset edge use; the local creation reads the face surface only
under m_bMakeAnalytics.
S4: nurbs.b_spline_surface_p2 fixture three_arcs_about_two_centres (WR-103,
worded as reproduced). S5: the trait loses tangency_tol_degrees, offset_edgeuse
is "exactly one", pairs are many-to-many, VertexOffset -> VertexOffsetGeometry
(#175 reconciliation in COORD.md). S6: surface outputs carry their NURB.
861 cases, 327 pass, 0 fail, 534 deferred, 0 both-errored; SENSITIVE 327/327;
--seeds 4000: 4061/1599/0/2462; b_spline_surface_p2 764/759/0/5; green-par 198.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBgcxze64BBVRNjGewaEuN
Hang guards: HANG-19 (negative offset distance makes CreateExtendedSurface's
doubling loop unbounded) as an exact dist < 0 term beside the measured closed-face
proxy for HANG-17. Local pairs name store surfaces only (a face's own surface
was deleted by the analytic copy and double-freed: three segfaults), resolved
at each local op. Output rule on both sides: out-parameters after a success
status only, existing-topology states after every status. A library
InvalidInput maps to upstream's 1007. UV trim curves of every B-spline kind
(SM_CAST_PTR), the ruled-plane fallback for any non-deferral failure, the
original arc kept across the plane tests of VertexOffset, and WR-103 in
nurbs.b_spline_surface_p2 (rOrigin aliases sRefFrame). MAX_INDEX 4096.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBgcxze64BBVRNjGewaEuN