← Phase 2 Phase 2 • Week 2 Delivery

Local SE Agent Masterclass

MacBook M3 16GB • Architecture Review Skill
📍 ส่วนที่ 1: หมุดตั้งโจทย์ & วัตถุประสงค์หลัก (Title Connection)

Chapter 26 — Building an Advanced Architecture Review Skill

ทำไมต้องชื่อนี้และเรียนไปเพื่ออะไร?

ใน Day 25 เราได้สร้าง pr_synthesizer เพื่อวิเคราะห์ Blast Radius และประกอบร่าง PR Description แต่ในกระบวนการส่งมอบระดับ Enterprise โค้ดที่ "เทสผ่าน" และ "รู้ขอบเขตผลกระทบ" ยังไม่เพียงพอ หากโค้ดนั้นละเมิดสถาปัตยกรรม (Architectural Violation), ทิ้ง Code Smells, หรือเปิดช่องโหว่ด้านความปลอดภัย (Security Vulnerabilities)

วัตถุประสงค์ของ Day 26: พัฒนา Skill Cartridge ตัวที่สามชื่อ architecture_reviewer เพื่อทำหน้าที่เป็น Automated Architecture Gatekeeper — 1) ตรวจสอบการละเมิดกฎ Clean Architecture / Layered Dependency โดยใช้ Call Graph + AST Import Analysis, 2) สแกนหา Security Antipatterns & Smells, 3) ส่งออกรายงาน Architectural Conformance Report พร้อมข้อเสนอแนะเชิงโครงสร้าง เพื่อยับยั้งการ Merge โค้ดที่สร้าง Technical Debt

✓ Day 25: PR Synthesis & Impact Day 26: Architecture Review Skill 🏛 Day 27: End-to-End Simulation
📂 ส่วนที่ 2: ผังโครงสร้างโปรเจกต์จริง & ตำแหน่งไฟล์ (Project File Structure)

โครงสร้างโปรเจกต์สำหรับ Day 26 โดยเพิ่มตลับสกิล skills/architecture_reviewer/ เข้าสู่ Skill Registry ตามมาตรฐาน Two-Stage Progressive Disclosure:

se_agent/
├── requirements.txt                          # tree-sitter, networkx, chromadb, rich
├── config.json                                # Model config & system parameters
├── main.py                                    # Entrypoint CLI
├── test_arch_review.py                    # [ไฟล์ใหม่ Day 26] สคริปต์ Integration Test ตรวจจับ Architectural Violations
├── skills/
│   ├── registry.py                           # Dynamic Skill Auto-Discovery & Mutex Policy
│   ├── lifecycle.py                          # Skill Context Injection Manager
│   ├── unit_test_synthesizer/               # Skill Cartridge #1 (Day 17)
│   ├── pr_synthesizer/                       # Skill Cartridge #2 (Day 25)
│   └── architecture_reviewer/              # [โฟลเดอร์ใหม่ Day 26] Skill Cartridge #3
│       ├── metadata.json                     # Stage 1 Card: Triggers, Cost, และ Tools
│       ├── instructions.md                   # Stage 2 Spec: Layered Boundaries, Smell Taxonomy
│       └── tools.py                          # สแกน Boundary Violations และ Security Smells
├── intelligence/
│   ├── ast_parser.py                        # AST Skeleton & Import Parser (Tree-sitter)
│   ├── call_graph.py                        # Call Hierarchy Directed Graph (NetworkX)
│   └── hybrid_retriever.py                  # RRF Dual Retrieval Engine
└── workspace/
    ├── sandbox_manager.py                  # Git Worktree Sandbox
    └── verification_engine.py              # Automated Verification Loop
📍 skills/architecture_reviewer/metadata.json

สารบัญย่อ (Stage 1) โหลดเข้า Context Window เพื่อดักจับ Intent เช่น "ตรวจ architecture", "check clean architecture", "code smells", "security audit"

📍 skills/architecture_reviewer/instructions.md

กฎเกณฑ์เชิงโครงสร้าง (Stage 2) กำหนดนิยาม Dependency Rules (Domain → Service → Controller/Infra) และเกณฑ์ Severity (BLOCKER, CRITICAL, WARNING)

📍 skills/architecture_reviewer/tools.py

Logic ตรวจจับการฝ่าฝืนเลเยอร์จาก Import Statement / AST Node และตรวจจับ Regex Patterns ของความเสี่ยงด้านความปลอดภัย

📍 test_arch_review.py

Integration Test จำลองการเขียนโค้ดที่ผิดสถาปัตยกรรม (เช่น Domain Entity แอบ import Repository/DB Driver) แล้วทดสอบว่า Skill จับได้แม่นยำหรือไม่

🏛 ส่วนที่ 3: สถาปัตยกรรม Architecture Conformance Engine (Mental Model)
แผนผังกระบวนการตรวจสถาปัตยกรรมและ Security Smells
               ┌────────────────────────────────────────────────────────┐
               │              Target Codebase in Sandbox                │
               │            (Source Files & Git Diff Scope)             │
               └──────────────────────────┬─────────────────────────────┘
                                          │
                   ┌──────────────────────┴──────────────────────┐
                   │                                             │
                   ▼                                             ▼
┌──────────────────────────────────────┐     ┌──────────────────────────────────────┐
│  AST Import & Call Site Extraction   │     │      Security & Smell Scanner        │
│  - สกัด package, imports, type refs  │     │  - Secret Leaks (AWS, JWT, Tokens)  │
│  - ตรวจ Dependency Direction         │     │  - Insecure DB Queries / Logging     │
└──────────────────┬───────────────────┘     └──────────────────┬───────────────────┘
                   │                                             │
                   │ Layer Violations                            │ Vulnerability Findings
                   └──────────────────────┬──────────────────────┘
                                          │
                                          ▼
               ┌────────────────────────────────────────────────────────┐
               │          Architecture Conformance Engine               │
               │   แมป Layer Boundary: Domain -> Service -> Infra       │
               │   จัดกลุ่ม Severity: BLOCKER | CRITICAL | WARNING       │
               └──────────────────────────┬─────────────────────────────┘
                                          │
                                          ▼
               ┌────────────────────────────────────────────────────────┐
               │             Synthesis (qwen2.5-coder:7b)               │
               │     สรุปผลพร้อมแนวทาง Refactor (Clean Code Advice)     │
               └────────────────────────────────────────────────────────┘
💻 ส่วนที่ 4: ซอร์สโค้ดจริง & คำอธิบายทีละบรรทัด (Line-by-Line Implementation)

คลิกเลือกดูซอร์สโค้ดของแต่ละไฟล์ที่ต้องสร้างขึ้นในวันนี้:

{
  "name": "architecture_reviewer",
  "version": "1.0.0",
  "description": "Reviews codebase against Clean Architecture rules, detects layer boundary violations, circular dependencies, and security code smells.",
  "triggers": [
    "review architecture",
    "architecture check",
    "clean architecture",
    "code smell",
    "security audit",
    "check boundaries"
  ],
  "required_tools": [
    "verify_layer_dependencies",
    "scan_security_smells",
    "generate_architecture_report"
  ]
}
# Architecture Reviewer - Enterprise Operational Guidelines

## Role & Mission
คุณทำหน้าที่เป็น Principal Software Architect และ Security Lead ทำหน้าที่บังคับใช้มาตรฐานโครงสร้างซอฟต์แวร์ (Architectural Governance) และความปลอดภัยของซอร์สโค้ด

## Layer Dependency Invariant (Clean Architecture)
กฎทิศทางการอ้างอิงที่ห้ามละเมิดโดยเด็ดขาด:
1. **Core Domain (`domain/**`)**:
   - ต้องเป็น Pure Business Logic
   - **ห้าม** Import หรือมี Dependency ใดๆ ไปยัง Controller, Web, Infrastructure, หรือ Database Libraries (เช่น Spring Data, JPA, JDBC) โดยตรง
2. **Application / Service Layer (`service/**`, `usecase/**`)**:
   - อ้างอิง Domain ได้
   - สื่อสารกับ Infrastructure ผ่าน Interface/Port เท่านั้น
3. **Infrastructure / Controller Layer (`controller/**`, `infra/**`)**:
   - อยู่รอบนอกสุด สามารถ Import เลเยอร์ภายในได้ แต่เลเยอร์ภายในห้ามเรียกกลับ (Inversion of Control)

## Violation Severity Matrix
- **BLOCKER**: มีการรั่วไหลของ Secret/Credential, SQL Injection, หรือ Circular Dependency ระหว่างโมดูล
- **CRITICAL**: Layer Boundary Inversion (เช่น Domain Model อ้างอิง Infrastructure Repository โดยตรง)
- **WARNING**: God Class (>500 lines), Method parameter ล้นหลาม (>5 params), Missing interface abstractions
import re
from pathlib import Path
from typing import Dict, List, Any

# กฎทิศทางต้องห้าม (Source Layer Pattern -> Banned Target Pattern)
BOUNDARY_RULES = [
    {
        "source": r".*/domain/.*",
        "banned": [r".*\.controller\..*", r".*\.infra\..*", r".*\.repository\..*", r"java\.sql\..*"],
        "reason": "Domain entity must not depend on external layers, controllers, or database drivers."
    },
    {
        "source": r".*/service/.*",
        "banned": [r".*\.controller\..*"],
        "reason": "Application services must not have upward dependencies to presentation/controller layers."
    }
]

# กฎตรวจจับ Security Smells เบื้องต้น
SECURITY_PATTERNS = [
    (r"(?i)(api[_-]?key|secret|password|bearer)\s*=\s*['\"][A-Za-z0-9_\\-]{8,}['\"]", "Hardcoded Credentials Detected", "BLOCKER"),
    (r"SELECT\s+.*\s+FROM\s+.*\s*\+\s*[a-zA-Z0-9_]+", "Possible Dynamic SQL String Concatenation (SQLi Risk)", "BLOCKER"),
    (r"System\.out\.print", "Production Code using stdout instead of Structured Logger", "WARNING")
]

def verify_layer_dependencies(files_with_imports: Dict[str, List[str]]) -> List[Dict[str, str]]:
    """
    ตรวจสอบว่าแต่ละไฟล์มีการ import ฝ่าฝืน Layer Boundary หรือไม่
    files_with_imports: { "src/domain/Order.java": ["com.app.infra.OrderRepository", "java.util.List"] }
    """
    violations = []
    for filepath, imports in files_with_imports.items():
        for rule in BOUNDARY_RULES:
            if re.match(rule["source"], filepath):
                for imp in imports:
                    for banned_pattern in rule["banned"]:
                        if re.match(banned_pattern, imp):
                            violations.append({
                                "file": filepath,
                                "violating_import": imp,
                                "reason": rule["reason"],
                                "severity": "CRITICAL"
                            })
    return violations

def scan_security_smells(file_contents: Dict[str, str]) -> List[Dict[str, str]]:
    """สแกนหาข้อบกพร่องด้านความปลอดภัยและ Code Smells ในเนื้อไฟล์"""
    findings = []
    for filepath, content in file_contents.items():
        lines = content.splitlines()
        for idx, line in enumerate(lines, 1):
            for pattern, desc, severity in SECURITY_PATTERNS:
                if re.search(pattern, line):
                    findings.append({
                        "file": filepath,
                        "line": idx,
                        "finding": desc,
                        "severity": severity,
                        "snippet": line.strip()
                    })
    return findings

def generate_architecture_report(violations: List[Dict[str, str]], smells: List[Dict[str, str]]) -> str:
    """รวบรวมข้อค้นพบทั้งหมดเป็นรายงาน Markdown เชิงวิศวกรรม"""
    status = "PASSED" if not violations and not any(s["severity"] == "BLOCKER" for s in smells) else "FAILED"

    violation_lines = []
    for v in violations:
        violation_lines.append(f"- **[{v['severity']}]** `{v['file']}`: Imports forbidden `{v['violating_import']}`\n  *Rationale: {v['reason']}*")
    violations_block = "\n".join(violation_lines) if violation_lines else "- No layer boundary violations found."

    smell_lines = []
    for s in smells:
        smell_lines.append(f"- **[{s['severity']}]** `{s['file']}:{s['line']}`: {s['finding']}\n  `{s['snippet']}`")
    smells_block = "\n".join(smell_lines) if smell_lines else "- No security risks or code smells detected."

    return f"""# Architecture & Quality Conformance Report

**Gate Status**: `[{status}]`

### 1. Layer Boundary Violations
{violations_block}

### 2. Security Findings & Code Smells
{smells_block}

### 3. Recommendation & Next Steps
{"- Clean up layer inversions and remove critical smells prior to merging." if status == "FAILED" else "- Code architecture adheres to enterprise clean architecture standards. Approved."}
"""
from skills.architecture_reviewer.tools import (
    verify_layer_dependencies,
    scan_security_smells,
    generate_architecture_report
)

def test_architecture_review_pipeline():
    print("=== Testing Day 26: Advanced Architecture Review Skill ===")

    # 1. จำลองโค้ดที่มีทั้งการละเมิด Layer และ Security Smells
    mock_files_imports = {
        "src/main/java/com/domain/Order.java": [
            "java.util.UUID",
            "com.app.infra.OrderRepository"  # ละเมิด: Domain แอบ import Infra
        ],
        "src/main/java/com/service/PaymentService.java": [
            "com.domain.Order",
            "java.util.List"
        ]
    }

    mock_file_contents = {
        "src/main/java/com/domain/Order.java": """
package com.domain;
import com.app.infra.OrderRepository;

public class Order {
    private String apiKey = "secret_ak_live_994829104812"; // BLOCKER: Hardcoded secret
    public void save() {
        System.out.println("Saving order..."); // WARNING: stdout
    }
}
"""
    }

    # 2. ทำการตรวจสอบ Boundary และ Code Smells
    violations = verify_layer_dependencies(mock_files_imports)
    smells = scan_security_smells(mock_file_contents)

    # 3. ตรวจสอบ Assertions
    assert len(violations) == 1
    assert violations[0]["severity"] == "CRITICAL"
    assert "OrderRepository" in violations[0]["violating_import"]

    blocker_smells = [s for s in smells if s["severity"] == "BLOCKER"]
    assert len(blocker_smells) == 1
    assert "Hardcoded Credentials" in blocker_smells[0]["finding"]

    # 4. สังเคราะห์รายงาน Architecture Conformance
    report = generate_architecture_report(violations, smells)
    print("\n--- Architecture Conformance Report Preview ---")
    print(report)

    assert "[FAILED]" in report
    print("\nVerification Successful: Architecture Review Skill correctly flagged violations!")

if __name__ == "__main__":
    test_architecture_review_pipeline()
⚡ ส่วนที่ 5: ปฏิบัติการจริงบน Terminal Mac M3 (Step-by-Step Lab)

เปิด Terminal บน MacBook M3 แล้วทำตามขั้นตอนเพื่อติดตั้งและทดสอบ Architecture Reviewer:

ขั้นตอนที่ 1: สร้างโฟลเดอร์สำหรับตลับสกิลใหม่
mkdir -p skills/architecture_reviewer
ขั้นตอนที่ 2: วางโค้ดลงในแต่ละไฟล์

- นำโค้ดใน ส่วนที่ 4 (metadata.json, instructions.md, tools.py) ไปวางภายใต้ skills/architecture_reviewer/
- นำโค้ดใน ส่วนที่ 4 (test_arch_review.py) ไปวางที่ root ของโปรเจกต์

ขั้นตอนที่ 3: สั่งรันการทดสอบผ่าน Python Environment
python test_arch_review.py

ผลลัพธ์ที่คาดหวัง: ตรวจจับ com.app.infra.OrderRepository ใน Domain เป็น CRITICAL, Hardcoded secret เป็น BLOCKER, และสรุป Gate Status เป็น [FAILED]

📝 ส่วนที่ 6: ชุดควิซประเมินความรู้ระดับสถาปนิก (ตอบปุ๊บรู้ผลทันที)

ข้อที่ 1: ทำไมการให้ Domain Model อ้างอิง Infrastructure หรือ DB Drivers โดยตรงจึงถือเป็นข้อผิดพลาดร้ายแรง (CRITICAL)?

ข้อที่ 2: ในสถาปัตยกรรม Multi-Skill Agent ของเรา อะไรเป็นตัวป้องกันไม่ให้ architecture_reviewer และ unit_test_synthesizer ตีกันใน Context Window?

🏁 สรุปหมุดเชื่อมโยง (Chapter Wrap-up)

เนื้อหาใน Day 26 — Building an Advanced Architecture Review Skill เติมตลับสกิล architecture_reviewer เป็น Gatekeeper ก่อน Merge: จับ Layer Violation, Security Smell และสรุปเป็นรายงาน Conformance พร้อมก้าวต่อไปยัง Day 27: End-to-End Enterprise Simulation