Skip to content

Fix five field-reported bugs: dead constraint solver, zoom teleport, ASCII STL, extrude area toggle, AppImage icon - #23

Merged
MakerViking merged 6 commits into
mainfrom
fix/field-reports-aug12
Aug 12, 2026
Merged

Fix five field-reported bugs: dead constraint solver, zoom teleport, ASCII STL, extrude area toggle, AppImage icon#23
MakerViking merged 6 commits into
mainfrom
fix/field-reports-aug12

Conversation

@MakerViking

Copy link
Copy Markdown
Owner

Works through the open field reports and GitHub issues. Each root cause was traced to specific code and adversarially verified before any fix was written.

1. The constraint solver never started in ANY packaged build

The headline. planegcs is an emscripten/embind module, and embind builds each invoker by handing a source string to the Function constructor. script-src carried 'wasm-unsafe-eval', which permits WebAssembly compilation but not the Function constructor, so the wasm compiled fine and initialisation then died constructing the bindings.

Reproduced three ways against the real bundle in Chromium 151:

CSP Result
shipping script-src 'self' 'wasm-unsafe-eval' EvalError, solver dead
shipping + 'unsafe-eval' works
no CSP (control) works

Reported four times: eec3752a (0.1.73), ffff5144 (0.1.109), 9042ea56 (0.1.117), cdf4c0f7 (0.1.123), plus once on Linux. It never reproduced locally because tauri dev serves from vite, which sends no CSP. The July CSP commit 099e29b did not fix it, and its message states the false premise outright ("the planegcs glue uses only WebAssembly.instantiate/instantiateStreaming, no eval/new Function").

The old message told users to update their webview runtime. It was wrong on both counts and one reporter reinstalled WebView2 for nothing, so it now blames the build. solver.test.ts encoded the same wrong diagnosis and is rewritten.

On 'unsafe-eval': it is a real loosening and I am not hiding it. The app's only eval sink is this vendored glue; src/params/parse.ts + eval.ts are a hand-written parser and must stay that way while the token is in the policy. I have opened Salusoft89/planegcs#12 upstream, built and tested, which removes the need for it: -sDYNAMIC_EXECUTION=0 produces a byte-identical wasm, passes all 59 upstream tests, initialises under the strict CSP, and costs ~1.5x on solve time (0.11 ms to 0.17 ms on a 100-line sketch). Once that lands, this token comes back out.

2. Camera teleported when zooming

Regression from ef432dc, which projected the cursor pivot onto the view axis and discarded its lateral component. Measured over 12 notches from NDC (0.255, 0.266): the point reached (0.978, 1.017) and left the viewport, then (2.553, 2.655). Scaling about the raw pivot pins it at (0.255, 0.266) for all 12.

ef432dc's justification does not hold for that branch: the camera-to-target offset is (cam - target) * ff either way, so setLookAt gets identical angles and only a translated target. The tilt it was chasing was in the ortho branch, fixed 55 minutes later in a056aca.

The near clamp now also guards the surface under the cursor, gated on zooming in, because that surface is routinely already inside MIN_PERSP_DIST and an ungated clamp would refuse to zoom back out.

Reports 9f62a2ac, db83c26e, plausibly 411082f2.

3. ASCII STL could not be imported, and the bar froze at 44%

Two separate defects. lib3mf (build123d's Mesher) cannot read ASCII STL at all, verified: Lib3MFException 5: Reading from a stream was not possible. OCCT's RWStl reads both encodings and is already linked in, so the triangles go through the same _sew_triangles round trip OBJ and glTF use. Verified an ASCII cube now imports to 6 faces / 1 solid / volume 1000, identical to its binary twin, including the case where a binary STL's header begins with solid.

The 44% was never a stage boundary: phase 0 has a 0.47 share with frac capped at 0.95, so int(100 * 0.47 * 0.95) = 44, and the mesh path published no phase at all. Publishing phases alone would have moved the freeze to 93%, which reads worse, because _importing bound its origin once per request. The origin is now per phase:

before: 0 -> 0 -> 4 -> 14 -> 23 -> 37 -> 44 -> 44 -> 44
after:  0 -> 47 -> 51 -> 61 -> 71 -> 85 -> 93 -> 96

Report b78de7ed.

4. Extrude area toggle (issue #14)

The mechanism was already fixed in 95f12e9, but removing the last area left the depth box on screen with its Enter handler still pointing at commit(), which bails to cancel() on an empty selection. Enter therefore discarded the whole extrude while the prompt read "select a profile to extrude". The drag-phase prompt also never mentioned Ctrl-click, so the affordance existed but nothing advertised it.

Closes #14.

5. AppImage icon (issue #13)

Upstream tauri-bundler bug, fixed in @tauri-apps/cli 2.11.4 (tauri #15596, which names AppManager, the reporter's tool). Confirmed still live in 0.1.123 by reading the published artifact's squashfs directory: .DirIcon is an absolute symlink into the runner's build dir. Lockfile bump plus an assertion in the repack step that fails the build rather than shipping a dead icon.

Closes #13.

Verification

npm run build green and 586 frontend tests pass, run in a clean worktree off main without the untracked evals/ norn/ claude/ directories. All 26 sidecar suites pass, re-run after the final server.py edit. Each commit is independent so a regression bisects.

Not yet verified, and this PR is how: the AppImage fix cannot be proven until the Linux leg runs here. And the CSP fix has not been hand-tested in a packaged build, which is structurally impossible in tauri dev. Before merging, an installed build should be checked: open a sketch, add a constraint, drag an unconstrained point.

Not included

Report 383e7bfd ("WAS DOING NOTHIG") is deliberately left open. The theory that the startup TDZ explains it is wrong: 0.1.111 is run_number 111 = 2f44701, and lastStatusCrumb did not exist at that SHA. It is an undiagnosed idle stall.

planegcs is an emscripten/embind module, and embind builds each invoker by
handing a source string to the Function constructor. script-src carried
'wasm-unsafe-eval', which permits WebAssembly compilation but not the
Function constructor, so the wasm compiled fine and initialisation then
died constructing the bindings.

Every packaged build since the solver shipped has had no working
constraints, dimensions or sketch point dragging. It never reproduced
locally because tauri dev serves from vite, which sends no CSP.

Reported four times, eec3752a (0.1.73), ffff5144 (0.1.109), 9042ea56
(0.1.117) and cdf4c0f7 (0.1.123), plus once on Linux. The message sent all
of them to update a webview runtime that was never the problem and one
reinstalled WebView2 for nothing, so it now blames the build instead.

'unsafe-eval' is a real loosening. The only eval sink in the app is this
vendored glue: src/params/parse.ts and eval.ts are a hand-written parser
and must stay that way while the token is in the policy. Upstream fix
proposed as Salusoft89/planegcs#12, which removes the need for it.
Perspective wheel zoom projected the cursor pivot onto the view axis and
scaled about that, discarding the pivot's lateral component. The camera
dived forward while nothing tracked sideways, so whatever the user aimed
at slid off screen in about seven notches. Measured over 12 notches from
NDC (0.255, 0.266), the point reached (0.978, 1.017) and left the viewport,
then (2.553, 2.655). Scaling about the raw pivot pins it for all 12.

This restores what ef432dc replaced. Its justification, that any lateral
camera move re-angles the model, does not hold for this branch: the camera
to target offset is (cam - target) * ff either way, so setLookAt receives
identical angles and only a translated target. The tilt it was chasing was
in the ortho branch and was fixed separately in a056aca.

The near-plane clamp now also guards the surface under the cursor, which
often sits much closer than the orbit target. It is gated on zooming in,
because that surface is routinely already inside MIN_PERSP_DIST and an
ungated clamp would refuse to zoom back out.

Field reports 9f62a2ac and db83c26e, and plausibly 411082f2.
Ctrl-clicking away the last area returned to the pick phase but left the
depth input on screen, and its Enter handler still pointed at commit(),
which bails to cancel() on an empty selection. Typing Enter after removing
the last area therefore discarded the whole extrude, while the prompt that
branch had just set read "select a profile to extrude".

The drag-phase prompt also never mentioned Ctrl-click, only the edit prompt
did, so a user who picked one of several profiles was told how to set depth
and nothing else. That is what GitHub issue #14 describes: the handler was
there, nothing advertised it.
lib3mf, which build123d's Mesher uses, cannot read ASCII STL at all. It
raises "Reading from a stream was not possible", and many exporters still
default to ASCII, so those imports failed outright. OCCT's RWStl reads both
encodings and is already linked in, so the triangles now go through the
same _sew_triangles round trip that OBJ and glTF use. That also gives ASCII
files the organic-mesh gate, which could only ever apply to binary.

The 44% is a second, separate defect. Phase 0 has a 0.47 share and frac is
capped at 0.95, so its ceiling is 44, and the mesh path never published a
phase at all. Every STL sat there, successful ones included.

Publishing phases alone would have moved the freeze to 93%, which reads
worse because it looks nearly done: _importing bound its origin once per
request, so frac measured total elapsed rather than time in the current
phase. The origin is now per phase, which also removes the same jump on
the STEP path.

Field report b78de7ed.
tauri-bundler before 2.11.4 wrote .DirIcon as an absolute symlink into the
CI runner's build directory, so it dangled everywhere else and AppImage
installers refused to install. Confirmed still live in 0.1.123 by reading
the published artifact's squashfs directory.

Upstream fixed it in 2.11.4 (tauri #15596), so this is a lockfile bump.
package.json moves from ^2 to ^2.11.4 so a regenerated lockfile cannot
fall back to the broken bundler. The repack step now asserts the link
resolves, which fails the build rather than shipping a dead icon again.

GitHub issue #13.
The top section is what the rolling beta publishes as its release notes, so
these need to be there before the next green main, not after.
@MakerViking
MakerViking merged commit dc3c288 into main Aug 12, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant