The policy layer folded every failure into "unconfigured", then wrote that emptiness back.
* **Any parse error reverted the WHOLE policy.** An unknown enum variant, a mistyped scalar, an
EACCES or EIO — all became `Err(_) => None`, i.e. the host silently ran on built-in defaults with
the operator's `display-settings.json` still sitting on disk. Parsing is now layered: strict
first, then per-axis salvage so one unreadable axis costs only that axis, and only `NotFound` is
quiet — EACCES/EIO warn loudly that the host is on defaults. `version` is read instead of being
blindly rewritten to 1.
* **One malformed entry dropped the entire custom-preset catalog**, and the next CRUD atomically
renamed the empty vector over the file. Entries are parsed one at a time now; a lossy load is
flagged and refuses to overwrite.
* `sanitized()` clamped `max_displays` but never `KeepAlive::Duration.seconds`, so a PUT could pin a
display for ~136 years — a deadline the reaper never reaches and a nonsense `expires_in_ms` in
`/display/state`. Clamped to a day, in both `sanitized()` and `sanitize_preset_fields`, and
sanitization now runs on LOAD as well as on write.
* The two stores' temp files had fixed names and no write lock, so concurrent saves could interleave
serialize -> rename -> in-memory update. Unique suffixes, a lock, and the in-memory update ordered
after the rename.
* `new_preset_id` never consulted the loaded entries for collisions.
* **Manual layout could place an unpinned display exactly on top of a pinned one**: the fallback was
the unconditional auto-row prefix sum, blind to where prior members were pinned. Unpinned members
now pack clear of the pins. Layout keys are canonicalized and unusable ones dropped at write time
rather than persisted-and-ignored.
Adds 20 tests, all running on macOS: a 20k-round randomized property test asserting no unpinned
member ever overlaps a sibling (verified to fail against the pre-fix `arrange_manual`), the salvage
and quarantine paths, the clamps, and a field-count guard that fails the moment a 13th policy axis
appears without being wired into the merge path.
Note: `partial_json_fills_defaults` was renamed to `serde_defaults_fill_a_partial_document` with no
assertion weakened — it pins the FILE contract (an old settings file must still load), which is not
the mgmt PUT contract that sweep item 11.1 is about.