App: PrintSessionViewModel gains selectedPaperSize/selectedQuality, seeds from Stage 1 workflow.pageSize, re-mirrors on page-size/printer changes, preserves user edits across unrelated publishes; .custom produces the synthetic id: 0 entry with point-based Custom.<pt>x<pt> token (mm × 72/25.4); PrintOptions carries paper token + quality into spool.
Stage 2 UI: paper + quality pickers (printerPaperSizeSelect / printerQualitySelect pop-up buttons; paperSizeGroup / qualityGroup containers); all existing identifiers unchanged.
Print panel: PrintPanelInitialSelections (paperSize/qualityKey/quality/mediaType/orientation fields); this phase consumes paper + quality only, written after PMSessionDefault* and before ColorSync suppression. Media/orientation preselect and full capture-return remain #186. Panel stub extended via ICCERY_TEST_PANEL_OPTIONS — no real NSPrintPanel in UI tests.
Out of scope (unchanged): #180 EPIJ_Qual fixture enrichment, #181 locale fix, #186 media/orientation + full capture-return. workflow.pageSize is never written by print-side selection. ColorSync SPI signature and ordering untouched. No dependency/signing/sandbox/deployment-target changes.
Extended core run (also green, 45/0) additionally included PrintSessionViewModelTests (8) and CupsOptionsFilterTests (5).
Note: the CupsParserTests.swift file's class was renamed CupsParsersTests → CupsParserTests to match the file name and the contract selector (a zero-match selector is a failed gate).
Refs #183
## Scope
Stage 2 paper-size and print-quality selection (M11 Phase 1):
- ICCeryCore: `PrinterQuality` model; `PrinterCapabilities` gains `qualityKey`/`qualities`/`qualityDefault`; `PrintOptions.quality`; `CupsParsers.qualityKeys` + `detectQualityKey` + `extractOption`/`extractQuality`/`extractOrientation`; `CupsService.capabilities` quality extraction (roster order, `*` default, PPD labels); `CupsOptionsFilter.relevantKeys` gains `EPIJ_Qual` (+ `CNIJPrintQuality`, `PrintQuality`) with `EPIJ_Quality` retained as alias; `LpArgs` emits `-o <qualityKey>=<quality>` after media/before orientation, captured options win case-insensitively, sanitized, never `-o raw`.
- App: `PrintSessionViewModel` gains `selectedPaperSize`/`selectedQuality`, seeds from Stage 1 `workflow.pageSize`, re-mirrors on page-size/printer changes, preserves user edits across unrelated publishes; `.custom` produces the synthetic `id: 0` entry with point-based `Custom.<pt>x<pt>` token (mm × 72/25.4); `PrintOptions` carries paper token + quality into spool.
- Stage 2 UI: paper + quality pickers (`printerPaperSizeSelect` / `printerQualitySelect` pop-up buttons; `paperSizeGroup` / `qualityGroup` containers); all existing identifiers unchanged.
- Print panel: `PrintPanelInitialSelections` (paperSize/qualityKey/quality/mediaType/orientation fields); this phase consumes paper + quality only, written after `PMSessionDefault*` and before ColorSync suppression. Media/orientation preselect and full capture-return remain #186. Panel stub extended via `ICCERY_TEST_PANEL_OPTIONS` — no real `NSPrintPanel` in UI tests.
Out of scope (unchanged): #180 EPIJ_Qual fixture enrichment, #181 locale fix, #186 media/orientation + full capture-return. `workflow.pageSize` is never written by print-side selection. ColorSync SPI signature and ordering untouched. No dependency/signing/sandbox/deployment-target changes.
## Test evidence
Gate command:
```
xcodebuild test -scheme ICCery -destination 'platform=macOS' \
-derivedDataPath build/DerivedData-feat-183-stage2-print-settings \
ARCHS="$(uname -m)" CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY='-' \
-only-testing:ICCeryCoreTests/CupsParserTests \
-only-testing:ICCeryCoreTests/LpArgsTests \
-only-testing:ICCeryCoreTests/PrintPanelStubTests \
-only-testing:ICCeryUITests/Milestone11PrintSettingsUITests \
-only-testing:ICCeryUITests/Milestone3UITests
```
Result (x86_64, local): **41 executed, 0 failures**
- CupsParserTests: 14
- LpArgsTests: 14
- PrintPanelStubTests: 4
- Milestone11PrintSettingsUITests: 3
- Milestone3UITests: 6
Extended core run (also green, 45/0) additionally included `PrintSessionViewModelTests` (8) and `CupsOptionsFilterTests` (5).
Note: the `CupsParserTests.swift` file's class was renamed `CupsParsersTests` → `CupsParserTests` to match the file name and the contract selector (a zero-match selector is a failed gate).
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.
Refs #183
Scope
Stage 2 paper-size and print-quality selection (M11 Phase 1):
PrinterQualitymodel;PrinterCapabilitiesgainsqualityKey/qualities/qualityDefault;PrintOptions.quality;CupsParsers.qualityKeys+detectQualityKey+extractOption/extractQuality/extractOrientation;CupsService.capabilitiesquality extraction (roster order,*default, PPD labels);CupsOptionsFilter.relevantKeysgainsEPIJ_Qual(+CNIJPrintQuality,PrintQuality) withEPIJ_Qualityretained as alias;LpArgsemits-o <qualityKey>=<quality>after media/before orientation, captured options win case-insensitively, sanitized, never-o raw.PrintSessionViewModelgainsselectedPaperSize/selectedQuality, seeds from Stage 1workflow.pageSize, re-mirrors on page-size/printer changes, preserves user edits across unrelated publishes;.customproduces the syntheticid: 0entry with point-basedCustom.<pt>x<pt>token (mm × 72/25.4);PrintOptionscarries paper token + quality into spool.printerPaperSizeSelect/printerQualitySelectpop-up buttons;paperSizeGroup/qualityGroupcontainers); all existing identifiers unchanged.PrintPanelInitialSelections(paperSize/qualityKey/quality/mediaType/orientation fields); this phase consumes paper + quality only, written afterPMSessionDefault*and before ColorSync suppression. Media/orientation preselect and full capture-return remain #186. Panel stub extended viaICCERY_TEST_PANEL_OPTIONS— no realNSPrintPanelin UI tests.Out of scope (unchanged): #180 EPIJ_Qual fixture enrichment, #181 locale fix, #186 media/orientation + full capture-return.
workflow.pageSizeis never written by print-side selection. ColorSync SPI signature and ordering untouched. No dependency/signing/sandbox/deployment-target changes.Test evidence
Gate command:
Result (x86_64, local): 41 executed, 0 failures
Extended core run (also green, 45/0) additionally included
PrintSessionViewModelTests(8) andCupsOptionsFilterTests(5).Note: the
CupsParserTests.swiftfile's class was renamedCupsParsersTests→CupsParserTeststo match the file name and the contract selector (a zero-match selector is a failed gate).