← Phase 3
D10
Standard: agentskills/agentskills

Day 10: Capstone: Enterprise Unit Test Skill

Capstone Release
🗺️ SECTION 1 / SYSTEM BLUEPRINT & INTEGRATION

The "Where & Why": รวมพลัง Phase 1-3 สู่ Enterprise-Grade Polyglot Capstone Package

🎯 Mental Map (149 Words): ตลอด 9 วันที่ผ่านมา เราสร้างส่วนประกอบย่อยของ Agent Skill มาทีละชิ้นส่วน: Semantic Routing & Invariants (Phase 1), Sandboxed Scripts & AST Extractors (Phase 2), และ References & Dynamic Mining (Phase 3)

ความท้าทายของ Capstone: ชิ้นส่วนที่กระจัดกระจายเหล่านี้ต้องถูกเชื่อมร้อยเป็น Production-Ready Unified Package เดียวกันที่ทำงานประสานกัน 100% โดยไม่มีข้อขัดแย้งของ Interface สัญญาณ หรือขอบเขต Token Budget
เป้าหมายของ Day 10: ประกอบร่าง Polyglot Backend Unit Test Skill (Spring Boot 3.x / Kotlin / Coroutines / MockK / Maven) ที่สมบูรณ์แบบที่สุด พร้อม Pre-flight Pipeline, Closed-Loop Remediation, Dynamic Slicing และ Zero-Dependency Execution พร้อมส่งมอบสู่ Production จริง
Enterprise Capstone Unified Architectural Topology Capstone v1.0 Production Release
┌──────────────────────────────────────────────────────────────────────────────────┐
│ HOST AGENT INVOCATION (GitHub Copilot / Cursor / Claude Code)                     │
│ Target Task: "Write pure unit tests for SettlementReconciliationService.kt"     │
└────────────────────────────────────────┬─────────────────────────────────────────┘
                                         │
                                         ▼ (Phase 1: Dual-Barrier Semantic Gate)
┌──────────────────────────────────────────────────────────────────────────────────┐
│ 🎯 SKILL.MD FRONTMATTER ROUTER [DAY 1-3]                                         │
│ Match Intent: Similarity > 0.85 • Negative Guard: DB & E2E Pruned               │
└────────────────────────────────────────┬─────────────────────────────────────────┘
                                         │
                                         ▼ (Phase 2 & 3: Pre-flight Dynamic Harvest)
┌──────────────────────────────────────────────────────────────────────────────────┐
│ 🎯 AUTOMATED PRE-FLIGHT PIPELINE                                                 │
│ 1. scripts/extract-target-ast.py  ──► Slices Constructor dependencies & suspend  │
│ 2. scripts/harvest-exemplars.py   ──► Mines Top-1 Golden Test from local repo    │
│ 3. scripts/query-reference.sh     ──► Hydrates canonical DTOs on demand (< 95tok)│
└────────────────────────────────────────┬─────────────────────────────────────────┘
                                         │
                                         ▼ (Code Synthesis with Invariants)
┌──────────────────────────────────────────────────────────────────────────────────┐
│ HOST GENERATES ISOLATED KOTLIN TEST SUITE                                        │
│ AAA Structure • MockK & coEvery • AssertJ • Zero Spring ApplicationContext       │
└────────────────────────────────────────┬─────────────────────────────────────────┘
                                         │
                                         ▼ (Phase 2: Closed-Loop Verification Gate)
┌──────────────────────────────────────────────────────────────────────────────────┐
│ 🎯 SCRIPTS/RUN-UNIT-TESTS.SH                                                     │
│ - Stage 1: Fast-fail AST regex scan (Exit 2 if Mockito / @SpringBootTest)        │
│ - Stage 2: Sandboxed Maven runner with 45s Timeout Guard (Exit 124)              │
│ - Stage 3: Python triage noise reduction to Stderr (Exit 3=Compile, 4=Assert)   │
└────────────────────────────────────────┬─────────────────────────────────────────┘
                                         │
                ┌────────────────────────┴────────────────────────┐
                ▼ (Non-zero Exit Code)                            ▼ (Exit Code 0)
┌──────────────────────────────────────────────┐ ┌─────────────────────────────────┐
│ CLOSED-LOOP REPAIR LOOP (Max 3 Retries)      │ │ 🏆 DELIVER CLEAN ARTIFACT       │
│ Host reads triage stderr & corrects target   │ │ 100% Deterministic Verification │
└──────────────────────────────────────────────┘ └─────────────────────────────────┘
        
PILLAR 01: TOTAL ORCHESTRATION

Cohesive Lifecycle

ร้อยเรียง AST Analysis, Dynamic Exemplar Mining และ Sandbox Execution ให้เป็น Workflow ที่ราบรื่นและเชื่อถือได้ 100%

PILLAR 02: HARDENED GOVERNANCE

Multi-Tier Defense

ผสานทั้ง In-Context RFC 2119 Invariants และ Fast-Fail Bash Regex Linters ป้องกัน Anti-pattern รั่วไหลสู่ Git Repository

PILLAR 03: CONTEXT BUDGET DISCIPLINE

< 1,200 Token Working Footprint

แม้เป็น Enterprise Skill เต็มรูปแบบ แต่วิศวกรรม Slicing รักษาพื้นที่ Context Window ให้เหลือพื้นที่ให้ LLM คิดตรรกะสูงสุด

⚙️ SECTION 2 / ARCHITECTURAL DEEP DIVE

สถาปัตยกรรมระดับ Production: การประสานส่วนประกอบ (Component Cohesion) และ Execution Lifecycle

ในระบบ Enterprise Software ทั่วไป การมี Unit Component ที่ดีไม่ได้รับประกันว่าระบบจะทำงานร่วมกันได้อย่างราบรื่น หากขาด Interface Contract ที่ชัดเจน ในโลกของ Agent Skills การเชื่อมต่อระหว่าง Markdown Instructions, POSIX Shell Scripts, Python Parsers, และ JSON Schemas ต้องมีลำดับการส่งมอบข้อมูล (Handoff Sequence) ที่ชัดเจนและทนทานต่อสภาวะขัดข้อง (Fault-Tolerant)

มิติสถาปัตยกรรม (Architectural Dimension) Casual Prompting (Prompt ทั่วไป) Single Script Runner (รันสคริปต์เดี่ยว) Enterprise Capstone Package (Day 10)
Execution Determinism Probabilistic: หวังว่าจะคอมไพล์ผ่าน ปานกลาง: รันเทสต์ได้แต่ไม่รู้สาเหตุละเอียด 100% Deterministic: ปิดลูป Triage 4 ระดับ
Repository Alignment ต่ำ: ใช้ Standard Libs ทั่วไป ปานกลาง: ต้องเขียนบอกใน Prompt ทุกรอบ สูงสุด: ทำ Dynamic Mining ดึง Custom DSL สด
Constructor Precision เดาสุ่ม (Blind Hallucination) เดาสุ่มจนกว่าคอมไพเลอร์จะด่า แม่นยำตั้งแต่รอบแรกผ่าน AST Inspection
Token Economy แปรปรวน: บวมตามขนาดการแชท พังทลาย: Maven Log 80KB กลืน Context ควบคุมเคร่งครัด: Stderr < 350t, Slice < 250t
The Multi-Phase Handoff Sequence

ลำดับการทำงานที่เชื่อมต่อทุก Component ใน Day 1-9 ถูกจัดเรียงเป็น Three-Phase State Machine:

Phase 1: Intent Routing (Frontmatter) Phase 2: Context Harvesting (AST + Mining + References) Phase 3: Generation & Sandboxed Remediation Loop

หากเกิดความผิดพลาดใน Phase 3 ตัว Agent จะไม่รีสตาร์ทกระบวนการใหม่ทั้งหมด แต่ใช้ Diagnostic Payload ที่ Triage Parser สกัดได้มาทำการแก้ไขเฉพาะจุดแบบ In-place Self-Correction

Zero-Dependency Production Deployment Rule

กฎเหล็กสำหรับ Enterprise Skill ที่ส่งมอบให้กับทีมพัฒนาขนาด 500+ คน:

  • 1. POSIX & Pure Python: สคริปต์ทุกตัวใน scripts/ ต้องรันผ่าน Python 3 Standard Library หรือ Bash ดั้งเดิม ห้ามบังคับ pip install
  • 2. Fail-Safe Temp Cleansing: ใช้คำสั่ง trap ทำลาย log ชั่วคราว ป้องกันปัญหา disk space รั่วไหลบน CI Runner
  • 3. Deterministic Exit Codes: แยกแยะ Environment Error (Exit 1) ออกจาก Invariant Violation (Exit 2) เพื่อความปลอดภัย
🧩 SECTION 3 / END-TO-END CODE BLUEPRINT

Complete Production Artifact: The Enterprise Unit Test Architect

ชุดโครงสร้างแพ็กเกจระดับ Production เต็มรูปแบบตามมาตรฐาน agentskills/agentskills ที่ประกอบร่างทุกส่วนประกอบอย่างสมบูรณ์แบบ

Skill Directory Placement
.github/skills/spring-boot-unit-tester/
├── SKILL.md                          ◄── [CAPSTONE MANIFEST: Fully Integrated Execution Protocol]
├── scripts/
│   ├── run-unit-tests.sh             ◄── Sandbox Execution & Timeout Orchestrator
│   ├── triage-test-failure.py        ◄── Stderr Diagnostic & Noise Stripping Parser
│   ├── extract-target-ast.py         ◄── AST Constructor & Suspend Symbol Extractor
│   ├── harvest-exemplars.py          ◄── Local Repo Golden Test Miner
│   └── query-reference.sh            ◄── On-Demand Heavy Schema Slicer
└── references/
    └── billing-domain-contracts.json ◄── Canonical DTO Fixture Schemas
        
FILE: .github/skills/spring-boot-unit-tester/SKILL.md Production Standard v1.0.0
---
name: spring-boot-unit-tester
schema-version: "1.0.0"
description: >
  Generates and refactors isolated JVM unit tests for Kotlin and Spring Boot 3.x 
  using JUnit 5, MockK, AssertJ, and Coroutines Test.
  
  USE WHEN:
  - Authoring unit tests for @Service, @Component, or Domain Logic classes.
  - Mocking suspend functions using MockK (`coEvery { ... }`, `runTest`).
  - Diagnosing failed Maven unit test runs.
  
  DO NOT USE WHEN:
  - Testing database interactions requiring Testcontainers, Postgres, or H2.
  - Writing integration tests annotated with @SpringBootTest or @DataJpaTest.
  - Writing frontend or end-to-end Cypress/Playwright tests.
tools:
  - name: extract-target-ast
    description: Extracts concise AST skeleton (constructor dependencies and suspend methods) from target source file.
    file: scripts/extract-target-ast.py
  - name: harvest-exemplars
    description: Dynamically harvests idiomatic golden unit test exemplars from the local repository.
    file: scripts/harvest-exemplars.py
  - name: query-reference
    description: Queries on-demand domain DTO schemas and fixtures from references/ directory.
    file: scripts/query-reference.sh
  - name: run-unit-tests
    description: Runs sandboxed Maven test execution with automatic stderr triage and timeout guards.
    file: scripts/run-unit-tests.sh
metadata:
  domain: "backend-quality"
  target-framework: "Spring Boot 3.x / Kotlin 1.9+"
---

# Spring Boot Unit Test Architect Specification

## 1. Architectural Invariants (RFC 2119 Mandates)
- **MUST NOT** import `org.mockito.*` or `org.springframework.boot.test.mock.mockito.*`.
- **MUST NOT** annotate test classes with `@SpringBootTest`, `@DataJpaTest`, or `@WebMvcTest`.
- **MUST NOT** use Reflection (`ReflectionTestUtils`). All dependencies MUST be injected via constructor.
- **MUST** execute strictly in-memory (< 50ms per method) without Spring ApplicationContext.
- **MUST** wrap all `suspend` methods inside `kotlinx.coroutines.test.runTest` using `coEvery` and `coVerify`.
- **MUST** follow explicit AAA phases marked with single-line comments: `// Arrange`, `// Act`, `// Assert`.


## 2. Sequential Execution Lifecycle

### Phase 1: Pre-flight Context Harvesting
Before writing any unit test code, the Host Agent MUST execute this sequential pre-flight:
1. **Extract AST Skeleton**: Run `python3 scripts/extract-target-ast.py <TARGET_FILE>` to harvest constructor dependencies.
2. **Mine Repo Exemplar**: Run `python3 scripts/harvest-exemplars.py <TARGET_FILE>` to identify local assertion DSLs.
3. **Query References (Conditional)**: If target uses complex DTOs, query `scripts/query-reference.sh`.

### Phase 2: Test Scaffolding
- Instantiate dependencies using `private val dep = mockk<Dep>()`.
- Implement clean Arrange-Act-Assert testing structure adhering to mined exemplar conventions.

### Phase 3: Sandboxed Verification & Remediation
1. Trigger validation runner: `bash scripts/run-unit-tests.sh <TARGET_TEST_FILE>`.
2. Inspect exit code:
   - **Exit 0**: Complete. Return test code to user.
   - **Exit 2**: Invariant failure. Purge Mockito or Spring runner immediately.
   - **Exit 3**: Compilation error. Parse line number and type mismatch from stderr.
   - **Exit 4**: Assertion error. Adjust mock stubs or expected values.
   - **Exit 124**: Execution timeout. Purge blocking operations or heavy context loaders.
3. Max Retries: Limit autonomous self-correction loop to 3 iterations.
          
FILE: scripts/run-unit-tests.sh POSIX Bash Orchestrator
#!/usr/bin/env bash
# ==============================================================================
# scripts/run-unit-tests.sh
# Standard: agentskills Standard v1.0 (Phase 3 Capstone Release)
# Complete Orchestrator: Fast-Fail Static Linter, 45s Timeout Sandbox & Triage
# ==============================================================================
set -euo pipefail

TARGET_FILE="${1:-}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TRIAGE_SCRIPT="${SCRIPT_DIR}/triage-test-failure.py"
LOG_FILE=$(mktemp /tmp/capstone_mvn.XXXXXX.log)

# Safe Cleanup Hook
trap 'rm -f "${LOG_FILE}"' EXIT

# 1. Parameter Verification
if [[ -z "${TARGET_FILE}" ]] || [[ ! -f "${TARGET_FILE}" ]]; then
    echo "### 🚨 DETERMINISTIC TRIAGE REPORT" >&2
    echo "- **Category**: \`ENVIRONMENT_ERROR\`" >&2
    echo "- **Error**: Target test file '${TARGET_FILE}' does not exist or was not specified." >&2
    exit 1
fi

CLASS_NAME=$(basename "${TARGET_FILE}" .kt)

# 2. Stage 1: Fast-Fail Negative Boundary Gate (< 50ms)
if grep -En "org\.mockito" "${TARGET_FILE}" >&2; then
    echo "### 🚨 DETERMINISTIC TRIAGE REPORT" >&2
    echo "- **Category**: \`STATIC_INVARIANT_VIOLATION\`" >&2
    echo "- **Error**: Forbidden Mockito import detected. Pure unit tests MUST use io.mockk." >&2
    exit 2
fi

if grep -En "@SpringBootTest|@DataJpaTest|@WebMvcTest" "${TARGET_FILE}" >&2; then
    echo "### 🚨 DETERMINISTIC TRIAGE REPORT" >&2
    echo "- **Category**: \`STATIC_INVARIANT_VIOLATION\`" >&2
    echo "- **Error**: Spring ApplicationContext runner detected. Unit tests must execute in pure memory." >&2
    exit 2
fi

# 3. Stage 2: Sandboxed Maven Execution with Timeout Guard (Max 45s)
set +e
timeout 45s mvn test -B --no-transfer-progress -Dtest="${CLASS_NAME}" > "${LOG_FILE}" 2>&1
BUILD_STATUS=$?
set -e

if [[ ${BUILD_STATUS} -eq 124 ]]; then
    echo "### 🚨 DETERMINISTIC TRIAGE REPORT" >&2
    echo "- **Category**: \`EXECUTION_TIMEOUT\`" >&2
    echo "- **Error**: Test execution exceeded 45s limit. Potential deadlock or heavy context initialization." >&2
    exit 124
elif [[ ${BUILD_STATUS} -ne 0 ]]; then
    # Pipeline raw noisy log into Python triage parser and output strictly to stderr
    python3 "${TRIAGE_SCRIPT}" "${LOG_FILE}"
    
    if grep -q "Compilation failure" "${LOG_FILE}"; then
        exit 3
    else
        exit 4
    fi
fi

# 4. Success Path: Clean Structured JSON to stdout, zero stderr
echo "{\"status\": \"SUCCESS\", \"class\": \"${CLASS_NAME}\", \"verified\": true}"
exit 0
          
FILE: scripts/triage-test-failure.py Zero-Dependency Python 3
#!/usr/bin/env python3
"""
scripts/triage-test-failure.py
Extracts compiler and assertion failures from noisy build logs.
Emits a compact diagnostic markdown card strictly to stderr (< 350 tokens).
"""
import sys
import re

def parse_build_diagnostics(raw_log: str) -> dict:
    diagnostics = {
        "category": "BUILD_FAILURE",
        "file": "Unknown",
        "line": "0",
        "message": "Unclassified build or test failure.",
        "root_cause_snippet": []
    }

    lines = raw_log.splitlines()

    kt_pattern = re.compile(r"\[ERROR\]\s+(/.+?\.kt):(\d+):(\d+):\s+error:\s+(.+)")
    mockk_pattern = re.compile(r"io\.mockk\.MockKException:\s+(.+)")
    assert_pattern = re.compile(r"org\.opentest4j\.AssertionFailedError:\s+(.+)")

    for line in lines:
        match_kt = kt_pattern.search(line)
        if match_kt:
            diagnostics["category"] = "COMPILATION_FAILURE"
            diagnostics["file"] = match_kt.group(1).split("/")[-1]
            diagnostics["line"] = match_kt.group(2)
            diagnostics["message"] = match_kt.group(4)
            diagnostics["root_cause_snippet"].append(line.strip())
            return diagnostics

        match_mockk = mockk_pattern.search(line)
        if match_mockk:
            diagnostics["category"] = "MOCKK_CONTRACT_VIOLATION"
            diagnostics["message"] = match_mockk.group(1)
            diagnostics["root_cause_snippet"].append(line.strip())
            return diagnostics

        match_assert = assert_pattern.search(line)
        if match_assert:
            diagnostics["category"] = "ASSERTION_FAILURE"
            diagnostics["message"] = match_assert.group(1)
            diagnostics["root_cause_snippet"].append(line.strip())
            return diagnostics

    error_tail = [l.strip() for l in lines if "[ERROR]" in l][-3:]
    if error_tail:
        diagnostics["root_cause_snippet"] = error_tail

    return diagnostics

def format_agent_card(diag: dict) -> str:
    return f"""### 🚨 DETERMINISTIC TRIAGE REPORT
- **Category**: `{diag['category']}`
- **Location**: `{diag['file']}:{diag['line']}`
- **Error**: {diag['message']}
- **Action Required**: Resolve the violation indicated above and re-execute runner.
```text
{chr(10).join(diag['root_cause_snippet'][:3])}
```"""

def main():
    raw_input = open(sys.argv[1], "r", encoding="utf-8", errors="ignore").read() if len(sys.argv) > 1 else sys.stdin.read()
    diag = parse_build_diagnostics(raw_input)
    sys.stderr.write(format_agent_card(diag) + "\n")

if __name__ == "__main__":
    main()
          
🛠️ SECTION 4 / HANDS-ON SCENARIO & LAB

Capstone Enterprise Incident: The Triple-Failure Settlement Engine Refactor

สถานการณ์จริงระดับ Mission-Critical: ทีมวิศวกรรมการเงินมอบหมายให้ AI สร้าง Unit Test ให้กับ SettlementReconciliationService.kt คลาสนี้มี 3 Constructor Dependencies, เมธอดหลักเป็น suspend fun, รับ Nested Billing DTO ที่มี 40 ฟิลด์, และทีมมี Custom Assertion DSL ชื่อ assertThatSettlement(result).isFullyReconciled()

⚠️ CAPSTONE CHALLENGE OBJECTIVES
  1. Pre-flight Phase: สั่งรัน extract-target-ast.py เพื่อดึง Constructor Dependencies และ harvest-exemplars.py เพื่อดึง Custom Assertion จากคลาสพี่น้อง
  2. On-Demand Reference: สั่งรัน query-reference.sh เพื่อสกัด Schema ของ SettlementInstruction โดยไม่ทำให้ Context Window บวม
  3. Verification & Triage: รัน run-unit-tests.sh เพื่อยืนยันว่าการทดสอบรันผ่านบน JVM Isolated Heap จริง (Exit Code 0) โดยไม่โหลด Spring ApplicationContext
GOLDEN ARTIFACT: src/test/kotlin/.../SettlementReconciliationServiceTest.kt 100% Pass@1 Deterministic Code
package com.enterprise.trading.settlement

import com.enterprise.testing.assertions.assertThatSettlement
import io.mockk.*
import kotlinx.coroutines.test.runTest
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import java.util.UUID

class SettlementReconciliationServiceTest {

    // 1. Dependencies harvested via extract-target-ast.py
    private val clearingClient: ClearingGatewayClient = mockk()
    private val ledgerRepo: SettlementLedgerRepository = mockk()
    private val auditLogger: FinancialAuditLogger = mockk(relaxed = true)

    private val service = SettlementReconciliationService(
        clearingClient = clearingClient,
        ledgerRepo = ledgerRepo,
        auditLogger = auditLogger
    )

    @AfterEach
    fun tearDown() {
        confirmVerified(clearingClient, ledgerRepo)
    }

    @Test
    fun `should successfully reconcile settlement batch and emit completed state`() = runTest {
        // Arrange: Fixture created using on-demand schema from query-reference.sh
        val instructionId = UUID.randomUUID()
        val instruction = SettlementInstruction(
            instructionId = instructionId.toString(),
            accountNumber = "ACC-9988221100",
            settlementAmount = BigDecimal("1250000.50"),
            currency = "USD",
            clearingRail = "SWIFT"
        )
        
        coEvery { clearingClient.verifyClearing(instructionId) } returns ClearingStatus.CLEARED
        coEvery { ledgerRepo.updateReconciliationStatus(instructionId, any()) } returns true

        // Act
        val result = service.reconcile(instruction)

        // Assert: Adheres to team Custom DSL mined via harvest-exemplars.py
        assertThatSettlement(result).isFullyReconciled()
        
        coVerify(exactly = 1) { clearingClient.verifyClearing(instructionId) }
        coVerify(exactly = 1) { ledgerRepo.updateReconciliationStatus(instructionId, "RECONCILED") }
    }
}
        
TERMINAL PROOF: Capstone Execution & Verification Execution Output
$ bash .github/skills/spring-boot-unit-tester/scripts/run-unit-tests.sh src/test/kotlin/com/enterprise/trading/settlement/SettlementReconciliationServiceTest.kt
{"status": "SUCCESS", "class": "SettlementReconciliationServiceTest", "verified": true}

$ echo $?
0
        
🎯 SECTION 5 / INTERACTIVE ARCHITECTURE & CAPSTONE QUIZ

ทดสอบสถาปัตยกรรม Enterprise Capstone Skill (Day 10)

Current Score
0 / 12

ตอบคำถามเชิงสถาปัตยกรรมระดับ Capstone ทั้ง 12 ข้อด้านล่าง ระบบจะตรวจคำตอบและให้ Feedback ทันทีเมื่อคลิกเลือกช้อยส์ พร้อมแสดงคำอธิบายเชิงลึก