Retire legacy reference data and the external command catalog (#302)

- Remove xtask/data/fusion-catalog.tsv and xtask/data/fusion-ids.tsv.
- Remove the legacy command-id table (crates/engine/src/legacy_ids.rs) and its use in
  find_command and in the shortcut, recents and pinned-command loaders. Only SolidCraft's
  dotted ids name commands; any other id is an unknown command.
- Boundary Fill's id becomes solid.boundary_fill.
- Replace the parity report with SolidCraft's own feature checklist: `cargo xtask features`
  writes docs/features.md from the command registry.
- docs/oracle.md, docs/step-import.md (corpus section) and docs/iges-import.md: reference
  results are being rebuilt on analytic and open-source (FreeCAD) values; see #292.
  `cargo xtask oracle` and `cargo xtask step-corpus [--iges]` write these placeholders.
- AGENTS.md, CLAUDE.md, CONTRIBUTING.md, README.md, ROADMAP.md and the book describe
  SolidCraft as independent, with reference tests on analytic values and open-source tools,
  and agents do not drive or extract data from commercial CAD products.


Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-12 11:19:15 -04:00
1 parent c7f0139ad4
commit 3b8028a040
32 files changed
+695 -2324

No files matched your search

+2 -2
View File
@@ -11,7 +11,7 @@ use crate::params::{bad, bool_, expr, req_expr, str_, string_list, vec3};
use crate::{Result, Session};
pub static COMMANDS: &[CommandSpec] = &[
CommandSpec::new("SurfaceSculpt", "Boundary Fill", boundary_fill).at("SOLID", "CREATE").icon("boundary_fill").params(
CommandSpec::new("solid.boundary_fill", "Boundary Fill", boundary_fill).at("SOLID", "CREATE").icon("boundary_fill").params(
"tools: [bodies]; cells: [[x,y,z] a point inside each cell to fill (a cell: inside some tools, outside the rest)]; operation?: new|join|cut|intersect; remove_tools?: bool",
),
CommandSpec::new("solid.coil", "Coil", coil).at("SOLID", "CREATE").icon("coil").params(
@@ -422,7 +422,7 @@ pub(super) fn snap_point(s: &Session, kind: &str, at: Vec3) -> Option<Vec3> {
}
fn boundary_fill(s: &mut Session, p: &Value) -> Result<Value> {
let cmd = "SurfaceSculpt";
let cmd = "solid.boundary_fill";
let tools = string_list(p, "tools");
let st = s.model.state();
if tools.is_empty() || tools.len() > 64 || tools.iter().any(|t| st.body(t).is_none()) {
+1 -3
View File
@@ -1,6 +1,6 @@
//! The command registry. Ids are SolveCraft's own dotted ids (`solid.extrude`,
//! `sketch.rectangle.two_point`); the toolbar placement (`tab`, `panel`) follows the familiar
//! Design workspace layout. Ids used before the rename still resolve (`legacy_ids`).
//! Design workspace layout.
/// The params-doc note of every command that adds sketch geometry (see `sketch::created`).
macro_rules! created_doc {
@@ -180,7 +180,5 @@ pub fn command_specs() -> Vec<&'static CommandSpec> {
pub fn find_command(id: &str) -> Option<&'static CommandSpec> {
let all = command_specs();
// Ids from before the rename still find their command.
let id = crate::legacy_ids::current_id(id);
all.iter().find(|c| c.id == id).or_else(|| all.iter().find(|c| c.id.eq_ignore_ascii_case(id))).copied()
}
+2 -2
View File
@@ -184,7 +184,7 @@ fn base(r: &mut Rng) -> Step {
("sketch.line", json!({"points": pts})),
("sketch.arc.three_point", json!({"start": [0, h], "end": [0, 0], "through": [-bulge, h / 2.0]})),
("sketch.finish", json!({})),
("Extrude", json!({"distance": d})),
("solid.extrude", json!({"distance": d})),
],
)
}
@@ -198,7 +198,7 @@ fn base(r: &mut Rng) -> Step {
("sketch.create", json!({"plane": "XZ"})),
("sketch.rectangle.two_point", json!({"p0": [r0, 0], "p1": [r1, h]})),
("sketch.finish", json!({})),
("Revolve", json!({"axis": "Z", "angle": angle})),
("solid.revolve", json!({"axis": "Z", "angle": angle})),
],
)
}
-236
View File
@@ -1,236 +0,0 @@
//! Legacy migration: the command ids SolveCraft used before 2026-10-09, when many commands
//! carried the id of the matching command in another CAD program, and the dotted ids that
//! replaced them. This is the one place the old ids live. Old scripts, recipes, control-channel
//! calls, saved shortcuts and toolbar layouts keep working: `find_command` and the preference
//! loaders map an old id through `current_id`. `solvecraft-tools/rename_ids.sh` converts a
//! worktree with this same table.
/// (old id, current id).
pub const LEGACY_IDS: &[(&str, &str)] = &[
("AsBuiltPositionsCmd", "component.revert_position"),
("FusionCreateComponentsFromBodiesCommand", "component.from_bodies"),
("FusionCreateNewComponentCommand", "component.create"),
("SnapshotCmd", "component.capture_position"),
("FusionShowDesignConfigPanelCmd", "config.table"),
("FusionStartDesignConfigModeCmd", "config.configure"),
("FusionComputeAllCommand", "timeline.compute_all"),
("FusionDeleteCommand", "timeline.delete"),
("FusionRenameTimelineEntryCommand", "timeline.rename"),
("RedoCommand", "edit.redo"),
("UndoCommand", "edit.undo"),
("timeline.rollTo", "timeline.roll_to"),
("AlignCmd", "solid.align"),
("EmbossCmd", "solid.emboss"),
("FusionReplaceFaceCommand", "solid.replace_face"),
("FusionRibCommand", "solid.rib"),
("FusionWebCommand", "solid.web"),
("PrimitiveCoil", "solid.coil"),
("SoftDeleteCommand", "solid.remove"),
("ConstructionPlaneAtAngleCommand", "construct.plane.at_angle"),
("ConstructionPlaneOffsetFromPlaneCommand", "construct.plane.offset"),
("Extrude", "solid.extrude"),
("FusionChamferCommand", "solid.chamfer"),
("FusionCombineCommand", "solid.combine"),
("FusionDraftCommand", "solid.draft"),
("FusionFilletEdgesCommand", "solid.fillet"),
("FusionHoleCommand", "solid.hole"),
("FusionMoveCommand", "solid.move"),
("FusionOffsetFacesCommand", "solid.offset_face"),
("FusionPressPullCommand", "solid.press_pull"),
("FusionShellBodyCommand", "solid.shell"),
("FusionSplitBodyCommand", "solid.split_body"),
("FusionThreadCommand", "solid.thread"),
("MirrorCommand", "solid.mirror"),
("ModifyScale", "solid.scale"),
("PatternCircular", "solid.pattern.circular"),
("PatternOnPath", "solid.pattern.path"),
("PatternRectangular", "solid.pattern.rectangular"),
("PrimitiveBox", "solid.box"),
("PrimitiveCylinder", "solid.cylinder"),
("PrimitivePipe", "solid.pipe"),
("PrimitiveSphere", "solid.sphere"),
("PrimitiveTorus", "solid.torus"),
("Revolve", "solid.revolve"),
("SolidLoft", "solid.loft"),
("StockModelCommand", "solid.bounding_solid"),
("Sweep", "solid.sweep"),
("ExportCommand", "file.export"),
("FusionImportCommandFromToolbar", "file.insert_step"),
("FusionSaveAsSTLCommand", "file.save_mesh"),
("NewDocumentCommand", "file.new"),
("ParaMeshInsertAlignCommand", "file.insert_mesh"),
("SaveDocumentAsCommand", "file.save_as"),
("SaveDocumentCommand", "file.save"),
("AppearanceCommand", "appearance.assign"),
("MeasureCommand", "inspect.measure"),
("PhysicalMaterialCommand", "material.assign"),
("FusionMotionRelationshipCommand", "joint.motion_link"),
("FusionMoveJointsCommand", "joint.drive"),
("InterferenceCheckCommand", "inspect.interference"),
("JointAsBuiltCmd", "joint.as_built"),
("JointAssembleCmdNew", "joint.create"),
("JointOrigin", "joint.origin"),
("RigidGroupCmd", "joint.rigid_group"),
("ContactSetCmd", "contact.create"),
("DisableAllContactCmd", "contact.disable_all"),
("EnableAllContactCmd", "contact.enable_all"),
("EnableContactSetsCmd", "contact.enable_sets"),
("FusionMotionStudyCommand", "motion.study"),
("ChangeParameterCommand", "parameters.change"),
("FusionFastenersCommand", "parts.fastener"),
("FusionAssignPlasticRuleCommand", "plastic.assign_rule"),
("FusionBossCommand", "plastic.boss"),
("FusionLipCommand", "plastic.lip"),
("FusionManagePlasticRuleCommand", "plastic.manage_rules"),
("FusionRestCommand", "plastic.rest"),
("FusionSnapFitCommand", "plastic.snap_fit"),
("FusionHalfSectionViewCommand", "inspect.section"),
("ConvertToSheetMetalCmd", "sheet.convert"),
("FusionSheetMetalFlangeCommand", "sheet.flange"),
("FusionSheetMetalFlatPatternCmd", "sheet.flat_pattern"),
("FusionSheetMetalHemFlangeCommand", "sheet.hem"),
("FusionSheetMetalRulesCommand", "sheet.manage_rules"),
("FusionSheetmetalUnfoldCommand", "sheet.unfold"),
("SheetMetalFoldCmd", "sheet.fold"),
("FusionAddCanvasCommand", "canvas.insert"),
("FusionAddEditDecalCommand", "canvas.decal"),
("ConstraintSmooth", "sketch.constraint.curvature"),
("SketchAutoConstrainAndFinish", "sketch.finish_auto_constrain"),
("SketchAutoConstraintAndDimCmd", "sketch.auto_constrain"),
("SketchAutoConstraintAndDimFromDatumCmd", "sketch.auto_constrain_from_datum"),
("SketchConstrainer", "sketch.constrainer"),
("SketchPolygonConstraintCmd", "sketch.constraint.polygon"),
("ArcTangent", "sketch.arc.tangent"),
("BlendG1CurveSketchCmd", "sketch.blend_curve"),
("CircleElipse", "sketch.ellipse"),
("CircleTanTanRadius", "sketch.circle.two_tangent"),
("CircleThreeTangent", "sketch.circle.three_tangent"),
("ConicCurveCmd", "sketch.conic"),
("DrawCVMSpline3D", "sketch.spline.control_point"),
("DrawCVMSpline5D", "sketch.spline.control_point_5"),
("DrawSpline", "sketch.spline.fit_point"),
("MTextCmd", "sketch.text"),
("ShapeArcSlotCenterTwoPoint", "sketch.slot.arc_center"),
("ShapeArcSlotThreePoint", "sketch.slot.arc_three_point"),
("ShapeSlotCenterPoint", "sketch.slot.center_point"),
("SketchMidpointLine", "sketch.line.midpoint"),
("ImportDxfFileCommand", "sketch.insert_dxf"),
("SketchImportSVG", "sketch.insert_svg"),
("FusionCenterOfMassCommand", "inspect.center_of_mass"),
("FusionCurvatureCombAnalysisCommand", "inspect.curvature_comb"),
("FusionIsoCurveAnalysisCommand", "inspect.isocurve"),
("FusionMinimumRadiusAnalysisCommand", "inspect.minimum_radius"),
("BreakSketchCmd", "sketch.break"),
("ChamferSketchDistanceAngle", "sketch.chamfer.distance_angle"),
("ChamferSketchDistanceDistance", "sketch.chamfer.two_distance"),
("ChamferSketchEqualDistance", "sketch.chamfer.equal_distance"),
("CircularSketchPatternCommand", "sketch.pattern.circular"),
("ExtendSketchCmd", "sketch.extend"),
("FilletSketchCmd", "sketch.fillet"),
("MirrorSketchCommand", "sketch.mirror"),
("Offset", "sketch.offset"),
("RectangularSketchPatternCommand", "sketch.pattern.rectangular"),
("SketchScaleCmd", "sketch.scale"),
("TrimSketchCmd", "sketch.trim"),
("FitCurvesToSectionCommand", "sketch.fit_curves_to_section"),
("Include3DGeometry", "sketch.include_3d"),
("IntersectCmd", "sketch.intersect"),
("IntersectionCurve", "sketch.intersection_curve"),
("ProjectNewCmd", "sketch.project"),
("ProjectToSurface", "sketch.project_to_surface"),
("SketchIsoparametricCurve", "sketch.isoparametric_curve"),
("SpunProfileCmd", "sketch.spun_profile"),
("ArcCenterTwoPoint", "sketch.arc.center_point"),
("ArcThreePoint", "sketch.arc.three_point"),
("CircleCenterRadius", "sketch.circle.center"),
("CircleThreePoint", "sketch.circle.three_point"),
("CircleTwoPoint", "sketch.circle.two_point"),
("ConstraintCoincident", "sketch.constraint.coincident"),
("ConstraintCollinear", "sketch.constraint.collinear"),
("ConstraintConcentric", "sketch.constraint.concentric"),
("ConstraintEqual", "sketch.constraint.equal"),
("ConstraintFix", "sketch.constraint.fix"),
("ConstraintHorizontalVertical", "sketch.constraint.horizontal_vertical"),
("ConstraintMidPoint", "sketch.constraint.midpoint"),
("ConstraintParallel", "sketch.constraint.parallel"),
("ConstraintPerpendicular", "sketch.constraint.perpendicular"),
("ConstraintSymmetry", "sketch.constraint.symmetry"),
("ConstraintTangent", "sketch.constraint.tangent"),
("DrawPoint", "sketch.point"),
("DrawPolyline", "sketch.line"),
("ShapePolygonCircumscribed", "sketch.polygon.circumscribed"),
("ShapePolygonEdge", "sketch.polygon.edge"),
("ShapePolygonInscribed", "sketch.polygon.inscribed"),
("ShapeRectangleCenter", "sketch.rectangle.center"),
("ShapeRectangleThreePoint", "sketch.rectangle.three_point"),
("ShapeRectangleTwoPoint", "sketch.rectangle.two_point"),
("ShapeSlotCenterToCenter", "sketch.slot.center_to_center"),
("ShapeSlotOverall", "sketch.slot.overall"),
("SketchActivate", "sketch.edit"),
("SketchCreate", "sketch.create"),
("SketchDimension", "sketch.dimension"),
("SketchStop", "sketch.finish"),
("FusionAccessibilityAnalysisCommand", "inspect.accessibility"),
("FusionCurvatureMapAnalysisCommand", "inspect.curvature_map"),
("FusionDraftAnalysisCommand", "inspect.draft"),
("FusionEnvironmentMapAnalysisCommand", "inspect.environment_map"),
("FusionZebraAnalysisCommand", "inspect.zebra"),
("FusionExtendCommand", "surface.extend"),
("FusionSurfacePatchCommand", "surface.patch"),
("FusionSurfaceStitchCommand", "surface.stitch"),
("FusionSurfaceThickenCommand", "surface.thicken"),
("FusionSurfaceTrimCommand", "surface.trim"),
("FusionSplitFaceCommand", "solid.split_face"),
("ConstructionAxisThroughCylinderCommand", "construct.axis.through_cylinder"),
("ConstructionAxisNormalToFaceCommand", "construct.axis.normal_to_face"),
("ConstructionAxisFromTwoPlanesCommand", "construct.axis.two_planes"),
("ConstructionAxisThroughTwoPointsCommand", "construct.axis.two_points"),
("ConstructionAxisThroughEdgeCommand", "construct.axis.edge"),
("ConstructionPointFromPointCommand", "construct.point.vertex"),
("ConstructionPointThroughTwoEdgesCommand", "construct.point.two_edges"),
("ConstructionPointFromThreePlanesCommand", "construct.point.three_planes"),
("ConstructionPointFromCircleOrSphereCommand", "construct.point.center"),
("ConstructionPointAtEdgeAndPlaneCommand", "construct.point.edge_plane"),
("ConstructionPointAlongPathCommand", "construct.point.along_path"),
("ConstructionMidPlaneCommand", "construct.plane.midplane"),
("ConstructionPlaneFromTwoEdgesCommand", "construct.plane.two_edges"),
("ConstructionPlaneFromThreePointsCommand", "construct.plane.three_points"),
("ConstructionTangentPlaneCommand", "construct.plane.tangent"),
("ConstructionPlaneAlongPathCommand", "construct.plane.along_path"),
];
/// The current id for a command id that may be a legacy one (unchanged otherwise).
pub fn current_id(id: &str) -> &str {
LEGACY_IDS.iter().find(|(old, _)| old.eq_ignore_ascii_case(id)).map(|(_, new)| *new).unwrap_or(id)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_legacy_id_names_a_command() {
let unknown: Vec<&str> =
LEGACY_IDS.iter().filter(|(_, new)| crate::find_command(new).is_none_or(|c| c.id != *new)).map(|(_, new)| *new).collect();
// The construction set and Split Face are on a branch not yet merged when the table was made.
let pending = ["solid.split_face"];
let unknown: Vec<&str> = unknown
.into_iter()
.filter(|n| {
!pending.contains(n)
&& !n.starts_with("construct.axis")
&& !n.starts_with("construct.point")
&& ![
"construct.plane.midplane",
"construct.plane.two_edges",
"construct.plane.three_points",
"construct.plane.tangent",
"construct.plane.along_path",
]
.contains(n)
})
.collect();
assert!(unknown.is_empty(), "{unknown:?}");
assert_eq!(crate::find_command("SketchCreate").map(|c| c.id), Some("sketch.create"));
}
}
-1
View File
@@ -10,7 +10,6 @@
pub mod cmd;
pub mod frames;
pub mod fuzz;
pub mod legacy_ids;
pub mod licences;
pub mod occurrences;
pub mod params;
+15 -4
View File
@@ -512,11 +512,22 @@ fn registry_is_consistent() {
let n = ids.len();
ids.dedup();
assert_eq!(ids.len(), n, "duplicate command ids");
assert!(find_command("extrude").is_some(), "case-insensitive lookup");
assert_eq!(find_command("Solid.Extrude").map(|c| c.id), Some("solid.extrude"), "case-insensitive lookup");
let s = Session::default();
assert!(!find_command("sketch.line").unwrap().info(&s).enabled);
}
/// Only SolidCraft's own dotted ids name commands; other ids are unknown commands.
#[test]
fn only_own_ids_name_commands() {
for old in ["Extrude", "SketchCreate", "FusionFilletEdgesCommand"] {
assert!(find_command(old).is_none(), "{old}");
let mut s = Session::default();
let err = s.execute(old, &serde_json::json!({})).unwrap_err();
assert!(matches!(err, crate::EngineError::UnknownCommand(_)), "{old}: {err}");
}
}
#[test]
fn sample_design_builds() {
let mut s = Session::default();
@@ -2336,15 +2347,15 @@ fn boundary_fill_cells() {
let mut s = Session::default();
run(&mut s, "solid.box", json!({"length": 20, "width": 20, "height": 20, "body_name": "A"}));
run(&mut s, "solid.box", json!({"corner": [10, 0, 0], "length": 20, "width": 20, "height": 20, "body_name": "B"}));
let r = run(&mut s, "SurfaceSculpt", json!({"tools": ["A", "B"], "cells": [[15, 10, 10]], "remove_tools": true}));
let r = run(&mut s, "solid.boundary_fill", json!({"tools": ["A", "B"], "cells": [[15, 10, 10]], "remove_tools": true}));
let m = run(&mut s, "inspect.measure", json!({}));
assert_eq!(m["body_count"], 1, "{r} {m}");
assert!(rel(m["total"]["volume_mm3"].as_f64().unwrap_or(0.0), 10.0 * 20.0 * 20.0) < 1e-9);
run(&mut s, "edit.undo", json!({}));
run(&mut s, "SurfaceSculpt", json!({"tools": ["A", "B"], "cells": [[5, 10, 10], [25, 10, 10]], "remove_tools": true}));
run(&mut s, "solid.boundary_fill", json!({"tools": ["A", "B"], "cells": [[5, 10, 10], [25, 10, 10]], "remove_tools": true}));
let m = run(&mut s, "inspect.measure", json!({}));
assert!(rel(m["total"]["volume_mm3"].as_f64().unwrap_or(0.0), 2.0 * 10.0 * 20.0 * 20.0) < 1e-9, "{m}");
assert!(s.execute("SurfaceSculpt", &json!({"tools": ["A"], "cells": [[100, 100, 100]]})).is_err());
assert!(s.execute("solid.boundary_fill", &json!({"tools": ["A"], "cells": [[100, 100, 100]]})).is_err());
}
/// Rectangles name their sides and corners, so they can be dimensioned without inspecting the