Skip to content

owieschon/sku-resolver

Repository files navigation

SKU Resolution Engine

Two catalog identifiers can differ by one character while describing physically different parts. A confident substitution looks harmless on a quote and becomes expensive at the loading dock. SKU Resolution Engine decodes catalog-specific part-number grammar for customer-facing voice and chat agents and for RFQ/PO processing. Uncertain language resolves only when the active catalog warrants the answer; otherwise the engine returns pending_disambiguation or unresolvable.

A language model can rank retrieved options at the edge. It cannot author the part number of record. The binding path is deterministic and translate() refuses to run without a catalog; catalog-free parsing is a separate, non-binding API.

The first grammar was derived from one 10,000+ SKU industrial catalog. Additional product catalogs exercised the induction and validation machinery. The reusable mechanism segments part numbers, groups families, proposes field roles, asks an SME about unresolved segments, and binds accepted interpretations to catalog rows. Those trials support reuse across many structured product catalogs; they do not establish universal catalog coverage.

Free text moves through a deterministic catalog-backed resolution path. Exact evidence resolves, ambiguity stays pending, and unsupported context remains unresolvable.

Three proofs, kept separate

Question Executable evidence Current result What it does not prove
Can the engine ever return a string outside its catalog? scripts/roundtrip_audit.py over the whole generated catalog 9,487/9,487 identity; 0 silent rewrites; 96.96% constructive round-trip Independent grammar accuracy—the catalog is generated from the grammar.
Does it stay inside the catalog under damaged input? scripts/noise_resilience_audit.py over 1,200 seeded typo/OCR/partial mutations 0 inventions That every correction is the intended part; non-high corrections require review.
Does behavior match labels not computed by product code? scripts/independent_resolution_eval.py over a literal catalog and manual cases 14/14 Field accuracy or pristine preregistration; this is a small post-hoc external evaluation.

The distinction is deliberate. Self-consistency, robustness, and externally labeled behavior answer different questions; one flattering number should not stand in for all three.

See it in 90 seconds

python -m pip install -e ".[dev]"
python scripts/independent_resolution_eval.py
python scripts/roundtrip_audit.py

The evaluation exercises three representative outcomes without publishing its literal identifiers in this documentation: a specific request resolves to a catalog row, an ambiguous request requires review, and an unsupported request remains unresolvable. The executable cases and expected states live in scripts/independent_resolution_eval.py.

Decision boundary

free text
  → normalize and extract a typed specification
  → exact / constructed / fuzzy catalog lookup
  → contradiction-aware disambiguation
  → resolved | pending_disambiguation | unresolvable
  • Exact or constructed answers must bind to a row in this tenant's catalog.
  • A missing exact SKU-shaped token is not silently substituted by the disambiguator.
  • Distance-based typo corrections are catalog-backed but marked non-high and require a human readback.
  • Retrieval proposes real catalog rows. The optional LLM chooser is bind-guarded to that retrieved set; an invented selection is rejected.
  • Raw free-text tracing is disabled by default and requires an explicit opt-in.

Start reading here

The normal vertical slice is mapped in docs/READING_PATH.md:

  1. src/resolution/service.py — tenant-bound orchestration and response contract;
  2. src/sku_translator/translator.py — deterministic resolution and refusal paths;
  3. src/resolution/chooser.py — the constrained model seam;
  4. tests/test_independent_resolution_eval.py — the external executable oracle.

The 5,900-line legacy pattern registry is named debt, not hidden craft. Its precedence is semantic and its decoders are heterogeneous, so a wholesale generator would move rather than remove complexity. docs/PATTERN_REGISTRY.md records the safe decomposition sequence and its required reachability witnesses.

Verify everything

ruff check .
mypy
pytest
python scripts/roundtrip_audit.py
python scripts/noise_resilience_audit.py
python scripts/independent_resolution_eval.py

Provider and live-ERP tests remain credential-gated. The deterministic core, catalog adapters, fulfillment logic, gateway policy, and simulated fault-injection paths run offline.

Claim and provenance boundaries

  • This repository is intentionally public under Apache-2.0. Its source, derived grammar, synthetic fixtures, and history are the published artifact.
  • The original 10,000+ SKU source catalog is not included. The generated structural catalog exercises the derived grammar; it is not an independent accuracy set.
  • The independent evaluation is manually labeled and executable, but small and post-hoc.
  • Live LLM, speech, telephony, and ERP I/O require credentials; scripted implementations exercise their parsing and decision boundaries in CI.
  • The long-tail grammar was derived from the original industrial catalog and is published here by the author. Do not present it as clean-room or independently reproducible from public specifications. See docs/PROVENANCE.md.

That final boundary is evidentiary: a reusable mechanism validated on several catalogs is not a claim that every product catalog can be decoded without domain review.

Apache-2.0 — see LICENSE and NOTICE.

About

Catalog-bound SKU resolution for AI agents: tenant-scoped evidence, explicit ambiguity, and no authority to invent system-of-record identifiers.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages