ADR-5: Sparse polymorphic sale fee override reason stamp
Date: 05/08/2026 Author(s): Jamie Batabyal
Status
Accepted
Context
First-slice Partner–Brand transaction fee overrides need sale provenance so invoicing and reporting can filter by override reason. apiGCSales and bulk_buy_gift_card_sales are large tables; adding columns there is costly. Reporting needs to know that an override applied and why — not which catalogue scheme governed the sale (the fee amount on the sale is enough). Bulk-buy already stores issuance_fee_scheme_id; that link stays.
Decision
We will record the sale fee override reason in a sparse polymorphic stamp table: override reason id plus a morph to the digital or bulk-buy sale row. A row exists only when the new Partner–Brand override model (scheme + reason) governed a committed sale. Standard resolution (including Standard Zero), legacy waive-only resolution, redemptions, and projected resolutions are not stamped. The stamp does not store scheme identity; the sale's fee amount and generic catalogue TFS identity remain the economic record.
The resolver exposes nullable override provenance to both committed and projected results, but only final API and Bulk Buy sale persistence writes a stamp. Stamps are write-once, one per sale, and duplicate-safe so a retry cannot create a second reason. A required stamp and its committed sale are persisted atomically.
Partner–Brand override config (catalogue scheme FK + reason FK) lives on dataPartnerBrand and rides the existing PartnerBrand audit. Apply, replace, and clear are one audited transition; when those transitions change the legacy waive flag, its previous and new values are included in the same audit record.
Consequences
Positive
- No new columns on the fat sale tables
- Same stamp contract for digital and bulk-buy
- Clear separation: current override config on PB; sale provenance is reason-only
- Retries cannot create duplicate provenance for a sale
Negative
- Digital sales still lack historical scheme id (accepted for first slice)
- ETL/reporting must join the stamp table (column contract with Data remains open)
- Polymorphic morph needs careful sale-type mapping for both sale shapes