Desain: Kuorum RUPS Ke-1 / Ke-2 (deteksi hybrid AI + konfirmasi notaris)
Status: ✅ Fase 1 IMPLEMENTED (backend penuh + toggle UI 3 flow V2; typecheck & test hijau) · Tanggal: 2026-07-14
Konteks: Ambang kuorum kehadiran RUPS berbeda antara rapat pertama dan kedua (UUPT). Sistem sekarang selalu memakai ambang rapat pertama karena tidak tahu sebuah akta itu RUPS ke-1 atau ke-2. Dokumen ini merancang cara AI mengusulkan tingkat rapat dan notaris mengonfirmasi, lalu ambang menyesuaikan.
Keputusan yang sudah dikunci bersama Efran:
- Bentuk field: angka rups_ke = 1 | 2 (RUPS ke-3 oleh pengadilan → di luar scope).
- Default: kalau notaris belum konfirmasi & AI tak menemukan penanda → RUPS pertama (ambang ketat, konservatif).
- Model: hybrid — AI mengusulkan, notaris mengonfirmasi/override.
- Scope: ketiga kategori kuorum — Perubahan non-AD, Perubahan AD, dan Ps.89 (Penggabungan / Peleburan / Pengambilalihan).
- Peleburan: cara ceknya disamakan dengan flow lain (cek roster AktaPemegangSaham di akta peleburan, ambang ps89, toggle rups_ke per-submission). Ini sesuai perilaku AHU Online yang juga cek kuorum atas satu PT representatif saja — bukan gap (§4.1).
1. Dasar hukum — ambang kehadiran
Hanya kehadiran yang dihitung (persetujuan tidak dihitung, sesuai keputusan sebelumnya).
| Kategori | Pasal | RUPS ke-1 | RUPS ke-2 |
|---|---|---|---|
| Perubahan data biasa (non-AD) | Ps.86 | > ½ | ≥ ⅓ |
| Perubahan Anggaran Dasar (AD) | Ps.88 | ≥ ⅔ | ≥ ⅗ |
| Penggabungan / Peleburan / Pengambilalihan | Ps.89 | ≥ ¾ | ≥ ⅔ |
AD = PAD ∪ PPAD. Non-AD = perubahan data saja.
2. Bagaimana AI tahu ini RUPS ke-1 atau ke-2?
RUPS kedua wajib menyebut dirinya rapat kedua dan merujuk rapat pertama yang gagal kuorum (Ps.86(5)-(6), 88(2), 89(2)). Jadi penandanya hampir selalu eksplisit di akta / BA RUPS:
| Penanda di dokumen | Kesimpulan |
|---|---|
| "Rapat Kedua" / "RUPS Kedua" / "rapat yang kedua" | ke-2 |
| "rapat pertama tidak/belum mencapai kuorum" | ke-2 |
| merujuk tanggal + panggilan rapat pertama yang gagal | ke-2 |
| kutipan "Pasal 86 ayat (5)/(6)", Ps.88(2), Ps.89(2) | ke-2 |
| tidak ada penanda apa pun | ke-1 (default) |
Kenapa tetap butuh konfirmasi manusia: kadang hanya akta RUPS kedua yang dinotariskan (BA pertama tak diserahkan), atau wording tak baku. AI hanya bikin default cerdas; notaris yang memutuskan.
3. Arsitektur (untuk 3 flow yang sudah punya rule)
Berlaku untuk Perubahan, Penggabungan, Akuisisi — ketiganya sudah menjalankan rupsQuorumRule dengan ctx.rupsQuorum yang berisi roster + kehadiran satu PT.
rups_ke + rups_ke_bukti] B --> C[Submission.rupsKe
default = usulan AI] C --> D[Toggle notaris:
Pertama / Kedua] D --> E[ctx.rupsQuorum.rupsKe] E --> F[rups-quorum.ts:
pilih ambang ke-1 / ke-2
per kategori]
3.1 Ekstraksi (AI mengusulkan)
src/schema/akta-perubahan.ts — tambah di samping jenis_rups / tanggal_rups / kehadiran_rups:
- rups_ke: 1 | 2 | null — usulan AI (null bila ragu)
- rups_ke_bukti: string | null — kutipan frasa penanda (audit + bantu konfirmasi notaris)
Prompt: instruksikan mencari penanda di §2; tak ada penanda → 1.
3.2 Persistensi (nilai terkonfirmasi)
rups_kehasil AI menempel di akta (sepertijenis_rups).- Nilai yang dipakai validasi = yang dikonfirmasi notaris → kolom baru
Submission.rupsKe Int?(default mengikuti usulan AI). Pola sama sepertichangeTypeResult/selectedJenisPerubahan.
3.3 Context
src/flow-engine/context/pt-akta-context.ts (~baris 385) — tambah rupsKe ke ctx.rupsQuorum:
Submission.rupsKe → fallback akta field rups_ke → fallback 1.
3.4 Rule — refactor ke kategori semantik
src/flow-engine/rules/pt-akta/rups-quorum.ts. Masalah: sekarang Penggabungan/Akuisisi memanggil rupsQuorumRule({ quorumThreshold: 3/4 }) — angka "buta" yang tak tahu fallback ke-2 nya ⅔.
Ganti opsi angka jadi kategori semantik, mis.:
rupsQuorumRule({ adAware: true }) // Perubahan: pilih non-AD/AD dari scope, tiap-tiap punya ke-1/ke-2
rupsQuorumRule({ category: "ps89" }) // Penggabungan / Akuisisi / Peleburan
Tabel ambang internal (kategori, rupsKe) → { threshold, comparator }:
| Kategori | ke-1 | ke-2 |
|---|---|---|
nonAd |
> 0.5 |
>= 1/3 |
ad |
>= 2/3 |
>= 3/5 |
ps89 |
>= 3/4 |
>= 2/3 |
3.5 UI toggle
Radio "RUPS: ● Pertama ○ Kedua" pre-filled dari rups_ke AI, di panel yang sudah menampilkan kehadiran RUPS. Override → simpan ke Submission.rupsKe lewat endpoint kecil. Tampilkan rups_ke_bukti sebagai hint ("Terdeteksi: '…rapat kedua…'").
4. Peleburan — disamakan dengan flow lain (keputusan Efran)
Keputusan: cara ceknya disamakan dengan flow yang sudah ada, tidak bikin mesin per-sumber. Peleburan diperlakukan sama seperti Penggabungan/Akuisisi — cek satu roster terhadap ambang ps89, dengan toggle rups_ke per-submission.
Konkretnya, samakan dengan pola §3 pada roster AktaPemegangSaham di akta AKTA_PELEBURAN (roster PT baru — satu-satunya roster kehadiran yang tersedia dari ekstraksi):
- Aktifkan matcher kehadiran untuk Peleburan — tambah
AKTA_PELEBURANke filter jenis akta dimatchRupsAttendance(src/services/rups-attendance-matcher.ts) dan setrupsAttendance: truedi rematch configpeleburan-pt.ts. Ini mengisikehadiranRupsdi roster akta peleburan, persis seperti Perubahan/Akuisisi. - Tambah rule —
rupsQuorumRule({ category: "ps89" })kePELEBURAN_RULE_SETdipeleburan-pt.ts. - Toggle
rups_ke— pakaiSubmission.rupsKeyang sama (per-submission), tampil di UI ekstraksi Peleburan seperti flow lain.
Dengan ini Peleburan masuk Fase 1 — tidak ada fase terpisah.
4.1 Cek single-PT MEMANG cara AHU Online — bukan kompromi (klarifikasi Efran 2026-07-14)
Ternyata pendekatan single-check kita sama persis dengan cara AHU Online. Di sistem asli tidak ada kuorum/RUPS terpisah per PT sumber. Walau secara hukum (Ps.89) tiap PT yang melebur seharusnya punya RUPS sendiri, implementasi AHU hanya mencatat kehadiran RUPS untuk SATU PT — yang dipilih notaris sebagai representatif (perseroan_check):
- actionIndex — pilih PT hasil peleburan pakai nama baru atau reuse nama salah satu PT yang melebur.
- actionLebur — input daftar 2+ PT (
perseroans[]+ NPWP), lalu pilih satu sebagaiperseroan_check(PT representatif). - actionPersyaratanUtama — tabel "Kehadiran RUPS" muncul, tapi datanya (pemegang saham/direksi/komisaris) hanya dari
perseroan_check. PT sumber lain hanya tercatat nama + NPWP, tanpa tabel kehadiran. - actionDetail — isi data lengkap PT hasil peleburan (mirip pendirian).
- Submit →
createLeburTransaksi()— PT lain langsungUPDATE status_transaksi = 5(dianggap bubar) satu batch, tanpa approval/kuorum terpisah. Daftar PT melebur disimpan sebagai satu JSON di pivotpeleburan_perseroan(metadata, bukan data kuorum).
⇒ Konsekuensi desain: cek kuorum single-PT terhadap satu roster = perilaku yang benar, sesuai sistem. Pendekatan "per-sumber" yang sempat dikhawatirkan sebagai gap bukan gap — sistem asli memang tidak melakukannya.
Satu-satunya perbedaan halus: AHU memakai roster registri milik perseroan_check, sedangkan PoC ini memakai roster hasil ekstraksi akta peleburan (AktaPemegangSaham = pemegang saham PT hasil peleburan). Untuk PoC ini roster akta adalah analog terdekat yang tersedia dan sudah memadai; menyelaraskan ke roster perseroan_check = penyempurnaan opsional, bukan keharusan.
5. Fasing
Semua masuk satu fase — keempat flow (Perubahan non-AD/AD, Penggabungan, Akuisisi, Peleburan) memakai cek seragam yang sama. Peleburan cuma butuh dua sambungan tambahan (aktifkan matcher + daftarkan rule).
Cek single-PT untuk Peleburan = perilaku yang sesuai AHU Online (§4.1), bukan penundaan. Penyelarasan roster ke perseroan_check = penyempurnaan opsional.
6. Ringkasan perubahan file (perkiraan)
src/schema/akta-perubahan.ts— field + promptrups_ke/rups_ke_buktiprisma/schema.prisma—Submission.rupsKe Int?src/flow-engine/context/pt-akta-context.ts— isirupsQuorum.rupsKesrc/flow-engine/rules/pt-akta/rups-quorum.ts— kategori semantik (nonAd/ad/ps89) + tabel ambang ke-1/ke-2src/flow-engine/flows/{perubahan,penggabungan,akuisisi}-pt.ts— ganti opsi rule ke kategori semantiksrc/flow-engine/flows/peleburan-pt.ts— tambahrupsQuorumRule({ category: "ps89" })+rupsAttendance: truesrc/services/rups-attendance-matcher.ts— tambahAKTA_PELEBURANke filter jenis akta- endpoint konfirmasi + komponen toggle RUPS ke-1/ke-2 (dipakai bersama keempat flow)
- tes unit rule (matriks kategori × ke-1/ke-2) + tes matcher Peleburan
Catatan: dokumen desain, bukan implementasi. Menyusul setelah Efran ACC. Peleburan disamakan dengan flow lain; pendekatan per-sumber ditunda (§4.1).