How a product becomes a code, and a code becomes a match
Two mappings carry the whole product. A spreadsheet row becomes a brand family and an HS6 code; a customs declaration becomes an HS6 code; the two meet on that six-digit string. Every claim of the form this account buys what you sell is that string matching — nothing more. Both mappings lose information on the way, and this page is where that loss is stated.
Two mappings, one join key
What has to be true for 'this account buys what you sell' to mean anything?
The brand family labels a row but never joins on one — it plays no part in matching. Everything the product claims rests on six digits derived twice, from two unrelated sources, by one rule.
Product → brand family
An exact string match. The Taxonomy sheet lists each family's products in a newline-separated cell; every Product Name* in the Client sheet is looked up in that list. All 2,512 match, none are duplicated, none are left over.
A perfect exact-match rate means Lanxess supplied the two sheets as a matched pair. There is no fuzzy fallback and no error path: change one character in either sheet and that product keeps its HS6, silently gets no family, and disappears from every family page while still counting toward code-level totals. Nothing would report it. If a future catalog arrives from a different process, check the unmatched count before trusting a family number.
2 pairs of families differ only by casing or trademark symbol — KALAMA® / Kalama®, KLARIX™ / Klarix®. They are kept separate rather than merged, because Lanxess listed them separately and collapsing a customer's own taxonomy is not our call — each page flags its twin. 27 of 234 families vanish entirely: every product they contain lacks a usable HS code, so nothing is left to match on.
Product → HS6
The HS Code (MARC) column is not uniform: 8 to 12 characters, some with a trailing letter (39092029000T), some dotted (3808.94.20.29). 128 of 2,512 products have no code at all and are excluded everywhere — they cannot be checked against any account.
Declaration → HS6
The customs field carries the code and its description: "90200090 - OTHER BREATHING APPLIANCES…". Both sides now use one rule (pipeline/hs_codes.py): take the leading code token, strip separators inside it, keep the first six digits. It cannot be “strip every non-digit” — that would absorb every digit in the description.
The pipeline took the leading digit run; the Lanxess catalog stripped all non-digits. On 3808.94.20.29 that is 3808 against 380894 — two values that never match, with no error raised. They agreed on all 10,889 observed customs codes only because none contained an internal separator; the spreadsheet did. Unified, verified as producing identical output on every code on both sides.
| Source code length | Distinct codes | Rows | Reading |
|---|---|---|---|
| 2 digits | 39 | 1,660 | Chapter or heading only — truncates to an hs6 that matches nothing |
| 4 digits | 238 | 9,610 | Chapter or heading only — truncates to an hs6 that matches nothing |
| 6 digits | 1,036 | 45,462 | HS6 exactly, internationally comparable |
| 8 digits | 3,082 | 239,606 | National extension; digits beyond six are country-specific |
| 10 digits | 4,519 | 299,715 | National extension; digits beyond six are country-specific |
| 11 digits | 1,760 | 49,179 | National extension; digits beyond six are country-specific |
| 12 digits | 215 | 2,689 | National extension; digits beyond six are country-specific |
Digits seven onward are set by the importing country, so two countries' 8-digit codes are not comparable even when they describe the same goods. Six is the deepest level that means the same thing everywhere, which is why it is the join — not a convenience.
277 codes across 11,270 rows yield fewer than six digits. They currently reach the payloads as two- and four-character “hs6” values that can never match a portfolio code. Dropping them is the right end state, but it moves figures app-wide, so it is a change to make deliberately rather than as a side effect — for now nonstandard_hs marks them.
6 codes (970 rows) claim chapter 00, which does not exist — zero-padded values like 0000320890, which almost certainly mean 320890. The padding is not stripped: “almost certainly” is a guess, and this pipeline flags rather than guesses. Chapters 98 and 99 are not flagged — both are legitimate national-use chapters and 36 codes (1,242 rows) use them here.
Some declaration lines name several codes at once — 320810 - PAINTS…, 320890 - PAINTS…, 320820 - PAINTS…. The first code takes the row's entire value, because the declaration states no split and inventing one would be a fabrication. multi_hs_code now marks these so the choice is countable rather than invisible.
What six digits cannot tell you
And from the other direction: the largest Lanxess fan-out is 391400 (172), 380899 (164), 390810 (156), 282110 (133), 390799 (110).
81.6% of Lanxess products share a code with ten or more siblings, and up to 92 national codes sit behind a single HS6 on the customs side. A match says the account imports something classified under this code. It cannot say which product, and no amount of presentation makes it able to. Every product page therefore labels its figure inherited from the code rather than attributed to the SKU.
What an HS description actually is
No official tariff nomenclature ships with this repository, so all 10,889 observed codes carry classification_source: observed_source_code and status: source_only. A description shown anywhere in the product is what the declaring party wrote on the paperwork — not what the tariff says the code means. Adding an approved official code table to the knowledge base promotes them to real matches; until then, treat descriptions as evidence of intent rather than classification.
Portfolio matching
A pasted portfolio goes through parseCodeList (lib/portfolio.ts), which truncates 8- and 10-digit national codes to six — the correct reading of a tariff line, not a guess — and reports anything unrecognised back instead of dropping it silently.
Of the 206 Lanxess codes, 178 appear somewhere in observed customs data. That is a larger number than the count of codes with demand shown on /lanxess, and both are correct: this one asks whether the code was ever seen at all, that one asks whether a covered account with usable coverage imported it. Neither is a market size.