7.5 KiB
7.5 KiB
// File: specs/200-fullstacks/235-ai-runtime-policy-refactor/checklists/cutover-validation.md // Change Log: // - 2026-06-11: Initial cutover validation checklist for T032 and sidecar pytest
Cutover Validation Checklist: Feature 235
Purpose: ใช้ปิด T032 และเก็บหลักฐานสำหรับเลื่อนสถานะ validation จาก PARTIAL ไป PASS
หมายเหตุ
- Checklist นี้อิง implementation ปัจจุบัน ของ Option B
- อย่าใช้ตัวอย่างเก่าใน
quickstart.mdที่ยังส่งexecutionProfile/large-contextจาก caller- คำสั่งด้านล่างเป็น PowerShell ตามกฎของ repo
1. Environment Ready
- Backend รันที่
http://localhost:3001 - Frontend รันที่
http://localhost:3000 - OCR sidecar รันที่
http://192.168.10.100:8765 - Ollama รันและมี tag
np-dms-ai/np-dms-ocr - มี admin token สำหรับเรียก API
- มี
documentPublicIdและprojectPublicIdที่มีอยู่จริงสำหรับทดสอบrag-query - มีไฟล์ PDF ตัวอย่างสำหรับ OCR Sandbox
2. Automated Validation
2.1 Backend targeted tests
- รัน:
pnpm --filter backend test -- --runInBand --testPathPatterns="ai.service.spec.ts|queue-policy.spec.ts|ai.controller.spec.ts|ai-policy.service.spec.ts|ocr-residency.spec.ts|vram-monitor.service.spec.ts"
- Expected: ทุก suite ผ่าน
2.2 Backend build
- รัน:
pnpm --filter backend build
- Expected: build ผ่านไม่มี compile error
2.3 Sidecar pytest
- รัน:
python -m pytest specs/04-Infrastructure-OPS/04-00-docker-compose/Desk-5439/ocr-sidecar/tests -v
- Expected:
test_retrieval_fallback.pyผ่านครบ - ถ้า
pytestไม่พบ module: บันทึกว่า environment ยังไม่พร้อม และติดตั้ง dependency ก่อน rerun
3. Manual Gate 1: Policy Contract
ตั้งค่า token และ ids ก่อน:
$TOKEN = "<admin-jwt>"
$PROJECT_PUBLIC_ID = "<existing-project-public-id>"
$DOCUMENT_PUBLIC_ID = "<existing-document-public-id>"
3.1 Reject forbidden model
- รัน:
$body = @{
type = "rag-query"
projectPublicId = $PROJECT_PUBLIC_ID
payload = @{ query = "test policy contract" }
model = @{ key = "typhoon2.5-np-dms:latest" }
} | ConvertTo-Json -Depth 5
Invoke-RestMethod "http://localhost:3001/api/ai/jobs" `
-Method Post `
-Headers @{
Authorization = "Bearer $TOKEN"
"Idempotency-Key" = "feature235-gate1-model"
"Content-Type" = "application/json"
} `
-Body $body
- Expected: HTTP
400
3.2 Reject forbidden executionProfile
- รัน:
$body = @{
type = "rag-query"
projectPublicId = $PROJECT_PUBLIC_ID
payload = @{ query = "test forbidden profile" }
executionProfile = "quality"
} | ConvertTo-Json -Depth 5
- Expected: HTTP
400
3.3 Reject forbidden parameter override
- รัน:
$body = @{
type = "rag-query"
projectPublicId = $PROJECT_PUBLIC_ID
payload = @{ query = "test forbidden temperature" }
temperature = 0.9
} | ConvertTo-Json -Depth 5
- Expected: HTTP
400
3.4 Valid rag-query
- รัน:
$body = @{
type = "rag-query"
projectPublicId = $PROJECT_PUBLIC_ID
documentPublicId = $DOCUMENT_PUBLIC_ID
payload = @{ query = "สรุปเอกสารนี้" }
} | ConvertTo-Json -Depth 5
Invoke-RestMethod "http://localhost:3001/api/ai/jobs" `
-Method Post `
-Headers @{
Authorization = "Bearer $TOKEN"
"Idempotency-Key" = "feature235-gate1-valid"
"Content-Type" = "application/json"
} `
-Body $body
- Expected:
- HTTP
201 modelUsed = "np-dms-ai"effectiveProfile = "standard"queueName = "ai-batch"
- HTTP
4. Manual Gate 2: Canonical Naming
4.1 Audit log check
- ตรวจ row ล่าสุดใน
ai_audit_logs - Expected:
effective_profileมีค่าcanonical_modelเป็นnp-dms-aiหรือnp-dms-ocr- ไม่มี runtime name หลุดออกในฟิลด์ user-facing
4.2 Admin Console check
- เปิด
http://localhost:3000/admin/ai - ตรวจ Overview / health / model cards
- Expected:
- เห็น
np-dms-ai - เห็น
np-dms-ocr - ไม่เห็น
typhoon2.5-np-dms:latest - ไม่เห็น
typhoon-np-dms-ocr:latest
- เห็น
4.3 OCR Sandbox badge check
- เปิด OCR Sandbox ในหน้า admin AI
- รัน OCR 1 รอบ
- Expected:
- badge หรือ result label แสดง
np-dms-ocr - ไม่โชว์ runtime name โดยตรง
- badge หรือ result label แสดง
5. Manual Gate 3: Adaptive OCR Residency
5.1 High-pressure / deep-analysis behavior
- ทำให้ main model กิน VRAM สูง หรือจำลอง workload ที่เข้าข่าย pressure
- รัน OCR Sandbox หรือ OCR job
- ตรวจ sidecar / backend logs
- Expected:
keep_alive = 0- reason เป็น
high-pressureหรือdeep-analysis-active
5.2 Headroom sufficient behavior
- รัน OCR job ตอนที่ GPU headroom สูง
- ตรวจ logs
- Expected:
keep_alive > 0- reason เป็น
headroom-sufficient
6. Manual Gate 4: Retrieval CPU Fallback
6.1 Force GPU pressure
- warm model:
$warm = @{
model = "np-dms-ai"
prompt = "warmup"
keep_alive = -1
} | ConvertTo-Json
Invoke-RestMethod "http://localhost:11434/api/generate" `
-Method Post `
-ContentType "application/json" `
-Body $warm
6.2 Submit rag-query under pressure
- ส่ง request แบบเดียวกับ Gate 1.4 แต่เปลี่ยน
Idempotency-Key - Expected:
- request enqueue สำเร็จ
- job ไม่ fail hard
6.3 Verify fallback evidence
- ตรวจ sidecar logs
- Expected:
device=cpuหรือdevice: cpu- reason เป็น
gpu-headroom-below-thresholdหรือgpu-query-failed
7. Evidence to Attach
- backend test output
- backend build output
- sidecar pytest output
- screenshot หน้า
/admin/ai - screenshot OCR Sandbox result
- copy log line ของ residency decision
- copy log line ของ CPU fallback
- sample successful
rag-queryresponse body
8. Pass Criteria
- Automated backend tests ผ่าน
- Backend build ผ่าน
- Sidecar pytest ผ่าน
- Gate 1 ผ่านครบ
- Gate 2 ผ่านครบ
- Gate 3 ผ่านครบ
- Gate 4 ผ่านครบ
- หลักฐานถูกแนบหรือบันทึกไว้ใน feature folder
9. Follow-up After Completion
- update
tasks.mdให้ติ๊กT032 - update
validation-report.mdจากPARTIALเป็นPASS - ถ้าเจอ spec drift ให้ปรับ
quickstart.mdและจุดอ้างอิงที่ยังใช้ contract เก่า