2026-08-29 · updated 2026-08-30 · Web / QA / OSS

サイト監査、リンク切れだけ見ても足りなかった。

公開サイトを見直してたら、内部リンク切れは0件。でもそれで終わりじゃなかった。古いブランド名、canonicalの二重化、sitemapに載ってない新ページが別々の場所に残ってた。

「壊れてない」と「揃ってる」は別

リンクが全部開いても、SNSカードのsite_nameだけ昔の名前だったり、同じcanonicalタグが2個入ってたり、新しく作ったサービスページがsitemapから漏れてたりする。ブラウザで普通に見るだけだと気付きにくい。

今回まとめて見たもの

①相対リンクの参照先が実在するか。②canonicalが1ページ1個か。③noindexが入ってるページはどれか。④リネーム前の文字列が残ってないか。⑤img / source のsrcsetに書かれたresponsive画像が実在するか。⑥video / audio / track / iframe のsrcとvideo posterが実在するか。ここまでを静的HTMLだけで見る小さいCLIにした。

srcだけ見てると2x画像が抜ける

あとから見つけた穴がsrcsetだった。imgのsrcが生きていても、2x用の画像だけ消えていれば高密度ディスプレイ側で壊れる。最初の監査はsrcしか見てなかったので、srcsetにあるlocal candidateも同じmissing asset検査へ流すようにした。

ここでもう1個ややこしかった。srcsetにはdata URIも書けて、その中にもカンマが入る。雑にカンマsplitするとinline画像と次のlocal画像の境界を壊せる。data URIだけを除外しつつ、後ろの普通のlocal candidateは飲み込まないよう回帰testまで追加した。

HTMLが生きてても、実デモのMP4だけ死ぬ

もう1段見落としてたのが埋め込みmedia。ポートフォリオのHTML自体は開けて、戻るリンクも正常。それでもvideoのsrcに置いたMP4だけ消えていれば、肝心の現物は再生できない。同じことはaudio、字幕のtrack、local iframe、video posterでも起きる。

なので普通のaタグやimgだけじゃなく、video / audio / track / iframe のsrcとvideo posterも同じlocal asset検査へ入れた。欠損5種類をまとめて落とす回帰testを追加して、GitHub Actions run 33317730012までsuccessを確認した。

noindexは自動でエラーにしない

noindexは意図的なこともある。だから検出はするけど、即failにはしない。逆に内部リンク切れ、canonical重複、禁止した旧文字列、欠損local assetはblocking扱い。機械が判断していい所と、人が意味を確認する所を分けた。

実サイトに当ててみた結果

修正後の公開面では、内部リンク切れ0、canonical重複0、旧ブランド文字列0。noindexは1ページだけ情報として残った。新しく追加したサービスや記事もsitemapへ載せ直した。実MP4を使うmotion sampleも、今回から監査対象にできる。

失敗を1回直して終わらせない

今回いちばん良かったのは、手作業の監査をそのまま再利用できる道具に変えられたこと。さらに、その道具自身の見落としもtestへ戻した。次のリネームやページ追加でも、同じ穴を最初から探し直さなくていい。

→ Site Surface Doctor · 検証メモ / CI evidence

Python標準ライブラリだけで動く静的チェック。ネットワークアクセスやファイル変更はしません。外部HTTP、DNS、CDN、実ブラウザ描画までは保証しない範囲です。