think
16px
820px

K.36 — Field-order shuffle, dead phone controls, the "can't load" page, Analisis Setoran

Deployed: ahu-ai-ocr:121b3694 @ x056.ahu-demo.ocr.val.id · 2026-07-21
Suites: backend 2813 · frontend 1034 (0 fail)

1. "Confirming a field sometimes reorders the section" — fixed (PT Perubahan)

Root cause is a classic Postgres trap: the perubahan projector iterated aktaDoc.fields in query order, and the relation had no orderBy — an UPDATE (which is what a confirm is) physically relocates the row in the heap, so the next refetch returned a different order and the section visibly reshuffled. An audit showed this was the only projector reading relation order (every other one walks a canonical key list) — it now iterates PT_DELTA_IDENTIFYING_KEYS in declared order, which is also the semantic display order.

2. "Unable to edit nor confirm the phone number field" — fixed (PT Pendirian)

The Telepon/Email Perseroan rows on a submission with no DATA_KONTAK document were emitted with documentId: null — and both frontend handlers (confirm and edit-save) silently bail on a null document. The result was exactly what you saw: a pencil and a confirm button that look alive and do nothing.

The deeper truth: with no contact document, those values are your own step-1 form input — there is no OCR output to verify and no storage for a confirmation. They now project as settled data (confirmed, USER_CONFIRMED, no dead pencil; empty ones show "Tidak ditemukan" with no controls). The same fix applies to the per-person phone when no contact entry exists to hold a confirmation. Where a contact document does exist, nothing changes — OCR values keep the strict never-pre-confirmed default.

3. Perubahan a44fe278 "can't open/load page" — already fixed, verified

That page died on the schema drift found in K.35: the dev/2 merge added Submission.rupsKe without a migration, so every full-row Submission read on staging 500'd (tests stayed green — the test DB syncs via db push). The catch-up migration shipped in K.35; I re-verified the exact URL headless: renders clean, zero console errors. If you still see a failure there, it's browser cache — hard refresh.

4. "Analisis Setoran" on Daftar Setoran — built

Server-computed (meta.buktiSetorAnalysis, additive contract change), rendered as a strip above the table:

  • Total setoran terbaca vs Modal Disetor and Modal Dasar — coverage badges (green ≥ 100%, amber below) and a selisih warning when deposits fall short;
  • Bank tersering (count + amount) and per-bank breakdown chips;
  • transaction and distinct-sender counts.

Live on 0f94caef (33 rows): BCA is the most-used bank (31 transaksi), and the 10094% dari Modal Disetor badge instantly exposes the two mis-OCR'd Mandiri amounts (Rp 27,5 M read as Rp 27,5 B) — which is precisely the kind of outlier this analysis exists to surface: the per-row table asks "is this row real", the strip asks "does the whole picture add up".

Commits

121b3694 all three fixes + the analysis (backend aggregation split into bukti-setor-analysis.ts per the fitness cap)