Pasty v0.9.6-beta
Pasty v0.9.6-beta — 14 件の P0 安定化パック
「データを失わない、操作を取りこぼさない、機密を漏らさない。」v0.9.5-beta の Stability Audit で洗い出された 14 件の P0 をまとめて落とします。
🛡 信頼性向上
Soft-delete の徹底
クリップを削除した瞬間に DB から物理消去するのをやめ、deleted_at タイムスタンプで 論理削除に統一 しました。これまでは UI 上の削除と内部読み出しのタイミングで「削除したはずのクリップが一瞬戻る」「FTS5 の結果に残骸が混じる」といった不整合が稀に発生していました。UI / Recent / Search / byId / FTS5 JOIN の全 SELECT パスに WHERE deleted_at IS NULL を強制し、削除されたクリップは表示・検索の双方から確実に消えます。
FTS5 バックフィル冪等マーカー
全文検索インデックス (FTS5) の再構築は本来 v8 で完了しているはずですが、過去のアップグレード経路では稀に未完で終わるケースが報告されていました。v9 で pasty_meta テーブルを新設し、v8.fts5_backfilled = true マーカーが無い場合は起動時に冪等で再投入します。一度完了すれば二度走らないので起動が遅くなることもありません。
DB 破損からの自動復旧
これまで ClipStore の初期化に失敗するとアプリは fatalError でクラッシュし、ユーザーは手動でファイルを退避する必要がありました。これからは clips.db を clips.db.corrupt-<timestamp> に退避し、新規 DB で起動を続行、NSAlert で「DB を再構築しました。バックアップは clips.db.corrupt-... に保存されています。」と通知します。データロスはバックアップで救済可能、起動だけは止まりません。
🧹 ディスク掃除
起動時 Blob GC
画像 / 動画 / PDF / ファイルクリップの実データは ~/Library/Application Support/io.pasty.app/blobs/ 配下に保存されます。これまでは tombstone 化したクリップの blob が永遠に残り続けていました。起動から ~1 秒後に BlobGC.sweep がバックグラウンドで走り、deleted_at から 30 日経過したクリップの blob と、どのクリップからも参照されない孤児 blob を削除します。30 日のグレース期間で、誤削除した直後でも元データは残っているので Undo 可能なまま掃除が進みます。
🔒 セキュリティ強化
アクセシビリティ未許可時のサイレント失敗を解消
これまで Pasty のアクセシビリティ権限が無効化されている状態でクリップを貼ろうとすると、CGEvent.post が空打ちになって 「貼ったつもりが貼れていない」 という最悪のサイレント失敗を起こすことがありました。AXIsProcessTrusted() で全 CGEvent.post サイトをガードし、未許可ならば pastyPasteFailed 通知を発火、Toast でユーザーに「アクセシビリティ権限を許可」と促せるようにしました。Blob 読み込み失敗も同様に通知化、無音で失敗することは無くなります。
OCR テキストの機密データ自動マスク
画像クリップから抽出した OCR テキストには稀にクレジットカード番号 / SSN / マイナンバー / API トークン / IBAN / 電話番号が含まれます。デフォルト ON で 正規表現 + Luhn 検証 で検出し、[CARD] / [SSN] / [MYNUMBER] / [TOKEN] / [IBAN] / [PHONE] に置換してから DB / FTS5 / AI に渡します。設定 → OCR の「機密データ自動マスク (CC / 身分証 / API トークン)」で無効化も可能。メールアドレスは検索性のため保持します。
NotificationCenter observer リーク修正
StripPanel が NotificationCenter にぶら下げた observer が .onDisappear で外れず、長時間稼働で memory pressure が増えていた問題を修正。observer token を捕捉して disappear 時に確実に剥がします。
MultiMode ペースト中レース修正
複数選択で連続ペースト中に ClipStore の更新が走ると、選択中のクリップ ID 配列が縮んでペースト対象がブレるケースがありました。ペースト開始時に ID をスナップショットして ID キー解決で 1 件ずつ処理、tombstone 化したクリップはスキップして次に進みます。
📊 操作の堅さ
NotchHover の表示中断レース修正
通知バー (NotchHover) の dismiss アニメーション中に再度トリガーすると、アルファ値が中途半端な状態で固まったり、Z オーダーが沈んだまま再表示される問題を修正。isDismissing フラグで状態遷移を捉えて、show 時に進行中アニメーションをキャンセルして見える状態を復元してから表示し直します。
サムネイル生成の TOCTOU 修正
動画 / PDF のサムネイル生成で、同じクリップに対する 2 つの concurrent リクエストが「片方が走っていればもう片方は待つ」をすり抜けて重複生成していた問題を NSLock で atomize。重複したファイル I/O が消えます。
📦 内部修正
FileManager.urls(...).first!を guard 化 (URLLinkPreview / DragDropSupport)URL(string: "about:blank")!を nil-coalescing でフォールバック (DragDropSupport)- ペースト失敗時の
pastyPasteFailed通知導入 (将来の Toast UI の土台) - BlobGC + soft-delete 整合性テスト 8 件追加 (ClipStoreSoftDeleteTests)
- SensitiveDataFilter のパターン網羅テスト 12 件追加 (SensitiveDataFilterTests)
🧪 テスト
全 36 テスト pass — 既存 16 + 新規 20 (ClipStore soft-delete × 8、SensitiveDataFilter × 12)。
リリース詳細: https://github.com/IvyGain/Pasty/releases/tag/v0.9.6-beta
GitHub Releases で詳細を見る ↗