KB-6356
S175 Why Round 2 - Gemini RCA Report
2 min read Revision 1
WHY-1: Event sync miss
- Root cause 1 dòng: Sync logic là "fire-and-forget" async, thiếu cơ chế retry hoặc lock khi có nhiều update dồn dập (race condition), dẫn đến việc Directus PATCH có thể nhận data từ một state trung gian của AD thông qua API GET /kb/get/.
- Evidence:
agent_data/event_system.py:418(emit_fire_and_forget),agent_data/directus_sync.py:143(_fetch_document), log AD cho thấy chuỗiPUT/PATCH/PATCHdồn dập chond-36-01trong cùng 1 giây. - Mức độ chắc chắn: CAO
WHY-2: Schema cho phép duplicate
- Root cause 1 dòng: Bảng
knowledge_documentsthiếu UNIQUE constraint trênsource_idhoặcfile_path, trong khi logicdirectus_sync.pychỉ tìm và update record ĐẦU TIÊN nó thấy (limit: 1). - Evidence: SQL
\d knowledge_documentschỉ cóUNIQUE (slug), không có unique chosource_id.agent_data/directus_sync.py:128sử dụnglimit: 1khi lookup. - Mức độ chắc chắn: CAO
WHY-3: limit=500 hardcode
- Root cause 1 dòng: Các script vận hành (DOT) và Nuxt composables hardcode
limit: 500để "tối ưu" thay vì dùng pagination, dẫn đến việc miss dữ liệu khi collection vượt ngưỡng này (hiện tại 618 rows). - Evidence:
dot/bin/dot-knowledge-sync-agentdata:87,web/composables/useKnowledgeTree.ts:101. Directus SDK default limit là 100. - Mức độ chắc chắn: CAO
Observations phụ
- Risk ẩn:
is_current_versionđang bị hardcodeTruetrong mọi payload push từ AD (directus_sync.py:186), dẫn đến tình trạng nhiều row cùng là "current" cho một document nếu AD push doc mới mà không revoke row cũ. - Pattern: Hệ thống đang lạm dụng "upsert by code" (find-then-patch) thay vì "upsert by database constraint", gây ra race condition và duplicates khi logic tìm kiếm bị giới hạn (limit 1).