ln-644-dependency-graph-auditor by levnikolaevich/claude-code-skills
npx skills add https://github.com/levnikolaevich/claude-code-skills --skill ln-644-dependency-graph-auditorPaths: File paths (
shared/,references/,../ln-*) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root. Ifshared/is missing, fetch files via WebFetch fromhttps://raw.githubusercontent.com/levnikolaevich/claude-code-skills/master/skills/{path}.
Type: L3 Worker Category: 6XX Audit
L3 Worker,用于构建和分析模块依赖图以强制执行架构边界。
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
超出范围(由其他 Worker 负责):
- architecture_path: string # 指向 docs/architecture.md 的路径
- codebase_root: string # 要扫描的根目录
- output_dir: string # 例如:"docs/project/.audit/ln-640/{YYYY-MM-DD}"
# 领域感知(可选,来自协调器)
- domain_mode: "global" | "domain-aware" # 默认:"global"
- current_domain: string # 例如:"users", "billing"(仅在 domain-aware 模式下)
- scan_path: string # 例如:"src/users/"(仅在 domain-aware 模式下)
# 基线(可选)
- update_baseline: boolean # 如果为 true,则将当前状态保存为基线
当 domain_mode="domain-aware" 时: 对所有 Grep/Glob 操作使用 scan_path 而不是 codebase_root。为所有发现项标记 domain 字段。
必读: 加载 shared/references/two_layer_detection.md 以了解检测方法。
必读: 加载 references/dependency_rules.md — 使用 3 层优先级链、架构预设、自动检测启发式方法。
架构检测使用 3 层优先级 — 显式配置优先于文档,文档优先于自动检测:
# 优先级 1:显式项目配置
IF docs/project/dependency_rules.yaml 存在:
加载自定义规则(模块、禁止、允许、必需)
跳过预设检测
# 优先级 2:架构文档
ELIF docs/architecture.md 存在:
读取第 4.2 节(模块、层、architecture_type)
读取第 6.4 节(边界规则,如果已定义)
将文档化的层映射到 dependency_rules.md 中的预设
应用预设规则,并用第 6.4 节中的显式规则覆盖
# 优先级 3:从目录结构自动检测
ELSE:
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root
运行结构启发式检测:
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"
# 仅检查循环 + 指标,无边界预设
ELIF len(signals) == 1:
architecture_mode = signals.keys()[0]
confidence = signals.values()[0]
应用 dependency_rules.md 中匹配的预设
ELSE:
architecture_mode = "hybrid"
confidence = "MEDIUM"
# 识别区域,为每个区域应用不同的预设(参见 dependency_rules.md 混合部分)
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})
添加跨区域规则:内部区域可访问,外部区域禁止依赖内部区域
必读: 加载 references/import_patterns.md — 使用语言检测、导入 Grep 模式、模块解析算法、排除列表。
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root
# 步骤 1:检测主要语言
tech_stack = Read(docs/project/tech_stack.md) IF exists
ELSE detect from file extensions: Glob("**/*.py", "**/*.ts", "**/*.cs", "**/*.java", root=scan_root)
# 步骤 2:按语言提取导入
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
# 步骤 3:仅过滤内部导入(根据 import_patterns.md 排除列表)
internal_imports = filter_internal(imports, scan_root)
# 步骤 4:解析到模块
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)
hex-graph 加速: 对于拥有 .hex-skills/codegraph/index.db 的项目,使用 find_cycles 进行即时循环检测。当图不可用时,回退到基于 grep 的 DFS。
根据 Robert C. Martin(Clean Architecture 第 14 章):“组件依赖图中不允许出现循环。”
# 成对循环(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)
})
# 第 2 层:仅测试依赖(devDependencies,测试导入)→ 跳过循环
# 具有文档化双向设计的插件/扩展架构 → 降级为 LOW
# 通过 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: # 跳过成对循环(已检测)
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, [])
# 文件夹级循环(基于 dependency-cruiser 模式)
folder_graph = collapse_to_folders(graph)
Repeat DFS on folder_graph for folder-level cycles
打破循环的建议(来自 Clean Architecture 第 14 章):
# 从阶段 1 的发现中加载规则
# rules = {forbidden: [], allowed: [], required: []}
# 检查 FORBIDDEN 规则
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 意味着仅跨组违规
boundary_violations.append({
rule_type: "forbidden",
from: source,
to: target,
file: get_import_location(source, target),
severity: rule.severity,
reason: rule.reason
})
# 检查 ALLOWED 规则(白名单模式)
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"
})
# 检查 REQUIRED 规则
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
})
hex-graph 加速: 对于拥有 .hex-skills/codegraph/index.db 的项目,使用 get_module_metrics 进行即时 Ca/Ce/I 计算。当图不可用时,回退到手动计算。
必读: 加载 references/graph_metrics.md — 使用指标定义、每层阈值、SDP 算法、Lakos 公式。
# 每模块指标(Robert C. Martin)
FOR EACH module IN graph:
Ce = len(graph[module]) # 传出耦合:出向
Ca = count(m for m in graph if module in graph[m]) # 传入耦合:入向
I = Ce / (Ca + Ce) IF (Ca + Ce) > 0 ELSE 0 # 不稳定性
metrics[module] = {Ca, Ce, I}
# SDP 验证(稳定依赖原则)
FOR EACH edge (A -> B) IN graph:
IF metrics[A].I < metrics[B].I:
# 稳定模块依赖于较不稳定的模块 — SDP 违规
sdp_violations.append({
from: A, to: B,
I_from: metrics[A].I, I_to: metrics[B].I,
severity: "HIGH"
})
# 阈值检查(根据 graph_metrics.md,考虑检测到的层)
FOR EACH module IN metrics:
layer = get_layer(module) # 来自阶段 1 的发现
thresholds = get_thresholds(layer) # 来自 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 聚合指标
CCD = 0
FOR EACH module IN graph:
DependsOn = count_transitive_deps(module, graph) + 1 # 包括自身
CCD += DependsOn
N = len(graph)
CCD_balanced = N * log2(N) # 具有 N 个节点的平衡二叉树的 CCD
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/**),将模块级图扩展到函数级。查找每个公共函数的最长副作用链(标记基于 shared/references/ai_ready_architecture.md)。如果 chain_length >= 3:添加到 cascade_findings。在阶段 8 的 DATA-EXTENDED JSON 中输出 "runtime_cascades" 数组。严重性:HIGH(4+),MEDIUM(3)。
灵感来自 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
# 仅将 NEW 违规报告为发现项
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:
# 首次运行 — 报告所有
active_findings = all_violations
baseline_info = {new: len(all_violations), resolved: 0, frozen: 0}
# 建议:输出提示 "Run with update_baseline=true to freeze current violations"
必读: 加载 shared/references/audit_worker_core_contract.md 和 shared/references/audit_scoring.md。
penalty = (critical * 2.0) + (high * 1.0) + (medium * 0.5) + (low * 0.2)
score = max(0, 10 - penalty)
注意: 当基线激活时,惩罚仅根据 active_findings(新违规)计算,而不是冻结的违规。
必读: 加载 shared/references/audit_worker_core_contract.md 和 shared/templates/audit_worker_report_template.md。
# 在内存中构建 markdown 报告,包含:
# - AUDIT-META(基于惩罚的标准:分数、计数)
# - 检查表(cycle_detection, boundary_rules, sdp_validation, metrics_thresholds, baseline_comparison)
# - 发现项表(按严重性排序的活动违规)
# - 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
Report written: docs/project/.audit/ln-640/{YYYY-MM-DD}/644-dep-graph-users.md
Score: 6.5/10 | Issues: 8 (C:1 H:3 M:3 L:1)
必读: 加载 shared/references/audit_worker_core_contract.md。
必读: 加载 shared/references/audit_worker_core_contract.md。
{output_dir}/644-dep-graph[-{domain}].md(原子性单次 Write 调用)references/dependency_rules.mdreferences/graph_metrics.mdreferences/import_patterns.mdshared/references/audit_scoring.mdVersion: 1.0.0 Last Updated: 2026-02-11
每周安装次数
144
代码仓库
GitHub 星标数
245
首次出现
Feb 12, 2026
安全审计
安装于
cursor136
gemini-cli135
codex135
github-copilot135
opencode135
amp133
Paths: File paths (
shared/,references/,../ln-*) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root. Ifshared/is missing, fetch files via WebFetch fromhttps://raw.githubusercontent.com/levnikolaevich/claude-code-skills/master/skills/{path}.
Type: L3 Worker Category: 6XX Audit
L3 Worker that builds and analyzes the module dependency graph to enforce architectural boundaries.
Out of Scope (owned by other workers):
- architecture_path: string # Path to docs/architecture.md
- codebase_root: string # Root directory to scan
- output_dir: string # e.g., "docs/project/.audit/ln-640/{YYYY-MM-DD}"
# 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
When domain_mode="domain-aware": Use scan_path instead of codebase_root for all Grep/Glob operations. Tag all findings with domain field.
MANDATORY READ: Load shared/references/two_layer_detection.md for detection methodology.
MANDATORY READ: Load references/dependency_rules.md — use 3-Tier Priority Chain, Architecture Presets, Auto-Detection Heuristics.
Architecture detection uses 3-tier priority — explicit config wins over docs, docs win over auto-detection:
# 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
MANDATORY READ: Load references/import_patterns.md — use Language Detection, Import Grep Patterns, Module Resolution Algorithm, Exclusion Lists.
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)
hex-graph acceleration: For projects with .hex-skills/codegraph/index.db, use find_cycles for instant cycle detection. Fall back to grep-based DFS when graph is unavailable.
Per Robert C. Martin (Clean Architecture Ch14): "Allow no cycles in the component dependency graph."
# 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
Cycle-breaking recommendations (from Clean Architecture Ch14):
# 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
})
hex-graph acceleration: For projects with .hex-skills/codegraph/index.db, use get_module_metrics for instant Ca/Ce/I calculation. Fall back to manual computation when graph is unavailable.
MANDATORY READ: Load references/graph_metrics.md — use 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)"})
Cascade chain extension: For service files (**/services/**), extend module-level graph to function-level. Find longest side-effect chain per public function (markers per shared/references/ai_ready_architecture.md). If chain_length >= 3: add to cascade_findings. Output "runtime_cascades" array in Phase 8 DATA-EXTENDED JSON. Severity: HIGH (4+), MEDIUM (3).
Inspired by ArchUnit FreezingArchRule — enables incremental adoption in legacy projects.
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"
MANDATORY READ: Load shared/references/audit_worker_core_contract.md and shared/references/audit_scoring.md.
penalty = (critical * 2.0) + (high * 1.0) + (medium * 0.5) + (low * 0.2)
score = max(0, 10 - penalty)
Note: When baseline is active, penalty is calculated from active_findings only (new violations), not frozen ones.
MANDATORY READ: Load shared/references/audit_worker_core_contract.md and shared/templates/audit_worker_report_template.md.
# 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
Report written: docs/project/.audit/ln-640/{YYYY-MM-DD}/644-dep-graph-users.md
Score: 6.5/10 | Issues: 8 (C:1 H:3 M:3 L:1)
MANDATORY READ: Load shared/references/audit_worker_core_contract.md.
MANDATORY READ: Load shared/references/audit_worker_core_contract.md.
{output_dir}/644-dep-graph[-{domain}].md (atomic single Write call)references/dependency_rules.mdreferences/graph_metrics.mdreferences/import_patterns.mdshared/references/audit_scoring.mdVersion: 1.0.0 Last Updated: 2026-02-11
Weekly Installs
144
Repository
GitHub Stars
245
First Seen
Feb 12, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
cursor136
gemini-cli135
codex135
github-copilot135
opencode135
amp133
智能代码探索工具smart-explore:AST解析结构化代码搜索与导航
798 周安装