Adapters and source authority
Adapters turn one normalized input into evidence. They do not merge results, cache calls, or decide the final draft.
Current adapters
Section titled “Current adapters”| Adapter | Input | Evidence | Status |
|---|---|---|---|
| Barcode Lookup | barcode | product identity, images, merchant offers | active when configured |
| Exa | barcode or text | web evidence, search suggestions, and images | optional, never authoritative |
| OpenAI packaging | resolved product | unit type, pack size, minimum order, and order increment | optional, never authoritative or cached |
| UPCitemdb | barcode | product identity, images, merchant offers | active |
| Open Food Facts | barcode | product identity and package data | active |
| Fixture catalog | barcode, URL, or text | deterministic demo data | local/demo only |
| Supplier samples | barcode, supplier URL, supplier SKU, or MPN | shared product identity and supplier offer | optional 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.
Good next examples
Section titled “Good next examples”| Adapter category | Example input | What it should contribute | Authority |
|---|---|---|---|
| Tenant catalog | tenant barcode, MPN, internal SKU, approved alias | identity, package data, preferred supplier | authoritative only for an exact tenant-approved mapping |
| Existing tenant items | previous barcode or approved alias | known item identity | authoritative when based on human-approved item data |
| Manufacturer catalog | GTIN or manufacturer part number | canonical identity, description, images | authoritative on an exact identifier |
| Supplier catalog | supplier SKU or product URL | offer, price, pack size, lead time | authoritative for the offer; identity only when explicitly mapped |
| Purchase history | prior supplier SKU or description | likely supplier and ordering data | not authoritative for identity |
| Label/OCR extraction | label text or an image processed upstream | candidate identifiers and description | not authoritative until corroborated |
| Web search | URL or free text | discovery candidates and images | not 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.
Authoring rules
Section titled “Authoring rules”Implement SourceAdapter:
src/server/lib/enrichment/engine/adapters/source-adapter.ts
in arda-frontend-app
Each adapter must:
- Use a stable
namefor logs and provenance. - Return
falsefromsupportsfor input kinds it cannot use. - Read
tenantIdand hints fromLookupContextwhen needed. - Return an empty list for a successful lookup with no match.
- Throw on upstream errors. The reconciler owns timeout and degradation behavior.
- Bound offers and images instead of returning an upstream catalog dump.
- Set
authoritativeonly for an exact identifier or an explicit, tenant-approved mapping. - Keep provider parsing in the adapter. Reconciliation belongs in
Reconciler. - Test a match, no match, malformed upstream data, and upstream failure.
- Set
cacheable: falsefor price or product content that must be refreshed. - Set
alwaysRunonly 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-provided data
Section titled “Tenant-provided data”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.
Runnable supplier example
Section titled “Runnable supplier example”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:
- authenticated with a client certificate, username, and password;
- obtained a bearer token, valid for up to 24 hours; and
- 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/priceThe 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/.
Input model limits
Section titled “Input model limits”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.
Related implementation and design
Section titled “Related implementation and design”Copyright: © Arda Systems 2025-2026, All rights reserved