# Artifact Plan: Modular Parsing Benchmark Pipeline

**Tanggal:** 13 Mei 2026

## Deskripsi
Dokumen ini merupakan perencanaan artefak (artifact plan) untuk pengembangan script benchmarking modular yang dikhususkan pada tahap pertama dari pipeline ingestion, yaitu **Parsing**. Script ini bertujuan untuk mengukur performa `HybridParser` terhadap dokumen PDF nyata, mendeteksi kegagalan secara real-time, memantau penggunaan *resource* (RAM & CPU), dan menyimpan metrik secara kumulatif dalam matriks, serta artefak hasil parsing untuk peninjauan manual.

## Metodologi
- **Modular Testing:** Pengujian dipisahkan per tahap. Fase ini hanya fokus pada tahap Parsing.
- **Real-Time Logging:** Hasil benchmarking langsung ditambahkan (append) ke dalam tabel matriks setelah satu dokumen selesai diproses, sehingga fail-safe jika terjadi crash di tengah antrean.
- **Separation of Concerns:** Memisahkan log metrik (Markdown), log error (Plain Text), dan hasil artefak (Markdown files) ke dalam folder yang spesifik.

## Keputusan
1. **Opsi Matriks:** Menggunakan Opsi 2 (Diagnostik Mendalam) yang **ditambah** dengan pemantauan *resource* sistem (Peak RAM dan Peak CPU menggunakan `psutil`). 
2. **Penyimpanan Output:**
   - **Artefak Parsing:** `archive/Testing-Pipeline/benchmark-parsing/Output-Parsing/`
   - **Log Error:** `archive/Testing-Pipeline/benchmark-parsing/Log-Error/parsing_errors.log`
   - **Matriks Performa:** `archive/Testing-Pipeline/benchmark-parsing/Perform-Matrix/performance_matrix_parsing.md`
   - **Lokasi Script:** `scripts/Testing-Pipeline/benchmark_parsing.py`
3. **Penanganan Error:** Error saat parsing tidak akan membuat matriks berantakan. Status pada matriks akan ditulis `❌ Failed`, sedangkan *stack trace* dan detail error ditulis ke log error terpisah.
4. **Mode Eksekusi:** Menggunakan mode eksekusi tunggal dengan *hardcoded* target file di dalam script untuk kemudahan pengujian awal.
5. **Auto-Directory Creation:** Script harus memvalidasi dan membuat semua struktur folder (Output, Log, Matrix) secara otomatis saat dijalankan.

## Alur Diagram

```mermaid
flowchart TD
    A[Mulai Benchmark] --> B{Cek Struktur Folder}
    B -- Belum Ada --> C[Buat Folder Output, Log, Matrix]
    B -- Sudah Ada --> D[Baca Target PDF]
    C --> D
    D --> E[Inisialisasi HybridParser]
    E --> F[Hitung Total Halaman PDF]
    F --> G[Catat RAM/CPU Awal & Mulai Timer]
    G --> H[parser.parse_pdf]
    
    H -- Berhasil & Ada Output --> I[Simpan Teks ke Output-Parsing]
    I --> J[Tulis Status: Success]
    
    H -- Berhasil tapi Kosong --> K[Tulis Status: Warning / Kosong]
    
    H -- Exception/Crash/Timeout --> L[Tulis Traceback ke Log-Error/parsing_errors.log]
    L --> M[Tulis Status: Failed]
    
    J --> N[Hentikan Timer & Catat RAM/CPU Akhir]
    K --> N
    M --> N
    
    N --> O[Append Baris ke Perform-Matrix/performance_matrix_parsing.md]
    O --> P[Selesai]
```

## Struktur Folder (Tree)

```text
backend-sre/
├── Markdown/
│   └── Testing-Pipeline/
│       └── Parsing-Benchmark/
│           └── Plan/
│               └── artifact_plan.md      <-- (File ini)
├── scripts/
│   └── Testing-Pipeline/
│       └── benchmark_parsing.py          <-- (Script yang akan dibuat)
└── archive/
    └── Testing-Pipeline/
        └── benchmark-parsing/
            ├── Perform-Matrix/
            │   └── performance_matrix_parsing.md
            ├── Log-Error/
            │   └── parsing_errors.log
            └── Output-Parsing/
                ├── RAGAS_Automated_Evaluation..._parsed.md
                └── SciLit_Joint_Literature..._parsed.md
```

## Asumsi & Batasan
- **Asumsi:** `HybridParser` dapat dijalankan secara independen tanpa bergantung pada service lain selain *library* parser internal (misalnya PyMuPDF/Tesseract).
- **Asumsi:** Direktori dokumen PDF sumber berada di folder `Literature/` pada root project.
- **Batasan Utama (STRICT):** Script pengujian **TIDAK BOLEH** menyentuh, mengubah, atau memodifikasi script yang sudah paten di dalam folder `app/` (seperti `app/services/parser/hybrid_parser.py`).
- **Dampak Batasan:** Karena kita dilarang memodifikasi `HybridParser`, jika parser tersebut saat ini tidak mengembalikan informasi terkait `Text Pages`, `OCR Pages`, atau `OCR Timeout Count`, maka script benchmark akan mencoba mengkalkulasi semampunya dari luar (misal membandingkan total halaman `fitz` dengan waktu eksekusi), atau mencatatnya sebagai `N/A` di dalam matriks.

## Konsep Tabel Matriks

File: `archive/Testing-Pipeline/benchmark-parsing/Perform-Matrix/performance_matrix_parsing.md`

| Timestamp | Document | Pages | Text Pgs | OCR Pgs | Peak RAM (MB) | Peak CPU (%) | Total Time (s) | Output Length | OCR Timeouts | Status | Note |
| :--- | :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :--- | :--- |
| 2026-05-13 14:00:00 | RAGAS_Automated... | 8 | N/A | N/A | 150.5 | 25.0 | 24.50 | 32450 | N/A | ✅ Success | - |
| 2026-05-13 14:05:00 | SciLit_Joint_... | 12 | N/A | N/A | 210.2 | 40.5 | 38.20 | 45120 | N/A | ✅ Success | - |
| 2026-05-13 14:10:00 | Corrupt_File... | 5 | N/A | N/A | 80.0 | 10.0 | 150.00 | 0 | N/A | ❌ Failed | Lihat log |

*(Catatan: Nilai `N/A` akan digunakan jika nilai tersebut tidak dapat diambil tanpa memodifikasi script di `app/`).*

## Konsep Prompting (Konvensi Kode)
*(Catatan: Konsep di bawah ini merupakan panduan implementasi kode / Code Constraints bagi agen yang akan menulis script).*

**Instruksi Acuan Implementasi Kode (Developer Prompting):**
1. Pastikan sanitasi nama file difilter secara ketat menggunakan regex: `re.sub(r'[^a-zA-Z0-9]', '_', name)` untuk menghindari path error di OS manapun.
2. Selalu gunakan `try...except Exception as e` pada blok `parser.parse_pdf()`. Tangkap nama *exception* menggunakan `type(e).__name__` dan traceback penuh menggunakan modul `traceback.format_exc()`.
3. Tulis file matriks dan error log *wajib* menggunakan metode akses file `"a"` (append).
4. Gunakan `psutil` untuk memantau pemakaian memory dan cpu sebelum dan setelah proses `parse_pdf`. (misal: jalankan `process = psutil.Process()`, cek `process.memory_info().rss` dan kalkulasi persentase CPU).
5. Pemotongan panjang nama di tabel matriks harus diatur maksimal ~45-50 karakter dengan sufiks `...`.
6. Patuhi batasan mutlak: **JANGAN MENGUBAH FILE APAPUN DI FOLDER `app/`**.

## Langkah Implementasi
1. Buat struktur folder di dalam `archive/Testing-Pipeline/benchmark-parsing` yang mencakup `Output-Parsing/`, `Log-Error/`, dan `Perform-Matrix/`.
2. Buat script utama di `scripts/Testing-Pipeline/benchmark_parsing.py`.
3. Tuliskan fungsi *helper* `sanitize_filename(name)` untuk merapikan judul PDF.
4. Susun fungsi *helper* `append_to_matrix(...)` yang meng-handle pembuatan header dan *append* baris data metrik.
5. Susun fungsi *helper* `append_to_error_log(doc_name, error_exc)` yang me-load timestamp dan detail stack trace.
6. Setup *Hardcoded Parameter*: `TARGET_PDF = "Literature/RAGAS Automated Evaluation of Retrieval Augmented Generation.pdf"`.
7. Eksekusi `fitz.open(TARGET_PDF)` untuk mendapatkan total halaman secara cepat dan langsung (*fail-safe* menggunakan blok *try/except*).
8. Instansiasi `parser = HybridParser()`, rekam `start_time`, `start_ram`, dan monitoring `cpu`, lalu jalankan parser.
9. Evaluasi balasan:
   - Jika teks ditemukan dan tidak kosong: Tetapkan status "✅ Success". Tulis teks ke `Output-Parsing/nama_disanitasi_parsed.md`.
   - Jika teks kosong: Tetapkan status "⚠️ Warning" dan beri catatan "Output kosong".
   - Jika *crash* (masuk block *except*): Tetapkan status "❌ Failed", panggil fungsi `append_to_error_log`.
10. Rekam metrik RAM/CPU puncak, serta `total_time`, dan jalankan `append_to_matrix()` untuk mencatat keseluruhan ke matriks.

## Tabel Eksekusi Task

| [ ] | Fase | Task | Detail Task | Deskripsi | Acceptance Criteria |
|:---:|:---|:---|:---|:---|:---|
| [x] | 1 | Setup Direktori | Membuat logika pembuatan folder bersarang | Menulis fungsi Python `ensure_dirs()` yang akan membuat `Output-Parsing`, `Log-Error`, dan `Perform-Matrix` di dalam `archive/Testing-Pipeline/benchmark-parsing`. | Saat script dijalankan, ketiga folder output tersebut harus otomatis terbuat jika belum ada. |
| [x] | 1 | Helper Functions | Sanitasi nama file | Membuat fungsi `sanitize_filename(name)` dengan regex. | Nama file seperti "Doc (2)!.pdf" menjadi "Doc_2_.pdf". |
| [x] | 1 | Helper Functions | Append Matriks | Membuat fungsi `append_to_matrix()` untuk menambahkan baris baru. | Jika file matriks belum ada, header tabel dibuat lengkap dengan kolom metrik. Jika sudah ada, tambahkan row di bawah. |
| [x] | 1 | Helper Functions | Append Error Log | Membuat fungsi `append_to_error_log()`. | File `parsing_errors.log` di dalam `Log-Error/` terisi timestamp, tipe error, dan stack trace lengkap secara append. |
| [x] | 2 | Main Script | System Monitoring | Menggunakan library `psutil` untuk mencatat metrik CPU dan RAM. | Penggunaan `Peak RAM (MB)` dan `Peak CPU (%)` terukur dengan valid selama proses parsing berjalan. |
| [x] | 2 | Main Script | Parsing Logic & Strict Constraint | Memanggil `parser.parse_pdf(file)`. Mencatat metrik yang memungkinkan **TANPA** menyentuh code `app/`. | Eksekusi parser jalan. File di folder `app/` dipastikan utuh. Metrik Text/OCR Pages diisi `N/A` jika tidak dikembalikan. |
| [x] | 2 | Main Script | Output Handling | Menyimpan hasil teks Markdown ke folder `Output-Parsing/`. | Terbentuk file `archive/Testing-Pipeline/benchmark-parsing/Output-Parsing/RAGAS..._parsed.md` yang isinya persis dengan output parser. |
| [x] | 2 | Main Script | Error Handling | Membungkus proses parse dengan `try...except Exception as e`. | Jika terjadi error, log masuk ke `Log-Error/` dan status Failed masuk ke matriks di `Perform-Matrix/`. Script tidak berhenti tiba-tiba. |
| [x] | 3 | Testing | Uji Coba Dokumen 1 | Menjalankan script menggunakan target `Literature/RAGAS Automated Evaluation of Retrieval Augmented Generation.pdf` | Terdapat 1 baris di matriks, dan 1 file output .md. Tabel memuat kolom RAM dan CPU. |
| [x] | 3 | Testing | Uji Coba Dokumen 2 | Mengganti *hardcoded* target file di script menjadi dokumen `SciLit` dan menjalankannya lagi. | Terdapat baris ke-2 di matriks, log dan matrix lama tidak tertimpa. Artefak output SciLit terbuat di Output-Parsing. |
