δ DeltaLint Architecture

構造矛盾検出器 — モジュール間の暗黙の契約違反を LLM で検出

2段階検出パイプライン

偽陰性コスト ≈ 29× 偽陽性コスト → Phase 1 で広く拾い、Phase 2 で絞る

📂 Git diff / --since / --scope
変更ファイル特定
Phase 0 — retrieval.py
--semantic
コンテキスト構築 · import解析 → 1-hop依存 → 4Tier信頼度
Phase 1 — detector.py
LLM検出 · 高Recall(30%の確信でも報告)· 10パターン
Phase 2 — verifier.py
--no-verify
LLM検証 · 5基準(実在/クロスモジュール/到達可能/非意図的/正確)
output.py — フィルタリング
severity + suppress.yml → shown / filtered / suppressed / expired
findings.py — JSONL永続化
append-only · 3層重複排除 · ダッシュボード生成
--autofix: fixgen.py + debt_loop.py
branch → fix → regression check → commit → PR

バッチ実行モデル

コンテキスト
> 40K chars?
▼ Yes
バッチ分割
Batch 1
Batch 2
Batch N
ThreadPoolExecutor で並列 → 共有JSONL集約

プロセス分離

サブプロセスとして再帰呼び出し。LLM タイムアウトが1バッチに閉じる。他バッチへの影響なし。

3軸スキャンモデル

scope × depth × lens = 3 × 2 × 3 = 18通り
🔭
Scope(広さ)
diff 変更ファイル + 1-hop依存
smart git履歴ベースのファイル選択
all 全ソースファイル(バッチ処理)
🔬
Depth(深さ)
default 直接の依存のみ(1-hop)
deep 3ホップまで辿る(×0.85減衰)
🎯
Lens(質)
default 構造矛盾(10パターン)
stress 仮想改修 → 地雷マップ
security 認証・権限・入力検証

3つのスキャンパス

通常スキャン
diff → 1-hop依存
→ LLM検出
→ LLM検証
日常の変更チェック
深層スキャン
正規表現抽出
→ 契約グラフ構築
→ LLM検証
フック系の構造解析
ストレステスト
構造分析
→ 仮想改修生成
→ N回スキャン → 集約
地雷マップ作成

モジュール構成

scripts/ 配下の主要モジュール。色はパイプラインでの役割を示す。

コアパイプライン

📋
cli.py
CLI エントリポイント(argparse + サブコマンド)
1,127行
cmd_scan.py
scan コマンド群(scan, deep, full, watch)
1,778行
🔍
retrieval.py
コンテキスト構築(import解析 → 4Tier依存)
1,651行
🎯
detector.py
Phase 1: LLM検出(高recall, 3段バックエンド)
525行
verifier.py
Phase 2: LLM検証(5基準, confidence<0.7→reject)
299行
📊
output.py
フィルタリング + 表示フォーマット

データ & スコアリング

💾
findings.py
JSONL管理 + 3層重複排除 + ダッシュボード生成
1,896行
📈
scoring.py
debt_score + ROI(唯一の重み定義元)
458行
🧮
info_theory.py
surprise × entropy + Chao1カバレッジ推定
302行
🚫
suppress.py
サプレス管理(ハッシュベース, 自動失効)
305行

自動修正

🔧
fixgen.py
LLM修正パッチ生成(old_code → new_code)
262行
🔄
debt_loop.py
負債解消ループ(1finding=1branch=1PR)
735行

解析 & 拡張

🧠
semantic.py
暗黙の仮定抽出(LLM + grep)
313行
💣
stress_test.py
仮想改修 × N → ヒートマップ集約
1,842行
👫
sibling.py
暗黙の兄弟ペア学習 → コンテキスト強化
433行
🕸️
contract_graph.py
フック経由の暗黙依存検出(実験的)
420行

サポート

⚙️
cli_utils.py
環境チェック, config/profile読込, ベースライン
771行
🚀
cmd_init.py
リポジトリ初期化(構造分析 + sibling_map)
570行
📦
cache.py
SHA256ベースのスキャンキャッシュ
106行
📝
git_enrichment.py
git churn(6ヶ月) / fan_out 計算

4軸スコアリングシステム

4つの独立した軸で優先度を多角的に評価。3層マージ: defaults ← config.json ← profile

静的評価
debt_score
sev × pattern × status × 1000
バグの深刻度(0〜1000)
修正価値
ROI
sev × churn × fan_out / fix_cost × 100
修正の費用対効果
情報量
info_score
(1/√n) × log₂(1+m) × 100
初出ほど高い驚き度
カバレッジ
Chao1
S_obs + f₁²/(2×f₂)
未発見finding数の推定

スコアリング補正

churn_weight

git log からの月次変更頻度。log₂(1+x) で外れ値抑制。月3回以上で max(0.5〜10.0)

fan_out_weight

git grep からの被参照ファイル数。5ファイル以上で max(1.0〜10.0)

放置コスト加速

1 + log₂(1 + days/30) × churn_ratio — 放置期間 × 変更頻度で加速

不確実ディスカウント

certainty=uncertain は roi_score × 0.3 に減額

検出パターン(10種)

構造矛盾(①-⑥)— 2箇所必須

# パターン名 検出対象 メカニズム
Asymmetric Defaults 入出力パスで同じ値の扱いが異なる copy_divergence
Semantic Mismatch 共有名がモジュール間で異なる意味 copy_divergence
External Spec Divergence RFC・言語仕様とコードが乖離 one_sided_evolution
Guard Non-Propagation 並行パスでバリデーション欠落 one_sided_evolution
Paired-Setting Override 独立に見える2設定が暗黙に干渉 independent_collision
Lifecycle Ordering 実行順序の前提が崩れる independent_collision

技術的負債(⑦-⑩)

# パターン名 検出対象 箇所数
Dead Code / Unreachable Path 未使用エクスポート、永久OFFフラグ 1箇所可
Duplication Drift コピペコードの片方だけ更新 2箇所
Interface Mismatch 呼び出し側と定義側で引数不一致 2箇所
Missing Abstraction 同一ロジックが3箇所以上に散在 1箇所可

メカニズム分布

~60%
copy_divergence
A→Bコピー時の不完全な適応
~25%
one_sided_evolution
片方だけ改善
~15%
independent_collision
独立開発の衝突

耐障害性設計

LLM は不安定 → 「壊れても最善を尽くす」設計

3段 LLM フォールバック

claude -p ($0) → Anthropic SDK → raw HTTP。CLI不可でもAPI、APIも不可ならHTTP直叩き

4段 JSON パーサー

markdownブロック抽出 → 直接parse → [...]ブラケット抽出 → rawテキスト(parse_error: true)

Verifier 不可時パススルー

Phase 2 が失敗 → Phase 1 結果を全件通過。精度は下がるが検出は止めない(graceful degradation)

バッチ分離

サブプロセス再帰呼び出し。1バッチのタイムアウトが全体に波及しない。失敗バッチは警告のみ

自動環境構築

依存未インストール → npm install / pip install / brew install を自動実行。全滅でもdry-runで動作

サプレス自動失効

コード変更で code_hash 不一致 → サプレスが自動的に無効化。再レビューを強制

3層重複排除

完全一致ハッシュ → trigram類似度55% → エンティティ重複60%。LLMの表現揺れを吸収

0件エスカレーション

検出0件時の3段階: sibling拡大 → 横断契約チェック → 最低確信候補の報告。黙って0件を返さない

設定システム(4層マージ)

CLI flags
>
Profile
>
config.json
>
Defaults

明示的に指定された上位が常に勝つ。指定されたキーだけ上書き。

config(何を使うか)

モデル、閾値、容量制限、severity。argparse のフラグに対応。

policy(どう動くか)

プロンプト追加指示、無効化パターン、スコアリング重み、テンプレート。