- Ensure unstructured Task closures in TargetWorkflowViewModel and
Stage2View run on @MainActor after awaiting CupsService / spool.
Without this, updates in the failure path were
not reaching the UI in time, failing Milestone3UITests.
- lpoptions parser: a token no longer truncates the whole
parse.
UI test results: Milestone3UITests 6/6 pass; Core tests 154/154 pass;
universal arm64 x86_64 build passes.
- rawPrintPanel: printerSelect (lpstat -e, auto-refresh on manifest),
printerStatusBadge (idle/printing/stopped), printerTraySelect +
printerMediaTypeSelect from lpoptions -l capabilities, portrait/
landscape toggle, btnPrinterProperties (bound NSPrintPanel), Print
All + per-page btnPrintPage-N, in-panel printNotification (cancel →
info, not error). No cupsOptionsGroup/chkPpdFallback — macOS always
uses the PM-captured path.
- TargetWorkflowViewModel: refreshPrinters, reloadSelectedCapabilities,
openPrinterPreferences (panel-side queue switch updates the select),
printAllPages / printPage (sequential, stop-on-first-error),
capturedCupsOptions per-queue session cache, wizard.printerName set
on spool (#95).
- CupsError.noPrinterSelected.
- Mock CUPS fixtures: lpstat (2 queues, one idle one disabled),
lpoptions (tray/media/EPIJ_CMat listings), lp (appends argv to
ICCERY_TEST_LP_ARGV). Milestone3UITests: enumeration, preferences
cancel→info, captured options replayed in argv, per-page print,
lp failure notice, printerName persistence.
- lpoptions parser: skip keyless '=value' tokens instead of truncating.
UI tests written but not executed here: the dev machine's console is
locked (IOConsoleLocked=true) so XCUIApplication.activate() cannot
bring the app to front — same failure on M2 baseline. Suite must be
run unlocked / on CI.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>