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.
| 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.
python -m pip install -e ".[dev]"
python scripts/independent_resolution_eval.py
python scripts/roundtrip_audit.pyThe 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.
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.
The normal vertical slice is mapped in docs/READING_PATH.md:
src/resolution/service.py— tenant-bound orchestration and response contract;src/sku_translator/translator.py— deterministic resolution and refusal paths;src/resolution/chooser.py— the constrained model seam;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.
ruff check .
mypy
pytest
python scripts/roundtrip_audit.py
python scripts/noise_resilience_audit.py
python scripts/independent_resolution_eval.pyProvider and live-ERP tests remain credential-gated. The deterministic core, catalog adapters, fulfillment logic, gateway policy, and simulated fault-injection paths run offline.
- 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.