ln-644-dependency-graph-auditor について
コードベースを監査し、モジュール依存グラフを構築して循環依存、アーキテクチャ境界、安定依存の原則を検証するスキルです。アーキテクチャの自動判定とベースラインにより、既存プロジェクトも段階的に監査できます。
主な機能
- 01インポートから依存グラフを構築
- 02直接・推移的な循環依存を検出
- 03依存境界ルールを検証
- 04結合度と安定性の指標を算出
- 05ベースラインで新規違反を追跡
活用シーン
- 01モジュール間の循環依存を発見
- 02依存関係とアーキテクチャルールを照合
- 03既存の違反を段階的に解消
MCP 対応
依存関係、循環、アーキテクチャ指標の分析には hex-graph、コードの読み取りには hex-line を優先して利用できます。MCP が利用できない場合や未インデックスの場合は、組み込みツールに切り替えます。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ levnikolaevich/ claude-code-skills --skill ln-644-dependency-graph-auditorインストール後、Claude Code で/ln-644-dependency-graph-auditorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/ac_validation_rules.mdagent_delegation_pattern.mdagent_instructions_writing_guide.mdagent_review_memory.mdagent_review_workflow.mdagent_skill_roots_contract.mdai_ready_architecture.mdaudit_coordinator_aggregation.mdaudit_coordinator_domain_mode.mdaudit_output_schema.mdreferences/agents/agent_registry.jsonagent_registry.json.SOURCE.mdagent_result_classifier.mjsagent_runner.mjsreferences/agents/prompt_templates/general_analysis.mditerative_refinement.mdrefinement_perspectives.mdreview_base.mdscenario_validator.mdscope_analysis.mdtask_decomposition.mdtraceability_validator.mdreferences/agents/prompt_templates/modes/code.mdcontext.mdplan_review.mdstory.mdreferences/agents/schemas/code_review_schema.jsoncontext_review_schema.jsonstory_review_schema.jsonreferences/agents/test/agent_result_classifier.mjs詳細
パス: ファイルパス(
references/、../ln-*)は、このスキルディレクトリからの相対パスです。
種類: L3 Worker カテゴリ: 6XX 監査
依存関係グラフ監査ツール
アーキテクチャ境界を適用するため、モジュール依存関係グラフを構築して分析する L3 Worker です。
目的と範囲
- import 文からモジュール依存関係グラフを構築します(Python、TS/JS、C#、Java)
- 循環依存を検出します:ペア単位(HIGH)+ DFS による推移的な依存(CRITICAL)
- 境界ルールを検証します:禁止、許可、必須(dependency-cruiser のパターンに準拠)
- Robert C. Martin の指標(Ca、Ce、Instability)+ Lakos の集約指標(CCD、NCCD)を計算します
- Stable Dependencies Principle(安定依存の原則、SDP)を検証します
- レガシーコードへの段階的な導入に向けて、ベースライン/凍結をサポートします(ArchUnit FreezingArchRule に準拠)
- 適応型: 3 層のアーキテクチャ検出 -- カスタムルール > ドキュメント > 自動検出
対象外(他の Worker の担当):
- I/O 分離違反(grep ベース) -> ln-642-layer-boundary-auditor
- API コントラクト違反 -> ln-643-api-contract-auditor
- コードの重複 -> ln-623-code-principles-auditor
入力(ln-640 から)
- architecture_path: string # Path to docs/architecture.md
- codebase_root: string # Root directory to scan
- output_dir: string # e.g., ".hex-skills/runtime-artifacts/runs/{run_id}/audit-report"
# Domain-aware (optional, from coordinator)
- domain_mode: "global" | "domain-aware" # Default: "global"
- current_domain: string # e.g., "users", "billing" (only if domain-aware)
- scan_path: string # e.g., "src/users/" (only if domain-aware)
# Baseline (optional)
- update_baseline: boolean # If true, save current state as baseline
domain_mode="domain-aware" の場合: すべての Grep/Glob 操作で codebase_root の代わりに scan_path を使用します。すべての検出結果に domain フィールドを付与します。
ワークフロー
必ず読み込む: 検出方法について references/two_layer_detection.md を読み込みます。
必ず読み込む: references/mcp_tool_preferences.md と references/mcp_integration_patterns.md を読み込みます。
依存関係のトポロジー、循環、またはアーキテクチャ指標が監査の質を大きく向上させる場合は、まず hex-graph を使用します。利用可能な場合は、ローカルのコードや設定を読み取る際に、まず hex-line を使用します。MCP が利用できない場合、未対応の場合、またはインデックスが作成されていない場合は、組み込みの Read/Grep/Glob/Bash を使用して続行し、レポートにフォールバックしたことを記載します。
フェーズ 1:アーキテクチャを特定する(適応型)
必ず読み込む: references/dependency_rules.md を読み込み、3 段階の優先順位チェーン、アーキテクチャプリセット、自動検出のヒューリスティクスを使用します。
アーキテクチャの検出には3 段階の優先順位を使用します。明示的な設定はドキュメントより優先され、ドキュメントは自動検出より優先されます。
# Priority 1: Explicit project config
IF docs/project/dependency_rules.yaml exists:
Load custom rules (modules, forbidden, allowed, required)
SKIP preset detection
# Priority 2: Architecture documentation
ELIF docs/architecture.md exists:
Read Section 4.2 (modules, layers, architecture_type)
Read Section 6.4 (boundary rules, if defined)
Map documented layers to presets from dependency_rules.md
Apply preset rules, override with explicit rules from Section 6.4
# Priority 3: Auto-detection from directory structure
ELSE:
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root
Run structure heuristics:
signals = {}
IF Glob("**/domain/**") AND Glob("**/infrastructure/**"):
signals["clean"] = HIGH
IF Glob("**/controllers/**") AND Glob("**/services/**") AND Glob("**/repositories/**"):
signals["layered"] = HIGH
IF Glob("**/features/*/") with internal structure:
signals["vertical"] = HIGH
IF Glob("**/adapters/**") AND Glob("**/ports/**"):
signals["hexagonal"] = HIGH
IF Glob("**/views/**") AND Glob("**/models/**"):
signals["mvc"] = HIGH
IF len(signals) == 0:
architecture_mode = "custom"
confidence = "LOW"
# Only check cycles + metrics, no boundary presets
ELIF len(signals) == 1:
architecture_mode = signals.keys()[0]
confidence = signals.values()[0]
Apply matching preset from dependency_rules.md
ELSE:
architecture_mode = "hybrid"
confidence = "MEDIUM"
# Identify zones, apply different presets per zone (see dependency_rules.md Hybrid section)
FOR EACH detected_style IN signals:
zone_path = identify_zone(detected_style)
zone_preset = load_preset(detected_style)
zones.append({path: zone_path, preset: zone_preset})
Add cross-zone rules: inner zones accessible, outer zones forbidden to depend on inner
フェーズ 2:依存関係グラフを構築する
必ず読み込む: references/import_patterns.md を読み込み、言語の検出、Import の Grep パターン、モジュール解決アルゴリズム、除外リストを使用します。
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root
# Step 1: Detect primary language
tech_stack = Read(docs/project/tech_stack.md) IF exists
ELSE detect from file extensions: Glob("**/*.py", "**/*.ts", "**/*.cs", "**/*.java", root=scan_root)
# Step 2: Extract imports per language
FOR EACH source_file IN Glob(language_glob_pattern, root=scan_root):
imports = []
# Python
IF language == "python":
from_imports = Grep("^from\s+([\w.]+)\s+import", source_file)
plain_imports = Grep("^import\s+([\w.]+)", source_file)
imports = from_imports + plain_imports
# TypeScript / JavaScript
ELIF language == "typescript" OR language == "javascript":
es6_imports = Grep("import\s+.*\s+from\s+['\"]([^'\"]+)['\"]", source_file)
require_imports = Grep("require\(['\"]([^'\"]+)['\"]\)", source_file)
imports = es6_imports + require_imports
# C#
ELIF language == "csharp":
using_imports = Grep("^using\s+([\w.]+);", source_file)
imports = using_imports
# Java
ELIF language == "java":
java_imports = Grep("^import\s+([\w.]+);", source_file)
imports = java_imports
# Step 3: Filter internal only (per import_patterns.md Exclusion Lists)
internal_imports = filter_internal(imports, scan_root)
# Step 4: Resolve to modules
FOR EACH imp IN internal_imports:
source_module = resolve_module(source_file, scan_root)
target_module = resolve_module(imp, scan_root)
IF source_module != target_module:
graph[source_module].add(target_module)
フェーズ 3:循環を検出する(ADP)
hex-graph による高速化: .hex-skills/codegraph/index.db があるプロジェクトでは、analyze_architecture(verbosity="full") を使用し、返された cycles を調べて循環を即座に検出します。これらの循環および結合度の指標はワークスペース内のモジュール単位であるため、単一パッケージのリポジトリでは 1 つのモジュールに集約されることがあります。パッケージ内分析にはグラフの出力が粗すぎる場合は、grep ベースの DFS、またはシンボル/ファイル単位のトレースにフォールバックします。
Robert C. Martin(『Clean Architecture』第 14 章):「コンポーネントの依存関係グラフに循環を許してはならない。」
# Pairwise cycles (A <-> B)
FOR EACH (A, B) WHERE B IN graph[A] AND A IN graph[B]:
cycles.append({
type: "pairwise",
path: [A, B, A],
severity: "HIGH",
fix: suggest_cycle_fix(A, B)
})
# Layer 2: Test-only dependencies (devDependencies, test imports) -> skip cycle
# Plugin/extension architecture with documented bidirectional design -> downgrade to LOW
# Transitive cycles via DFS (A -> B -> C -> A)
visited = {}
rec_stack = {}
FUNCTION dfs(node, path):
visited[node] = true
rec_stack[node] = true
FOR EACH neighbor IN graph[node]:
IF NOT visited[neighbor]:
dfs(neighbor, path + [node])
ELIF rec_stack[neighbor]:
cycle_path = extract_cycle(path + [node], neighbor)
IF len(cycle_path) > 2: # Skip pairwise (already detected)
cycles.append({
type: "transitive",
path: cycle_path,
severity: "CRITICAL",
fix: suggest_cycle_fix_transitive(cycle_path)
})
rec_stack[node] = false
FOR EACH module IN graph:
IF NOT visited[module]:
dfs(module, [])
# Folder-level cycles (per dependency-cruiser pattern)
folder_graph = collapse_to_folders(graph)
Repeat DFS on folder_graph for folder-level cycles
循環を解消するための推奨策(『Clean Architecture』第 14 章より):
- DIP -- 依存される側のモジュールにインターフェースを抽出し、依存する側のモジュールで実装します
- 共有コンポーネントの抽出 -- 共有コードを新しいモジュールに移し、両方のモジュールから依存させます
- ドメインイベント/メッセージバス -- ドメインをまたぐ循環では、非同期通信によって結合を解消します
フェーズ 4:境界ルールを検証する
# Load rules from Phase 1 discovery
# rules = {forbidden: [], allowed: [], required: []}
# Check FORBIDDEN rules
FOR EACH rule IN rules.forbidden:
FOR EACH edge (source -> target) IN graph:
IF matches(source, rule.from) AND matches(target, rule.to):
IF rule.cross AND same_group(source, target):
CONTINUE # cross=true means only cross-group violations
boundary_violations.append({
rule_type: "forbidden",
from: source,
to: target,
file: get_import_location(source, target),
severity: rule.severity,
reason: rule.reason
})
# Check ALLOWED rules (whitelist mode)
IF rules.allowed.length > 0:
FOR EACH edge (source -> target) IN graph:
allowed = false
FOR EACH rule IN rules.allowed:
IF matches(source, rule.from) AND matches(target, rule.to):
allowed = true
BREAK
IF NOT allowed:
boundary_violations.append({
rule_type: "not_in_allowed",
from: source,
to: target,
file: get_import_location(source, target),
severity: "MEDIUM",
reason: "Dependency not in allowed list"
})
# Check REQUIRED rules
FOR EACH rule IN rules.required:
FOR EACH module IN graph WHERE matches(module, rule.module):
has_required = false
FOR EACH dep IN graph[module]:
IF matches(dep, rule.must_depend_on):
has_required = true
BREAK
IF NOT has_required:
boundary_violations.append({
rule_type: "required_missing",
module: module,
missing: rule.must_depend_on,
severity: "MEDIUM",
reason: rule.reason
})
フェーズ 5:グラフ指標を計算する
hex-graph の高速化: .hex-skills/codegraph/index.db があるプロジェクトでは、analyze_architecture(verbosity="full") を使用し、返された coupling 指標を調べて Ca/Ce/I を即座に計算します。グラフを利用できない場合は、手動計算に切り替えます。
必ず読む: references/graph_metrics.md を読み込みます。Metric Definitions、Thresholds per Layer、SDP Algorithm、Lakos Formulas を使用します。
# Per-module metrics (Robert C. Martin)
FOR EACH module IN graph:
Ce = len(graph[module]) # Efferent: outgoing
Ca = count(m for m in graph if module in graph[m]) # Afferent: incoming
I = Ce / (Ca + Ce) IF (Ca + Ce) > 0 ELSE 0 # Instability
metrics[module] = {Ca, Ce, I}
# SDP validation (Stable Dependencies Principle)
FOR EACH edge (A -> B) IN graph:
IF metrics[A].I < metrics[B].I:
# Stable module depends on less stable module -- SDP violation
sdp_violations.append({
from: A, to: B,
I_from: metrics[A].I, I_to: metrics[B].I,
severity: "HIGH"
})
# Threshold checks (per graph_metrics.md, considering detected layer)
FOR EACH module IN metrics:
layer = get_layer(module) # From Phase 1 discovery
thresholds = get_thresholds(layer) # From graph_metrics.md
IF metrics[module].I > thresholds.max_instability:
findings.append({severity: thresholds.severity, issue: f"{module} instability {I} exceeds {thresholds.max_instability}"})
IF metrics[module].Ce > thresholds.max_ce:
findings.append({severity: "MEDIUM", issue: f"{module} efferent coupling {Ce} exceeds {thresholds.max_ce}"})
# Lakos aggregate metrics
CCD = 0
FOR EACH module IN graph:
DependsOn = count_transitive_deps(module, graph) + 1 # Including self
CCD += DependsOn
N = len(graph)
CCD_balanced = N * log2(N) # CCD of balanced binary tree with N nodes
NCCD = CCD / CCD_balanced IF CCD_balanced > 0 ELSE 0
IF NCCD > 1.5:
findings.append({severity: "MEDIUM", issue: f"Graph complexity (NCCD={NCCD:.2f}) exceeds balanced tree threshold (1.5)"})
カスケードチェーンの拡張: サービスファイル(**/services/**)では、モジュールレベルのグラフを関数レベルまで拡張します。各公開関数について、最も長い副作用チェーンを見つけます(マーカーは references/ai_ready_architecture.md を参照)。chain_length >= 3 の場合は、cascade_findings に追加します。フェーズ 8 の DATA-EXTENDED JSON に "runtime_cascades" 配列を出力します。重大度:HIGH(4 以上)、MEDIUM(3)。
フェーズ 6:ベースラインのサポート
ArchUnit FreezingArchRule に着想を得たもので、レガシープロジェクトへの段階的な導入を可能にします。
baseline_path = docs/project/dependency_baseline.json
IF file_exists(baseline_path):
known = load_json(baseline_path)
current = serialize_violations(cycles + boundary_violations + sdp_violations)
new_violations = current - known
resolved_violations = known - current
# Report only NEW violations as findings
active_findings = new_violations
baseline_info = {new: len(new_violations), resolved: len(resolved_violations), frozen: len(known - resolved_violations)}
IF input.update_baseline == true:
save_json(baseline_path, current)
ELSE:
# First run -- report all
active_findings = all_violations
baseline_info = {new: len(all_violations), resolved: 0, frozen: 0}
# Suggest: output note "Run with update_baseline=true to freeze current violations"
フェーズ 7:スコアを計算する
必ず読む: references/audit_worker_core_contract.md と references/audit_scoring.md を読み込みます。
penalty = (critical * 2.0) + (high * 1.0) + (medium * 0.5) + (low * 0.2)
score = max(0, 10 - penalty)
注: ベースラインが有効な場合、ペナルティは凍結された違反ではなく、active_findings(新しい違反)のみから計算します。
フェーズ 8:レポートを作成する
必ず読む: references/audit_worker_core_contract.md と references/templates/audit_worker_report_template.md を読み込みます。
references/audit_summary_contract.md に従って JSON の概要を書き込みます。管理モードでは、呼び出し元から runId と summaryArtifactPath の両方が渡されます。スタンドアロンモードでは、共有コントラクトに従って、ワーカーが実行単位のアーティファクトパスを生成します。
# Build markdown report in memory with:
# - AUDIT-META (standard penalty-based: score, counts)
# - Checks table (cycle_detection, boundary_rules, sdp_validation, metrics_thresholds, baseline_comparison)
# - Findings table (active violations sorted by severity)
# - DATA-EXTENDED: {graph_stats, cycles, boundary_violations, sdp_violations, metrics, baseline}
IF domain_mode == "domain-aware":
Write to {output_dir}/644-dep-graph-{current_domain}.md
ELSE:
Write to {output_dir}/644-dep-graph.md
フェーズ 9:概要を返す
Report written: .hex-skills/runtime-artifacts/runs/{run_id}/audit-report/644-dep-graph-users.md
Score: 6.5/10 | Issues: 8 (C:1 H:3 M:3 L:1)
重要なルール
必ず読む: references/audit_worker_core_contract.md を読み込みます。
- 適応型アーキテクチャ -- スタイルを決めつけず、プロジェクト構造またはドキュメントから検出します
- 3 段階の優先順位 -- カスタムルール > architecture.md > 自動検出
- ハイブリッド対応 -- 複数のスタイルが混在するプロジェクトでは、ゾーンごとに異なるプリセットを適用します
- カスタム = セーフモード -- パターンを検出できない場合は、循環依存 + 指標のみをチェックします(境界違反の誤検出は行いません)
- 内部のみ -- 標準ライブラリとサードパーティをグラフから除外します(プロジェクトのモジュールのみ)
- ベースラインモード -- ベースラインがある場合、新しい違反のみを報告します
- 循環依存の修正 -- 実行可能な推奨事項を必ず提示します(DIP、共有機能の抽出、ドメインイベント)
- ファイル + 行 -- 違反箇所について、正確なインポート位置を必ず提示します
完了の定義
必ず読む: references/audit_worker_core_contract.md を読み込みます。
- アーキテクチャを検出済み(適応型の 3 段階検出を適用済み)
- インポート文から依存関係グラフを構築済み(内部モジュールのみ)
- 循環依存を検出済み(ペアごと + 推移的 DFS + フォルダー単位)
- 境界ルールを検証済み(禁止 + 許可 + 必須)
- 指標を計算済み(モジュールごとの Ca、Ce、I + 集計値の CCD、NCCD)
- SDP を検証済み(安定モジュールが不安定なモジュールに依存していない)
- ベースラインがある場合は適用済み(新しい違反のみを報告)
- ドメインを考慮する場合、すべての Grep/Glob を scan_path に限定し、検出結果にドメインのタグを付与済み
- audit_scoring.md に従ってスコアを計算済み
-
{output_dir}/644-dep-graph[-{domain}].mdにレポートを作成済み(アトミックな単一の Write 呼び出し) - コントラクトに従って概要を作成済み
参照ファイル
- 境界ルールとプリセット:
references/dependency_rules.md - 指標としきい値:
references/graph_metrics.md - インポートパターン:
references/import_patterns.md - スコアリングアルゴリズム:
references/audit_scoring.md
バージョン: 1.0.0 最終更新日: 2026-02-11