think
16px
820px

Plan — Fix klasifikasi dokumen pendukung Berakhirnya

Konteks: Reproduksi via Playwright (UI http://localhost:47023/klasifikasi, sample sample-berakhirnya, txn PT BIS 4026062431700115). Deteksi paket sudah benar (banner "Terdeteksi: Berakhirnya Status Badan Hukum PT", tombol "Lanjut ke Ekstraksi" aktif), tetapi 4 dari 6 dokumen pendukung salah lane.

1. Hasil reproduksi

Dokumen Seharusnya GPU classifier Conf
Salinan Akta Berakhirnya AKTA_BERAKHIRNYA AKTA_BERAKHIRNYA 0.9998
Keputusan Sirkuler BERITA_ACARA_RUPS BERITA_ACARA_RUPS 0.9997
Pengumuman Koran Likuidasi BUKTI_PENGUMUMAN_149 OTHER 0.9999
Pengumuman Koran Ps.152 BUKTI_PENGUMUMAN_152 SURAT_KETERANGAN_BANK 0.9565
Laporan Pertanggungjawaban Likuidator LAPORAN_LIKUIDASI BERITA_ACARA_RUPS 0.9996
Surat Permohonan Berakhirnya SURAT_PERMOHONAN AKTA_BERAKHIRNYA 0.6617

2. Akar masalah

Model classifier GPU (ahu-doc-classifier, engine hands-off) tidak punya kelas untuk dokumen pendukung Berakhirnya, dan alih-alih abstain ia mengembalikan label lain dengan confidence tinggi (confidently wrong). Tier koreksi di repo ini (backend/src/routes/klasifikasi.ts) justru di-gate pada confidence rendah, jadi jaring pengaman tidak pernah aktif.

flowchart TD GPU[GPU classifier
confidently wrong] --> RA[refineAktaLabel] RA --> RS{refineSupportingLabel} RS -->|"label AKTA_* / BERITA_ACARA_RUPS
→ return early"| OUT[label salah dipertahankan] RS -->|"confidence >= 0.6
→ return early"| OUT RA --> LT{letter-confirm LLM tail} LT -->|"confidence >= 0.6 ATAU
label AKTA_* → skip"| OUT OUT --> BOARD[Lane salah di board]

Tiga blocker konkret di klasifikasi.ts:

  1. refineSupportingLabel (≈line 138): if (label.startsWith("AKTA_") || label === "BERITA_ACARA_RUPS") return label; lalu if (confidence >= config.classifierMinConfidence) return label;
    → Laporan Likuidasi (GPU BERITA_ACARA_RUPS @0.9996) dobel-blokir.
  2. Letter-confirm LLM tail (≈line 498): if (confidence < minConfidence && !refinedClassification.startsWith("AKTA_"))
    → Koran (OTHER/BANK @≥0.95) diblokir confidence tinggi; Surat Permohonan (AKTA_BERAKHIRNYA) diblokir prefix AKTA_.
  3. refineAktaLabel tidak membedakan surat permohonan (yang menyebut "berakhirnya status badan hukum") dari akta-nya → menahan AKTA_BERAKHIRNYA.

Yang penting: suggestByKeyword (head-anchored LAPORAN/PERMOHONAN, axis _149/_152) + classifyBerakhirnyaSupportingViaLlm sudah dirancang untuk keempat dokumen ini — hanya tidak pernah terpanggil.

3. Perbaikan yang diusulkan (semua di repo ini, bukan engine)

Prinsip: jalankan re-examination dokumen-pendukung berdasarkan bentuk dokumen (head-anchored keyword), bukan bergantung confidence GPU. Aman karena suggestByKeyword return null untuk apa pun yang tak match pola, dan hanya hit autoAcceptable yang diadopsi otomatis; sisanya jadi suggestion chip (operator yang apply).

3a. Ungate refineSupportingLabel untuk label rawan-salah

Ganti gate confidence dengan allowlist label GPU yang diketahui salah untuk paket Berakhirnya: OTHER, BUKTI_TRANSFER-SURAT_KETERANGAN_BANK, SURAT_KETERANGAN_BANK, dan BERITA_ACARA_RUPS. Untuk label-label ini, jalankan classifySupportingDoc tanpa syarat confidence; adopsi hanya bila autoAcceptable (mis. LAPORAN_LIKUIDASI head-anchored @0.85).
- Buang/khususkan early-return label === "BERITA_ACARA_RUPS" supaya BAR bisa diperiksa ulang → hanya berubah jika head jelas laporan (rule head-anchored dicek pertama; BAR asli tak match).
- Confidence rendah tetap seperti sekarang (tidak ada regresi untuk flow lain).

3b. Ungate letter-confirm + BUKTI_PENGUMUMAN suggestion

Jalankan classifySupportingDoc({ llm }) untuk label rawan-salah tanpa syarat confidence < min, dan teruskan namaPerseroanHint agar axis _149/_152 ter-anchor ke box PT pemohon. Hasil:
- Koran → suggestion BUKTI_PENGUMUMAN + fineLabel _149/_152 (chip amber, bukan auto).
- Laporan → auto-adopt LAPORAN_LIKUIDASI (autoAcceptable).

3c. Surat Permohonan yang tertukar jadi AKTA_BERAKHIRNYA

Tambah pengecekan head-anchored SURAT_PERMOHONAN khusus saat label AKTA_BERAKHIRNYA: bila head cocok pola permohonan (suggestByKeywordSURAT_PERMOHONAN) → keluarkan suggestion chip (jangan auto-flip; akta asli tak match pola head permohonan). Ini menutup gotcha "surat menyebut berakhirnya".

3d. (Opsional) Scoping paket

Karena classify jalan per-file (belum tahu ini paket Berakhirnya), scoping cukup dari spesifisitas rule head-anchored — tidak perlu sinyal paket. Jika mau ekstra hati-hati, gate 3a–3c hanya aktif ketika AKTA_TXN_CLASSIFIER_URL/berakhirnya-env tersedia (sudah default).

4. File yang disentuh

  • backend/src/routes/klasifikasi.tsrefineSupportingLabel, blok letter-confirm (≈498), tambah cabang SURAT_PERMOHONAN untuk AKTA_BERAKHIRNYA.
  • (Kemungkinan) backend/src/services/supporting-doc-classifier.ts — hanya bila perlu param baru; kemungkinan besar tak berubah.
  • Tes: backend/src/routes/__tests__/*klasifikasi* + services/__tests__/supporting-doc-classifier.test.ts — tambah kasus "confidently-wrong GPU label → refine/suggest benar".

5. Risiko & mitigasi

  • Regresi flow lain (pendirian/perubahan): rule head-anchored spesifik + adopsi hanya autoAcceptable → risiko rendah. Dijaga test suite existing.
  • Koran & permohonan tetap suggestion-only (autoAcceptable:false) sesuai desain spec (operator authoritative) — bukan auto-adopt. Berarti operator masih 1 klik apply per dokumen; kalau mau full-auto perlu keputusan terpisah (naikkan confidence rule / auto-adopt koran) — butuh konfirmasi.
  • Engine tidak disentuh (sesuai CONVENTIONS): fix murni di orchestrator repo.

6. Validasi

Jalankan ulang harness Playwright (.pw-scratch/run-berakhirnya.mjs) → target: 6/6 lane benar/ter-suggest; bunx tsc --noEmit; bun test untuk klasifikasi.

7. Keputusan yang aku butuh

  1. Koran & Surat Permohonan: auto-adopt atau suggestion-chip? (spec bilang suggestion-only; auto lebih mulus tapi menyalahi desain).
  2. Boleh ubah early-return BERITA_ACARA_RUPS di refineSupportingLabel (perlu untuk Laporan)?