From the llvm-cov run of `difftest --green`: 136 fixture cases
(fixtures/<unit>/coverage.json, each citing the upstream branch and the
Rust line it covers) execute about 70 previously uncovered spans in
offset_surface (zero first derivatives replaced by base tangents, a
hyperboloid base), sphere (coincident/concentric spheres, degenerate
arcs, tangency marks, cone and box rejects, pole and seam inversion),
surface_p5 (singular iso curve, CoverOtherCoincidentSurface branches,
IdenticalSolutions at a pole), surface_p4 (curve/surface crossing
classification on dome, saddle and cylinder points), surf_of_extrusion_p1
(coincident generators touching or disjoint), surface_p6 (solutions at a
pole), surface_point_solve_p2 (cross-seam solutions), torus (horn torus,
axis-start minor circle), curve_bounded_surface (== stops) and
surf_of_revolution_p1/p3 (revolutions of a real SmHyperbola).
The surf_of_revolution_p1 runner, FFI and shim gain a hyperbola
generator; the five shims sharing that generator block parse it too.
Fuzzing it showed SmHyperbola's constructor ignoring a failed MakeNurb
(NULL or non-finite NURB, then a segfault): the shims refuse such a
hyperbola, and plan/upstream-issues.md UB-46 records the trigger.
Generated cases are unchanged.
All eleven units PASS with 0 failures and 0 deferred (max_rel_err 0);
--perturb SENSITIVE on all; --fuzz 200 (p1, p3, offset): FUZZ-PASS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
125 shims carried private copies of the same small helpers (put_vec, st,
nl_status, Rd, dump_crv, read_nurb, ...). Move the most common, byte-identical
form of each into three headers grouped by the upstream API they need, and have
those shims pull them in with `using sc::<name>;`. Shims with a different
variant keep their own copy; files touched by open PRs are left alone.
`the_context()` stays per shim (its function-local SmContext must not be shared).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FBLgPenT24P1dunqnZR1Dj
Global solver (rough / polygon guesses, refinements, grids, seams, Solve) and
stepper (AdjustStep, norms, convergence, Step, line searches, boundary tests).
Solve keeps upstream's eStat reset by RefineGuessByGrid and maps a failed rough
guess to SM_ERR. The shim and runner also build real SmSurfOfRevolution surfaces
(240 rev_gen cases), validated against the domain the C++ reports.
difftest: 1320 cases, 1230 pass, 90 deferred (surface_p4 63, surface_p5 27).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BY8UpXKuMci15rAWGXsbsm