t ambiguity requires enforcing a strict mapping between product-level axis declarations and variant-level selections. The implementation follows four architectural steps.
Step 1: Declare Canonical Axes at the Product Level
Define selectable dimensions explicitly. Each axis must carry a stable identifier and a normalized label set. This establishes the contract that variants must fulfill.
interface SelectionAxis {
axis_id: string;
display_name: string;
allowed_values: string[];
}
interface ProductDefinition {
product_uid: string;
title: string;
selectable_axes: SelectionAxis[];
}
Rationale: Centralizing axis definitions prevents drift. When allowed_values is explicitly enumerated, downstream validation can reject variants that introduce undeclared options. This also enables agents to validate user intent against a known vocabulary before cart submission.
Step 2: Map Variants to Explicit Selection Arrays
Every variant must declare its position across all declared axes using a standardized selection format. This replaces implicit ordering or opaque IDs with explicit key-value pairs.
interface AxisSelection {
axis_ref: string;
value_label: string;
}
interface VariantNode {
variant_uid: string;
selections: AxisSelection[];
pricing: { base_amount: number; currency: string };
inventory: { status: InventoryStatus; sku: string };
}
Rationale: The selections array mirrors the UCP selected_option shape but uses explicit references (axis_ref) to guarantee alignment with ProductDefinition.selectable_axes. Agents can now perform exact string matching against value_label without parsing compound strings or guessing ordinal positions.
Step 3: Enforce Cardinality Synchronization
The number of declared axis combinations must match the number of actual variants. If a product declares Color × Size, the variant array must contain exactly N_colors × N_sizes entries, or the axis declaration must be pruned.
function validateVariantCardinality(product: ProductDefinition, variants: VariantNode[]): boolean {
const expectedCombinations = product.selectable_axes.reduce(
(acc, axis) => acc * axis.allowed_values.length, 1
);
return variants.length === expectedCombinations;
}
Rationale: Phantom axes cause agents to request combinations that do not exist. Lenient agents guess; strict agents abort. Synchronizing cardinality eliminates both failure modes.
Step 4: Attach Deterministic Availability Signals
Inventory state must be embedded directly in the variant payload. Agents use this to filter out-of-stock items before cart submission, preventing checkout-layer rejections.
type InventoryStatus = 'in_stock' | 'backorder' | 'preorder' | 'out_of_stock' | 'discontinued';
interface VariantNode {
// ... previous fields
inventory: {
status: InventoryStatus;
restock_date?: string;
sku: string;
};
}
Rationale: Checkout endpoints reject unavailable SKUs. By surfacing status at the variant level, agents can apply substitution logic or surface accurate availability messages to users, reducing retry cycles and cart_created stalls.
Pitfall Guide
1. Opaque Identifiers Without Axis Mapping
Explanation: Variants are exposed as bare IDs (var_8821) with no option metadata. Agents cannot map user intent to a specific SKU and default to the first entry or random selection.
Fix: Every variant must include a selections array that explicitly declares its position across all product axes. Never rely on implicit ordering.
2. Compound Attribute Strings
Explanation: Multiple dimensions are merged into a single label (e.g., "Medium / Regular Fit"). Agents split the string inconsistently across models, causing divergent variant picks for identical prompts.
Fix: Decompose compound strings into separate axes. "Medium" belongs to Size, "Regular" belongs to Fit. Each axis gets its own AxisSelection entry.
3. Lexical Inconsistency Across Siblings
Explanation: Variants on the same product use different labels for the same value ("M", "Medium", "med", "Medium "). Agents perform exact string matching; lexical drift breaks resolution.
Fix: Enforce a canonical label registry at the product level. Validate all variant payloads against this registry during ingestion. Strip trailing whitespace and normalize case.
4. Silent Stock Omissions
Explanation: Variants lack availability flags. Agents add sold-out items to the cart, triggering checkout rejection and silent session termination.
Fix: Always populate the inventory.status field. Use standardized enum values. If stock data is unavailable, default to out_of_stock rather than omitting the field.
5. Phantom Axis Declarations
Explanation: selectable_axes declares dimensions that no variant actually implements. Agents attempt to satisfy selections that have no corresponding SKU.
Fix: Run a cardinality check before publishing. If an axis has no variant coverage, remove it from selectable_axes. Do not leave dangling dimensions.
6. Locale-Dependent Label Drift
Explanation: Variant labels are translated dynamically without preserving a stable canonical key. Agents caching responses in one locale fail when switching regions.
Fix: Separate value_label (display) from value_key (stable identifier). Agents should match against value_key, while UI layers render value_label based on locale.
7. Stale Variant Caching
Explanation: Product catalogs cache variant payloads for performance, but inventory or pricing updates are not propagated. Agents operate on outdated data, causing cart rejections.
Fix: Implement cache invalidation hooks tied to inventory management systems. Use ETags or versioned variant payloads (variant_version: 14) to force agent refreshes on state changes.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Simple product with single variant | Omit selectable_axes; use metadata.attributes for descriptive properties | Prevents agents from rendering unnecessary pickers; reduces payload size | Low (schema simplification) |
| Multi-variant product with stable inventory | Canonical selections array + explicit inventory.status | Guarantees deterministic agent matching; eliminates checkout rejections | Medium (data modeling effort) |
| Dynamic inventory with frequent stockouts | Variant-level status field + cache versioning | Enables agents to filter unavailable SKUs before cart submission; reduces retry latency | Medium (inventory sync integration) |
| Global marketplace with multiple locales | Stable value_key + locale-aware value_label | Prevents resolution failures across regions; maintains agent consistency | High (localization pipeline) |
| Legacy catalog with compound strings | Automated decomposition script + canonical registry | Fixes agent divergence without rewriting frontend UI; aligns with spec requirements | Medium (data migration) |
Configuration Template
// product-catalog.types.ts
export interface AxisDeclaration {
axis_id: string;
display_name: string;
canonical_values: string[];
}
export interface VariantSelection {
axis_ref: string;
value_key: string;
display_label: string;
}
export type StockStatus = 'in_stock' | 'backorder' | 'preorder' | 'out_of_stock' | 'discontinued';
export interface VariantPayload {
variant_uid: string;
selections: VariantSelection[];
pricing: {
base_amount: number;
currency: string;
discount_applied?: number;
};
inventory: {
status: StockStatus;
sku: string;
restock_estimate?: string;
};
metadata?: Record<string, string | number | boolean>;
}
export interface ProductCatalogEntry {
product_uid: string;
title: string;
description: string;
selectable_axes: AxisDeclaration[];
variants: VariantPayload[];
schema_version: '2026-04-08';
}
Quick Start Guide
- Extract current variant payloads from your catalog API and run a lexical consistency check against a canonical label registry. Flag any compound strings or mismatched labels.
- Refactor variant objects to include a
selections array. Map each variant to its corresponding axes using explicit axis_ref and value_key pairs. Remove implicit ordering.
- Attach inventory status to every variant. Use standardized
StockStatus enums. Ensure out-of-stock items are explicitly marked rather than omitted.
- Validate cardinality by comparing
selectable_axes combinations against actual variant counts. Prune unused axes or generate missing variants to maintain synchronization.
- Deploy with cache versioning. Add a
variant_version field or ETag header to force agent refreshes. Monitor cart_created session rates; a drop below 5% indicates successful alignment.