Skip to content

Adapters and source authority

Adapters turn one normalized input into evidence. They do not merge results, cache calls, or decide the final draft.

AdapterInputEvidenceStatus
Barcode Lookupbarcodeproduct identity, images, merchant offersactive when configured
Exabarcode or textweb evidence, search suggestions, and imagesoptional, never authoritative
OpenAI packagingresolved productunit type, pack size, minimum order, and order incrementoptional, never authoritative or cached
UPCitemdbbarcodeproduct identity, images, merchant offersactive
Open Food Factsbarcodeproduct identity and package dataactive
Fixture catalogbarcode, URL, or textdeterministic demo datalocal/demo only
Supplier samplesbarcode, supplier URL, supplier SKU, or MPNshared product identity and supplier offeroptional sample

Provider names are implementation details. The useful adapter categories are identity catalogs, tenant catalogs, supplier catalogs, extractors, and discovery sources.

The engine has no Amazon adapter. The BFF reaches Amazon by delegating to /api/amazon/import (URL/ASIN) and /api/amazon/search (text), outside the engine — see Front door: wrapping Amazon.

Adapter categoryExample inputWhat it should contributeAuthority
Tenant catalogtenant barcode, MPN, internal SKU, approved aliasidentity, package data, preferred supplierauthoritative only for an exact tenant-approved mapping
Existing tenant itemsprevious barcode or approved aliasknown item identityauthoritative when based on human-approved item data
Manufacturer catalogGTIN or manufacturer part numbercanonical identity, description, imagesauthoritative on an exact identifier
Supplier catalogsupplier SKU or product URLoffer, price, pack size, lead timeauthoritative for the offer; identity only when explicitly mapped
Purchase historyprior supplier SKU or descriptionlikely supplier and ordering datanot authoritative for identity
Label/OCR extractionlabel text or an image processed upstreamcandidate identifiers and descriptionnot authoritative until corroborated
Web searchURL or free textdiscovery candidates and imagesnot authoritative

authoritative applies to a candidate, not an entire adapter. A manufacturer adapter can mark an exact GTIN match authoritative while leaving a fuzzy name search non-authoritative.

Implement SourceAdapter: src/server/lib/enrichment/engine/adapters/source-adapter.ts in arda-frontend-app

Each adapter must:

  1. Use a stable name for logs and provenance.
  2. Return false from supports for input kinds it cannot use.
  3. Read tenantId and hints from LookupContext when needed.
  4. Return an empty list for a successful lookup with no match.
  5. Throw on upstream errors. The reconciler owns timeout and degradation behavior.
  6. Bound offers and images instead of returning an upstream catalog dump.
  7. Set authoritative only for an exact identifier or an explicit, tenant-approved mapping.
  8. Keep provider parsing in the adapter. Reconciliation belongs in Reconciler.
  9. Test a match, no match, malformed upstream data, and upstream failure.
  10. Set cacheable: false for price or product content that must be refreshed.
  11. Set alwaysRun only for a live commerce source that must run even when an identity-memory shortcut would otherwise skip it.

An adapter may return one product candidate plus separate offer candidates. This keeps product identity independent from supplier ranking.

Structured provider responses should be mapped directly. AI extraction is a separate fallback for unstructured URL or text inputs, not a required step in the barcode path. It must remain non-authoritative until an identifier is corroborated.

ModelExtractionAdapter is the disabled-by-default path for that fallback. It depends on a small ProductExtractor interface and emits non-authoritative, non-cacheable discovery candidates.

The active model path is narrower: OpenAiPackagingAdapter receives an already-resolved product and may only suggest packaging fields under a strict JSON schema. It cannot modify identity, supplier, or price.

Tenant data should live in a tenant-scoped catalog repository and be read by a TenantCatalogAdapter. It is not tenant memory:

  • tenant catalog data is user-managed source evidence;
  • tenant memory is a cache of matched enrichment results.

Importing tenant data needs a separate CSV/API ingestion path with validation, provenance, and audit fields. The enrichment import route should remain read-only. LookupContext.tenantId is already available to adapters so the lookup can be scoped safely.

Do not encode a catalog in hints. Hints are request-level disambiguation, not durable source data.

SupplierCatalogAdapter reads the sample feed at the engine’s supplier-catalog.json resource. It includes shared Grainger, Uline, and McMaster-Carr records and demonstrates barcode, supplier SKU, MPN, and URL matching. Enable it with ENRICHMENT_SUPPLIER_SAMPLES_ENABLED=true.

The adapter builds barcode, URL, supplier-SKU, and MPN indexes at startup. supplier-profiles.json separately defines supplier domains and category keywords used to constrain Exa. Request hints, resolved product terms, and tenant policy can select a smaller domain set. Without a supplier signal, Exa performs a broad product-page search instead of silently restricting discovery.

The prototype feed is intentionally global. Catalog records support an optional tenantId, and adapters already receive LookupContext.tenantId, so a future database-backed source can add tenant scope without changing the route or adapter contracts.

This sample models an imported or manually maintained supplier feed. It does not scrape supplier storefronts.

McMaster’s Product Information API is a refresh source, not a discovery source. It accepts known McMaster part numbers after an approved customer has:

  1. authenticated with a client certificate, username, and password;
  2. obtained a bearer token, valid for up to 24 hours; and
  3. subscribed to each product, subject to account and daily limits.

The practical flow is therefore:

barcode -> local approved barcode/part-number mapping -> McMaster part number
-> subscribed Product Information API lookup -> current details/price

The local index provides fast barcode discovery. A future authorized importer can refresh product status, descriptions, specifications, images, and price without changing the lookup contract. It must handle expired-token retries, subscription limits, discontinued replacements, and the price endpoint’s quantity tiers. See https://www.mcmaster.com/help/api/.

The current import accepts barcode, URL, or free text. That is enough for the active adapters. Structured identifiers and images should be explicit future input types rather than conventions embedded in text, for example:

{
"kind": "identifier",
"namespace": "manufacturer_part_number",
"value": "2090-48EC"
}

Image input would require an upload or asset reference. OCR output can use the existing text path until that contract exists.