キュー投稿の仕組みで動くブログは「下書き時点のフォルダ名」と「公開後の記事番号」が別物になる。この設計を放置したまま、31記事・58本の内部リンクが気づかれずに壊れていた——姉妹メディアSURPLUSで実際に起きた事故から、下書きIDと公開IDが分離するパイプライン全般に共通する落とし穴を読み解く。
「下書き時のID」と「公開後のID」が別物になる設計で何が壊れるかの実例と、機械的な変換表が存在しない状態から31記事・58リンクを本文の内容だけを頼りに特定して直した検出・修正・検証の手順。
姉妹メディアSURPLUS(経済学の読み物サイト)で、公開中の1記事の内部リンクが本番で404になっていることに気づいた。
原因を追うと、その記事内で他記事へ張っていたリンク5本が、すべて存在しないURLを指していた。旧いスラッグ名のままのものと、相対パスの階層がずれているものが混在していた。念のため他の記事も同じパターンで壊れていないか横断的に洗い出したところ、被害は1記事どころではなかった——31記事・58本のリンクが同種の不具合を抱えていた。
このブログ(FLOW)もSURPLUSも、同じ設計で毎日記事を公開している。原因はどちらも「下書き時点の名前」と「公開後の名前」が別物になる仕組みそのものにある。
記事はqueue/NN_slug/という仮のスラッグ名フォルダで執筆し、publish_next.batが公開のタイミングで正式な記事番号へ採番し直す。他記事へリンクを張ろうとしたとき、公開後の番号はまだ決まっていないため、執筆時点で分かる名前(仮スラッグや暫定の連番)をそのまま書いてしまうと、公開後は存在しない宛先を指したまま残る。
正しくは../ArtN/のはずが../../ArtN/のように一段深すぎる——あるいはその逆になっているケースも見つかった。手で書く相対パスは、ディレクトリの階層を毎回正確に意識しないと簡単にずれる。仮スラッグの問題とは独立に、こちらも普通に起こる。
一番厄介だったのは、「どの仮スラッグが最終的にどの記事番号になったか」を機械的に引ける対応表が、どこにも存在しなかったことだ。
queue/フォルダは公開時に消費されて消える設計なので、後から遡って「このスラッグは実はこの記事番号だった」と突き止める手段がない。結局、壊れたリンクひとつひとつについて、アンカーテキストや前後の文脈を読み、内容が一致する記事を実際に本文から探し当てるしかなかった。31記事・58本のリンクを、この方法で1本ずつ特定していく地道な作業になった。
ここが核心。「下書き時のID」と「公開後のID」が分かれるパイプラインでは、両者を結ぶ対応表を公開した瞬間に残しておかないと、後から人力で復元するコストが跳ね上がる。仮スラッグは公開と同時に情報として失われる、使い捨てのラベルだと考えたほうがいい。
特定した正しいリンク先に本文を書き換えたあと、再アップロード用のスクリプトで31記事を本番へ反映し、修正した58リンク先すべてを実際にHTTPで叩いて200を確認した。ログに「直しました」と書かれているだけでは、それが本当に直っているかは分からない——AIの「できました」を信じない|3段階で検品する運用で書いた考え方を、リンク修正という場面でもう一度なぞった形になる。
再発防止として考えられるのは、投稿時に本文中の相対リンクを機械的に洗い出し、リンク先が実在するかを自動チェックする仕組みを挟むことだ。ただし今回はそこまでは実装しておらず、まだ手作業の棚卸しに頼ったままになっている。次に取り組むべき宿題として、あえてここに書き残しておく。
このブログ自身もまったく同じ「仮スラッグ→採番し直し」の設計で毎朝記事を公開している。事故はよそのメディアで起きたが、仕組みは共通だから、同じ壊れ方がいつここで起きてもおかしくない。