Downloads
SolidOut 0.2.0 — the desktop app (same UI on both platforms, engine 1.4.1 built in; no separate install)
| Platform | File | Notes |
|---|---|---|
| macOS (Apple silicon) | SolidOut-macOS-AppleSilicon.dmg | Developer ID signed, notarized and stapled. Conversions need macOS 26 or newer (the bundled OCCT libraries). |
| Windows 10/11 (x64) | SolidOut-Windows-x64-setup.exe (recommended) · SolidOut-Windows-x64.msi | Unsigned (no Authenticode): SmartScreen will ask once on first run. |
| Checksums | SHA256SUMS.txt | All app files. |
New in SolidOut 0.2.0: the engine updates itself. The Engine card in the right panel shows the engine in use and an Update engine button. On launch and on the button the app checks this repository's latest release; when a newer engine exists the line under the button turns amber and one press downloads, verifies (SHA-256 from the manifest; Developer ID Team ID on macOS) and installs it into the app's data folder. Nothing in the app bundle is modified, so signatures stay intact, and the next conversion uses the new engine without a restart.
Engine bundles — what the updater installs (you do not need these to use SolidOut)
| Platform | File | Notes |
|---|---|---|
| macOS (Apple silicon) | stl2step-engine-v1.4.1-macos-arm64.tar.gz | stl2step + Frameworks/ (28 OCCT dylibs), Developer ID signed and notarized, macOS 26+. |
| Windows 10/11 (x64) | stl2step-engine-v1.4.1-windows-x64.zip | stl2step.exe + 33 DLLs beside it, unsigned. |
| Manifest | engine-manifest.json · SHA256SUMS-engine.txt | Schema 1: engineVersion, per-platform name, sha256, size, minOS/minWindows, teamId. A release without a manifest is not an engine candidate. |
SolidOut is closed source; its binaries ship here as release assets. The engine it drives is this repository.
stl2step CLI 1.4.1 — build from source on macOS, Linux or Windows per the README; the CLI is what SolidOut bundles. 1.4.1 is 1.4.0 plus the version-string fix (the 1.4.0 binary reported stl2step 1.3.0) and the engine bundles above; there is no other engine change.
What 1.4 converts that 1.3 did not (measured on the training parts shipped in tests/corpus): shelf_bracket and Body244 no longer revert to facets (32 planes / 20 cylinders and 364 / 178, one valid closed solid each); plane-meets-cylinder ellipses bind as ELLIPSE edges (55 unhandled edges on the training set down to 1); the torus stage builds a certified torus face on the S04 fixture; the RESULT census counts exactly what ships. The same-surface union engine and mouth-round tori on the real parts are recorded for 1.5.
Engine changelog (1.4.1)
Fixed
- Version string fix: the v1.4.0 binary reported
stl2step 1.3.0becauseproject(stl2step VERSION …)inCMakeLists.txtandSTL2STEP_VERSION_*in the public header were never bumped for the 1.4.0 release.
Added
- Per-platform engine bundles (
stl2step-engine-<tag>-macos-arm64.tar.gz,windows-x64.zip) andengine-manifest.jsonfor the SolidOut in-app updater (published with the release).
Engine changelog (1.4.0)
Added
- Torus engine — stage T transactional reclaim + U-3 face sharing the cylinder rim (D-140-6, D-140-11). Stage T admits torus candidates, but cylinder reclaim commits only when the U-3
Geom_ToroidalSurfaceface ships; a failed U-3 build restores the pre-stage-T topology and rebuilds with fresh vertices (Body28/Body11 byte-identical to the no-torus binary). The toroidal face shares the cylinder rim via explicit pcurves (Geom2d_Line((u0−f, v), (1,0))on the reused rim TShape, both seam pcurves atu0/u0+2π, and the c-rev wire). S04's boss-top round ships as a valid closed solid (TOROIDAL_SURFACE,solids=1,faceCount=9, I-checker PASS). S19 mouth rounds, the plate mouth band, and Handle pickup admit 0 tori — the certificate is honest on the real parts (smoothBuiltTori=0, expected-redS19.mouth-round-not-built). The torus closed-360 gate usesbandArc + asin(min(1, τ/hmin))(θ_q) instead of the retired1.5·bandArchand constant; U-3 probe warnings are discarded on topology revert. - Torus math — the
circle-on-torusclass (src/refit_torus_math.{hpp,cpp},torus_math_unit; D-140-6 §3(4), the D-130-3 hard gate applied verbatim; D-130-2).circleOnTorusMaxreturns, in closed form, the supremum distance from a circle COAXIAL with a ring torus to the untrimmed toroidal surface: every point of such a circle has the same(rho, z) = (r_c, h), so the distance is the constant|hypot(r_c − Rmaj, h) − Rmin|and that constant is the supremum — exactly0on every v-iso circle, in particular on the two tangency circles a mouth round is bounded by (S04:rho = 10 @ z = 22andrho = 7 @ z = 25; S19: both rims of both tori). A non-coaxial circle, a spindle or horn torus (Rmaj − Rmin <= gp::Resolution(), OCCT's own guard) and a degenerate tube are refused with-1.0/unhandled-circle-on-torus— tier 2, counted, never a widened tolerance. WithpointTorusDist,torusVIsoCircle(the tier-1 bounds a blend patch carries) andtorusVOfProfilePoint. Own translation unit for the reason the cone math has one (0d67eba): the P1 include allowlist is neither touched nor widened. No build path is edited;exactMaxAtBindstill returnsunhandled-surfacefor a torus until the build lane binds through this class. - The same-surface union census is readable with the door closed (D-140-8 U-R13; SPEC-union PART B). Under
STL2STEP_LAWBAND_DIAGtheDIAG_LAWUNIONline no longer reports theSTL2STEP_UNIONdoor's behaviour: it takes a copy of every law band's claim, applies D-140-8 U-R1…U-R4 to the copy (the D-130-13(2) same-surface islands undermax(bandResid, q), the joint-refit roll-back, the axial-extent overlap, the mutual-containment merge, in band order) and prints, per certified surface,nTri sigma punctures edgePieces domainFaces pinchVertices sizes=[..] pieces=[..] domainTris loc dir.sigmais U-R5's closed-form supremummax over the claim's welded edges of (R − dist(axis, midpoint)), punctures are U-R6's non-claim vertices withinsigmaof the surface,domainFacescounts U-R7's components of the claim plus the on-surface stars of its punctures,pinchVerticescounts U-R8's vertices whose link inside a component is two or more fans. The copy is never written back:claimTris, the band fits and every emitted Region are untouched, so the shipped STEP is byte-identical with the diag on or off and with the door open or closed (the plate:R=10.000000 nTri=255 sigma=0.019733720 punctures=8 edgePieces=6 domainFaces=1 pinchVertices=0 domainTris=279; Handle pickup:R=3.999998 nTri=52 punctures=20 edgePieces=11 domainFaces=1 pinchVertices=0 domainTris=84). New TUsrc/refit_union_census.cpp(claimChordSagitta,unionCensus, declared inrefit_internal.hpp; pureMeshViewmeasurement, no Region, no build path) and unit targetunion_census_unit:sigmaagainst the regular-ring closed form and a numerical supremum along every welded edge at three radii × three densities, world and placed frames, toPrecision::Confusion(), plus the U-R6/U-R7/U-R8 counts on hand-built interrupted rings. - Ellipse math — the two closed forms behind the ELLIPSE bind class (
src/refit_ellipse_math.{hpp,cpp},ellipse_math_unit; D-140-9 §2, D-130-2, D-S3-111; the third instance of the 130-CONE-MATH / torus-math shape). Measured first (SPEC-ellipse PART 0): all 55unhandlededges on the 9-fixture edge-class red line are plane∩cylinder ellipses whose plane-side pcurve is the exact 2-DELLIPSEGeomAPI::To2dwrites and whose cylinder-side pcurve is one degree-8 Bézier with affineuand a sinusoid-approximatingv.ellipseOnPlaneMaxis the EXACT supremum of|E(t) − S(pc(t))| = |W + A cos t + B sin t|over[f, l]: thetan(t/2)quartic's real roots (Ferrari, threshold-free shift, fixed Newton polish) plus the endpoints;W = 0collapses toσ_max([A B])(ellipseTrigSupZeroOffset), the shipped case to exactly0.0, and fora = bit is≤ circleOnPlaneMax(the D-S3-111 triangle bound) — the sanity relation between the two classes.ellipseOnCylMaxis a certified UPPER BOUND and says so in its name: the section identity (ellipseIsCylinderSection:ρ ≡ R,θ = θ₀ ± t,z = z₀ + Λ cos(t − ψ), residual carried exactly),ε_uexact from the poles by the Bernstein hull, the axial residual per knot span by Chebyshev interpolation (L_n max_j |v(x_j) − z(x_j)| + Λ H^{n+1}/(2^{2n+1}(n+1)!), the refused midpoint-Taylor form is 2⁸ = 256× looser), composed through the exact two-point identity on a cylinder. The grazing predicate (D-S3-111's open predicate):ellipseCylGrazingSin = |N̂·d̂| = cos α = b/aandellipseVertexBound = √(s² + h²) + s²/(2ρ_min)with|h| ≤ δ_pl,|s| ≤ (δ_cy + δ_pl|cos γ|)/sin γ; the class refuses (unhandled-ellipse-grazing) where that exceedsmeshTolCap— never a hand angle. Every refusal is named (unhandled-ellipse-plane-{param,degenerate},unhandled-ellipse-cyl-{oncyl,uaffine,span,degenerate}). No build path is edited;exactMaxAtBindstill returnsunhandled-otherfor an ellipse until the bind lane binds through these classes (SPEC-ellipse PART B), soedgeUnhandledis unchanged by construction and B0 holds trivially. - The ELLIPSE bind class —
ellipse-on-plane(EXACT) andellipse-on-cylinder/ellipse-on-cylinder-bound(a certified upper bound) insrc/refit_ellipse_bind.{hpp,cpp}on top ofsrc/refit_ellipse_math.{hpp,cpp}, reached by two branches inexactMaxAtBind(D-140-9 §1/§3).unhandledon the 9-fixture edge-class red line was 55, and every one of the 55 was an ellipse — an oblique plane∩cylinder cut shipping as tier-1Geom_Ellipsewith no closed-form supremum. The plane side is exact: both curves are evaluated at the samet, soE(t) − S(pc(t)) = W + A cos t + B sin tidentically, and the supremum is the maximum of|·|over the real roots of the quartic inτ = tan(t/2)plus the two endpoints. The cylinder side is a bound, and says so in its name: under the section identity (centre on axis,a|Û⊥| = b|V̂⊥| = R,Û⊥·V̂⊥ = 0) the azimuth is affine — so|Δθ| ≤ ε_uexactly, from the poles, by the convex hull at the Greville abscissae — while the axial coordinate isz₀ + Λ cos(t−ψ), and no NURBS reproducescos tint, so the axial residual is bounded per span byL_n·max_j |v_pc(x_j) − z(x_j)| + Λ h^{n+1}/(2^{2n+1}(n+1)!)at then+1Chebyshev nodes, over an exact de Casteljau subdivision (every depth is a valid bound, so the minimum over a fixed depth set is taken). The two compose on the cylinder as√(4R² sin²(ε_u/2) + max|Δz|²). Refusal is by named clause, never by silence:unhandled-ellipse-{plane-param,plane-degenerate,cyl-oncyl,cyl-uaffine,cyl-span,cyl-degenerate,grazing}; the range clause carries D-130-16's seam sub-clause, so a full-turn ellipse edge is refused rather than certified. Measured:unhandled55 → 1 (Body28 25→0, S11-b 24→0, linkage_bores_chamfer 4→0, handle-pickup 1→0; S16-R1-explode-success stays 1 under the seam clause, residueellipse.s16-post-bind-tolerance), withoverTol,overCapandpolylineTier2unchanged on every fixture and every corpus STEP byte-identical. No tolerance writer, no pcurve writer and no instrument was touched. - J6/free-edge containment, landed then fully sunset (D-140-4, D-140-5, D-140-12; SPEC-reverts-cycle2 §2). Cycle 2 landed three edits; none of them ships. Change 3 (the J6
if (j6UncollapsePass > 0)handoff plussmoothContainedRegions/smoothContainedTriangles) was reverted by D-140-5's sunset. Changes 1–2 —regionClosureHealEligibledroppingbuiltAs == BuiltAs::Singlein favour ofregionBuiltAnalytic(...), andfallbackGuardPass == 0widened to<= 2— were kept as "dormant" by D-140-5, then reverted by D-140-12: on Linux they were live, not dormant, and letS16-R2-ChainUnstablecomplete the analytic path (spike-s16r2-linux: first build at78f85b4). Restored to the3bf0575form: eligibility requiresbuiltAs == Single; the heal stays behindfallbackGuardPass == 0. - Two RESULT keys,
smoothContainedRegionsandsmoothContainedTriangles(D-130-10 declaration;RefitStats::containedRegions/containedTriangles, summed inConverter::run). Incremented at exactly one place — the J6-handoff demotion, after the admitted set shrank. Never on the seamed360-fail explode path, never on the D-S3-54 closure heal (which already fires at3bf0575and keeps reporting itself throughDIAG_HEAL/DIAG_HEAL_SUM). The warningsmooth: contained N region(s) to facets -- component builtis emitted only whenN > 0.DIAG_CONTAINis emitted only from the J6 handoff, underdiagP2Enabled(), with a realfreeBefore > 0.
The site never shipped live containment on any artefact this project owned (keys0/0,DIAG_CONTAINcount0). Sunset (D-140-4 §1(5)) fired in D-140-5 for the J6 handoff. D-140-12 then reverted changes 1–2 as well: they were not dormant on Linux — they let S16-R2-ChainUnstable build (planes/cylinders/tier2) where macOS and3bf0575Linux still revert. Eligibility and reachability do not stay. S20_cross_bore_union, the same-surface union fixture, with its own negative control (D-140-8 U-R15/U-R16). An 80×60×40 block with a mid-span slot, one Ø20 bore on +X across both walls — so it ships as two coaxial faces at disjoint axial spans, [0,30] and [50,80] — and a Ø12 cross bore on +Z at x = 15 piercing the wall-A span atu = 90°andu = 270°, strictly inside it. Both bores are 48-gon prisms, and that is the mechanism: the two prisms' intersection polyline alternates between bore-edge × cross-facet vertices (exactly on R = 10) and cross-edge × bore-facet vertices, which lie on a chord of the bore and are therefore punctures in D-140-8 U-R6's sense — the plate's eight slot-window corners, reproduced by construction.gen_corpusasserts the topology on its own welded float32 mesh before any engine run and prints theS20-UNIONcensus: union boresigma=0.0214118609mm= 3240.66178 q,edgePieces=38,punctures=92,domainFaces=1,innerWires=2,windingPerWire=[0,0],pinchVertices=40; control boredomainFaces=1,innerWires=0;axialOverlap=0. The predicate is never relaxed — a deflection-halving retry loop runs up to 8 times and the lane throws if it exhausts.exactVolumeis a closed form on the generator's own parameters (inclusion–exclusion over slot ∪ bore ∪ cross bore; the two prisms' intersection integrand is piecewise quadratic, so Simpson on the breakpoint intervals is exact, not a quadrature) and is asserted againstBRepGProp::VolumePropertieson the exact solid:closedForm=142038.9690342799 BRepGProp=142038.96903428048. The PRG multiset ceiling for R = 10 on this fixture is therefore exactly 2: over-segmentation fails (D-130-14) and over-merging fails (U-R3).src/is untouched — the union itself is expected-red asS20.union-not-built.- Two real-export corpus fixtures,
shelf_bracket(2340 tris; 32 planes + 20 cylinders + 735 facet faces in one valid closed solid,volumeDeltaPct = 0.000142) andBody244(6268 tris;builtPlanes/builtCylinders364/178 (D-140-3 record),volumeDeltaPct = 0.000099,rid=1explodes to 148 facets under expected-redBody244.cyl360.rid1). shelf_bracket is the analytic-plus-facet-island proof on real geometry thatS17_hole_vs_islandwas to assert synthetically; S17 is withdrawn this cycle under expected-redS17.cap-claimed-by-a2(D-140-4 §4). stl2step_grade, the mesh-oracle recovery grader (tests/grade/, targetsstl2step_grade+stl2step_grade_selftest; D-140-1). Independent ofstl2step::core(grafts onlystl_quant); oracle classes plane / cylinder / cone / sphere / torus from the mesh atτ = 2q; seven training grades + ctest selftests. Cycle 6 torus/cone oracles certify on the training parts (D-140-1, D-140-6). Selftest core 68/68, synthetic 25/25.- Torus fixtures — S04 recoverable +
S19_mouth_round(D-140-6 §4, SPEC-torus PART A). S04'smustRemainFacetedTorusNYI is cleared and recoverable gainstorusRec(7.0, 3.0, {25,25,22}, +Z, 1, true)(STL bytes unchanged);S19_mouth_roundis a 60×60×20 box, R=10 through hole, mouth rounds r=2 top / r=1 bottom. Generator-exact sidecars and*.exact.step; S04 now builds a toroidal face; expected-redS19.mouth-round-not-builtstays;gates_fullI-checker XFAIL on S19 registered (D-140-6 §4(e)). Fixtures only on the fixture commit; build landed on this branch. - Volume-attribution identity, default-off (
STL2STEP_VOLID; D-140-10). Diag-only instrument besidedumpR2Probe: pcurve and contour readings ofv(F)=(1/3)[kA+p·N], the §2.5closesbracket, and the S01/S02/S03 unit (volid_identity17/17).faceVolumeContributionand the caller probe are untouched; no product read ofcloses. Knob unset/0is a no-op (OFF≡ON for STEP bytes). Measuredcloses8/9 (platevolid.cone-bracket).
Removed
- The J6 handoff containment round and its two RESULT keys (D-140-5): D-140-4 §1(5)'s sunset fired — 1 529 generated candidates found no constructible
S18_uncontainable_rim(clause A, an orphaned collapsed chain within the site's 1.0 mmmatchTol, fires 0 times post-heal) — sorefit_build.cpp:15877-15925reverts to its3bf0575form, dropping the containment round,smoothContainedRegions/smoothContainedTriangles,resetContained(), and thesmooth: contained ...warning. - J6 eligibility and heal reachability restored to
3bf0575(D-140-12, completing D-140-5): D-140-5 had left change 1 (regionClosureHealEligible→regionBuiltAnalytic) and change 2 (fallbackGuardPass <= 2) in place as widenings of a "live" heal. On Linux those two lines were the first-build at78f85b4for S16-R2-ChainUnstable (spike-s16r2-linux:smoothRevertedComponents1→0,polylineTier20→25,overCap0→1). Restored:builtAs == BuiltAs::SingleandfallbackGuardPass == 0. MacOS B0 is unchanged because the path was dormant there; Linux S16-R2 returns to the revert contract. - The
STL2STEP_UNIONdoor (D-140-8 U-R14): cycle 1 did not close U-R9 (plate seamed cylinder with 2 inner window wires =UnorientableShapest=27; domain-boundary extraction yields window-sized caps and fragment loops, not a face-construction miss). The door is deleted; merge/emit stay off so no partial construction lands. S20 fixture, census, and expected-red rows stay. The union engine is deferred to 1.5.
Tests (1.4.0)
- S19_mouth_round compose expectation (lane seeds-140c, D-130-24; D-140-6 §4(e)) — generator sidecar: six box planes in
recoverable[]; recoverable6/7/8 (R=10 closed360 cylinder + two coaxial mouth-round tori) declaredmustRemainFacetedwithS19.mouth-round-not-built/ TorusNYI wording; closed-form geometry kept in deferred comments. STL bytes unchanged;p1_compose_gategreen. - 1.4.0 instrument seeds (lane seeds-140, D-130-24) — Body244 / shelf_bracket live
volumeBudgetMM3fromvolumeBudgetMM3(|meshVolume|)(D-140-3 §4(b)); edge-class new cells for Body244, shelf_bracket, S19_mouth_round, S20_cross_bore_union fromedge_class_gate.py --measure; S11-b expected-red shrink; S20 live[] disposition ESCALATE (S20.union-not-builtsunset). S04 / recoverable7 torus rows left unseeded. Body28polylineTier2left at 1442 (macOS still 1442). S16-R2 B0 UNCERTAINTY exception retired (D-140-13): canonical STEP identical to3bf0575on all platforms. - Per-run scratch dirs in corpus engine check —
run_engine_check.shwrites fixture artefacts undermktemp -dinstead of fixed/tmp/${id}_*paths, so concurrent ctest batteries no longer truncate each other's RESULT JSON. - Windows
volid_identityportable launch (5ff406b; D-140-10): MSVC-hostedvolid_identityuses_putenv/_popeninstead of the POSIXsetenv/popenpath — no shell prefix — so the unit test launches on Windows CI. gates_fullctest TIMEOUT 3600→6000 (75e4e95): budget from measured wall time on the shop PC (~3870 s Windows/MSVC; macOS 883 s, Linux 1174 s); Body244 dominates on Windows (~55 min vs ~3 min macOS) — Windows I/O pathology, 1.4.1 follow-up. Harness budget only; no gate logic change.
Fixed
- J6 sunset completion — closure-heal eligibility and guard bound restored to
3bf0575(D-140-12; D-140-5; cd6e86f): D-140-5's "dormant" widenings (change 1:regionClosureHealEligible→regionBuiltAnalytic; change 2:fallbackGuardPass <= 2) were live on Linux and let S16-R2-ChainUnstable take the analytic path where macOS still reverted. RestoredbuiltAs == BuiltAs::SingleandfallbackGuardPass == 0. - A component with refused-mint composites takes the facet fallback when its shell fails (D-140-13; D-140-2):
buildWithInnersstill returns true after a failedprepare()on a mintRefused polyline-rim face — those faces can ship in a closing shell (shelf_bracket 32/20, Body244builtPlanes/builtCylinders364/178 (D-140-3 record)). When the component's shell then fails to close or validate,buildFacestakes the existing ChainUnstable → all-facet path instead of returning false, so S16-R2 ships as facets the way3bf0575did. Components without a mintRefused face keep the previous shell-failure semantics. Cap-mint refusal is unchanged. - RESULT census counts the shipped pass, not the torus probe (D-140-6, D-140-11): when stage T admits candidates, U-3 fails, and the pre-T snapshot rebuild ships,
smoothBuiltPlanes(and the other construction counters) were left on the discarded probe's RegionSet — Body11 1603→1590, Body28 499→488, Body244 364→338 — while the STEP stayed byte-identical. The pre-T snapshot now carries its ownRefitStatsand the revert restores it (same leak class as the discarded probe warnings). - A component with refused-mint composites takes the facet fallback when its shell fails (D-140-13; D-140-2):
buildWithInnersstill returns true after a failedprepare()on a mintRefused polyline-rim face — those faces can ship in a closing shell (shelf_bracket 32/20, Body244 364/178). When the component's shell then fails to close or validate,buildFacestakes the existing ChainUnstable → all-facet path instead of returning false, so S16-R2 ships as facets the way3bf0575did. Components without a mintRefused face keep the previous shell-failure semantics. Cap-mint refusal is unchanged. - Torus U-3 probe warnings discarded on topology revert (D-140-6, D-140-11): when stage T admits candidates but U-3 fails and the pre-T snapshot rebuild ships, warnings from the discarded probe build are no longer forwarded — Body244 returns to 2 warnings (IntAna + seamed360) with byte-identical STEP.
- Transactional torus cylinder reclaim (D-140-6, D-140-11): stage T still admits candidates, but a failed U-3 torus face build restores the pre-stage-T topology and rebuilds with fresh vertices so Body28/Body11 match the no-torus binary; cylinder reclaim commits only when
Geom_ToroidalSurfaceships. The torus closed-360 gate usesbandArc + asin(min(1, τ/hmin))(θ_q) instead of the retired1.5·bandArchand constant. - The OpenCASCADE toolkits the engine uses are named explicitly (github issue #1):
stl2step_corelinked only the finder's umbrella target, which omitted TKPrim (BRepPrimAPI_MakePrism) and TKBO (BRepAlgoAPI_Fuse,BOPAlgo_GlueEnum); they arrived transitively on Homebrew and on an OCCT that ships a CMake package config, and not at all under Debian/Ubuntu'sld --as-neededwhen OCCT is installed without one (undefined reference to BRepAlgoAPI_Fuse::~BRepAlgoAPI_Fuse()/libTKBO.so: DSO missing from command line). CMakeLists.txt now links the measured minimal cover of 15 toolkits, selected byif(TARGET ...)with afind_libraryfallback and the pre-7.8 TKSTL/TKSTEP* spellings as alternates. - takeFullCap may not mint against an unbuilt partner (D-140-2): a
Seamed360cap facing an island / eprimeFill / exploded / non-analytic region keeps the mesh polyline both sides already share, instead of inventing a full-2πCIRCLETShape that the fill cannot carry. shelf_bracket's eight through-holes ship as cylinders; the shell closes with noJ6:line. Body244 shipsbuiltPlanes/builtCylinders364/178 (D-140-3 record;volumeDeltaPct = 0.000099); the shell closes with noJ6:line. - Corpus checker parses sidecars linearly (MSVC hosted CI):
check_corpus.cppparsed each sidecar withstd::regexpatterns chaining[\s\S]*?across the document; MSVC throwsregex_error(error_complexity)on the plate sidecar (Exit code 0xc0000409, no stdout). Replaced with a single forward scan; matching semantics kept.
Changed
- Grader selftest expected-red, and its first row retired in the same release (D-140-7):
tests/gates/baseline/expected-red.jsongains agradersection andgrade_selftesttheXFAIL/XPASSreporting that reads it — a listed check that fails is reportedXFAILand excluded from the exit code; a listed check that passes is reportedXPASS, counted as a failure, and names the row to delete, so the list can only shrink. The section's first and only row,grade.reverse-seed.handle-pickup(case 9's cylinder-phase claim-order dependence), was registered when the grader landed and is gone again in this same 1.4.0 cycle. What closed it: the oracle's stage-A pass no longer consumes triangles or names a seed. Each class phase now answers one boolean per edge-connected component of the unclaimed set — does this component carry the class? — over a frozen ambient set, and §5.4's growth walk is then re-run over the union of the carrying components, entered at the lowest triangle index. That domain is a function of(mesh, class order)alone, so no permutation of the seed enumeration can move it; the three mechanisms that used to move it (band-offset chop, skipped-seed slack, two competing cylinders on the same quads) are each closed by it. The probe itself is untouched and still real —--reverse-seedsstill reversesseedList(), which still drives the growth for every seed, andgrade_selftest.cpp's assertions are unchanged. Selftest core 68/68 (was 67/68), synthetic 25/25, 0 XFAIL, 0 XPASS; the seven training grades are byte-identical under file order,--reverse-seedsand a third geometry-derived permutation (--seed-order n, triangle-centroid order), with no grade changed. The emptygradersection stays: the machinery is what landed, the deferral was not. - Same-surface union engine → 1.5 (D-140-8): the
STL2STEP_UNIONdoor is deleted, not compiled-in-off. 1.4.0 ships the seed piece(s) per surface (plate cross bore 214/279 in 2 faces); S20 remains expected-redS20.union-not-built.