A variable round is the envelope of the balls rolled along the edge, which takes less than a
quarter round in each section. The expectations are now that union, the law continued past the
edge's ends along its end slopes, integrated by Gauss-Legendre panels in x and t; 2, 4 and 8
panels agree to 1e-9 of the body's values, and 77's removed volume matches a brute-force union of
balls to 2.5e-10. The nearest-ball search now scans the balls the ray meets around ball x
(|x - s| < r(s) sqrt(sin 2t)) on their own, which near the faces and where 78's radius closes to 0
are narrower than the global scan's step. Regenerating keeps each case's known_failure. 79, a
constant radius, is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base flange; an edge flange at 90 deg; four made together, the corners closed on the mitre plane
with the rule's gap, at 90, 72 (leaning out, the ends run on along a slant) and 108 deg (leaning
in, cut back); round, rectangular and tear reliefs; a hem; a fold, unfolded and refolded; the
tray's flat pattern (outline size and area, bend lines); a bracket with a hole and a flange on a
flange. K = 0.5, so every volume is T x the flat area. The 108 deg tray is a sheet-metal rig case too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
G 1/2 external and Rp 1/2 internal (ISO 228-1 / ISO 7-1, 55 deg) by Pappus turn by turn; R 1/2
and 1/2-14 NPT external and Rc 1/2 internal tapers (1 in 16 from the standard's diameter at the
free end, crests cut by the major or minor cone) by the screw sweep's Jacobian, integrated exactly
(ladder_lib.sweep_removed); an S20x4 run down to a shoulder with its steep flank toward the end and
toward the start, which moves where the groove stops; tip: start, and a Tr20x4 chamfered at its own
30 deg and 2.5 mm; refusals for a Tr chamfer without a depth and for the square form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1/4-20 UNC (#7, 0.201 in) and Rc 1/2 (17.6) through the stock, 1/4-28 UNF (5.45) blind with a
flat floor, 1/4-18 NPT (10.85) through: a cosmetic thread in a straight hole, so each volume is
the stock less that cylinder. The drills are the catalogue's (Guhring, Yamawa YEU23); each method
gives the standard's minor diameter beside it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The tap maker's 6.8 mm M8 drill, the chamfered tip's ISO 724 d3 with tip: both, and 07/016's
refusal reason were edited into the cases' JSON but not into cases.py, so running it undid them.
Its output now matches the committed cases (to the last rounding digit of two volumes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
17-loft's expected values were FreeCAD's (OpenCASCADE's Part.makeLoft), which runs each side of
the square to its quarter of the circle at uniform angle (arc length). That correspondence has
no exact rational B-spline form, and SolidCraft keeps its surfaces exact: its ruled loft runs
each side to one rational quarter of the circle's B-spline by their own parameters, 35080.7251
mm^3, 0.13% less (the oracle failed on volume and the second moments). The owner chose this
correspondence. The case is now worked out in tools/oracle-analytic/cases_basic.py: the section
area is quadratic in t with the loops' mixed area, so volume and centroid are closed forms of it
(the mixed area and the wall area by Gauss-Legendre on the exact rational arcs); its note says
why it differs from OpenCASCADE and gives that volume, and its `compare` leaves out the surface
check against OpenCASCADE's reference.stl. All its checks pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The inner corner of a 20 x 20 x 10 notch in the 60 x 40 x 20 box, three
concave r5 rounds with corner: g2: one valid body of 13 faces within the box,
the patch's twelve seams jumping at most 1e-3 per mm clear of the hole's six
corners (2.7e-4 measured; the ball corner jumps 0.2). The continuity check
looks within 11 mm of the corner: the vertical round, 2.5 mm long past its
setback, meets its faces 11.2 mm out with every round's G1 jump.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
expected.json `continuity`: over the tangent seams wholly within `within_mm`
of `near`, the curvature jump across them (exact surfaces, 65 stations a
seam) at most `curvature_jump_per_mm` clear (`clear_mm` along the seam) of the
vertices where two of them turn, where a neighbour's own G1 seam ends.
07/015, the box corner's three r5 rounds with corner: g2: one valid body of 10
faces within the box, its patch's twelve seams jumping at most 1e-3 per mm
clear of the hole's six corners by 1.2 mm (2.7e-4 measured; the ball corner
of 009 jumps 0.2). Its golden entry is the passing run's.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The r7 on the vertical edge runs on (tangent chain) up the side's arc on the
r5 round, a circle of radius 5: its contact line on that face would be the arc
offset 7 towards its centre, so no such round exists and the right answer is
a clean refusal. 018 picks a radius that fits (r2: 11 faces, inside the box).
cases.py now writes 013 (the corner setback, graded by its convexity bounds)
instead of marking it missing; its tolerance is the interval's exact half
width.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
003 and 004 passed on one valid body alone. 003 is now the flange less
its M30 groove (stopped clear of the root round, run out through the
chamfer) and three M8 tap drills; 004 is 10/008 less the M16 groove on
the shelled boss, which cuts the wall only. With bboxes. Both hold on
SMLib (worst 1.4e-7 relative).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It passed on one valid body alone. Each d3 vent goes through the shelled
top skin into the cavity and meets nothing else, so the case is 09/011
less 4 pi 1.5^2 1.5; with the bbox. Holds on SMLib (1e-6 relative).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
010, 011 and 014 passed on one valid body alone. 010 (top rounds in
mitres, shelled open below) and 014 (drafted box with tilted rounds:
every level section loses the same elliptic corner) now check closed-form
volumes, exact counts and bbox (014 also its centre of mass). 011, the
running part shelled 1.5, checks the part less its cavity built feature
by feature, the offset faces meeting sharp at concave edges as in the
rest of the tier (a distance-based offset would differ by 0.3%). All hold
on SMLib (worst 1e-6 relative).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It passed on one valid body alone. It now checks the chamfer's prism, the
two r2 rounds below it and the columns they carry on up into the chamfer
face (the section's first moment), with exact counts and bbox. Holds on
SMLib (8e-9 relative).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
010, 011 and 012 passed on one valid body alone. 010 (r7 then an r3 chain
round its arc) and 011 (two r5 rounds in a mitre) now check closed-form
volumes, counts and bbox; 012's variable round takes only its edge and
runs on into the vertical round's column, so its volume is graded as the
interval between that end carried on as a constant r5 tube and as its
growing radius. All hold on SMLib (worst 4e-8 relative; 012 at the
growing-radius end).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
010 passed on one valid body alone: it now checks the tier-05 part less
the M16 groove (stopped w above the boss's shoulder, run out at its free
top) and the bbox. Two new cases with closed forms: 018, an M10 cut both
hands, whose crossing grooves leave the material fraction squared
(2 pi L int r m^2 dr, exact for L a whole number of pitches); 019, a
two-start Tr40x14(P7), six pitches of the Tr40x7 section. All hold on
SMLib (worst 2e-6 relative).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
07, 08, 09, 11 and 12 passed on one valid body alone. Each now checks
its volume, bbox and (where derived) counts, area and centre of mass:
the three-section loft is the degree-2 interpolant r = 10 + (z-20)^2/40;
the square-to-circle loft a ruled prismatoid, its mixed area from the
sides ruled to rational quarter arcs; the periodic fit spline the cyclic
C2 chord-length cubic; the pleated skins star polygons on fixed rays,
their crossing integrated exactly per wedge; the cap's union integrated
as y-intervals over x and z. All hold on SMLib (worst 9e-8 relative).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generator had fallen behind the tree: it no longer wrote 02/021-025,
03/010, 04/011-012 and 09/012-015, and its 07/016 lacked the second round's
tangent_chain. Each is now built in cases.py; the two reporters' scripts
(04/011, 04/012) are kept verbatim in reported.py. Regenerating reproduces
the tree exactly; the only file changes are the generator's own format
(volumes to 9 decimals, one-space indent, a final newline), all under 1e-8
relative.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ladder 06/009 had no way to ask for one: "solid.thread has no runout (vanishing thread)
length". With SMLib's smlib_screw_sweep_radial (replay e7acea1):
- smlib: the FFI binding and Brep::screw_sweep_radial, the profile moved off the axis by a
piecewise linear law of the turn; crate test: a tooth moved out 1 mm over three turns has
A 2π (c turns + ∫ offset dt).
- kernel: sweep_helix_radial, sharing sweep_helix's checks (helix_profile).
- doc: `ease_in`, `ease_out` (a length, or ISO 3508's standard 2.5 P or short 1.25 P) fade the
groove over that length, its section moving out of the material as it turns (outward for a
shaft, inward for a nut). ease_in is at the end the thread starts from. The runout lies past
the full-form length: beyond a square stop, before a shoulder up to its clearance; at a free
end inside the face. Runouts longer than the thread are refused. No end gets one by default,
so saved threads keep their geometry.
The cut is the integral over the turn of the clipped section's 2π∫ r dA: engine test (2.5 P
and 1.25 P between two collars) within the sweep's wall tolerance times the runouts' wall area
(0.029 against a 0.036 mm³ bound), ladder 06/009 (004's shaft, a 2 P runout before the
shoulder) graded in closed form (measured 1.7e-6 off).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`tip: chamfer` cuts ISO 4753's chamfered end at each free end a modelled external thread
reaches, after the groove, so the last teeth taper into the cone instead of ending in a
ragged first turn: the material outside a cone `chamfer_angle` to the axis (default 45°)
reaching d_f = d - 2 `chamfer_depth` at the face's end (default the external minor diameter,
the largest the standard allows), a revolved ring cut by one boolean per end. Past the end the
ring keeps to the radii the groove's overrun already cuts. An internal thread is refused (its
entry takes the hole's countersink), as is a tip with no free end or on a cosmetic thread.
The cone is axisymmetric and cut after the screw-symmetric groove, so the volume is the stock's
chamfered section with the thread's material fraction: engine test (both ends 45°, and 30°
x 0.5 mm at a shaft's one free end above a collar) within 1e-4, ladder 06/017 (measured
2.4e-7 off).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ladder 06/008 had no way to ask for one: "solid.thread has no start count". `starts: n` (1 to
8) cuts n grooves of lead n x P, the j-th a j/n turn round from the first (the same helix j
pitches along), in one boolean with their union. A designation that gives the lead
(M16xPh3P1.5, Tr40x14(P7)) gives the starts, and a `starts` that disagrees is refused. The
helix's self-clearance check and the turn limit use the lead.
Over the same length n grooves of lead nP take the volume of one start of pitch P: engine test
(2 and 3 starts, M10xPh3P1.5) within 1e-4 of the closed form, ladder 06/008 graded as 001
(measured 3.5e-7 off).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the ISO metric 60° thread existed. Forms now (crates/doc/src/thread_forms.rs, values and
sources in docs/threads.md): ISO metric (ISO 68-1), trapezoidal (ISO 2904 design profile, ISO
2902 sizes), general purpose Acme (ASME B1.5), metric buttress 3°/30° (DIN 513), buttress inch
7°/45° (ASME B1.9 basic profile). Each has its groove as a straight-flanked polygon, its standard
sizes (none for ASME buttress), its designations (M10, M16xPh3P1.5, Tr40x14(P7), S20x4,
1/2-10 ACME, 2.5-8 BUTT) and the size that fits a face. The square thread is refused: no current
standard defines it.
`hand: right | left | both`: a left-handed groove is the screw motion about the reversed axis
rising along it; both cuts the two grooves, crossing, in one boolean. `steep_flank` turns a
buttress. The design diameters are checked against the published tables (ISO 2904/DIN 103,
DIN 513 via IS 4696-3); every form's cut against 2π∫ r w(r) dr per turn to 1e-4 in engine tests
and to 1e-4 in ladder 06/011 to 016 (they measure within 5e-7).
FeatureKind::Thread holds every option the command has (form, hand, starts, ease_in, ease_out,
tip, chamfer_angle, chamfer_depth, steep_flank, all defaulted so saved threads load unchanged);
starts, runouts and the chamfered tip are refused as not built yet. suggested_thread_in takes the
form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A thread of some length ran from "the end of the face nearest the pick", a coin toss for a
pick in the middle (rig 602's 4 mm thread meant for the free bottom end ran at the head end,
cutting 1.17 mm into the hex), and every thread end at a face end got a one-pitch overrun,
which at a shoulder gouged the material past it (ladder 06/004 cut 0.9% of its volume out of
the collar).
- kernel: material_in_ring, the exact intersection of a body with a ring about a cylinder
face's axis, by an SMLib boolean.
- doc: a face end is free when no material lies past it, over the span the groove's one-pitch
overrun reaches beyond its first pitch, within the radii the groove cuts (a cap, a chamfer
the groove runs out through, a counterbore). At a free end the groove runs out as before; at
a closed one (a shoulder, a head, a blind hole's bottom) it stops with its widest part clear
of it; inside the face it stops square.
- doc: a thread of some length starts at the end nearest `from`, else at the face's only free
end, else at the end the pick lies within a third of the face of; a pick in the middle of a
face whose ends are alike is refused, naming `from`. A length as long as the face runs the
whole face. `up_to` a plane or a point's place along the axis. New fields `from`, `up_to`
default to none, so saved threads keep their meaning where it was not a coin toss.
- engine: solid.thread takes extent (full|length|up_to), from and up_to.
- ladder 06/003 (now with `from`), 004 and 007 are graded by volume and centre of mass in
closed form (a square stop inside material removes exactly length/P turns, the section being
symmetric); rig 602's method says why the thread is at the bottom, tolerance 0.02%.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ladder/05/011 expected 8 faces (the stock's 6 and one per hole). With equal
radii the two walls cross along two ellipses that meet at the two points
where the walls are tangent (x = 25 and 35, y = 20, z = 10), so each wall is
left in two pieces that touch only at those points, with no edge between
them: separate faces, 10 in all. SMLib makes those 10 (volume exact); truck's
8 came with an invalid record. Derivation in the case's method.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
Tiers: primitives; booleans in the degeneracy classes (coincident and coplanar faces, edge-on-edge,
vertex-on-face, tangent along a line and a circle, near-tangent gaps and overlaps of 1e-3 and
1e-6 mm, seam and pole crossings) and cuts that end in a single line (a knife-edge wedge, a V
groove and a cylinder that pinch the part in two, a hole tangent to a face, a notch flush with an
end); line-and-arc extrudes and revolves (partial, touching the axis); spline profiles, sweeps
and lofts; holes and tapped holes (blind, drilled, counterbore, countersink, M5-M8 taps, into a
curved face, near and tangent to an edge, crossing); modelled threads (external, fine, partial,
to a shoulder, internal, into a chamfer, at a filleted shoulder); fillets (constant, tangent
chains, convex and concave, variable down to 1e-3 and to 0 at a vertex, corners with equal and
unequal radii, g2 corners); chamfers (two distances, angle, three- and two-edge corners, curved);
shells and offsets; patterns and mirrors (overlapping instances that cut a core free); and
cumulative parts.
A running part grows one tier at a time through `base` (back wall, revolved boss and slot,
spline window, tapped holes, rounds, chamfers, shell, vents), and the last case adds its thread:
it carries every tier. Answers are analytic wherever the geometry has them (Pappus, Steinmetz,
ISO 68-1 basic thread profiles, exact Gauss quadrature of Bezier profiles, inclusion-exclusion
for chamfered corners), otherwise invariants; each `method` gives the derivation, and
tools/kernel-ladder/cases.py (standard-library Python, like tools/oracle-analytic) writes them.
Capabilities SolidCraft lacks are `missing` cases: multi-start threads, thread runout lengths,
fillet corner setbacks.
The golden is the first recording on truck, each tier sorted by its time. SMLib booleans are
not on this branch yet, so the smlib column records "not supported yet" for every case.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWhMwdqJYQKQq8RCLSL1LT
* claim: #5523
* Windows resize smoke test: wait for a settled window before hit testing
Startup placement can move the window between CheckBorder reading its rect
and the hit tests, so correct answers for the new position failed against
stale coordinates. Wait for two reads 200 ms apart to agree before the first
pass, compare the rect after each pass, and retry the pass (up to three tries)
when it moved. A pass with a stable rect fails exactly as before.
Fixes#5523
* wip(render): reconcile completed material and image pipeline source with 0.20 (#5493)
Source-only integration reference for staged review, not a merge-ready aggregate.
Donor: 0xlillith/solidcraft@aea20b0115.
Upstream: 858e5995d6.
Retain original CPU/material contracts and explicit GPU donor provenance in
docs/render-materials-lab.md (#2067, #2191, #2780, #3306). Preserve released
format migrations and current navigation/startup/shell behavior. New saved
records use pending descriptors. The physical-card descriptor follows the
maintainer's material-engineering-cards naming request, with a legacy-lab
format-29 regression. Replace raw new panel hosts with shared containers.
Repository checks, complete workspace/all-target Clippy, and the independent
physical/resource authoring checks pass for this source. The fresh full local
CI invocation has reached test compilation and is not yet complete. Do not
transfer donor native output or prior test totals to this integration.
Generated review screenshots, video, package ZIP and machine logs remain at
the immutable personal evidence pin. Uncommitted geometric displacement is
backed up separately, not silently included. No kernel/vendor change, direct
main write, release or independent contributor-branch rewrite.
Co-authored-by: Christian Svensson <blue@cmd.nu>
* test(cli): pin the Compact camera-sample admission diagnostic (#5493)
The bounded request still refuses 1024x1024x64 samples before host initialization and writes no output. Update only the stale expected diagnostic to the existing Compact budget wording; production limits and code are unchanged. Exact-tree CLI regression suite: 14 passed, 0 failed. The full repository gate has been invoked separately and is not yet complete.
* Normalize UI container violation paths across platforms
Report repository-relative paths with forward slashes so diagnostics and the existing nested-package regression assertions agree on Windows and Unix. Keep the container detection rules unchanged.
Validation: official ui-containers gate and all seven focused xtask tests passed; rustfmt and diff checks passed. Only xtask/dependencies were compiled; no application build or heavy tests.
(cherry picked from commit 44b58d8e10)
* fix(render): preserve camera contracts and correct acceptance regressions (#5493)
Preserve Design view.apply semantics with a separate strict Render camera command. Retain existing translations when English-only aliases collide; add material-axis entries and camera-specific pitch labels. Compare complete validated engineering cards and retain job handles before cancellation.
Focused and native acceptance is pinned to tree f8a423b21f. Full CI has been invoked separately and is not claimed green. Landing follows the render integration policy in #5493.
* fix(render): resolve showcase licence and upstream resource hygiene (#5493)
Record SychPL's explicit MIT OR Apache-2.0 grant, retaining source/model bytes and the Ubuntu lettering notice. Remove 80 absent attribution rows, personal fork records, dead delivery attributes and three fork/resource-only workflows. Existing xtask assets now performs bounded offline hash checks and rejects orphan render attribution; no parallel draft CI or package installation. Original authoring reproduction remains explicit. Scoped xtask tests, assets, Clippy, formatting and prepared SELENE validation pass; no application or renderer-wide result is inferred.
* fix(render): align saved bounds and progressive sample resolution (#5493)
Address review r4364211669/r4364211677/r4364211681/r4364211691/r4364211695. Persisted light/frame domains respect the existing 1e9 document bound; related LED/rectangle/direction cases use the same bound. Workstation primary resolve shares the 4096 admission cap and film counters use checked conversions. Exact candidate: 485 CPU render tests, 21 render document tests and strict scoped Clippy pass, including positive boundary round trips and 2048/4096 end-to-end checkpoints. No released format/migration edits, relaxed test limits or full-stack acceptance claim.
* wip(render): isolate optional resources and harden sample handling (#5493)
Review work in progress: opt-in encoded render library with reproducible runtime catalog exports; native-only robust dependency through the workspace; checked bloom slices; per-sample point-light diagnostics; independent area-light spatial/film keys. Resource-module binaries in both configurations, generation, Cargo production feature graphs and attribution checks pass. Full engine/render regression and combined acceptance are pending: do not merge this donor as a constituent or treat scoped resource proof as runtime acceptance.
* fix(gpu): preserve donor allocations through the scope-safety repair (#5722)
Port the native-validated #5723 scope-cleanup correction into the experimental donor, retaining its adaptive, volume, aging, photographic and bloom allocations. Same reverse-drain helper and regression cases; the donor combination still needs its own compile/test gate and is not covered retroactively by render-base results.
* claim: #1369
* Reject unknown pending concepts after format folding (#1369)
* test(render): close bounded sampling and bloom review regressions (#5493)
Validate the optional-resource/lighting/dependency donor at its exact tree. Required Vulkan GPU 127/0/3; CPU renderer 487/0; engine Render 72/0; document render 21/0; lean library 7/0; strict scoped Clippy, assets/layers/lists/containers and lean-engine WASM pass. Preserve original failed controller/typing attempts. This is the draft donor/disposition source, not a replacement for constituent render PRs or final main acceptance.
* wip(render): preserve stable aging target validation candidate
Exact staged source from prior review work on donor 3b892eab5e. This is a recovery/review checkpoint, NOT accepted delivery. An actual command-path regression currently fails because the selected executor refuses ordered surface aging. No assertion, capability or admission limit is weakened. Native/UI/full combination acceptance remains pending. Saved/runtime split adds one pending descriptor and retains original file scope; no main/render branch is changed.
* test(render): preserve numeric setup intent at the admitted coordinate bound
Follow up jyviko review on #5494 without weakening the corrected saved-coordinate contract. The positive clicked fixture uses 1e9 instead of inadmissible 2e9; explicit out-of-range cases still refuse, and the full saved setup round-trips through JSON and the native container. Exact-source Render workspace 95/0 and strict all-target UI Clippy pass. This does not incorporate the separately failing stable-aging candidate or claim full current-render acceptance.
* test(render): use the real GPU executor for saved aging
Move successful native cold-reopen Check/Start coverage from the CPU-backed protocol fixture into the production GPU executor tests. Verify capture-index changes preserve the stable target and that enabling aging changes both PNG and raw EXR output. Retain explicit, allocation-free refusal coverage for executors without aging support. Production capabilities and admission checks are unchanged.
* fix(render): persist stable identities for targeted aging (#5493)
Separate saved RenderBodyTarget identities from captured mesh ordinals. Reject legacy ambiguous targets, resolve Check/Start after visibility changes and preserve native reopening, copies and undo. Unsupported executors still refuse; real AMD Vulkan regression completes saved aging after reordered capture.
Source tree 6b84c8ad passes document 23, engine Render 75, GPU effects 5 and Render UI 95 with no failures; scoped strict Clippy, WASM and repository gates pass. Fresh CLI/native reopen and clean/aged GPU exports pass with identical physical totals and inspected actual images. Whole current-render integration is separate.
* fix(render): reconcile combined CPU/GPU contracts on current upstream
Unify captured resources/status and CPU-vs-GPU request schemas after the real two-parent integration; remove obsolete duplicate Vulkan selector and retain combined platform-filter regression. Deduplicate only identical or superseded test definitions, retaining the stronger card metadata and reserved-executor assertions. No assertions, admission limits or feature refusals are weakened.
All targets of render dependencies, GPU, engine, UI, CLI and native app pass cargo check with raytrace-cpu and bundled-render-library at tree c70d00d1. Native executable tests and full current-source acceptance remain pending. This is a private integration rehearsal for subsequent constituent PRs, not an aggregate official render/main merge.
* test(render): retain one complete host lifetime regression set
Deduplicate byte-identical DropProbe/task-lifetime tests and retain the adapted environment/texture ownership regressions with every assertion and complete memory estimate. Keep the registered-geometry admission regression once; only struct field order differed. Replace a one-element diagnostic loop with its equivalent block, preserving all wrap/width assertions.
Test-only integration repair. Formatting and diff checks pass; refreshed executable validation is required. No production behavior, limits, assertions or ignores changed.
* fix(doc): recognize the proven format-29 card descriptor alias
Normalize only the historical format-29 physical-material-cards spelling, and only when material-engineering-cards is registered. Admission and migration de-duplication use the same identity. Unknown concepts, wrong versions and incapable readers still refuse before mutation. Six controlled-history Rust regressions and actual CLI migration/no-clobber acceptance pass. No version, released migration or CI changes. Refs #5793, #1369, #5493.
* test(render): preserve grounding refusal before explicit instance moves
Update the two Render binding fixtures for upstream first-occurrence grounding. Verify grounded movement refuses without changing document/history, then explicitly unground through the public command before the intended move. Retain every target, resource, copy and persistence assertion. Refs #5493.
---------
Co-authored-by: Christian Svensson <blue@cmd.nu>
Co-authored-by: Victor Santos Oliveira <56417388+Vittuu@users.noreply.github.com>
Co-authored-by: cfaulkingham <colin.faulkingham@gmail.com>
* feat(geom): surfaces through curve networks, and spline spaces to build them
Adds spline_space (clamped B-spline spaces, Hermite interpolation, exact
embedding by Bézier degree elevation and knot insertion, a monotone cubic
for reparameterising) and network (loft, Coons and Gordon surfaces through
curves in one or two directions, with G1/G2 cross-boundary conditions
against a neighbouring face). Part of #763.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(kernel): boundary surfaces from sketch curves, 3D curves and edges
kernel::boundary_network turns sketch chains, 3D sketch polylines and edge chains
into network curves, gives G1 frames of the faces along open edges
(EdgeFaces), builds the B-spline face (sides split at chain vertices so a
join shares the body's edges) and joins it into a surface body by stitching.
G2 is refused for now (not supported yet). Part of #763.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(kernel): second derivatives of B-spline surfaces in the vendored truck-geometry
BSplineSurface::uuder and vvder multiplied the second differences by p
instead of p·(p − 1), as BSplineCurve::der2 does, so every surface of
degree p ≥ 3 (NURBS too, through its homogeneous surface) reported
1/(p − 1) of its second derivative: a cubic surface's curvature read as
half. This is why a G2 boundary surface on a cylinder measured half the
curvature it carries (#763). New tests hold both to finite differences
for degrees 2 to 5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* feat(kernel): G2 boundary surfaces against a body's face
The network always carried the face's curvature across a G2 edge; the
refusal came from measuring it with truck's halved surface second
derivatives (fixed in the previous commit). EdgeFaces now reads the
face's second fundamental form from the exact second derivatives
instead of differencing the normal. A new test holds the curvature
across a cylinder's edge to the cylinder's within 0.1%, also with a
sheared far curve; G3 is refused (a network holds up to G2).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* test(kernel): a boundary patch with straight corners measures its own area
A stadium's arcs meet its lines at 180°, so the Coons patch is singular
at its corners. From such a corner the reference mesher's boundary walk
ran onto the B-spline's extrapolation past its domain (a planar spline
passes through every point of its plane there), and the face measured
289 mm² for its 158.5 (#763). The vendored mesher's bounded projection
(nearest_projection, #2043) keeps the walk on the domain; this holds it
there, by the faces, the measuring mesh and the display mesh. The
display path (#1653) was never affected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* feat(geom,kernel): three-sided boundary surfaces (one side collapsed to a point)
A network curve may be a PointCurve: the apex where the two sides beside
it meet. The curves through it cross it at the point itself, its row of
the net collapses there, and the kernel's face leaves that side out of
its loop (three edges, one vertex at the apex). One point per patch, as
a side; refused elsewhere, when it moves, or with a continuity
condition. Tests: a triangle and a quarter disc filled flat with their
analytic areas (40 mm², 25π), by geom and by the kernel's faces and
meshes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* feat(doc): boundary surfaces through curve networks and loops of three or four
FeatureKind::SurfaceNetwork saves a network as `u` and `v` curves, each
a sketch chain (planar or 3D), a chain of a body's edges with an
optional G1/G2 continuity, or a point (the apex of a three-sided
patch), and an `operation` that can join the surface into the body of
its edges. A SurfaceBoundary of three or four sketch curves, refused
until now, builds as the flat Coons patch of its loop (three collapse
the side opposite the first curve). The format change is one pending
file; feature-walk goldens record the new variant's sketches, bodies
and points.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* feat(engine): surface.boundary through loops of three or four and curve networks
The command keeps its loop form (two to four curves of one sketch; three
and four now build the flat patch of the loop, crown refused there) and
gains a network form: `u` and `v`, each curve a sketch curve id, a
{sketch?, curves} chain (planar or 3D), a {body, edges, continuity?}
edge chain (g1/g2 with the face beside it) or a {point} for a
three-sided patch, with `operation` new or join. Edits may move between
the two forms (timeline.redefine accepts the command now that it has a
dialog).
Tests: analytic areas of loop patches and of a hyperbolic paraboloid
bounded by four 3D lines (every mesh vertex on z = xy/10), a loft
across two sketches, G1 and G2 measured across a cylinder's edge with
inspect.continuity (angle < 0.1°; curvature jump 1e-16 with G2 against
0.027 with G1), 26 hostile networks refused without panicking, and u/v
added to hostile_params_never_panic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* feat(ui): Boundary Surface dialog
Curves and Cross curves take sketch curves and edges (picks that meet
end to end in one sketch or body are one chain); Continuity and
Operation (New Body or Join). Two to four sketch curves of one sketch
with nothing across are the loop patch; anything else is a network.
Edit Feature brings either back (per-side orders, crown and stations
the dialog does not show are kept). Strings in en, ja and zh.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* docs: ROADMAP M8 and the bridge patch's notes for boundary networks (#763)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* test(oracle): a boundary surface through a loop, thickened (#763)
Case 83: four sketch curves (a square's three sides and a half circle
for its top) make one boundary surface, thickened 2 mm; analytic values
from tools/oracle-analytic/cases_surfaces.py (V = 2A, area 2A + 2P,
centroid by moments). Recipes gain boundary_surface, thicken and remove.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
* refactor: boundary surfaces, review cleanups
Project onto the face once per derivative evaluation (the frame is
passed to natural() and reused by scale()), keep each track's
finite-difference step instead of rescanning its table, export the
kernel's edge-pick and chain caps and the default station count for
the engine, doc and dialog to share, map TooLarge spline errors to
KernelError::TooLarge, reuse the engine's operation parser, and skip
the dialog's sketch lookup when the picks are no loop.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LGeCa5jWWdroMWvXxN3LLM
---------
Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: bherbruck <brennen.herbruck@gmail.com>
* Windows: resize border from the first frame, DPI-correct window moves (#1381)
- The egui resize zones were laid out after the start page's early return, so a launch without
a design had no resize edges at all. They now run on every page.
- Windows: the main window's procedure answers WM_NCHITTEST with the resize edges and corners,
Windows' own border width at the window's DPI (8 px at 100 %), so the OS shows its resize
cursors and runs its own resize (snap included) from the first message; no egui zones there.
- Windows: WM_GETDPISCALEDSIZE returns the size winit then applies (same logical size), so the
rect the OS suggests while the title bar is dragged onto a monitor with another scale is the
rect the window gets.
- Zone sizes and hit test shared in titlebar.rs and unit-tested; Windows CI checks the hit test
right after launch and a real edge drag.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Windows resize smoke: find the main window by its title
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Windows resize smoke: probe the maximized window at the screen's edge
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Windows: start Direct3D 12 first, and Vulkan only without a D3D12 GPU
wgpu started Vulkan, D3D12 and OpenGL together and preferred Vulkan, so
every Windows start loaded all installed Vulkan drivers. An old Intel
Vulkan driver (igvk64.dll) crashed 0.10.1 at startup inside the driver.
The app now probes D3D12, then Vulkan, then OpenGL, one backend at a
time, and starts only the first with a hardware adapter (WARP when none
has one). WGPU_BACKEND still wins; graphics.json's "backend" sets the
order by hand; the software renderer (safe mode, the retry) uses D3D12
alone. A new Windows CI job starts the real app under several settings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CI: a test filter YAML parses
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CI: the startup smoke test writes graphics.json where the app reads it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* CI: run the WARP shader tests one at a time
WARP's shader JIT (d3d10warp.dll) crashed twice in 124 runs of the gpu
tests with four test threads, with a null read inside its own optimizer
while several devices compiled compute pipelines at once. Serial runs
did not crash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Thin Extrude builds walls of a set thickness along sketch curves, open chains and closed loops, with the wall centred, inside, outside or on both sides at two thicknesses. Saved under format 20 (thin on an Extrude); an extrude without thin saves as before. Closes#721.
Adds oracle case 81 (a box edge rounded at a clamped cubic B-spline radius) with analytic expected values, and passes spline fillets through recipes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The oracle no longer uses Fusion measurements. tests/oracle/<case>/ now holds the 76 recipes
(our own format, with recorded measurements and tool-specific fields removed) and an
expected.json per case:
- 55 analytic cases: closed-form values from tools/oracle-analytic/ (stdlib Python, formulas
in each case's "method").
- 21 FreeCAD cases: the same recipe built with FreeCAD's public scripting API by
tools/freecad-oracle/ (an external program, not a dependency), with a reference.stl for 20.
solvecraft-cli oracle compares body count, volume, area, centre of mass, bbox, face counts
where the geometry fixes them, and, against reference.stl, the sampled Hausdorff distance and
the principal moments (spatial.rs from #301). cargo xtask oracle reads tests/oracle, writes
docs/oracle.md with the source of each value, and supports known_failure marks for tracked
bugs. CI runs it on every PR; a manual workflow regenerates the FreeCAD values. step-corpus,
seam normalisation and the through-all emulation, which only existed to compare with Fusion,
are removed.
75/76 pass; 75-sm-bracket-holes is a known failure (#296).
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT
Co-authored-by: bherbruck <bherbruck@herbrucks.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>