.icceryproj v1 JSON index (ICCeryProject): basename + cwd + optional media_recipe_id / preset_id / calibration_url / printer fields + last_verification ΔE₀₀ snapshot. Strict schema: schema_version != 1 throws before any field is applied; corrupt files are preserved.
The project is never a second source of truth: open writes WizardState and re-probes via the existing windowDidBecomeKey path — JSON-vs-disk drift surfaces as the projectChipStale chip state + info banner, never as gating.
RecentProjectsStore (recent_projects.json in app data): cap 20, dedupe by path, bookmark+path entries, missing files pruned on submenu build, Clear Menu wipes the recents file only.
ProjectSession view model: New/Open/Save/Save As/Close/Save Report flows, dirty tracking with a • window title, dirty-gate alert, missing-cwd relocate sheet. Live CAL_ basenames resolve the persisted original or refuse with a banner — CAL_ is never persisted.
File menu commands on the existing WindowGroup + a compact sidebar project chip (no new large buttons). Dedicated selectProjectFile / selectProjectSavePath pickers; UITestHooks inject all panel results.
Targeted gate: all selected unit suites + Milestone10ProjectUITests (4) + AboutHelpUITests (2) — pass, UI tests execute (no attach-skip).
Full host-arch suite: ICCeryCoreTests 439/439; ICCeryUITests 48/49 — testSpotReadButtonDisabledDuringChartread timed out once on the mock chartread calibrate prompt and passes standalone (timing flake, unrelated).
Refs #149
## Summary
- `.icceryproj` v1 JSON index (`ICCeryProject`): basename + cwd + optional `media_recipe_id` / `preset_id` / `calibration_url` / printer fields + `last_verification` ΔE₀₀ snapshot. Strict schema: `schema_version != 1` throws before any field is applied; corrupt files are preserved.
- The project is never a second source of truth: open writes `WizardState` and re-probes via the existing `windowDidBecomeKey` path — JSON-vs-disk drift surfaces as the `projectChipStale` chip state + info banner, never as gating.
- `RecentProjectsStore` (`recent_projects.json` in app data): cap 20, dedupe by path, bookmark+path entries, missing files pruned on submenu build, Clear Menu wipes the recents file only.
- `ProjectSession` view model: New/Open/Save/Save As/Close/Save Report flows, dirty tracking with a `•` window title, dirty-gate alert, missing-cwd relocate sheet. Live `CAL_` basenames resolve the persisted original or refuse with a banner — `CAL_` is never persisted.
- File menu commands on the existing `WindowGroup` + a compact sidebar project chip (no new large buttons). Dedicated `selectProjectFile` / `selectProjectSavePath` pickers; `UITestHooks` inject all panel results.
## Tests
- New: `ICCeryProjectTests`, `RecentProjectsStoreTests`, `ProjectSessionTests`, `Milestone10ProjectUITests`.
- Targeted gate: all selected unit suites + `Milestone10ProjectUITests` (4) + `AboutHelpUITests` (2) — pass, UI tests execute (no attach-skip).
- Full host-arch suite: `ICCeryCoreTests` 439/439; `ICCeryUITests` 48/49 — `testSpotReadButtonDisabledDuringChartread` timed out once on the mock chartread calibrate prompt and passes standalone (timing flake, unrelated).
- `git diff --check` clean; no secrets; Media/Spot/Gamut implementation files untouched (Sidebar/Root observation wiring only).
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 #149
Summary
.icceryprojv1 JSON index (ICCeryProject): basename + cwd + optionalmedia_recipe_id/preset_id/calibration_url/ printer fields +last_verificationΔE₀₀ snapshot. Strict schema:schema_version != 1throws before any field is applied; corrupt files are preserved.WizardStateand re-probes via the existingwindowDidBecomeKeypath — JSON-vs-disk drift surfaces as theprojectChipStalechip state + info banner, never as gating.RecentProjectsStore(recent_projects.jsonin app data): cap 20, dedupe by path, bookmark+path entries, missing files pruned on submenu build, Clear Menu wipes the recents file only.ProjectSessionview model: New/Open/Save/Save As/Close/Save Report flows, dirty tracking with a•window title, dirty-gate alert, missing-cwd relocate sheet. LiveCAL_basenames resolve the persisted original or refuse with a banner —CAL_is never persisted.WindowGroup+ a compact sidebar project chip (no new large buttons). DedicatedselectProjectFile/selectProjectSavePathpickers;UITestHooksinject all panel results.Tests
ICCeryProjectTests,RecentProjectsStoreTests,ProjectSessionTests,Milestone10ProjectUITests.Milestone10ProjectUITests(4) +AboutHelpUITests(2) — pass, UI tests execute (no attach-skip).ICCeryCoreTests439/439;ICCeryUITests48/49 —testSpotReadButtonDisabledDuringChartreadtimed out once on the mock chartread calibrate prompt and passes standalone (timing flake, unrelated).git diff --checkclean; no secrets; Media/Spot/Gamut implementation files untouched (Sidebar/Root observation wiring only).