diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs index 8f8b988693..0167a24c23 100644 --- a/crates/ui-egui/src/dialogs.rs +++ b/crates/ui-egui/src/dialogs.rs @@ -787,8 +787,8 @@ fn about_tab_body(app: &mut PhotocraftApp, ui: &mut egui::Ui, tab: &str) { /// The dialog title as shown: [`title`] in the UI language. fn display_title(d: &Dialog) -> String { match d.fields.get("__colorPicker").and_then(Value::as_str) { - Some("foreground") => return crate::color_picker_ui::title_for(tl!("Foreground Color")), - Some("background") => return crate::color_picker_ui::title_for(tl!("Background Color")), + Some("foreground") => return tl!("Color Picker (Foreground Color)").to_string(), + Some("background") => return tl!("Color Picker (Background Color)").to_string(), _ => {} } if crate::smart_filter_dialog::owns(&d.fields) { diff --git a/crates/ui-egui/src/panels/actions/tests.rs b/crates/ui-egui/src/panels/actions/tests.rs index eda298616e..b5a608dea3 100644 --- a/crates/ui-egui/src/panels/actions/tests.rs +++ b/crates/ui-egui/src/panels/actions/tests.rs @@ -50,7 +50,10 @@ fn loading_json_actions_uses_engine_import_and_selects_the_new_action() { fn default_actions_load_from_empty_panel_and_play() { use egui_kittest::{Harness, kittest::Queryable}; let app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default()); - let mut h = Harness::builder().with_size(vec2(360.0, 400.0)).build_ui_state(|ui, app| panel(app, ui), app); + let mut h = Harness::builder() + .with_size(vec2(360.0, 400.0)) + .with_context_setup(|ctx| PhotocraftApp::setup_context(ctx, Default::default())) + .build_ui_state(|ui, app| panel(app, ui), app); h.run_steps(3); h.get_by_label("Load Default Actions").click(); h.run_steps(3); diff --git a/crates/ui-egui/src/pen_variants_tests.rs b/crates/ui-egui/src/pen_variants_tests.rs index 330f2bc6f3..4b5cf04d61 100644 --- a/crates/ui-egui/src/pen_variants_tests.rs +++ b/crates/ui-egui/src/pen_variants_tests.rs @@ -211,7 +211,8 @@ fn the_pen_carries_on_an_open_path_from_either_end() { } /// #6593 review: carrying on a subpath keeps its path operation, and a draft whose subpath changed -/// meanwhile is added as a new subpath instead of overwriting another one. +/// meanwhile refuses without overwriting newer work. The historical test name is retained +/// for reviewed-head provenance; captured-revision validation supersedes its stale fallback. #[test] fn a_resumed_subpath_keeps_its_operation_and_a_stale_draft_adds_a_new_one() { let mut app = app(Tool::Pen); @@ -223,21 +224,28 @@ fn a_resumed_subpath_keeps_its_operation_and_a_stale_draft_adds_a_new_one() { let work = work_path(&app); assert_eq!((work.subpaths.len(), work.subpaths[0].knots.len()), (1, 3)); assert_eq!(work.subpaths[0].op, photocraft_doc::vector::PathOp::Subtract, "the operation is kept"); - // The work path is replaced while the draft is open: the draft becomes a new subpath. + // Replacing the source invalidates the draft; neither explicit commit nor a frame retries it. click(&mut app, 20.0, 20.0); click(&mut app, 20.0, 80.0); app.run("path.set", json!({"name": "work", "path": {"subpaths": [open(120.0, 180.0, "combine")]}})).unwrap(); + let newer = work_path(&app); + let steps = app.session.active().unwrap().history.past_len(); crate::vector_ui::pen_commit(&mut app, false); let work = work_path(&app); - assert_eq!(work.subpaths.len(), 2, "a new subpath, the replaced one untouched"); + assert_eq!(work, newer, "the replaced source is unchanged by a stale draft"); + assert_eq!(work.subpaths.len(), 1); + assert!(app.ui.pen.is_none() && app.ui.status_error); + assert_eq!(app.session.active().unwrap().history.past_len(), steps); assert_eq!(work.subpaths[0].knots.iter().map(|k| k.anchor.x).collect::>(), [120.0, 180.0]); - // The same with nothing selected in the Paths panel: still added to the Work Path it came from. + // Deselecting the path does not allow a stale draft to replace the newer source. click(&mut app, 180.0, 20.0); click(&mut app, 180.0, 90.0); app.ui.selected_path = None; app.run("path.set", json!({"name": "work", "path": {"subpaths": [open(120.0, 160.0, "combine")]}})).unwrap(); crate::vector_ui::pen_commit(&mut app, false); - assert_eq!(work_path(&app).subpaths.len(), 2, "added, not replacing the Work Path"); + assert_eq!(work_path(&app).subpaths.len(), 1, "no stale component is appended"); + assert_eq!(work_path(&app).subpaths[0].knots.iter().map(|k| k.anchor.x).collect::>(), [120.0, 160.0]); + assert!(app.ui.pen.is_none() && app.ui.status_error); // And with another path selected: the draft still goes back to the path it came from. app.run("path.set", json!({"name": "Other", "path": {"subpaths": [open(10.0, 30.0, "combine")]}})).unwrap(); click(&mut app, 160.0, 20.0); @@ -245,7 +253,9 @@ fn a_resumed_subpath_keeps_its_operation_and_a_stale_draft_adds_a_new_one() { app.ui.selected_path = Some("Other".into()); app.run("path.set", json!({"name": "work", "path": {"subpaths": [open(120.0, 150.0, "combine")]}})).unwrap(); crate::vector_ui::pen_commit(&mut app, false); - assert_eq!(work_path(&app).subpaths.len(), 2, "joined the Work Path it came from"); + assert_eq!(work_path(&app).subpaths.len(), 1, "neither selected path accepts stale geometry"); + assert_eq!(work_path(&app).subpaths[0].knots.iter().map(|k| k.anchor.x).collect::>(), [120.0, 150.0]); + assert!(app.ui.pen.is_none() && app.ui.status_error); let st = app.session.active().unwrap(); let other = st.doc.paths.iter().find(|p| p.name == "Other").unwrap(); assert_eq!(other.path.subpaths.len(), 1, "the selected path is untouched"); diff --git a/docs/integration-testing/approved-bugfix-parity-2026-10-29.md b/docs/integration-testing/approved-bugfix-parity-2026-10-29.md index 30ecf2cbf3..d1503a6d70 100644 --- a/docs/integration-testing/approved-bugfix-parity-2026-10-29.md +++ b/docs/integration-testing/approved-bugfix-parity-2026-10-29.md @@ -257,7 +257,8 @@ Final source SHA and portable artifact are **not frozen yet**. Historical result | Final formatting / compile / strict lint | NOT RUN | Local formatting completed; final exact-head checks required. | | Full engine sweep | PASSED at `e40cdadb6` | 2,420 passed, zero failed, 16 ignored; full sweep enabled. Successor coverage required. | | Previous aggregate CI | FAILED | [40833090784](https://github.com/FredApps/photocraft/actions/runs/40833090784) at `2334a460f`: Linux alias fixture and Windows text unit failures. Windows integration, corpus, no-HEIF, web/wasm, morphology and quick performance passed. | -| Corrected-environment focused UI | PASSED on pending reconciliation | 244 executed tests passed, zero failures, one intentionally ignored capture test. Includes ownership, Direct Selection, Pen/vector, smart filters, gradient controls, polygon and catalog checks. Full UI sweep is in progress. | +| Corrected-environment focused UI | PASSED targeted checks | 244 tests passed at the reconciliation source. Later targeted Color Picker, default-action and Pen-variant corrections also passed. Full validation is moving to GitHub. | +| Broad local UI attempt | FAILED / ABORTED | At `c3d1e816c`, 3,788 completed success lines and three assertion failures preceded native Windows exit `0xc0000005`; no aggregate pass. Targeted corrections passed afterward. Process-isolated full validation uses the existing GitHub CI runner; no further broad local sweep. | | Corrected text suite | PARTIAL | Runner: 283 passed, zero failed, five ignored. Two Cairo-dependent early-return cases are BLOCKED. Both hanging-row regressions executed and passed. | | Final workspace / corpus / engine rerender / performance | NOT RUN | Final source needs its own full-sweep aggregate and separate IO/rerender evidence. Previous green jobs are historical. | | Photoshop/platform/manual cases | NOT RUN | Photoshop reopening, macOS, Intel/DX12 hardware and PDB identity require the specified environments. | diff --git a/docs/integration-testing/integration-status.json b/docs/integration-testing/integration-status.json index c1264ef003..37e3e42012 100644 --- a/docs/integration-testing/integration-status.json +++ b/docs/integration-testing/integration-status.json @@ -1279,21 +1279,21 @@ } ], "current_checkpoint_sha": "2334a460f22ed2c09d7e5f73cbb2ebe9125d4fc1", - "updated_at": "2026-10-29T08:55:58.674249+00:00", - "active_subsystem": "Final focused UI reconciliation; full corrected-environment UI sweep queued on focused success", + "updated_at": "2026-10-29T09:17:39.597875+00:00", + "active_subsystem": "Focused corrections passed; successor full validation is hosted in GitHub", "parent_decision_required": null, "validation": { "compositor_at_31ce2208": "PASSED: 402 passed, 0 failed, 2 ignored", - "current_full_workspace": "NOT RUN on final source; previous aggregate CI failed", + "current_full_workspace": "Pending hosted successor validation", "current_build_check": "PENDING successor check at 964a47b51; 30a2b002b workspace/all-target passed in 1m20s; UI helper extraction compile passed", "pattern_store_at_d98e4195": "PASSED: 35 tests, 0 failed, 1 benchmark ignored; final tree not yet tested", "manual": "NOT RUN", - "portable_final_build": "NOT RUN: blocked on remaining UI validation failures", + "portable_final_build": "NOT RUN; requires applicable hosted validation", "current_ci": "40833090784 at2334a460f FAILED aggregate; Windows integration/corpus/noHEIF/web/morphology/quickperf passed", "jxl_export": "PASSED 5/5 at 30a2b002b; no codec changes since", "ownership": "PASSED at e40cdadb6: 17 passed, 0 failed, 0 ignored", "engine": "PASSED at e40cdadb6: 2420 passed, 0 failed, 16 ignored, full sweep enabled", - "local_full_ui": "FAILED at2334a460f, requested DX12: 4378 passed, 75 failed, 22 ignored. Includes missing-font prerequisites and real integration/fixture reconciliation. Not an acceptance pass.", + "local_full_ui": "ABORTED at c3d1e816c:3788 completed success lines, three assertion failures, native Windows exit0xc0000005; no aggregate pass. Three targeted corrections passed afterward. No new broad local sweep.", "superseded_ci": "40831890924 and 40832695382 cancelled intentionally; cancelled stages are not passes", "corrected_text": "283 runner passes, zero failures, five ignored; two Cairo-only early-return cases BLOCKED; hanging-row regressions executed", "corrected_focused_ui": "PASSED on reconciliation working tree:244 passed, zero failed, one intentionally ignored capture; full corrected UI sweep running"