Write the order list as a Mastercam tool library - #13
Merged
Merged
Conversation
A `.TOOLDB` is a SQLite database carrying Mastercam's own 79-table schema, and writing one is `@toolpath/tool-support/export/mastercam`, not this application. `app/shared/mastercam-input.ts` is the seam. It reads differently from the Fusion one on purpose. Fusion embeds a holder inside the tool record, so one tool in two holders is two records; Mastercam joins them relationally, so the order list goes in grouped — one entry per distinct tool carrying one set-up per stack, one entry per distinct holder, under the catalog's own guids. Six stacks sharing an ER32 chuck put one holder in the file rather than six. The one identifier this mints is the assembly's, per stack. An assembly's id is derived upstream from its tool and holder, which cannot tell apart the same tool in the same holder at two stickouts — those would collapse and the second stickout would be lost. A minted guid costs a re-export a fresh set of assemblies; the tools and holders under them keep their catalog guids. `app/shared/export-input.ts` is what both formats read, extracted from `fusion-input.ts` now that there is a second consumer. One dialog serves both, `library-export-dialog.tsx` — only four strings differ between the two — and `ExportReport.holderWarnings` is `warnings`, meaning the same quantity for each: rows of the order list that reached the file. The exporter is imported on the press rather than at the top of the route: it carries 82 KB of pinned schema, and `vite.config.ts` pre-bundles the subpath so that import is a fetch rather than a discovery. `tool-support` moves to 0.6.0, which is what carries the Mastercam exporter. That release also changed what a holder stating no gauge length means: the Fusion exporter `filled`s it with the height of the shape it wrote rather than `dropped`ing it, so it is no longer a warning. `fusion-input.test.ts` now pins a stated gauge length its own dimensions contradict, which still is one, and pins the silence on the case that stopped being.
wevanscfi
approved these changes
Sep 14, 2026
`tool-support` 0.6.0 carries the Mastercam exporter, and `app-support` 0.1.6, `tool-drawing` 1.0.3 and `tool-scraper` 3.0.3 each depend on `^0.6.0`. A 0.x caret does not span a minor, so bumping `tool-support` alone left the older three asking for 0.4.0 and the install carried two copies — the same split `build: resolve the Toolpath packages onto one tool-support` closed before. `pnpm-lock.yaml` resolves one copy again, and the suite now runs against the published package rather than a local link.
wevanscfi
marked this pull request as ready for review
September 14, 2026 13:27
The dialog says `aria-modal="true"`, which tells a screen reader the page behind it is inert, and nothing kept that promise: Tab walked straight onto the order list underneath while the reader still announced the dialog, and opening it left the focus on the button behind the overlay. The kit's `Dialog` is the component to reach for and does not fit — it is an alert whose `confirm()` resolves to a boolean and closes on the press, where this dialog reads a name back off an input and goes on showing a report afterwards; its `@base-ui/react` primitive is not a dependency here. So the focus is handled beside the markup it governs, and the component now says which kit component it turned down and why. The name takes the focus on open, Tab cycles within the dialog, and the opener gets the focus back when it closes. Three tests pin those, because the markup makes the claim whether or not the behaviour is there.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
The order list leaves as a Mastercam
.TOOLDBas well as a Fusion library. Theexporter is not this application's — a
.TOOLDBis a SQLite database carryingMastercam's own 79-table schema, pinned upstream from a real library — so what
is here is the seam,
app/shared/mastercam-input.ts.Stacked on #9. Based on
paul/tool_catalog, so the diff here is theMastercam work alone. GitHub will retarget it to
mainwhen #9 merges.Why it reads differently from the Fusion seam
Fusion embeds a holder inside the tool record, so one tool in two holders is
two records, and
fusion-input.tsmints a guid per stack to keep them apart.Mastercam's schema is relational —
TlToolholds the tool,TlAssemblyjoinsit to a holder — so the order list goes in grouped: one entry per distinct
tool carrying one set-up per stack, one entry per distinct holder, under the
catalog's own guids. Six stacks sharing an ER32 chuck put one holder in the
file rather than six, which is what a machinist sees in Mastercam's own tree.
The one guid this mints
An assembly's identifier is derived upstream from its tool and holder, which is
stable across re-exports but cannot tell apart the same tool in the same holder
at two different stickouts — those two would collapse into one assembly and the
second stickout would be lost silently. So every set-up states its own guid,
minted per stack. The cost is that a re-export is a fresh set of assemblies; the
tools and holders under them keep their catalog guids and do update.
The extraction
app/shared/export-input.tsis what both formats read, pulled out offusion-input.tsnow that there is a second consumer — the repo's rule beingthat the second consumer is the trigger and a copy is a divergence with a delay
on it. It stays inside the application rather than moving to
packages/,because everything in it reaches for this catalog's own record types.
One dialog serves both,
library-export-dialog.tsx: only four strings differbetween a Fusion export and a Mastercam one.
ExportReport.holderWarningsisnow
warnings, meaning the same quantity for each — rows of the order list thatreached the file.
Loaded on the press
The exporter is imported by a dynamic
import()in the button handler ratherthan at the top of the route: it carries 82 KB of pinned schema before a single
tool, and every visitor to the order list would otherwise download it to find
out whether they wanted it.
vite.config.tspre-bundles the subpath so thatimport is a fetch rather than a discovery mid-session.
The version move, and why it is four packages
tool-support0.6.0 is what carriesexport/mastercam. Bumping it alone is notenough:
app-support,tool-drawingandtool-scrapereach depended on^0.5.0, and a0.xcaret does not span a minor, so the install carried twocopies of
tool-support— the split #10 closed, reopened. They move together to0.1.6, 1.0.3 and 3.0.3, each on
^0.6.0, and the lockfile resolves one copy.A behaviour change that came with the bump
tool-support0.5.0 changed what a holder stating no gauge length means to theFusion exporter: it used to
dropthe gauge length and leave Fusion to ask, andnow
fills it with the height of the shape it exported — a real number ratherthan a gap. A
fillednote is the format's own convention and is deliberatelynot surfaced, so that case stopped being a warning and its test failed against
0.6.0.
fusion-input.test.tsnow pins the case that still raises something a shop mustact on — a stated gauge length its own published dimensions contradict — and
pins the silence on the case that stopped being one. This is a Fusion
behaviour change riding in on the bump, not something the Mastercam work did.
Tests
app/shared/mastercam-input.test.ts— the grouping, the minted assembly guid,the notes read back per row.
apps/catalog/tests/on-the-part.spec.ts— a separate end-to-end test from theFusion one, because a
.TOOLDBis a database: it opens the downloaded filewith
node:sqliteand runsPRAGMA integrity_check, which is the only way tocatch a b-tree written slightly wrong. It also proves the dynamic
import()behind the press resolves in a real browser.
pnpm checkgreen (check-style, lint, build, check-types, 1,509 unit tests),and both export e2e tests pass — all of it against the published 0.6.0
rather than a local link.