Grounded audit (3 parallel investigators over the real code + cross-checked vs the spec/memories, then synthesized). Verdict:
| Module | Verdict |
|---|---|
| PP (Perseroan Perorangan) | ✅ Done (for a PoC) — all 5 in-scope flows end-to-end + tested; the 3 absent flows are intentional registry/form-only |
| Apostille / Legalisasi | 🟡 Mostly done — the spine is complete, but 3 real (non-cosmetic) defects remain before it’s trustworthy |
⚠️ Verify-before-acting: this session repeatedly found audit claims that were already fixed in code (NPWP16, bbox over-capture, paddle y-bucket). The specific file:line claims below are worth a 30-second confirm before you act on them — though the two headline Apostille defects match what I independently saw earlier.
| Flow | Status | Note |
|---|---|---|
| Pendirian PP | ✅ done | Route + validator + processor + BO CRUD + 3-gate finalize + packet ZIP + OCR + FE review + ~10 tests |
| Perubahan PP | ✅ done | Largest flow (1659-line route) but widest test set (~17 route+service+FE); per-jenis gating, diff packet, dissolution guard |
| Perbaikan Data PP | ✅ done | Edit/confirm + KBLI/BO CRUD + MENUNGGU_KONFIRMASI owner step w/ lazy-expiry; e2e + unit + FE tests |
| Pembubaran PP | ✅ done | 4-gate finalize + owner konfirmasi + double-dissolve guard; tested |
| Peralihan PP→PT | ✅ done | Akta-upload start, asal-PP match, live dissolution re-check, isolated rules; FE review-page test missing (medium) |
| Cek Kemiripan | ⚪ intentional | Embedded as pp-nama-filter.ts validation in Pendirian+Perubahan; standalone surface out of scope — not a gap |
| Laporan Keuangan PP | ⚪ intentional | Registry/form-only per design; no OCR surface |
| BO standalone | ⚪ intentional | BO fully implemented as an in-flow sub-resource; standalone registry surface intentionally not built |
PP remaining = pure polish: one FE review-page test (Peralihan), a hardcoded/guessed PP_MODAL_MAX capital ceiling (TODO open question), and a stale “Stubs for later tasks” comment above fully-implemented code in perbaikan-processor.ts:56.
| Flow | Status | Note |
|---|---|---|
| Upload (submit-form + legacy /start) | ✅ done | Country→service derivation, KTP + multi-doc zones, both AP+LGL. Redirect ?token is stored but never decoded (feeds the NIK gap) |
| Classify (LLM + KTP/translation overrides + board) | ✅ done* | Service-category gate FE+BE; deterministic overrides; OCR cached. 290-line classifier has ZERO unit test (high) |
| Extract (generic LLM + doc-number/word-date recovery) | ✅ done | Grounded fallbacks implemented + tested (21 cases). Multi-page extraction quality untested (medium) |
| Signer pre-match + AMBIGUOUS/UNMATCHED resolution | ✅ done* | Fail-soft MariaDB registry (circuit breaker + timeout), full pick/set/manual UI. resolve-signer MANUAL-preservation invariant untested (high) |
| Terjemahan two-axis sworn-translation | ✅ done | Translator-as-signer override gated on cert/reg, rides the same resolveSigner pipeline; covered in extract tests |
| Applicant review (manual confirm, bbox, edits-history) | ✅ done* | Auto-confirm intentionally removed (verified); shared PT FieldCorrection/PdfViewer; no page test (medium) |
| Submit gate (READY → IN_VERIFICATION) | ✅ done* | Hard+soft gates (NO_DOCUMENTS / VALIDATION_FAILED / SECTIONS_NOT_CONFIRMED / SIGNER_UNRESOLVED). Route gates have NO test (high) |
| Verifikator decide (APPROVE/REVISE/REJECT) + finalize | ✅ done | Transactional transitions + read-back banner; tested (6 cases). REJECT & APPROVE both land COMPLETED (no distinguishing badge); verifikatorId hardcoded (no auth — PoC) |
| List / verifikator queue | 🟡 gap | Queue NOT status-filtered — verifikator sees CREATED/EXTRACTING/READY rows and “Verifikasi” routes them to a not-yet-submitted request |
| Cross-validation (13 rules) | 🟡 gap | 12 rules live + tested (65 cases); but AP_T2_NIK_VS_KTP is permanently SKIPPED — accountNik hardcoded null at apostille-cross-validator.ts:511, so the redirect-identity FAIL never fires |
| Trained-model classifier backend | ⚪ intentional | APOSTILLE_CLASSIFIER=model throws a by-design error; llm is the working path |
* = done but with a test gap.
AP_T2_NIK_VS_KTP can never fire: accountNik is hardcoded null (apostille-cross-validator.ts:511) and the redirect ?token is stored but never decoded. Plumb the NIK from the token so the redirect-account-vs-KTP identity FAIL actually enforces.ApostilleListPage / GET /list lists pre-submission rows; “Verifikasi” can land a verifikator on a not-yet-submitted request. Filter to IN_VERIFICATION for the verifikator role.apostille.ts route file has only 2 route tests (signer set/pick, doc add/delete/reclassify all untested); apostille-classifier.ts (290 lines, branchy overrides) and apostille-resolve-signer.ts (MANUAL-preservation) have zero unit tests. (PP has ~52 backend + 10 FE for contrast.)