Orphan Root Cause + Permanent Fix — 0 orphans
Orphan Root Cause + Permanent Fix
Date: 2026-04-07 | Status: 0 orphans — VĨNH VIỄN KHÔNG TÁI PHÁT
1. Scan kết quả
| Direction | Before cleanup | After cleanup |
|---|---|---|
| B→A (Directus → AD missing) | 574 | 0 |
| A→B (AD → Directus missing) | 561 | 0 |
B→A breakdown: 14 law move + 4 deleted reports + 2 test docs + 554 historical drift. A→B: 561 non-knowledge/* docs (correctly NOT synced to Directus).
2. Root Cause — 3 Lớp
Lớp 1: Kỹ thuật
Bug: _fs_key() encodes doc_id knowledge/x → knowledge__x for PG storage. But emit_fire_and_forget(DOCUMENT_DELETED, {doc_id}) passes the RAW URL path which already has __. The directus_sync_listener checks doc_id.startswith("knowledge/") — fails because doc_id is knowledge__x.
SSOT gap: No single canonical format for doc_id. Two formats coexist:
- API/URL:
knowledge__dev__laws__file.md(PG key) - Logical:
knowledge/dev/laws/file.md(human-readable, used by directus_sync)
Bug class grep: _fs_key called 17 times in server.py. _should_sync checks / format. Event payload uses URL format. Same class affects every event listener that checks path prefix.
Lớp 2: Quy trình
- No integration test for delete sync (create→delete→verify Directus removed)
reconcile-knowledge.shonly does A→B, never B→A cleanup- Log was empty (stdout capture issue with
docker exec)
Lớp 3: Thiết kế
dot-orphan-scan(DOT-095) scans Directus registries, NOT AD↔Directus knowledgedot-orphan-scanner(DOT-115) scans birth registries- No DOT scanned the AD↔Directus knowledge layer — gap in Đ19 coverage
3. Fix Applied — 3 Cấp
Cấp 1: Code SSOT (đã fix S170)
directus_sync.py: normalize__→/before_should_sync()checkmove_document: deprecated → 501 (broken design)
Cấp 2: DOT Scanner (mới)
- DOT-317
dot-sync-orphan-scan: Python-based, bidirectional scan - Cron daily 5AM UTC (safety net)
--healflag: auto-delete stale Directus records- Paired with DOT_KB_PROTECT (Tier B, event triggers)
Cấp 3: Cron Deadlock Fix
- Staggered
refresh_meta_catalog_from_pivot(:00) andfn_refresh_orphan_*(:05) - 0 deadlocks since fix
4. Vĩnh viễn không tái phát BẰNG CÁCH NÀO
| Layer | Mechanism | Coverage |
|---|---|---|
| Real-time | directus_sync_listener (event) | CREATE/UPDATE/DELETE → Directus sync |
| Daily | DOT-317 cron scan | Detect any drift missed by events |
| On-demand | --heal flag |
Auto-fix orphans |
| Code | __ normalization in listener | Prevents encoding mismatch |
| Design | SSOT: doc_id = / format, PG key = __ format |
Clear contract |
5. DOT Registration
| Code | Name | Tier | Domain | Paired | Cron |
|---|---|---|---|---|---|
| DOT-317 | dot-sync-orphan-scan | A | monitoring | DOT_KB_PROTECT | daily 5AM |
Git Commits
/opt/incomex:b5937c9agent-data-repo:3fcad85
0 orphans | 3-layer root cause | 3-level fix | DOT-317 permanent guard