Merit · Seller Portal · Requirement

Flow for Variant Creation in Product Upload (MSP-392)

This is the requirement behind MSP-392, dated 26 August 2026.

Ticket MSP-392, parent epic MSP-118 Product Upload and PIM Integration
Requirement owner Brian Arfi, Product. Delivery Hassan Ahmad (epic), Khawar Rasheed (scheduling)
Work tree node np-sp (E-Commerce Solution, New World, Seller Portal)
Builds on DEC-0172 (19 Aug), DEC-0168 (19 Aug), DEC-0164 (18 Aug). Supersedes nothing.
Date 26 August 2026

01Why this document exists

MSP-392 sat in backlog with an empty description and no assignee. The same question surfaced three times, in two channels and one DM.

Where the question came up

DateWhereQuestion
10 Aug #seller-portal-x-merchandise-service Ghaith Fakhouri asked who owns variant creation for products that do not exist yet, and how the parent gets created.
20 to 24 Aug #temp-ecomm-core-x-online-catalogue-sync Akshay Chennupati, Usman Abbas, Ghaith Fakhouri, Heba Wahba and Alex Korobchuk argued whether two items that share a variant attribute set are the same item.
24 Aug DM to Brian Khawar Rasheed reported MSP-392 still in backlog, awaiting requirements.

The Slack argument and MSP-392 are one question in two places: what makes a variant distinct. Merit already answered that question for a different case five days ago. Section 2 applies the same answer. Section 4 turns it into the upload flow.

02The rule: what makes a Variant distinct

Merit runs an Amazon-style catalogue. This is not new work, and MSP-392 sits on top of it rather than inventing a parallel model.

2.1 The model that already exists

Product, Variant, Offer

Product (parent) · PIM Canonical identity Name, brand, description, images, category, attributes Buyer sees: one product page Variant · PIM One buyable configuration Variant axis values, its own barcode, its own images Buyer sees: the selector Offer · Ecommerce Core One seller's terms Price, stock location, condition, shipping profile, channel Buyer sees: the price and the seller

One Product can carry several Variants. One Variant can carry several Offers, one per seller.

EntityLives inHoldsThe buyer sees
Product (parent)PIMCanonical shared identity: name, brand, description, images, category, attributesOne product page
VariantPIMOne buyable configuration. Carries the variant axis values, its own barcode, its own imagesThe selector on that page
OfferEcommerce CoreOne seller's terms for one Variant: price, stock location, condition, shipping profile, channelThe price, and the seller behind it

Sources: Master PIM Documentation section 2.1, PRD Ecom Core Seller Offer Management sections 2 and 5.1.

The rules that bind the design, from PRD PIM Category and Attribute Structure:

RuleWhat it saysWhy it matters here
FR-10Up to 5 attributes per category can be variant axesAdding an axis is not free. There is a hard cap
FR-15Variant axes are configured per categoryThe axis list is a category property, not a form property
FR-17Every combination of axis values generates a child SKU with its own barcode, stock and priceAdding an axis multiplies SKUs across the whole category
FR-18 (P2)Sellers can define custom axes where the admin enabled itMust stay OFF here. See rule 4 below
FR-19Axis values must match the admin-defined allowed values listThis is what keeps a new axis from becoming free text

2.2 The four rules

Rule 1

A Variant is identified by the Product plus the complete set of its variant axis values. That combination is unique inside the Product.

The uniqueness constraint that Akshay's team deployed is correct. Keep it.

An axis is not live until every existing variant in that category carries a value for it. The admin names that default value at the moment the axis is created, and it must be one of the FR-19 allowed values. WAIT-0450 established the gap: an existing product does not pick up a new axis without a migration path. Without this clause the whole legacy population has no value on the new axis, so "the complete set" is false for all of it and uniqueness over a missing value is undefined.

Rule 2

When two real items collide on the same axis values, take the cheapest answer that is true, in this order. Never an Offer, at any rung.

  1. Are they the same Product at all? A submission matched into the wrong parent splits into its own Product. Not every collision is a variant question.
  2. Does an axis already exist that separates them? Add the allowed value to it. This is cheap, and D4 already treats it as a different decision from rung 3.
  3. Only then, a new axis. Under the FR-10 cap of 5 per category, with the FR-17 cross product priced in, and carrying the rule 1 backfill.

An automatic new axis on every collision burns a permanent, category-wide axis slot to settle one pair of items, and multiplies SKUs across every product in the category under FR-17. The iPad case lands on rung 3 on its merits, not by default.

Merit already decided exactly this, for regional units. DEC-0172, decided 19 August: region becomes a third variant axis on Smartphones, pinned by an FR-19 allowed values list of exactly [UAE, International, US], and regional units stay one Product. The iPad case that Heba Wahba raised has the same shape. The answer is a Connectivity axis with WiFi and WiFi + Cellular, on the tablet category, pinned by FR-19. After that both items are ordinary variants and nothing is special-cased.

Ghaith reached this on 23 August: "that means they are different, and the variant attribute is what making them show separately". Akshay agreed the next day.

Rule 3

An Offer never carries anything that changes what the buyer receives, apart from condition.

Offers differ by seller, stock location, price, stock and condition, which is an enumerated field on the Offer entity (NEW, REFURBISHED, USED_LIKE_NEW, USED_GOOD, USED_ACCEPTABLE) and is shown to the buyer. Nothing else about the item may live on the Offer.

This is why the workaround Usman proposed, which links a second Offer to the existing Variant when the axis values collide, cannot be the answer. The B2C app shows the lowest-price Offer for the selected Variant, as Usman described on 24 August. Put a WiFi unit and a WiFi plus Cellular unit on one Variant as two Offers, and the buyer selects the item they want, is charged for the cheaper one, and receives the wrong hardware. Nothing errors anywhere. Merit would find it in returns.

Usman's closing message points at the same answer from the other side: "If you want to eliminate this confusion completely, you can provide us with unique Variants under each Product, where each Variant has a unique combination of attribute values."

Rule 4

A seller can never create a variant axis. Only a catalogue admin can.

The rule is absolute, not flag-driven. Product Upload never renders an axis-creation control, whatever allow-custom-axes says for the category. FR-18 stays available to admins inside PIM and stays out of reach of the seller flow. DEC-0172 already turned allow-custom-axes OFF for Smartphones and Electronics; this rule means the seller flow does not depend on that flag being read correctly for any other category. A seller-invented axis fragments the category permanently, and FR-17 means every existing product in that category gains a cross product of empty SKUs.

2.3 What happens when the right axis does not exist yet

Ops cannot wait for a schema change on every collision, and the seller must not be able to force one. So the flow fails loudly and routes the request.

1
The create fails with a named error.
"A variant with these option values already exists on this product. If this is a different item, request the option that tells them apart."
2
The error raises an axis request against the category.
Which category, the two colliding items, and the axis or allowed value the seller believes is missing.
3
A catalogue admin decides.
Adding an allowed value to an existing axis is cheap. Adding a new axis is a category-level change under the FR-10 cap of 5 and the FR-17 cross product, so it needs the same review DEC-0172 got.
4
Until it is decided, nothing is written.
No duplicate variant, and no offer.

Failing loudly is the point. A silent merge or a duplicate only surfaces after a customer receives the wrong item.

2.4 Two schemas, one flow

PIM holds variant axes per category. The Online Catalogue holds required variant attributes per product group. They are not the same list, and the mismatch already broke production: Hexcode became a required variant attribute on the "Bags / Luggages" product group on 30 April 2026, existing products were never backfilled, and catalogue sync failed on 22 August.

The repair of that specific data has no owner and no ticket, checked on 31 August 2026. See open item 3.

For MSP-392 the source of truth is the PIM category axis list, because that is what the seller is creating into. The Online Catalogue product group attributes are a push-time requirement, checked before the outbound push, not a form requirement. Requirement G5 covers this.

03Where the flow starts

The seller is in Product Upload and wants to sell something. Four paths exist. Only the first is specified today.

Merit has no dependable GTIN, EAN or UPC, so identity is resolved by matching, not by a barcode lookup. The one real seller catalogue Merit holds, 11,425 rows, has no barcode column at all. The waterfall runs the seller SKU map first, then semantic search on title and attributes, then LLM disambiguation, then seller confirmation. Every branch below is entered by a match result. Source: BRD for AI Product Matching, 20 August 2026.

Decision tree from the match result. Merit has no dependable GTIN, so identity comes from AI matching

Seller submits title, attributes, own SKU AI product matching waterfall seller SKU map, semantic search, LLM, seller confirms Matched to an existing Variant CASE A Create an Offer on that Variant Already specified and built Matched to a parent, configuration missing CASE B Create a new Variant under that parent Not specified. MSP-392 Nothing found CASE C Create Parent Product + first Variant Not specified. MSP-392 Axis values collide with an existing Variant CASE D Block, name the collision, raise the axis request Not specified. MSP-392

Case A is covered by PRD Seller Portal Product Upload Improvements v1 section 3.2, the SKU conflict resolution flow. Cases B, C and D are the scope of MSP-392.

04Requirements

Requirement ids B1 to B9, C1 to C7, D1 to D5 and G1 to G5 are the deliverable of this document.

4.1 Case B: add a Variant to an existing Product

#Requirement
B1"Add a variant" is available from a product card in Search Existing Products. The variant count already on that card (PRD v1 section 3.1) tells the seller what exists.
B2The variant form is built from the category's variant axis list, read live from PIM. It is never a static form.
B3Every axis on the category is mandatory. A variant with a missing axis value is not a valid SKU under FR-17.
B4Axis values are selected from the FR-19 allowed values list where one is configured. Free text is only permitted where no list exists.
B5The form never offers "add a new option", in any category, whatever allow-custom-axes says. FR-18 is unreachable from the seller flow by construction, per rule 4 and DEC-0231.
B6On submit, the axis value combination is checked against every existing Variant of that parent. A collision goes to Case D.
B7The seller supplies their own seller SKU, variant images, and a barcode only if they hold one. The barcode is an optional stored field under FR-17 and is never the identity key. Merit has no dependable GTIN, EAN or UPC. Parent content is read only in this form.
B8A successful submit creates the Variant and the seller's Offer against it in one action. The seller never has to run Case A afterwards.
B9The new Variant enters LiveOps review before publish.

4.2 Case C: create a Product and its first Variant

#Requirement
C1The parent and at least one Variant are created in one flow. A parent with zero variants is never written.
C2The parent form asks only for shared content: name, description, brand, category, terms and conditions, shared images. Nothing region-specific and nothing SIM-specific in the description, per DEC-0164.
C3Before the parent is written, duplicate detection runs on brand plus name plus category, and the near matches are shown. The seller either picks an existing parent, which sends them to Case B, or confirms this is new.
C4Before the Variant is written, the AI product matching waterfall runs on it. An ambiguous match is shown to the seller to confirm or reject, per decision 8 of the AI Product Matching BRD. Barcode is not used, because Merit has none to match on.
C4aAuto-routing is off until shadow mode ends. BRD business rule 6 says the service scores everything and links nothing until measured precision earns it, per category. So on day one every match is shown to the seller, and a confident match only routes straight to Case A once that category has passed the shadow-mode exit bar. The confidence bands are deliberately unset, and two existing documents disagree, so do not build a fixed threshold into this flow. See open item 8.
C5The variant part of the form follows B2 to B7 without exception.
C6Region defaults to MENA and country to Saudi Arabia for seller-portal-originated products, per the agreement Brian confirmed on 21 August in the sync channel. See open item 4, which records what that agreement did not settle.
C7The parent and the Variant enter LiveOps review before publish. Nothing a seller creates publishes without review.

4.3 Case D: axis collision

#Requirement
D1The create is blocked. The message names the conflicting Variant, its SKU and its axis values.
D2Two paths are offered: "this is the same item, create an offer instead", which goes to Case A, and "this is a different item, request a new option".
D3The axis request captures the category, both colliding items, and the axis or allowed value the seller believes is missing. It routes to a catalogue admin.
D4Adding an allowed value to an existing axis and adding a new axis are different decisions. The request states which one it is, because the second is capped by FR-10 and multiplies SKUs under FR-17.
D5No variant and no offer is written while the request is open. The seller sees the request state on their draft.

4.4 Rules that apply to every case

#Requirement
G1Variant uniqueness is enforced server side, on the complete axis value set, inside the parent Product. The client-side check is a convenience only.
G2An Offer is only created against a Variant that already exists, and carries only seller, price, stock location, stock, condition, shipping profile and channel.
G3Identity keys on productId, variantId and offerId, never on sellerSku. A seller renaming their SKU must not orphan the product.
G4Inventory is held at Variant level, never at parent level.
G5Before the outbound push to the Online Catalogue, the record is checked against the target product group's required variant attributes. A missing required attribute blocks the push with a named error and does not fail silently. This is the Hexcode case.

05Acceptance criteria

Five scenarios, one card each.

Scenario · seller adds a colour that does not exist yet

  • Given the parent product "Tumi Voyageur" exists with variants in Black and Navy
  • When I select "Add a variant", choose Colour = Red from the allowed values list and fill every axis
  • Then a new Variant is created under that parent
  • And my Offer is created against it in the same action
  • And both enter LiveOps review

Scenario · two items share an axis value set

  • Given the variant "iPad Pro 11 inch, 256GB, Space Black" exists
  • When I create a variant with the same category, size, storage and colour for the cellular model
  • Then the create is blocked
  • And the message names the existing variant and its SKU
  • And I am offered "create an offer instead" or "request a new option"
  • And no variant and no offer is written

Scenario · seller cannot invent an axis

  • Given any category, whatever allow-custom-axes is set to
  • When I open the variant form
  • Then there is no control to add my own option
  • And the axis values I can pick are exactly the FR-19 allowed values

Scenario · required catalogue attribute missing at push time

  • Given the target product group "Bags / Luggages" marks Hexcode required
  • And my variant has no Hexcode value
  • When the outbound push to the Online Catalogue runs
  • Then the push is blocked for that record with an error that names Hexcode and the product group
  • And the rest of the batch is unaffected

Scenario · the product already exists and matching finds it

  • Given "iPhone 17 Pro Max 256 blue" is already a variant in the catalogue
  • When I submit "iPhone 17 Pro Max blue 256" while creating a new product
  • Then the matching waterfall returns it as a candidate
  • And I am shown the existing product and variant and asked to confirm
  • And on confirming I am sent to create an Offer against it, not to create a duplicate
  • And no exact string comparison is used to reach this, because it fails on word order today

06Dependencies and open items

Every row was re-checked against its primary source on 31 August 2026. The Answer column records what was found, not what was assumed.

#ItemOwnerAnswer, as at 31 Aug 2026
1 Creating new products and variants in the Online Catalogue is Phase 2 of the OC API contract, not Phase 1. Phase 1 only pushes supplier products for variants that already exist in Seller Portal. DEC-0168 made the outbound leg the priority direction. Akshay Chennupati No date has ever been committed. The last live status is Akshay on 6 July 2026, in DM: "aiming for Phase 2 implementation-ready by the start of the next sprint. Firm estimate and target date to follow once the scope is fixed." The follow-up never came. Tahsin's MOM of 9 June recorded the same promise of a timeline. Still blocking. Asked again in the catalogue sync thread on 6 September 2026.
2 The axis request path in D3 and D4. Brian Arfi, requirement. Catalogue admin decides CLOSED 6 September 2026. Raised as MSP-545, a Task under epic MSP-118 beside MSP-392, carrying A8a (the backfill clause) and A8b (the DEC-0231 ladder). Ghaith Fakhouri is asked only to name the admin role that decides a request, which is an ops answer and not a build.
3 Backfill of required attributes added to a product group after it went live, the Hexcode case. Alex Korobchuk Root cause is documented, the fix is not owned. Alex, 18 August: the product existed before Hexcode was added as a required dynamic field on 30 April 2026, and whoever added it never filled it for the other products in that group. No ticket, no owner and no status for the backfill itself. MPS-1602, strict merchandise variant field validation, is Done and adjacent, but it is validation and not a data repair. Needs a ticket.
4 Country and region defaults for seller-portal-originated products. Akshay Chennupati, Alex Korobchuk Decided, and the decision is Brian's own. The thread ran 19 to 21 August, not 22 August. Brian objected on 19 August that Just Lounge is live in UAE and would be tagged Saudi Arabia silently. Akshay answered on 20 August why a per-supplier country does not work, because one Product can carry suppliers in different countries, and never addressed Just Lounge. Brian confirmed the default on 21 August citing "as we agreed in grooming", a conversation captured nowhere. So C6 stands as written, but the Just Lounge case was never answered on its merits and no one has said what happens to that catalogue.
5 LiveOps review capacity. Every Case C submit creates review work. Ghaith Fakhouri owns the measurement Not an MSP-392 item. It is already tracked as WAIT-0393, which asks for the three numbers that would size it: share of rows reaching manual review, median and 90th-percentile minutes per review, and the split of reviewer outcomes. The AI Product Matching BRD states it plainly: no baseline exists, and the flow is not instrumented. One nudge has gone out. Track it there, not here.
6 allow-custom-axes is confirmed OFF for Smartphones and Electronics by DEC-0172. The setting for every other category is unknown. PIM team CLOSED by DEC-0231, 6 September 2026. The flag state could not be answered from documents and the audit could not be sized, because Merit has no enumerated leaf-category list in any repo source. Rule 4 is now absolute, so Product Upload never renders the control and B5 no longer depends on the flag. The audit is still worth doing for PIM admin tooling, but it does not block this ticket.
7 B6, C3 and C4 sit on top of AI product matching. Ruba Jaikat, PRD. Khawar Rasheed, ticket Ticket exists and is as empty as MSP-392 was. MSP-506, "AI Matching Engine: Training with Common Products", P1, reporter Khawar, no description and no assignee. The BRD is at v2.1. Ruba owns the PRD, proposed for 3 September and explicitly not committed. WAIT-0392 has no progress note since 20 August. Blocking C3 and C4. B and D can still be built and tested against a parent the seller picked by hand.
8 The confidence bands that decide when C4 auto-routes to Case A. Ruba Jaikat Deliberately unset, and two documents disagree. The Bulk Upload TechSpec proposes 95 percent to auto-link and 70 to 95 for seller review. The BRD says two existing documents disagree, 90 and 60 against 95 and 70, and neither is calibrated. BRD business rule 6 is shadow mode first: the service scores everything and links nothing until measured precision earns it, per category. So C4 must not auto-route on day one. See C4.
9 Validation is being specified in three places. Usman Abbas WAIT-0395 already records that two PRDs specify the same validation independently. Requirement G5 here is a third. Someone has to pick one owner before all three ship a different error message.

07Limits of this analysis

The variant identity rule is taken from three sources: the Slack thread where Akshay and Ghaith converged on 24 August, the B2C behaviour Usman described (the app shows the lowest-price Offer for the selected Variant), and DEC-0172, which already applied the same rule to regional units. This document did not read the MedusaJS schema or the Ecommerce Core code, so field names may need mapping by Usman Abbas and Hassan Ahmad.

The four cases in section 3 come from the existing Seller Portal product upload documentation plus the two Slack threads. If Product Upload has a fifth path that neither document records, it is not covered here.

Open item 6 was a gap this document could not close from the repo, and DEC-0231 closed it by making rule 4 absolute instead of flag-driven. Which categories allow custom axes today is still not written down anywhere found so far; it no longer blocks this ticket.

Merit Incentives · Seller Portal · Flow for Variant Creation in Product Upload (MSP-392)
Prepared by Brian Arfi Faridhi, 26 August 2026.