[{"data":1,"prerenderedAt":361},["ShallowReactive",2],{"content-/mac-migration-backup-and-delete-guard":3,"all-pages-for-dir":341,"related-/mac-migration-backup-and-delete-guard":342,"og-image-/mac-migration-backup-and-delete-guard":360},{"id":4,"title":5,"body":6,"category":322,"concepts":323,"description":324,"extension":325,"meta":326,"navigation":114,"ogImage":323,"path":327,"project_name":328,"published":329,"publishedAt":330,"seo":331,"source":332,"stem":333,"tags":334,"todo":323,"unpublished":329,"updatedAt":323,"__hash__":340},"pages/2026-08/2026-08-04/mac-migration-backup-and-delete-guard.md","Macへの移行でバックアップを作り直したら、削除ガードが動いていなかった",{"type":7,"value":8,"toc":310},"minimark",[9,13,17,20,23,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,144,147,150,160,175,178,181,192,195,198,201,204,211,214,217,220,223,226,229,232,235,238,245,251,254,257,260,263,266,269,272,275,278,281,284,287,290,294,297,300,303,306],[10,11,5],"h1",{"id":12},"macへの移行でバックアップを作り直したら削除ガードが動いていなかった",[14,15,16],"p",{},"朝の日記コマンドの出力に、見慣れないスタックトレースが1行だけ混じっていた。",[14,18,19],{},"記事の生成は止まらず、最後まで通った。\nだから最初は気に留めなかった。\n別の記事を並列で書かせている間に、そのエラーだけ調べさせた。",[14,21,22],{},"無害ではなかった。",[24,25,26],"h2",{"id":26},"朝のログに混じっていたエラー",[14,28,29],{},"Nodeがモジュールの解決に失敗したときのエラーだった。",[14,31,32],{},"設定ファイルには、削除コマンドを実行前に検査するフックのパスが書いてある。\nそのパスが旧マシンのままで、指している実体はこちらのマシンに無かった。\nフックの本体を置いてあるリポジトリごと、まだクローンしていなかった。",[14,34,35],{},"読み込みに失敗したフックは、拒否も許可も返さない。\n拒否の判断が返らなければ、コマンドはそのまま実行される。\n再帰削除を止める仕組みが、止める側だけ黙って外れていた。",[14,37,38],{},"同じ設定ファイルには、シェルコマンドを分類器に通すための禁止文言もある。\nそちらも旧マシンのパスで書いてあり、文字列が一致しないので実質的に効いていない。",[14,40,41],{},"移行してからの数日、その状態で動いていたことになる。",[24,43,44],{"id":44},"保存先を1つに減らす",[14,46,47],{},"バックアップ一式をMacへ移してほしい、と頼んだ。\nただし今回は保存先が1つしかない。",[14,49,50],{},"Windows側では、暗号化したセッション履歴をクラウドストレージと外付けSSDの2か所へ送っていた。\nSSDは持ってきていないので、クラウド側だけにしてほしいと伝えた。",[14,52,53],{},"2系統を前提にした箇所が2つ引っかかった。\n1つは外付け側への送出そのもの。\nもう1つは、どこまで送ったかを記録する目印の前進判定だった。",[14,55,56],{},"元の設計では、片方でも失敗したら目印を前に進めない。\n次の実行で同じ範囲を送り直すための仕掛けだ。\nただし系統が1つになると、無効な系統の失敗を永久に待つことになる。\n有効な系統だけを見て判定するように変えさせた。",[14,58,59],{},"Windows側のノートPCも同じリポジトリを使う。\n上書きはせず、OSを見て分岐させる方針にした。",[14,61,62],{},"クラウド側にはデスクトップ同期のフォルダが無いので、API経由で送る形になった。",[24,64,65],{"id":65},"bashが全角の括弧を変数名として食う",[14,67,68],{},"移植で最初に転んだのは、シェルのバージョン差だった。",[14,70,71],{},"macOSに最初から入っているbashは3.2で、Windows側で使っていた4系とは挙動が違う。\n暗号化も送出もせず、収集と完全性検証までを流すDRY_RUNで走らせたら、変数が空になる箇所が出た。\n原因は日本語のログ出力だった。",[73,74,79],"pre",{"className":75,"code":76,"language":77,"meta":78,"style":78},"language-bash shiki shiki-themes vitesse-light vitesse-light","# 3.2 は「MANIFEST（...」までを変数名として読む\necho \"$MANIFEST（...\"\n\n# 直した形\necho \"${MANIFEST}（...\"\n","bash","",[80,81,82,91,109,116,122],"code",{"__ignoreMap":78},[83,84,87],"span",{"class":85,"line":86},"line",1,[83,88,90],{"class":89},"sxvE3","# 3.2 は「MANIFEST（...」までを変数名として読む\n",[83,92,94,98,102,106],{"class":85,"line":93},2,[83,95,97],{"class":96},"sz8Xr","echo",[83,99,101],{"class":100},"sMJiu"," \"",[83,103,105],{"class":104},"sdGka","$MANIFEST（...",[83,107,108],{"class":100},"\"\n",[83,110,112],{"class":85,"line":111},3,[83,113,115],{"emptyLinePlaceholder":114},true,"\n",[83,117,119],{"class":85,"line":118},4,[83,120,121],{"class":89},"# 直した形\n",[83,123,125,127,129,133,136,139,142],{"class":85,"line":124},5,[83,126,97],{"class":96},[83,128,101],{"class":100},[83,130,132],{"class":131},"shFtX","${",[83,134,135],{"class":104},"MANIFEST",[83,137,138],{"class":131},"}",[83,140,141],{"class":104},"（...",[83,143,108],{"class":100},[14,145,146],{},"全角の丸括弧が変数名の直後に来ると、3.2はそれを変数名の一部として読む。\n存在しない名前の変数を探しにいって、空を返す。",[14,148,149],{},"全スクリプトを走査させたら12箇所あった。\nすべて波括弧で囲う形に直した。\nWindows側の4系でも意味は変わらないので、片方だけ動く直し方にはならない。",[14,151,152,153,156,157,159],{},"ここでDRY_RUNが通り、59ファイル127MBの収録一覧が完全に一致した。\n鮮度をチェックするスクリプトがGNUの ",[80,154,155],{},"date"," を前提にしていた箇所も、BSDの ",[80,158,155],{}," で通るよう直した。",[14,161,162,163,166,167,170,171,174],{},"残りは本番で走らせてから出てきた。\n同じ3.2でもう1つ引っかかる。\n空の配列を ",[80,164,165],{},"\"${arr[@]}\""," で展開すると、",[80,168,169],{},"set -u"," が未定義として弾く。\nこちらは ",[80,172,173],{},"env"," を挟む形に変えた。",[24,176,177],{"id":177},"パスフレーズが渡らない",[14,179,180],{},"暗号化のところでも止まった。",[14,182,183,184,187,188,191],{},"gpg 2.x は ",[80,185,186],{},"--passphrase-fd"," でパスフレーズを渡すとき、",[80,189,190],{},"--pinentry-mode loopback"," を併記しないと受け取らない。\nWindows側ではagentの設定で通っていたらしく、この指定が無いまま動いていた。\n両方のOSで有効な形に直させた。",[24,193,194],{"id":194},"テストコマンドが自分のガードに弾かれた",[14,196,197],{},"削除ガードのフックも、Windows版を壊さないようOS判定で分岐させた。",[14,199,200],{},"判定が正しく効くかどうかは、実際にJSONを流して確かめさせた。\n許可すべきものと拒否すべきものを9通り流して、すべて期待どおりだった。",[14,202,203],{},"設定ファイルは書き換える前に退避を取らせた。\nフック2件を両OS対応に書き換え、失敗したときに止まる性質はそのまま残した。\n分類器に渡す禁止文言にはこちらのマシンのパス基準を足し、Windows側の記述は消していない。",[14,205,206,207,210],{},"書き換えたあとで動作確認のコマンドを流したら、そのコマンド自体が拒否された。\n文字列に ",[80,208,209],{},"~/.claude"," の削除が含まれていたからだった。\n確認したかったことが、確認の失敗という形で返ってきた。",[24,212,213],{"id":213},"復元できて初めてバックアップになる",[14,215,216],{},"本番で走らせた。",[14,218,219],{},"127MBがクラウドへ上がり、サイズが一致し、目印も前に進んだ。\n保存先の最新が8月1日のままだったのが、この日のものに入れ替わった。\n8月1日は、Windows側で最後に走った日だ。",[14,221,222],{},"ここで止めれば「バックアップが動いた」で終わる。\n戻せるかどうかは別の話なので、復元テストも移植させた。\nクラウドから実際に落として復号し、展開した。\n60ファイル全部のSHA-256を突き合わせたら、全件一致した。",[14,224,225],{},"日次の自動実行はlaunchdに登録した。\n懸念はここだった。\nバックアップはパスワードマネージャからパスフレーズを取り、クラウドへの送出にも認証が要る。\nどちらも普段はターミナルから叩いていて、launchdが渡す環境はそれとは違う。",[14,227,228],{},"実際に起動させたら exit 0 で通り、パスフレーズの取得もアップロードも抜けた。",[14,230,231],{},"復元テストのほうは10日周期で登録した。\nセッション履歴の自動削除は無効にしてあり、6月19日分がまだ残っている。\n消える心配は当面ないが、壊れていることに早く気づける周期のほうがいい。",[24,233,234],{"id":234},"消し忘れた登録",[14,236,237],{},"設定ファイルを開いていて、セッション開始時に走るスクリプトの登録が目に入った。",[14,239,240,241,244],{},"拡張子が ",[80,242,243],{},".ps1"," で、パスがWindowsのものだった。\nMacでしか使わないのに、なぜPowerShellなのか分からなかった。",[14,246,247,248,250],{},"タイムスタンプが答えだった。\n",[80,249,243],{}," は8月2日の08:39、同じ処理のshell版は09:15。\n移行の初日にPowerShell版を先に書いて登録し、36分後にshell版へ作り直している。\nそのとき、設定ファイルから古いほうの登録を消していなかった。",[14,252,253],{},"残骸なので消させた。\n設定に名前だけが残って実体が無いのは、削除ガードと同じ形だ。",[14,255,256],{},"許可リストにも同じものが溜まっていた。\nWindows固有のエントリが22件。\n全部消すとノートPC側で許可が外れるので、危ないものだけを3件外して、macOS用を足した。",[24,258,259],{"id":259},"あるはずのコマンドが見つからない",[14,261,262],{},"同じ朝、支援先の案件を扱うリポジトリで作業していて、日記コマンドが候補に出てこなかった。",[14,264,265],{},"ユーザーレベルに置いてあるつもりでいたので、消えたのかと思って調べさせた。",[14,267,268],{},"消えていなかった。\nそのコマンドはユーザーレベルではなく、このサイトのリポジトリのプロジェクトレベルに置いてある。\n別のリポジトリで作業していたのだから、候補に出る対象ではない。",[14,270,271],{},"先月末に環境を丸ごと失っている。\nだから見つからないものを見ると、まず消えたと疑う。\n今回は、置き場所を間違えて覚えていただけだった。",[14,273,274],{},"日記コマンド自体にも手を入れた。\n月次のデータベースバックアップを回すステップがWindows専用の資材に依存していて、Macでは実行できない。\nその日は手で飛ばしたが、手順定義に「macOSではスキップ」と書かせた。",[24,276,277],{"id":277},"ステータスラインの数字が空だった",[14,279,280],{},"ステータスラインに、5時間と1週間、それに上位モデルの利用制限のパーセンテージを出している。",[14,282,283],{},"Macに移してから、この3つが出ていなかった。\nWindowsとMacの互換性だろうと見当をつけて、調査と修正を頼んだ。",[14,285,286],{},"そのとおりだった。\n違っていたのは認証情報の置き場所で、MacではOAuthのトークンがKeychainに入る。\nスクリプトはWindowsのファイルだけを見ていた。\nだから取得が丸ごと失敗して、3つとも空欄になっていた。",[14,288,289],{},"Keychainから無人で取り出せることを、中身は出さずキー名だけ見て確認させた。\nそのうえでKeychain経由の取得を足した。\n実際に走らせて、3つのパーセンテージが並ぶところまで見た。",[24,291,293],{"id":292},"移行で壊れたものは壊れたと言ってこない","移行で壊れたものは、壊れたと言ってこない",[14,295,296],{},"この日直した3つは、症状の出方が違うだけで形は同じだった。",[14,298,299],{},"削除ガードはスタックトレースを1行出した。\nセッション開始のスクリプトは何も出さず、設定ファイルに名前だけ残した。\nステータスラインは、数字のあった場所が空欄になった。",[14,301,302],{},"質が悪いのは、エラーを出さないほうだ。\nバックアップが動いていることは、送出のログを見れば分かる。\nガードが効いていないことは、消されるまで分からない。",[14,304,305],{},"だから復元テストを周期で回すことにしたし、フックは9通りのJSONを流して確かめた。\n「設定に書いてある」と「動いている」は別のことだと、移行のたびに教わっている。",[307,308,309],"style",{},"html pre.shiki code .sxvE3, html code.shiki .sxvE3{--shiki-default:#A0ADA0;--shiki-dark:#A0ADA0}html pre.shiki code .sz8Xr, html code.shiki .sz8Xr{--shiki-default:#998418;--shiki-dark:#998418}html pre.shiki code .sMJiu, html code.shiki .sMJiu{--shiki-default:#B5695977;--shiki-dark:#B5695977}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .shFtX, html code.shiki .shFtX{--shiki-default:#999999;--shiki-dark:#999999}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":78,"searchDepth":93,"depth":93,"links":311},[312,313,314,315,316,317,318,319,320,321],{"id":26,"depth":93,"text":26},{"id":44,"depth":93,"text":44},{"id":65,"depth":93,"text":65},{"id":177,"depth":93,"text":177},{"id":194,"depth":93,"text":194},{"id":213,"depth":93,"text":213},{"id":234,"depth":93,"text":234},{"id":259,"depth":93,"text":259},{"id":277,"depth":93,"text":277},{"id":292,"depth":93,"text":293},"dev",null,"主作業機をMacに移した環境の作り直しの記録。バックアップ一式をmacOSへ移植して保存先をクラウド単系統にし、bash 3.2の変数展開とBSD date、gpgのパスフレーズ渡しでつまずいた。旧マシンのパスが残って削除ガードが止まっていたことにも気づいた。","md",{},"/mac-migration-backup-and-delete-guard","claude-code-tools",false,"2026-08-04T00:00:00.000Z",{"title":5,"description":324},"make-diary","2026-08/2026-08-04/mac-migration-backup-and-delete-guard",[335,336,337,77,338,339],"Mac","バックアップ","Claude Code","launchd","開発環境","NQ_mEU7uBeU9fANcAnY8ein8p7BeiDf7HOUz7PXALaw",[],[343,347,351,354,357],{"title":344,"path":345,"publishedAt":346},"Macに移った2日目、引っかかるたびに設定を直した","/mac-workflow-friction-fixes","2026-08-03T00:00:00.000Z",{"title":348,"path":349,"publishedAt":350},"2026年8月2日の開発日記 - WindowsからMacへ環境を移した一日","/2026-08-02-diary","2026-08-02T00:00:00.000Z",{"title":352,"path":353,"publishedAt":350},"Mac の新環境で Gmail 接続を確かめ、送信前に下書きで止める","/gws-cli-mail-draft-on-mac",{"title":355,"path":356,"publishedAt":350},"Windows 前提のリポジトリを Mac で動かし、herdr でセッションを並べ始めるまで","/mdx-playground-mac-migration",{"title":358,"path":359,"publishedAt":330},"2026年8月4日の開発日記 - 守ってくれているつもりの仕掛けが、止まっていた","/2026-08-04-diary","https://log.eurekapu.com/og/blog/mac-migration-backup-and-delete-guard.png?v=2026-08-04T00%3A00%3A00.000Z&title=Mac%E3%81%B8%E3%81%AE%E7%A7%BB%E8%A1%8C%E3%81%A7%E3%83%90%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%E3%82%92%E4%BD%9C%E3%82%8A%E7%9B%B4%E3%81%97%E3%81%9F%E3%82%89%E3%80%81%E5%89%8A%E9%99%A4%E3%82%AC%E3%83%BC%E3%83%89%E3%81%8C%E5%8B%95%E3%81%84%E3%81%A6%E3%81%84%E3%81%AA%E3%81%8B%E3%81%A3%E3%81%9F&author=Kei%20Komatsu&sig=ecbd8564c0fb2503",1786233142152]