# Flow 2E: Background Maintenance (Cron Job)

Fase ini menjelaskan mekanisme asinkron yang menjaga sistem Knowledge Graph tetap akurat seiring bertambahnya data. Berjalan secara terjadwal setiap pukul 02:00 AM, skrip `update_global_threshold.py` bertugas mengkalibrasi *noise floor* (tingkat kemiripan acak) dari seluruh *database* secara global, dan menuliskan ambang batas (*threshold*) baru yang aman untuk digunakan oleh fase *Ingestion* utama keesokan harinya.

```mermaid
flowchart TD
    classDef init fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
    classDef logic fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
    classDef database fill:#3355CC,stroke:#232F3E,stroke-width:2px,color:#FFFFFF;
    classDef math fill:#ffeb3b,stroke:#e65100,stroke-width:3px,color:#212121;
    classDef exit fill:#ffebee,stroke:#c62828,stroke-width:2px;

    Start((Start: 02:00 AM)):::init --> ReadLastUpdate
    
    %% Pre-flight Check (Safety Guard)
    ReadLastUpdate["Baca _metadata.last_updated<br/>dari config/thresholds.json"]:::logic --> CountNewNodes
    CountNewNodes[("Hitung Node Baru<br/>di Neo4j")]:::database --> PreFlightCheck
    
    PreFlightCheck{"Node Baru > 100?<br/>(NEW_NODES_THRESHOLD)"}:::logic
    PreFlightCheck -- "Tidak" --> AbortPreFlight(["Abort (Pertahankan State Lama)"]):::exit
    PreFlightCheck -- "Ya" --> LoopPillars
    
    %% The Math & Sampling
    LoopPillars["Looping untuk 5 Pilar:<br/>BG, MET, GAP, OBJ, FUT"]:::logic --> SampleNeo4j
    
    SampleNeo4j[("Ambil 500 Pasangan Acak<br/>(Global Tanpa Filter project_id)")]:::database --> CalcCosine
    
    CalcCosine["Hitung Cosine Similarity<br/>Setiap Pasangan"]:::logic --> StatsMath
    
    subgraph Statistics ["📐 Z-Score Calibration (Math)"]
        direction TB
        StatsMath["Hitung Mean (μ)<br/>&amp; Standard Deviation (σ)"]:::math --> ZScore
        ZScore["Kalkulasi Z-Score:<br/>Threshold = μ + 3σ"]:::math --> ApplyMult
        ApplyMult["Terapkan Bobot:<br/>Threshold = Z-Score × Section_Multiplier"]:::math
    end
    
    ApplyMult --> RecordResult["Simpan Hasil Sementara"]:::logic
    
    RecordResult --> NextPillar{"Ada pilar lain?"}:::logic
    NextPillar -- "Ya" --> LoopPillars
    
    %% Final Safety & Write
    NextPillar -- "Tidak" --> GuardIncomplete
    
    GuardIncomplete{"Hasil Lengkap 5 Pilar?"}:::logic
    GuardIncomplete -- "Tidak" --> AbortIncomplete(["Abort (Cegah Konfigurasi Rusak)"]):::exit
    
    GuardIncomplete -- "Ya" --> WriteJSON
    WriteJSON["Overwrite config/thresholds.json<br/>(Dengan Metadata Baru)"]:::logic --> End
    
    End(["Selesai (Kalibrasi Berhasil)"]):::init
```

### Penjelasan Detail (Kombinasi Safety & Math):
1. **Safety Mechanism (Pre-Flight Check):** Sistem tidak akan membakar sumber daya komputasi secara sia-sia. Begitu skrip berjalan, ia memeriksa jumlah dokumen baru sejak kalibrasi terakhir. Jika dokumen baru kurang dari 100, skrip membatalkan operasinya secara diam-diam.
2. **Global Sampling:** Saat mengambil 500 pasangan acak untuk dianalisis, skrip secara sengaja *tidak menggunakan* filter `project_id`. Tujuannya adalah untuk mendapatkan gambaran *noise floor* (tingkat "kebisingan" atau kemiripan acak) yang sesungguhnya di seluruh sistem, memastikan bahwa ambang batas yang dihasilkan bersifat obyektif.
3. **The Math (Statistik Z-Score):** Sistem menggunakan distribusi normal matematis. Ia menghitung rata-rata kemiripan (*Mean* / μ) dan deviasi standarnya (σ). Angka dasar didapat dari `μ + 3σ` (yang menjamin 99.7% probabilitas bahwa kemiripan itu nyata, bukan kebetulan). Setelah itu, angka tersebut dikalikan dengan `Section_Multiplier` khusus (misalnya 1.15x untuk "Gap" karena harus lebih ketat).
4. **Final Guard:** Jika salah satu pilar gagal dihitung karena alasan apa pun (misal API terputus), skrip akan menggugurkan seluruh proses penulisan. Ini menjamin bahwa `config/thresholds.json` tidak pernah menyimpan data yang cacat atau parsial.
