think
16px
820px

PR #2 (dev/2 → refactor/tidyup-foundation) — failure inventory & fix guide

Hand-off for the dev/2 team. Written to be actionable by a human or a Claude agent working on the dev/2 branch. Fix everything here on dev/2, get both suites green, and the merge becomes trivial — the PR already contains the base branch, so there are no conflicts to resolve.

Context

Repo Virtue-Digital-Indonesia/ahu-ocr-akta-notaris-POC
PR #2, dev/2refactor/tidyup-foundation
Head audited a6428fe3 (fix(peleburan): disable model thinking …)
Base at audit b836d222already an ancestor of the head, so the merge itself is conflict-free
Verdict Do not merge yet. Backend: 20 failing tests (base: 0). Frontend: 12 failing tests (base: 0). All failures are introduced by dev/2-side changes (or by semantic conflicts with base changes that git merged cleanly).

How to reproduce (exact commands)

git checkout dev/2
bun install && (cd backend && bun install && bunx prisma generate) && (cd frontend && bun install)

# Backend — needs the test DB in sync with dev/2's schema first
# (dev/2 adds migration 20260717000000_peleburan_acuan_rups: ALTER TABLE "PeleburanSourcePt" ADD COLUMN "isAcuanRups")
cd backend
export TEST_DATABASE_URL="<your test postgres url>"
bunx prisma db push --url "$TEST_DATABASE_URL"
bun run test            # → 20 fail as of a6428fe3

# Frontend
cd ../frontend
bunx vitest run         # → 12 fail as of a6428fe3

Note: if you run the backend suite WITHOUT the db push, you'll see ~800 failures — that's just schema drift, not real breakage. Sync first; the real count is 20.


Backend — 4 clusters

Cluster 1 — fitness: file-size ceilings burst (1 test, 3 offenders)

src/__tests__/architecture/file-size.test.ts — "no new monster files":

services/document-processor.ts: grew to 2580 (ceiling 2576) — split before growing
routes/perubahan.ts:            grew to 1784 (ceiling 1763) — split before growing
routes/submissions.ts:          grew to 2502 (ceiling 2500) — split before growing

Fix: the policy is split before growing, not bump the ceiling. Each file is only a few lines over — move a coherent chunk (a helper cluster, a route group) into a sibling module. Precedent on the base branch: routes/apostille-guards.ts and routes/apostille-spesimen.ts were split out of routes/apostille.ts for exactly this reason.

Cluster 2 — POST /api/submissions returns 409 "Temp file metadata not found" (10 tests)

Failing tests:
- src/routes/__tests__/submissions-create-selected-jenis.test.ts — all 8:
- "persists the selection at creation for a PERUBAHAN_PT submission"
- "leaves the column null when the field is omitted"
- "ignores the field for non-perubahan types (no 400, nothing persisted)"
- "rejects a malformed shape with 400 (validation runs before the create)"
- "rejects a fully-empty selection with 400 (mirrors the PATCH route)"
- parseSelectedJenisPerubahanInput × 3 (shape rules)
- "X2 — ownerId stamping at creation > stamps the authenticated principal's sub; anonymous stamps null"
- "POST /api/submissions — AKTA_PERALIHAN_PP_PT file > does NOT auto-dispatch other types from POST / (PENDIRIAN_PT stays CREATED)"
- Also in this family: "BERAKHIRNYA_STATUS_PT routing + gating … create route now CREATES a BERAKHIRNYA_STATUS_PT submission" and the PEMBUBARAN_PT twin.

Error signature (identical in all of them):

[error] Temp file metadata not found for fileId: no-such-temp-file {"scope":"submissions"}
--> POST /api/submissions 409   (test expects 200)

Diagnosis: these tests exist on the base branch and pass there. On dev/2, POST /api/submissions now hard-fails (409) when a posted fileId has no temp-file metadata row, where the base behavior tolerated it (or the merge combined the base's creation-path changes — ownerId stamping, selectedJenisPerubahan — with a dev/2 rework of the same route in a way that compiles but changes the contract). This is a textually-clean, semantically-broken merge inside routes/submissions.ts.

Fix approach: diff backend/src/routes/submissions.ts between b836d222 and dev/2 head, find where the temp-file-metadata check became a hard 409 on the create path, and restore the base contract for the cases the tests cover (metadata-less fileIds in tests / non-dispatching types). Run the 3 files above after each change:

bun test src/routes/__tests__/submissions-create-selected-jenis.test.ts

Cluster 3 — RUPS attendance registry fallback broken (3 tests)

  • "matchRupsAttendance × BERAKHIRNYA_STATUS_PT > registry fallback: zero deed PS rows → rupsKehadiranRegistry built from oldData + BA match"
  • "matchRupsAttendance — PEMBUBARAN_PT registry-roster fallback (spec §4.3) > writes rupsKehadiranRegistry from oldData.pemegang_saham when the deed restates no roster"
  • "pembubaran route family > PUT /kehadiran registry path: operator edit SURVIVES the post-edit rematch even when BA-RUPS disagrees (merge-preserve 3c2906c)"

Diagnosis: dev/2 heavily reworked backend/src/flow-engine/rules/pt-akta/rups-quorum.ts (+123 lines; commits around 4c0d57df feat(rups): force WAJIB_AUDIT by company profile and the rups-ke2 quorum work). The registry-roster fallback (when the deed restates NO shareholder roster, attendance is matched against the stored SABH snapshot oldData.pemegang_saham) no longer produces rupsKehadiranRegistry, and the operator-edit merge-preserve on the pembubaran kehadiran PUT regressed with it.

Fix approach: re-read the failing specs — they encode the intended behavior (including the merge-preserve contract from commit 3c2906c). Preserve the fallback path when adding the ke-2/WAJIB_AUDIT logic; the fallback must still fire when the deed has zero PS rows.

Cluster 4 — fork-vs-V2 parity oracles (4 tests)

  • "flow parity — fork vs shadow v2 (equivalence oracle) > PERUBAHAN_PT: produces identical ValidationResult row sets"
  • same, "AKUISISI_PT"
  • "rematch parity — fork reMatchAndValidatePerubahan vs engine reMatchAndValidateFlow > identical ValidationResult row sets AND checklist fulfilled states"
  • same, "AKUISISI leg … converge on all six surfaces"

Architecture note (why these exist): the repo still carries BOTH validation halves for perubahan/akuisisi — the legacy "fork" implementation and the V2 flow-engine — with equivalence oracles proving they produce identical results. They are scheduled to retire together after the owner's smoke pass, but until then any rule change must land on BOTH sides.

Diagnosis: dev/2 changed V2-side rules (rups-quorum, laporan-rups, peleburan/pembubaran/berakhirnya rule files) without mirroring the change in the legacy fork half (or vice-versa), so the oracles diverge.

Fix approach: run each parity test, read the diff it prints (it names the diverging ValidationResult rows), and mirror the rule change on the other side. Do NOT delete/skip the oracles — that retirement is explicitly gated on the smoke pass, not on this PR.


Frontend — 2 clusters (12 tests)

Cluster 5 — FlowStepLayout refactor broke its own suite (10 tests)

src/components/process/__tests__/flow-step-layout.test.tsx — all 10 fail, e.g.:
- "always renders the StepIndicator with the given steps/currentStep/variant"
- "renders no title block when neither eyebrow nor title is given"
- "renders eyebrow, h1, and description centered" / "left-aligned text-2xl h1…" / "defaults to 'wide'…" / "titleIcon before the title…" / "destructive tone…" / "afterStepper slot…" / "children after the header block…" / "merges an extra className…"

Diagnosis: dev/2's broad V2-review-page restyling changed FlowStepLayout's rendered structure/props without updating its test suite. Since ~15 pages consume this component, decide deliberately: if the new structure is intended, update the tests to pin the NEW contract; if not, restore the old render shape.

Cluster 6 — extraction-page back buttons (2 tests)

  • src/pages/__tests__/PeralihanExtractionPage.test.tsx > "back button returns to the Klasifikasi step when not processing"
  • src/pages/__tests__/PendirianExtractionPage.perubahanPp.test.tsx > "back button goes to the PP perubahan select page"

Diagnosis: back-navigation targets changed on those pages (likely alongside the klasifikasi manual-picker work, ee540a3e). Either the new destination is intended (update the tests) or it's a regression (restore the routes). Note the second one is a PP-flow path — check it wasn't collateral of a PT-only change.


Acceptance criteria

  1. cd backend && bun run test → 0 fail (with dev/2 schema pushed to the test DB).
  2. cd frontend && bunx vitest run → 0 fail.
  3. No fitness ceilings bumped — offending files split instead.
  4. Parity oracles untouched and green.

When those hold, ping to merge — the base is already contained in the PR, so the merge itself is a no-op fast-forward-style integration.