ADR-0002. Run v1 (/simulation) and v2 (/simulation-v2) calculators side by side; v2 canonical
| Field | Value |
|---|---|
| Status | Accepted |
| Date | 2026-04 |
| Deciders | pricing-team |
| Supersedes | — |
Context
- The original v1 pipeline (
src/services/core/) returns a flat per-line price + tax response. It works but cannot express who bears each amount (buyer / seller / platform / government) or carry a self-contained audit trail. - Downstream needs (refunds, tax declaration, platform reconciliation, immutable receipts) require a snapshot with applied-rule provenance and a per-role (
byBearer) ledger. - Sale already persists the v2 snapshot on
SaleOrder.priceMetadataas the audit/refund source-of-truth. - v1 and v2 share roughly 90% of fare/tax logic, so a hard cutover risks regressing the flat path that is still in use.
Decision
Keep both pipelines live behind separate routes: v1 at POST /simulation/calculate (flat) and v2 at POST /simulation-v2/calculate (snapshot — OrderPricingSnapshot + LineItemPricingSnapshot[]). v2 is canonical for all new work. Sale calls both at checkout during the transition; v2 is the persisted source-of-truth.
Consequences
| Pros | Cons |
|---|---|
| New consumers get full rule provenance + by-bearer ledger | ~90% logic overlap means fixes usually land in both pipelines |
| No regression risk for existing flat-price consumers | Two code paths to maintain until v1 retires |
Snapshot envelopes are independently versioned (v: 1 per layer) | Doubled calculate latency at checkout while both are called |
Alternatives Considered
| Option | Pros | Cons | Why rejected |
|---|---|---|---|
| Hard-cutover v1 → v2 | One code path | High regression risk; all callers must migrate at once | Too disruptive mid-flight |
| Extend v1 response in place | No new route | Breaks the flat contract; can't add byBearer without churn | Backward-incompatible |
| Compute v2 only, derive flat from it | Single engine | v1 callers would need a downshaping layer; not yet built | Deferred until v1 retires |
References
pricing/src/services/core/(v1)pricing/src/services/core-v2/(v2 +pricing-snapshot/)pricing/src/controllers/simulation/,pricing/src/controllers/simulation-v2/