同じ機能が複数の画面から呼ばれているとき、データの供給経路が画面ごとに違う——それを踏んで、その対策を書いて、同じ晩にまた踏んだ記録です。
写真に重ねて綴った言葉を、テンプレートに全部出すようにした。テストは緑(テストツールは成功を緑、失敗を赤で出します。つまり全部パス)。ミューテーション(わざと実装を壊して落ちるか見る確認)も通した。
ブラウザで開いたら出ていなかった。
原因は、作成画面のプレビューだけサーバの解決を通らず、その画面でローカルに組み立てていたこと。保存後のページと共有リンクはサーバ経由なので出ていて、テストが見ていたのもそっちだった。手元で組み立てるときの材料はお気に入り一覧のデータで、これは1枚につき代表の綴り1件しか持っていません。同じテンプレを描いていても、面が違えば手に入るデータの粒度が違います。
ミューテーションが通ったのも当然だった。あれは「テストが見ているコードを壊したら気づくか」を測る道具でしかありません。テストが一度も描いていない面があること自体は、どうやっても測れません。
この穴を塞ぐ作業からは、同じ晩に別の記録が2本出ている。塞ぐ前に書いたテストの赤の理由を読み違えた話が「テストが3本とも落ちたのに、落ちた理由が違った — 赤を確認しただけで実装に入りかけた話」、繋いだ先で見つけた別の欠陥が「同じデータを2つの型で持っていたら、代表の選び方まで2つに分かれていた」。
判断ログにこう書いた。
新しいフィールドを足したら、そのテンプレートを描く面を全部数える。
ここで言う「面」は、同じテンプレートが実際に絵として描かれる場所のこと。同じ部品でも、呼ぶ画面ごとに材料の渡され方が違います。
3時間後、grep をかけた
穴を塞いだあと、念のため呼び出し元を機械的に出してみた。
# frontend/ で実行。JSX の開きタグで引く=「描いている場所」だけが出る
rg -n '<TemplatePageView' src4件出た。
3時間前の自分は画面の記憶から3つ挙げていた。「試着プレビューと、保存したページと、共有面」。頭の中の地図で数えていて、コードでは数えていなかった。
これは自分たちのプロジェクトで何度も言っている「二次情報を根拠にしない」に、そのまま当てはまる。コメントや設計書の断定を疑うようにはなっていたけど、自分の記憶も二次情報だった。
4面目は、そもそも空だった
見つけた面を実際に測ったら、もっと大きいものが出てきた。
テンプレを選ぶ画面のカードには、選んだ写真で実際に描いた小さなプレビューが載る作りになっています。等倍で描いて CSS で縮めるという凝った作りで、コメントには「ライブ試着サムネ」と書いてあります。
ブラウザで中身を測った。
// カードのサムネ部分(img が1枚も無い)
{ imgs: 0 }試着サムネが出るはずの9枚すべてで、写真がゼロだった。
おそらく同期した写真が本線になった時点から壊れている。誰も気づかなかったのは、名前と説明文だけでテンプレを選べてしまうからです。そしてこの部分には aria-hidden が付いています。飾りだと明記してあるので、テストの対象にもなっていなかった。
学び
「数える」を意志の問題にしない。 気をつけるでは同じことが起きます。前例に書くなら心構えではなく、コマンドごと書く。
上のコマンドで効いているのは < の1文字で、部品名だけで引くと31行・14ファイル出る(型定義のコメント、import、テストのヘルパー…)。開きタグに絞ると4行だけになって、描いている場所がそのまま並ぶ。
同じことを7月16日にもやっている。背景に出る帯を直したとき、目視で見つけた3ファイルを直して終わったつもりが、後からリポジトリ全体を検索したら同じ1行は5ファイルにあった(ページの途中で背景の色が切り替わる「帯」が出る — background-attachment: fixed の仕様)。散らばり方の性質は違う(あちらはコピペで増えた CSS 1行、こちらは同じ部品の呼び出し元)が、目で数えた数と機械で出る数が合わないところは同じ。
「飾り」と書いてある部品ほど、壊れても誰も気づきません。 aria-hidden や pointer-events: none が付いた部品は、テストからも人の目からも外れます。でもデータの供給経路を持っているなら、それは面として数える必要があります。
直し自体は小さい(写真の実体を picker まで1本通すだけ・材料は同じ画面にある)。ただし直すと見た目が変わるので、これは今すぐ入れずに残タスクへ回した。
この2日後、同じロールアウトの中で「数えた数」と実物がまた合わなかった。そのときは呼び出し元の面ではなく、テンプレの種類のほうを数え落としている(テストに「この1つは対象外」と書いた行が、あとから来た決定を素通りさせた)。
この記事は2026年7月時点の自分の理解で書いています。仕様や認識が変わってる可能性があります。