Contextual Pricing (Member + Bulk)
com.os.retailagent.shopping.member_pricing
com.os.retailagent.shopping.bulk_pricing
Plane 3 · Price & Value · Tier 2 · Priced · Reference implementation in Playground
Abstract
This spec defines how a merchant declares contextual pricing — prices that vary by buyer identity and order quantity — and how an agent computes the applicable price at catalog time, before a cart is built. It produces a ComputedPriceState contract: a single unit price with full provenance.
The defining feature is offer transparency. Every applied discount carries a structured AppliedOffer record; every evaluated-but-superseded discount appears in suppressedOffers[] with the reason it lost. An agent can explain why the price is $X, not just state it.
The problem this solves
- A gold member is quoted the public price because the agent doesn't know member prices exist.
- A wholesale buyer orders below MOQ and hits a wall at checkout with no explanation.
- A guest sees an item they can't add but gets no teaser showing the member price or how to qualify.
- An agent quotes a price without knowing which offers were applied — the RAOS-0007 quote token can't bind what it can't see.
What goes in
Merchant declares on the variant
Member price, teaser, bulk tiers, MOQ, quantity increments, purchase limits.
Agent supplies buyer context
Customer type and membership tier determine which price the buyer qualifies for.
Agent supplies quantity
Cart-line quantity determines which bulk tier applies and whether MOQ/increments are met.
What comes out
Applied offers
Which discounts applied, and what each one did to the price. RAOS-0007 quote tokens bind this array.
Suppressed offers
Discounts that were evaluated but didn't win — with the reason why. An agent can show buyers exactly why their expected discount didn't apply.
Reason code registry
Every pricing decision is machine-readable. Two namespaces, seven codes.
| Code | Meaning | Severity | Resolvable? |
|---|---|---|---|
MEMBER_PRICE_APPLIED | Member pricing applied to this buyer. | INFO | Advisory |
TEASER_LOCKED | Guest or unqualified buyer sees a teaser price but cannot add to cart. Addability is blocked by RAOS-0001 eligibility. | CONDITION | Upgrade membership tier |
BULK_TIER_APPLIED | A volume pricing tier was matched and applied. | INFO | Advisory |
BELOW_MOQ | Quantity is below the minimum order quantity. Cannot proceed. | BLOCK | Increase quantity to MOQ |
QUANTITY_INCREMENT_MISMATCH | Quantity is not a multiple of the required increment. | BLOCK | Adjust quantity to a valid increment |
PURCHASE_LIMIT_EXCEEDED | Quantity exceeds the per-order purchase limit for this pricing configuration. | BLOCK | Reduce quantity to within the limit |
CALL_FOR_PRICE | Price is not published — must be requested via the merchant. Distinct from a zero ($0) price. | CONDITION | Submit intent capture (RAOS-0013 forward-ref) |
How the price is computed
Start with the base price. Apply member pricing first (priority 10), then bulk tier pricing (priority 20) — bulk overrides member when the quantity threshold is met. Promo pricing (priority 30) overrides all. Each override records the previous price as a suppressed offer so agents can always explain the price history.
Real merchant scenarios
Sara's Boutique — member teaser (DTC)
Guest
TEASER_LOCKED (CONDITION) — shows $28 teaser, cannot add
Member tier: gold
MEMBER_PRICE_APPLIED (INFO) — proceeds
Member tier: none
TEASER_LOCKED — tier not met
Atlas Wholesale — MOQ + tier boundary (B2B)
qty 5
BELOW_MOQ (BLOCK, min=10)
qty 7
BELOW_MOQ + QUANTITY_INCREMENT_MISMATCH (both BLOCK)
qty 10 (exact MOQ)
BULK_TIER_APPLIED — tier boundary exactly met (>=)
qty 50 (next boundary)
BULK_TIER_APPLIED — higher tier
qty 100
BULK_TIER_APPLIED — max volume tier
Fresh Corner Market — member price + rounding (Grocery)
Guest
Base price — no rounding needed
Member / gold
MEMBER_PRICE_APPLIED — $3.995 rounds to $4.00 (half-up)
Open questions
These are genuine forks. Tell me I'm wrong.
#1Member price higher than bulk tier: last-wins or best-for-buyer?
When a gold member's member price ($58) is lower than the applicable bulk tier ($60), bulk still wins today because it runs second (last-wins). Should bulk override member when its price is worse for the buyer?
Option C: defer to the RAOS-0006 stacking ladder, where member and bulk become named ladder entries with merchant-declared priorities. Until then, last-wins is documented behavior with the suppressed offer visible in the payload.
#2`callForPrice` and eligibility interaction
When callForPrice is true, the pricing stage emits CALL_FOR_PRICE (CONDITION). Should eligibility (RAOS-0001) also signal call-for-price, or is it strictly the pricing stage's concern?
Currently pricing-only. Open for comment.
#3`purchaseLimit` scope: per-order vs per-customer
This spec defines purchaseLimit as a per-order (cart) limit, not a cumulative per-customer limit across multiple orders. Should it be renamed perOrderLimit to avoid confusion with RAOS-0011's per-customer limits?
Renaming to `perOrderLimit` would be more precise but is a breaking change to the config shape. Open for comment — currently kept as `purchaseLimit` with the scope documented explicitly.
Have a view on any of these?
The member-vs-bulk precedence question (§9.1) matters most if you run a wholesale or grocery operation. Email me or reply on the build-log post.
rikbanerjee007@gmail.comWhy start here
Pricing is the most visible merchant-reasoning gap after eligibility. An agent that can't explain “why $X” is not useful for wholesale buyers negotiating or loyalty members expecting their discount. More importantly, RAOS-0007 (Quote Integrity) requires a stable AppliedOffer shape to bind in the quote token — shipping that shape here, before 0007, ensures those specs are additive evolutions rather than breaking changes.