Sketch solver evaluation
This engineering decision record evaluates PlaneGCS as the industrial sketch solver behind InvariantCAD’s existing replaceable solver protocol. The implementation-grade bakeoff was completed on July 24, 2026 against@salusoft89/planegcs@1.2.0.
Decision
InvariantCAD will use an owned, maintained PlaneGCS fork and replaceable WASM runtime as the selected industrial-solver path, subject to the promotion gates. InvariantCAD will not ship, repackage, or make@salusoft89/planegcs@1.2.0 the production backend directly. The numerical
solver is a credible basis, but the published wrapper and its vendored solver
snapshot do not meet the project’s packaging, lifecycle, diagnostics,
cancellation, provenance, or distribution requirements.
The decision separates three claims:
Evaluated inputs
The current InvariantCAD sketch contract has four entity kinds—point, line, circle, and arc—and 17 constraint kinds. Its result contract also requires status, solved geometry, degrees of freedom, iteration count, residual, and structured diagnostics. The evaluated upstream package was the exact1.2.0 release
at verified commit
ee9b156da9827a91a56a888a53520f63d5cffaa6.
The npm tarball reported that same gitHead, had no runtime npm dependencies,
and passed its published npm integrity check.
The wrapper vendors FreeCAD PlaneGCS commit
5f8eac49f31626354ee69bf40616bac801ca5560,
dated April 25, 2025. Its build uses
Emscripten 3.1.45
and the published
link flags.
Adapter result
Every current constraint kind has a direct or controlled synthetic mapping:
Point, line, and circle entities map directly. An InvariantCAD arc needs hidden
start and end points plus PlaneGCS
arc_rules. It also needs two hidden equal
constraints that freeze its start and end angles. Without those constraints,
PlaneGCS introduces two degrees of freedom that do not exist in the current
InvariantCAD IR.
The production adapter must emit authored IDs in lexical order, then points,
higher geometries, hidden arc helpers, and constraints in a fixed topological
order. Synthetic numeric tags must map back to authored IDs, with hidden
implementation tags excluded from public diagnostics.
Measured evidence
All results below are finite observations from the bakeoff, not universal solver guarantees.
The determinism sample does not justify an
artifactCompatibilityFingerprint. That field claims exact numeric semantics
for every runtime represented by the fingerprint, which requires a broader
reviewed golden matrix.
Size and memory
The lifecycle loop finished with zero outstanding Emscripten value handles and
unchanged WASM memory. In one warmed run, host RSS still increased by about
18 MiB. That is neither proof of a leak nor proof of leak freedom; production
promotion needs longer bounded-memory and large-sketch evidence.
Why the npm wrapper is rejected
Solver snapshot
The wrapper release is current, but its PlaneGCS core is not. Compared with the April 2025 pin, the latest stable FreeCAD release at the evaluation cutoff,1.1.2 contains 11
later commits in the PlaneGCS path and changes 8 of its 11 files. FreeCAD main
contained 23 later path commits at the evaluation cutoff.
Those later changes include material solver work such as
small-sketch DenseQR,
concentric-circle tangent handling,
line-circle tangent orientation,
and
arc constraint orientation.
Adopting the package version alone would therefore not adopt a current solver
core.
Package and runtime boundaries
- Strict TypeScript 7
NodeNextchecking withskipLibCheck: falsefailed. The tarball omits the declaration besidedist/planegcs_dist/planegcs.js, and several emitted declarations use extensionless ESM imports. - The package has no
exportsmap. Vite worked with warnings, while upstream still tracks an open Webpack packaging issue. - The WASM module has a fixed 16 MiB memory.
ALLOW_MEMORY_GROWTHis absent, and 5 MiB is reserved for the stack. - The build remains on Emscripten 3.1.45; the upstream toolchain-upgrade issue records a blocker around the current configuration.
- The API is synchronous and cannot observe an
AbortSignalduring native solving. Hard cancellation therefore requires terminating a worker or process. - The binding exposes neither actual iteration count nor final residual. InvariantCAD can independently recompute residuals, but it must not invent an iteration count.
- Conflict and redundancy IDs are flat. PlaneGCS has richer native conflict groups, but the wrapper has an open group-export issue.
- Redundancy diagnosis emitted unsolicited native console output in the bakeoff; the wrapper has no injectable logger.
Ownership boundary
destroy_gcs_module() is not idempotent: a second call and post-disposal use
both throw an Emscripten binding error. Returned native vectors also require
explicit deletion.
Inspection of the upstream
GcsWrapper
found another future-facing ownership problem in the B-spline path: four
temporary native integer vectors passed to
make_bspline() are not deleted, and cached native B-spline geometry is
removed from the JavaScript map without deletion. Current InvariantCAD sketches
do not author B-splines, but the leak risk blocks using that path for the
comprehensive sketch milestone.
License and package boundary
This section is an engineering distribution requirement, not legal advice or legal approval. The upstreampackage.json
declares LGPL-2.0-or-later, its included
LICENSE
is LGPL 2.1, the wrapper source headers say LGPL 2.1-or-later, and the vendored
FreeCAD PlaneGCS headers say GNU Library GPL v2-or-later. An owned combined
runtime should use the safe common outbound expression
LGPL-2.1-or-later, subject to external legal review.
The intended publication boundary is:
The runtime distribution must include:
- Exact wrapper-fork and FreeCAD source commits.
- Complete corresponding native and binding source.
- Every InvariantCAD patch with notices.
- Build scripts and a toolchain container pinned by immutable digest.
- License texts, attribution, source archive, checksums, and SBOM.
- Documented runtime-byte replacement and relinking instructions.
- No terms or technical controls that prohibit permitted reverse engineering for modification and debugging.
Target integration
The owned implementation should use a worker-first boundary:- Adapter protocol and runtime package version.
- InvariantCAD fork and exact FreeCAD source commits.
- Emscripten version and build flags.
- WASM SHA-256.
- Algorithm, tolerance, convergence, and iteration-limit semantics.
- Entity/constraint mapping protocol.
- Exact runtime matrix covered by the claim.
Promotion gates
The conditional selection becomes a supported industrial backend only when all of these gates pass:- Modern solver source: pin a reviewed current FreeCAD snapshot or stable snapshot plus explicit reviewed backports, then pass the complete regression corpus.
- Owned binding: expose real iterations, residual, grouped conflicts, redundancy, controlled logging, and closed status semantics.
- Package correctness: publish strict ESM declarations and exports that pass supported TypeScript and package-lint matrices without consumer workarounds.
- Lifecycle correctness: make disposal idempotent, close all native vector and geometry ownership, and prove fresh-session recovery after failures.
- Cancellation and isolation: make worker/process execution the supported hard-cancellation boundary and test pre-start, in-flight, timeout, crash, and recovery behavior.
- Bounded scale: establish explicit entity, constraint, iteration, time, WASM-memory, and host-memory limits with representative large and degenerate sketches.
- Conformance matrix: pass all current constraints, mixed sketches, conflict/redundancy/drag cases, invalid and non-finite inputs, and the future construction/conic/spline corpus across supported Node and browser engines.
- Determinism: pass reviewed fresh-process and cross-runtime golden tests before advertising any artifact-compatibility fingerprint.
- Supply chain: reproduce exact runtime bytes from pinned inputs, verify checksums and provenance before execution, and ship an SBOM.
- Distribution approval: complete external legal, security, provenance, and release review for the LGPL runtime and its source/relink channel.
Explicit non-claims
The bakeoff does not establish:- Arbitrary-sketch correctness or numerical robustness.
- Browser support beyond the tested Chromium build.
- Compatibility across Node, operating-system, CPU, or browser matrices.
- Leak freedom, peak-memory bounds, or large-sketch capacity.
- Reliable partial-redundancy classification or conflict grouping.
- Safe use of the current B-spline wrapper.
- A valid cross-runtime artifact fingerprint.
- Public-release readiness or LGPL compliance approval.