ssotize-local について
ssotize-localは、複数のパスで同じ内容を必要とする場合に、重複ファイルやディレクトリツリーを集約するスキルです。監査と承認の後にリンクを作成し、内容や保持属性を検証します。
主な機能
- 01重複を監査して計画を作成
- 02パスとリンク機能を調査
- 03内容とファイル属性を比較
- 04承認後にリンクを作成
- 05リンクを検証し復元を支援
活用シーン
- 01一つのファイルを複数パスで共有
- 02重複ディレクトリツリーの参照元を統一
- 03リンク変更と可逆性を確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ lilmgenius/ paperthin --skill ssotize-localインストール後、Claude Code で/ssotize-localを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlscripts/identity.mjsidentity.test.mjs詳細
重複するファイルやツリーには正本となる配置場所を一つだけ設け、監査と承認の後、ほかのすべてのパスをその正本と同一のものにします。
目標
重複するファイルやツリーには正本となる配置場所を一つだけ設け、ほかのすべてのパスを、このマシンのファイルシステムが保持するその正本と同一のもの、つまりハードリンク、シンボリックリンク、ジャンクション、またはバインドマウントにします。その過程で失われるものはありません。バイト列も、ACL、所有者とモード、名前付きストリーム、xattr、保持する必要があるタイムスタンプを含む保存契約も失われません。複数のパスで同じバイト列を必要とし、テキストによる参照では対応できない場合に使用します。
-local サフィックスは、ポータビリティがその方式に依存することを意味します。クローン、コピー、別のホストのどれでも維持されるかは、「ルール」の各方式の項で示します。重複が見つからなかった実行では何も変更されず、いずれかのゲートで停止することも有効な結果です。
ワークフロー
決定的な各ステップでは、このスキルのフォルダーから node scripts/identity.mjs を実行し、サブコマンド probe、digest、compare、link、verify、unlink を使用します。すべてのサブコマンドで --json を指定できます。
-
監査。 重複するファイルやツリーについて、Skill ツールを「ssotize」とともに呼び出し、読み取り専用の監査と計画を実施します。同じバイト列を必要とする各コピーについて、リンクを提案します。その結果が今回の実行におけるインベントリです。インベントリには、出現箇所の表、正本となる配置場所とその理由、矛盾、固有の詳細、計画が通過すべき承認ゲートが含まれます。ssotize が停止した場合、今回の実行も停止します。ssotize がインストールされていない場合は、その旨を伝えて停止します。監査と承認なしにリンクを作成すると、安全を確保するゲートを省略するためです。
-
リンク用にインベントリを拡張する。 リンクに必要な情報を追加します。すべてのコンシューマー、エイリアス、信頼境界、隠し項目と空の項目、ネストされたリンクを含め、各リンクのターゲットを明示的に解決します。共有ディレクトリには、コンシューマーが必要とするすべてのメンバーを含めます。
-
推測せず、プローブする。 すべての候補とすべての宛先親ディレクトリに対して
node scripts/identity.mjs probe <path>...を実行し、コマンド、終了コード、出力、時刻を記録します。プローブはパス、リンクの状態とターゲット、ID とリンク数、サイズ、mtime、導出可能な場合はマウントルート、そして一時ディレクトリでテストしたリンク機能を報告します。一時ディレクトリへの書き込みが、監査で行われる唯一の書き込みです。宛先の権限、ローカル性、ファイルシステム、マウント権限は個別にプローブし、すべての祖先リンクとマウントを解決します。ラベルは何の証明にもならず、不明な点は未証明のままです。 -
書き込み元について確認する。 人間が次の正確な質問に回答します。「メンテナンスウィンドウ、またはすべての書き込み元が遵守するロックによって、変更と検証の全期間にわたり、並行するすべての書き込み元を排除できますか?」明示的な「はい」のみを認め、その回答を記録します。ハンドルの一覧はスナップショットであり、ロックではありません。「いいえ」の場合、または回答がない場合は、「Exclusive access unproven for ; no mutation」と報告して停止します。無関係なプロセスを終了させてはいけません。
-
ダイジェストを取得して比較する(読み取り専用)。
node scripts/identity.mjs digest <path>...は、すべての名前を通じたパス、mtime、サイズ、sha256、ID、ソート済みの相対メンバー、マニフェストハッシュを出力します。node scripts/identity.mjs compare <a> <b>は、バイト列と ID を分類し、同一または同一性がある場合は終了コード 0、差異または固有のメンバーがある場合は 3、エラーの場合は 1 で終了します。ACL、所有者とモード、名前付きストリーム、xattr、タイムスタンプは個別に調べ、読み取りまたは ID の変更によって生じた差分を報告します。このスクリプトが証明するのは、主なバイト列とメンバーのみです。ツールがない場合、読み取りが拒否された場合、またはフィールドがサポートされていない場合、契約は未証明のままです。 -
分類。 正本となる配置場所に照らして候補を分類し、ケースごとに1行を記載します。
ケース 分類 対応 バイト列と契約が同一 適格 承認後にリンクし、バックアップは不要 バイト列は同一だが、契約が異なるか読み取れない 未証明 差分を明示してから停止するか、保存を明示的に解決します。バックアップは同一性の証明にはなりません バイト列が異なる インベントリですでに報告されている矛盾 人による選択または依頼されたマージのために停止します。新しい方や大きい方を優先することは決してありません 一方の場所にのみ存在 取り込み 人の個別承認を得たうえで、対象ごとに Skill ツールを再度「ssotize」と呼び出し、リンク前に再監査します すでに意図された正規のものにリンク済み 同一性が証明された変更なし 報告して再検証します。再リンクは決して行いません -
報告します。 パスごとに、インベントリの出現箇所テーブルの横に、選択した段階、置き換えられた名前、保存場所、証明、元に戻す操作を記載します。個別承認を得て取り込みを実行した場合は、その結果に対して手順 1〜6 を再実行し、新しいインベントリに基づいて報告します。取り込みの承認が手順 8 の代わりになることはありません。
-
承認を得ます。 インベントリの承認ゲートで、人に「変更ステップでも同一であればリンクする」という正確な文言で計画を提示します。この文言だけがリンクの手順を対象とします。承認がなければ、読み取り専用の報告を行った時点で停止します。この承認は、未解決の競合や後からの変更には適用されず、取り込み、マージ、コピーにはそれぞれ個別の同意が必要です。承認後、保持する必要のあるタイムスタンプを決めるのは人です。タイムスタンプを参照するもの(mtime を基準にする同期やビルド、バックアップ、台帳など)に基づいて各タイムスタンプを提案し、人が決定するまで保持します。リンクの名前はすべて正規のもののタイムスタンプを示すため、保持すべき重複ファイルのタイムスタンプは、手順 9 で検証する保存先に含めます。
-
書き込みの直前に再確認します。 バックアップや照合を含め、対象への書き込みを行う直前に、候補を再列挙し、項目ごとにパス、mtime、サイズ、sha256、契約、同一性、除外の証拠を、承認済み監査と照合しながら再読み込みします。候補が追加、欠落、読み取り不能、置換、変更された場合は、ファイル名とその差分を明示して書き込みを停止します。実行は新たな監査のため手順 1 に戻り、書き込みの前に人から新たな承認を得るため手順 8 に戻ります。スクリプトがスナップショットを取るのはステージングと移動対象であり、承認や書き込み元の除外ではありません。ハッシュ化によって競合の可能性は絞り込めますが、なくすことはできません。バイト列と契約の同一性が証明された場合はバックアップを省略します。未証明の候補では、まず契約を含む独立した保存を検証する必要があります。それが不可能な場合は停止します。
-
ケースごとに段階を 1 つ選んでリンクします。
node scripts/identity.mjs link <canonical> <alias> --mechanism hardlink|symlink|junction [--staged <absent-sibling>]は、証明済みのリンクを作成し、置き換えられるエントリがあればそのまま保持します。未検査のパスを上書きしたり、ツリーを再帰的に削除したりしてはいけません。失敗した場合は、元のものとステージを保持します。次の段階から選択します。段階 条件 方法 ファイルのハードリンク サポート対象の同一ローカルボリューム上にある通常ファイルで、親ディレクトリへの権限がある プローブしてから、 link --mechanism hardlinkディレクトリのハードリンク 主流のすべてのシステムで非対応 試行しない シンボリックリンク ディレクトリでは第一候補、ファイルでは代替手段。作成権限と親ディレクトリへの権限をプローブ済みの場合 link --mechanism symlinkジャンクション Windows でディレクトリを対象とする代替手段。書き込み可能な親ディレクトリ、絶対パスのローカルターゲットが必要で、ネットワーク上のターゲットは不可。同一ボリュームの要件はありません link --mechanism junctionバインドマウント 明示的に人が選択した Linux のみの方法。必要な権限をプローブし、承認済みの空のマウントポイントと個別の永続化計画がある場合 スクリプトの対象外です。暗黙の代替手段として使用してはいけません コピー 人が明示的に同意した場合のみ 「SSOT ではなくなった」と報告し、リンクとは扱いません これらの文書には各方式がサポートする内容が記載されていますが、このマシンで測定したものではないため、各段階では引き続きステップ 3 のプローブが必要です:https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions , https://man7.org/linux/man-pages/man2/link.2.html , https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/link.2.html -
変更のたびに、読み取り専用で検証します。 承認済みのマニフェストと契約に対して、
node scripts/identity.mjs verify <canonical> <alias>...を実行します。ハードリンクでは dev:ino(またはボリュームとファイル ID)が一致し、リンク数が対象セットをカバーしている必要があります。シンボリックリンクまたはジャンクションは正規パスに解決される必要があります。すべての名前を通じて各メンバーのハッシュが一致する必要があります。バイト列が一致するだけでは、同一性の証明にはなりません。バインドマウントには、個別のマウント、ソース、同一性の証明が必要です。不明な場合は中止します。稼働中の対象にセンチネルを書き込んではいけません。書き込みテストは、承認済みの破棄可能なフィクスチャで行います。 -
人が復元を承認した後、方式に応じて復元します。 プローブを繰り返し、破棄可能なデータで削除もプローブします。
node scripts/identity.mjs unlink <alias> --stage <dir>を実行します。<dir>は、リンクされたツリーの外にある、エイリアスと同じボリューム上の既存フォルダーです。このコマンドは、エイリアス名の下に、独立していることが証明されたコピーを配置してリンクを置き換えます。削除するのはエントリのみで、対象ツリーは削除しません。また、ジャンクションは再帰的に削除されません(https://learn.microsoft.com/en-us/dotnet/api/system.io.directory.delete )。コピーされたバイト列では ACL、ストリーム、xattr が保証されないため、まずステージされた契約を検証します。リンクを通じて削除してはいけません。正規パスのメンバー、ハッシュ、契約、および選択されなかったすべてのリンクが変更されていないことを証明します。リンク数が想定するエイリアス数と一致することを確認します。これは必ずしも 1 とは限りません。バインドマウントには、明示的なアンマウント(使用中なら中止し、強制アンマウントや遅延アンマウントは行わない)、対象のマウントが存在しないこと、ソースが変更されていないこと、マウントポイントに別個の ID が現れていることの確認が必要です。マウントポイントへのステージングや削除は決して行わず、アンマウントによってコピーが作成されることもありません。一部で失敗した場合は、証跡と原本を保持します。検証できないものは未完了のままにします。
ルール
- ステップ 1 の監査と承認が完了するまでは、対象に書き込まないでください。プローブの一時ディレクトリは対象ではありません。読み取り専用のまま維持されたものと、人間の判断が必要なものを報告してください。該当事項がない場合も有効です。
- リンクが越える境界があれば、リンクによって共有された変更と権限がすべての利用者に公開されるため、非公開から公開、または社内向けから顧客向けに移る場合は、人間に確認してください。
- リンクをたどってリンク先を削除してはいけません。エイリアスで再帰的に削除してはいけません。また、一部失敗した場合も元のファイルを保持してください。
- 移植性は仕組みごとに異なります。ハードリンクは Git クローン内で識別情報を引き継ぎません。相対シンボリックリンクは同じディレクトリ構成が再現される場所で機能します。また、
core.symlinks=falseではリンク先のテキストがファイルとして書き込まれるため、設定(https://git-scm.com/docs/git-config#Documentation/git-config.txt-coresymlinks)を確認し、移行先で検証してください。絶対シンボリックリンクには、同じリンク先パスが必要です。ジャンクションは Windows 専用で、ローカルかつ絶対パスを使用します。バインドマウントには、ホストの管理者権限と承認済みの永続化が必要です。コピーはもはや SSOT ではありません。 - 利用者が追加、削除、置換を確認する必要がある場合は、ディレクトリリンクを優先してください。ファイルのハードリンクは置換後に必ず再検証してください。リンクが恒久的に維持されるとは決して約束しないでください。
- すでにリンクされているセットは、報告対象の変更なしとして再検証し、再リンクはしないでください。
- 以下の障害記録には、リンク作成後にリンクが切れる要因を記載しています。どの項目も、今回の実行で必要な証明の代わりにはなりません。
| # | 障害 | 根拠 | 再検証 |
|---|---|---|---|
| 1 | 置換を伴う保存ではハードリンクが切れますが、インプレース保存では維持されます | 出典あり、未計測 | 保存後にセット全体を検証する |
| 2 | チェックアウトやスタッシュで置換ファイルが書き込まれることがあります | 出典あり | 外部エイリアスも含め、書き換えのたびに検証する |
| 3 | リンクを保持しない復元ではセットが展開されることがあります | 出典あり | 往復後に検証する。オプションから推測しない |
| 4 | クラウド同期サービスがリンクを拒否したり、コピーとして実体化したりすることがあります | 出典あり | プローブを実行し、各ホストで検証する。不明なら停止する |
| 5 | 監査後の編集によって同一性が無効になります | 過去の事例 | 書き込み前の再確認で差分を明示し、停止する |
| 6 | バイト列が同じでも、ACL、ストリーム、xattr が異なる場合があります | 提案段階 | 契約の証明を繰り返す。証明できない場合は停止したままにする |
| 7 | 最終ハッシュの後に書き込みが行われることがあります | 提案段階 | 排他に関する回答がなければ停止する。競合が解消されたとは決して主張しない |
検証
完了する前に、次の点を確認してください。
- ステップ 1 の監査が最初に実行され、その承認を受けてからすべての書き込みが行われたこと。分散が発生しなかった実行では変更がなく、停止も有効な結果として報告されていること。
- プローブした段階、排他に関する回答、承認が記録されていること。
- 書き込み前の差分がすべて報告され、必要な保持がすべて検証されていること。
- 識別情報、ハッシュ、契約がすべての名前を通して証明されていること。
- 該当する場合、7 種類すべての障害クラスが再検証されていること。
- 段階的な復元を実行した場合、その結果が証明されていること。不明なものは未完了のままにすること。
- すべての記録に、コマンド、終了コード、時刻、実行前後の識別情報、保持場所、未解決の項目が記載されていること。
- 最終報告に、リンクされたもの、読み取り専用のまま維持されたもの、人間の判断がまだ必要なものが記載されていること。