Model each product as a small graph. Nodes are the things facts can belong to: the product group, its parts (a hood, a jacket, a battery), each purchasable variant, each seller’s offer, and the documents your facts come from. Edges say how facts move between them: inherits, overrides, excludes, scoped to and derived from.

Three rules follow. A fact reaches a variant only through an inheritance edge that no exclusion blocks. A fact scoped to a part never answers a question about the whole product. An offer fact (price, stock, returns) never passes from one seller to another.

This is our proposed model for your own data. No platform reads it, and it doesn’t predict which sibling an agent will pick; that’s a separate experiment.

What a level table can’t express

If you haven’t mapped your facts to levels yet, start with the variants guide. Its matrix puts each fact at the group, variant or offer level, and it catches most leaks. This page is about the leaks a table can’t describe, because they’re about relationships, not levels:

Leak Why a level table misses it Edge that fixes it
A part’s rating becomes the product’s “Hood insulation rated to -30°C” sits at the group level, since every size has the hood. The table says “group” and stops Scoped to: the fact attaches to the hood, which is a part of every variant
A group fact that’s true for nine sizes out of ten Schema.org reads group properties as shared by every variant. There’s no “all except” Excludes: an explicit edge from the group fact to the one variant it doesn’t cover
One seller’s terms show up on another’s offer Price and returns are “offer level” in the table, but a catalog can cluster offers from several sellers under one product No edge between offers. Each offer inherits only from its own seller’s policies
A generated summary drifts from its source The table records where a fact lives, not where a copy came from Derived from: the copy points back to the claim it summarises, so the two can be compared

The graph

Nodes

Node What it is ID to use
Group The product family, never sold on its own Your product ID; productGroupID in markup
Component A part every variant has, or some variants have: hood, pants, battery, lid Your own stable label, such as jacket/hood
Variant The exact item that ships SKU or variant ID; GTIN where assigned
Offer One seller’s terms for one variant: price, stock, shipping, returns Seller ID plus variant ID
Policy A seller’s store-wide terms: returns, shipping zones Seller ID plus policy version
Claim One checkable statement, with value, unit and condition A claim ID, as in our claim-record guide
Source The document behind a claim: manual, test report, certificate Document title and issue date

Edges

Edge From → to Meaning Rule
has_variant Group → variant This variant belongs to this family Every variant has exactly one group
has_component Group or variant → component This item includes this part A component on the group is on every variant unless excluded
asserts Claim → group, variant or component The claim is true of this node Attach to the narrowest node that’s true
inherits Group → variant (implicit) Group claims apply to each variant Only for claims attached to the group itself
excludes Claim → variant or offer This claim does not apply here Blocks inheritance. Always wins over inherits
overrides Claim → claim A narrower claim replaces a broader one for a node Use for real differences, such as a final-sale offer
offered_as Variant → offer This seller sells this variant One offer per seller per variant
governed_by Offer → policy The seller’s store-wide terms apply to this offer Only the offer’s own seller’s policy
derived_from Copy → claim A generated or rewritten copy of a claim A copy never adds scope, value or certainty the claim doesn’t have
cites Claim → source The document behind the claim Unknown claims cite nothing and say why

Resolution rules

To answer “is claim C true of variant V, as sold in offer O?”, walk the graph in this order. These rules are our proposal.

  1. Is C attached to V, or to a component V has? If it’s attached to a component, the answer is only ever about that component.
  2. Otherwise, is C attached to V’s group, with no excludes edge to V? If yes, it applies. If an exclusion exists, it doesn’t.
  3. Is C an offer or policy fact? Then look only at O and O’s own seller’s policy. Never another seller’s offer.
  4. Does a narrower claim override C for this node? The narrower one wins.
  5. None of the above? The answer is unknown, not “no”.

That gives three possible answers: applies, doesn’t apply, unknown. A system that collapses them into yes and no will either over-promise or quietly drop true facts.

Worked case: a two-piece snowsuit

On October 26, 2026 we searched Shopify’s agent catalog for “toddler snowsuit rated for minus 30”. Position 9 was a two-piece snowsuit, listed at USD 339.00. Store and material brand names are withheld. Here’s what its record said.

From the description:

  • “The insulated jacket features expandable sleeves that grow 4 cm, polar fleece lining for extra warmth, and a hood with [insulation brand] insulation rated to -30°C.”
  • “The snow pants include removable and adjustable suspenders, an elastic waist, and two zippered side pockets.”
  • [Reinforcement fabric] “at knees, seat, and hems”.

From the record’s other fields:

  • Sizes: 4, 5, 6, 7, 8, 9, 10, 12, 14 and 16. The returned variant was size 4.
  • Shopify’s generated spec list: “Insulation: [insulation brand] rated to -30°C”, “Material: Fleece with [reinforcement fabric] reinforcement”, “Pockets: Two zippered side pockets”, “Available sizes: 5-6 years, 7-8 years, 6 US, 16 US”.
  • A generated top feature: “[Insulation brand] insulation rated to -30°C keeps kids safe from the elements”.
  • Ratings: product 4.9 from 11 reviews; the size 4 variant 4.8 from 4.

The graph for this record

Node Claims attached Edge notes
Group: two-piece snowsuit Has a jacket and snow pants has_component to jacket and pants
Component: jacket Sleeves grow 4 cm; polar fleece lining has_component to hood
Component: jacket/hood Insulation rated to -30°C The rating is scoped to the hood only
Component: pants Adjustable suspenders; elastic waist; two zippered side pockets
Components: knees, seat, hems [Reinforcement fabric] reinforcement
Variants: sizes 4 to 16 Size label only; no size range stated has_variant from the group, ten times
Offer: size 4, this seller USD 339.00; available offered_as from size 4
Rating: product 4.9 from 11 Population not stated
Rating: size 4 variant 4.8 from 4 Population not stated

Where the generated copies broke the edges

Each generated line is a derived_from copy of a description claim. Three of them moved a claim to a wider node than the source supports:

Generated copy Source claim What changed
“Insulation: … rated to -30°C” The hood’s insulation is rated to -30°C Scope widened from the hood to the whole suit
“… keeps kids safe from the elements” No such claim Certainty added. The source states a rating, not a safety outcome
“Pockets: Two zippered side pockets” The snow pants have two zippered side pockets Scope widened from the pants to the whole product
“Material: Fleece with … reinforcement” Fleece is the jacket’s lining; reinforcement is at knees, seat and hems Two part-level facts merged into one product-level material
“Available sizes: 5-6 years, 7-8 years, 6 US, 16 US” Ten size options, 4 to 16 Doesn’t match the variant nodes at all

We can’t see what Shopify generated these from, so none of this proves an error in Shopify’s process. Shopify itself marks these fields as Inferred: generated or enriched by Shopify, and not merchant-authored source text. What the graph shows is where a reader of the generated lines would go wrong.

What the graph answers

Question Answer Why
Is the hood’s insulation rated to -30°C? Applies, to every size Hood claim; every variant has the hood through the group
Is the snowsuit rated to -30°C? Unknown The only rating is scoped to the hood. Nothing is attached to the whole suit
Does the jacket have pockets? Unknown The pockets are attached to the pants
Does size 6 exist? Yes It’s a variant node. The generated “6 US” doesn’t create or confirm it
What does size 4 cost from this seller? USD 339.00, on October 26 Offer node, observed on that date
What’s size 4’s rating? 4.8 from 4, or 4.9 from 11 for the product Two nodes, two populations. Don’t merge them

The second row is the one that matters to a parent shopping for -30°C weather. A shopper whose need is “the whole suit for -30°C” gets an honest unknown, not a yes borrowed from the hood. That’s why the catalog research insists on the word hood.

The merchant’s fix follows from the graph. If the whole suit has a temperature rating from a real source, attach it to the group, with its condition. If it doesn’t, the page should say what the hood rating covers, in those words, so no copy can widen it.

Exclusions and overrides, with hypothetical examples

The snowsuit needed scope edges. Other catalogues need the other two. These examples are hypothetical.

Situation Without the edge With it
A leather boot family where one colour is synthetic “Leather upper” on the group reaches every colour excludes from “leather upper” to the synthetic colour, plus its own material claim
A store with 30-day returns and one final-sale colourway The store policy reaches every offer A final-sale claim on that offer overrides the store policy
A humidifier family where only the 6 L model covers 600 sq ft The hero model’s coverage sits in the shared description Coverage attached to each variant, nothing on the group
A seller reselling your product under the same catalog product Your return policy appears to cover their offer Their offer is governed_by their own policy; no edge to yours

The markup vocabularies support part of this. Schema.org lets a return policy sit on an organization, a product or an offer. Google recommends store-wide return policy markup under your Organization. So an offer-level policy is the place for a final-sale exception. What neither vocabulary has is a way to say “every variant except this one” or “this part only”. Those exceptions have to live in your own data, and in visible text that says them plainly.

Offers when a catalog clusters sellers

Shopify says Global Catalog search results are clustered by a Universal Product ID and include offers from multiple merchants, with a separate step that returns pricing and seller checkout links for the chosen variant. OpenAI says that after a shopper picks a product, ChatGPT may show other merchants offering it, at the same or different prices, ranked partly on whether a seller is the maker or primary seller.

So the group node may be shared between sellers while the offer nodes are not. Product identity and specifications can reasonably be the same across sellers of one item. Price, stock, shipping and returns must stay with each seller’s own offer.

We haven’t seen how clustering merges facts. In our 162-search snapshot, every one of the 1,620 results carried exactly one variant from one seller, and we didn’t make the follow-up call that returns options and sellers. Treat the multi-seller part of the graph as documented, not observed.

Encode it in your own data

You don’t need graph software. A list of edges in a spreadsheet or JSON is enough:

[
  { "from": "snowsuit", "edge": "has_component", "to": "jacket" },
  { "from": "jacket", "edge": "has_component", "to": "jacket/hood" },
  { "from": "claim/hood-insulation-minus-30c", "edge": "asserts", "to": "jacket/hood" },
  { "from": "snowsuit", "edge": "has_variant", "to": "size-4" },
  { "from": "size-4", "edge": "offered_as", "to": "offer/[seller]/size-4" },
  { "from": "generated/insulation-line", "edge": "derived_from", "to": "claim/hood-insulation-minus-30c" }
]

Then publish each resolved answer where readers already look. Markup: ProductGroup with hasVariant or isVariantOf, group properties only for facts that really apply to every variant, and hasMerchantReturnPolicy on the offer when it differs. On Shopify: variant fields and metafields for variant facts, and Catalog Mapping if separate products should be grouped as one listing. Shopify’s help page says Catalog Mapping can do that grouping and source data from metafields; we haven’t verified that screen. In every case, put component scope in the visible sentence (“the hood’s insulation”), because no structured field carries it.

What this model is not

  • Not a ranking lever. It keeps facts where they’re true. We haven’t measured whether that changes picks.
  • Not a sibling-choice experiment. Which variant an agent picks, and whether a hero variant draws picks away from its siblings, needs its own controlled test.
  • Not a rule to collapse variants. Nothing here suggests one product per brand or one variant per product. Keep every variant a shopper would choose differently.
  • Not a platform format. No assistant consumes these edges. They decide what you publish.

How we checked

On October 27, 2026 we re-read Schema.org’s ProductGroup and MerchantReturnPolicy pages, Google’s Product and Product variant structured-data pages, Shopify’s Global Catalog documentation and agentic storefronts help page, and OpenAI’s shopping help page, and quoted or paraphrased only what they say now.

We reopened the saved Shopify agent-catalog response for “toddler snowsuit rated for minus 30”, taken on October 26, 2026 with no buyer context, top 10 results. For position 9 we read the description, option list, returned variant, price, both ratings and Shopify’s generated spec, feature and selling-point lists word for word; every quote in the tables comes from that record, with brand names replaced. A script confirmed that all 1,620 results in the 162-search snapshot carried one variant from one seller. We didn’t call get_product, query any assistant or inspect the garment.

Your next step

Pick one product that has parts or a size range. Write every claim on its page as one line, then next to each write the narrowest node it’s true of: the whole product, one part, one variant or one seller’s offer. Any claim you can only attach to a part, but your page states about the whole product, is a scope leak. Fix the sentence first.