Map ProfilingPreset ↔ targen / printtarg / colprof configs in one place #82

Closed
opened 2026-09-10 18:23:13 +01:00 by gronod · 1 comment
Owner

Summary

ProfilingPreset is a flat snake_case snapshot of Stage 1 + 2 + 4 + calibration fields (v1 JSON schema). TargetWorkflowViewModel.applyPreset / saveCurrentAsPreset and ProfileWorkflowViewModel.applyPreset / presetSnapshot hand-copy every field. A new flag will be forgotten on one path.

Do not merge ProfilingPreset into the live configs — the JSON schema is a compatibility surface (docs/22-settings-presets.md).

Spec refs

  • docs/22-settings-presets.md
  • Issue 11 (presets engine)
  • Types: ProfilingPreset, TargenConfig, PrinttargConfig, ColprofConfig

Scope

In
Add initializers / snapshots on the Core configs (preferred) or a dedicated PresetMapping enum in Packages/ICCeryCore/Sources/ICCeryCore/Settings/:

extension TargenConfig {
    public init(preset: ProfilingPreset, basename: String, workingDirectory: URL?)
}
extension PrinttargConfig {
    public init(preset: ProfilingPreset, basename: String, workingDirectory: URL?, calibrationFile: String?)
}
extension ColprofConfig {
    public init(preset: ProfilingPreset, basename: String, workingDirectory: URL?, description: String?, copyright: String?)
}
extension ProfilingPreset {
    public init(
        id: String, name: String, description: String,
        targen: TargenConfig, printtarg: PrinttargConfig, colprof: ColprofConfig,
        calibrationFile: String?, applyCalibration: Bool?
    )
}

TargetWorkflowViewModel.applyPreset becomes: assign form fields from the three configs (or assign configs then push into form bindings — pick one direction and document it). saveCurrentAsPreset builds the three configs from the live form (buildTargenConfig, buildPrinttargConfig, profile.buildColprofConfig) then ProfilingPreset(...).

Layout-order encoding stays:

  • noRandomize == true.raster (-r)
  • seed 1.deterministic (-R 1)
  • else .customSeed
    Page size "210x297" custom parse stays (parseCustomPage).

ProfileWorkflowViewModel.applyPreset should call ColprofConfig(preset:) (or shared FWA parse). FWA mapping (none / "" / D50 / D65 / custom path) lives in one function next to ColprofFwaSelection.

Out

  • Changing built-in catalog JSON (PresetCatalog).
  • Changing import/export file format.
  • Splitting the target view model (sibling).

Full solution

  • Keep colourSpace on the preset as "rgb"|"cmyk" strings.
  • fullSpreadAlgorithm storage stays the flag letter / "ofps" via existing FullSpreadAlgorithm.presetValue.
  • Optional advanced fields: nil means “control off / omit flag”. Do not write 0 / 0.50 sentinels that would emit flags targen is specified to skip.
  • Calibration fields on the preset remain calibrationFile + applyCalibration; they are not part of TargenConfig.

Rewrite invariants

  • Built-in ids remain immutable (PresetStore.saveCustom still throws).
  • Imported names/descriptions still render with SwiftUI Text only (#114).
  • Draft preset dpi=150 must still be visible on #tiffDpi after apply (M2 regression).

Dependencies

Blocks-on: none.
Unblocks: cleanup ticket (optional ArgsBuilder work touches the same arg/config files — land mapping first).

Test

  • Extend Tests/ICCeryCoreTests/PresetTests.swift:
    • Round-trip: ProfilingPreset → three configs → ProfilingPreset equals on all Stage 1/2/4 fields (ignore generated id if you re-id).
    • Built-in “draft” / 150 DPI preset produces PrinttargConfig.dpi == 150.
    • nil optional fields do not become 0 in TargenConfig (grey/single/neutral/ink/dark/devicePower).
    • FWA "none" / "" / "D50" / custom path survive the round-trip.
    • Custom page "210x297".custom + width/height; invalid "foo" falls back to A4 (match current VM behaviour).
  • Extend UI tests only if apply/save identifiers change (they should not): Milestone2UITests preset apply.

Acceptance criteria

  • No field-by-field assignment lists in the two view models beyond “apply these three configs”.
  • v1 preset JSON still imports.
  • Unit round-trip tests cover DPI, layout order, optional targen flags, FWA.
  • Preset apply UI test still passes.
## Summary `ProfilingPreset` is a flat snake_case snapshot of Stage 1 + 2 + 4 + calibration fields (v1 JSON schema). `TargetWorkflowViewModel.applyPreset` / `saveCurrentAsPreset` and `ProfileWorkflowViewModel.applyPreset` / `presetSnapshot` hand-copy every field. A new flag will be forgotten on one path. Do **not** merge `ProfilingPreset` into the live configs — the JSON schema is a compatibility surface (`docs/22-settings-presets.md`). ## Spec refs - `docs/22-settings-presets.md` - Issue 11 (presets engine) - Types: `ProfilingPreset`, `TargenConfig`, `PrinttargConfig`, `ColprofConfig` ## Scope **In** Add initializers / snapshots on the Core configs (preferred) or a dedicated `PresetMapping` enum in `Packages/ICCeryCore/Sources/ICCeryCore/Settings/`: ```swift extension TargenConfig { public init(preset: ProfilingPreset, basename: String, workingDirectory: URL?) } extension PrinttargConfig { public init(preset: ProfilingPreset, basename: String, workingDirectory: URL?, calibrationFile: String?) } extension ColprofConfig { public init(preset: ProfilingPreset, basename: String, workingDirectory: URL?, description: String?, copyright: String?) } extension ProfilingPreset { public init( id: String, name: String, description: String, targen: TargenConfig, printtarg: PrinttargConfig, colprof: ColprofConfig, calibrationFile: String?, applyCalibration: Bool? ) } ``` `TargetWorkflowViewModel.applyPreset` becomes: assign form fields from the three configs (or assign configs then push into form bindings — pick one direction and document it). `saveCurrentAsPreset` builds the three configs from the live form (`buildTargenConfig`, `buildPrinttargConfig`, `profile.buildColprofConfig`) then `ProfilingPreset(...)`. Layout-order encoding stays: - `noRandomize == true` → `.raster` (`-r`) - seed `1` → `.deterministic` (`-R 1`) - else `.customSeed` Page size `"210x297"` custom parse stays (`parseCustomPage`). `ProfileWorkflowViewModel.applyPreset` should call `ColprofConfig(preset:)` (or shared FWA parse). FWA mapping (`none` / `""` / `D50` / `D65` / custom path) lives in **one** function next to `ColprofFwaSelection`. **Out** - Changing built-in catalog JSON (`PresetCatalog`). - Changing import/export file format. - Splitting the target view model (sibling). ## Full solution - Keep `colourSpace` on the preset as `"rgb"|"cmyk"` strings. - `fullSpreadAlgorithm` storage stays the flag letter / `"ofps"` via existing `FullSpreadAlgorithm.presetValue`. - Optional advanced fields: `nil` means “control off / omit flag”. Do not write `0` / `0.50` sentinels that would emit flags targen is specified to skip. - Calibration fields on the preset remain `calibrationFile` + `applyCalibration`; they are not part of `TargenConfig`. ## Rewrite invariants - Built-in ids remain immutable (`PresetStore.saveCustom` still throws). - Imported names/descriptions still render with SwiftUI `Text` only (#114). - Draft preset dpi=150 must still be visible on `#tiffDpi` after apply (M2 regression). ## Dependencies Blocks-on: none. Unblocks: cleanup ticket (optional `ArgsBuilder` work touches the same arg/config files — land mapping first). ## Test - Extend `Tests/ICCeryCoreTests/PresetTests.swift`: - Round-trip: `ProfilingPreset` → three configs → `ProfilingPreset` equals on all Stage 1/2/4 fields (ignore generated id if you re-id). - Built-in “draft” / 150 DPI preset produces `PrinttargConfig.dpi == 150`. - `nil` optional fields do not become `0` in `TargenConfig` (grey/single/neutral/ink/dark/devicePower). - FWA `"none"` / `""` / `"D50"` / custom path survive the round-trip. - Custom page `"210x297"` → `.custom` + width/height; invalid `"foo"` falls back to A4 (match current VM behaviour). - Extend UI tests only if apply/save identifiers change (they should not): `Milestone2UITests` preset apply. ## Acceptance criteria - [ ] No field-by-field assignment lists in the two view models beyond “apply these three configs”. - [ ] v1 preset JSON still imports. - [ ] Unit round-trip tests cover DPI, layout order, optional targen flags, FWA. - [ ] Preset apply UI test still passes.
gronod added this to the M7 — Deduplicate & consolidate (develop) milestone 2026-09-10 18:23:13 +01:00
gronod added the Kind/Enhancement
Priority
Medium
3
Project/ICCery-v2Feature/Backend
labels 2026-09-10 18:23:13 +01:00
gronod self-assigned this 2026-09-10 18:23:13 +01:00
Author
Owner

Implementation originally landed in stacked commit d4261ba via PR #87.
Completion/verification landed in PR #98 at 597cce7.

Acceptance evidence:

[x] Centralised ColprofFwaSelection and FWA mapping logic in PresetMapping.swift.

[x] Stale custom FWA paths cleared on nil/none preset application.

[x] Preset calibration fields applied before Stage 2 config construction.

[x] TestAppEnvironment harness implemented for isolated temporary testing.

[x] Round-trip mapping asserted across all 8 full-spread algorithms and page formats.

Verification at milestone/m8-consolidation 891a504ee7:

targeted suites: passed (25 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.

Implementation originally landed in stacked commit d4261ba via PR #87. Completion/verification landed in PR #98 at 597cce7. Acceptance evidence: [x] Centralised ColprofFwaSelection and FWA mapping logic in PresetMapping.swift. [x] Stale custom FWA paths cleared on nil/none preset application. [x] Preset calibration fields applied before Stage 2 config construction. [x] TestAppEnvironment harness implemented for isolated temporary testing. [x] Round-trip mapping asserted across all 8 full-spread algorithms and page formats. Verification at milestone/m8-consolidation 891a504ee722037ab15e01c1ae801a4d4cb9415a: targeted suites: passed (25 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.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: gronod/iccery-v2-mac#82