Rename SolveCraft to SolidCraft everywhere, with compatibility shims (#389)

* WIP deep rename (not for push)

* WIP2

* WIP3

* WIP4 wxs fix

* rustfmt

* Rename the remaining identifiers in merged crash-report code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RjGw4gA5ZvKrU8MQP6sBgT

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
bherbruckandClaude Opus 5.5 authored and GitHub committed 2026-10-12 17:17:01 -04:00
1 parent 27415e4dd7
commit 296683229d
464 files changed
+3408 -2956

No files matched your search

+43 -43
View File
@@ -28,8 +28,8 @@ fn coincident_independent_primitives_keep_their_own_semantic_faces() {
let state = s.model.state();
let a = state.body("Cube").unwrap();
let b = state.body("Other").unwrap();
let a_names = solvecraft_doc::naming::face_names(a);
let b_names = solvecraft_doc::naming::face_names(b);
let a_names = solidcraft_doc::naming::face_names(a);
let b_names = solidcraft_doc::naming::face_names(b);
assert!(a_names.contains(&format!("F{first}:+z")));
assert!(b_names.contains(&format!("F{second}:+z")));
assert!(!b_names.contains(&format!("F{first}:+z")));
@@ -55,7 +55,7 @@ fn nested_definition_dag_and_histories_are_independent() {
near(volume(&mut s, parent), 24.0);
near(volume(&mut s, new), 16.0);
let saved = s.doc.to_json();
let reopened = solvecraft_doc::Document::from_json(&saved).unwrap();
let reopened = solidcraft_doc::Document::from_json(&saved).unwrap();
assert_eq!(reopened.occurrences.iter().filter(|o| o.parent == new).count(), 2);
}
@@ -144,7 +144,7 @@ fn generated_feature_parameter_dependencies_are_independent() {
.doc
.features
.iter()
.find(|f| f.component == clone && matches!(f.kind, solvecraft_doc::FeatureKind::Box { .. }))
.find(|f| f.component == clone && matches!(f.kind, solidcraft_doc::FeatureKind::Box { .. }))
.unwrap()
.param_names
.clone();
@@ -195,12 +195,12 @@ fn copied_sheet_base_targets_its_own_sketch_history() {
let copied = copy(&mut s, part);
let new = copied["component"].as_u64().unwrap();
near(volume(&mut s, new), source_volume);
let clone_sketch = s.doc.features.iter().find(|f| f.component == new && matches!(f.kind, solvecraft_doc::FeatureKind::Sketch { .. })).unwrap().id;
let clone_sketch = s.doc.features.iter().find(|f| f.component == new && matches!(f.kind, solidcraft_doc::FeatureKind::Sketch { .. })).unwrap().id;
assert_ne!(clone_sketch, sketch);
let base = s.doc.features.iter().find(|f| f.component == new && matches!(f.kind, solvecraft_doc::FeatureKind::SheetBase { .. })).unwrap();
let base = s.doc.features.iter().find(|f| f.component == new && matches!(f.kind, solidcraft_doc::FeatureKind::SheetBase { .. })).unwrap();
assert_eq!(base.kind.input_sketches(), vec![clone_sketch]);
// Mutate only source geometry, then verify the copied base remains unchanged.
if let solvecraft_doc::FeatureKind::Sketch { sketch, .. } = &mut s.doc_mut().feature_mut(sketch).unwrap().kind {
if let solidcraft_doc::FeatureKind::Sketch { sketch, .. } = &mut s.doc_mut().feature_mut(sketch).unwrap().kind {
for p in &mut sketch.points {
p.pos.x *= 2.0;
}
@@ -223,8 +223,8 @@ fn renamed_pattern_outputs_and_later_body_operands_follow_clone() {
near(volume(&mut s, new), 24.0);
let state = s.model.state();
let target = state.bodies.iter().find(|b| b.name == "Custom Output (copy)").unwrap();
near(solvecraft_kernel::measure(&target.body).unwrap().centroid.y, 6.0);
assert_eq!(s.doc.features.iter().filter(|f| f.component == new && matches!(f.kind, solvecraft_doc::FeatureKind::Move { .. })).count(), 1);
near(solidcraft_kernel::measure(&target.body).unwrap().centroid.y, 6.0);
assert_eq!(s.doc.features.iter().filter(|f| f.component == new && matches!(f.kind, solidcraft_doc::FeatureKind::Move { .. })).count(), 1);
}
#[test]
@@ -233,15 +233,15 @@ fn configuration_rows_follow_copied_parameters_material_and_strict_face_lineage(
let part = component(&mut s, "Configured");
let source = box2(&mut s);
let length = s.doc.feature(source).unwrap().param_names[0].clone();
let target = solvecraft_doc::config::ConfigFaceTarget {
let target = solidcraft_doc::config::ConfigFaceTarget {
body: "Cube".into(),
origin_feature: source,
name: format!("F{source}:+z"),
point: solvecraft_geom::Vec3::new(1.0, 1.0, 2.0),
point: solidcraft_geom::Vec3::new(1.0, 1.0, 2.0),
certificate: None,
};
run(&mut s, "config.configure", json!({"params":[length],"materials":["Cube"],"component_appearances":[part],"face_appearances":[target]}));
let face_key = s.doc.config_key(&solvecraft_doc::config::Column::FaceAppearance(target.clone()));
let face_key = s.doc.config_key(&solidcraft_doc::config::Column::FaceAppearance(target.clone()));
run(
&mut s,
"config.row",
@@ -271,26 +271,26 @@ fn configured_extrude_cap_copy_keeps_independent_semantic_lineage() {
run(&mut s, "sketch.finish", json!({}));
let feature = run(&mut s, "solid.extrude", json!({"distance":2}))["feature"].as_u64().unwrap();
let body_name = s.model.state().bodies.last().unwrap().name.clone();
let target = solvecraft_doc::config::ConfigFaceTarget {
let target = solidcraft_doc::config::ConfigFaceTarget {
body: body_name,
origin_feature: feature,
name: format!("F{feature}:top"),
point: solvecraft_geom::Vec3::new(1.0, 1.0, 2.0),
point: solidcraft_geom::Vec3::new(1.0, 1.0, 2.0),
certificate: None,
};
run(&mut s, "config.configure", json!({"face_appearances":[target]}));
let key = s.doc.config_key(&solvecraft_doc::config::Column::FaceAppearance(target));
let key = s.doc.config_key(&solidcraft_doc::config::Column::FaceAppearance(target));
run(&mut s, "config.row", json!({"name":"Painted","values":{key:{"name":"Custom","color":[0,255,0],"opacity":1.0}}}));
let copied = copy(&mut s, part)["component"].as_u64().unwrap();
run(&mut s, "config.activate", json!({"row":"Painted"}));
let state = s.model.state();
let body = state.bodies.iter().find(|b| b.component == copied).unwrap();
assert!(solvecraft_doc::naming::face_names(body).contains(&format!("F{}:top", body.feature)));
assert!(solidcraft_doc::naming::face_names(body).contains(&format!("F{}:top", body.feature)));
assert!(s.doc.face_colors(body).iter().any(|(_, look)| look.color == [0, 255, 0]));
assert!(s.doc.configuration_style_status(&state).is_ok());
let saved = s.doc.to_json();
let reopened = solvecraft_doc::Document::from_json(&saved).unwrap();
let mut model = solvecraft_doc::Model::default();
let reopened = solidcraft_doc::Document::from_json(&saved).unwrap();
let mut model = solidcraft_doc::Model::default();
model.evaluate(&reopened);
assert!(reopened.configuration_style_status(&model.state()).is_ok());
}
@@ -310,8 +310,8 @@ fn selected_second_occurrence_emboss_copy_remaps_target_and_author_paths_and_reo
let copied = run(&mut s, "component.paste_new", json!({"component":part,"occurrence":second,"path":[second],"translate":[20,0,0]}));
let new = copied["component"].as_u64().unwrap();
let placement = copied["occurrence"].as_u64().unwrap();
let emboss = s.doc.features.iter().find(|f| f.component == new && matches!(f.kind, solvecraft_doc::FeatureKind::Emboss { .. })).unwrap();
let solvecraft_doc::FeatureKind::Emboss { face: Some(face), .. } = &emboss.kind else { panic!("missing selected face") };
let emboss = s.doc.features.iter().find(|f| f.component == new && matches!(f.kind, solidcraft_doc::FeatureKind::Emboss { .. })).unwrap();
let solidcraft_doc::FeatureKind::Emboss { face: Some(face), .. } = &emboss.kind else { panic!("missing selected face") };
assert_eq!(face.body, "Sleeve (copy)");
assert_eq!(face.path, vec![placement]);
assert_eq!(face.author_path, vec![placement]);
@@ -321,7 +321,7 @@ fn selected_second_occurrence_emboss_copy_remaps_target_and_author_paths_and_reo
run(&mut s, "parameters.change", json!({"name":height,"expression":"30 mm"}));
near(volume(&mut s, new), clone_volume);
assert!(volume(&mut s, part) > original_volume);
let mut reopened = Session { doc: solvecraft_doc::Document::from_json(&s.doc.to_json()).unwrap().into(), ..Session::default() };
let mut reopened = Session { doc: solidcraft_doc::Document::from_json(&s.doc.to_json()).unwrap().into(), ..Session::default() };
reopened.refresh();
assert!(reopened.doc.features.iter().all(|f| reopened.model.result(f.id).is_some_and(|r| r.error.is_none())));
near(volume(&mut reopened, new), clone_volume);
@@ -339,7 +339,7 @@ fn reassigned_sample_plate_paste_new_preserves_complex_frozen_geometry() {
run(&mut s, "occurrence.ground", json!({"occurrence":occurrence,"grounded":true}));
let original_volume = volume(&mut s, part);
let source_mesh = s.model.state().body(&body).unwrap().mesh();
let boss_probe = solvecraft_geom::Vec3::new(40.0, 35.0, 12.0);
let boss_probe = solidcraft_geom::Vec3::new(40.0, 35.0, 12.0);
let source_boss = source_mesh.contains(boss_probe);
let copied = run(&mut s, "component.paste_new", json!({"component":part,"translate":[10,10,0]}));
assert_eq!(s.doc.components.len(), 2);
@@ -354,11 +354,11 @@ fn reassigned_sample_plate_paste_new_preserves_complex_frozen_geometry() {
for (point, expected) in
[([5.0, 25.0, 4.0], true), ([12.0, 25.0, 4.0], false), ([68.0, 25.0, 4.0], false), ([40.0, 25.0, 12.0], false), ([0.0, 0.0, 4.0], false)]
{
assert_eq!(mesh.contains(solvecraft_geom::Vec3::new(point[0], point[1], point[2])), expected, "{point:?}");
assert_eq!(mesh.contains(solidcraft_geom::Vec3::new(point[0], point[1], point[2])), expected, "{point:?}");
}
assert_eq!(mesh.contains(boss_probe), source_boss);
assert_eq!(state.body(&body).unwrap().mesh().contains(boss_probe), source_boss);
let mut reopened = Session { doc: solvecraft_doc::Document::from_json(&s.doc.to_json()).unwrap().into(), ..Session::default() };
let mut reopened = Session { doc: solidcraft_doc::Document::from_json(&s.doc.to_json()).unwrap().into(), ..Session::default() };
reopened.refresh();
assert!((volume(&mut reopened, new) - original_volume).abs() < 1e-5 * original_volume);
}
@@ -375,7 +375,7 @@ fn generated_copy_parameters_cannot_heal_an_unrelated_missing_reference() {
let missing = probe.new_model_param("2 mm", "mm");
let feature = s.doc_mut().feature_mut(broken).unwrap();
feature.component = 0;
if let solvecraft_doc::FeatureKind::Box { width, .. } = &mut feature.kind {
if let solidcraft_doc::FeatureKind::Box { width, .. } = &mut feature.kind {
*width = missing;
}
s.refresh();
@@ -418,7 +418,7 @@ fn external_transfer_entry_and_internal_rotated_transfer_clone_once() {
assert!(before.min.dist(after.min) < 1e-6);
assert!(before.max.dist(after.max) < 1e-6);
assert!(body.transferred);
let mut reopened = Session { doc: solvecraft_doc::Document::from_json(&s.doc.to_json()).unwrap().into(), ..Session::default() };
let mut reopened = Session { doc: solidcraft_doc::Document::from_json(&s.doc.to_json()).unwrap().into(), ..Session::default() };
reopened.refresh();
assert!(reopened.model.state().body("Foreign (copy)").unwrap().mesh().bounds().min.dist(before.min) < 1e-6);
}
@@ -433,7 +433,7 @@ fn suppressed_external_entry_does_not_supply_clone_baseline() {
let skipped = s
.doc_mut()
.add_feature(
solvecraft_doc::FeatureKind::BodyTransfer { bodies: vec!["Foreign".into()], from: 0, to: part, transform: solvecraft_doc::IDENTITY },
solidcraft_doc::FeatureKind::BodyTransfer { bodies: vec!["Foreign".into()], from: 0, to: part, transform: solidcraft_doc::IDENTITY },
None,
)
.unwrap();
@@ -454,13 +454,13 @@ fn transferred_frozen_face_paint_ignores_consumed_legacy_offset() {
run(&mut s, "appearance.assign", json!({"body":"Foreign","faces":[[1,1,2]],"color":"#00ff00"}));
s.doc_mut().body_offsets.insert(
"Foreign".into(),
solvecraft_doc::rigid(solvecraft_geom::Vec3::new(7.0, 0.0, 0.0), solvecraft_geom::Vec3::ZERO, solvecraft_geom::Vec3::Z, 0.0),
solidcraft_doc::rigid(solidcraft_geom::Vec3::new(7.0, 0.0, 0.0), solidcraft_geom::Vec3::ZERO, solidcraft_geom::Vec3::Z, 0.0),
);
s.refresh();
let part = component(&mut s, "Part");
run(&mut s, "component.move_bodies", json!({"component":part,"bodies":["Foreign"]}));
let original = s.doc.appearances.faces.iter().find(|face| face.body == "Foreign").unwrap();
let expected = solvecraft_doc::naming::point_on_face(&s.model.state(), original.name.as_ref().unwrap(), original.point).unwrap().0;
let expected = solidcraft_doc::naming::point_on_face(&s.model.state(), original.name.as_ref().unwrap(), original.point).unwrap().0;
copy(&mut s, part);
let paint = s.doc.appearances.faces.iter().find(|face| face.body == "Foreign (copy)").unwrap();
assert!(paint.point.dist(expected) < 1e-6, "{:?} versus {expected:?}", paint.point);
@@ -468,18 +468,18 @@ fn transferred_frozen_face_paint_ignores_consumed_legacy_offset() {
#[test]
fn boundary_material_proof_requires_resolvable_stock_and_void() {
use solvecraft_geom::Vec3;
let a = solvecraft_kernel::box_solid(Vec3::ZERO, Vec3::new(10., 10., 10.)).unwrap().tessellate(1e-3).unwrap();
let b = solvecraft_kernel::box_solid(Vec3::new(1e-5, 0., 0.), Vec3::new(10.00001, 10., 10.)).unwrap().tessellate(1e-3).unwrap();
use solidcraft_geom::Vec3;
let a = solidcraft_kernel::box_solid(Vec3::ZERO, Vec3::new(10., 10., 10.)).unwrap().tessellate(1e-3).unwrap();
let b = solidcraft_kernel::box_solid(Vec3::new(1e-5, 0., 0.), Vec3::new(10.00001, 10., 10.)).unwrap().tessellate(1e-3).unwrap();
let p = Vec3::new(5e-6, 5., 5.);
assert_ne!(a.contains(p), b.contains(p));
assert!((super::mesh_distance(&a, p) - 5e-6).abs() < 1e-12);
assert!((super::mesh_distance(&b, p) - 5e-6).abs() < 1e-12);
assert!(super::material_probe_matches(&a, &b, p, 1e-3, 1e-3));
let shifted = solvecraft_kernel::box_solid(Vec3::new(1., 0., 0.), Vec3::new(11., 10., 10.)).unwrap().tessellate(1e-3).unwrap();
let shifted = solidcraft_kernel::box_solid(Vec3::new(1., 0., 0.), Vec3::new(11., 10., 10.)).unwrap().tessellate(1e-3).unwrap();
assert!(!super::material_probe_matches(&a, &shifted, p, 1e-3, 1e-3));
let thin = solvecraft_kernel::box_solid(Vec3::ZERO, Vec3::new(10., 10., 1e-4)).unwrap().tessellate(1e-6).unwrap();
let thin_shifted = solvecraft_kernel::box_solid(Vec3::new(0., 0., 1e-4), Vec3::new(10., 10., 2e-4)).unwrap().tessellate(1e-6).unwrap();
let thin = solidcraft_kernel::box_solid(Vec3::ZERO, Vec3::new(10., 10., 1e-4)).unwrap().tessellate(1e-6).unwrap();
let thin_shifted = solidcraft_kernel::box_solid(Vec3::new(0., 0., 1e-4), Vec3::new(10., 10., 2e-4)).unwrap().tessellate(1e-6).unwrap();
// Every resolvable replacement is void: thin ambiguous material is refused.
assert!(!super::material_probe_matches(&thin, &thin_shifted, Vec3::new(5., 5., 5e-5), 1e-3, 1e-3));
assert!(!super::material_probe_matches(&a, &b, p, f64::INFINITY, 1e-3));
@@ -487,7 +487,7 @@ fn boundary_material_proof_requires_resolvable_stock_and_void() {
#[test]
fn frozen_bore_boundary_copy_preserves_stock_void_and_reopen() {
use solvecraft_geom::Vec3;
use solidcraft_geom::Vec3;
let bore = |center: f64| {
let mut s = Session::default();
run(&mut s, "solid.box", json!({"length":30,"width":20,"height":10,"body_name":"Drilled"}));
@@ -500,7 +500,7 @@ fn frozen_bore_boundary_copy_preserves_stock_void_and_reopen() {
// cardinal angle, so its distance is bounded by the requested sag tolerance.
assert!(super::mesh_distance(&source, Vec3::new(6., 10., 5.)) <= 1e-3);
let shifted = bore(11.).model.state().body("Drilled").unwrap().body.tessellate(1e-3).unwrap();
let lost = solvecraft_kernel::box_solid(Vec3::ZERO, Vec3::new(30., 20., 10.)).unwrap().tessellate(1e-3).unwrap();
let lost = solidcraft_kernel::box_solid(Vec3::ZERO, Vec3::new(30., 20., 10.)).unwrap().tessellate(1e-3).unwrap();
assert!(!super::material_probe_matches(&source, &shifted, Vec3::new(6.5, 10., 5.), 1e-3, 1e-3));
assert!(!super::material_probe_matches(&source, &lost, Vec3::new(10., 10., 5.), 1e-3, 1e-3));
let created = run(&mut s, "component.from_bodies", json!({"bodies":["Drilled"]}));
@@ -517,17 +517,17 @@ fn frozen_bore_boundary_copy_preserves_stock_void_and_reopen() {
}
};
check(&s);
check(&Session::new(solvecraft_doc::Document::from_json(&s.doc.to_json()).unwrap()));
check(&Session::new(solidcraft_doc::Document::from_json(&s.doc.to_json()).unwrap()));
}
#[test]
fn frozen_r6_bore_copy_uses_current_geometry_despite_mesh_measure_bias() {
use solvecraft_geom::Vec3;
use solidcraft_geom::Vec3;
let mut s = Session::default();
run(&mut s, "solid.box", json!({"length":20,"width":20,"height":10,"body_name":"Drilled"}));
run(&mut s, "solid.cylinder", json!({"base":[10,10,0],"radius":6,"height":10,"operation":"cut"}));
let source = s.model.state().body("Drilled").unwrap().body.clone();
let original = solvecraft_kernel::step_export(&[&source], "source").unwrap();
let original = solidcraft_kernel::step_export(&[&source], "source").unwrap();
let created = run(&mut s, "component.from_bodies", json!({"bodies":["Drilled"]}));
let part = created["components"][0]["component"].as_u64().unwrap();
let before = s.doc.to_json();
@@ -535,7 +535,7 @@ fn frozen_r6_bore_copy_uses_current_geometry_despite_mesh_measure_bias() {
let check = |session: &Session| {
let state = session.model.state();
let body = state.bodies.iter().find(|b| session.doc.model_body_component(b) == copied).unwrap();
assert_eq!(solvecraft_kernel::certified_prism_equivalent(&source, &body.body).unwrap(), Some(true));
assert_eq!(solidcraft_kernel::certified_prism_equivalent(&source, &body.body).unwrap(), Some(true));
let mesh = body.body.tessellate(1e-3).unwrap();
for (point, material) in
[(Vec3::new(3., 10., 5.), true), (Vec3::new(5., 10., 5.), false), (Vec3::new(10., 10., 5.), false), (Vec3::new(18., 10., 5.), true)]
@@ -543,10 +543,10 @@ fn frozen_r6_bore_copy_uses_current_geometry_despite_mesh_measure_bias() {
assert_eq!(mesh.contains(point), material, "{point:?}");
}
let original_body = state.body("Drilled").unwrap();
assert_eq!(solvecraft_kernel::step_export(&[&original_body.body], "source").unwrap(), original);
assert_eq!(solidcraft_kernel::step_export(&[&original_body.body], "source").unwrap(), original);
};
check(&s);
check(&Session::new(solvecraft_doc::Document::from_json(&s.doc.to_json()).unwrap()));
check(&Session::new(solidcraft_doc::Document::from_json(&s.doc.to_json()).unwrap()));
run(&mut s, "edit.undo", json!({}));
assert_eq!(s.doc.to_json(), before);
run(&mut s, "edit.redo", json!({}));