Skip to content

Fix portable plugin preferences backup coverage - #505

Merged
ggbond268 merged 8 commits into
mactools-app:mainfrom
xcv58:codex/503-plugin-preferences-backup
Oct 27, 2026
Merged

ggbond268 merged 8 commits into
mactools-app:mainfrom
xcv58:codex/503-plugin-preferences-backup

Conversation

@xcv58

@xcv58 xcv58 commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and result

Exporting preferences from Dev and importing them into another MacTools installation loses settings such as modifier dragging and centered window guides. This restores portable plugin configuration and shows what was included, excluded, unavailable, or failed.

Closes #503.

Changes

  • Expand portable backup support to 42 providers and declare coverage/exclusions for all 68 plugins, including the missing Trackpad Gestures presentation settings.
  • Validate bounded, versioned payloads before durable restoration; retain custom identities and unresolved application mappings. Restore dependent actions only when their definitions succeed.
  • Preserve the last good automatic, cloud, and safety backups when selected exporters fail. Add coverage and restore outcomes to the existing backup UI.
  • Keep credentials, permissions, private history, and local activation policy local. Custom prompt text and launch-item notes require separate persisted opt-ins; excluded legacy private text does not block configuration export or get rewritten when absent from an import.
  • Preserve existing destination AI credential access across upgrades with incomplete disabled service drafts, locally supported gateway URLs, and large excluded prompt libraries. Transactions journal only affected fields and retain old-journal recovery; backup size limits remain unchanged. Saved disabled drafts transfer with incomplete fields and remain disabled; structural/privacy bounds still apply and unsaved editor contents are excluded. Imported endpoints remain quarantined until a local credential is explicitly entered.
  • Apply imported AI Usage refresh intervals without fetching during import, retain failure/rate-limit backoff, and resume suppressed low-battery warnings after a new local notification grant without duplicating existing warnings.
  • Transfer saved per-app volume preferences while preserving running playback. Imported gains apply when an app starts playback or its audio processes change, including while another volume edit is pending. Subsequent edits and failed-operation rollback preserve other apps’ current gains.
  • Preserve both per-prompt recorder and Actions & Shortcuts assignments for included disabled AI prompts while leaving execution disabled. Reconcile open Input Remapping and AI prompt editors after changed definitions restore, including cloud imports with stable identities; unchanged prompt imports preserve unsaved drafts.
  • Validate every enabled service's credential requirements before key writes. Commit profiles and final grants together, and recover prior grants on later failures only when a fresh raw read proves the effective credential unchanged, including Translator's default-profile legacy fallback. Changed or unreadable results stay revoked.
  • Keep Clipboard retention deferral destination-local and durable across relaunches. Import commits it with changed retention settings; ordinary captures or local retention edits resume pruning. Failed deferral writes reject the operation safely.
  • Apply recorder shortcut customizations only after their selected source definitions restore successfully. Canonical assignments and recorder bindings use the same dependency checks; protected cloud-local bindings are merged afterward.
  • Validate Translator's final merged enabled configurations before mutation. Validate its exported profile projection without applying portable size limits to excluded local prompt text; pending recovery still blocks export.
  • Manual import replaces the entire selected Shortcuts category: omitted bindings reset to defaults, including excluded Clipboard item and prompt bindings. The warning is explicit in all 12 locales; unselected categories and local content remain intact. Cloud sync retains its separate machine-specific preservation policy.
  • Resolve pending recovery before ordinary AI prompt saves, without applying portable limits to excluded local libraries. Preserve destination-only Translator templates when source text is omitted, regardless of destination export opt-in.
  • Preserve open Translator drafts across shortcut/language-only imports while refreshing imported languages and changed profiles. In Launch Control, invalidate only drafts whose saved note text changed; omitted/unchanged notes retain drafts.
  • Retain archive format 7 and the existing PluginKit ABI. Add the generated inventory, contributor contract, localized UI, and app/plugin changelog entries.

Older archives cannot recover omitted settings. Install updated builds and export a fresh backup to transfer them.

Verification

Validated head: 9b9fe63a.

  • Hosted Build #1626 passed on this exact head.
  • Focused AI Assistant, Translator, Launch Control, host backup, and cloud-sync checks: 97 passed, with no skips.
  • Local make -j1 ci: 3,067 XCTest passed, 234 script tests passed, and the frozen PluginKit v7 binary compatibility client passed. Six on-demand desktop checks were skipped: four existing Window Switcher focus/search checks, backup acceptance, and the mounted Input Remapping editor check.
  • Two separate native mounted-editor checks passed through the real host cloud-import handler. Translator retained its prompt draft through shortcut-only and language-only restoration, refreshed both language fields before the next save, and replaced its editor when saved profiles changed. Launch Control preserved a private draft when incoming notes were omitted, then refreshed it when included saved text changed. These use synthetic stores, owned offscreen windows, and observation-only hooks archived outside the repository; no production hook is committed and no live transport/Keychain or launchctl operations ran.
  • The separate native dark export-sheet check passed with CUA-operated Return and Escape actions; one earlier capture attempt hit the evidence test's time limit and passed on a prompt retry. A four-frame native interaction sequence and dark screenshot are attached below.
  • A disposable mounted AI prompt editor probe passed through the real host cloud-import handler: unchanged definitions preserved an unsaved draft; changed definitions replaced the mounted editor; the next toggle retained restored text and added prompts. An observation-only hook exposed the actual mounted editor. No production hook is committed, and no live cloud transport or Keychain was used.
  • Earlier on-demand Input Remapping workspace/native-switch evidence remains applicable; that production path is unchanged by the latest fixes.
  • make validate-changelog and git diff --check passed.
  • Previously completed scripts/testing/preferences-backup/run.sh acceptance on the unchanged Window Layouts, export UI, and Right Click paths: actual modifier movement and centered-guide snapping on an owned test window, relaunch persistence, denied-permission preservation, native keyboard/accessibility checks, and same-window Right Click filter refresh from txt to md for the same application UUID.
  • Regression coverage verifies recorder dependencies after failed/deselected definition restoration, unchanged credentials across provider-order and later-write failures, separate legacy/scoped credential accounts, durable Clipboard deferral and write failures, included disabled-prompt recorder and canonical round trips, rejection of invalid enabled configurations after merging preserved text, excluded Translator prompt records above 1 MiB, selected versus unselected shortcut replacement, playback-session turnover and rollback, excluded AI Assistant prompt storage above 2 MiB, scoped/legacy journal recovery, and disabled service drafts. Committed source and dependency inputs match the locally tested state.

Desktop evidence used synthetic preferences and temporary app identities. The latest audio checks use injected routers/monitors; real audio hardware, native notification authorization dialogs/banner delivery, and live services were not exercised. The updated import warning was checked in the localized resources and compiled, without new native screenshots.

Review status

Ready for review following the maintainer's explicit decision to defer the low-frequency Window Layouts editor finding. The completed independent review covers the full cumulative 263-file PR at 9b9fe63a. Three fresh independent reviewers used an immutable snapshot without prior review reports or implementation rationale. All initial reports were captured before targeted reconciliation. The four earlier findings have fixes and passing focused/native validation.

Deferred finding (P2): focused Window Layouts name submission overwrites restored geometry. The maintainer accepted deferring this narrow overlap case and proceeding to review; it remains unfixed. At WindowLayoutsStore.swift:147–149, a same-UUID cloud import publishes changed command definitions. The mounted editor's synchronizeDraftIfNeeded (WindowCustomCommandSettingsView.swift:536–541) skips changes while its name field is focused; Return/blur then commits the entire stale command at lines 524–532. This overwrites successfully imported dimensions/anchor and can restore the previous local Run Link permission flag. Preserve current saved fields when accepting a name edit, or reconcile restoration even while the field is focused. The case requires focus to remain through restoration; changed identities or navigation unmounts avoid it.

A disposable native diagnostic reproduced the actual mounted state and real host cloud-import path: width 80% → imported 30% with external invocation disabled → name submission → width 80% and the old external-invocation flag restored. The diagnostic deliberately asserts this incorrect outcome: 1 passed, 0 failed or skipped. Stores, hotkeys and executor were synthetic; no real windows moved, live cloud, Keychain, or user assets were used. Observation hooks/tests were archived outside the repository and removed afterward. Source, index, immutable snapshot and unrelated local plan remain unchanged. No fixes were made during the read-only review.

UI evidence

Entry points: Settings → General → Preferences Backup; plugin settings for AI Assistant/Translator prompt inclusion, Launch Control note inclusion, and unavailable Right Click applications.

The completed export UI was captured and inspected locally in English, Simplified Chinese, German, and Arabic. The unavailable-application explanation and live editor refresh were also verified. Native before/after Input Remapping editor captures were also inspected locally. The screenshots below use synthetic settings. They cover light and dark appearances. The sequence below combines four actual native screenshots at two seconds per frame to show scrolling and expansion; it is a captured interaction sequence, not a real-time video. Export UI/Right Click captures predate the latest fixes on unchanged production paths; Input Remapping captures compare the stale editor with the repaired behavior.

Export coverage: English, Chinese, German, Arabic Export coverage in English Export coverage in Chinese Export coverage in German Export coverage in Arabic
Unavailable app explanation and Input Remapping before/after Unavailable Right Click application

Before: after a cloud-restored mapping and local toggle, the stale editor wrote Back over Forward.
Input editor before fix

After: Forward remains after the toggle.
Input editor after fix

Dark appearance and native interaction sequence Dark backup coverage details Native backup-sheet interaction sequence

Checklist

  • Core behavior and relevant risks are verified using existing tests, focused additions, or manual checks; results or limitations are recorded.
  • UI evidence is attached where applicable; shared components, themes, localization, and accessibility are respected.
  • User-facing documentation and changelog fragments are updated when required.
  • Plugin metadata, runtime contracts, action policies, and minimum-host compatibility agree.
  • Licensing and third-party notices are complete; no credentials, local configuration, or unrelated generated files are included.

@xcv58
xcv58 marked this pull request as ready for review October 26, 2026 02:01
@ggbond268
ggbond268 merged commit ae6837a into mactools-app:main Oct 27, 2026
2 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.

[Bug] Preferences Backup omits persisted settings from 36 plugins

2 participants