指示と、この文書が決めたこと
shika の指示は次の 5 点だった。
- life で作った HTML を静的ホスティングし、Cloudflare Pages に上げていく
- 認証は不要。URL を知っている人は誰でも読めてよい
- 認証情報は life ルートの
.envにあるCF_TOKEN_PERSONALとCF_ACCOUNT_PERSONALを参照する - 実装計画や調査レポートのような「自分が読むもの」は Markdown ではなく HTML で出力し、Pages に上げる
- 階層は「各プロジェクト」と「それ以外」に分けて提案する
この文書は、階層の提案(採用案と採らなかった案)、公開の仕組み、静かに壊れる箇所、受け入れ基準、残課題を記録する。規約の正本は life ルートの CLAUDE.md の節「人が読むレポートは Markdown ではなく HTML で書き、Cloudflare Pages に公開して URL を報告する」で、この文書はその根拠側である。
公開先と現在の状態
| 項目 | 値 | 確認方法・出典 |
|---|---|---|
| Cloudflare Pages プロジェクト | shika-notes(shika が 2026-09-08 14:33 UTC に作成済み。Git 連携なしの直接アップロード型) | Pages API のプロジェクト一覧を 2026-09-09 00:50 JST 頃に取得。当時デプロイは 0 件だった |
| 本番 URL | https://shika-notes.pages.dev/ | プロジェクトの domains フィールド |
| 初回デプロイ | 2026-09-09 00:55 JST 頃、10 ファイル。デプロイ固有 URL は https://67811c63.shika-notes.pages.dev | bin/pages-deploy.sh の出力 |
| 認証情報 | life ルートの .env(*.env で git 無視。git check-ignore -v .env が .gitignore:9 を返す) | スクリプトは CF_TOKEN_PERSONAL → CLOUDFLARE_API_TOKEN、CF_ACCOUNT_PERSONAL → CLOUDFLARE_ACCOUNT_ID に載せ替える。環境変数名は wrangler の公式ページによる |
| アップロード手段 | npx --yes wrangler@4.86.0 pages deploy <ステージング> --project-name shika-notes --branch main --commit-dirty=true | wrangler pages deploy の公式リファレンス。バージョンは 2026-09-09 時点で npx が解決した最新を固定した |
/user/tokens/verify は「Invalid API Token」を返すが、アカウント配下の /accounts/<ID>/tokens/verify は status: active を返した(2026-09-09 01:00 JST 実測)。権限を狭めるときは Cloudflare ダッシュボードのアカウント側の API トークン画面で編集する。URL の階層(提案と採用)
採用: リポジトリの相対パスをそのまま URL にする
「各プロジェクト」と「それ以外」の分け方は、既にリポジトリのディレクトリ構成がそうなっている。projects/<プロジェクト名>/ がプロジェクトごとの置き場で、それ以外の HTML は research/(単発調査)・docs/(横断の設計・規約)・sessions/(セッションの副産物)・pokemon/(対戦ログ)にある。URL 用の階層を別に発明すると、ファイルと URL の対応表が要るようになり、その表が古くなる。だから発明しない。
https://shika-notes.pages.dev/ ├── / トップ索引(pages-deploy.sh が生成。プロジェクト別・調査・設計・セッション・ポケモン) ├── /projects/<プロジェクト名>/… 各プロジェクトの文書(要件定義・実装計画・手順書・設計図) │ 例 /projects/mycocktails/requirements │ /projects/PersonalOS/docs/overview ├── /research/ 調査レポートの索引(research/index.html。bin/research-index.sh が生成) │ └── /research/<カテゴリ>/YYYY-MM-DD_<slug> ├── /docs/design/YYYY-MM-DD_<slug> 横断の設計・規約(この文書もここ) │ /projects/battle-feedback/battles/<試合>/feedback 対戦フィードバック(別リポジトリ。docs/** と feedback.html だけ。frames/ と JSON は上げない) ├── /sessions/<セッション>/<文書> セッションの副産物(.snapshots/ は除く) └── /pokemon/battle-logs/YYYY-MM-DD_<slug> 対戦ログ
Pages は /x.html への要求を /x へ、/dir/index.html を /dir/ へ転送する(公式の配信規則。実測ではステータス 308)。報告に書く URL は転送後の .html を省いた形に統一する。HTML 同士の相対リンク(../projects/…/x.html のような)はパス構造が同じなのでそのまま動く。
採らなかった案
mycocktails.pages.dev のように)は採らない。プロジェクトを跨ぐ相対リンク(調査索引からプロジェクト文書へのリンクなど)が切れる。トークンで作れるプロジェクト数の上限は 100(公式 limits)で数の問題ではなく、リンクの問題である。/reports/2026-09-08_xxx のように日付だけで並べる)は採らない。「調査レポートは索引がリンクで拾い、ファイルは動かさない」という 2026-09-07 の決定(bin/research-index.sh 冒頭)と同じ理由で、対応表を持つと壊れる。_headers で全パスに X-Robots-Tag: noindex を付ける(公式の _headers 仕様)。後で認証が要るなら、Pages プロジェクトに Access ポリシーを付けるだけでスクリプトは変えなくてよい。*.html を全部上げる案は採らない。docs/profile/my-data.md のように外へ出してはいけない平文が life にはある。今は Markdown なので対象外だが、いつか誰かが HTML 化したときに黙って公開される経路を作らない。公開対象は列挙で固定する。CLAUDE.md に置いた。公開の仕組み(bin/pages-deploy.sh)
- 収集: 列挙されたパターン(
projects/*/*.html・projects/*/docs/*.html・research/**/*.html・sessions/*/*.html・pokemon/**/*.html・docs/**/*.html、および別リポジトリprojects/battle-feedback/のdocs/**/*.htmlとbattles/*/feedback.html。shika の指示 2026-09-09 で追加)から HTML を集める。submodule と外部リポジトリの clone、.snapshots/は除く。<head>に<meta name="pages-publish" content="no">がある HTML は除外し、除外した件数と名前を毎回表示する(0 件でも「0 件」と出す) - 索引: 先に
bin/research-index.shを走らせてresearch/index.htmlとreports.jsonを最新にしてから集める。トップのindex.html(プロジェクト別・調査・設計・セッション・ポケモンの 5 区分)と404.html、_headersをステージングに生成する - 検査: 25 MiB を超えるファイル(Pages の 1 ファイル上限。公式 limits)があれば上げる前に終了コード 1 で止まる。
<title>の無い HTML は警告し、公開後に終了コード 2 を返す - 認証:
.envから 2 つのキーだけを読む(set -aでファイル全体を export しない)。無ければ終了コード 1 で止まり、理由にキー名を出す - 公開: 固定バージョンの wrangler で
pages deploy。成功したら本番 URL と、引数で渡されたファイルの公開 URL を並べる
bin/pages-deploy.sh research/technology/2026-09-08_xxx.html # 収集→索引→公開→この文書の URL を表示
bin/pages-deploy.sh --dry-run # 公開せず対象一覧と件数だけ
bin/pages-deploy.sh --url projects/mycocktails/requirements.html # URL だけ計算
bin/pages-deploy.test.sh # 契約の検査(ネットワークに出ない)
静かに壊れる箇所(気づけないこと)
| 何が起きるか | 気づけない理由 | 手当て |
|---|---|---|
Pages は 404.html が無いと単一ページアプリと見なし、未知のパスにトップページを返す(公式) | リンク切れが「索引が表示される」という形になり、ステータスも 200 で、エラーが出ない | スクリプトが必ず 404.html を同梱する。実測で /no/such/page と /docs/profile/my-data.md が 404 を返すことを確認した(2026-09-09 00:57 JST) |
battle-feedback の仕様書は同じリポジトリの README.md・pipeline/README.md・sets/*.json へ相対リンクしている | Markdown と JSON は公開対象外なので、そのリンクは Pages 上で 404 になる。HTML 同士のリンクは生きているので、壊れているのが一部だけで気づきにくい | 404 ページに「公開対象に入っていないかパスが変わっている」と書いてある。Markdown を HTML 化するかは残課題の検討事項 |
| 列挙に無い場所に置いた HTML は公開されない | 「書いた」「上げた」と報告しても、その URL は 404 になる。スクリプトはその場所を見ていないので警告しない | 引数で渡したファイルが公開対象に無いとき、スクリプトは「公開対象に入っていない」と URL の代わりに表示する。置き場所の規約は CLAUDE.md |
| ステージングの中にマニフェストを書くと、それもアップロードされる | 1 ファイル増えるだけで、デプロイは成功する | マニフェストはステージングの外(<ステージング>.manifest.json)に書く |
| wrangler のメジャーバージョンが上がると、オプション名や出力形式が変わりうる | npx wrangler は黙って最新を取る。URL の抽出(出力から *.pages.dev を拾う)だけが空になる | バージョンを wrangler@4.86.0 に固定。上げるときはこの文書を更新する |
| 個人の機微情報を含む HTML を公開対象の場所に置く | 認証が無いので、URL が漏れれば誰でも読める。公開は成功し、エラーは出ない | 規約(CLAUDE.md)で「置かないか、除外メタを付ける」と定める。機械的な検知は未実装(残課題) |
受け入れ基準(落ちるべきときに落ちることを確かめたもの)
いずれも 2026-09-09 に実行し、スクリプトをわざと壊して落ちることも見た(除外判定を無効化すると 4 本、404.html の生成を止めると 1 本が落ちる)。判別力の預け先は、データに依存しない最小入力の一時ディレクトリ。
| 叩くこと | 期待する出力 | 落ちたら |
|---|---|---|
bin/pages-deploy.test.sh; echo "exit=$?" | 最後の 2 行が ALL OK と exit=0 | ❌ の行の検査名に対応する説明が同スクリプト冒頭のコメントにある。bin/pages-deploy.sh --dry-run で除外・件数の実値を見る |
bin/pages-deploy.sh --dry-run >/dev/null 2>&1; echo "exit=$?" | exit=0(<title> 無しがあれば 2) | bin/pages-deploy.sh --dry-run を再実行し、⚠️ の行のファイルに <title> を付ける |
curl -s -o /dev/null -w '%{http_code} %header{x-robots-tag}\n' https://shika-notes.pages.dev/no/such/page | 404 noindex | 200 なら 404.html が同梱されていない。bin/pages-deploy.sh --dry-run のあと PAGES_STAGE_DIR=/tmp/s bin/pages-deploy.sh --dry-run; ls /tmp/s/404.html |
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' https://shika-notes.pages.dev/research/index.html | 308 https://shika-notes.pages.dev/research/ | Pages の転送規則が変わった可能性。--url の変換規則(スクリプトの to_url)を見直す |
git check-ignore -v .env; echo "exit=$?" | .gitignore:9:*.env .env と exit=0 | 🔴 コミットする前に止まる。.gitignore の *.env の行を戻す |
ロールバック: デプロイは Cloudflare のダッシュボード(Pages → shika-notes → Deployments)から過去のデプロイに戻せる。スクリプトと規約の変更は git で戻せる。.env はこの作業で触っていない。
残課題
実測タスク(叩けば答えが出る)
- 未確認 Pages の直接アップロードに回数制限があるか。公式 limits ページには「builds 500/月」しか無く、直接アップロードの記述が無い。確認方法: 1 日に 20 回程度デプロイして拒否されないかを見る(通常運用で自然に分かる)。意味: 制限に当たるなら「1 セッション 1 回」に規約を絞る
検討事項(判断が要る)
- 機微情報の機械的な検知(年収・口座番号・住所らしき文字列が公開対象の HTML にあれば止める)を入れるか。今は規約だけで守っている
- 独自ドメインを付けるか。
*.pages.devのままでも運用に支障は無い - 既存の Markdown レポート(
research/**/*.md)を HTML 化して公開するか。索引には載っているが、Pages には上がらない(Markdown は対象外)