ln-646-project-structure-auditor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
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.
路径: 文件路径(
shared/
references/
../ln-*
)均相对于技能仓库根目录。如果在当前工作目录未找到,请定位到该SKILL.md文件所在目录,向上返回一级即为仓库根目录。

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
    audit_scoring.md
    formula
  • 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)
undefined

Workflow

工作流

MANDATORY READ: Load
shared/references/two_layer_detection.md
for detection methodology.
必读: 加载
shared/references/two_layer_detection.md
了解检测方法论。

Phase 1: Detect Tech Stack

阶段1:检测技术栈

MANDATORY READ: Load
../ln-700-project-bootstrap/references/stack_detection.md
-- use Detection Algorithm, Frontend Detection, Backend Detection, Structure Detection.
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root
必读: 加载
../ln-700-project-bootstrap/references/stack_detection.md
——使用其中的检测算法、前端检测、后端检测、结构检测规则。
scan_root = scan_path IF domain_mode == "domain-aware" ELSE codebase_root

Priority 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" | ... }
undefined
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" | ... }
undefined

Phase 2: File Hygiene Audit

阶段2:文件健康度审计

MANDATORY READ: Load
references/structure_rules.md
-- use "File Hygiene Rules" section. Also reference:
../ln-724-artifact-cleaner/references/platform_artifacts.md
(Platform Detection Matrix, Generic Prototype Artifacts).
undefined
必读: 加载
references/structure_rules.md
——使用“文件健康度规则”章节。同时参考:
../ln-724-artifact-cleaner/references/platform_artifacts.md
(平台检测矩阵、通用原型产物)。
undefined

Check 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")
undefined
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")
undefined

Phase 3: Ignore File Quality

阶段3:忽略文件质量审计

MANDATORY READ: Load
references/structure_rules.md
-- use "Ignore File Rules" section. Also reference:
../ln-733-env-configurator/references/gitignore_secrets.template
(secrets baseline),
../ln-731-docker-generator/references/dockerignore.template
(dockerignore baseline).
undefined
必读: 加载
references/structure_rules.md
——使用“忽略文件规则”章节。同时参考:
../ln-733-env-configurator/references/gitignore_secrets.template
(密钥基线)、
../ln-731-docker-generator/references/dockerignore.template
(dockerignore基线)。
undefined

Check 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", ...)
undefined
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", ...)
undefined

Phase 4: Framework Convention Compliance

阶段4:框架约定合规性检查

MANDATORY READ: Load
references/structure_rules.md
-- use framework-specific section matching detected tech_stack.
rules = get_framework_rules(tech_stack, structure_rules.md)
必读: 加载
references/structure_rules.md
——使用与检测到的tech_stack匹配的框架专属章节。
rules = 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}")
undefined
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}")
undefined

Phase 5: Domain/Layer Organization

阶段5:领域/层级组织检查

undefined
undefined

Check 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")
undefined
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")
undefined

Phase 6: Naming Conventions

阶段6:命名规范检查

MANDATORY READ: Load
references/structure_rules.md
-- use "Naming Convention Rules" section.
naming_rules = get_naming_rules(tech_stack)
必读: 加载
references/structure_rules.md
——使用“命名规范规则”章节。
naming_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}")
undefined
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}")
undefined

Phase 7: Score + Report + Return

阶段7:评分 + 生成报告 + 返回结果

MANDATORY READ: Load
shared/references/audit_scoring.md
for scoring formula. Load
shared/templates/audit_worker_report_template.md
for file format.
undefined
必读: 加载
shared/references/audit_scoring.md
了解评分公式。加载
shared/templates/audit_worker_report_template.md
了解文件格式。
undefined

7a: 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

IDCheckStatusDetails
file_hygieneFile Hygiene{status}Build artifacts, temp files, env files, binaries
ignore_filesIgnore File Quality{status}.gitignore completeness, secrets, .dockerignore
framework_conventionsFramework Conventions{status}{framework} structure compliance
domain_organizationDomain/Layer Organization{status}Junk drawers, root cleanliness, consistency
naming_conventionsNaming Conventions{status}File/dir/test naming patterns
IDCheckStatusDetails
file_hygieneFile Hygiene{status}Build artifacts, temp files, env files, binaries
ignore_filesIgnore File Quality{status}.gitignore completeness, secrets, .dockerignore
framework_conventionsFramework Conventions{status}{framework} structure compliance
domain_organizationDomain/Layer Organization{status}Junk drawers, root cleanliness, consistency
naming_conventionsNaming Conventions{status}File/dir/test naming patterns

Findings

Findings

SeverityLocationIssuePrincipleRecommendationEffort
{sorted by severity: CRITICAL first, then HIGH, MEDIUM, LOW}
<!-- DATA-EXTENDED { "tech_stack": {"language": "...", "framework": "...", "structure": "..."}, "dimensions": { "file_hygiene": {"checks": 6, "issues": N}, "ignore_files": {"checks": 4, "issues": N}, "framework_conventions": {"checks": 3, "issues": N}, "domain_organization": {"checks": 3, "issues": N}, "naming_conventions": {"checks": 3, "issues": N} }, "junk_drawers": [{"path": "src/utils", "file_count": 23}], "naming_dominant_case": "PascalCase", "naming_violations_pct": 5 } -->
"""
SeverityLocationIssuePrincipleRecommendationEffort
{sorted by severity: CRITICAL first, then HIGH, MEDIUM, LOW}
<!-- DATA-EXTENDED { "tech_stack": {"language": "...", "framework": "...", "structure": "..."}, "dimensions": { "file_hygiene": {"checks": 6, "issues": N}, "ignore_files": {"checks": 4, "issues": N}, "framework_conventions": {"checks": 3, "issues": N}, "domain_organization": {"checks": 3, "issues": N}, "naming_conventions": {"checks": 3, "issues": N} }, "junk_drawers": [{"path": "src/utils", "file_count": 23}], "naming_dominant_case": "PascalCase", "naming_violations_pct": 5 } -->
"""

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)
undefined
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)
undefined

Scoring

评分规则

Uses standard penalty formula from
shared/references/audit_scoring.md
:
penalty = (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.md
中的标准惩罚公式:
penalty = (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
    docs/project/tech_stack.md
    or auto-detection)
  • 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
    scan_path
    , findings tagged with domain
  • Score calculated per
    audit_scoring.md
  • Report written to
    {output_dir}/646-structure[-{domain}].md
    (atomic single Write call)
  • 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