Add three-axis milling with independent CAM and Fusion validation (#1682)
Thanks @CypherNaught-0x.
This commit is contained in:
1 parent
dd5278a402
commit
737c9358d0
85 files changed
+14487
-43
No files matched your search
+598
@@ -0,0 +1,598 @@
|
||||
# Three-axis milling and independent validation
|
||||
|
||||
The planned first milling workflow is implemented and its four-strategy Fusion comparison
|
||||
gate passes. See the [requirement-to-evidence audit](cam-acceptance.md) for scope, tests and
|
||||
recorded limitations. This is not parity with all Fusion CAM features. No output is qualified
|
||||
for a physical machine controller.
|
||||
|
||||
## Architecture and commands
|
||||
|
||||
`solidcraft-cam` is pure Rust at L1 and depends on geometry. The document persists manufacturing
|
||||
through the pending `manufacturing` format extension. Older designs receive an empty
|
||||
manufacturing section; drilling coordinates remain explicit without inferred associations. Generated paths and
|
||||
verification results are session caches and are deliberately absent from saved designs.
|
||||
The engine resolves bodies, explicit occurrence paths and durable sketch-profile curve identities
|
||||
into immutable snapshots in setup coordinates. Missing or ambiguous references require reselection.
|
||||
Any document or pending occurrence-placement edit makes the cached job stale; undo can restore it.
|
||||
|
||||
The Manufacture workspace, CLI and MCP share these registered commands:
|
||||
|
||||
| Command | Input / behavior |
|
||||
|---|---|
|
||||
| `cam.setup.put` | `{setup: Setup}`: rectangular stock, right-handed rigid frame, model/fixture references, clearance, retract, G54–G59 |
|
||||
| `cam.tool.put` | `{tool: Tool}`: document-local center-cutting flat mill or twist drill, cutting/shank/holder dimensions |
|
||||
| `cam.holes.from_selection` | `{setup,selections}`: ordered cylindrical-face/circular-profile picks; returns centers, diameters and persistent sources |
|
||||
| `cam.boundary.from_profile` | `{setup, sketch, profile, occurrence?}`: returns sampled boundary and durable source reference |
|
||||
| `cam.operation.put` | `{operation: Operation}`: face, contour, pocket or drill; explicit feed, plunge, spindle and depth settings |
|
||||
| `cam.program.put` | `{program: {id,name,setup,operations}}`: ordered operations, one setup/work offset |
|
||||
| `cam.operation.order` | `{program, operations}`: permutation of existing operations |
|
||||
| `cam.delete` | `{kind,id}`: refuses removal while referenced |
|
||||
| `cam.generate` | `{program, background?}`: immutable job; returns job ID/status |
|
||||
| `cam.job.status`, `cam.job.cancel` | `{job}` |
|
||||
| `cam.inspect` | `{job?, include_path?, include_stock?, motion?, finding?}`: world-space stock display mesh and machine state after the requested number of motion blocks |
|
||||
| `cam.simulate` | `{job, background?}`: independent post round trip and stock/clearance checks |
|
||||
| `cam.post` | `{job,path?,background?}`: requires fresh generated paths and passing verification |
|
||||
| `cam.export` | `{job,format,path?,background?}`: `toolpath`, `setup_sheet`, `stock`, `validation` |
|
||||
| `cam.export.result` | `{job}`: consumes completed background output after checking freshness; writes its requested path or returns content |
|
||||
|
||||
UI export and posting use background jobs: a native worker or the browser's cooperative scheduler
|
||||
builds the complete artifact from the immutable snapshot. `cam.job.status` includes an `export`
|
||||
state (`idle`, `running`, `ready`, `failed`, `cancelled`). `cam.export.result` rechecks document and
|
||||
occurrence freshness before consuming output and atomically writing the requested destination.
|
||||
No file is written before this collection command. Cancellation returns no partial artifact;
|
||||
`cam.job.cancel` cancels the job, including its export. One pending/ready export per job is allowed.
|
||||
The UI collects completion through that same command and displays export progress and errors.
|
||||
Programmatic calls default to the existing synchronous behavior. JSON values and stock geometry
|
||||
are preserved; incremental JSON can use different whitespace and object-key order. Artifacts are
|
||||
bounded to 128 MiB; exhausted output budgets fail explicitly.
|
||||
|
||||
All dimensions are mm; speeds are mm/min and rpm; angles in the command model are radians.
|
||||
The UI displays tool and ramp angles in degrees. IDs must be nonzero and unique per item kind.
|
||||
See the serializable types in `crates/cam/src/model.rs` and original fixtures in
|
||||
`crates/cam/src/corpus.rs` for complete payloads. Without a path, exports return `content`.
|
||||
|
||||
Facing cuts stock with raster passes. Contouring uses geometric inside/outside cutter-radius
|
||||
offsets. Pocketing uses successive offsets, handles islands, and retracts between loops.
|
||||
Drilling expands every peck into ordinary motions and distinguishes tip depth from full-diameter
|
||||
depth. Contours/pockets can use tangential leads and feed-controlled ramps. Allowance means stock
|
||||
to leave; use a separate zero-allowance operation for finishing. Flat mills are explicitly assumed
|
||||
to be center cutting. Entry/lead collisions are checked during simulation, before posting.
|
||||
|
||||
The reference spindle rotates clockwise (M3) with right-handed cutters. Climb milling keeps
|
||||
the finished material to the right of travel: counterclockwise inside walls, clockwise around
|
||||
external bosses and pocket islands. Facing advances rows in +Y and cuts toward -X for climb;
|
||||
conventional reverses each cutting direction. Full-width entry can engage both sides of the
|
||||
cutter. Independent tests interpret posted NC and check travel direction and signed loop area
|
||||
for both settings and both input windings. The convention follows the
|
||||
[Haas mill programming workbook](https://www.haascnc.com/content/dam/haascnc/videos/bonus-content/ep81-essential-9-lines/programming-workbooks/mill---programming-workbook.pdf),
|
||||
printed pages 51 and 61. Generator version `cam/14` invalidates paths made with the earlier
|
||||
reversed direction settings; regenerate and simulate before posting.
|
||||
|
||||
Offsets use exactly `cavalier_contours 0.9.0` (MIT OR Apache-2.0) behind bounded input checks.
|
||||
Crossing/touching loops, nested islands, oversized tools, non-finite values and exceeded budgets
|
||||
are errors. The offset adapter uses 1e-8 mm position/join and 1e-7 mm distance tolerances;
|
||||
these avoid merging small distinct slices in round-island pockets with upstream defaults.
|
||||
Boundary validation queries an edge spatial index instead of charging every possible edge pair
|
||||
against its work budget. Crossings, near touches and adjacent backtracking still fail; candidate
|
||||
work remains capped, with cancellation checkpoints during construction, queries and containment.
|
||||
The offset adapter scales coordinates by a power of two so the shortest edge is at least one
|
||||
library unit, and scales distance tolerances by the same factor. This avoids the library treating
|
||||
short nonparallel segments as parallel through its cross-product epsilon. It removes no vertices
|
||||
and restores output to millimetres; the original input remains the independent verifier's target.
|
||||
Dense convex/concave, reversed-winding, translated/scaled and 100-island regressions cover the
|
||||
adapter. Output retains operation IDs, machine events and linear/planar-arc motions.
|
||||
|
||||
## Reference NC dialect
|
||||
|
||||
The post emits tool-tip coordinates, three linear axes, absolute mm positioning, XY arcs with
|
||||
incremental I/J centers, units-per-minute feed and geometrically applied cutter compensation.
|
||||
Post version `solidcraft-reference-3axis/2` explicitly initializes
|
||||
G21/G90/G17/G91.1/G94/G54–59/G40/G49/G80 and stops the spindle and coolant with M5/M9
|
||||
before the declared initial pose. It emits tool/spindle/coolant events,
|
||||
and expands drilling. Startup is a declared position at clearance; physical travel to that
|
||||
initial pose is outside this reference dialect's contract. There is no machine kinematics,
|
||||
G28/G53 homing, length offset activation, canned cycle or controller-specific behavior.
|
||||
|
||||
The separate NC reader consumes every word and rejects unsupported commands. It supports G20
|
||||
and G91 for comparison, but requires complete absolute XYZ for the initial pose. Modal groups,
|
||||
units, feed, tool changes, spindle state, planar arc radii and program termination are checked.
|
||||
M6 stops the spindle, preserves coolant and the programmed speed, and requires a subsequent
|
||||
M3 before cutting. Speed words take effect before motion and alongside coolant/stop commands.
|
||||
Program end includes spindle/coolant shutdown in the interpreted event stream. Hand-authored
|
||||
modal programs check these transitions and reject cutting with a stopped spindle. The post
|
||||
round trip checks its three startup events separately, without assigning them an operation;
|
||||
subsequent motions are compared against the pre-post typed IR with a 0.001 mm error budget.
|
||||
|
||||
Semantics reference: [NIST RS274/NGC](https://tsapps.nist.gov/publication/get_pdf.cfm?pub_id=823374).
|
||||
The reader is a deliberately strict subset, not a general RS274 interpreter.
|
||||
|
||||
## Verification and present limits
|
||||
|
||||
The independent verifier uses adaptive XY cells with conservative lower/upper stock heights,
|
||||
flat-mill or drill-cone removal, local target-surface checks, and swept rapid/shank/holder bounds.
|
||||
Fixture checks use pinned `parry3d-f64 0.31.1` (Apache-2.0): separate cutter, drill cone, shank and
|
||||
holder shapes are swept against fixture triangles. Initial-distance and closed-volume winding
|
||||
checks catch stationary contact and tools already inside fixtures. Body groups preserve enclosed
|
||||
cavities and prevent opposite winding in separate fixtures from cancelling. Open/nonmanifold
|
||||
meshes, clearance within the interpolation/refinement margin, and failed numerical queries remain
|
||||
**inconclusive**. It does not call offset or toolpath-generation algorithms and observes cancellation
|
||||
during topology preparation and collision queries. The current algorithm fingerprint is `cam/18`;
|
||||
the geometry and tessellation changes invalidate older generated/verified caches.
|
||||
No target fitting, translation, unit guessing or discarded unknown NC commands is allowed.
|
||||
|
||||
Default dimensional tolerance is 0.01 mm; interpolation/post error is 0.001 mm; requested spatial
|
||||
refinement is 0.0025 mm. Reports distinguish requested refinement from the actual maximum stock
|
||||
height interval. Limits are 250,000 cells and 30 million work units by default. Exhaustion or an
|
||||
unresolved collision blocks posting. Remaining-stock volume is an interval, not an exact number.
|
||||
|
||||
Stock STL contains a conforming conservative exterior of the upper height envelope. Shared edges and
|
||||
vertical steps are split, internal walls are removed, and every edge and vertex link is checked
|
||||
for a closed, consistently oriented manifold. Coplanar cells merge exactly without resampling.
|
||||
Vertical drill cones use exact rectangular-cell radial extrema. Adaptive cells can still create
|
||||
tiny saddle contacts: export may fill these upward by at most 0.00001 mm per cell, with no XY
|
||||
snapping or removed material. This declared artifact budget does not alter simulation intervals;
|
||||
analytic artifact checks independently compare the resulting STL against those intervals.
|
||||
Exports are bounded to 60,000 merged cells, 500,000 triangles and 128 MiB. Larger or unresolved
|
||||
non-manifold contacts are rejected explicitly; validation JSON retains the cell intervals. `stock_complete` is
|
||||
false after verification budget exhaustion, which blocks export of a misleading partial stock.
|
||||
A watertight upper-bound mesh does not establish finished-part dimensional accuracy.
|
||||
|
||||
Stock comparisons require declared stock bounds and exact, non-overlapping cell coverage. Older
|
||||
reports without bounds remain inconclusive. Imported reference meshes must be closed, consistently
|
||||
oriented manifolds within those bounds, with downward faces only on the stock bottom. Unsupported
|
||||
undercuts, reversed faces, degenerate triangles and out-of-frame vertices are rejected. Projection
|
||||
coverage uses boundary incidence and pinned `robust 1.2.0` orientation predicates, not sums of
|
||||
triangle areas. Duplicate or overlapping faces cannot counterfeit coverage. Extremely small nonzero
|
||||
XY coordinates below 1e-100 are rejected to avoid predicate underflow; coordinates are never snapped.
|
||||
|
||||
The comparator independently bounds reference heights from triangles, reusing only the validated
|
||||
spatial partition before further adaptive subdivision. It certifies whole-column distances for
|
||||
both remaining material and removed space, in both directions, including the stock exterior.
|
||||
This resolves narrow uncertainty bands at vertical walls without concealing an omitted deep hole.
|
||||
Failures require a definitely present material/void point farther than tolerance from all possible
|
||||
corresponding columns; inconclusive intervals are not failures. Distance maxima describe examined
|
||||
regions; a certified failure may stop at its first witness. Cell/work exhaustion remains inconclusive.
|
||||
Tests include independent analytic round holes, alternate facet layouts, generated drilling-stock
|
||||
round trips, shifted walls, missing holes, incomplete coverage and malformed reference meshes.
|
||||
|
||||
The current passing verification status certifies the implemented no-gouge/clearance checks.
|
||||
The separate `finished_dimensions` status certifies facing planes, analytic drill cylinders/cones,
|
||||
pocket floors and islands, and the selected side of contour walls. The milling verifier uses
|
||||
independent robust winding and point-to-segment distances, with whole-cell signed-distance bounds;
|
||||
it never calls the generator's offset functions. A contour must finish its selected wall and floor
|
||||
within one tool radius of the allowance boundary. Farther stock on the cutting side may remain as
|
||||
roughing stock; it cannot be cut below the specified floor. A pocket must clear its full selected
|
||||
interior to the allowance floor while preserving its islands and outer wall.
|
||||
|
||||
The radial tolerance band reserves half the dimensional tolerance for paired-wall/diameter error,
|
||||
then subtracts the post/interpolation budget. Associated CAD profiles also reserve their chord-error
|
||||
budget, at most 0.0005 mm (and at most 1/16 of operation tolerance), during engine sampling and
|
||||
independent certification. Requested features drive adaptive refinement even if the NC omits them.
|
||||
Multiple operations compose by taking the minimum permitted remaining-height envelopes.
|
||||
Drilling requires zero stock allowance: use explicit depth, since drill paths do not apply milling
|
||||
allowance. Sharp inaccessible internal corners, omitted islands, wrong tools/depths and shifted
|
||||
paths fail dimensional validation and block posting. Exhaustion and unresolved bounds stay
|
||||
inconclusive. Posting requires both clearance and finished dimensions to pass and complete stock.
|
||||
|
||||
Motion queries use an independent XY index and retain original sequence IDs for withdrawals and
|
||||
machine-state checks. Exact item bounds exclude irrelevant candidates; shank/holder radii remain
|
||||
included whenever those components can reach stock. Region predicates have bounded work and
|
||||
cooperative cancellation. The analytic contour/pocket recipes now use an original 128-sided round
|
||||
boundary and matching protected walls/floors; they no longer rely on a plane-only square smoke test.
|
||||
Constant-height and vertical mill sweeps use rectangular-cell lateral bounds: the segment's
|
||||
bounding box tightens minimum distance, and convexity bounds maximum distance at the four corners.
|
||||
This avoids artificial overlap from circumscribed disks along straight walls. Sloping moves retain
|
||||
the common-disk height bound; neither tolerances nor resource limits are relaxed.
|
||||
|
||||
Protected height-field boundaries use local spatial certificates. A conservative upper target
|
||||
height at a neighboring XY point bounds distance to the outside of the protected solid for an
|
||||
entire potentially removed cell column. A gouge is reported only with a definitely removed point
|
||||
inside a protected volume by more than tolerance. Clearance reserves 0.001 mm post/interpolation
|
||||
error plus the 0.0025 mm verifier budget; CAD tessellation uses half that verifier budget as a fixed physical tolerance. It bypasses the
|
||||
display mesher's size-dependent tolerance floor and planar display reprojection. Exhausted edge
|
||||
or surface refinement, non-finite evaluations, missing faces and excessive triangle output fail
|
||||
preparation instead of accepting a coarser or partial target. The original large-cylinder
|
||||
regression (radius 5000 mm) previously had 0.00954 mm radial chord error for a 0.00125 mm
|
||||
request; the verification path reduces it below 0.00125 mm, including through engine snapshot
|
||||
preparation. These checks expose known mesher fallbacks; they are not an analytic approximation
|
||||
proof for arbitrary oscillatory surfaces.
|
||||
Queries use an independent XY index, observe work limits and cancellation, and leave unsuccessful
|
||||
certificates explicitly inconclusive with a `protected_surface_unresolved` finding.
|
||||
|
||||
The original drilling fixture now contains the plate top, hole wall and cone, replacing its former
|
||||
plane-only protected target. Tests cover boundary clearance, shifted-hole and through gouges,
|
||||
sloping surfaces, overlapping projected targets and large-coordinate precision. A native CAD
|
||||
drilled body also passes create/generate/simulate/post/save/reopen through registered commands.
|
||||
This does not establish qualification of arbitrary non-height-field solids.
|
||||
Native CAD pocket and contour workflows also pass through durable sketch-profile references,
|
||||
ramp entry, generation, simulation, posting and save/reopen. All four analytic strategies now
|
||||
require passing finished-dimension checks; independent point probes supplement those certificates.
|
||||
The Fusion oracle requires the same dimensional checks for both programs. Current acceptance
|
||||
evidence and supported limits are:
|
||||
|
||||
- Nine analytic recipes / fourteen operation stages cover concave regions, two islands, a narrow
|
||||
channel, allowances, multiple depths/tools, shifted origins and blind/through drilling. Deliberate
|
||||
faulty programs check missing cuts, protected material, unsafe leads and inaccessible channels.
|
||||
- Fixture regressions cover thin swept obstacles, initial overlap, enclosed volumes and cavities,
|
||||
holder/shank interference, malformed/open meshes and cancellation. Supported stock/model geometry
|
||||
remains vertical height-field scope. Fixture triangles must form closed consistently wound bodies
|
||||
for volume-containment certification; surface contact can still be detected on an open mesh.
|
||||
- Background jobs yield during preparation, boundary validation, between offset queries and every
|
||||
256 emitted motions, as well as during verification, NC round trips, fingerprint encoding and
|
||||
conforming stock extraction. The browser shares a four-ms scheduling target across jobs in
|
||||
round-robin order; status queries advance one checkpoint. This target is checked between polls,
|
||||
so it is not a hard deadline. Measured dense offset, large-body tessellation and long-reference
|
||||
encoding remain atomic for about 21.2, 90.8 and 8 ms respectively on the documented browser.
|
||||
The previously synchronous export path is now incremental: original large export probes measure
|
||||
batches at most4.3ms, with no batch above16ms; direct synchronous command calls remain atomic.
|
||||
The measured geometry calls above remain explicit scheduling limits, not a hard deadline.
|
||||
Native background jobs perform profile sampling, tessellation, transforms and hashing on the
|
||||
worker from an immutable snapshot. Synchronous command calls remain available. Status distinguishes
|
||||
`preparing` from `running`; the fingerprint is null until preparation completes. Cancellation
|
||||
cannot publish a partial path or revive a cancelled job.
|
||||
- Associated CAD curves use second-derivative chord-error bounds after placement, including a
|
||||
numerical reserve and a shared 10,000-vertex boundary limit. Requests exceeding precision or
|
||||
vertex budgets fail explicitly rather than silently loosening the operation tolerance.
|
||||
- The four initial local Fusion reference cases pass. Native desktop walkthroughs cover each
|
||||
strategy through generation, simulation, posting through the system save dialog, save/reopen/
|
||||
edit/regenerate, stock display and playback. Eight additional recovery captures cover lost-profile
|
||||
reselection, line-linked fixture collisions and correction, simulation cancellation and stale
|
||||
feed edits followed by regeneration. Preparation cancellation is covered by an engine regression;
|
||||
it was not manually clicked during that walkthrough.
|
||||
- The [completed acceptance audit](cam-acceptance.md) maps the original requirements to
|
||||
implementation and concrete assertions, including multi-operation ordering and native saving.
|
||||
|
||||
The first milling milestone is complete within these declared limits. The passing reference
|
||||
corpus is evidence for its recorded fixtures, not qualification of arbitrary parts or physical
|
||||
controllers.
|
||||
|
||||
## Reproducible comparisons
|
||||
|
||||
Run `cargo xtask cam-validate`. Original analytic recipes generate input snapshots, canonical paths,
|
||||
NC, stock, setup sheets, validation JSON and an HTML report under ignored `target/cam-validation/`.
|
||||
Nine recipes cover the four initial strategies, a rounded concave pocket with two islands,
|
||||
a four-operation facing → roughing → finishing → peck-drilling program with multiple tools and
|
||||
a shifted G55 setup, two clamped through holes, an external square-boss contour and a narrow capsule channel. The harness
|
||||
verifies prefixes of the actual complete program after every operation, including roughing
|
||||
allowance, coolant transitions and conventional finishing. All fourteen
|
||||
stages require protected-surface, dimensional, point-probe and independent exported-STL checks.
|
||||
The new target surfaces have independently calculated volume expectations; deleting islands,
|
||||
omitting finishing, choosing the wrong tool or changing the work offset must fail. Reports link
|
||||
each stage's NC diagnostics, setup sheet and stock, and include tool order, retract count, cutting
|
||||
and rapid distance, feed-time estimate and a remaining-volume interval. Analytic checks
|
||||
run in ordinary CI and `cargo xtask ci`. Core tests include modal state, inch/mm equivalence, wrong
|
||||
arc direction, deliberate gouges/unsafe rapids, shank interference, fixture overlap, geometry errors,
|
||||
islands, ramps and cancellation. Engine tests cover save/reopen, undo and stale-result rejection.
|
||||
Post validation also compares arc sweeps: a tiny arc rounding to coincident endpoints must not
|
||||
become a full circle. Generated arcs shorter than 0.00025 mm become lines, bounded by their total
|
||||
arc length. Shared reference-mesh edges do not cause false interior height discontinuities;
|
||||
positive-area overlaps retain both heights even for extremely thin regions.
|
||||
|
||||
The through-hole recipe uses both simple and peck drilling with full-diameter depth below the
|
||||
stock bottom, a closed raised clamp between the axes, and an independently calculated perforated
|
||||
plate target. Tests reject missing breakthrough, insufficient cutting length and a rapid crossing
|
||||
the clamp at Z7, identifying its NC line. The external-contour recipe uses a reversed square
|
||||
boundary, four depth passes, tangential leads, ramp entry, 0.2 mm roughing allowance and a separate
|
||||
conventional finish. Wrong-side cutting and omitted finishing cannot pass. The final external
|
||||
contour uses 243,154 cells in the current native run, below the unchanged 250,000-cell default;
|
||||
larger jobs can still return inconclusive when their declared budgets are exhausted.
|
||||
|
||||
The narrow-channel recipe has a 2.2 mm width, 10 mm between semicircle centers and a 1 mm
|
||||
cut depth in a 20 × 20 × 6 mm plate. Its R1.1 ends use 64 original polygon segments per
|
||||
semicircle; a 2 mm cutter must finish the floor and both walls while preserving the surrounding
|
||||
plate. An independent polygon-area formula checks target volume, and point probes check both
|
||||
ends, the center and protected stock. Negative regressions reject a 2.4 mm cutter, detect uncut
|
||||
material in a 1.6 mm neck between accessible R2 lobes, and reject a 5 mm lead that gouges the
|
||||
original target. The lead failure retains its operation/motion/NC-line attribution. These cases
|
||||
exercise the unchanged dimensional, clearance and posting gates; they are original analytic
|
||||
evidence and do not count as additional Fusion reference captures.
|
||||
|
||||
Run `cargo xtask cam-oracle --dir plan/fusion/cam/oracle` for local Fusion packages. The harness
|
||||
requires separate `face`, `contour`, `pocket`, `drill` directories. Missing evidence is a failure
|
||||
to establish parity, never a skipped pass. Each directory requires:
|
||||
|
||||
- `manifest.json`: nonempty `fusion_version`, `captured_at`, `input_fingerprint`,
|
||||
`post_identity`, SHA-256 `post_sha256`, and `capture_complete: true` only after actual capture.
|
||||
`capabilities` records a nonempty `license` string and an array of available `strategies`.
|
||||
`source_geometry` names the captured source file inside the package (for example `source.step`).
|
||||
`artifact_sha256` maps every required artifact below, including source geometry and both input
|
||||
snapshots, to its SHA-256 hash. Hashes bind the captured set and reject stale replacements;
|
||||
they do not establish that the input transcription or original capture was correct.
|
||||
- `post.cps`, `post-properties.json`, `input.json`, independently captured `reference-input.json`.
|
||||
Input snapshots must match exactly, including frames, geometry, tools, allowance and settings.
|
||||
- `reference.nc`, Fusion `setup-sheet.html`, `setup-sheet-values.json` with `setup`, `tools`,
|
||||
`operations` values transcribed from the captured sheet/API, and `simulation.json` as below.
|
||||
- `stock.stl` in setup millimetres, captured after the operation. Each first fixture has one
|
||||
operation; multi-operation coverage must capture and validate every intermediate state.
|
||||
|
||||
`simulation.json` must record `status` (`pass`, `fail`, or `inconclusive`), `complete: true`,
|
||||
`at_program_end: true`, a captured `findings` array, `completed_operations` in canonical input
|
||||
ID order, and `stock_after_operation` equal to the final operation ID. Its `accuracy` object
|
||||
records the actual UI `setting` and positive `resolution_mm` when available. If Fusion does
|
||||
not report a numeric resolution, use `resolution_mm: null` and `resolution_status: "not_reported"`;
|
||||
do not infer a resolution from the slider or confuse it with the independent verifier budget.
|
||||
Missing accuracy/end-position evidence is incomplete. Captured failure or uncertainty prevents
|
||||
a pass even when the independent checks pass. `post-properties.json` must contain valid JSON
|
||||
(an object or array), including an empty object when the post has no properties.
|
||||
Each finding has nonempty `detail` and `severity` (`error`, `unresolved`, or `information`).
|
||||
An error or unresolved finding prevents a pass even if the captured summary says `pass`;
|
||||
unknown severities are rejected. Add operation/motion/line locations when the reference exposes them.
|
||||
|
||||
The harness verifies provenance/input fingerprints and the actual post hash, interprets both
|
||||
programs, simulates them through the same independent verifier, compares local spatial stock
|
||||
bounds and the exported reference STL, checks setup values and reports distance/time/volume
|
||||
deltas. Spatial indexing bounds local comparisons. HTML path overlays link to numbered NC listings and diagnostics. Stock heatmaps show sampled
|
||||
remaining material relative to protected geometry; they are diagnostic views, not acceptance tests. Intermediate roughing must be judged against protected geometry and allowed stock;
|
||||
identical roughing paths, retract counts or execution times are not acceptance criteria.
|
||||
|
||||
All three stock pairs must pass directly: SolidCraft NC versus reference NC, SolidCraft NC
|
||||
versus reference STL, and reference NC versus its own exported STL. Tolerance comparisons
|
||||
are not transitive: two results can each lie within 0.01 mm of a third while differing by
|
||||
0.012 mm from each other. An original analytic regression exercises that failure. Reports
|
||||
retain definite failures even alongside inconclusive checks and include `cam-oracle/2`
|
||||
comparison provenance, capture settings, artifact hashes, generator/post identities and error
|
||||
budgets. The imported NC report identifies the captured post, rather than attributing it to
|
||||
SolidCraft's post. Synthetic unit-test packages are original expectations and never count
|
||||
as Fusion parity evidence.
|
||||
|
||||
Create geometry from the original analytic recipe in each application. Record Fusion version,
|
||||
license/capabilities, all resolved settings and capture timestamps. Use its current
|
||||
[NC Program posting API](https://help.autodesk.com/cloudhelp/ENU/Fusion-360-API/files/PostToolpaths_Sample_Sample.htm)
|
||||
and [Save Stock](https://www.autodesk.com/support/technical/article/caas/sfdcarticles/sfdcarticles/How-to-save-the-stock-as-an-STL-from-simulation-in-Autodesk-HSM-and-Fusion-360.html)
|
||||
where no supported automated stock export exists. Do not fabricate missing artifacts or mark
|
||||
incomplete captures complete. Additional fixtures must cover concavity, multiple islands,
|
||||
reversed winding, narrow channels, round profiles, offsets, through holes and multiple tools.
|
||||
|
||||
All Fusion-produced files and derived reports belong in ignored `plan/` or outside the repository.
|
||||
The oracle refuses an unignored in-repository destination. Commit only original recipes, harness
|
||||
code and independently authored expectations. No vendor post source, templates or assets are
|
||||
part of SolidCraft. Local references for facing, contouring, pocketing and drilling now pass
|
||||
input reconciliation, setup values, both programs' clearance and dimensional checks, and all
|
||||
three NC/stock comparisons (4/4). Together with the [acceptance audit](cam-acceptance.md),
|
||||
this closes the planned first milling milestone. The contour, pocket and drill exports use the maximum
|
||||
Stock Accuracy setting after replay to completion; the original coarser exports and their
|
||||
failed/inconclusive comparisons remain in ignored local storage. Numeric Fusion resolution is
|
||||
recorded as not reported, without substituting the independent verifier's resolution. Acceptance
|
||||
remains 0.01 mm with the original post and verifier error budgets.
|
||||
|
||||
## Manufacture display and playback
|
||||
|
||||
The workspace shows the selected program's model, initial stock or simulated final stock, with
|
||||
separate fixture coloring and visibility controls. Stock uses the setup coordinate frame; hidden
|
||||
model and fixture bodies cannot be selected in the viewport. Editing a setup reveals the bodies
|
||||
for reference selection. Missing or stale stock falls back to the model with an explicit message.
|
||||
The remaining-stock display is the final conservative upper surface, not stock removal animated
|
||||
at each playback step. Its mesh is cached by the simulation job and shares the bounded, conforming
|
||||
boundary extraction used by STL export. Display extraction errors do not replace simulation status.
|
||||
|
||||
Playback advances typed motion/event blocks at an adjustable rate, independent of frame rate.
|
||||
Zero means the initial clearance pose. The panel shows operation, tool, spindle and tool-tip
|
||||
coordinates; paths distinguish rapid and cutting motion, including full-circle arcs. `cam.inspect`
|
||||
exposes the same machine state, and `ui.inspect.manufacturing` exposes the current display choices.
|
||||
Stock extraction runs on the native worker and cooperatively on WebAssembly. Cell sorting,
|
||||
boundary stitching, triangulation, manifold validation and large topology-map cleanup yield and
|
||||
check cancellation. Cancellation returns no partial mesh; synchronous STL export uses the same
|
||||
implementation. Native UI tests cover stock-frame
|
||||
placement, visibility, stale results and playback boundaries. The four-strategy headless UI
|
||||
walkthrough exercises background generation/simulation, posting, stock selection and playback zero,
|
||||
with CPU-rendered stock views. A separate native desktop-window walkthrough exercises facing,
|
||||
internal contouring, pocketing and peck drilling on original CAD plates. Contour and pocket
|
||||
operations retain associated circular sketch boundaries and ramp entry; drilling retains a
|
||||
cylindrical face selected in the viewport. Closing and reopening the saved designs clears derived
|
||||
jobs while retaining those references. Editing coolant in the operation dialog and regenerating
|
||||
passes clearance and finished-dimension checks for each case. Native-posted contour, pocket and
|
||||
drill files match their command exports byte for byte. Playback, final-stock display and stale-post
|
||||
rejection were also checked. Local artifacts and screenshots are in ignored
|
||||
`target/cam-native-acceptance/`; this is SolidCraft evidence, not a Fusion comparison.
|
||||
|
||||
A second disposable native-window walkthrough checks recovery. A missing profile produces a
|
||||
reselection error; selecting the original profile and using the operation editor's **Use selected
|
||||
sketch profile** and **Save** restores generation and passing simulation. A clamp intersecting
|
||||
the pocket produces a cutter/fixture error attributed to motion 7 and NC line 20; **Locate issue**
|
||||
seeks that motion. Moving the same associated clamp clear restores passing clearance and dimensions.
|
||||
Cancelling active simulation through **Cancel job** leaves the job cancelled and blocks posting,
|
||||
including after later jobs finish. Editing feed in the operation dialog marks the result stale;
|
||||
posting rejects it, and regeneration/simulation passes. Geometry, deliberately broken references,
|
||||
profile selection and fixture correction were arranged through registered commands; editor actions,
|
||||
generation, simulation, cancellation and issue location used native UI input. Evidence is local in
|
||||
`target/cam-native-recovery/`. Preparation cancellation is covered by engine regressions, not this
|
||||
native walkthrough.
|
||||
|
||||
Interactive Save, Save As and Open use the same picker/background-loading flows as the toolbar;
|
||||
JSON commands remain dialog-free. Keyboard shortcuts use the modifier state on each key event,
|
||||
so a quick Command/Ctrl+S still saves if the modifier is released in the same frame. Regression
|
||||
tests cover these flows, cancelled pickers and persistence of manufacturing definitions.
|
||||
|
||||
Verification findings include a one-based interpreted NC `record` when a physical line is
|
||||
known. SolidCraft's independent post round trip also attaches `source` with physical line,
|
||||
operation ID and one-based IR block (the completed-block count used by playback). Attribution
|
||||
is added after verification and never influences clearance or dimensional decisions. Raw NC
|
||||
comments and deserialized data cannot supply this trusted mapping; imported programs retain
|
||||
line/record attribution without a guessed SolidCraft operation. Arc subdivisions share their
|
||||
original source block. Program-wide and missing-cut findings may have no responsible line.
|
||||
|
||||
`cam.inspect {job, finding: index}` uses a zero-based finding index and returns the reported
|
||||
world-space point, operation definition, associated CAD source, exact NC line and playback state
|
||||
where mapped. It rejects stale jobs and invalid indices; failed verification still blocks posting.
|
||||
The Manufacture panel's **Locate issue** action uses that command to center the reported witness
|
||||
and seek the completed source block. The marker remains visible when paths are hidden, can be
|
||||
cleared, and disappears when inputs change. The marked witness is not a claim of the exact first
|
||||
collision contact, and the stock view remains the final conservative stock surface. Validation
|
||||
JSON and HTML NC diagnostics retain the operation/block/line attribution.
|
||||
|
||||
Findings have explicit information, unresolved or error severity. The bounded list keeps one
|
||||
representative witness per kind/NC line/severity, prioritizes definite errors when full, and
|
||||
shows errors first. This list is diagnostic sampling, not an exhaustive inventory of affected
|
||||
points; verification status and stock intervals are computed independently of finding retention.
|
||||
|
||||
## Browser responsiveness measurements
|
||||
|
||||
A local release-mode WebAssembly probe on Chrome 155 (macOS, 2026-10-15) measured the original
|
||||
four analytic fixtures, using the actual generator, verifier and stock extractor. Before cooperative
|
||||
stock extraction, its longest single call was 433.1 ms for contour, 275.8 ms for pocket and
|
||||
383.1 ms for drill. After the change, the longest stock-extraction poll across those fixtures was
|
||||
2.5 ms. Triangle counts and passing clearance/dimension results were unchanged.
|
||||
|
||||
A second probe reused the UI scheduler with a four-ms target and one batch per animation frame.
|
||||
The largest observed batch was 4.9 ms; no batch exceeded 16 ms. These are local observations,
|
||||
not performance guarantees or complete browser acceptance: the probe excludes CAD snapshot
|
||||
preparation, the rendered application, export serialization, concurrent jobs and hostile-size
|
||||
inputs. Later primitive/export probes below cover representative accepted-size inputs; their
|
||||
remaining atomic latencies are explicit limits in the acceptance audit. Unit
|
||||
regressions verify exact synchronous/cooperative mesh agreement, early/mid/late cancellation,
|
||||
round-robin fairness, completed-job termination and a poll cap if the host clock stalls.
|
||||
|
||||
The clamped through-hole and external-contour recipes also pass the same local release Wasm
|
||||
probe. Their largest observed scheduler batches were 5.2 ms and 7.4 ms, with no batch over 16 ms;
|
||||
stock extraction peaked at 4.0 ms and 4.1 ms. The external contour produced 243,154 cells and
|
||||
111,102 triangles. These measurements have the same limited scope described above.
|
||||
|
||||
## Associated drilling selections
|
||||
|
||||
In a drilling operation, select inward cylindrical faces or circular sketch profiles in drilling
|
||||
order, then choose **Use selected holes**. The engine command accepts `selections` containing
|
||||
`{kind:"face",body,index,occurrence?}` or `{kind:"profile",sketch,index,occurrence?}`. A face pick
|
||||
without `occurrence` uses the displayed world body name; an explicit occurrence path uses the
|
||||
body definition name. Profile picks use the sketch feature ID and evaluated profile index.
|
||||
The returned `sources` belong in `Operation.hole_sources`, with the returned `holes` as the
|
||||
preview coordinates in `geometry.holes`. The command also reports selected diameters.
|
||||
|
||||
Face sources store a body/occurrence identity and persistent face name. Profile sources store
|
||||
sketch curve identities. Immutable job preparation resolves these again in setup coordinates,
|
||||
including uncaptured occurrence moves. Stored preview centers are never used as a fallback.
|
||||
Matching cylindrical seam faces on the same body occurrence become one hole, retaining the first
|
||||
pick’s source. Duplicate identical references and conflicting coincident axes are rejected.
|
||||
|
||||
Missing, split-to-new-name or ambiguous faces/profiles require reselection. Noncircular profiles,
|
||||
external cylindrical faces and axes not parallel to setup Z are rejected. A linked hole's diameter
|
||||
must match the drill within
|
||||
the operation tolerance; choose a matching tool or explicitly unlink before pilot drilling.
|
||||
|
||||
Linked coordinates are read-only in the operation dialog. **Unlink holes** retains the displayed
|
||||
coordinates as explicit input. Feeds, spindle, top/bottom heights, peck depth and tip/full-diameter
|
||||
depth remain user-controlled. The complete operation settings, resolved centers and source
|
||||
identities are included in setup sheets and canonical toolpath JSON; inspection exposes the
|
||||
operation's hole sources. Selection establishes an axis only: independent machining and clearance
|
||||
verification still decides whether the program can be posted.
|
||||
|
||||
### Snapshot hashing responsiveness
|
||||
|
||||
A local Chrome 155 release-Wasm stress probe found synchronous snapshot hashing calls of
|
||||
54.6 ms for 32 operations with 10,000 boundary vertices each, 172.6 ms for 1,000 operations
|
||||
with 1,000 vertices each, and 92.2 ms for 200,000 target triangles. Background snapshot
|
||||
preparation now hashes incrementally, yielding before each operation/tool and every 256
|
||||
triangles. It preserves the exact existing serialized fingerprint, including field order and
|
||||
numeric/string encoding; no algorithm-version or cache-key change is needed. Cancellation
|
||||
checks surround every yield and cannot return a partial digest. Regression tests compare the
|
||||
old and incremental encoders across the original corpus and a maximum-size triangle snapshot.
|
||||
On the same local probe, maximum scheduler batches for those three large cases were 5.1,
|
||||
4.2 and 4.2 ms respectively; none exceeded 16 ms. These are measured observations, not hard
|
||||
deadlines.
|
||||
|
||||
One setup or operation is still encoded atomically. This hashing probe alone does not measure
|
||||
large reference lists, CAD tessellation, a single offset query or direct synchronous exports.
|
||||
The subsequent primitive/export probes cover those cases and record remaining atomic limits.
|
||||
These measurements do not establish whole-application latency guarantees.
|
||||
|
||||
### NC round-trip responsiveness and limits
|
||||
|
||||
Background simulation now yields during reference posting, independent modal interpretation
|
||||
and IR correspondence checking. Posting and correspondence yield every 256 blocks; the reader
|
||||
yields every 256 physical lines, including comment/blank lines. Cancellation is checked before
|
||||
and after each yield and returns no partial G-code, parsed program or trusted line mapping.
|
||||
The synchronous APIs use the same processing code with immediately ready checkpoints.
|
||||
|
||||
A local Chrome 155 release-Wasm probe measured a 228.9 ms synchronous round trip for 199,990
|
||||
blocks. The cooperative path's largest scheduler batch was 4.2 ms. A 200,000-block path also
|
||||
passes, with 200,003 interpreted records including the three post startup events; its largest
|
||||
batch was 4.1 ms. Neither case had a batch over 16 ms. The former reader incorrectly counted
|
||||
startup against the generated-path limit and rejected the maximum-size path. Both posted blocks
|
||||
and external interpreted records now have explicit, independently checked bounds.
|
||||
|
||||
Regression tests exercise the exact path limit and excess input, synchronous/cooperative bytes
|
||||
and machine-state equality, operation/block/line provenance, unchanged unknown-command errors,
|
||||
and cancellation at every checkpoint across all three stages. Measurements exclude direct
|
||||
synchronous export commands, CAD preparation, offset queries and the rendered application;
|
||||
these observations do not establish a universal latency guarantee.
|
||||
|
||||
### Dense boundary validation and offsetting
|
||||
|
||||
The original 10,000-vertex seven-lobe boundary exceeded the all-pairs validation budget before
|
||||
reaching offset generation. Indexed candidate checks now admit that simple boundary without
|
||||
relaxing intersection tests or the candidate-work limit. A separate dense-circle regression
|
||||
exposed a library assertion on short segments; power-of-two coordinate normalization resolves
|
||||
the reproduced case without simplifying geometry. Independent regular-polygon distance checks
|
||||
cover every output vertex at two scales and shifted coordinates; concave checks sample output
|
||||
vertices against the original input segments. These checks are not whole-stock certification.
|
||||
|
||||
A local Chrome 155 release-Wasm generation probe on 2026-10-16 produced 6,674 blocks from the
|
||||
10,000-vertex seven-lobe input. Its longest scheduler batch was 21.2 ms (one batch above 16 ms),
|
||||
compared with 6.4 ms for the 1,400-vertex case. Validation is cooperative, but the library offset
|
||||
query remains atomic. This records an unresolved responsiveness limit; it is not a guarantee of
|
||||
frame-rate responsiveness. The probe excludes CAD preparation and stock verification.
|
||||
|
||||
|
||||
A 2026-10-16 primitive probe measures the remaining atomic work separately from machining
|
||||
acceptance. A 100-island pocket with 9,904 vertices emits 80,307 blocks with a maximum 9.7 ms
|
||||
scheduler batch. Hashing 1,000 setup references or 10,000 profile curve IDs (256-byte names and
|
||||
64-element occurrence paths) takes batches up to 3.2 ms and 8.0 ms respectively. These original
|
||||
synthetic probes test computation; they do not supply matching intended geometry for dimensional
|
||||
acceptance. Fixed-tolerance CAD cylinder tessellation takes about 12 ms at radius 10 mm,
|
||||
102 ms at radius 500 mm and 1,087 ms at radius 5000 mm, producing 3,560, 8,188 and 28,382
|
||||
triangles. The largest case now respects the requested 0.00125 mm chord tolerance instead of
|
||||
silently coarsening it. Native preparation runs on its worker, but a Wasm shell tessellation is
|
||||
still atomic and the measured large-body stall remains a browser responsiveness gap. Local
|
||||
before/after evidence is in `target/cam-web-probe/primitive-baseline.json` and
|
||||
`primitive-fixed.json`; output budgets and tolerances were not relaxed.
|
||||
|
||||
|
||||
The follow-up mesher optimization uses Spade's bulk point insertion and an original conservative
|
||||
line/AABB index for trim-boundary candidates. It retains every boundary segment and the existing
|
||||
winding predicate; uncertain arithmetic visits candidates rather than pruning them. Rounded
|
||||
positions are mapped back to vertex handles so duplicate points do not change constraint indices.
|
||||
Differential tests compare indexed and complete winding scans across concavity, holes, reversed
|
||||
winding, translated/scaled coordinates, boundary points and nearly parallel rays. Kernel checks
|
||||
independently assert concave two-hole prism volume/containment and large-cylinder chord/volume
|
||||
bounds. The algorithm fingerprint advances to `cam/18` because tessellation can change triangle
|
||||
ordering. A local instrumented prototype reduced the radius-5000 case from about 1089.8 ms to
|
||||
96.5 ms with the same 28,382 triangles and 0.00100715 mm maximum measured radial chord error.
|
||||
Its segment visits fell from 352,784,748 to 1,462,907. This optimization does not make shell
|
||||
meshing incremental; its remaining atomic latency is recorded below. Incremental exports are
|
||||
covered by the subsequent acceptance checks.
|
||||
|
||||
The uninstrumented production release-Wasm follow-up measured 10.3 / 27.2 / 90.8 ms for radii
|
||||
10 / 500 / 5000 mm, with the same triangle counts and radial errors as the fixed-tolerance
|
||||
baseline. The largest case remains an approximately 91 ms atomic step on this machine; no
|
||||
hard scheduling deadline or full browser responsiveness claim follows from this measurement.
|
||||
Evidence: `target/cam-web-probe/tessellation-production-index.json`.
|
||||
|
||||
|
||||
## Incremental export acceptance
|
||||
|
||||
A quiet Chrome155 release-Wasm probe with an original 200,000-block path measured synchronous
|
||||
toolpath JSON up to296.7ms and posting/roundtrip342.5–360.8ms. An original tiled height field
|
||||
with40,000cells exported34,051,171bytes of STL in540.5ms; validation JSON took35.5ms. These are
|
||||
serialization/resource measurements, not claims that a synthetic report passed machining checks.
|
||||
The incremental path avoids a full intermediate JSON Value for large arrays, yields between
|
||||
motion/cell/triangle batches and each operation/tool, and reuses cooperative stock extraction
|
||||
through ASCII serialization. Focused tests compare all JSON fields, HTML values/escaping and
|
||||
STL/NC bytes, inject cancellation at every serialization checkpoint, and check stale/cancelled
|
||||
background results cannot write output. The UI regression now exercises background posting and collection through an injected save-picker
|
||||
service. A disposable native command walkthrough additionally exports all five formats, including
|
||||
a33.9MB stock mesh, and verifies no destination file exists before explicit result collection.
|
||||
A fresh system save-dialog attempt was not completed: native accessibility timed out and window
|
||||
capture reported no presented frame. That manual check is not counted as a new passing walkthrough.
|
||||
|
||||
The incremental follow-up measured at most4.3ms per scheduler batch for the same original export
|
||||
cases (no batch above16ms). The40,000-cell STL is still34,051,171bytes, and the200,000-block NC
|
||||
program is still11,999,980bytes. Toolpath JSON shrinks from41,002,015 to15,201,072bytes through
|
||||
whitespace removal; semantic equivalence is asserted against the original serializer. Evidence:
|
||||
`target/cam-web-probe/exports-baseline.json` and `exports-incremental.json`. These timings exclude
|
||||
file-system publication and are machine-specific; command freshness checks still govern publication.
|
||||
|
||||
|
||||
The final native save retry used a regular disposable app bundle. The actual system Save dialog
|
||||
created `posted.nc` (146,348 bytes), identical to the registered-command NC export. Job status
|
||||
confirmed a fresh verified job, passing clearance/dimensions and idle export after UI collection.
|
||||
Post-save screenshot capture remained unavailable; the result is established by the output file
|
||||
and job state. Evidence: `target/cam-native-audit/save-acceptance.json`.
|
||||
Reference in new issue
Block a user