Every panic (in a command, in the kernel, anywhere else) and every unclean
exit (abort, stack overflow, kill) leaves a report in a local crash folder:
message, file:line, a trimmed backtrace, version, commit, system and renderer,
the command and recent commands, and when possible the design and replay.json
that reproduce it (solvecraft-cli crashes replay <id>).
- Cost: nothing until the app installs the hook (tests, CLI and web never
do); then one small journal line per top-level command of the design on
screen, taken back with a truncate when the command changed nothing.
- Unclean exits: each run holds a lock on its journal; a journal nobody holds
at the next start belongs to an app that died. Autosaves restart the
journal from the autosaved design.
- Bounded: a crash's signature (place + message, numbers ignored) is counted,
not rewritten; at most 5 new reports per run, 20 reports, 50 MB, 90 days;
recovered kernel panics are pruned first.
- Agents: diagnostics.crash_reports / crash_report / crash_reports.clear
commands, the MCP crash_reports tool, solvecraft-cli crashes, solvecraft
--crash-log; diagnostics.crash_test (with SOLVECRAFT_CRASH_TEST) checks it.
- People: the Crash Reports window opens after a crash (Help > Crash
Reports…) with a reviewed issue draft per report; nothing is sent.
- Release builds keep line tables for file:line in backtraces.
Tests: child processes that really panic in a command, in the kernel, on a
thread, and abort; dedup counts, limits, hostile folders, journal parsing,
the UI window and draft, the MCP tool. docs/crash-reports.md.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
* feat(sketch): constructive solving ahead of the numeric solver
Part 1 of splitting #251: the sketch crate only. A graph-constructive front
end (Owen 1991; Fudos & Hoffmann 1997) places what it can by ruler-and-compass
loci and cluster decomposition, Levenberg-Marquardt finishes and verifies the
rest, and the rank analysis stays authoritative for degrees of freedom. Solves
can follow a reference (the previous solution), so edits and drags keep their
branch instead of flipping.
New API: solve_with (hold, reference, analysis, budget) and
solve_after_value_edit; solve and solve_holding keep their signatures as
wrappers, so no caller changes here.
When the seed moves an arc's centre, the arc's unconstructed ends start carried
along (the arc translates) instead of left behind for LM to turn; found by the
reference test 20-slot-constrained.
Refs #203
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWc1smHYwTSVrVc8SNvS44
* feat(doc): keep a sketch's solved state across value edits
Part 2 of splitting #251 (builds on part 1, the sketch crate):
- Sketch edits solve for the document's values continuing from the stored
solved state (Document::solve_sketch), so a dimension edit keeps the
sketch's branch instead of re-solving from scratch.
- A value edit (parameters, a configuration, the units) that would make a
sketch that solved before fail or turn over is refused with the
conflicting constraints named; otherwise the solved sketches are written
back into the document (Model::adopt_solved_sketches), which changes what
saved designs store.
- Later features are keyed by a sketch's solved geometry (to a 1e-6 mm
quantum), so setting a value back reuses their earlier results.
- Solved sketches in a model state are shared (Arc) between states.
Refs #203
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWc1smHYwTSVrVc8SNvS44
* feat(sketch): live drag that keeps its solution, ended by sketch.drag_end
Part 3 of splitting #251 (builds on part 2):
- sketch.drag follows a long move in short held steps, so the geometry keeps
its branch, and reports how far it got (reached, at).
- live: true runs one frame of an interactive drag: the sketch is solved
once and shown, later features keep their last result (marked stale)
until sketch.drag_end or any command that reads the model evaluates it
(CommandSpec::live, reads_model, doc_only).
- sketch.drag_end adds the constraint the drag let go on and evaluates the
model once.
- Undo and redo evaluate a new document once (execute does) instead of
twice.
- The viewport drives drags through live frames and drag_end; dimension
text drags start only off sketch geometry.
Refs #203
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TWc1smHYwTSVrVc8SNvS44
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Remove xtask/data/fusion-catalog.tsv and xtask/data/fusion-ids.tsv.
- Remove the legacy command-id table (crates/engine/src/legacy_ids.rs) and its use in
find_command and in the shortcut, recents and pinned-command loaders. Only SolidCraft's
dotted ids name commands; any other id is an unknown command.
- Boundary Fill's id becomes solid.boundary_fill.
- Replace the parity report with SolidCraft's own feature checklist: `cargo xtask features`
writes docs/features.md from the command registry.
- docs/oracle.md, docs/step-import.md (corpus section) and docs/iges-import.md: reference
results are being rebuilt on analytic and open-source (FreeCAD) values; see #292.
`cargo xtask oracle` and `cargo xtask step-corpus [--iges]` write these placeholders.
- AGENTS.md, CLAUDE.md, CONTRIBUTING.md, README.md, ROADMAP.md and the book describe
SolidCraft as independent, with reference tests on analytic values and open-source tools,
and agents do not drive or extract data from commercial CAD products.
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The old ids live only in crates/engine/src/legacy_ids.rs (the legacy migration table): find_command maps them, so old scripts, recipes and control calls keep working, and saved shortcuts, recent and pinned commands are migrated on load (designs store no command ids). Parity maps the observed catalog ids to ours through xtask/data/fusion-ids.tsv. The agent rule now reads: our own dotted id, never another product's. Cargo.toml's repository points at github.com/bherbruck/solvecraft.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Kernel (surfaces):
- Bodies with an open shell are surface bodies (Body::is_surface).
- patch_region: a planar patch of a sketch region. patch_edges: a planar
patch filling a closed loop of a body's edges.
- copy_faces: faces copied out as a surface.
- stitch: sew surfaces along coinciding edges, turning faces to agree; the
result is a solid when it closes.
- trim: cut a surface by a plane or face and keep one side.
- thicken: offset planar and circular-cylindrical faces along their
normals (one side or symmetric) into a solid. Plane copies slide;
cylinder copies scale about the axis, exact for NURBS circles. Free
edges get ruled walls. Faces meeting at a sharp edge are refused.
Doc features Patch, Stitch, Thicken (with operations) and SurfaceTrim;
engine commands FusionSurfacePatchCommand, FusionSurfaceStitchCommand,
FusionSurfaceThickenCommand and FusionSurfaceTrimCommand.
Tests (volumes):
- A 10x10 patch thickened by 2 gives 200, also symmetric.
- Half a cylinder side thickened outward gives half a ring; both halves
inward give the full ring.
- Six faces of a box stitched back give 6000; an open box with its top
patched from the edges, stitched, gives 6000.
- Trim keeps 30 or 70 of 100.
- Engine: patch, trim, thicken gives 140.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL