Unify wizard process orchestration: logged-run helper, single Notice channel, ProcessLogView #80
Closed
opened 2026-09-10 18:23:12 +01:00 by gronod
·
1 comment
No Branch/Tag Specified
main
fix/165-settings-deltae-clip
develop
fix/163-cal-view-overflow
fix/m10-ci-ui-macos12
fix/146-viewbuilder-ten-child
chore/m10-docs-hygiene
feat/149-project-file
feat/147-gamut-compare
feat/148-spot-read
feat/146-media-library
chore/m10-tracking
feat/119-debug-disable-lib-validation
feat/117-static-iccerycore
feat/115-assertisolated-swift57
feat/113-printtask-defer-swift57
feat/111-stage4-viewbuilder-limit
feat/109-ci-xcodegen-pin
feat/m9-slice4-state-and-views
feat/m9-slice3-xctest-async-stateful
feat/m9-slice2-xctest-core-pure
feat/m9-slice1-config-and-core-syntax
milestone/m8-consolidation
feat/80-process-run-notice-consolidation
feat/79-runner-loop-contract-tests
feat/86-args-builder-completion
feat/84-process-manager-edge-contracts
feat/83-calibration-profile-contracts
feat/82-preset-mapping-contracts
feat/81-json-store-contracts
v2.0.0-prerelease-163
v2.0.0-monterey
v2.0.0-pre2-grok
v2.0.0-pre1
Labels
Clear labels
Bug/Architecture
Bug/Backend
Bug/DevOps
Bug/UI
Compat/Breaking
Feature/Architecture
Feature/Backend
Feature/DevOps
Feature/UI
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Project/ICCery-v2
Core / wizard / process infra defect
Argyll orchestration, file/data defect
Build, packaging, CI defect
Views, controls, dialogs defect
Breaking change that won't be backward compatible
Core / wizard / process infra
Argyll orchestration, file/data engines
Build, packaging, CI
Views, controls, dialogs
Something is not working
Documentation changes
Improve existing functionality
New functionality
This is security issue
Issue or pull request related to testing
Priority
Critical
1
The priority is critical
Priority
High
2
The priority is high
Priority
Low
4
The priority is low
Priority
Medium
3
The priority is medium
ICCery v2 Mac rewrite
Reviewed
Confirmed
1
Issue has been confirmed
Reviewed
Duplicate
2
This issue or pull request already exists
Reviewed
Invalid
3
Invalid issue
Reviewed
Won't Fix
3
This issue won't be fixed
Status
Abandoned
3
Somebody has started to work on this but abandoned work
Status
Blocked
1
Something is blocking this issue or pull request
Status
Need More Info
2
Feedback is required to reproduce issue or to continue work
Milestone
No items
No Milestone
M7 — Deduplicate & consolidate (develop)
Projects
Clear projects
No projects
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: gronod/iccery-v2-mac#80
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Every stage view model reimplements “set running flag, clear log, nested
Task { @MainActor }log append,wizard.showNoticeon success/fail.” Stage-local banners (printNotice+printNoticeIsError,finishNotice+finishNoticeIsError,lastError) duplicateNotice/NoticeBanner.Extract one orchestration helper and one notice type. Do not change wizard gating or artefact rules.
Spec refs
docs/21-ui-reference.md(#wizardNotification,#printNotification, stage log containers)docs/06-wizard-and-artefacts.md(notices are not gates)Sources/ICCery/NoticeBanner.swift,WizardViewModel.showNoticeScope
In
@MainActor@Observableview models, e.g.Sources/ICCery/ProcessRunSupport.swift:The log callback must hop to the main actor once. Today
generateTarget/createLayout/createProfile/generateTarget(cal) /computeCurves/finishAndAveragenestTask { @MainActor }inside an already-main task. Kill the inner hop or replace it withMainActor.assumeIsolatedonly when the callback is known main-isolated; prefer a single documented hop.Apply in:
TargetWorkflowViewModel.generateTarget/createLayoutCalibrationViewModel.generateTarget/computeCurvesProfileWorkflowViewModel.createProfile/verifyProfile(and the innerrunIccgamutlog append)MeasurementWorkflowViewModel.finishAndAverageand chartread log batchesWizardViewModel.notice+NoticeBanneras the session-wide banner.printNotice/printNoticeIsErrorandfinishNotice/finishNoticeIsErrorwithNotice?(printNotice: Notice?,finishNotice: Notice?).Notice.kindinstead of a parallel bool.lastErroron measurement / profile / calibration: either becomeNotice?or write throughwizard.showNotice(..., kind: .error)and drop the unused field. Do not keep both a stagelastErrorText and a global banner that say the same thing unless a UI test asserts both ids — if a test asserts#stage4error text, keep a boundNotice?on that VM, not a rawString.ProcessLogViewinSources/ICCery/ProcessLogView.swift:Text(lines.joined(separator: "\n"))minHeight/maxHeightparametersaccessibilityIdentifierfor container + log bodyStage1View.logSectionandStage2View.logSection. Stage 3/4 logs should use it if they are structurally the same.importMeasurementDataset— thecatch let error as CGATSParseErrorand genericcatchcurrently emit the same"Import failed: \(error.localizedDescription)". One catch.Out
TargetWorkflowViewModelinto a print session object (sibling ticket). After this ticket, print state still lives on the target VM but usesNotice.autoHideAfter: nil) unless a UI test requires otherwise.Full solution
targenLog,targenLogContainer,printtargLog,printtargLogContainer,printNotificationIcon,printNotificationText, and any Stage 3 finish notice ids. The view may wrapNoticeBanneror a thin sibling; ids must not vanish.kind: .info, never.error(issue 17 invariant).Task { @MainActor in(no weak) withTask { @MainActor [weak self] in.Rewrite invariants
#84/ process isolation unchanged — helper only hops coalesced batches.wizard.go,refreshGating) stays in the caller, not the helper.Dependencies
Blocks-on: none.
Unblocks: print-session split ticket (needs a single notice type before that state moves).
Test
ICCeryCoreor a tinyICCerySupportfile with aTests/ICCeryCoreTestsor app-target test. Otherwise cover via UI tests.Tests/ICCeryUITests/Milestone2UITests.swift(targen/printtarg log containers still exist; generate/layout still show success/error banners).Milestone3UITests.swift: print cancel → info notice, not error; print failure still sets error kind.Milestone4UITests.swift: finish/average success and “promoted first pass” paths still surface a notice.Milestone5UITests.swift/Milestone6CalibrationUITests.swift: profile/cal failure still visible.lastErrorviews go away, retarget assertions atNoticeBanneror the stageNotice?id.importMeasurementDatasetmaps parser vs I/O failures through one path (mock file dialog is alreadyUITestHooks).Acceptance criteria
Task { @MainActor }solely to append log lines.printNoticeIsError/finishNoticeIsErrordeleted.ProcessLogViewused by Stage 1 and Stage 2.Implementation originally landed in stacked commit
d4261bavia PR #87.Completion/verification landed in PR #103 at
0d0233e.Acceptance evidence:
[x] Adopted ProcessRunSupport.runLogged across Calibration, Profile, Measurement, and Target ViewModels.
[x] Removed redundant pre-run state assignments and manual reset calls.
[x] Consolidated Notice usage; deleted printNoticeIsError and finishNoticeIsError flags.
[x] ProcessLogView adopted in Stage3View and Stage4View with deterministic container IDs.
[x] Unit test seam importMeasurementDataset(from:) added and tested for parser/IO errors.
[x] No nested Task { @MainActor } log hops; no direct ViewModel use of logSink.
Verification at milestone/m8-consolidation
891a504ee7:targeted suites: passed (29 tests)
full universal ICCeryCoreTests: 339 passed, 0 failed
full ICCeryUITests: 29 passed, 0 failed
Closing manually after code and tests are present on the milestone branch.