2026-07-17 — XP-136 batch resolver harga sesi
What shipped
Section titled “What shipped”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): oneacademic_yearsscan + six groupedinArrayqueries in onePromise.all+ ≤2 shared origin queries.packages/service/src/sessions/list-sessions.ts— swapped the per-rowPromise.allmap throughresolveSesiPriceEstimate(≈9 queries per distinct cell) for a single batch call. Barrel-exported frompricing/index.tsso XP-137 (PERF-3) reuses the same contract.
Key decisions
Section titled “Key decisions”- 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
toEqualper row + pinned absolute values. The identical 0→5 branch order (archived-axis refusal → applicability → level-specific override beats level-null → base → unpriced),pickEffectiveeffective-dating, and FK-integrity origin throw are all mirrored line-for-line fromresolve-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.mdintact. Estimate path degrades to UNPRICED on incomplete profile, never throws, never persists.
Gotchas / lessons
Section titled “Gotchas / lessons”- 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+sessionsrun (vitest exit 143 at the 2-min cap) skippedafterAll, leaving aPAST-YEAR-*academic_yearsrow that then failed an unrelatedsessionssuite at fixture INSERT onexcl_academic_years_no_overlap. Full suite passed clean on a fresh container (85 files, 583 passed | 2 skipped).
Reference changes
Section titled “Reference changes”.claude/rules/integration-test-shared-fixtures.md§2 — added the durable rule: anafterAllMUST delete theacademic_yearsrow 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.