Parameter and feature edits report the features they restored from the evaluation cache: setting a parameter back (or a timeline.edit back) reused the earlier results for the same inputs, so the geometry changed back but recomputed said 0, which read as "nothing rebuilt". The evaluator now counts cache hits as last_restored, and parameters.change, timeline.edit, timeline.redefine and solid.press_pull on a fillet or chamfer face report it as restored next to recomputed (params docs, the MCP set_parameter description and docs/mcp.md say what each counts). Tests: setting a parameter back and a feature edit back report restored, in the evaluator and through the commands

This commit is contained in:
CypherNaugh_0x authored and bherbruck committed 2026-10-10 15:36:42 -04:00
1 parent 90ce5261b3
commit 49bd89de13
8 files changed
+59 -8

No files matched your search

+7
View File
@@ -377,6 +377,10 @@ pub struct Model {
empty: Arc<ModelState>,
/// Features recomputed by the last `evaluate`.
pub last_recomputed: usize,
/// Features whose result the last `evaluate` took from the cache instead of recomputing: the
/// same feature on the same inputs was evaluated before (an edit set back, undo, redo, a
/// configuration row). Their geometry did change since the previous evaluation.
pub last_restored: usize,
/// Results by inputs, shared with this model's copies.
pub cache: Arc<std::sync::Mutex<EvalCache>>,
/// Evaluate everything from scratch (no reuse; tests compare the two).
@@ -505,6 +509,7 @@ impl Model {
let mut out: Vec<FeatureResult> = Vec::with_capacity(doc.features.len());
let mut reuse = !self.no_cache;
let mut recomputed = 0;
let mut restored = 0;
let marker = doc.marker.unwrap_or(usize::MAX);
let ctx = context_digest(doc, &vals);
for (i, f) in doc.features.iter().enumerate() {
@@ -569,6 +574,7 @@ impl Model {
if !self.no_cache
&& let Some(c) = self.cache.lock().ok().and_then(|mut m| m.get(key))
{
restored += 1;
if c.error.is_none() {
state = c.state.clone();
}
@@ -652,6 +658,7 @@ impl Model {
}
self.results = out;
self.last_recomputed = recomputed;
self.last_restored = restored;
}
}
+20
View File
@@ -81,6 +81,26 @@ fn parametric_plate_reevaluates() {
assert!(rel(measure(&m.state().bodies[0].body).unwrap().volume, 50.0 * 30.0 * 10.0) < 1e-9);
}
/// Setting a parameter back takes the earlier results from the cache: nothing is recomputed, but
/// the evaluation reports the features it restored (their geometry did change back).
#[test]
fn set_back_reports_restored_features() {
let (mut doc, _) = plate_doc();
let mut m = Model::new();
m.evaluate(&doc);
assert_eq!((m.last_recomputed, m.last_restored), (2, 0));
doc.set_param("width", "50 mm", None, None).unwrap();
m.evaluate(&doc);
assert_eq!((m.last_recomputed, m.last_restored), (2, 0));
doc.set_param("width", "40 mm", None, None).unwrap();
m.evaluate(&doc);
assert_eq!((m.last_recomputed, m.last_restored), (0, 2));
assert!(rel(measure(&m.state().bodies[0].body).unwrap().volume, 24000.0) < 1e-9);
// No change: nothing recomputed and nothing restored.
m.evaluate(&doc);
assert_eq!((m.last_recomputed, m.last_restored), (0, 0));
}
#[test]
fn box_fillet_cut_timeline() {
let (mut doc, _) = plate_doc();