think
16px
820px

Done-report — Berakhirnya Status PT (revised-plan gap fixes)

Branch: fix/berakhirnya-status-badan-hukum (from refactor/tidyup-foundation@feacb3f6).
Scope: the revised plan's residual gaps only — the flow itself was already shipped/launched
on the base branch. Tahap 0 (baseline) → A → B → C → D. All touched test files green in
isolation; no net-new full-suite failures vs the pre-change baseline.

What shipped (8 commits, feature-ordered interface→impl→test)

flowchart LR T0["Tahap 0\nbaseline (no code)"] --> A["Tahap A\nPs.152(3) upper bound"] A --> B["Tahap B\nseam calibration + anchoring"] B --> C["Tahap C\nextractor per-pasal + nomor recovery"] C --> D["Tahap D\ndwifungsi FAIL message (message-only)"]
# Commit What
1–2 c78e89b3, 1e04bbe8 Tahap ABSBHP_PENGUMUMAN_ORDER now enforces the Ps.152(3) upper bound (t152 ≤ tRUPS+30d) alongside the existing lower bound; stays severityFloor:"WARNING".
3–4 3cf52554, c1a39d18 Tahap B seam — pasal axis by majority of DISTINCTIVE hits (not first-match); PT-name anchoring to the applicant's box; SIRKULER→BERITA_ACARA_RUPS; laporan "pernyataan…selesai" variant; permohonan/pemberitahuan-pembubaran variant.
5 be0eb411 Tahap B wiring — classify route returns the kepala-akta PT name + accepts ?namaPerseroan; frontend threads it so korans anchor.
6–7 b9172ac3, 4d1ade0a Tahap Cbukti-pengumuman-extract parametrized per pasal (127/149/152); recoverDocNumberViaLlm wired as the nomor_pengumuman fallback, gated to Ps.149/152 (peleburan byte-identical).
8 82a61e11 Tahap D (message-only)BSBHP_REQUIRED_DOCS FAIL hints the dual-function possibility. Structural handling deferred to you (options below).

Two scope corrections (evidence-backed, NOT done as the plan literally said)

  1. BSBHP_AKTA_RECENCY NOT added — already covered by the wrapped AKTA_DATE_WINDOW
    (pt-akta-context.ts:257 hardcodes isPerubahan:true → 30-day window = exactly [today−30,
    today]). Adding it would double-validate the same field. Tahap A therefore = item 2 only.
  2. Company-lookup (old Tahap 3.7) untouched — you confirmed the 2026-07-03 erratum stands.

Tahap 0 baseline → calibration (drove Tahap B)

Full report: https://x056.think.val.id/TAHAP0-baseline-berakhirnya.md. Key: the seam's whole-page
axis scan mislabeled 4/5 of the Ps.149 samples as _152 (a stray PERTANGGUNGJAWABAN from a
neighbouring newsprint box). After Tahap B (anchoring + distinctive majority): 8/10 anchored axis
accuracy; all previously-uncaught variants (2 laporan, 2 sirkuler BAR, 1 pemberitahuan-pembubaran)
now classify correctly. Validated against the real rawText dumps, not just synthetic fixtures.

The Bukit Lentera Ps.149 sample is literally a court-ordered pailit-closure notice — which is why
axis 149 gained PAILIT|KURATOR|…, and why generic PEMBUBARAN|PUTUSAN were dropped (they recite
in both pasals and swamped the count → 4/10). This is data-driven, not the plan's literal keyword list.

Tests

  • New/updated unit tests: rules-berakhirnya.test.ts (152 upper bound ×2, dwifungsi message),
    supporting-doc-classifier.test.ts (11 new: axis majority/anchoring, sirkuler, variants),
    bukti-pengumuman-extract.test.ts (4 new: per-pasal prompt, recovery gating, pasal derivation).
  • Full suite: 1886 pass (baseline 1867), 126 fail / 115 err — all pre-existing infra
    (DB custom triggers not created by prisma db push, MinIO-off specimen tests, env-default config
    tests, gateway-dependent integration tests). Zero net-new failures at every stage.
  • Baseline harness + rawText dumps live outside the repo (~/…/baseline-berakhirnya*); the harness
    is in the gitignored backend/tmp/. Nothing sample-related is committed.

Needs your decision — Tahap D (dual-function document)

Real sample (PT Bukit Lentera): the same PDF serves as BERITA_ACARA_RUPS and
LAPORAN_LIKUIDASI (a Keputusan Sirkuler that memuat the liquidator's pertanggungjawaban). Today
uploadedDocTypes = one file → one classifiedType, so one slot is missing → BSBHP_REQUIRED_DOCS
FAIL unless the notaris uploads the file twice. I only improved the FAIL message (committed).
The actual handling is your call:

  • (a) allow one document to satisfy >1 checklist slot (board/checklist change);
  • (b) accept the upload-twice workaround + the clearer FAIL message (shipped);
  • (c) content-detect the dual role in BSBHP_REQUIRED_DOCS (a BAR whose text carries the
    liquidator pertanggungjawaban covers the laporan slot).

Known residual (not a regression)

  • Anchoring is best-effort at board time: a koran classified before the deed in the upload
    order falls back to whole-page (the board reclassify stays authoritative). Richest activation
    would be a post-submission axis re-suggest using oldData.perseroan.nama — a small follow-up.
  • A permohonan letter that recites "pengumuman surat kabar" still hits the koran rule first
    (operator re-maps on the board). The future generated surat-permohonan template you mentioned
    would make this deterministic — left out of scope this branch, as the plan states.