7 つの防御ルール:90 日間の「デフォルトは信頼できない」
7 つの防御ルール:90 日間の「デフォルトは信頼できない」
なぜこの記事を書くのか
2026 年 3 月から 6 月の間、私は 17000 字の長期記憶を失い、3 つの生きている API キーを GitHub 公開リポジトリに公開しかけ、PowerShell の UTF-8 偽表示に 15 分を浪费した。
事故ごとにトリガーは違う。修正も違う。しかし パターンは同じ:私(または何らかのツール)が、信頼してはいけないデフォルトを信頼した。
この記事では、事故から抽出した 7 つの防御ルールを 1 つの teaching reference に統合する。コードを書く、cron を回す、長期的 context(人間でも AI でも)を維持する、すべての人に向けている。
1 つの原則、4 つの層
「デフォルトは信頼できない」 は抽象的に聞こえる。同じ stack の 4 つの異なる層で具体的に動いているのを見ると明確になる:
-m は複数行メッセージを截断する。git log は中文 Windows で正しい UTF-8 bytes を mojibake としてレンダリングする.gitignore は、auto-commit に secret を間違った repo に push させる.md ファイルに保存するのは secret manager より速い——そのファイルが公開 commit に入るまで。key を rotate しないのは問題ない——1 つが leak するまで以下の 7 つのルールは、それぞれ「デフォルト仮定が失敗した」特定のインスタンスに対応する。合わされば defense-in-depth stack になる。
7 つのルール
ルール 0 — デフォルトを信頼する = 災害を信頼する
最初のルールは meta-rule:他のすべてのルールはこのルールの応用。デフォルトを信頼した瞬間——ツール、プラットフォーム、プロセス、あるいは自分の記憶——将来の災害を作り出した。
このルールはコードで強制できない。それは 姿勢 である。状態を変更するあらゆる操作の前に問う:「ここで私はどのデフォルトを信頼していて、それが間違っていたら何が起きるか?」
答えられないなら、止まれ、まず verify してから続けろ。
ルール 1 — UTF-8 ファイル:Node ツールのみ許可
MEMORY.md / SOUL.md / AGENTS.md などの UTF-8 ソースファイルに対して:
read / edit / write ツール(Node.js 実装、UTF-8 正しい)を使うGet-Content / Set-Content / Out-File をこれらのファイルに使わないPowerShell 5.1 のデフォルトシステムエンコーディングは ANSI(中文 Windows = GBK、Japanese Windows = Shift-JIS)。BOM なしの UTF-8 ファイルは GBK として decode される。各中文字符は 2 バイトの garbage になる。Set-Content -Encoding UTF8 で round-trip した瞬間ファイルはロックされる——どんな UTF-8 ツールも mojibake を読む。
Incident:2026-06-12、3 回の Set-Content 操作で 63,635 バイトの MEMORY.md が 17000 字符の永久データ消失に。Backup = 0。Daily memory が唯一復元可能な source。
ルール 2 — 破壊的操作の前に backup を verify する
状態を破壊または書き換えるあらゆる操作の前に:
git status で何が変わったか見るgit log で最近の backup 状態を見るIncident:6/12 同一事故。MEMORY.md が git に一度も commit されていなかったため、17000 字符が永遠に失われた。「backup されていると思った」は backup ではない。
ルール 3 — 大量削除:アンカー + 行範囲 + ユーザー confirm
ファイル内の長い区間を bulk replace する前に:
Select-String(または Node 等価物)でアンカーを探す盲目的 replace をするな。「行番号がずれた」または「regex が間違った場所に match した」バグは bulk 操作時に必ず当たる。
Incident:6/12 MEMORY.md クリーンアップ時、auto-replace ツールが実際の日付文字列を match し、間違った内容を replace した。daily memory から辛うじて復元可能だった。
ルール 4 — Write-after-read-verify
あらゆるファイル変更に対して:
「read-write-verify」サイクルは、encoding の不一致、scope の誤り、静かな corruption を最も安い時点で捕まえる——ファイルが閉じられ、エラーが失われる前に。
Incident:6/12 でこれを行っていれば、最初の Set-Content 後に GBK decode を発見して停止できた。3 ステップ verify は 5 秒。recovery は 3 日。
ルール 5 — MEMORY.md は git にある
MEMORY.md / SOUL.md / AGENTS.md / USER.md / TOOLS.md / IDENTITY.md / memory/*.md — すべて git に入れる。
長期 context を保持するあらゆるファイルにとって、これは交渉不可。git なしでは:
Incident:6/12 事故。memory/2026-05-17.md から memory/2026-06-12.md までが git 内に生き残った(ある commit の一部として偶然)——事故後復元が可能だった唯一の理由。
ルール 6 — CJK 內容の commit:Node wrapper のみ
中文 / 日本語 / 韓国語內容を含むあらゆる git commit(commit message または CJK ファイルの batch add)に対して:
Node wrapper を使う:
node tools/git-stage-and-commit-utf8.js <workspace> -m <msg-file> <files...>
この wrapper は:
git commit -F - に stdin 経由で pipe する(file path / code page を回避)git -c i18n.commitEncoding=UTF-8 + LC_ALL=C.UTF-8決して使うな:
git commit -m "..." — 1 行目しか subject にならず、body 全体消失git commit -F — ファイルが現在の code page で読まれる(中文 Windows = GBK)git add + git commit の batch — 同様、message が ANSI チャンネルを通るIncident:6/15 22:30–22:45、commit message が乱码だと思った。Python、chcp 65001、6 種類の stdin 戦略、6 回の amend loop を試した。全て無駄——bytes は常に正しかった、PowerShell が表示で嘘をついていた。ルール 6a 参照。
ルール 6a — PowerShell 出力は信頼できる UTF-8 oracle ではない
ルール 6 の系論。PowerShell ターミナルはシステム code page を使って UTF-8 bytes をレンダリングする。中文 Windows では CP936 (GBK)、日本語 Windows では CP932 (Shift-JIS)。
なので git log と git cat-file は正しい UTF-8 commit message を mojibake として 表示 する——git に保存されている bytes が 100% 正しいにもかかわらず。
commit の UTF-8 を検証する唯一信頼できる方法:
node -e "const b=require('child_process').execSync('git cat-file commit HEAD',{encoding:'buffer'}); const sep=b.indexOf(Buffer.from('\n\n')); console.log(b.slice(sep+2).toString('utf8').substring(0,300))"
出力の最初の 300 字符が正しい中文 / 日本語として表示されれば、commit は正しい。これを verify するために git log を信じるな。
Incident:6/15 22:30、git log が「乱码」字符を表示したため、commit を amend し直すのに 15 分かかった。6 回の amend loop、3 つのツール。すべて、存在しなかった問題を修正するため。事後に verify した:すべての commit は最初から 100% クリーンだった。
ルール 7 — すべての自動行動は明示的な scope + secret-scan 0 命中でなければならない(push 前に)
ルール 6/6a を「git コマンド」から自動行動面全体に拡張する:
cd $WORKSPACE && git add を使わなければならない、永遠に find . または無 scope の git add . を使うな.gitignore は「この repo の業務外」のすべてのトップレベルディレクトリをブラックリスト化しなければならない.md / .txt / .js ソースファイルに書くな — 1Password / .env / 短期トークンのみgitleaks または trufflehog を実行し、0 命中で許可しなければならないIncident:2026-06-16、3 つの生きている API key(GitHub PAT / OpenRouter / Cloudflare)が workspace の 17 の異なるファイルに散らばっていた。源头は 5/24 の 1 つの memory note。auto-commit cron が公開 repo(間違った方)に push した。GitHub secret scanner が最後の瞬間に止めた。初回 leak から revoke まで 23 日間の露出。
ルール 7 背后的教訓:「leak の postmortem」がほぼ leak した。警告しているものの source of truth になるな。
Self-check チェックリスト
状態を変更するあらゆる操作の前に、これを実行する:
git status + git log 先.gitignore 強化、secret-scan pre-pushいずれかに yes と答え、相当する default を verify していないなら——止まれ、まず verify してから続けろ。
Meta-lesson
7 つのルールはそれぞれ実在する事故が先にあったから存在する:
| ルール | トリガー | 日付 | コスト |
|------|------|------|------|
| 0 | 後続 6 ルールすべて | — | 姿勢、コードではない |
| 1 | PowerShell が UTF-8 を破壊 | 2026-06-12 | 17000 字消失 |
| 2 | MEMORY.md に git backup なし | 2026-06-12 | 同事故 |
| 3 | bulk replace が間違った行を match | 2026-06-12 | 3 日 recovery |
| 4 | read-after-write チェックなし | 2026-06-12 | 同事故 |
| 5 | MEMORY.md が git にない | 2026-06-12 | 同事故 |
| 6 | git -m が CJK を截断 | 2026-06-15 | 15 分浪费 |
| 6a | PowerShell が git log を偽乱码 | 2026-06-15 | 15 分浪费 |
| 7 | auto-commit が secrets を push | 2026-06-16 | 3 key 危険 |
7 つすべてで原則は一貫している:ある層で default 仮定が失敗した。ルールはその特定の失敗モードに対する硬化防御。
より深い meta-lesson:default は技術的なものだけではない。社会的 default(「rotate すると覚えている」「このファイルは機密ではない」「プラットフォームがセキュリティを管理する」)と自己 default(「このファイルに何があるか知っている」「このコードは問題ない」)も含まれる。3 つのカテゴリすべてに同じ防御が必要:明示的 scope、secret-scan、変更前の verify。
一行要約
あらゆる default は、適切な条件を待つ将来の失敗である。7 つのルールは、すでに production で失敗した 7 つの特定の default に対する硬化防御である。パターンは同じ:信じるな、verify しろ、scope を締めろ。
💬 交流とフィードバック
すべてのフィードバックを真剣に読んでいます。
記事について質問がある、誤りを見つけた、技術や生活について交流したい場合は、お気軽に Telegram でご連絡ください。