DEV Community

Cover image for The Inventory Bug Hiding in Every AI-Facing Store (And in Every LLM)
Almin Zolotic
Almin Zolotic

Posted on

The Inventory Bug Hiding in Every AI-Facing Store (And in Every LLM)

At Zologic we build UCPReady, the WooCommerce implementation of the Universal Commerce Protocol. It's the infrastructure that lets AI agents like Claude, Gemini, and ChatGPT discover, search, and check out on a WooCommerce store autonomously. Most of what we write about is protocol compliance, checkout funnels, agent behavior. This one's different. It's about a bug we found in a customer's store that has nothing to do with AI agents on the surface, and everything to do with them underneath.

The incident

One of our customers runs a fragrance dropshipping store with a catalog north of 53,000 SKUs, synced nightly from a wholesale supplier's API. Standard architecture: pull the vendor feed, match by SKU, update price and stock.

One night, a customer ordered a product. The order came through, payment cleared, and the product didn't exist anymore. Not out of stock. Deleted upstream. The wholesaler had quietly removed the SKU weeks earlier after it sat unsold for over a month. The store's sync script had no way of knowing, because it was never built to ask.

Why this matters more than it looks

Here's the part that made us stop and think harder than a routine sync bug usually warrants: at 53,000+ SKUs, a store like this isn't just serving human shoppers anymore. It's a surface AI agents crawl, index, and reason over, through UCP manifests, MCP tool calls, product schemas. When an agent (or a human, for that matter) asks "is this in stock," the honest answer your system should be able to give is "as of the last time I confirmed it." Most systems don't track that distinction. They track "the last value I stored," full stop.

That's the bug. Not a missing if statement. A wrong mental model. The store's database wasn't holding "the inventory." It was holding a cached copy of what the vendor said, last time anyone asked. And a cache with no expiry policy isn't a cache. It's a slowly rotting assumption.

What we found once we fixed it

We rebuilt the sync to track presence, not just values: every SKU the vendor's feed actually returns gets marked as reconfirmed this run. Anything previously published that's absent from a full feed read gets quarantined, not deleted, just pulled from the storefront, ready to snap back the instant the vendor restocks it.

Running it for the first time against a catalog that had never had this check before surfaced the scale of the accumulated drift:

  • ~2,700 products (over 11% of the published catalog) had been silently stale, some for months
  • 151 new products picked up automatically in the same pass
  • Total catalog stock units moved from 921,786 to 955,594 in a single sync: a +33,808 unit correction
  • Published stock alone: 676,169 → 698,153 (+21,984 units)
  • Draft-side stock: 245,617 → 257,441 (+11,824 units) That's not a rounding error. That's tens of thousands of stock units that were wrong, on a store an AI shopping agent could have been confidently quoting availability from, minutes before check-in.

The paradigm shift

Physical inventory feels like it should be a stable, durable fact. A bottle either exists in a warehouse or it doesn't. But from your system's point of view, that's never something you observe directly. It's an inference from the last API response you got, and every inference like that has a shelf life whether you model it or not.

Anything your system ingests from an external source is perishable by default. Freshness has to be actively reconfirmed, never assumed from silence. "The feed didn't mention it" and "the feed confirmed it's fine" have to be different states in your data model. Collapsing them into one is exactly the bug we found.

Where this converges with everything else we build

This is the same failure shape we deal with constantly on the UCP side. An AI agent operating on stale product data doesn't just annoy a customer. It makes a purchase decision, or tells a shopper a store carries something it doesn't, based on a snapshot nobody re-verified. Multiply that by every WooCommerce store that gets discovered and transacted with autonomously, and "is this data still true, or just still there" stops being a backend nitpick and becomes a trust question for the entire agentic commerce stack.

And if you work with LLMs directly, you already know this pattern under a different name. A model's training data is a frozen snapshot. "Who's the CEO," "does this product line still exist," "is this API still current" all fail the exact same way our customer's SKU did: not because the model is wrong, but because nothing tells it its answer has gone stale. That's why retrieval and web search exist. They reintroduce the "did I just reconfirm this" check that a frozen snapshot structurally can't perform on its own. Even RAG can quietly reintroduce the bug at a smaller scale: an indexed-once, never-recrawled document lets "it's in my vector store" stand in for "it's true," when it only ever meant "it was true whenever I last indexed it."

Same fix, every time: track last confirmed, not just last known.

Takeaway

If your store, or your product, or your model, holds any data it didn't generate itself, ask the unglamorous question up front: what tells you an entry has gone stale, and is "I haven't seen an update" quietly standing in for "confirmed still valid"? At 53,000 SKUs, that gap was worth tens of thousands of stock units and a very real risk of selling something that doesn't exist. At agent scale, it's worse. It's a trust failure nobody notices until an autonomous checkout completes on a product that isn't there.

Perishable by default. Freshness earned, not assumed. That's the standard we're building UCPReady to hold stores to as AI agents become a bigger share of who's actually reading your catalog.

Top comments (0)