The "Where & Why": สถาปัตยกรรม Progressive Disclosure และการจัดการ Context Pollution
ปัญหาคอขวดใหม่ที่พบใน Phase 3: เมื่อระบบต้องจำลองข้อมูลทดสอบ (Test Fixtures) สำหรับ Domain Objects หรือ DTOs ขนาดใหญ่ที่มี 30-50 ฟิลด์ หากเรายัด JSON Schemas, OpenAPI Specs, หรือ Database Contracts ทั้งหมดลงใน
SKILL.md จะเกิด Context Window Flooding และ Attention Drift ทันทีเป้าหมายของ Day 8: เราจะติดตั้งเลเยอร์
references/ ตามมาตรฐาน agentskills พร้อมนำกลยุทธ์ Dynamic Progressive Disclosure มาใช้: ให้ SKILL.md เก็บเฉพาะ Pointer References น้ำหนักเบา และเปิดทางให้ Agent อ่าน Heavy Schemas เฉพาะเมื่อถึงจุดที่ต้อง Mock เท่านั้น
┌────────────────────────────────────────────────────────────────────────┐
│ TIER 1: FAST DISCOVERY (~100 Tokens) │
│ Host Agent Session Startup scans Frontmatter description only │
└───────────────────────────────────┬────────────────────────────────────┘
│ (Intent Match > 0.80)
▼
┌────────────────────────────────────────────────────────────────────────┐
│ TIER 2: ACTIVE WORKING MEMORY (~800 Tokens) │
│ SKILL.md Hydration: Invariants (Day 3), PRS (Day 4), Tool Defs (Day 5) │
│ Contains POINTERS to External References (Zero Heavy Data Flooding) │
└───────────────────────────────────┬────────────────────────────────────┘
│
├────────────────────────────────────┐
│ Need: Simple Mock? │ Need: Complex Nested DTO?
▼ ▼
┌──────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────┐
│ FAST IN-MEMORY SYNTHESIS │ │ 🎯 TIER 3: ON-DEMAND REFERENCES/ LAYER [TODAY] │
│ Agent generates fixtures using standard AST info │ │ Agent reads: references/billing-schemas.json │
│ Context remains ultralight (< 1,000 tokens) │ │ Hydrates only the targeted 40-field schema slice │
└──────────────────────────────────────────────────┘ └──────────────────────────────────────────────────┘
Tiered Hydration
ไม่โหลดข้อมูลก้อนใหญ่เข้าสู่ Prompt ล่วงหน้า แต่ใช้ Pointer Rules ให้ Agent ดึงเฉพาะไฟล์ใน references/ ที่จำเป็นต่องานย่อย
Eliminate Distraction
การแยก Heavy Contracts ออกจาก SKILL.md ช่วยรักษาความสนใจของโมเดลให้มุ่งเน้นที่ Invariants และ Test Behavior ได้อย่างแม่นยำ
Single Source of Truth
เมื่อ Enterprise API Contract มีการปรับโครงสร้าง สามารถแก้ไขที่ไฟล์ใน references/ จุดเดียวโดยไม่ต้องตามแก้ Instruction หลัก
วิศวกรรม Context Budgeting: การเปลี่ยน Heavy Payloads สู่ On-Demand Pointer Architecture
ในระบบปฏิบัติการ (Operating Systems) คอมพิวเตอร์ไม่โหลดโปรแกรมขนาด 10 GB ทั้งหมดลงใน L1 Cache แต่ใช้กลไก Virtual Memory และ Paging เพื่อดึงข้อมูลเฉพาะหน้าที่ใช้งานจริง ในโลกของ LLM Context Window ก็มีพฤติกรรมดุจเดียวกัน: หากเรายัด DTO definitions และ Enterprise Schemas ทั้งหมดลงในไฟล์คำสั่งหลัก Attention Mechanism ของโมเดลจะถูกเจือจางด้วย Token นับพันตัวที่ไม่ได้ใช้งานในแต่ละรอบ
| มิติสถาปัตยกรรม (Architectural Dimension) | Monolithic Prompt (ยัดทุกอย่างใน SKILL.md) | Ad-hoc Search (ให้ Agent ไล่ค้นหาไฟล์เอง) | Tiered References Layer (Day 8 Standard) |
|---|---|---|---|
| Baseline Context Consumption | วิกฤต (3,000 - 8,000 Tokens ต่อ Request) | ต่ำตอนเริ่ม แต่บวมมหาศาลหลังการ Grep สะเปะสะปะ | ต่ำที่สุด (< 850 Tokens สำหรับ Core Spec) |
| Attention Degradation Risk | สูงมาก: โมเดลละเลย Negative Invariants | ปานกลาง: โมเดลติดหล่มในไฟล์เก่าที่ค้นพบ | ต่ำที่สุด: กฎหลักยังคงตรึง Attention สูงสุด |
| Complex Fixture Accuracy | ปานกลาง: มักสุ่มเดาฟิลด์ย่อยที่ซ่อนอยู่ลึกๆ | ต่ำ: มีโอกาสหยิบ Mock เก่าที่ไม่ตรงกับระบบปัจจุบัน | แม่นยำ 100%: อ่าน Schema Canonical ล่าสุดตรงๆ |
| Maintenance Cost | สูงมาก: แก้ DTO 1 ฟิลด์ต้องแก้ SKILL.md ทุกตัว | ไม่มีการควบคุมมาตรฐาน | ต่ำมาก: อัปเดตไฟล์ใน references/ แยกอิสระ |
ในเชิงทฤษฎี Information Density ยิ่ง Token ที่ป้อนเข้าสู่ Active Window มีความสำคัญต่อการตัดสินใจมากเท่าใด ผลลัพธ์ก็จะยิ่งแม่นยำขึ้นเท่านั้น:
หากนำ Schema ขนาด 2,000 Tokens ยัดไว้ในคำสั่งตลอดเวลา อัตราส่วน Efficiency จะร่วงลงทันที การนำข้อมูลนั้นไปเก็บไว้ใน references/ แล้วทิ้งไว้เพียง Pointer Directive (เช่น "If mocking SettlementPayload, read references/settlement-schema.json") จะช่วยรักษา Efficiency ให้อยู่ในระดับสูงสุด
สัญญาระหว่าง SKILL.md กับไดเรกทอรี references/ มีกฎเหล็ก 3 ประการ:
- 1. Explicit Trigger Condition: ต้องระบุเงื่อนไขจำเพาะว่าจะเปิดอ่านเมื่อใด ไม่เขียนว่า "อ่านไฟล์นี้เสมอ"
- 2. Relative Path Stability: เส้นทางไฟล์ต้องเป็น Relative Path เทียบจากโฟลเดอร์ Skill เสมอ
- 3. Single Responsibility: แยก 1 ไฟล์ต่อ 1 โดเมน เช่น
billing-dto.json,tax-contract.mdไม่รวมเป็นไฟล์ยักษ์
Production Artifact: Progressive References Architecture
ชุดเครื่องมือและไฟล์ตัวอย่างจริงตามมาตรฐาน agentskills/agentskills ที่แยก Heavy Billing Domain Schema ออกจาก SKILL.md พร้อมสคริปต์สืบค้น Reference สด
.github/skills/spring-boot-unit-tester/
├── SKILL.md ◄── [UPDATED: Added Tier 3 Progressive Pointer Rules]
├── scripts/
│ ├── run-unit-tests.sh ◄── Day 5-6: Sandboxed Execution & Triage Runner
│ ├── extract-target-ast.py ◄── Day 7: Lightweight AST Class Inspector
│ └── query-reference.sh ◄── [TODAY'S ARTIFACT: Targeted Schema Slice Extractor]
└── references/ ◄── [TODAY'S ARTIFACT: Heavy Domain Schemas Layer]
└── billing-domain-contracts.json ◄── Canonical DTO Fixture Specification
---
name: spring-boot-unit-tester
schema-version: "1.0.0"
description: >
Generates deterministic, isolated Kotlin unit tests for Spring Boot 3.x
using MockK and AssertJ. MUST NOT load Spring ApplicationContext.
tools:
- name: inspect-class-context
description: Extracts concise AST skeleton from target source file.
file: scripts/inspect-class-context.sh
- 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 test execution with automatic stderr triage.
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 & Execution Protocol
1. Follow AAA pattern with isolated JVM memory execution (< 50ms per method).
2. MUST NOT use `@SpringBootTest`, `@DataJpaTest`, or `org.mockito.*`.
3. Pre-flight: Execute `inspect-class-context` to retrieve Constructor parameters and suspend methods.
## 2. On-Demand Domain References & Fixture Contracts
Do NOT guess domain fixture schemas or inject bloated dummy objects.
When testing services that interact with complex billing or trading payloads, consult external references on-demand:
- **Settlement & Invoicing DTOs**:
When the target method consumes or returns `SettlementInstruction` or `InvoicePayload`, query:
`bash .github/skills/spring-boot-unit-tester/scripts/query-reference.sh references/billing-domain-contracts.json SettlementInstruction`
- **Rules for Ingestion**:
1. DO NOT read the entire `references/` directory in advance.
2. Extract ONLY the target schema node needed to build the specific mock fixture.
3. Keep fixture instantiation minimal: set mandatory fields accurately, leave optional fields empty.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"domain": "EnterpriseBilling",
"version": "4.2.0",
"schemas": {
"SettlementInstruction": {
"type": "object",
"required": ["instructionId", "accountNumber", "settlementAmount", "currency", "clearingRail"],
"properties": {
"instructionId": { "type": "string", "format": "uuid", "example": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d" },
"accountNumber": { "type": "string", "pattern": "^[A-Z0-9]{12,34}$", "example": "ACC-9988221100" },
"settlementAmount": { "type": "string", "format": "decimal", "example": "1250000.50" },
"currency": { "type": "string", "enum": ["USD", "EUR", "THB", "JPY"], "example": "USD" },
"clearingRail": { "type": "string", "enum": ["FEDNOW", "TARGET2", "SWIFT", "PROMPTPAY"], "example": "SWIFT" },
"metadata": {
"type": "object",
"properties": {
"originatingBic": { "type": "string", "example": "CHASTHBNXXX" },
"regulatoryTag": { "type": "string", "example": "SEC_RULE_15C3" },
"auditTimestamp": { "type": "integer", "example": 1774218800 }
}
}
}
},
"SettlementResult": {
"type": "object",
"required": ["settlementId", "status", "reconciliationCode"],
"properties": {
"settlementId": { "type": "string", "format": "uuid", "example": "e4eaaaf2-d142-11e1-b3e4-080027620cdd" },
"status": { "type": "string", "enum": ["COMPLETED", "PENDING_MATCH", "REJECTED_FUNDS"], "example": "COMPLETED" },
"reconciliationCode": { "type": "string", "example": "RC-2026-99" },
"executionLatencyMs": { "type": "integer", "example": 14 }
}
}
}
}
#!/usr/bin/env bash
# ==============================================================================
# scripts/query-reference.sh
# Standard: agentskills Standard v1.0 (Phase 3 Reference Architecture)
# Slices out a specific schema node from references/ on demand (< 150 tokens)
# ==============================================================================
set -euo pipefail
REF_FILE="${1:-}"
NODE_KEY="${2:-}"
# 1. Validation of Arguments
if [[ -z "${REF_FILE}" ]] || [[ ! -f "${REF_FILE}" ]]; then
echo "### 🚨 REFERENCE QUERY ERROR" >&2
echo "- **Category**: \`REFERENCE_FILE_NOT_FOUND\`" >&2
echo "- **Error**: Reference file '${REF_FILE}' does not exist or was not specified." >&2
exit 1
fi
# 2. Extract Specific Sub-Schema Using Zero-Dependency Python Slicer
python3 -c "
import sys, json
try:
with open('${REF_FILE}', 'r', encoding='utf-8') as f:
data = json.load(f)
key = '${NODE_KEY}'
schemas = data.get('schemas', {})
if key and key in schemas:
target = schemas[key]
print(f'### 📑 CANONICAL REFERENCE SLICE: {key}')
print(f'- **Required Fields**: \`{target.get(\"required\", [])}\`')
print('- **Field Blueprint**:')
for prop, details in target.get('properties', {}).items():
t = details.get('type', 'any')
ex = details.get('example', 'N/A')
print(f' - \`{prop}\` ({t}) -> Example: \`{ex}\`')
else:
print(f'### ⚠️ SCHEMA KEY NOT FOUND: {key}')
print(f'- Available keys in reference: {list(schemas.keys())}')
sys.exit(2)
except Exception as e:
sys.stderr.write(f'Parsing error: {str(e)}\\n')
sys.exit(1)
"
exit 0
Enterprise Incident: The 45-Field Billing DTO Context Window Suffocation
สถานการณ์จริง: Host Agent กำลังเขียน Unit Test ให้กับ BillingSettlementService.kt ซึ่งต้องสร้าง Object จำลองของ SettlementInstruction ในขั้นตอน // Arrange เนื่องจากผู้เขียน Skill เดิมเผลอนำ JSON Schema ขนาด 15 KB (กว่า 3,500 Tokens) ใส่ไว้ในเนื้อหา SKILL.md โดยตรง ส่งผลให้ Context Window เต็ม Attention ของโมเดลเจือจาง และทำให้ Agent "ลืม" กฎใน Day 3 จนเผลอ Import org.mockito.Mockito กลับเข้ามาในโค้ดอีกครั้ง
- ย้ายเนื้อหา Schema ทั้งหมดออกจาก
SKILL.mdไปเก็บไว้ที่references/billing-domain-contracts.jsonเพื่อคืนพื้นที่ Context Window กว่า 90% - ทดสอบรันสคริปต์
query-reference.shเพื่อสกัดเฉพาะ NodeSettlementInstructionออกมาเป็น Markdown Slice ขนาดไม่เกิน 95 Tokens - พิสูจน์ว่า Host Agent สามารถนำ Field Blueprint ที่ได้ไปสร้าง Test Fixture ใน MockK ได้ถูกต้องสมบูรณ์ 100% โดยไม่ทำให้ Invariants หลุด
# Inside SKILL.md body directly:
Here is the entire JSON schema of all 25 Enterprise
Billing DTOs, including Invoices, Statements, Taxes,
Regulatory reports, Ledger entries, KYC records...
{
"$schema": "https://json-schema.org/...",
"schemas": { ... 1,200 lines of JSON ... }
}
// Consequence: Attention Drift, Model forgets Negative Rules!
### 📑 CANONICAL REFERENCE SLICE: SettlementInstruction
- **Required Fields**: `['instructionId', 'accountNumber', 'settlementAmount', 'currency', 'clearingRail']`
- **Field Blueprint**:
- `instructionId` (string) -> Example: `9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d`
- `accountNumber` (string) -> Example: `ACC-9988221100`
- `settlementAmount` (string) -> Example: `1250000.50`
- `currency` (string) -> Example: `USD`
- `clearingRail` (string) -> Example: `SWIFT`
$ bash .github/skills/spring-boot-unit-tester/scripts/query-reference.sh references/billing-domain-contracts.json SettlementInstruction
### 📑 CANONICAL REFERENCE SLICE: SettlementInstruction
- **Required Fields**: `['instructionId', 'accountNumber', 'settlementAmount', 'currency', 'clearingRail']`
- **Field Blueprint**:
- `instructionId` (string) -> Example: `9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d`
- `accountNumber` (string) -> Example: `ACC-9988221100`
- `settlementAmount` (string) -> Example: `1250000.50`
- `currency` (string) -> Example: `USD`
- `clearingRail` (string) -> Example: `SWIFT`
$ echo $?
0
ทดสอบสถาปัตยกรรม references/ Layer & Context Budgeting (Day 8)
ตอบคำถามเชิงสถาปัตยกรรมทั้ง 12 ข้อด้านล่าง ระบบจะตรวจคำตอบและให้ Feedback ทันทีเมื่อคลิกเลือกช้อยส์ พร้อมแสดงคำอธิบายเชิงลึก