2026-10-15 · resilience · catalog continuity

When the store API goes dark: a trustworthy continuity layer for agentic commerce

How signed, bounded snapshots and a recovery state machine keep merchants discoverable without inventing availability or overriding merchant control.

TL;DR — When a store's live API fails, KaliCart can switch discovery to a merchant-signed, complete and freshness-bounded snapshot that was verified before the incident. In a controlled test the switch took 7.6 seconds, with zero snapshot downloads from the merchant and zero AI calls. Returning to live requires a full authoritative re-read. The snapshot keeps a store discoverable; it is never an authority for checkout, payment or final availability.

On 3 October we described the building block: a signed catalog snapshot that keeps discovery honest when a WooCommerce API is unreachable. This post is about what it took to put that snapshot into operation as a continuity layer, and what we measured when we broke a live store on purpose.

An AI shopping agent asks a federated catalog for "a gluten-free flour under €10". One of the best matches comes from a small WooCommerce store. At that exact moment, the store's REST API returns a 500: a hosting hiccup, a maintenance window, an anti-bot rule that just changed.

What should the network do?

There are two obvious answers, and both are wrong.

Drop the store. Simple and "safe", but it punishes the merchant for something that has nothing to do with their catalog. In agentic commerce, a store that disappears for an hour disappears from every answer generated during that hour. Discovery is not a page you can refresh later; it is a decision an agent makes now.

Serve whatever we cached. Convenient, but it quietly turns a cache into an authority. How old is it? Is it complete? Has the merchant withdrawn consent since? A cache has no answers to those questions, and an agent cannot tell the difference.

The tension is easy to state:

Availability without authority is unsafe. Authority without continuity is fragile.

At KaliCart we treated that gap as its own infrastructure problem: catalog continuity. This post describes how we designed it, what we measured, and what we got wrong along the way.

The Catalog Continuity Contract

The core idea is not a cache. It is a contract between the merchant and the network:

The merchant authorizes the network to temporarily serve the last complete, verified representation of its catalog when the live channel is unavailable, within explicit limits.

We hold that contract to four invariants:

  1. Provenance. Every snapshot is published by the merchant's own plugin and bound to a verified store identity. The network never builds a substitute catalog from scraping or guesswork.
  2. Completeness. A snapshot is either complete or it is not served. Partial catalogs silently mislead agents ("this store only sells three products").
  3. Bounded freshness. A snapshot has an expiry. Past it, the store is suspended, not "best-effort" served.
  4. Reversibility. An explicit consent revocation, a failed signature or identity verification, or freshness expiry cuts the path, and the network falls back to fail-closed.

Everything else in the design is the machinery that keeps those four promises under real-world failure.

1 · Provenance
Merchant-signed
Published by the merchant's own plugin and bound to a verified store identity. Never scraped or guessed.
→
2 · Completeness
All or nothing
A snapshot is complete or it is not served. Partial catalogs silently mislead agents.
→
3 · Bounded freshness
It expires
Past its expiry the store is suspended, not "best-effort" served.
→
4 · Reversibility
Revocation wins
Explicit revocation, failed verification or expiry cut the path to fail-closed.
Live REST stays authoritative. The signed snapshot is a verified hot standby, served only during an outage and only inside these four limits.

What the merchant publishes

The KaliCart Bridge plugin (WordPress/WooCommerce) periodically publishes a static snapshot of the store's public catalog: a manifest plus content shards. The manifest carries a monotonic sequence number, a content hash, a completeness flag and a generation timestamp. The plugin announces each new generation through a signed heartbeat, so the network learns about it within minutes instead of discovering it by polling.

Two design choices matter here:

The hot candidate: verify before the emergency

The naive version of a fallback downloads the snapshot when the outage happens. That is the worst possible moment: the merchant's server is already struggling, and you are about to make it serve the whole catalog to you.

Instead, the network keeps a hot candidate: the latest snapshot, already downloaded, verified against its manifest and staged, ready to be switched in. Verification happens on a calm day, not during the incident.

When the live API fails, switching source is a local operation. In our canary on a test store with 110 products:

(These are measurements from a controlled test, not service-level promises.)

That last point deserves its own section.

Keep AI out of the control plane

Our catalog pipeline uses language models to enrich products: categories, attributes, normalized descriptions. It would be easy to let a source switch trigger re-enrichment "just to be safe". That would turn every outage into a bill, and every flapping API into a cost amplifier.

So we made a hard rule: switching between live and snapshot is deterministic and AI-free. Enrichment is keyed on the content that actually feeds it. If the snapshot carries the same product content as the live API, the cached enrichment is reused. We track unexpected AI calls as an explicit metric, and in the canary that number was zero.

The general principle: models can live in the data plane, never in the decision of which source is authoritative right now.

A state machine with hysteresis

Serving follows a small state machine:

Normal
Live
The merchant's REST API is the source. A verified snapshot waits, already staged.
→
Sustained failures
Snapshot
Local switch to the hot candidate: no download, no AI. Flapping stores are held here.
→
Sustained health
Recovery
A full, authoritative re-read of the live catalog, applied atomically.
→
Re-read OK
Live again
If the re-read fails, the store stays on the snapshot that was still valid.
A health check alone never flips a store back to live: recovery is earned.

A few properties keep it from becoming a liability:

And the snapshot stays hot through the round trip. One of the bugs we found (more on that below) was a routine refresh destroying the standby right after recovery: the next outage would have fallen back to the slow path. The fix: keep the candidate as long as it is still the current generation, and re-arm it promptly after recovery when it is missing. In a second simulated outage, the switch came straight from the hot candidate, with no download.

Fail-closed, with the right semantics

"Fail-closed" sounds simple until you ask closed on what.

We ended up distinguishing four situations that look similar from the outside:

  1. The API is down but the plugin is there (5xx, timeouts, maintenance). That's an outage: serve the snapshot within its freshness window.
  2. WordPress answers, but the plugin is gone. It may be a temporary deactivation, an update in progress or recovery mode. The network treats absence alone as an outage, not as an explicit revocation: a previously verified hot snapshot may remain usable only within the consent and freshness bounds already in force, after which the store is suspended.
  3. The merchant explicitly revokes consent. That's immediate. No grace period, no snapshot.
  4. The snapshot itself expires or fails verification. Suspended, regardless of anything else.

Recovery starts symmetrically. In our test, a store under active monitoring was confirmed healthy again under two minutes after the plugin was reactivated. For stores checked less often, the reactivated plugin sends a signed heartbeat a couple of minutes later, and the network uses that signal to re-check the store right away instead of waiting hours for its regular schedule. Returning serving to live is a separate, guarded step: it still requires the full authoritative re-read and the state-machine conditions to pass.

The point is that "missing" and "revoked" are different facts, and a continuity layer has to keep them apart. Treating every absence as a revocation punishes merchants for routine maintenance. Treating every absence as consent forever ignores the merchant's control.

Not every release should cost the merchant a full re-read

A quieter lesson came from routine plugin releases. Our network used to force a full re-read of a store's catalog whenever the plugin version changed, to make sure every product carried the newest format. For one store with ~950 products, that meant about 50 minutes of work and load on the merchant's server, for a release that only changed lifecycle code.

We now separate the plugin's software version from the catalog data version it produces. For current Bridge versions that declare that data version, routine full re-reads are keyed to a data-format change rather than to every software release; legacy or unknown formats stay conservative. The work is not "free": it is simply no longer paid for releases that don't change catalog data.

How we built it: implementation, independent review, human decision

KaliCart is built by a very small team, with AI as a core part of the engineering loop. The method that worked for this project:

The reviews found real bugs that the implementation's own tests missed:

We don't present two AIs as a guarantee. The value is in the independent reproductions and in a human who owns the trade-offs. One example: when a plugin is deactivated, briefly serving a still-valid snapshot is a risk we chose explicitly, as the lesser evil, and bounded in time. That's a decision, not a default.

Operational lessons

What this is, and what it is not

The snapshot is not an authority for checkout, payment or final availability. The merchant's live store remains the source of truth for the purchase. What the continuity layer protects is discoverability: an agent can still find and describe the store's products, with clear provenance, while the live channel recovers.

Agentic commerce will not be built on APIs alone. Agents act on a store's products in real time and at scale, and every gap becomes a lost answer. The infrastructure underneath needs what the web learned from CDNs: continuity. Merchant-signed, bounded, verifiable and reversible.

That's the Catalog Continuity Contract. We think every agentic catalog will need one.

Sources and implementation references

← All posts