静的サイトジェネレーター(SSG)や技術ブログで図解を掲載する際、Mermaid などのテキスト記法で作成したダイアグラムを画像(PNG や WebP)へ変換して記事へ貼り付けるワークフローは広く使われています。表示の高速化やプラットフォームごとのレンダリング差異を避ける上でも、画像の事前生成は堅実な選択肢です。

その一方で、画像化した後に必ず直面するのが「元となったダイアグラムのソースコードをどう保守するか」という問題です。「将来の修正や再編集に備えて、画像のすぐ近くにソースを残しておきたい」「AI アシスタントにも図の設計意図を読ませたい」という親切心から、記事の Markdown 内に HTML コメント(<!-- ... -->)として Mermaid コードを埋め込んでおく運用パターンが考案され、現場で実践されてきました。

ドキュメントの二重保持とは、静的サイトや技術文書において、画像等の成果物と同一のファイル内に、保守や再編集用の元ソースコード(Mermaid 等)をコメントなどの形式で重複して残す運用パターンです。

しかし、私の個人サイトにおいて 147 記事にわたってこの二重保持を運用した結果、待っていたのは「エスケープ事故の頻発」と「それを防ぐための検査スクリプトの肥大化」という不毛な泥沼でした。

「後で直すかもしれない」「念のため」とドキュメント本文にソースを二重保持するのは、Git の存在意義を殺すアンチパターンです。画像化前のコミット履歴に完全な生ソースが残されているのであれば、本文に二重管理する理由はどこにもありません。

本記事では、147 記事に蓄積された 243 ブロックの Mermaid コメントを一括削除(5,777 行削減)し、検査スクリプトごと運用を全廃した実務の経緯と、Git 履歴を信頼してドキュメントを最小限に保つ設計判断について解説します。

なぜ本文コメントの Mermaid 保持は破綻したのか:実務での選択理由

画像化した図の元ソースを HTML コメントに残すアプローチは、一見すると非常に合理的で便利な工夫に見えます。実際、技術メディア等でも「人間の視認性と AI の理解を両立する設計パターン」として具体的に紹介されてきました1。

引用元: https://tech-lab.sios.jp/archives/51351

<!-- この図のソースコード(AI向け):
sequenceDiagram
    Client->>+Server: ログインリクエスト
    Server->>+DB: ユーザー照合
    DB-->>-Server: 結果
    Server-->>-Client: トークン発行

設計意図: DB直接参照を避け、サービス層を経由する設計。
理由: テスタビリティとマイクロサービス移行への備え。
-->
![認証フロー図](./images/auth-flow.png)

人間には PNG 画像を見せつつ、エディタを開いた作業者やテキストを走査する AI には HTML コメント内の構造化テキストを読ませるという二層管理です。しかし、この運用を実際の Markdown 原稿で運用し続けると、仕様上の構造的な罠に嵌まることになります。

CommonMark 仕様と Mermaid 矢印記法の構造的衝突

最大の問題は、Markdown の標準仕様である CommonMark と、Mermaid の基本構文が真っ向から衝突する点にあります。

CommonMark 0.31.2 の仕様(Section 4.6 HTML blocks)において、HTML コメント(Type 2 HTML block)は「<!-- で始まり、行内に --> が含まれると終了する」と明確に定義されています2。

一方、Mermaid のフローチャートで最も頻繁に使われる矢印記法はまさに --> です3。そのため、HTML コメント内に Mermaid のコードを生のまま記述すると、パーサーは最初の矢印が出現した瞬間に HTML コメントが閉じたと判断してしまいます。

ファイル: markdown:broken-comment.md

<!--
```mermaid
graph TD
  A --> B
```
-->

上記のコードを CommonMark パーサーが処理すると、A --> の時点でコメントブロックが強制終了します。結果として後続の B や ``` が通常の段落テキストや壊れたコードブロックとして解釈され、公開された記事の本文に生のテキストやゴミ文字が露出・破損してしまいます。

HTML Standard の仕様においても、コメントの内部テキストに --> や --!> を含めることは禁止されています4。さらに歴史的にも、XML や SGML において二重ハイフン(--)はコメント内部で厳しく制限されてきた経緯があります5。行頭以外に置かれた不完全なコメントはインライン HTML として扱われ、前後のブロック構造を意図せず分割してしまう問題も知られています6。

この早期終了を避けるためには、Mermaid コード内のすべての -- を \-\- のように手動またはスクリプトでエスケープしなければなりません。しかし、置換処理のミスによって本来の矢印が --\-\-> のように壊れた記法へ変換されてしまうインシデントが発生しました。壊れたエスケープは画像の文字照合検査などを素通りし、手動で正規表現を書いて初めて自己発見されるという有様でした。

検査スクリプト追加という「過剰防衛」の罠

エスケープ崩れ事故が起きたとき、最初に頭に浮かぶ解決策は「検査を強化すること」です。「壊れたエスケープを機械的に検出するバリデーションスクリプトを書こう」と考え、私は筆者が運営する技術ブログのリポジトリ(非公開。以下、リポジトリA)に mermaid-comment.py(46 行)を実装しました。

引用元: リポジトリAの mermaid-comment.py(削除前の版)

"""mermaid-comment: HTML コメントに退避した Mermaid が壊れていないかを判定する。

用途: python3 tools/checks/mermaid-comment.py <記事.md> [--against <git-rev>]
判定:
  1. コメント内の Mermaid に、エスケープされていない `--` が残っていない(残るとコメントがそこで閉じる)
  2. --against を付けたとき: その版の記事にあった生の Mermaid と、コメント内の Mermaid の `\\-\\-` を戻したものが、出現順に一字一句一致する
契約: 違反を stderr に出して exit 1。問題が無ければ exit 0。
"""

このスクリプトは、未エスケープの -- が残っていないか検査し、さらに過去のコミットの生 Mermaid と一字一句一致するかどうかまで検証する精密なものでした。画像化スキルの手順内バリデータとして組み込み、エスケープの破壊を防ごうとしたのです。

しかし、これは典型的な「過剰防衛」でした。壊れやすい複雑な運用を守るために、専用の検査スクリプトを作り、例外ルールを増やし、保守対象を増やしていたのです。しかもこのスクリプトは特定の作業手順の中でしか走らず、手動の修正やすでに過去の記事に埋もれた破損までは防ぎきれませんでした。

検査を増やすのではなく運用を捨てる:147記事・243ブロックの一括削除

「エスケープが壊れていないかをどう検査するか」を考えるのをやめ、「そもそもこの運用は本当に必要なのか」と問い直した瞬間に、事態は一気に単純になりました。

「画像化直前のコミットに生ソースがある」という気づき

当時の意思決定メモを振り返ると、事故直後の議論ですでに「バリデータを書いて検査するより、画像化直前(生 Mermaid を挿入した段階)にコミットを挟んで Git 履歴から復元できるようにする方が低コストである」という方針が確認されていました。

実際、ある連載記事の執筆中に画像生成 API のエラーが発生した際、直前の生 Mermaid 挿入コミット(71 行追加)をわずか 16 分後に git revert して元の状態へ戻すという実務を経験しました。ソースコードは、コミット履歴の側に完全に保管されていたのです。

当サイトの執筆パイプラインでは、下書き作成時にまず生 Mermaid を含んだ状態でコミットを刻み、その後に画像化スクリプトを実行して生成画像をコミットする多段コミット運用を標準としています。そのため、過去のリビジョンには画像化前の完全な生ソースが必ず残されていました。

Git にあるものを本文に二重に持つ必要はありません。画像化前のコミットに生ソースが残っているなら、本文の HTML コメントはただの冗長な二重管理であり、エスケープ事故のリスク源でしかありませんでした。

2026 年 10 月 20 日、私は本文コメント保持運用の全廃を決定し、mermaid-comment.py を完全削除しました。スクリプトに欠陥があったから消したのではなく、守るべき運用そのものが不要になったからです。

一括削除の実測と、コメント早期終了の実態

運用を廃止した直後、既存記事に残っていた退避コメントを一括削除するスクリプトを実行しました。その結果、1 回のコミットで 147 ファイル・5,777 行の削除 が行われました(git show --shortstat による確認)。

引用元: リポジトリAの一括削除コミットの git show --shortstat

 147 files changed, 5777 deletions(-)

一括削除の過程で 243 ブロックの Mermaid コメントを精査したところ、驚くべき事実が判明しました。243 ブロック中、実に 15 ブロック(過去の連載記事ファイルなど)において未エスケープの --> が残存しており、HTML コメントが途中で意図せず終了して本文が破損したまま、数か月にわたって公開されていたのです。

精密な検査スクリプトを作っていたにもかかわらず、手作業や個別編集による破損はすり抜けていました。147 記事分のコメントを一括削除したことで、長年放置されていた 15 箇所の表示崩れは一掃され、画像化を行わずにサイト上で直接描画されている生レンダリング用の Mermaid(380 ブロック)には一切手を触れずに無傷で維持されました。

検査の向きの逆転:コメント残存を弾く検収へ

運用を撤回した後の再発防止策として、私は検査の向きを 180 度逆転させました。

これまでは「HTML コメント内の Mermaid が壊れていないか」を検査していました。しかし新しく導入した publish-ready.py(49 行)の役割は、「そもそも記事本文にコメントアウトされた Mermaid が残っていないこと」 を検知することです。

引用元: リポジトリAの publish-ready.py

COMMENTED_MERMAID = re.compile(r'<!--\s*\n\s*```mermaid')

予防は「原因の空間」に対して設計し、検収は「結果の空間」に対して設計します。エスケープミスや構文崩れという原因は無限に存在するため、予防ルールをどれだけ積んでも漏れが生じます。一方で、気にしている性質(本文にコメント退避しない)を結果の空間として検収すれば、わずか 1 つの正規表現で完全に閉じることができます。

このチェックをテストコマンド(mise run test)および記事編集時フックに組み込んだことで、退避コメントの混入は機械的に恒久的に遮断されました。

本文二重保持 vs Git履歴復元のトレードオフと適用限界

本文への HTML コメント保持を全廃し、Git 履歴への委託に切り替えたアプローチの特性を整理します。

ドキュメントのソース管理方針について、本文内への二重保持と Git 履歴への委託を比較すると、保守コストと破損リスクにおいて明確な違いが生じます。

評価軸本文HTMLコメント保持Git履歴への委託(採用方針)
再編集の手軽さファイル単体で完結し即座に確認可能git log や過去コミットの参照が必要
本文の保守性・破損リスクエスケープ漏れによる構文破壊・表示崩れのリスク大コメント自体が存在しないため破損リスクはゼロ
CI・検査の複雑性エスケープ整合性検査(バリデータ)の維持が必要「コメント残存なし」の1点検収のみで完結
向いている環境Git 履歴を持たない CMS、単一ファイル完結の配布文書Git でバージョン管理されている静的サイト・技術ブログ

Git でバージョン管理されているリポジトリであれば、本文内に二重管理するリスクを背負うよりも、履歴を信頼して本文から完全に排除する方が長期的な保守コストを圧倒的に低減できます。

もちろん、このアプローチにもトレードオフはあります。エディタ上で Markdown を開いた際、その場ですぐに Mermaid ソースをコピーすることはできず、Git のログを辿る手間が発生します。しかし、公開済みの記事の図を再編集する頻度は、記事全体の保守頻度や新規執筆の頻度に比べて極めて低いのが通常です。滅多に起きない再編集の手軽さのために、日常の執筆・ビルド時に破損リスクを抱え続けるのは割に合わない取引でした。

前提が変われば結論はどう変わるか

この結論は、「静的サイトで図を画像化して配信する」という前提に基づいています。

もし今後、静的サイトジェネレーターのビルドパイプラインがさらに進化し、ビルド時に完全自動かつゼロランタイム JS で Mermaid を最適化されたインライン SVG へ変換できるようになれば、そもそも「事前画像化と元ソースの保管場所」という二者択一の悩み自体が消滅します。生の Mermaid をそのまま本文に書き、ビルド成果物として画像が出るのが理想形です。

しかし、ビルド時の描画オーバーヘッドやフォントレンダリングの安定性が課題となる現行の環境においては、「画像として記事に配置し、元ソースは Git のコミット履歴に委ねる」という切り分けが、最も壊れにくくシンプルな運用境界となります。

よくある質問(FAQ)

Q. Git履歴から過去のMermaidソースを復元するには具体的にどうすればよいですか?

A. git log コマンドで該当のファイルを追跡します。特定の記事で使われていた Mermaid を探す場合は git log -S "mermaid" -- <記事ファイルパス> を実行して挿入や削除のコミットハッシュを特定し、git show <コミットハッシュ>:<記事ファイルパス> で過去のリビジョンを表示すれば、画像化前の完全な生ソースをいつでも安全に取り出せます。

Q. AIアシスタントに図の意図を正確に読ませるために、コメントでソースを残す必要はありませんか?

A. 必須ではありません。画像の alt 属性や前後の本文テキストで図の意図や主要な関係性を自然言語で記述しておけば、現代の AI は十分に文脈を理解できます。むしろ、エスケープ崩れによって HTML コメントが途中で閉じた壊れたコード片が本文に露出する方が、AI のパーサーや読解に悪影響を及ぼします。

まとめ

本記事で解説した設計判断の要点は以下の通りです。

  • 守るべき運用自体の要否を問う: 検査スクリプトやエスケープ規約を増やす前に、守ろうとしている運用そのものが本当に必要かを問い直してください。
  • Git履歴にあるものを本文に二重保持しない: バージョン管理システムを信頼し、現在の原稿ファイルは「今レンダリングに必要な最小限」に保つのが原則です。
  • 原因の予防より結果の検収へ逆転させる: 無限に広がるエスケープ失敗を検査で追うのではなく、望まない状態(退避コメントの残存)を機械的に遮断する検収へ倒すことで、CI と運用を極小化できます。

ドキュメント管理の簡素化や自動化パイプラインの設計、運用改善について、ぜひ コンタクトフォーム よりお気軽にご相談ください。

Footnotes

  1. 仕様書の図はAIに読ませるな — 軽量コードを添える設計パターン 龍:Ryu, SIOS Tech Lab, 2026年2月24日。人間向け画像とAI向けHTMLコメント退避を併用する二層管理パターンの提唱・具体マークアップ例。 ↩

  2. CommonMark Spec John MacFarlane, 2024年版 (v0.31.2)。Section 4.6 HTML blocks: Type 2 HTMLコメントの開始条件(<!--)と終了条件(-->)の定義。 ↩

  3. Flowcharts - Basic Syntax Mermaid 公式ドキュメント。フローチャートの標準リンク矢印 --> の記法、および行頭 %% による Mermaid 固有コメント構文。 ↩

  4. HTML Standard WHATWG, Living Standard。13.1.6 Comments: コメント内部における --> や --!> の禁止規定。 ↩

  5. Double Dash In HTML Comments Robert Price, 2009年12月2日。XML/SGML/HTML仕様における二重ハイフン(--)の制限とパーサー破壊の歴史的背景。 ↩

  6. Clarify the following HTML comment case CommonMark Discussion Forum。行頭以外のHTMLコメントが inline raw HTML として扱われブロック分割される仕様挙動。 ↩