# Flow 2D: Neo4j Storage & Edge Generation (The Gauntlet)

Fase ini adalah tempat di mana data yang telah diekstrak dan divektorisasi pada Flow 2C akhirnya disimpan ke dalam Neo4j. Karena pembentukan relasi (*edge*) yang sembarangan dapat menyebabkan "halusinasi graf", sistem menerapkan serangkaian gerbang validasi berlapis (*The Gauntlet*). 

Mengingat kompleksitasnya, fase ini dipecah menjadi tiga diagram terpisah.

---

## 1. Dynamic Threshold & Multi-Tenant Gate
Tahap pertama berfokus pada injeksi Node baru dan pencarian kandidat tetangga. Sistem membaca ambang batas (*threshold*) dari konfigurasi lokal yang dikalibrasi oleh *Cron Job* (Z-Score) dan menerapkan isolasi data secara ketat.

```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 reject fill:#ffebee,stroke:#c62828,stroke-width:2px;

    Start(["Vectors &amp; Pillars (Dari Flow 2C)"]):::init --> MergeNode
    
    MergeNode[("MERGE Node (Neo4j)<br/>Set project_id &amp; Vectors")]:::database --> ReadJSON
    
    ReadJSON["get_current_thresholds()<br/>Baca config/thresholds.json"]:::logic --> CheckJSON
    
    CheckJSON{"JSON Valid?"}:::logic
    CheckJSON -- "Ya" --> ThresholdZ["Gunakan Dynamic Threshold<br/>(Z-Score per Pilar)"]:::logic
    CheckJSON -- "Tidak" --> ThresholdF["Gunakan Static Fallback<br/>Threshold"]:::logic
    
    ThresholdZ --> VectorSearch
    ThresholdF --> VectorSearch
    
    VectorSearch[("Vector Search KNN<br/>(Neo4j)")]:::database --> FilterProject
    
    FilterProject{"Isolasi Multi-Tenant:<br/>target.project_id == source.project_id?"}:::logic
    FilterProject -- "Tidak" --> Reject1(["Reject (Beda Workspace)"]):::reject
    
    FilterProject -- "Ya" --> FilterScore{"Skor >= Threshold Pilar?"}:::logic
    FilterScore -- "Tidak" --> Reject2(["Reject (Di Bawah Ambang Batas)"]):::reject
    
    FilterScore -- "Ya" --> PassGate1(["Lolos ke Coherence Gate"]):::init
```

---

## 2. Coherence Gate
Setelah menemukan kandidat yang secara matematis mirip (lolos dari Gate 1), sistem memastikan bahwa kemiripan tersebut masuk akal secara logis. Target harus memiliki kecocokan di beberapa pilar yang saling mendukung, tidak boleh berdiri sendiri secara acak.

```mermaid
flowchart TD
    classDef init fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
    classDef logic fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
    classDef reject fill:#ffebee,stroke:#c62828,stroke-width:2px;

    Start(["Kandidat Lolos Gate 1"]):::init --> Grouping
    
    Grouping["Bundle Candidates by Target<br/>Kumpulkan skor berdasarkan Target ID"]:::logic --> MinMatch
    
    MinMatch{"Minimal 3 Pilar Cocok?<br/>(COHERENCE_MIN_MATCHED_PILLARS)"}:::logic
    MinMatch -- "Tidak" --> Reject3(["Reject (Single/Double Pillar Match)"]):::reject
    
    MinMatch -- "Ya" --> RuleCheck{"Sesuai COHERENCE_GATE_RULES?"}:::logic
    
    RuleCheck -- "Tidak (Misal: Methodology tanpa Objective/Gap)" --> Reject4(["Reject (Anchor tanpa Support)"]):::reject
    
    RuleCheck -- "Ya" --> PassGate2(["Lolos ke Domain &amp; Reasoning Gate"]):::init
```

---

## 3. Domain & Reasoning Gate
Gerbang terakhir dan yang paling berat. Di sini, kecerdasan LLM diuji untuk memvalidasi kesamaan *domain* penelitian (melalui *keywords*) dan memaksa LLM menghasilkan kalimat *reasoning* yang spesifik dan empiris (bukan sekadar "kedua jurnal ini mirip").

```mermaid
flowchart TD
    classDef init fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
    classDef logic fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
    classDef ai fill:#00A4A6,stroke:#232F3E,stroke-width:2px,color:#FFFFFF;
    classDef database fill:#3355CC,stroke:#232F3E,stroke-width:2px,color:#FFFFFF;
    classDef reject fill:#ffebee,stroke:#c62828,stroke-width:2px;

    Start(["Kandidat Lolos Gate 2"]):::init --> EvalDomain
    
    %% Domain Gate
    EvalDomain["LLM: Evaluasi Kompatibilitas Domain<br/>(Source Keywords vs Target Keywords)"]:::ai --> CheckDomain
    
    CheckDomain{"Domain Cocok?"}:::logic
    CheckDomain -- "Tidak" --> Reject5(["Reject (Domain Mismatch)"]):::reject
    
    %% Reasoning Generation
    CheckDomain -- "Ya" --> GenReasoning
    GenReasoning["LLM: Generate Edge Reasoning<br/>(1 Paragraf Spesifik per Pilar)"]:::ai --> ValidateReasoning
    
    %% Reasoning Quality Check
    ValidateReasoning{"Reasoning Quality Gate:<br/>- >= 15 Kata?<br/>- Ada Specificity Keywords?<br/>- Tidak Ada Pola Generik?"}:::logic
    
    ValidateReasoning -- "Tidak" --> Reject6(["Reject (Alasan Generik/Lemah)"]):::reject
    
    %% Final Merge
    ValidateReasoning -- "Ya" --> BatchMerge
    
    BatchMerge[("Batch MERGE Edge (Neo4j)<br/>SIMILAR_*, Skor, dan Reasoning")]:::database --> End
    
    End(["Selesai (Node &amp; Edge Terhubung)"]):::init
```