Skip to content

fix: keep bottle settings loadable across versions and crashes#102

Merged
frankea merged 5 commits into
mainfrom
fix/settings-robustness
Jun 11, 2026
Merged

fix: keep bottle settings loadable across versions and crashes#102
frankea merged 5 commits into
mainfrom
fix/settings-robustness

Conversation

@frankea

@frankea frankea commented Jun 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • Atomic settings writes: BottleSettings.encode(to:) used a bare data.write(to:), so a crash or power loss mid-save could leave a truncated Metadata.plist and wipe the bottle's configuration. Now writes with .atomic.
  • Lenient GraphicsBackend decode: the doc comment on BottleGraphicsConfig promised unknown values decode gracefully to .recommended, but decodeIfPresent(GraphicsBackend.self) actually throws on an unknown raw value — failing the entire bottle settings load. A new decodeGraphicsBackendIfPresent helper decodes the raw string and falls back (.recommended for the bottle config, nil for program overrides and game-DB variants). This is forward-compat groundwork: a bottle written by a future Whisky with a new backend still opens on this build.

Verification

  • 4 new regression tests (bottle config, full BottleSettings path, GameConfigVariantSettings, ProgramOverrides) — all reproduced the dataCorrupted failure before the fix.
  • Full WhiskyKit suite: 1001 tests pass.

- Write Metadata.plist atomically so an interrupted save can't truncate it
- Decode unknown GraphicsBackend values leniently (.recommended for the
  bottle config, nil for program overrides and game-DB variants) so settings
  written by a newer Whisky still load — forward-compat groundwork for new
  backends
@sentry

sentry Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.46875% with 25 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
WhiskyKit/Sources/WhiskyKit/Whisky/Program.swift 0.00% 10 Missing ⚠️
...ources/WhiskyKit/Whisky/BottleGraphicsConfig.swift 79.48% 8 Missing ⚠️
...yKit/Sources/WhiskyKit/Whisky/BottleSettings.swift 85.71% 7 Missing ⚠️

📢 Thoughts on this report? Let us know!

Address review on the settings-robustness change:
- Generalize decodeGraphicsBackendIfPresent into a reusable
  decodeLenientIfPresent<T: RawRepresentable where RawValue == String>,
  so the upcoming DXMT backend case needs no new plumbing, and apply it to
  the other string-backed enums in the same decode paths (performancePreset,
  resolutionPreset) — they had the same brick-the-whole-file failure mode.
- Log the unknown-value and malformed-type fallbacks via Logger.wineKit so a
  corrupted or foreign setting is diagnosable instead of silently reset.
- Narrow the doc comment: keyed-Codable enums (EnhancedSync, DXVKHUD) are not
  covered and still decode strictly.
- Add tests: malformed (wrong-typed) backend value, persist/reload round-trip
  after fallback, and performancePreset leniency; guard the substitution
  tests against silently becoming no-ops if the encoding shape changes.
- CHANGELOG: overrides/game-DB entries fall back to inheriting the bottle's
  choice (not .recommended); atomic write covers crash, not power loss.
@frankea frankea force-pushed the fix/settings-robustness branch from 6c2f52e to 075ccc7 Compare June 10, 2026 15:37
…t files

- Apply the lenient enum decode to every persisted string-backed enum (wine,
  launcher, audio, cleanup, display, and performance presets), not only the
  graphics backend, so settings written by a newer Whisky still load instead
  of resetting the whole bottle to defaults
- Quarantine an unreadable Metadata.plist (move it aside, preserved for
  diagnosis) before writing defaults, instead of silently overwriting it
- Classify the decode-failure logs (corruption at .error, forward-compat at
  .warning) with the coding path and non-redacted type and error
- Add regression tests for the bottle-level presets and the quarantine path
- Remove a stray exported signing key and gitignore key and cert export patterns
@frankea frankea force-pushed the fix/settings-robustness branch from 075ccc7 to 82813f2 Compare June 10, 2026 15:46
…program settings

A failed wine-version stamp rewrite after a successful decode no longer
propagates as a load failure, which moved a perfectly valid Metadata.plist
into quarantine and reset the bottle to defaults. The stamp now retries on
the next load instead.

Per-program settings get the same protections bottle settings already had:
atomic writes, and quarantining an undecodable file before defaults replace
it. Quarantine filenames now carry a random suffix so two recoveries in the
same second cannot collide and drop the second file.

Decode-failure and unknown-enum log lines are now marked public (they carry
fixed enum tokens and bottle paths, not personal data) so release logs stay
diagnosable.

Tests cover the file-version-mismatch quarantine path, stamp-write-failure
resilience, and unknown-value fallback for the audio, cleanup, and launcher
config groups.
@frankea frankea force-pushed the fix/settings-robustness branch from 3182024 to 73b7509 Compare June 11, 2026 02:23
@frankea frankea merged commit fb87228 into main Jun 11, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant