ln-646-project-structure-auditor
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePaths: File paths (,shared/,references/) are relative to skills repo root. If not found at CWD, locate this SKILL.md directory and go up one level for repo root.../ln-*
路径: 文件路径(、shared/、references/)均相对于技能仓库根目录。如果在当前工作目录未找到,请定位到该SKILL.md文件所在目录,向上返回一级即为仓库根目录。../ln-*
Project Structure Auditor
项目结构审计器
L3 Worker that audits the physical directory structure of a project against framework-specific conventions and hygiene best practices.
L3 Worker,用于对照框架专属约定和健康度最佳实践,审计项目的物理目录结构。
Purpose & Scope
目的与适用范围
- Auto-detect tech stack and apply framework-specific structure rules
- Audit 5 dimensions: file hygiene, ignore files, framework conventions, domain/layer organization, naming
- Detect project rot: leftover artifacts, inconsistent naming, junk drawer directories
- Complement ln-642 (code-level layer analysis) with physical structure analysis
- Score and report findings per standard formula
audit_scoring.md - Output: file-based report to
{output_dir}/646-structure[-{domain}].md
Out of Scope (owned by other workers):
- Code-level layer boundary violations (import analysis) -> ln-642-layer-boundary-auditor
- Platform artifact cleanup (removal) -> ln-724-artifact-cleaner
- Structure migration (creation/movement of directories) -> ln-720-structure-migrator
- Dependency vulnerability scanning -> ln-625-dependencies-auditor
- 自动检测技术栈并应用对应框架的结构规则
- 从5个维度进行审计:文件健康度、忽略文件、框架约定、领域/层级组织、命名
- 检测项目腐化:遗留产物、命名不一致、垃圾目录
- 补充ln-642(代码级层级分析)的物理结构分析能力
- 按照标准公式对发现的问题进行评分并生成报告
audit_scoring.md - 输出:基于文件的报告,存储到
{output_dir}/646-structure[-{domain}].md
不适用范围(由其他Worker负责):
- 代码级层级边界违规(导入分析)→ ln-642-layer-boundary-auditor
- 平台产物清理(移除操作)→ ln-724-artifact-cleaner
- 结构迁移(目录创建/移动)→ ln-720-structure-migrator
- 依赖漏洞扫描 → ln-625-dependencies-auditor
Input (from ln-640)
输入(来自ln-640)
- codebase_root: string # Root directory to scan
- output_dir: string # e.g., "docs/project/.audit/ln-640/{YYYY-MM-DD}"- 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-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)
undefined- 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)
undefinedWorkflow
工作流
MANDATORY READ: Load for detection methodology.
shared/references/two_layer_detection.md必读: 加载了解检测方法论。
shared/references/two_layer_detection.mdPhase 1: Detect Tech Stack
阶段1:检测技术栈
MANDATORY READ: Load -- use Detection Algorithm, Frontend Detection, Backend Detection, Structure Detection.
../ln-700-project-bootstrap/references/stack_detection.mdscan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root必读: 加载——使用其中的检测算法、前端检测、后端检测、结构检测规则。
../ln-700-project-bootstrap/references/stack_detection.mdscan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_rootPriority 1: Read docs/project/tech_stack.md if exists
Priority 1: Read docs/project/tech_stack.md if exists
IF exists(docs/project/tech_stack.md):
tech_stack = parse(tech_stack.md)
IF exists(docs/project/tech_stack.md):
tech_stack = parse(tech_stack.md)
Priority 2: Auto-detect from project files
Priority 2: Auto-detect from project files
ELSE:
Check package.json -> React/Vue/Angular/Express/NestJS
Check .csproj/.sln -> .NET
Check pyproject.toml/requirements.txt -> Python/FastAPI/Django
Check go.mod -> Go
Check Cargo.toml -> Rust
Check pnpm-workspace.yaml/turbo.json -> Monorepo
tech_stack = {
language: "typescript" | "python" | "csharp" | "go" | ...,
framework: "react" | "fastapi" | "aspnetcore" | ...,
structure: "monolith" | "clean-architecture" | "monorepo" | ...
}
undefinedELSE:
Check package.json -> React/Vue/Angular/Express/NestJS
Check .csproj/.sln -> .NET
Check pyproject.toml/requirements.txt -> Python/FastAPI/Django
Check go.mod -> Go
Check Cargo.toml -> Rust
Check pnpm-workspace.yaml/turbo.json -> Monorepo
tech_stack = {
language: "typescript" | "python" | "csharp" | "go" | ...,
framework: "react" | "fastapi" | "aspnetcore" | ...,
structure: "monolith" | "clean-architecture" | "monorepo" | ...
}
undefinedPhase 2: File Hygiene Audit
阶段2:文件健康度审计
MANDATORY READ: Load -- use "File Hygiene Rules" section. Also reference: (Platform Detection Matrix, Generic Prototype Artifacts).
references/structure_rules.md../ln-724-artifact-cleaner/references/platform_artifacts.mdundefined必读: 加载——使用“文件健康度规则”章节。同时参考:(平台检测矩阵、通用原型产物)。
references/structure_rules.md../ln-724-artifact-cleaner/references/platform_artifacts.mdundefinedCheck 2.1: Build artifacts tracked in git
Check 2.1: Build artifacts tracked in git
FOR EACH artifact_dir IN structure_rules.build_artifact_dirs:
IF Glob("{scan_root}/**/{artifact_dir}"):
findings.append(severity: "HIGH", issue: "Build artifact directory in repo",
location: path, recommendation: "Add to .gitignore, remove from tracking")
FOR EACH artifact_dir IN structure_rules.build_artifact_dirs:
IF Glob("{scan_root}/**/{artifact_dir}"):
findings.append(severity: "HIGH", issue: "Build artifact directory in repo",
location: path, recommendation: "Add to .gitignore, remove from tracking")
Check 2.2: Temp/log files
Check 2.2: Temp/log files
FOR EACH pattern IN structure_rules.temp_junk_patterns:
IF Glob("{scan_root}/**/{pattern}"):
findings.append(severity: "MEDIUM", ...)
FOR EACH pattern IN structure_rules.temp_junk_patterns:
IF Glob("{scan_root}/**/{pattern}"):
findings.append(severity: "MEDIUM", ...)
Check 2.3: Platform remnants (from platform_artifacts.md)
Check 2.3: Platform remnants (from platform_artifacts.md)
FOR EACH platform IN [Replit, StackBlitz, CodeSandbox, Glitch]:
IF platform indicator files found:
findings.append(severity: "MEDIUM", issue: "Platform remnant: {file}",
principle: "File Hygiene / Platform Artifacts")
FOR EACH platform IN [Replit, StackBlitz, CodeSandbox, Glitch]:
IF platform indicator files found:
findings.append(severity: "MEDIUM", issue: "Platform remnant: {file}",
principle: "File Hygiene / Platform Artifacts")
Check 2.4: Multiple lock files
Check 2.4: Multiple lock files
lock_files = Glob("{scan_root}/{package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb}")
IF len(lock_files) > 1:
findings.append(severity: "HIGH", issue: "Multiple lock files: {lock_files}",
recommendation: "Keep one lock file matching your package manager")
lock_files = Glob("{scan_root}/{package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb}")
IF len(lock_files) > 1:
findings.append(severity: "HIGH", issue: "Multiple lock files: {lock_files}",
recommendation: "Keep one lock file matching your package manager")
Check 2.5: .env files committed
Check 2.5: .env files committed
env_files = Glob("{scan_root}//.env") + Glob("{scan_root}//.env.local")
- Glob("{scan_root}/**/.env.*.local") IF len(env_files) > 0: findings.append(severity: "CRITICAL", issue: ".env file(s) committed", recommendation: "Remove from tracking, add to .gitignore")
env_files = Glob("{scan_root}//.env") + Glob("{scan_root}//.env.local")
- Glob("{scan_root}/**/.env.*.local") IF len(env_files) > 0: findings.append(severity: "CRITICAL", issue: ".env file(s) committed", recommendation: "Remove from tracking, add to .gitignore")
Check 2.6: Large binaries tracked by git
Check 2.6: Large binaries tracked by git
FOR EACH file IN Glob("{scan_root}/**/*.{zip,tar,gz,rar,exe,dll,so,dylib,jar,war}"):
findings.append(severity: "MEDIUM", issue: "Binary file tracked: {file}",
recommendation: "Use Git LFS or remove from repository")
undefinedFOR EACH file IN Glob("{scan_root}/**/*.{zip,tar,gz,rar,exe,dll,so,dylib,jar,war}"):
findings.append(severity: "MEDIUM", issue: "Binary file tracked: {file}",
recommendation: "Use Git LFS or remove from repository")
undefinedPhase 3: Ignore File Quality
阶段3:忽略文件质量审计
MANDATORY READ: Load -- use "Ignore File Rules" section. Also reference: (secrets baseline), (dockerignore baseline).
references/structure_rules.md../ln-733-env-configurator/references/gitignore_secrets.template../ln-731-docker-generator/references/dockerignore.templateundefined必读: 加载——使用“忽略文件规则”章节。同时参考:(密钥基线)、(dockerignore基线)。
references/structure_rules.md../ln-733-env-configurator/references/gitignore_secrets.template../ln-731-docker-generator/references/dockerignore.templateundefinedCheck 3.1: .gitignore exists
Check 3.1: .gitignore exists
IF NOT exists(.gitignore):
findings.append(severity: "HIGH", issue: "No .gitignore file")
ELSE:
content = Read(.gitignore)
Check 3.1a: Stack-specific entries present
required_entries = get_required_gitignore(tech_stack)
FOR EACH entry IN required_entries:
IF entry NOT covered in .gitignore:
findings.append(severity: "MEDIUM", issue: ".gitignore missing: {entry}")
Check 3.1b: Secrets protection (compare with gitignore_secrets.template)
secrets_patterns = [".env", ".env.local", ".pem", ".key", "secrets/"]
FOR EACH pattern IN secrets_patterns:
IF pattern NOT in .gitignore:
findings.append(severity: "HIGH", issue: ".gitignore missing secrets: {pattern}",
principle: "Ignore Files / Secrets")
Check 3.1c: IDE/OS entries
ide_patterns = [".vscode/", ".idea/", "*.swp", ".DS_Store", "Thumbs.db"]
missing_ide = [p for p in ide_patterns if p NOT covered in .gitignore]
IF len(missing_ide) > 2:
findings.append(severity: "LOW", issue: ".gitignore missing IDE/OS: {missing_ide}")
IF NOT exists(.gitignore):
findings.append(severity: "HIGH", issue: "No .gitignore file")
ELSE:
content = Read(.gitignore)
Check 3.1a: Stack-specific entries present
required_entries = get_required_gitignore(tech_stack)
FOR EACH entry IN required_entries:
IF entry NOT covered in .gitignore:
findings.append(severity: "MEDIUM", issue: ".gitignore missing: {entry}")
Check 3.1b: Secrets protection (compare with gitignore_secrets.template)
secrets_patterns = [".env", ".env.local", ".pem", ".key", "secrets/"]
FOR EACH pattern IN secrets_patterns:
IF pattern NOT in .gitignore:
findings.append(severity: "HIGH", issue: ".gitignore missing secrets: {pattern}",
principle: "Ignore Files / Secrets")
Check 3.1c: IDE/OS entries
ide_patterns = [".vscode/", ".idea/", "*.swp", ".DS_Store", "Thumbs.db"]
missing_ide = [p for p in ide_patterns if p NOT covered in .gitignore]
IF len(missing_ide) > 2:
findings.append(severity: "LOW", issue: ".gitignore missing IDE/OS: {missing_ide}")
Check 3.2: .dockerignore
Check 3.2: .dockerignore
IF exists(Dockerfile) AND NOT exists(.dockerignore):
findings.append(severity: "MEDIUM", issue: "Dockerfile exists but no .dockerignore",
recommendation: "Create .dockerignore to reduce build context")
ELIF exists(.dockerignore):
FOR EACH required IN [node_modules, .git, .env, "*.log"]:
IF required NOT in .dockerignore:
findings.append(severity: "LOW", ...)
undefinedIF exists(Dockerfile) AND NOT exists(.dockerignore):
findings.append(severity: "MEDIUM", issue: "Dockerfile exists but no .dockerignore",
recommendation: "Create .dockerignore to reduce build context")
ELIF exists(.dockerignore):
FOR EACH required IN [node_modules, .git, .env, "*.log"]:
IF required NOT in .dockerignore:
findings.append(severity: "LOW", ...)
undefinedPhase 4: Framework Convention Compliance
阶段4:框架约定合规性检查
MANDATORY READ: Load -- use framework-specific section matching detected tech_stack.
references/structure_rules.mdrules = get_framework_rules(tech_stack, structure_rules.md)必读: 加载——使用与检测到的tech_stack匹配的框架专属章节。
references/structure_rules.mdrules = get_framework_rules(tech_stack, structure_rules.md)Returns: {expected_dirs, forbidden_placements, co_location_rules}
Returns: {expected_dirs, forbidden_placements, co_location_rules}
Check 4.1: Expected directories exist
Check 4.1: Expected directories exist
FOR EACH dir IN rules.expected_dirs WHERE dir.required == true:
IF NOT exists(dir.path):
findings.append(severity: "MEDIUM", issue: "Expected directory missing: {dir.path}",
principle: "Framework Convention / {tech_stack.framework}")
FOR EACH dir IN rules.expected_dirs WHERE dir.required == true:
IF NOT exists(dir.path):
findings.append(severity: "MEDIUM", issue: "Expected directory missing: {dir.path}",
principle: "Framework Convention / {tech_stack.framework}")
Check 4.2: Source code in wrong locations
Check 4.2: Source code in wrong locations
FOR EACH rule IN rules.forbidden_placements:
matches = Glob(rule.glob_pattern, scan_root)
FOR EACH match IN matches:
IF match NOT IN rules.exceptions:
findings.append(severity: "HIGH", issue: "Source file in wrong location: {match}",
recommendation: "Move to {rule.expected_location}")
FOR EACH rule IN rules.forbidden_placements:
matches = Glob(rule.glob_pattern, scan_root)
FOR EACH match IN matches:
IF match NOT IN rules.exceptions:
findings.append(severity: "HIGH", issue: "Source file in wrong location: {match}",
recommendation: "Move to {rule.expected_location}")
Check 4.3: Co-location rules (React feature folders)
Check 4.3: Co-location rules (React feature folders)
IF tech_stack.framework IN ["react", "vue", "angular", "svelte"]:
component_dirs = Glob("{scan_root}/**/components//")
colocation_count = 0
FOR EACH dir IN component_dirs:
has_test = Glob("{dir}/.{test,spec}.{ts,tsx,js,jsx}")
IF has_test: colocation_count += 1
Only flag if project already uses co-location (>50%)
IF colocation_count > len(component_dirs) * 0.5:
FOR EACH dir IN component_dirs:
IF NOT has_test_for(dir):
findings.append(severity: "LOW", issue: "Component missing co-located test: {dir}")
undefinedIF tech_stack.framework IN ["react", "vue", "angular", "svelte"]:
component_dirs = Glob("{scan_root}/**/components//")
colocation_count = 0
FOR EACH dir IN component_dirs:
has_test = Glob("{dir}/.{test,spec}.{ts,tsx,js,jsx}")
IF has_test: colocation_count += 1
Only flag if project already uses co-location (>50%)
IF colocation_count > len(component_dirs) * 0.5:
FOR EACH dir IN component_dirs:
IF NOT has_test_for(dir):
findings.append(severity: "LOW", issue: "Component missing co-located test: {dir}")
undefinedPhase 5: Domain/Layer Organization
阶段5:领域/层级组织检查
undefinedundefinedCheck 5.1: Junk drawer detection
Check 5.1: Junk drawer detection
junk_thresholds = structure_rules.junk_drawer_thresholds
FOR EACH dir IN Glob("{scan_root}/**/"):
dir_name = basename(dir)
IF dir_name IN junk_thresholds:
file_count = len(Glob("{dir}/."))
IF file_count > junk_thresholds[dir_name].max_files:
findings.append(severity: junk_thresholds[dir_name].severity,
issue: "Junk drawer directory: {dir} ({file_count} files)",
principle: "Organization / Module Cohesion",
recommendation: "Split into domain-specific modules or feature folders")
junk_thresholds = structure_rules.junk_drawer_thresholds
FOR EACH dir IN Glob("{scan_root}/**/"):
dir_name = basename(dir)
IF dir_name IN junk_thresholds:
file_count = len(Glob("{dir}/."))
IF file_count > junk_thresholds[dir_name].max_files:
findings.append(severity: junk_thresholds[dir_name].severity,
issue: "Junk drawer directory: {dir} ({file_count} files)",
principle: "Organization / Module Cohesion",
recommendation: "Split into domain-specific modules or feature folders")
Check 5.2: Root directory cleanliness
Check 5.2: Root directory cleanliness
root_files = Glob("{scan_root}/*") # Direct children only
source_in_root = [f for f in root_files
if f.ext IN source_extensions AND basename(f) NOT IN allowed_root_files]
IF len(source_in_root) > 0:
findings.append(severity: "MEDIUM", issue: "Source files in project root: {source_in_root}",
recommendation: "Move to src/ or appropriate module directory")
config_in_root = [f for f in root_files if is_config_file(f)]
IF len(config_in_root) > 15:
findings.append(severity: "LOW",
issue: "Excessive config files in root ({len(config_in_root)})",
recommendation: "Move non-essential configs to config/ directory")
root_files = Glob("{scan_root}/*") # Direct children only
source_in_root = [f for f in root_files
if f.ext IN source_extensions AND basename(f) NOT IN allowed_root_files]
IF len(source_in_root) > 0:
findings.append(severity: "MEDIUM", issue: "Source files in project root: {source_in_root}",
recommendation: "Move to src/ or appropriate module directory")
config_in_root = [f for f in root_files if is_config_file(f)]
IF len(config_in_root) > 15:
findings.append(severity: "LOW",
issue: "Excessive config files in root ({len(config_in_root)})",
recommendation: "Move non-essential configs to config/ directory")
Check 5.3: Consistent module structure across domains
Check 5.3: Consistent module structure across domains
IF domain_mode == "global" AND len(detect_domains(scan_root)) >= 2:
domains = detect_domains(scan_root)
structures = {d.name: set(subdirectory_names(d.path)) for d in domains}
all_subdirs = union(structures.values())
FOR EACH domain IN domains:
missing = all_subdirs - structures[domain]
IF 0 < len(missing) < len(all_subdirs) * 0.5:
findings.append(severity: "LOW",
issue: "Inconsistent domain structure: {domain.name} missing {missing}",
recommendation: "Align domain module structures for consistency")
undefinedIF domain_mode == "global" AND len(detect_domains(scan_root)) >= 2:
domains = detect_domains(scan_root)
structures = {d.name: set(subdirectory_names(d.path)) for d in domains}
all_subdirs = union(structures.values())
FOR EACH domain IN domains:
missing = all_subdirs - structures[domain]
IF 0 < len(missing) < len(all_subdirs) * 0.5:
findings.append(severity: "LOW",
issue: "Inconsistent domain structure: {domain.name} missing {missing}",
recommendation: "Align domain module structures for consistency")
undefinedPhase 6: Naming Conventions
阶段6:命名规范检查
MANDATORY READ: Load -- use "Naming Convention Rules" section.
references/structure_rules.mdnaming_rules = get_naming_rules(tech_stack)必读: 加载——使用“命名规范规则”章节。
references/structure_rules.mdnaming_rules = get_naming_rules(tech_stack)Returns: {file_case, dir_case, test_pattern, component_case}
Returns: {file_case, dir_case, test_pattern, component_case}
Check 6.1: File naming consistency
Check 6.1: File naming consistency
violations = []
FOR EACH file IN Glob("{scan_root}/**/*.{ts,tsx,js,jsx,py,cs,go}"):
expected_case = naming_rules.file_case
IF is_component(file) AND NOT matches_case(basename(file), expected_case):
violations.append(file)
IF len(violations) > 0:
pct = len(violations) / total_source_files * 100
severity = "HIGH" if pct > 30 else "MEDIUM" if pct > 10 else "LOW"
findings.append(severity, issue: "Naming violations: {len(violations)} files ({pct}%)",
principle: "Naming / {naming_rules.file_case}")
violations = []
FOR EACH file IN Glob("{scan_root}/**/*.{ts,tsx,js,jsx,py,cs,go}"):
expected_case = naming_rules.file_case
IF is_component(file) AND NOT matches_case(basename(file), expected_case):
violations.append(file)
IF len(violations) > 0:
pct = len(violations) / total_source_files * 100
severity = "HIGH" if pct > 30 else "MEDIUM" if pct > 10 else "LOW"
findings.append(severity, issue: "Naming violations: {len(violations)} files ({pct}%)",
principle: "Naming / {naming_rules.file_case}")
Check 6.2: Directory naming consistency
Check 6.2: Directory naming consistency
dirs = get_all_source_dirs(scan_root)
dir_cases = classify_cases(dirs) # Count per case style
dominant = max(dir_cases)
inconsistent = [d for d in dirs if case_of(d) != dominant]
IF len(inconsistent) > 0:
findings.append(severity: "LOW",
issue: "Inconsistent directory naming: {len(inconsistent)} dirs use mixed case")
dirs = get_all_source_dirs(scan_root)
dir_cases = classify_cases(dirs) # Count per case style
dominant = max(dir_cases)
inconsistent = [d for d in dirs if case_of(d) != dominant]
IF len(inconsistent) > 0:
findings.append(severity: "LOW",
issue: "Inconsistent directory naming: {len(inconsistent)} dirs use mixed case")
Check 6.3: Test file naming pattern
Check 6.3: Test file naming pattern
test_files = Glob("{scan_root}/**/*.{test,spec}.{ts,tsx,js,jsx}")
- Glob("{scan_root}/**/*_test.{py,go}") IF len(test_files) > 0: patterns_used = detect_test_patterns(test_files) # .test. vs .spec. vs _test IF len(patterns_used) > 1: findings.append(severity: "LOW", issue: "Mixed test naming patterns: {patterns_used}", recommendation: "Standardize to {dominant_test_pattern}")
undefinedtest_files = Glob("{scan_root}/**/*.{test,spec}.{ts,tsx,js,jsx}")
- Glob("{scan_root}/**/*_test.{py,go}") IF len(test_files) > 0: patterns_used = detect_test_patterns(test_files) # .test. vs .spec. vs _test IF len(patterns_used) > 1: findings.append(severity: "LOW", issue: "Mixed test naming patterns: {patterns_used}", recommendation: "Standardize to {dominant_test_pattern}")
undefinedPhase 7: Score + Report + Return
阶段7:评分 + 生成报告 + 返回结果
MANDATORY READ: Load for scoring formula. Load for file format.
shared/references/audit_scoring.mdshared/templates/audit_worker_report_template.mdundefined必读: 加载了解评分公式。加载了解文件格式。
shared/references/audit_scoring.mdshared/templates/audit_worker_report_template.mdundefined7a: Calculate Score
7a: Calculate Score
penalty = (critical * 2.0) + (high * 1.0) + (medium * 0.5) + (low * 0.2)
score = max(0, 10 - penalty)
penalty = (critical * 2.0) + (high * 1.0) + (medium * 0.5) + (low * 0.2)
score = max(0, 10 - penalty)
7b: Build Report in Memory
7b: Build Report in Memory
report = """
report = """
Project Structure Audit Report
Project Structure Audit Report
<!-- AUDIT-META
worker: ln-646
category: Project Structure
domain: {domain_name|global}
scan_path: {scan_path|.}
score: {score}
total_issues: {total}
critical: {critical}
high: {high}
medium: {medium}
low: {low}
status: complete
-->
<!-- AUDIT-META
worker: ln-646
category: Project Structure
domain: {domain_name|global}
scan_path: {scan_path|.}
score: {score}
total_issues: {total}
critical: {critical}
high: {high}
medium: {medium}
low: {low}
status: complete
-->
Checks
Checks
| ID | Check | Status | Details |
|---|---|---|---|
| file_hygiene | File Hygiene | {status} | Build artifacts, temp files, env files, binaries |
| ignore_files | Ignore File Quality | {status} | .gitignore completeness, secrets, .dockerignore |
| framework_conventions | Framework Conventions | {status} | {framework} structure compliance |
| domain_organization | Domain/Layer Organization | {status} | Junk drawers, root cleanliness, consistency |
| naming_conventions | Naming Conventions | {status} | File/dir/test naming patterns |
| ID | Check | Status | Details |
|---|---|---|---|
| file_hygiene | File Hygiene | {status} | Build artifacts, temp files, env files, binaries |
| ignore_files | Ignore File Quality | {status} | .gitignore completeness, secrets, .dockerignore |
| framework_conventions | Framework Conventions | {status} | {framework} structure compliance |
| domain_organization | Domain/Layer Organization | {status} | Junk drawers, root cleanliness, consistency |
| naming_conventions | Naming Conventions | {status} | File/dir/test naming patterns |
Findings
Findings
| Severity | Location | Issue | Principle | Recommendation | Effort |
|---|---|---|---|---|---|
| {sorted by severity: CRITICAL first, then HIGH, MEDIUM, LOW} |
"""
| Severity | Location | Issue | Principle | Recommendation | Effort |
|---|---|---|---|---|---|
| {sorted by severity: CRITICAL first, then HIGH, MEDIUM, LOW} |
"""
7c: Write Report (atomic single Write call)
7c: Write Report (atomic single Write call)
IF domain_mode == "domain-aware":
Write to {output_dir}/646-structure-{current_domain}.md
ELSE:
Write to {output_dir}/646-structure.md
IF domain_mode == "domain-aware":
Write to {output_dir}/646-structure-{current_domain}.md
ELSE:
Write to {output_dir}/646-structure.md
7d: Return Summary
7d: Return Summary
Report written: docs/project/.audit/ln-640/{YYYY-MM-DD}/646-structure[-{domain}].md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
undefinedReport written: docs/project/.audit/ln-640/{YYYY-MM-DD}/646-structure[-{domain}].md
Score: X.X/10 | Issues: N (C:N H:N M:N L:N)
undefinedScoring
评分规则
Uses standard penalty formula from :
shared/references/audit_scoring.mdpenalty = (critical x 2.0) + (high x 1.0) + (medium x 0.5) + (low x 0.2)
score = max(0, 10 - penalty)Severity mapping:
- CRITICAL: .env files committed (security risk). Exception: .env.example / .env.template with default values → skip CRITICAL
- HIGH: Build artifacts tracked, missing .gitignore, source in wrong location, multiple lock files, missing secrets in .gitignore. Exception: Build artifacts in Git LFS → skip
- MEDIUM: Missing framework dirs, junk drawers, temp files, platform remnants, missing stack-specific gitignore entries, naming violations >10%
- LOW: IDE/OS patterns missing, inconsistent dir naming, mixed test patterns, minor config issues
使用中的标准惩罚公式:
shared/references/audit_scoring.mdpenalty = (critical x 2.0) + (high x 1.0) + (medium x 0.5) + (low x 0.2)
score = max(0, 10 - penalty)严重等级映射:
- CRITICAL: 已提交.env文件(安全风险)。例外情况: 包含默认值的.env.example / .env.template → 不标记CRITICAL
- HIGH: 跟踪了构建产物、缺少.gitignore文件、源代码位置错误、存在多个锁文件、.gitignore缺少密钥规则。例外情况: 存储在Git LFS中的构建产物 → 不标记
- MEDIUM: 缺少框架要求的目录、垃圾目录、临时文件、平台遗留文件、.gitignore缺少技术栈专属条目、命名违规率>10%
- LOW: 缺少IDE/操作系统相关忽略规则、目录命名不一致、测试文件命名模式混合、轻微配置问题
Critical Rules
核心规则
- Auto-detect, never assume: Always detect tech stack before applying framework rules
- No false positives on conventions: Apply framework rules ONLY for detected stack
- Security-first: .env files committed = CRITICAL, missing secrets in .gitignore = HIGH
- Complement, not overlap: Do NOT check import-level layer violations (owned by ln-642)
- Report only, never modify: Never move/delete files (owned by ln-720/ln-724)
- Reuse platform detection: Reference ln-724 patterns for platform remnants
- Co-location awareness: Only flag missing co-location if project already uses the pattern (>50%)
- Evidence always: Include file paths for every finding
- 自动检测,绝不假设: 应用框架规则前必须先检测技术栈
- 约定检查无假阳性: 仅对检测到的技术栈应用对应框架规则
- 安全优先: 提交.env文件=CRITICAL,.gitignore缺少密钥规则=HIGH
- 功能互补,不重叠: 不检查导入层级的边界违规(由ln-642负责)
- 仅生成报告,不修改内容: 绝不移动/删除文件(由ln-720/ln-724负责)
- 复用平台检测逻辑: 参考ln-724的平台遗留文件规则
- 就近存放感知: 仅当项目已普遍使用就近存放模式(>50%)时,才标记缺失的就近存放测试
- 所有发现必有证据: 每个问题都要包含对应的文件路径
Definition of Done
完成定义
- Tech stack detected (from or auto-detection)
docs/project/tech_stack.md - File hygiene checked: build artifacts, temp files, platform remnants, lock files, .env, binaries
- Ignore files audited: .gitignore completeness, secrets protection, .dockerignore if Dockerfile present
- Framework conventions applied: expected dirs, forbidden placements, co-location rules
- Domain/layer organization checked: junk drawers, root cleanliness, cross-domain consistency
- Naming conventions validated: file/dir/test naming patterns
- If domain-aware: all Glob scoped to , findings tagged with domain
scan_path - Score calculated per
audit_scoring.md - Report written to (atomic single Write call)
{output_dir}/646-structure[-{domain}].md - Summary returned to coordinator
- 已检测技术栈(从读取或自动检测)
docs/project/tech_stack.md - 已检查文件健康度:构建产物、临时文件、平台遗留文件、锁文件、.env、二进制文件
- 已审计忽略文件:.gitignore完整性、密钥保护、存在Dockerfile时检查.dockerignore
- 已应用框架约定:预期目录存在、无违规放置、就近存放规则
- 已检查领域/层级组织:垃圾目录、根目录整洁度、跨域一致性
- 已验证命名规范:文件/目录/测试文件命名模式
- 如果是领域感知模式:所有Glob范围限定在内,所有问题标记所属领域
scan_path - 已按照计算得分
audit_scoring.md - 已将报告写入(原子化单次写入调用)
{output_dir}/646-structure[-{domain}].md - 已向协调器返回摘要信息
Reference Files
参考文件
- Worker report template:
shared/templates/audit_worker_report_template.md - Scoring algorithm:
shared/references/audit_scoring.md - Structure rules:
references/structure_rules.md - Stack detection:
../ln-700-project-bootstrap/references/stack_detection.md - Platform artifacts:
../ln-724-artifact-cleaner/references/platform_artifacts.md - Gitignore secrets:
../ln-733-env-configurator/references/gitignore_secrets.template - Dockerignore baseline:
../ln-731-docker-generator/references/dockerignore.template
Version: 1.0.0
Last Updated: 2026-02-28
- Worker报告模板:
shared/templates/audit_worker_report_template.md - 评分算法:
shared/references/audit_scoring.md - 结构规则:
references/structure_rules.md - 技术栈检测:
../ln-700-project-bootstrap/references/stack_detection.md - 平台产物:
../ln-724-artifact-cleaner/references/platform_artifacts.md - Gitignore密钥规则:
../ln-733-env-configurator/references/gitignore_secrets.template - Dockerignore基线:
../ln-731-docker-generator/references/dockerignore.template
版本: 1.0.0
最后更新: 2026-02-28