# Flow 2B: Smart Chunking & Data Purification (JIT V2)

Diagram ini mengilustrasikan fase kedua dari *Ingestion Pipeline*, di mana Markdown mentah diubah menjadi potongan data terstruktur. Fokus utama fase ini adalah **Multi-Level Chunking** untuk presisi pencarian, **Dual-Path Storage** untuk menjaga data asli, dan **JIT (Just-In-Time) Purification V2** yang ekstrem untuk mencegah LLM berhalusinasi akibat menelan "data sampah".

```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 purify fill:#fff3e0,stroke:#f57c00,stroke-width:2px;
    classDef discard fill:#ffebee,stroke:#c62828,stroke-width:2px;

    Start(["Raw Markdown (Dari Flow 2A)"]):::init --> CheckValid{"Markdown<br/>Kosong?"}:::logic
    CheckValid -- "Ya" --> Abort(["Abort (Failed)"]):::discard
    
    CheckValid -- "Tidak" --> RawChunks["Generate Raw Chunks<br/>(Untuk Supabase)"]:::logic
    RawChunks --> SplitStorage{Pemisahan<br/>Alur Penyimpanan}:::logic

    %% Path 1: Non-Destructive Storage
    SplitStorage -- "Path 1: Asinkron" --> QueueSupabase["Upload Queue<br/>(Supabase Worker)"]:::logic
    QueueSupabase --> Supabase[("Supabase DB<br/>document_chunks")]:::database
    
    %% Path 2: Multi-Level Chunking & Upstream Filter
    SplitStorage -- "Path 2: Memori" --> HeaderFilter{"Header Blok Teks<br/>Blacklisted?<br/>(Irrelevant_Headers)"}:::purify
    HeaderFilter -- "Ya" --> DropBlok(["Buang Satu Bab Penuh"]):::discard
    
    HeaderFilter -- "Tidak" --> MultiLevel["Generate Parent &amp; Child Chunks"]:::logic
    MultiLevel --> ParentChunk["Parent Chunks<br/>(1500 chars)"]:::logic
    MultiLevel --> ChildChunk["Child Chunks<br/>(200 chars, linked to Parent ID)"]:::logic
    
    %% JIT Purification V2
    ParentChunk --> FilterJIT["JIT Purification V2 (On-the-Fly)<br/>(Filter Berdasarkan Isi Teks)"]:::purify
    ChildChunk --> FilterJIT
    
    FilterJIT --> CheckRef{"Mengandung Referensi /<br/>Ucapan Terima Kasih?"}:::purify
    CheckRef -- "Ya" --> Trash(["Buang Chunk (Noise)"]):::discard
    CheckRef -- "Tidak" --> CleanRegex["Bersihkan Residu OCR,<br/>Tabel &amp; Email via Regex"]:::purify
    
    CleanRegex --> CheckLength{"Panjang Teks<br/>Memadai?"}:::purify
    CheckLength -- "Tidak" --> Trash
    
    CheckLength -- "Ya" --> PurifiedChunks["Purified Parent &amp; Child Chunks"]:::init
    PurifiedChunks --> NextPhase(["Lanjut ke Flow 2C: Ekstraksi &amp; Embedding"]):::init
```

### Penjelasan Detail (Kombinasi A, B, dan C):
1. **Penyimpanan Dual-Path (Non-Destructive Storage):** Sistem mencabangkan aliran data tepat setelah chunk mentah (Raw Chunks) dihasilkan. Chunk mentah dikirim ke *Upload Queue* untuk disimpan selamanya di Supabase tanpa dimodifikasi. Ini memastikan kita tidak pernah merusak atau kehilangan data asli.
2. **Upstream Header Filtering:** Sebelum teks dipotong menjadi Multi-Level Chunk di RAM, teks akan diperiksa berdasarkan judul bab-nya (menggunakan array `IRRELEVANT_HEADERS`). Jika judulnya "Daftar Pustaka" atau "Appendix", seluruh bab tersebut dibuang agar tidak perlu diproses di tahap selanjutnya.
3. **Hierarki Multi-Level Chunking:** Teks yang lolos dari filter *header* dipecah menjadi dua level. *Parent Chunks* berukuran besar (1500 karakter) untuk memberikan konteks yang kaya saat dibaca oleh LLM. *Child Chunks* berukuran sangat kecil (200 karakter) dan tertaut ke *Parent* via `parent_id`, berfungsi semata-mata sebagai "target bidik" yang tajam untuk pencarian vektor (E5-Small).
4. **JIT Purification V2 (Saringan Isi Teks Ekstrem):** Untuk teks sampah yang *lolos* dari filter *header* (misal: penulis lupa memberi judul bab), sistem melakukan pembersihan tingkat kedua (*Just-In-Time*) sesaat sebelum digunakan. Pola seperti `[1]`, `(Smith, 2020)`, "Ucapan Terima Kasih", serta blok teks tabel dari OCR dihancurkan via *Regex*. Ini menggaransi bahwa ruang vektor terbebas dari polusi semantik.
