> ## Documentation Index
> Fetch the complete documentation index at: https://docs.landedfees.com/llms.txt
> Use this file to discover all available pages before exploring further.

# HS classification

> How the classifier picks an HS or HTS code from a product description, using vector retrieval, 3-sample voting, adversarial verification, and CROSS ruling anchoring.

## The pipeline

`/v1/classify` runs a five-stage pipeline. The full pipeline runs on
the hot path (single line, low latency). Bulk paths can skip the
voting and adversarial stages for throughput.

### 1. Embed

The product description is embedded once with the local 384-dim
MiniLM model. No description ever leaves LandedFees infrastructure
for embedding.

### 2. Vector-first retrieval

The engine issues two parallel vector lookups:

* Top 10 HTS candidate lines from the destination country's tariff
  schedule (US pulls from `us_hts_codes`, others from `hs_codes`).
* Top 8 CROSS rulings (US Customs binding-ruling database).

If vector retrieval returns fewer than the target count, the shortfall
is topped up with Postgres full-text search using a websearch tsquery.
The two candidate sets are deduplicated by code and ruling ID.

### 3. Primary classification

The candidates and CROSS rulings are fed to a GRI-based classification
prompt (General Rules of Interpretation, WCO). The model returns a
recommended 6-digit HS code, a 10-digit HTS suggestion when the
schedule supports it, a confidence score, and a natural-language
reason string. If the caller passed `hs_code_printed`, the prompt is
asked to compare and flag disagreements.

### 4. Three-sample consistency voting

Fires when the primary confidence is between 0.55 and 0.85. The
engine re-runs the classifier three times at a slightly warmer
temperature and takes the majority vote. Splits below majority are
returned with `needs_review: true`.

### 5. Adversarial devil's-advocate pass

Fires when the primary result lands high-confidence (0.85 or above).
A separate prompt is instructed to argue for the strongest alternate
HS code from the same candidate pool. The result carries one of
three verdicts:

* `confirmed_primary`: adversarial refused to flip. Primary stands.
* `plausible_alternate`: a real alternate exists at or near primary
  confidence. `needs_review` is set.
* `not_triggered`: voting split or explicit skip.

## What you get back

```json theme={null}
{
  "hs_6_code": "851762",
  "recommended_10_digit": "8517.62.00.90",
  "confidence": 0.92,
  "reason": "Wireless communication apparatus, other reception apparatus",
  "needs_review": false,
  "candidates": [
    { "hts_code": "8517.62.00", "description": "Machines for reception, conversion and transmission", "score": 0.94 },
    { "hts_code": "8518.30.20", "description": "Headphones and earphones, other", "score": 0.71 }
  ]
}
```

## When to trust the code

Ship-without-review is safe when `needs_review: false` and
`confidence` is 0.85 or above. Below 0.85 the engine has already
flagged the line; route it to a licensed broker before filing. The
threshold is configurable per call via `confidence_threshold`.

## Comparing the printed code

Suppliers often print an HS code on the commercial invoice that is
wrong for your destination country. Pass it in `hs_code_printed`:

```json theme={null}
{
  "description": "Silicone phone case, hard shell",
  "destination_country": "US",
  "hs_code_printed": "3926.90"
}
```

If the classifier chooses a different code, the response includes
`disagreement_with_printed: true` and the recommended code in
`hs_6_code`. This is the flag your broker wants to see before entry.

## Batch mode

`/v1/classify` accepts either a single description or a `lines[]`
batch of up to 50. Batch responses add a `consistency` block: when
most lines share an HS chapter (first 2 digits) and one line
diverges, the outlier is flagged. Useful for a bill of materials
where all lines should live in the same tariff chapter.
