The "Where & Why": In-Context Architectural Guardrails และการหยุดยั้ง Hallucination Drift
ปัญหาและช่องโหว่ที่พบ: เมื่อ Host Agent ผ่าน Semantic Gate เข้ามาและเริ่มสร้างโค้ด LLM มักเกิด Hallucination Drift หรือ Architectural Decay เช่น ดึง Library เก่า (Mockito), ติด Annotation ผิดประเภท (
@SpringBootTest), หรือสร้าง Code Smells เพราะในคำสั่งมีแต่เป้าหมายเชิงบวก (What to do) แต่ขาด Negative Constraints (What NOT to do)เป้าหมายของ Day 3: เราจะฝัง In-Context Non-Negotiable Boundaries ตามมาตรฐาน RFC 2119 (MUST NOT, SHALL NOT) และ Anti-Pattern Tables ลงใน Body ของ
SKILL.md เพื่อล็อกพฤติกรรม LLM ให้มี Deterministic Conformance 100%
[Day 2 Semantic Router Matches Intent: Similarity > 0.85]
│
▼ (Skill Hydrated into Active Context)
┌────────────────────────────────────────────────────────────────────────┐
│ ACTIVE CONTEXT WINDOW (Host Agent + LLM Attention Stack) │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ YAML Frontmatter (Metadata, Targets, Tools) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ 🛡️ IN-CONTEXT CONSTRAINTS & ARCHITECTURAL BOUNDARIES [DAY 3] │ │
│ │ - RFC 2119 Invariants (MUST NOT inject Spring Context) │ │
│ │ - Explicit Forbidden List (org.mockito.*, @DataJpaTest) │ │
│ │ - Memory & Speed Budget (< 50ms runtime, pure isolated heap) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ Dynamic Execution & Code Generation Phase │ │
│ │ LLM evaluates proposed AST against Negative Constraint Matrix │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────┬─────────────────────────────────────┘
│
┌──────────────┴──────────────┐
▼ ▼
[Violates Negative Rule?] [All Constraints Clear?]
│ │
▼ ▼
❌ HALT & SELF-CORRECT ✅ COMPILE-READY ARTIFACT
(Pre-commit AST Rejection) (Zero Spring context, MockK)
Negative Contracts
กำหนดขอบเขตข้อห้ามเด็ดขาด (Invariants) เช่น ห้ามโหลด Spring Context ลงใน Unit Test เปรียบเสมือน Type System สกัด Compile Errors
Anti-Drift Anchors
จัดวาง Constraints ไว้บนสุดของ Instruction Body เพื่อตรึง Attention Heads ของ LLM ไม่ให้หลุดลอยตามบริบทโค้ดขนาดยาว
Zero Tolerance
ให้ LLM ปฏิเสธการสร้างโค้ดทันทีหาก Preconditions ขัดแย้ง แทนที่จะเดาจนเกิดภาพหลอน (Hallucination)
วิศวกรรม Negative Constraints: Type Systems, Attention Drift และ RFC 2119
ในหลักการ Software Engineering แบบดั้งเดิม เราใช้ Strong Type Systems, Immutable Data Structures และ Assertions เพื่อป้องกันสถานะที่ผิดพลาด (Invalid States) ไม่ให้เกิดขึ้นตั้งแต่ต้น ในทำนองเดียวกัน การเขียน Agent Skill ต้องไม่พึ่งพาเพียงคำขอร้องเชิงบวก แต่ต้องสร้าง Negative Invariants เพื่อตัด Search Space ของโมเดล LLM ให้เหลือเพียงโค้ดที่ถูกต้องเท่านั้น
| มิติสถาปัตยกรรม (Architectural Dimension) | Weak Prompting (คำสั่งเชิงบวกทั่วไป) | Specification-First Guardrails (Day 3) |
|---|---|---|
| Instruction Syntax | "Please use MockK and make tests clean and fast." | "Tests MUST NOT import org.mockito.* under any circumstances. Tests SHALL NOT boot ApplicationContext." |
| Attention Drift Resilience | ต่ำมาก: เมื่อเจอรหัสเดิมที่เป็น Mockito หรือ Java LLM จะดริฟต์ตามโค้ดเก่าทันที | สูงมาก: มี Negative Anchor สกัดกั้นไม่ให้โมเดลหยิบ Pattern ในโค้ดเก่ามาใช้ซ้ำ |
| Behavior on Ambiguity | โมเดลเดาสุ่ม นำพา Library ผิดประเภทเข้ามาใน Dependency | Defensive Halt: โมเดลหยุดและแจ้ง violation ล่วงหน้าก่อนเขียนไฟล์ |
| AST Verification Alignment | ไม่สามารถเชื่อมต่อกับ Script เชิงสถิติได้ เพราะไม่มีเกณฑ์ชี้ชัด | แมปเข้ากับ Bash/AST regex linter ได้ 1:1 ตรวจสอบได้แบบ Deterministic |
เมื่อ LLM อ่านเอกสารใน Context Window นานขึ้น Attention Weights จะกระจายตัวกว้างขึ้นและเจือจางลง ปรากฏการณ์นี้เรียกว่า Attention Degradation
การกำหนดคำว่า "FORBIDDEN", "MUST NOT" และระบุ Package Name ที่ห้ามใช้ตรงๆ จะสร้าง Dense Attention Peak ทำให้โมเดลจัดลำดับความสำคัญของกฎข้อห้ามเหนือกว่าตัวอย่างโค้ดในโปรเจกต์ที่อาจยังใช้เทคโนโลยีเก่าอยู่
การเลือกคำศัพท์ในเอกสารสถาปัตยกรรมระดับองค์กรต้องอ้างอิงมาตรฐาน IETF RFC 2119:
- MUST NOT / SHALL NOT: ข้อห้ามเด็ดขาด หากฝ่าฝืนถือเป็น Critical Specification Bug ทันที
- SHOULD NOT: พฤติกรรมที่ไม่แนะนำ ยกเว้นมีเหตุผลทางสถาปัตยกรรมที่ระบุไว้อย่างชัดเจน
- MUST / REQUIRED: ข้อกำหนดบังคับที่ Artifact ต้องมี (เช่น โครงสร้าง AAA เท่านั้น)
Production Artifact: In-Context Guarded Contract
ไฟล์ SKILL.md สมบูรณ์แบบที่นำ In-Context Constraints และ Anti-Pattern Defense เข้ามาติดตั้งเพื่อควบคุม Host Agent ในระบบ Maven / Kotlin / Spring Boot
.github/skills/spring-boot-unit-tester/
├── SKILL.md ◄── [TODAY'S ARTIFACT: In-Context Constraints & Anti-Patterns]
├── scripts/
│ ├── eval-triggers.sh ◄── Day 2: Router Evaluation
│ └── verify-constraints.sh ◄── Day 3: Static AST Anti-Pattern Linter
└── tests/
└── routing-fixtures.json
---
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, and AssertJ. Use for service and domain layer tests.
DO NOT USE for integration tests, Testcontainers, @SpringBootTest, or database testing.
metadata:
domain: "backend-quality"
target-framework: "Spring Boot 3.x"
---
# Spring Boot Isolated Unit Test Engine Contract
## 1. Architectural Boundaries & Negative Constraints
As an autonomous code generation engine, you MUST adhere to the following normative invariants:
### 1.1 Strictly FORBIDDEN Constructs (MUST NOT)
- **NO Mockito Infiltration**: You MUST NOT import `org.mockito.*`, `org.springframework.boot.test.mock.mockito.*`, or use `@MockBean` / `@SpyBean`.
- **NO ApplicationContext Booting**: You MUST NOT annotate test classes with `@SpringBootTest`, `@DataJpaTest`, `@WebMvcTest`, or `@AutoConfigureTestDatabase`.
- **NO Spring Extension**: You MUST NOT use `@ExtendWith(SpringExtension.class)`. Pure JVM tests execute without Spring container overhead.
- **NO Reflection-Based State Injection**: You MUST NOT use `ReflectionTestUtils.setField()`. All dependencies MUST be injected via constructors.
- **NO Hardcoded Time or Latency**: You MUST NOT use `Thread.sleep()`. Use virtual clocks or explicit mock timings.
### 1.2 Required Structural Mandates (MUST)
- **Framework Stack**: MUST use JUnit 5 (`org.junit.jupiter.api.*`), MockK (`io.mockk.*`), and AssertJ (`org.assertj.core.api.Assertions.assertThat`).
- **Isolation Guarantee**: Tests MUST execute in under 50ms per test method strictly in-memory.
- **Explicit AAA Phases**: Every test method body MUST be divided using explicit single-line comments:
`// Arrange`, `// Act`, and `// Assert`.
## 2. Anti-Pattern Triage & Replacement Matrix
| Anti-Pattern Observed | Severity | Permitted Architecture Alternative |
| :--- | :--- | :--- |
| `Mockito.when(mock.call()).thenReturn(val)` | CRITICAL | `every { mock.call() } returns val` |
| `@MockBean private lateinit var repo: Repo` | CRITICAL | Constructor injection: `val repo = mockk<Repo>()` |
| `assertEquals(expected, actual)` | MAJOR | `assertThat(actual).isEqualTo(expected)` |
| `@Test fun test_save() { ... }` (Snake case) | MINOR | Use backtick descriptions: @Test fun \`should calculate tax correctly\`() |
## 3. Defense-in-Depth Self-Check
Before finalizing output, execute an in-context AST scan on your generated code:
1. Did you accidentally retain any `import org.mockito.*` in the import header? -> REMOVE IMMEDIATELY.
2. Is there any Spring Context annotation present? -> STRIP AND INSTANTIATE RAW CLASS.
Enterprise Incident: The Mockito Legacy Infiltration & Context Leak
สถานการณ์จริง: ใน Maven Multi-module Kotlin Project ขนาด 2 ล้านบรรทัด ทีมงานกำลัง refactor โค้ดเก่า แต่เมื่อเรียก GitHub Copilot หรือ Cursor ให้เขียน Unit Test ให้กับ PaymentSettlementService ตัว AI กลับเหลือบไปเห็น module ข้างเคียงที่ยังใช้ Mockito + @MockBean อยู่ AI จึง generate โค้ดที่ติด @SpringBootTest และ Mockito ส่งผลให้ CI/CD Pipeline จากเดิมที่รัน 10 วินาที พุ่งขึ้นเป็น 4 นาที และ Build พังเนื่องจาก Dependency Conflict
- ฝัง Negative Architectural Constraints ลงใน
SKILL.mdด้วยคำสำคัญ RFC 2119 อย่างเคร่งครัด - สร้าง Deterministic Shell Verifier (
verify-constraints.sh) ที่ทำหน้าที่เป็น Linter ตรวจจับ AST/Regex สำหรับ Annotation และ Import ต้องห้าม - ทดสอบรัน Verifier บนโค้ดตัวอย่างเพื่อให้แน่ใจว่า Exit Code มีพฤติกรรมตามสัญญา (Exit 0 เมื่อถูกต้อง, Exit 1 เมื่อพบ Anti-pattern)
#!/usr/bin/env bash
# ==============================================================================
# verify-constraints.sh
# Deterministic AST & Regex Invariant Checker for Kotlin Unit Tests
# Enforces Day 3 In-Context Architectural Guardrails
# ==============================================================================
set -euo pipefail
TARGET_FILE="${1:-src/test/kotlin/com/enterprise/billing/PaymentSettlementServiceTest.kt}"
echo "🛡️ [1/4] Checking file presence: $TARGET_FILE"
if [[ ! -f "$TARGET_FILE" ]]; then
echo "❌ Error: Target test file $TARGET_FILE does not exist!" >&2
exit 1
fi
VIOLATIONS=0
echo "🔍 [2/4] Scanning for FORBIDDEN Mockito artifacts..."
if grep -En "org\.mockito|org\.springframework\.boot\.test\.mock\.mockito|Mockito\." "$TARGET_FILE"; then
echo " ❌ CRITICAL VIOLATION: Forbidden Mockito package or syntax detected!" >&2
VIOLATIONS=$((VIOLATIONS + 1))
else
echo " ✅ Clean: No Mockito contamination."
fi
echo "🔍 [3/4] Scanning for FORBIDDEN Spring Context Annotations..."
FORBIDDEN_ANNOTATIONS=("@SpringBootTest" "@DataJpaTest" "@WebMvcTest" "@ExtendWith(SpringExtension" "@MockBean")
for anno in "${FORBIDDEN_ANNOTATIONS[@]}"; do
if grep -Fn "$anno" "$TARGET_FILE"; then
echo " ❌ CRITICAL VIOLATION: Forbidden Context annotation '$anno' found!" >&2
VIOLATIONS=$((VIOLATIONS + 1))
fi
done
if [[ $VIOLATIONS -eq 0 ]]; then
echo " ✅ Clean: Zero Spring Context dependencies detected. Pure JVM memory isolation guaranteed."
fi
echo "🔍 [4/4] Verifying MANDATORY MockK and AAA conventions..."
if ! grep -q "io\.mockk" "$TARGET_FILE"; then
echo " ❌ VIOLATION: Missing required 'io.mockk' import!" >&2
VIOLATIONS=$((VIOLATIONS + 1))
fi
if ! grep -q "// Arrange" "$TARGET_FILE" || ! grep -q "// Act" "$TARGET_FILE" || ! grep -q "// Assert" "$TARGET_FILE"; then
echo " ⚠️ WARNING: Test does not clearly follow mandatory // Arrange // Act // Assert comments."
fi
# Exit Code Evaluation
if [[ $VIOLATIONS -gt 0 ]]; then
echo "🛑 REJECTED: Test failed with $VIOLATIONS architectural invariant violation(s)." >&2
exit 1
fi
echo "🎉 PASSED: Generated unit test satisfies all enterprise architectural guardrails!"
exit 0
ทดสอบสถาปัตยกรรม In-Context Constraints & Guardrails (Day 3)
ตอบคำถามเชิงสถาปัตยกรรมทั้ง 12 ข้อด้านล่าง ระบบจะตรวจคำตอบและให้ Feedback ทันทีเมื่อคลิกเลือกช้อยส์ พร้อมแสดงคำอธิบายเชิงลึก