Repository navigation
fix(desktop): standard parts are told by SolidCraft's library and cannot be forged by a description - #356
Open
ManuelStaggl wants to merge 6 commits into
Open
fix(desktop): standard parts are told by SolidCraft's library and cannot be forged by a description#356ManuelStaggl wants to merge 6 commits into
ManuelStaggl wants to merge 6 commits into
Conversation
… part, not 12 named families
Audit S-01, G2, N-normteile-policy-1. The mirror told parts.insert components by a fixed list of
12 family names; SolidCraft 0.40.1 has 13. The countersunk screws partbuddy_mechanism puts in went
to print check, plate and export as printed bodies while the tool said they were standard parts.
The mirror now reads parts.library with the components' metadata and takes a description for a
part when it is a family's name, one of its sizes and a length. A family SolidCraft adds is known
without a change here; a text that only begins like a family ("Hex nut holder") is no part.
Measured against SolidCraft 0.40.1 (tools/audit, normteile-policy): families recognised 12/13 ->
13/13 (185 of 185 over every size); screw joint with head countersunk: structure.standardParts
[] -> [Body1, Body2], STL of the exported bodies 6084 -> 1364 triangles (block and plate alone:
1364).
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…ard part
Audit H-01. PartBuddy tells the parts SolidCraft's library put in by their component's description,
and the assistant could write that field: component.metadata.set {description: "Hex nut M3"} on a
lid 0.3 mm thick took the lid out of print check, plate and export.
The policy now refuses component.metadata.set with a description, in both forms SolidCraft 0.40.1
takes (description, values.description) and as a batch step. Other properties, component.rename
and free properties stay allowed; measured, none of them makes a body a standard part.
Measured (tools/audit, normteile-policy-metadata): decide() allow -> deny; after the attempt
structure.standardParts [Deckel] -> [], printed bodies [Box] -> [Box, Deckel], print check ready
-> block ("walls down to 0.3 mm").
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…t of printing Audit S-01 (same recognition for every caller). The to-buy list of the sharing package took every row of assembly.bom with a part number, whatever print check, plate and export made of its bodies. A printed component with a part number was listed to print and to buy. The list now keeps the rows whose components hold standard parts only, by the same structure.standardParts the export leaves out. Measured against SolidCraft 0.40.1: screw joint with two countersunk screws and a printed lid given part_number "ISO 4032 M3": rows listed 2 (2 x ISO 10642 M3x10, 1 x ISO 4032 M3) -> 1 (2 x ISO 10642 M3x10); the lid stays in print check (block) and export. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…SolidCraft runs it Review of the audit fix for H-01. The policy compared command ids exactly, SolidCraft reads them in any case: execute Component.Metadata.Set, Document.Metadata.Set with PartBuddy's own key, Edit.Checkpoint, Doc.recovery_list, Diagnostics.Crash_Reports and Settings.* were allowed and ran. A batch step named by id instead of command, and a batch reading its steps from a script file (path), passed every rule unseen. Every rule now sees the lower-case, trimmed id, normalised in one place for execute, batch steps and nested steps; a step's id is decided like its command; batch with a path is refused. Measured with SolidCraft 0.40.1 (headless): of 50 spellings of tool, command, argument and parameter names it runs a command id in any case, a step's id, and batch path; tool names, argument names and parameter keys only as written. decide() for those forms: allow -> deny; the description of the printed lid stays unset. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…hat very body for its part Review of the audit fix for S-01 and H-01. A component described as a library part made every body in it a standard part, so a printed lid moved, copied or built into a nut's component, or joined onto the nut, left print check, plate and export. A second channel, body names kept in the design's metadata, took a lid renamed to a remembered name. The list of parts to buy followed assembly.bom, whose rows the assistant can merge or empty through part number and BOM type. A failed parts.library switched the recognition off without a word. One recognition now, behind print check, plate, size list, export and the list to buy: - a library component counts only with the one body the library builds (all 13 families build one); - that body must have the shape SolidCraft builds for the description: solidcraft-cli builds the part alone and both are measured with inspect.measure (volume, area, faces, edges, vertices); - the names in the design's metadata are neither read nor written any more; - the parts to buy are these parts, counted by their placements, with SolidCraft's part number; - parts.library is read once per engine; whatever fails is logged and counts as printed. Measured with SolidCraft 0.40.1 (tools/audit): lid 0.3 mm and an M3 nut, print check before the steps "block". After move_bodies, copy_bodies, activate + box, combine join, box join, the nut removed and the lid moved in, a forged description, a rename into the remembered name: "ready" without the lid -> "block" with the lid in print check and export, in all 10 cases. Parts to buy with the lid given the nut's part number, the nut set to reference, the nut's part number emptied: nut missing or lid listed -> 1 nut, 2 washers in all cases. All 13 families and 185 of 185 sizes stay standard parts, a third of them turned; a part turned, hidden or resized differs from its reference by at most 6e-11. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
ManuelStaggl
force-pushed
the
fix/standard-parts-audit
branch
from
November 12, 2026 14:16
93206cc to
9f88b5d
Compare
…ept, and told by every face Second review of the audit fix for S-01 and H-01. The mirror waited for solidcraft-cli to build each new part (0.4 s for one, 4 s for 30, 43 s for all sizes, with every start of the app), a failed run was tried again with every mirror, and volume, area and three counts did not fix the shape: a ring of other radii and height met the M3 washer on all five to 2.6e-11. - The mirror no longer waits. A part without a reference counts as printed until it is built in the background; then the design is mirrored once more. Export, slicer, size list and the parts to buy wait for the references, so nothing leaves with a screw in it. - References are kept in the cache folder under the program's version, size and date. A part SolidCraft does not build is remembered with its reason; a run that gave no answer is not tried again for five minutes. A run ends after 20 s plus 2 s a part instead of 2 min. - A part asked for while it is being built is not built a second time. - A shape is also the area, outline and radius of each face, from inspect.measure of the face. model.faces and model.edges give mesh values, up to 2 % apart between a part straight and turned. - Every body left printed is logged with its name and the reason. Measured with SolidCraft 0.40.1 (tools/audit): the mirror's question for references 4 to 14 ms (before: 0.37 s to 43 s); background build 0.7 s for one part, 11 s for 30, 98 to 112 s for all 185 sizes, once per SolidCraft; after a restart 0.1 s from the file. A refused part (M3x5000): one run of 0.2 s, then none (before: one with every mirror). The ring is printed; 13 of 13 families and 185 of 185 sizes stay standard parts, a third of them turned. Two designs saved by the audit and opened again: 13 of 13 and 2 of 2 parts told. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
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.
Fixes the severity-A findings of the full audit (2026-11-12) on telling bought standard parts from printed bodies, and the gaps an independent review found in the first version of this change. Everything is measured with the audit harness (
tools/audit, casesnormteile-policy-*) against SolidCraft 0.40.1, headless.How a standard part is told now
One recognition (
boughtPartsinmirror.ts) stands behind print check, plate, size list, export and the list of parts to buy. A body is a standard part only whenparts.insertwrites: a family's name, one of its sizes and a length, all read fromparts.library(no list of names in PartBuddy);solidcraft-cli runbuilds the part alone, and both are measured withinspect.measure: volume and area, the counts of faces, edges and vertices, and of each face its area, the length of its outline and its radius (all within 1e-6).Whatever cannot be read, measured or built counts as printed and is logged with the body and the reason: a screw in the print check shows, a printed part missing from it does not. The mirror does not wait for a part being built; export, slicer, size list and the parts to buy do.
S-01 / G2 / N-normteile-policy-1: one of 13 library families was printed and exported
countersunk_socket_screwmissing)partbuddy_mechanism {kind: screw, head: countersunk}:structure.standardParts[][Body1, Body2]head: capThe tool's sentence "the screws are in the design as standard parts" is true for both heads.
mechanismTool.tsandmechanisms.tsare untouched.H-01: the assistant could turn a printed body into a "standard part"
execute component.metadata.set {component, description: "Hex nut M3"}took a 0.3 mm lid out of print check, plate and export. The policy refusescomponent.metadata.setwith a description (description,values.description, as a batch step). Since review point 2 the forged description would no longer work either: the lid is not shaped like the nut.decide()structure.standardPartsafter the attempt[Deckel][]Review
1. The policy compared command ids exactly; SolidCraft runs them in any case. Measured over 50 spellings of tool, command, argument and parameter names: SolidCraft takes a command id in any case (
Component.Metadata.Set,File.Export), a batch step's command asid, and a batch's steps from a script file (path); tool names, argument names and parameter keys only as written (Execute,Params,Path,Keyare unknown or ignored). Every rule now sees the lower-case, trimmed id, normalised in one place for execute, batch steps and nested steps; a step'sidis decided like itscommand;batchwith apathis refused.decide()forComponent.Metadata.Set,Document.Metadata.Setwith PartBuddy's key,Edit.Checkpoint,Doc.recovery_list,Diagnostics.Crash_Reports, a step{id: ...}andbatch {path}: allow -> deny. Test:agent.test.ts, "decides a command id in any spelling SolidCraft runs".2. Bodies in a library component counted unchecked. A box, a 0.3 mm lid (print check
block) and an M3 nut; the steps sent past the policy:component.move_bodiesof the lid into the nutcomponent.copy_bodiesinto the nutcomponent.activatethe nut +solid.boxsolid.combinejoin of a plate onto the nutsolid.box {operation: join}onto the nutsolid.removethe nut, lid moved inStage 2 comes from a reference, not from library dimensions: a world bounding box changes with the part's direction, volume and area do not (turned, hidden, resized: at most 6e-11 off the reference). What the reference costs and where it is kept: see the second review, point 1. Tests:
structure.test.ts("counts every body of a library component as printed…", "takes a body for the part only when it has the shape…"),partReference.test.ts,mirrorRevision.test.ts.3. Body names kept in the design's metadata. The key is neither read nor written any more; parts put in from the menu are library components like any other. Measured: key set to
["SHCS M3x12"], nut renamed, lid renamed toSHCS M3x12: the lid stays printed, the renamed nut stays a standard part. The policy still refuses writes to the key by its prefix.4. Parts to buy. No longer
assembly.bom: the list is the standard parts themselves, counted by their placements through subassemblies, with the part number SolidCraft gives the reference. A nut, a washer in a subassembly placed twice, a printed lid: with the lid givenpart_number: "ISO 4032 M3"(BOM: one row, components [2, 5], count 2), the nut set tobom_type: reference(BOM: no nut), the nut's part number emptied: the list is 1 x Hex nut M3, 2 x Plain washer M3 in every case. Test:structure.test.ts, "lists the parts to buy from the standard parts themselves".5. A failed
parts.libraryswitched the recognition off silently. A failed batch, a rejected request, no results and an empty library each write a line to the log; the library is read once per engine connection and again after a failure. Test:mirrorRevision.test.ts, "says so in the log when parts.library fails or is empty".6. A fallback to the former twelve names is left out. A family SolidCraft renames or a size it drops cannot be built by the installed SolidCraft, so there is nothing to hold the body against; a fallback by name alone would be the gap of point 2 again. Such a part counts as printed and is logged.
Second review
1. The reference blocked the mirror, and a failed run was tried again with every mirror.
part-references.jsonin the cache folder (kept under the program's version, size and date)Socket head cap screw M3x5000)Until a part's reference is there its body counts as printed, so for that moment the print check sees the screw. What leaves PartBuddy does not: export, send to slicer, the size list and the parts to buy read the standard parts anew and wait for their references. The build takes two runs now (how many faces a part has is known only once it is built), which is why it is slower than the one the review timed.
2. The same reference was built twice by the mirror and the list of parts to buy. A description being built is not started again; whoever waits, waits for the run that is under way.
3. Five numbers did not fix the shape. A ring of R 4.0251, r 3.3699, 1 mm high has the volume, area and counts of the M3 washer to 2.6e-11. The shape now also holds each face's area, outline and radius.
model.facesandmodel.edgeswere measured and are not used: they give values of the display mesh, up to 2 % apart between the same part straight and turned;inspect.measureof a face is exact. Measured: the ring, described as "Plain washer M3", stays printed; all 185 sizes stay standard parts, a third of them turned.4.
cliReferenceswas untested.partReference.test.ts, with the program's runs injected: a reference is kept and no process runs for it again; a refused part is remembered, also over a restart; a part that cannot be built lets the others stand; a run without an answer is tried again only after a while; the script file is removed; a background build asks for exactly one more mirror (mirrorRevision.test.ts: "mirrors the delivered revision again, once however often it is asked"); two askers, one build; the ring against the washer.5. Older designs. No saved design with standard parts lies in the repository (
apps/desktop/e2e,tools/fixtures,tools/templates,site: none). Measured instead on the two designs the audit saved on 2026-11-12 (families.sc, one part of each family;screw-cap.sc, a screw joint), opened again bysolidcraft-cli run --in: 13 of 13 and 2 of 2 parts are told after the rebuild. Which SolidCraft wrote them (0.40.0-rc.4 or 0.40.1) the files do not say.Still open
shortcut:inmirror.ts).screenshot {path},compare_picture {reference},document.metadata.set {properties}) and S-30 (C) are not part of this change.Not checked
e2e/solidcraft.contract.spec.ts) and the app itself were not started. Two of them depend on the reference fromsolidcraft-cliinside the app ("standard part" on a seatedSHCS M3x12, two standard parts after a screw joint); the same flows pass in the harness. One expectation changed: the screw joint test waits up to 30 s for the two "standard part" labels (they follow a mirror after the bodies show), as the other test already does.body "<name>" is described as "<description>" but is not that part (…)or…, which SolidCraft did not build to hold it against (<reason>).parts.insert.🤖 Generated with Claude Code