fix: loadSettings の migration 保存失敗で全設定が既定値に倒れるのを防ぐ (#448) - #450
Merged
Merged
Conversation
- 単一 try/catch を 3 段(migration 実行 / migration の disk 保存 / 読み出し ループ)に分割し、それぞれの失敗で既定値へ倒す範囲を分ける - migration の settingsSave 失敗では読み出せた設定を返す(settings:set 済みの 値は main cache 上で有効なため、セッション全体を既定値にする理由がない) - 3 経路とも error toast で通知する。従来は無通知で loadRemoteImages が 既定 (true) へ戻り、ユーザーが気付けなかった - migration 保存失敗の文言は「次回起動時に移行を再試行」。_schemaVersion も disk に載らないため値は巻き戻らず再実行されるので、saveSetting の 「元の値へ戻ります」はこの経路では成立しない - load 側の通知は saveSetting のスロットル窓を共有しない(起動時通知が直後の save 失敗通知を黙らせるのを防ぐ) - store.test.ts に失敗系 6 ケースを追加
- 「次回起動時に移行を再試行します」は全ケースで真にならない。main 側 persist() は cache 全体を書き出すため、後続の settings:save や window state 保存が 1 回 でも成功すれば _schemaVersion ごと disk に載り再実行されない。両ケースで真な 「今回の起動では有効・移行結果は失われない」に絞る - 読み出し失敗の文言も「設定ファイルは変更されません」→「既定値をファイルへ 書き戻すことはありません」。migration 保存が成功した直後に読み出しが失敗する ケースでは前者は偽になる - migration の再実行耐性 (冪等性) を docs/specification.md と Migration interface に明文化。本 PR で「失敗しても読み出しを継続し次回起動で再実行」が正式な回復 経路になったため、要件を暗黙にしない - store.test.ts の mockStatefulStore を describe 上位へ hoist し、既存 migration テストのインライン stateful mock と一本化
- test 名とコメントが「次回起動で migration が再実行される」という旧主張のまま だったのを、直前 commit が否定した内容に合わせて更新 - 読み出し失敗経路のコメント「settings.json は無傷のまま」も同型の過剰主張。 段 2 の migration 保存が成功した後にこの経路へ入る世界では偽になる - 「既定値をファイルへ書き戻すことはありません」の節を test で pin。旧文言への 回帰が素通りしていた(mutation で KILLED を確認) - migration の再実行は後続 persist が一度も成功しなかった場合に限るため、 docs / interface コメントの断定を「再実行され得る」に修正
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概要
loadSettingsの失敗ハンドリングを 3 段に分割し、migration の disk 保存が失敗しただけでセッション全体が全設定既定値へ倒れる欠陥 (#448) を解消する。3 経路とも error toast で通知するようにし、無通知の巻き戻りを無くす。従来は
loadSettings全体が単一のtry/catchで包まれており、migration 適用後のsettingsSave()が throw すると settings.json 自体は読めているのに catch が{ ...DEFAULTS }を返していた。結果としてloadRemoteImagesも既定 (true = リモート画像許可) へ戻るが、ユーザーへの通知は一切なかった。関連 Issue
Closes #448
移行 Stage
変更内容
applyMigrations自体の失敗 ② migration 結果の disk 保存失敗 ③ 読み出しループの失敗。①② では既定値へ倒さず読み出しを継続する(settings:setは main 側 cache を即更新するので、移行結果も他の設定値も今回の起動中は有効)。全既定値へ倒すのは settings IPC 自体が壊れている ③ のみsettings:save/ window state 保存)が 1 回でも成功すれば_schemaVersionごと disk に載り、一度も成功しなければ次回起動で migration が再実行される。どちらでも失われないので、文言は「今回の起動では有効・失われることはありません」まで降ろす(「次回起動時に再試行します」は前者で偽、saveSettingの「元の値へ戻ります」も成立しない)saveSettingのスロットル窓を共有しない — 共有すると起動時の通知が直後のユーザー操作起因の save 失敗通知を黙らせ、設定の保存失敗が無通知で、プライバシー設定が次回起動時に巻き戻りうる #446 で可視化した巻き戻り警告が再び無通知になるdocs/specification.mdの移行フローとMigrationinterface のコメントに書き下ろしたloadSettingsテストの stateful mock も共通ヘルパーへ一本化)動作確認
検証エビデンス
リスク分類
tier: medium — reasons: (classify-risk.sh の出力は
{"tier": "medium", "reasons": []}。特別な加点要因なしの既定 tier)実行した検証
./node_modules/.bin/vitest run./node_modules/.bin/vitest run src/lib/store.test.ts src/lib/store-migration.test.tspython3 scratchpad/s148-mutate.py/s148-mutate2.py./node_modules/.bin/biome check --write src/lib/store.ts src/lib/store.test.ts src/lib/store-migration.ts./node_modules/.bin/tsc --noEmit -p tsconfig.node.json / tsconfig.web.json / tsconfig.e2e.jsone36a4d8..54f759a)pnpm test:e2ee2e/search.spec.ts:232(#300 の上限 notice)で本 PR の変更経路とは無関係、retry で greenpnpm test:e2e:electrontestjobレビュー指摘と対応
store.test.ts—mockStatefulStoreが既存テストのインライン stateful mock と重複(reuse / simplification の 2 観点が収束)store.ts— 3 段の try/catch がボイラープレートの反復store.ts—notifyLoadFailureをnotifySaveFailureのレジストリへ統合すべき(altitude)store.ts— 「次回起動時に移行を再試行します」は全ケースで真にならない(後続 persist の成功で_schemaVersionごと disk に載る)persist()が cache 全体を atomic write することを実装で裏取りし、両ケースで真な文言へ変更docs/store-migration.ts— migration の再実行耐性が未文書化のまま回復機構として依存されているMigrationinterface に冪等性要件を明記store.ts— ③ の「設定ファイルは変更されません」は ② 成功後に ③ が失敗する世界で偽undefined(実 IPC はnull)store.test.ts— test 名とコメントが「次回起動で再試行」の旧主張のまま(同一 commit が否定した内容)store.ts— ③ のコメント「settings.json は無傷のまま」が同型の過剰主張docs/store-migration.ts— 「再実行される」は断定しすぎ(後続 persist が一度も成功しなかった場合に限る)store.test.ts— 「既定値をファイルへ書き戻すことはありません」が pin されておらず旧文言への回帰が素通りstore-migration.test.ts— 冪等性専用の pin テストが未追加追跡先
backlog delta: 起票 0 件 / 本 PR で close 1 件 (#448) / 現在 open 17 件
本 PR で fix しない finding ((b) 起票 / (c) 対応しない): なし
Draft 判定