asset-route
Git の外に置くアセット(画像・PDF・レンダー・原本)の置き場を「誰が使うか」で決め、正確なコマンドへ導く。 サイトが配信する→public R2 / GitHub Actions が読み書きする→private R2 / 人か手元のスクリプトだけ→Google Drive vault。 新しいアセット群を追加するとき、既存 group を別 tier へ移すとき、R2 か Drive か迷っ
SKILL.md.claude/skills/dev/asset-route/SKILL.md
GitHub置き場ルールの真実源は asset-storage-policy.md §1。 このスキルは判断を再現する決定木と、その判断に対応するコマンドだけを持つ。
決定木
- サイト(
doboku-note.com)がその実体を配信するか? —<img src>・og:image・_redirects301 の先・配布 ZIP の URL →audience: site→ public R2doboku-note(asset-storage.json、bucket: public)。 記事図版はr2-sync.ymlが自動同期、OGP はogp-supply.ymlが生成・供給する。手で offload しない。 - GitHub Actions がその実体を読むか書くか? —
.github/workflows/*.ymlを grep して確かめる(憶測で「CI が使う」と言わない。 2026-09-05 の調査で、動画レンダー・Kindle・IG 公開のワークフローは存在しなかった) →audience: ci→ R2(bucket: privateかbyVisibility)。現在この区分のグループは無い(2026-09-29 まで note カバー PNG が該当)。 - それ以外=人か手元のスクリプトだけが使う →
audience: human→ Google Drive vaultマイドライブ/doboku-note/(drive-vault.json)。原本 PDF・ページ画像・文字起こし・配布 PDF・未投稿レンダー・Kindle・ココナラ素材。- R2 に残す例外は
asset-storage.jsonのaudienceExceptionに 20 字以上の理由を書く(例: git 履歴 bundle 2.65GB)。 理由が書けないなら例外ではない。
- R2 に残す例外は
「著作権物だから private R2」は判断軸ではない。著作権物でも人しか読まないなら Drive、public に出せないのは両 tier とも同じ。
置き場ごとのコマンド
端末間の引き継ぎは、先に asset-storage-policy.md §1-3 の接続・容量・復元確認を行う。マウントが無いだけで転送不能と判断しない。Driveコネクターを利用できる場合は既存フォルダーを特定して個別ファイルを転送し、全バイト読み戻しの記録を node scripts/drive-connector-register.mjs --receipt <json> [--commit] で既存台帳へ登録する。ZIPを置いただけの状態と、個別復元可能な状態を区別する。
| audience | 台帳 | 追加・同期 | 取り戻し | 検査 |
|---|---|---|---|---|
| site / ci | .claude/state/assets/manifest.json |
node scripts/asset-offload.mjs --group <id> [--include-untracked] --commit |
npm run asset-hydrate -- --group <id> |
npm run check-asset-storage |
| human | .claude/state/assets/drive-manifest.json |
npm run drive-vault-sync -- --group <id> --commit |
npm run drive-vault-sync -- --pull --group <id> |
npm run check-drive-vault |
教材文字起こしの既存 group は source-transcript(Drive の各原資料内 ocr/)。新しい原本は先に
config/reference-sources.json へ登録し、文字起こし frontmatter からその ID を指す。詳細は
.claude/knowledge/reference/reference-sources-policy.md。
どちらも既定は dry-run。書き込みは --commit。ローカル削除・untrack・R2 側の削除は別操作・別承認。
新しい group を足すとき
- 決定木で audience を決める。
site/ciならasset-storage.jsonにaudienceつきで group を追加。humanならdrive-vault.jsonにstatus: active・vaultDir(3 フォルダのどれか: 原資料PDF / 制作物 / アーカイブ)・keyFrom・reasonを書く。npm test(tests/asset-storage.test.mjs/tests/drive-vault.test.mjsが audience と衝突を固定)とnpm run check-drive-vault(同じパスが両 tier に一致しないか)を通す。.gitignoreに実体のパターンを足す(拡張子で書く・台帳と README は除外しない)。asset-storage-policy.md§1 の「各 group の行き先」表に 1 行足す。
既存 group を R2 から Drive へ移すとき(順序は必須)
node scripts/drive-vault-sync.mjs --group <id> [--from-r2] [--dedupe-by-sha] # 1 dry-run
node scripts/drive-vault-sync.mjs --group <id> [--from-r2] [--dedupe-by-sha] --commit # 2 vault へ(読み直し sha256)
node scripts/drive-vault-sync.mjs --group <id> --verify --deep --cloud --out .tmp/<id>-ok.txt # 3 台帳・vault・クラウド md5 の 3 者一致
node scripts/delete-r2-objects.mjs --bucket private --from-manifest-group <id> [--commit] # 4 R2 側を消す(byVisibility は --bucket public も)
node scripts/asset-offload.mjs --forget-group <id> --commit # 5 R2 台帳から外す(Drive 側で保全確認できたキーだけ)
# 6 asset-storage.json から group を削除・drive-vault.json 側を status: active・tests のサンプルを差し替え・docs
- 3 を飛ばして 4 へ行かない。 マウントへ書けた=クラウドへ上がった、ではない(Drive クライアントの同期は非同期)。
--cloudは rclone リモートdoboku-gdriveが要る(rclone configで Google Drive バックエンド・ブラウザ OAuth・人が 1 回)。 未設定なら fail-closed で止まる。 --from-r2は R2 にしか実体が無い group(教材 PDF 等)向け。R2 台帳のキーで引く(logicalPathの旧値は使わない)。--dedupe-by-shaは vault のdedupeScan(原資料PDF/)配下に同じ sha256 があればコピーせず採用(adopted: true)。 手で置いた原本と二重化しない。byVisibilityの group(IG レンダー)は public / private の両バケットにキーがあるので、4 を--bucketごとに 2 回。
つまずきどころ
- マウントが無い:
resolveVaultRoot()が{ root: null, reason }を返す。Google ドライブ アプリを起動するかDOBOKU_DRIVE_VAULT=/pathで指定。CI には無いのが正常(check-drive-vaultは「実体検査 0 件」と出す)。 statのサイズが 16,777,216: ストリーミングマウントのプレースホルダ。cloud-only のファイルは読むまで実サイズが分からない。realBytesAndHashes()(読んで測る)を使い、statSync.sizeで比較しない。- Windows 会社 PC: 候補は
G:/マイドライブ/doboku-note・%USERPROFILE%/Google Drive/マイドライブ/doboku-note。 マウント経由のdrive-vault-syncはプロキシを使わない。コネクター経由は利用可能な接続と取得機能を確認する。 check-asset-storageの not-offloaded: Drive 台帳に載っているか active な Drive group に一致するファイルは数えない。 出たら R2 tier の未退避=asset-offload。- reels の wav/mp4・YouTube Shorts mp4(
sns-archived-media)も 2026-09-05(DN-0170)から Drive vault制作物/SNS音声動画/(旧upload-sns-r2=public R2 系統は廃止)。パック単位の退避可否はsns-archive-auditor(sns-archive-policy.md)。