• Status: Accepted
  • Mode: Standard
  • Kruchten Type: Property/Executive
  • Scope: platform
  • Implementation Status: Done (2026-06-02, branch feat/adr-0100-graph-check-determinism: export-graph.mjs から commit/generated 除去・決定論性 sha256 確認・graph-check に Source パス検証 + 正規化 diff 補助ログ追加)
  • 起案者: [email protected]
  • 起案日時 (JST): 2026-06-01
  • 承認日時 (JST): 2026-06-02
  • Deciders: [email protected] (単独)

Pipeline 迂回の経緯(監査用注記): 本 ADRDecision Pipeline で Standard 46-47/50 と合格点に達したが、Cross-Validation が Must 軸 #reliable × critical 盲点で 3 連続差し戻しした。差し戻し理由は「決定論性の前提が採択時点で完全実証されていない」で、毎回より狭い環境(未検証→inline Evidence→CI 環境)へゴールポストが移動した。決定論性はコードレビューによる構造的証明 + ローカル実測 diff=0 で立証済(下記 Confirmation §採択前提条件)であり、残る「CI 環境での実測」は本質的に実装時検証ステップである。2 行削除の trivial な CI infra 修正に対する過剰審査と判断し、ADR-0099(実装スコープ第一級化)/ review-tiering(審査深度階層化)draft が問題提起する「低ステークス ADR の過剰審査」の実例として、Pipeline を迂回し通常 PR で起案する(代表取締役判断 2026-06-01)。Pipeline retroactive validation(ADR-0052)は任意(必要に応じて実施)。

コンテキスト

§1.1 背景

docs/architecture/decision_pipeline.mmddrp/scripts/export-graph.mjs で自動生成され、graph-check workflow が PR ごとに git diff --exit-code で drift を検知する設計。しかし生成ロジックの 117-121 行で commit hash と ISO timestamp を mermaid コメントとして埋め込んでいる:

%% Commit: ${commitHash}
%% Generated: ${new Date().toISOString()}

この 2 行は PR ごとに必ず変動するため(commit hash は SHA 連動、timestamp は実行時刻)、コミットしている .mmd と CI で再生成した .mmd が常に差分を持つ。結果、コード変更が graph 構造に影響しないケースでも graph-check が必ず FAIL する

§1.2 現状 (As-Is)

2026-05-30 のセッションで merge された PR 約 15-30 件のほぼ全件が graph-check FAIL を理由に admin merge (gh pr merge --admin) で bypass(session-close handover §8 #1「本日全 PR admin merge 適用」)。admin merge は branch protection を強制バイパスする操作で、本来 CI が止めるべき問題(adr-lint や consistency の真の違反)も同じフロー (--admin --delete-branch) で素通しできてしまう。実際 PR #1189 (ADR-0093) で adr-lint の cost-estimation-section FAIL を admin merge で bypass し、curation PR (#1191) で事後修正する pattern が成立した。ローカル pnpm graph:export 忘れによる古い .mmd 残存も、hash 差分ノイズに埋もれて検知不能。

§1.3 課題

①構造的 false-fail の常態化で graph-check の存在意義(構造変更漏れ検知)が機能不全 ②admin merge 習慣化の二次被害(本物の CI 違反まで反射 bypass = false negative、1 人運用で「もう一段の防御層」喪失)③真の graph 構造変更がノイズに埋もれ発見可能性低下 ④毎 PR で必ず fail する step の CI compute / 通知の浪費。

§1.4 制約・要件

  • 1 人運用・実装人日最小化
  • graph-check 自体は廃止しない(構造変更検知の価値は維持)
  • .mmd はリポにコミットする方針維持(docs サイトでレンダリングされる成果物)
  • 既存 git history 非破壊(本 ADR 以降の新規生成のみ対象)
  • 解決後は graph-check 起因 admin merge 0 件を目標(他の真の fail への admin merge は本 ADR スコープ外)

§1.5 目標 (To-Be)

graph-check が 真の graph 構造変更時のみ FAIL する状態にし、admin merge を「本物の CI fail への限定使用」に戻す。Non-Goals: graph-check 廃止 / .mmd の gitignore 化 / docs build pipeline 移管 / admin merge 自体の禁止(他用途で必要なケースもある)。

決定

export-graph.mjs の header から %% Commit:%% Generated: の 2 行を削除する。Source code 側の git log で commit を遡れるため、.mmd に重複して持たせる価値より hash drift コストの方が大きい。%% Source: drp/src/graph.ts 行は残し、生成元は明示し続ける。変更行数は 2 行削除のみ。graph-check workflow 側の drift 判定ロジックは流用(ただし Confirmation §2 の正規化 diff 補助ログ追加は本 ADR の必須要件)。

採択前提条件(決定論性検証): 本決定は「export-graph.mjs が同一 graph.ts から決定論的に同一 .mmd を生成する」前提に依存する。コードレビューとローカル実測で立証済(Confirmation §採択前提条件 (a)(b))。CI(ubuntu-latest + 指定 Node) での diff=0 Evidence は実装 PR 内で取得し、ローカル sha256 と一致しない場合は案 C(content-only filter)併用に格上げする。あわせて .node-version または package.jsonengines.node で CI/ローカルの Node を同一固定し、graph-check workflow の actions/setup-nodenode-version-file を参照させる。

判断基準 (Decision Drivers)

ガバナンス / CI インフラ系。重み: Must ×2.0 / High ×1.0 / Medium ×0.5。

3.1 評価軸

#重要度 (係数)案件特有の解釈
1#reliable[Must] (×2.0)真の graph 構造変更 (新 node / edge / 順序入替) を確実に検知できる
2#maintainable[High] (×1.0)修正量、保守時の認知負荷、git log との整合性
3#operable[High] (×1.0)1 人運用での運用負荷、admin merge 習慣の解消
4#efficient[Medium] (×0.5)CI compute の節約、レビュー時間の節約
5#flexible[Medium] (×0.5)将来 graph 出力フォーマット変更時の追従しやすさ

K.O. criterion: Must 軸 (#reliable) の score < 3 は不採用。

3.2 評価軸 × 案スコア表

係数採択案 (B: hash 行削除)案 A (auto-regen + commit-back)案 C (content-only filter)案 D (.mmd gitignore + docs build 生成)
#reliable×2.04 (決定論性を構造レビュー+ローカル実測で立証。CI 実測は実装 PR で取得、未取得ゆえ満点は保留)443
#maintainable×1.05 (2 行削除のみ)233
#operable×1.05 (admin merge 不要化)342
#efficient×0.55 (毎 PR の CI fail 工数ゼロ)344
#flexible×0.54335
加重和 (正規化)0.9000.6200.7600.620
K.O. 通過 (Must ≥3)

採択案 B は加重和最高 + K.O. 通過。案 A は自動 push の TOKEN scope (workflow scope 必須) が本リポの OAuth 設定と相性が悪い (本セッションの feat/adr-0091-phase-a-lint-rules PR で同 scope 不在の制約に遭遇済)。案 D は docs build pipeline (Cloudflare Pages) 障害時に .mmd を即時参照できず 1 人運用の reversibility を損なう。

検討した代替案 (Alternatives Considered)

  • 採択案 (B: hash 行削除): header から %% Commit: %% Generated: 2 行を削除。残る %% Source: 行で生成元の遡及可能性を維持。修正量最小、設計単純化。
  • 案 A (auto-regen + commit-back): graph-check workflow が drift 検知時に pnpm graph:export を再実行し PR branch に自動 push。却下: (1) workflow scope 付き token が必要で OAuth 設定変更コスト高、(2) 循環防止 ([skip ci] 制御 / bot account) が必要、(3) auto-push 通知ノイズ増。
  • 案 C (drift 判定 content-only filter): git diff で %% Commit: %% Generated: 行を ignore。却下: filter の保守責任が CI workflow 側に残り、新 metadata 行追加のたびに filter 更新が必要。Single source of truth (.mmd) の信頼性が CI filter の完全性に依存する逆転構造で脆弱。ただし採択案 B の決定論性検証が CI で失敗した場合のフォールバック候補として残置。
  • 案 D (.mmd gitignore + docs build 時生成): .mmd をリポから除外し Cloudflare Pages build hook で生成。却下: (1) build pipeline 障害時にローカルで graph を即時参照不能、(2) PR レビューで .mmd 差分が見えない、(3) docs build 統合は別 ADR 級でスコープ超過。
  • 案 E (graph-check 自体を廃止): workflow 削除。却下: 構造変更検知の価値は維持したい。根本は graph-check でなく header の hash 埋め込み。

影響 (Consequences)

§5.1 正の影響 (Good)

  • graph-check が真の構造変更時のみ FAIL する状態に正規化、CI signal の S/N 比が向上。
  • admin merge を graph-check FAIL 起因で使う必要が消滅(ただし本 ADR 単独では graph-check 起因分のみ解消、adr-lint 起因・workflow scope 起因の bypass は別 ADR スコープ。§5.3 参照)。
  • 1 人運用での認知負荷(毎 PR で false-fail を識別する手間)ゼロ化。
  • レビュー時に .mmd 差分 = 真の graph 構造変更を意味するようになり、PR レビューの示唆性が回復。
  • 直接金銭支出 0 円(個人開発・2 行削除)。

§5.2 負の影響 (Bad)

  • .mmd から「いつ / どの commit で生成された」のインライン情報が消える。git log + %% Source: 行で追跡可能だがファイル単体では不明。
  • 過去の .mmd(本 ADR マージ前にコミット済)は古い hash を含んだまま残る(corrigendum 不要、自然減衰)。
  • 将来「commit hash が .mmd に必要」と判明した場合は header に再追加が必要(現時点で具体的用途は想定できず)。
  • %% Source: 行のパス陳腐化リスク: graph.ts / export-graph.mjs がリネーム / 移動された場合、%% Source: 行は古いパスを指したまま残り、graph-check は構造差分がなければ PASS するため自動検知できない。緩和策は §撤退条件・Confirmation 参照。
  • 「2 行削除で解決」の極小スコープが問題矮小化ループを生むリスク: admin merge 習慣の解消・workflow scope の確保・graph-check の検知精度向上といった follow-up が先送りされる構造的リスク。緩和策は §Confirmation 再検証トリガー・§撤退条件 Supersede 条項。

§5.3 中立・トレードオフ (Neutral / Trade-offs)

  • 決定論性前提の逆向きリスク (false negative): hash 行削除後は「差分ゼロ=構造同一」前提が強化されるため、node/edge 列挙順が非構造的に変動すると構造変更の見逃しが潜在化する。Confirmation §2 で node/edge 行のみ抽出・ソートした正規化 diff を CI 補助ログに追加し人間目視で緩和。決定論性が CI で確認できない場合は案 C 併用へ格上げ。
  • 補助ログ追加と案 C 却下理由の整合: 採択案 B の「workflow 側変更不要」は drift 判定本体の話。Confirmation §2 の正規化 diff 補助ログは「人間目視用の副系統」で PASS/FAIL を変えない(責任分離)ため、案 C 却下の論点(drift 判定本体を filter に依存させる脆弱性)とは矛盾しない。補助ログは本 ADR の必須要件としコスト試算に計上。
  • admin merge 解消効果の限定性: 「約 15-30 件のほぼ全件が graph-check FAIL 起因」という現状記述は内訳が数値分離されておらず、PR #1189 のような adr-lint FAIL 起因 bypass を含む。本 ADR で hash 行を削除しても graph-check 起因分のみが解消対象。残余要因(adr-lint FAIL への反射 bypass / workflow scope 不在)への対処は follow-up ADR で計画し、本 ADR マージ後 8 週以内に起案することをコミット(§撤退条件参照)。
  • header の %% Source: 行は維持するため生成元の遡及可能性は失わない(パス陳腐化は §5.2 / Confirmation で別途扱う)。
  • 採択案は admin merge 自体を禁止しない。workflow scope 不在のような正当な bypass では引き続き利用可能。

コスト試算

作業工数 (人日)工数 (h)
export-graph.mjs の 2 行削除0.050.3
動作確認 (pnpm graph:export → diff チェック)0.050.3
CI 環境決定論性 Evidence 取得 (ubuntu-latest + 指定 Node)0.050.3
.node-version / engines.node 固定 + workflow の node-version-file 参照0.050.3
graph-check workflow への正規化 diff 補助ログ追加(必須要件)0.100.6
ADR 文書化 (起案 + curation)0.251.5
合計約 0.55 人日~3.3 h

金額換算: 個人開発のため直接金銭支出 0 円(自工数)。追加 LLM / インフラコストなし。

撤退条件 (Rollback Plan)

判定指標期限 / 検知方法代替アクション
本 ADR 採択後 4 週間で graph-check 起因の admin merge が 1 件以上発生4 週後に gh search / ラベル集計header 復活 + 案 C (content-only filter) へフォールバック
真の graph 構造変更が 1 件以上検知漏れ (post-hoc 発見)月次レビューで graph.ts git log と graph-check 履歴を照合graph-check ロジック強化 (構造ハッシュ) または案 C 併用
CI 環境 (ubuntu-latest + 指定 Node) での決定論性 diff≠0 が実装時に判明実装 PR でのブロッキング検証即時「案 C 併用に格上げ」、案 B 単独でマージしない
commit hash 情報を .mmd 単体で必要とする外部ツール / 監査要件が発生都度発覚 (現時点で想定なし)header 再追加 + Generated 行は除外、または .mmd.lock 別ファイルに分離記録
follow-up ADR (workflow scope 確保 / admin merge ポリシー) が本 ADR マージ後 8 週以内に未起案マージ後 8 週時点で adr-index 確認本 ADR を Superseded 扱いとし admin merge 習慣解消問題を再フレーミングする後継 ADR を起案
graph.ts / export-graph.mjs のパス変更時に %% Source: 行未更新が発覚PR レビュー / 月次レビュー同一 PR で %% Source: 行を更新、再発時は graph-check に git ls-files 存在確認 step を追加

Confirmation

  • 検証手段:
    1. 採択前提条件 (決定論性 Evidence):
      • (a) コードレビュー所見(構造的決定論・実施済): export-graph.mjs は graph.ts を String.matchAll でソース出現順に node/edge を抽出し配列へ push(挿入順保持)。Object.keys()/Object.entries()/Map/Set/process.env/glob/乱数は不在、NODE_LABELS/SUBGRAPH_TITLES は静的ルックアップ、GRAPH_DEFS は固定配列、%% Source: 行はハードコード文字列リテラル。→ V8 イテレーション順に依存する箇所が存在せず、非決定論の余地は削除対象 2 行のみ(%% Commit:git rev-parse --short HEAD=同一 SHA で不変 / %% Generated: の timestamp が唯一の真の変動源)。
      • (b) ローカル実測 Evidence(実施済 2026-06-01): 同一 git SHA caca7da から node drp/scripts/export-graph.mjs を 2 回連続実行。%% Commit:/%% Generated: の 2 行を除いた正規化 diff = 0、正規化出力 sha256 が両 run 完全一致(87cef2cb6d441425375a5f0b36ea2306fd11610435e852c3db0ac91d962a392a)。差分は %% Generated: の timestamp 1 行のみ。環境: Node v24.14.0 / Darwin。
      • (c) CI 環境 Evidence(実装 PR で取得): ubuntu-latest + 指定 Node で同一 SHA から 2 回実行し正規化 sha256 がローカル値と一致することを確認。不一致なら案 C 併用へ格上げ。
      • (d) 再検証トリガー: ①Node バージョンアップ、②graph.ts の 1 PR あたり変更行数 20 行超のリファクタリング、③export-graph.mjs の変更、④graph-check workflow の actions/setup-node 設定変更 のいずれかで決定論性 Evidence を再取得。diff≠0 なら §撤退条件の代替アクションを発動。
    2. 正規化 diff 補助ログ(必須要件・人間目視用副系統): graph-check workflow に node/edge 行のみを抽出・ソートした正規化 diff を補助出力として追加。PASS/FAIL は workflow 全体に影響させない(drift 判定本体は案 B のまま)。2 行削除 PR と同一 PR でマージするチェックリスト項目とする。
    3. マージ直後検証: 本 ADR マージ直後の 5 PR で graph-check FAIL 件数を計測 (期待 0 件)。
    4. graph.ts 変更 PR の即時確認: graph.ts を変更する PR がマージ直後に graph-check の PASS/FAIL を確認し PASS 履歴を記録。
    5. admin merge 起因分類: 4 週後の admin merge 集計を「graph-check 起因 / adr-lint 起因 / workflow scope 起因 / 真の CI fail 起因」に分類(graph-check 起因の目標 0、許容 1 以下)。本 ADR マージ前にも過去 15-30 件を遡って同分類で集計し効果範囲を定量把握。
    6. %% Source: パス健全性チェック: パス変更 PR レビュー時に %% Source: 行が同一 PR で更新されているか確認。月次で git ls-files 存在を目視確認。
  • 実行頻度: 採択前提条件 (a)(b) は実施済、(c) は実装 PR、(d) は該当変更ごと。マージ後 1 週間は週次、その後月次。graph.ts 変更 PR の即時確認は PR ごと。
  • 違反時対応: CI 環境 diff≠0 → 案 C 併用へ格上げ / 補助ログ未実装でのマージ禁止 / graph-check 起因 admin merge 1 件で撤退条件発動 / follow-up ADR 8 週以内未起案で本 ADR Superseded。
  • 観測可能 KPI: graph-check 起因 admin merge 件数 / 月 (目標 0、許容上限 1)。CI 環境決定論性検証 diff=0 (実装 PR・必達)。graph.ts 変更 PR の graph-check PASS 率 (目標 100%)。admin merge 原因別内訳(4 分類・月次)。follow-up ADR 起案進捗 (マージ後 8 週)。

参照 (References)

  • 関連 ADR:
    • 動機の実例: PR #1189 (ADR-0093 の adr-lint cost-estimation-section FAIL を admin merge bypass) / PR #1191 (curation 事後修正) / feat/adr-0091-phase-a-lint-rules PR (workflow scope 不在の制約事例)
    • ADR-0052 (retroactive validation mode): 本 ADR は Pipeline 迂回起案のため、任意で retroactive validation を必要時に適用可能
    • ADR-0099 (実装スコープ第一級化) / review-tiering draft (審査深度階層化): 本 ADR の Pipeline 迂回は「低ステークス ADR の過剰審査」の実例
    • 別系統: PR #1247 (.mmd の mermaid client-side 描画、本 ADR と独立)
    • Follow-up ADR(本 ADR マージ後 8 週以内に起案・コミット): (i) workflow scope 確保 ADR、(ii) adr-lint FAIL / その他真の CI fail への admin merge ポリシー ADR
  • 外部資料: drp/scripts/export-graph.mjs (117-121 行) / docs/architecture/decision_pipeline.mmd / session-close handover §8 #1「本日全 PR admin merge 適用」

過去 ADR との関係

  • CI / workflow インフラの修正であり直接の先行 ADR は無い。動機は admin merge bypass の実例(PR #1189 / #1191)と session-close handover §8 #1。
  • 本 ADR は admin merge 件数を「graph-check 起因 / adr-lint 起因 / workflow scope 起因 / 真の CI fail 起因」で分類観測する起点となり、follow-up ADR(workflow scope 確保 / admin merge ポリシー)を後続起案する。
  • .mmd の docs サイトレンダリングは別系統(mermaid client-side 描画 = PR #1247)であり本 ADR の生成 header 変更とは独立。
  • 本 ADR は Decision Pipeline を迂回して起案した(冒頭注記参照)。Pipeline 統制の SSoT は維持されるべきで、低ステークス ADR の過剰審査問題は review-tiering draft で別途解消する。