690617:1443 237 #01.3
CI / CD Pipeline / build (push) Failing after 7m26s
CI / CD Pipeline / deploy (push) Has been skipped

This commit is contained in:
2026-06-17 14:43:30 +07:00
parent 82b41ad5d9
commit db16c95019
42 changed files with 3084 additions and 352 deletions
+10 -4
View File
@@ -92,16 +92,17 @@ Container สำเร็จรูป (FastAPI Sidecar บน Desk-5439) ทำ
_Avoid_: OCR microservice (ที่ขาดการป้องกัน)
**Prompt Version**:
Immutable snapshot ของ prompt template ใน `ai_prompts` table — ทุกครั้งที่ admin กด "บันทึก" จะสร้าง version ใหม่ (version*number เพิ่มทีละ 1) version เก่ายังอยู่ใน history ลบได้ยกเว้น active version (ADR-029)
\_Avoid*: Prompt config, Prompt setting, Editable prompt
Immutable snapshot ของ prompt template ใน `ai_prompts` table — ทุกครั้งที่ admin กด "บันทึก" จะสร้าง version ใหม่ (`version_number` เพิ่มทีละ 1) version เก่ายังอยู่ใน history ลบได้ยกเว้น active version (ADR-029)
_Avoid_: Prompt config, Prompt setting, Editable prompt
**Active Prompt**:
Prompt Version ที่มี `is_active = 1` ต่อ `prompt_type` — ใช้โดยทั้ง OCR Sandbox และ `processMigrateDocument` พร้อมกัน, cached ใน Redis TTL 60s; invalidated เมื่อ admin activate version อื่น (ADR-029)
_Avoid_: Production prompt (sandbox และ migrate-document ใช้เดียวกัน)
**Prompt Template**:
String ที่มี `{{ocr_text}}` placeholder บังคับ — backend validate ก่อน save; processor แทนที่ด้วย OCR output ก่อนส่งเข้า Ollama (ADR-029)
_Avoid_: Prompt string, Prompt text (ambiguous)
String ที่ใส่ placeholder ตาม `prompt_type` — backend validate ก่อน save; processor แทนที่ด้วยค่าจริงก่อนส่งเข้า Ollama (ADR-029, ADR-037)
Canonical placeholder names per type: `ocr_extraction``{{ocr_text}}` (required), `{{master_data_context}}` (optional); `rag_query_prompt``{{query}}`, `{{context}}` (both required); `rag_prep_prompt``{{text}}` (required); `classification_prompt``{{document_text}}` (required)
_Avoid_: Prompt string, Prompt text (ambiguous); ห้ามใช้ชื่อ placeholder อื่น เช่น `{{user_query}}`, `{{retrieved_chunks}}`, `{{document_metadata}}` — ชื่อเหล่านี้ไม่ใช่ canonical
**Human-in-the-loop**:
ทุก AI suggestion ต้องผ่านการ accept/reject โดย user ก่อนกลายเป็น state change — บันทึกใน `ai_audit_logs`
@@ -285,6 +286,11 @@ _Avoid_: Throw exception from tool, Untyped error
- **"`temperature/topP/maxTokens` ใครคุม"** — resolved: ใช้ **Profile-Only Parameter Governance**; caller ส่งได้แค่ profile ส่วน runtime parameters จริงให้ backend policy คุมทั้งหมด
- **"BGE GPU uplift อยู่ใน scope เดียวกันไหม"** — resolved: ใช้ **Integrated Retrieval Acceleration Policy**; retrieval acceleration เป็นส่วนหนึ่งของ runtime resource policy เดียวกัน
- **"ADR-036 system_settings store ใหม่"** — resolved: **ไม่สร้าง** parallel param store ใน `system_settings`; `ai_execution_profiles` คือ setting store เดิมที่ production ดึงค่าอยู่แล้ว (`getProfileParameters()`) — ADR-036 เป็น **enhance** (เติม write/apply path) ไม่ใช่ supersede Profile-Only Parameter Governance
- **"VersionHistory pagination — button-based หรือ infinite scroll"** — resolved: **infinite scroll** ตาม spec FR; ใช้ `IntersectionObserver` + sentinel `<div>` (ไม่ใช้ external library); แสดง 20 รายการแรก โหลดเพิ่มครั้งละ 20 เมื่อ scroll ถึง sentinel; `visibleCount` รีเซ็ตเมื่อ `versions` prop เปลี่ยน; แสดง counter "แสดง X จาก Y เวอร์ชัน" ขณะยังมีของเหลือ (2026-06-15)
- **"ContextConfigEditor Language enum และ default"** — resolved: enum ที่ถูกต้องคือ `th`/`en`/`mixed` (lowercase ตาม seed data และ code); default = `th` (ไม่ใช่ `MIXED` ตามที่ spec เดิมระบุ); frontend เพิ่ม `mixed` option แล้ว (2026-06-15); backend `@IsString()` ไม่มี enum constraint — accept any string; spec FR-020 + ADR-037 อัปเดตแล้ว
- **"Sandbox Step 3 ใช้ selected version หรือ active version ของ rag_prep_prompt"** — resolved: **ใช้ Active Prompt เสมอ** (`getActive('rag_prep_prompt')`) — RAG Prep เป็น global chunking operation ไม่ผูกกับ version ที่กำลังทดสอบ; Step 2 (ocr_extraction) ใช้ selected version ได้เพราะเป็น version ที่ admin กำลัง evaluate แต่ Step 3 ทดสอบ embedding quality ของ active chunking strategy (ADR-037)
- **"Step 3 RAG Prep sandbox ใช้ BGE-M3 standalone หรือ Sidecar"** — resolved: ใช้ `OcrService.embedViaSidecar()` (OCR Sidecar `/embed` endpoint) ไม่ใช่ BGE-M3 standalone; LLM (`np-dms-ai`) ทำ semantic chunking ผ่าน `rag_prep_prompt` template (`{{text}}`) → parse `<chunk>` XML tags → embed แต่ละ chunk ผ่าน sidecar; ผลลัพธ์เก็บใน Redis 60 min TTL เท่านั้น **ไม่ commit ลง Qdrant**; queue = `ai-batch` ไม่ใช่ `ai-realtime` (ADR-037, 2026-06-15)
- **"ชื่อ placeholder ใน Prompt Template"** — resolved: ใช้ชื่อตาม code/processor จริงเป็น canonical (`{{query}}`, `{{context}}`, `{{text}}`, `{{document_text}}`) ไม่ใช่ชื่อ spec เดิมที่ semantic กว่า (`{{user_query}}`, `{{retrieved_chunks}}`, `{{document_metadata}}`); `{{master_data_context}}` เป็น optional ใน `ocr_extraction` ไม่ block save; ADR-037 + spec.md FR-023FR-026 ถูกอัปเดตให้ตรงกับ code แล้ว (2026-06-15)
- **"ADR-036 systemPrompt เก็บที่ไหน"** — resolved: systemPrompt อยู่ใน `ai_prompts` (**Active Prompt**, ADR-029, versioned, มี `{{ocr_text}}`) เท่านั้น — ห้ามเก็บใน `ai_execution_profiles` หรือ `system_settings`
- **"ADR-036 OCR tunability"** — resolved: OCR tunable params = **`temperature`/`top_p`/`repeat_penalty`** เท่านั้น (ตรงกับ `OcrTyphoonOptions`) เก็บเป็น row `ocr-extract` ใน `ai_execution_profiles` พร้อมเพิ่ม column `canonical_model`; `num_ctx`/`max_tokens` nullable (OCR ไม่ใช้); **`keep_alive` ไม่ tunable** — ใช้ Adaptive OCR Residency (ADR-033) ดู Gap 2
- **"ADR-036 read semantics (Apply to Production)"** — resolved: คง **Snapshot semantics** — params ถูกแช่แข็งลง job payload ณ เวลา dispatch (`createJobPayload()`); ค่าที่ admin apply มีผลกับงานใหม่เท่านั้น ไม่แทรกงานที่ค้างคิว (รักษา reproducibility + audit `snapshot_params_json`)