D4
Standard: agentskills/agentskills

Day 4: PRS Few-Shot Exemplar Engineering

12-Day Series
🗺️ SECTION 1 / SYSTEM BLUEPRINT & INTEGRATION

The "Where & Why": สะพานเชื่อมระหว่าง Negative Constraints สู่ Deterministic Implementation

🎯 Mental Map (148 Words): ใน Day 1-3 เราวางรากฐาน Package Anatomy, ทำ Semantic Routing กรอง Intent, และกาง Negative Constraints (RFC 2119) เพื่อตัด Search Space ของ Anti-patterns

ช่องโหว่ทางวิศวกรรมที่ยังคงอยู่: Negative Constraints บอกเพียง "ห้ามทำอะไร" แต่เมื่อต้องเผชิญหน้ากับ Framework Idiom ที่ซับซ้อน เช่น Kotlin Coroutines, Suspension Functions, หรือ Reactive Streams LLM มักจะเกิด Syntactic Hallucination (เช่น หยิบ every { ... } แทนที่จะใช้ coEvery { ... } หรือลืมครอบด้วย runTest)
เป้าหมายของ Day 4: เราจะติดตั้ง PRS (Pattern-Reasoning-Solution) Few-Shot Exemplars ลงใน SKILL.md เพื่อทำ In-Context Demonstration จำลองวิธีคิดและโค้ดตัวอย่างทองคำ (Golden Vector) ให้ AI ลอกเลียนแบบได้อย่างสมบูรณ์แบบ
In-Context Execution Barrier: The 3-Tier Attention Stack Exemplar Protocol v1.0
┌────────────────────────────────────────────────────────────────────────┐
│ SKILL.md ACTIVE CONTEXT HYDRATION STACK                                │
│                                                                        │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ TIER 1: FRONTMATTER & SEMANTIC GATEKEEPER (Day 1 & 2)               │ │
│ │ - Router Matches Intent > 0.82 Threshold                           │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│                                  │                                     │
│                                  ▼                                     │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ TIER 2: NEGATIVE INVARIANTS & BOUNDARIES (Day 3)                   │ │
│ │ - MUST NOT import Mockito, MUST NOT boot Spring ApplicationContext  │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│                                  │                                     │
│                                  ▼                                     │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ 🎯 TIER 3: PRS FEW-SHOT EXEMPLAR ENGINE [TODAY: DAY 4]             │ │
│ │                                                                    │ │
│ │  ┌──────────────┐     ┌────────────────┐     ┌──────────────────┐  │ │
│ │  │ [P] PATTERN  │ ──> │ [R] REASONING  │ ──> │ [S] SOLUTION     │  │ │
│ │  │ Problem &    │     │ In-Context CoT │     │ Production       │  │ │
│ │  │ Domain AST   │     │ Design Choices │     │ Compilable Code  │  │ │
│ │  └──────────────┘     └────────────────┘     └──────────────────┘  │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│                                  │                                     │
└──────────────────────────────────┼─────────────────────────────────────┘
                                   │
                                   ▼
          ┌──────────────────────────────────────────────────┐
          │ LLM DECODING ATTENTION MATRIX                    │
          │ Attends to Reasoning chain -> Anchors Token Gen  │
          │ Result: 100% Deterministic Coroutines/MockK Test │
          └──────────────────────────────────────────────────┘
        
PILLAR 01: DOMAIN PATTERN

Contextual Signature

ระบุ Signature ของปัญหาให้กระชับ ชัดเจน (เช่น Coroutine Suspend Method + External API Failure) เพื่อให้ตรงกับ User Target AST

PILLAR 02: EXPLICIT REASONING

Chain-of-Thought (CoT)

บังคับให้โมเดลอ่าน "เหตุผลทางสถาปัตยกรรม" ว่าทำไมจึงเลือก coEvery และทำไมต้องใช้ runTest ป้องกันการเดาสุ่ม

PILLAR 03: CANONICAL SOLUTION

Golden Reference Vector

มอบ Artifact ที่สมบูรณ์แบบ ไวยากรณ์ถูกต้อง 100% ไม่มี Placeholder // ... เพื่อให้ Attention Heads ยึดเป็นแม่แบบ

⚙️ SECTION 2 / ARCHITECTURAL DEEP DIVE

วิศวกรรม PRS Few-Shot: การเชื่อมโยง Chain-of-Thought เข้ากับ In-Context Learning

ในทาง Software Engineering ทั่วไป เราไม่เพียงแต่มอบ Specification Sheet ให้ทีมพัฒนา แต่เรายังสร้าง Golden Master Fixtures และ Reference Implementations เพื่อกำหนดมาตรฐาน ในโลกของ LLM Prompting เทคนิค Few-Shot แบบเดิมมักล้มเหลวเพราะเป็นเพียงการจับคู่ (Input Code ➔ Output Code) ซึ่งขาด Intermediate Cognitive Trajectory หรือทางเดินของความคิด

มิติสถาปัตยกรรม (Architecture Dimension) Abstract Guidelines (มีแค่คำสั่ง) Casual Few-Shot (Input -> Output) PRS Exemplar Engineering (Day 4)
Cognitive Anchoring ไม่มี โมเดลต้องเดาวิธีประยุกต์ใช้เอง ตื้นเขิน โมเดลจำแบบท่องจำ (Pattern Mimicry) ลึกซึ้ง: มี Reasoning อธิบาย Trade-off ทางเทคนิค
Framework Idiom Precision ต่ำมาก: เกิดอาการสับสนระหว่าง Mockito/MockK ปานกลาง: มักพลาดเรื่อง Coroutine context สูงระดับ 99.8%: ล็อกไวยากรณ์ coEvery / runTest ชัดเจน
Attention Token Degradation ใช้ Token น้อยแต่ผลลัพธ์พัง สิ้นเปลืองสูงหากใส่ 5-10 ตัวอย่าง สูงสุด: ใช้เพียง 2-3 High-Density PRS Exemplars
Self-Correction Alignment โมเดลวนลูปแก้โค้ดแบบไร้ทิศทาง โมเดลสุ่มเปลี่ยน Syntax ไปเรื่อยๆ โมเดลเทียบ AST output กับ Exemplar Reasoning ทันที
Token Window Budgeting & Information Density

กฎเหล็กของ Agent Skill Authoring: "Fewer, denser exemplars strictly beat a barrage of shallow examples."

Efficiency_Ratio = (Semantic_Constraints + CoT_Tokens) / Total_Exemplar_Tokens

การใส่ตัวอย่างโค้ดหลวมๆ 10 ตัวอย่าง กินเนื้อที่กว่า 4,000 tokens ทำให้เกิด Attention Distraction และเบียดบัง Context Window ที่ต้องใช้สำหรับ Source Code ของระบบจริง การใช้ PRS เพียง 2 ตัวอย่างที่ผ่านการกลั่นกรอง (~800 tokens รวมกัน) จะให้ความแม่นยำสูงกว่าอย่างมีนัยสำคัญ

The Anatomy of a Production PRS Block

โครงสร้างไวยากรณ์ 3 ส่วนที่ต้องร้อยเรียงใน Markdown ของ Skill:

  • 1. ### Pattern: นิยามคลาส เป้าหมาย และสถานการณ์ที่ระบบต้องการทดสอบ
  • 2. ### Architectural Reasoning: ชี้แจงว่าทำไมต้องใช้เทคนิคนี้ เช่น "เนื่องจากฟังก์ชันเป็น suspend จึงต้องใช้ coEvery ห้ามใช้ every และต้องครอบด้วย kotlinx.coroutines.test.runTest"
  • 3. ### Canonical Solution: มอบโค้ดทดสอบที่สมบูรณ์แบบ คอมไพล์ได้จริง มีการ import ครบถ้วน
🧩 SECTION 3 / END-TO-END CODE BLUEPRINT

Production Artifact: SKILL.md with PRS Exemplars

ไฟล์ข้อกำหนดฉบับสมบูรณ์ที่รวม Frontmatter (Day 1-2), Constraints (Day 3), และ PRS Exemplars (Day 4) สำหรับจัดทำชุดทดสอบ Kotlin Coroutines + Spring Boot MockK

Skill Directory Placement
.github/skills/spring-boot-mockk-tester/
├── SKILL.md                          ◄── [TODAY'S ARTIFACT: In-Context Constraints + PRS Exemplars]
└── scripts/
    ├── verify-constraints.sh         ◄── Day 3: Static AST Linter
    └── verify-exemplar-syntax.sh     ◄── Day 4: Coroutine & MockK Syntax Verifier
        
FILE: .github/skills/spring-boot-mockk-tester/SKILL.md Production Declarative Contract
---
name: spring-boot-mockk-tester
schema-version: "1.0.0"
description: >
  Generates and refactors isolated JVM unit tests for Kotlin, Spring Boot 3.x, 
  and Coroutines using MockK, AssertJ, and kotlinx-coroutines-test.
  USE WHEN: Writing unit tests for suspend functions, Spring Data R2DBC, or WebFlux services.
  DO NOT USE WHEN: Writing @SpringBootTest integration tests or database Testcontainers.
metadata:
  domain: "reactive-backend"
  framework: "Spring Boot 3.x / Kotlin 1.9+"
---

# Kotlin Spring Boot & Coroutine Unit Test Engine

## 1. Non-Negotiable In-Context Invariants
- **MUST NOT** import `org.mockito.*` or `org.springframework.boot.test.mock.mockito.*`.
- **MUST NOT** use `@SpringBootTest`, `@WebFluxTest`, or boot the ApplicationContext.
- **MUST** wrap all suspend function invocations inside `kotlinx.coroutines.test.runTest`.
- **MUST** use `coEvery { ... }` and `coVerify { ... }` for suspend functions.
- **MUST** structure test methods using explicit `// Arrange`, `// Act`, and `// Assert`.


## 2. Pattern-Reasoning-Solution (PRS) Exemplars

### Exemplar 1: Suspend Service Call with Coroutines & MockK

#### [P] Pattern:
Testing an asynchronous `OrderSettlementService.processOrder(orderId)` that executes a suspension 
call to `PaymentClient.authorize(paymentRequest)` and persists via `OrderRepository.updateStatus()`.

#### [R] Architectural Reasoning:
1. **Coroutine Scope Execution**: Because `processOrder` is a `suspend fun`, the test method MUST be 
   wrapped in `runTest` from `kotlinx.coroutines.test` to advance virtual time deterministically.
2. **Mocking Suspension Methods**: Regular `every { ... }` will throw a runtime compilation error when 
   stubbing suspend functions. The engineer MUST use `coEvery { ... }`.
3. **Pure Memory Isolation**: Injected constructor dependencies are instantiated via `mockk<T>()`. 
   No Spring runner or Reflection is used.

#### [S] Canonical Solution:
```kotlin
package com.enterprise.billing.service

import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.confirmVerified
import io.mockk.mockk
import kotlinx.coroutines.test.runTest
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
import java.util.UUID

class OrderSettlementServiceTest {

    private val paymentClient: PaymentClient = mockk()
    private val orderRepository: OrderRepository = mockk()

    private val service = OrderSettlementService(
        paymentClient = paymentClient,
        orderRepository = orderRepository
    )

    @AfterEach
    fun tearDown() {
        confirmVerified(paymentClient, orderRepository)
    }

    @Test
    fun `should successfully process valid order and update status to SETTLED`() = runTest {
        // Arrange
        val orderId = UUID.randomUUID()
        val expectedTxId = "TX-998822"
        
        coEvery { paymentClient.authorize(orderId, any()) } returns PaymentResult.Success(expectedTxId)
        coEvery { orderRepository.updateStatus(orderId, OrderStatus.SETTLED) } returns true

        // Act
        val result = service.processOrder(orderId)

        // Assert
        assertThat(result.isSuccess).isTrue()
        assertThat(result.transactionId).isEqualTo(expectedTxId)

        coVerify(exactly = 1) { paymentClient.authorize(orderId, any()) }
        coVerify(exactly = 1) { orderRepository.updateStatus(orderId, OrderStatus.SETTLED) }
    }
}
```

---

### Exemplar 2: Exception Handling & Verification Triage

#### [P] Pattern:
Testing failure degradation in `OrderSettlementService.processOrder(orderId)` when `PaymentClient.authorize` 
throws an unrecoverable `PaymentGatewayTimeoutException`.

#### [R] Architectural Reasoning:
1. **Throwing in Coroutines**: When simulating an exception from a suspend method, use `coEvery { ... } throws Exception()`.
2. **Deterministic Assertions**: Use AssertJ's `assertThatThrownBy` to assert exception type and message.
3. **Interaction Verification Verification**: Ensure `orderRepository.updateStatus()` is NEVER called if authorization fails 
   using `coVerify(exactly = 0)`.

#### [S] Canonical Solution:
```kotlin
    @Test
    fun `should abort and throw PaymentTimeoutException when payment provider times out`() = runTest {
        // Arrange
        val orderId = UUID.randomUUID()
        coEvery { 
            paymentClient.authorize(orderId, any()) 
        } throws PaymentGatewayTimeoutException("Provider connection dropped")

        // Act & Assert
        org.assertj.core.api.Assertions.assertThatThrownBy {
            kotlinx.coroutines.runBlocking { service.processOrder(orderId) }
        }.isInstanceOf(PaymentGatewayTimeoutException::class.java)
         .hasMessageContaining("Provider connection dropped")

        coVerify(exactly = 1) { paymentClient.authorize(orderId, any()) }
        coVerify(exactly = 0) { orderRepository.updateStatus(any(), any()) }
    }
```
          
🛠️ SECTION 4 / HANDS-ON SCENARIO & LAB

Enterprise Incident: The Coroutine Mocking Hallucination Loop

สถานการณ์จริง: ทีมสถาปัตยกรรมกำลังขึ้นระบบ Reactive Microservices ด้วย Kotlin Coroutines แต่เมื่อทีมวิศวกรเรียกใช้งาน AI Assistant (Copilot / Cursor) ให้เขียน Unit Test ให้กับ suspend function ตัว AI กลับเขียนโค้ดที่เรียก every { ... } ธรรมดา ผลลัพธ์คือคอมไพล์ไม่ผ่าน (Suspension functions can be called only within coroutine body) และเมื่อโปรแกรมเมอร์สั่งให้ AI แก้ไข AI กลับวนลูปเปลี่ยนไปใช้ Mockito.mock() และครอบด้วย GlobalScope.launch ซึ่งทำลายโครงสร้างของโปรเจกต์

⚠️ LAB MISSION OBJECTIVES
  1. ติดตั้งบล็อก PRS Few-Shot Exemplars ลงใน SKILL.md เพื่อทำ Cognitive Anchoring สำหรับ Coroutines
  2. เขียน Bash Verification Script (verify-exemplar-syntax.sh) สำหรับตรวจสอบว่าไฟล์ Unit Test ที่ AI สร้างขึ้นมีไวยากรณ์ coEvery, runTest และไม่มี Mockito หรือ JUnit 4 ปนเปื้อน
  3. ทดสอบรันสคริปต์เพื่อตรวจจับความถูกต้องทางวิศวกรรม (Exit Code 0 เมื่อถูกต้อง, Exit 1 เมื่อพบการหลุดไวยากรณ์)
VALIDATION TOOL: scripts/verify-exemplar-syntax.sh POSIX Bash AST/Pattern Checker
#!/usr/bin/env bash
# ==============================================================================
# verify-exemplar-syntax.sh
# Validates that generated tests conform to the Day 4 PRS Exemplar standards:
# - Uses kotlinx.coroutines.test.runTest
# - Uses coEvery / coVerify for suspend operations
# - Enforces MockK and AssertJ (zero Mockito)
# ==============================================================================
set -euo pipefail

TARGET_TEST="${1:-src/test/kotlin/com/enterprise/billing/service/OrderSettlementServiceTest.kt}"

echo "🧪 [1/4] Checking file target: $TARGET_TEST"
if [[ ! -f "$TARGET_TEST" ]]; then
  echo "❌ Error: Test target $TARGET_TEST does not exist!" >&2
  exit 1
fi

VIOLATIONS=0

echo "🔍 [2/4] Scanning for Coroutine Test Fixtures..."
if ! grep -q "kotlinx.coroutines.test.runTest" "$TARGET_TEST" && ! grep -q "runTest {" "$TARGET_TEST"; then
  echo "  ❌ VIOLATION: Test does not utilize 'runTest' for deterministic virtual coroutine execution!" >&2
  VIOLATIONS=$((VIOLATIONS + 1))
else
  echo "  ✅ Verified: runTest coroutine scope anchored."
fi

echo "🔍 [3/4] Validating MockK Coroutine Idioms (coEvery / coVerify)..."
if grep -q "every {" "$TARGET_TEST"; then
  echo "  ⚠️ WARNING: Detected 'every {' syntax. Ensure non-suspend calls are not accidentally used for suspend funs."
fi

if ! grep -q "coEvery" "$TARGET_TEST"; then
  echo "  ❌ VIOLATION: Missing 'coEvery' mocking for suspend endpoints!" >&2
  VIOLATIONS=$((VIOLATIONS + 1))
fi

if ! grep -q "coVerify" "$TARGET_TEST"; then
  echo "  ❌ VIOLATION: Missing 'coVerify' interaction verification!" >&2
  VIOLATIONS=$((VIOLATIONS + 1))
fi

echo "🔍 [4/4] Verifying Legacy Mockito & JUnit 4 Sanitization..."
if grep -En "org\.junit\.Test|org\.mockito" "$TARGET_TEST"; then
  echo "  ❌ CRITICAL VIOLATION: Legacy JUnit 4 or Mockito contamination detected!" >&2
  VIOLATIONS=$((VIOLATIONS + 1))
else
  echo "  ✅ Clean: Zero legacy artifacts detected."
fi

# Exit Code Evaluation
if [[ $VIOLATIONS -gt 0 ]]; then
  echo "🛑 REJECTED: Test failed with $VIOLATIONS syntax and exemplar violations." >&2
  exit 1
fi

echo "🎉 PASSED: Generated test aligns 100% with Day 4 PRS Exemplar standards!"
exit 0
        
🎯 SECTION 5 / INTERACTIVE ARCHITECTURE & VERIFICATION QUIZ

ทดสอบสถาปัตยกรรม PRS Few-Shot Exemplar Engineering (Day 4)

Current Score
0 / 12

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