Skip to content

2026-07-17 — XP-136 batch resolver harga sesi

  • packages/service/src/pricing/resolve-sesi-price-estimates-batch.ts (new) — resolveSesiPriceEstimatesBatch(db, inputs[]) -> SesiPriceEstimate[] (aligned by index). Resolves an entire session page in a constant number of round-trips (≤9, independent of N): one academic_years scan + six grouped inArray queries in one Promise.all + ≤2 shared origin queries.
  • packages/service/src/sessions/list-sessions.ts — swapped the per-row Promise.all map through resolveSesiPriceEstimate (≈9 queries per distinct cell) for a single batch call. Barrel-exported from pricing/index.ts so XP-137 (PERF-3) reuses the same contract.
  • Re-derive the branch logic in JS, don’t call the per-cell resolvers — calling them per row IS the N+1. Fidelity is guaranteed instead by an AC2 old-vs-new property test that drives BOTH paths over 11 heterogeneous cell kinds and asserts toEqual per row + pinned absolute values. The identical 0→5 branch order (archived-axis refusal → applicability → level-specific override beats level-null → base → unpriced), pickEffective effective-dating, and FK-integrity origin throw are all mirrored line-for-line from resolve-price.ts / resolve-price-origin.ts.
  • Freeze path untouched: FROZEN sesi pass their stored economic record straight through (only origin re-derived, no live price re-read) — domain-pricing-snapshot.md intact. Estimate path degrades to UNPRICED on incomplete profile, never throws, never persists.
  • WIB academic-year covering is re-derived in JS with a fixed UTC+7 shift (Jakarta has no DST ever) + string date compare, matching the SQL AT TIME ZONE 'Asia/Jakarta'::date. Correct only because the effective-dating compare is a separate instant compare — the two must not be conflated.
  • Shared-Neon-DB fixture hazard bit twice: a timed-out pricing+sessions run (vitest exit 143 at the 2-min cap) skipped afterAll, leaving a PAST-YEAR-* academic_years row that then failed an unrelated sessions suite at fixture INSERT on excl_academic_years_no_overlap. Full suite passed clean on a fresh container (85 files, 583 passed | 2 skipped).
  • .claude/rules/integration-test-shared-fixtures.md §2 — added the durable rule: an afterAll MUST delete the academic_years row itself (not just child price rows), and a killed/timed-out run’s skipped teardown poisons later suites; sweep test-labelled orphan year rows before assuming a diff regressed.