Stage 0 scans page 1 for supplier markers. The router exposes an opaque plant
string (valdosta or bordeaux) that Stage 4 uses to bind the
correct PLANTS[plant] entry — articles file, clients file, entity
file, and the three Snake models (data/models/<plant>/*). Adding a
plant is a five-step procedure documented in the internal playbook.
Plant
Stage 0 markers
SKUs
Customers
PO format
Valdosta GA
SAFT AMERICA, Valdosta GA addresses, US tariff codes
9,425
22
Verizon Ariba / Satair / direct
Bordeaux FR
SAFT BORDEAUX, A1908000 buyer ID, P\d{7} PO format
43,332
2,990
Saft Ferak (60-I prefix), framework POs
Pipeline stages
#
Stage
Cost
Typical time
Output
0
Client + plant ID
regex + 1 Haiku call
< 1 s
customer_id, plant routing, PO#, layout family
1
Doc Analyzer
regex + 1 Haiku call
< 1 s
page triage, layout family
2
Unified Extractor
text-mode (free) when totals
reconcile, else 1 Sonnet/3-page chunk
0.1–6 s
structured JSON (mfr_pn, customer_pn, desc, qty, unit, price)
Models are versioned in s3://monce-saft-archive/models/<plant>/<name>_matcher.json.
The EC2 caches them locally with ETag tracking; first-touch downloads from S3,
subsequent restarts no-op. POST /matching/reload hot-pulls fresh
models without bouncing the service.
GitHub Actions on push to main → rsync + restart, ~28 s
The /matching public route
The matcher is exposed as a stable HTTP surface for monceapp and other Monce services
to call without rerunning the whole pipeline.
Endpoint
What
GET /matching/health
liveness, which plants/matchers are loaded, S3 store status
GET /matching/version
full manifest, ETags, S3 VersionIds, load timings
POST /matching/reload
refetch from S3, rebuild in-process Snake without restart
POST /matching/snake
raw text → Snake prediction across all 3 matchers for one plant
POST /matching/article
full 5-tier cascade for one PN, plant-aware
POST /matching/po
full Stage 4 on a parsed PO — no PDF required
Extensibility
New customer layout. Add a pattern to
stage0_client_extraction.py:_BUYER_PATTERNS for the relevant plant,
plus an entry in the corresponding clients catalogue.
New plant. See CLAUDE.md — five steps:
drop master data, write generate_<plant>_catalog.py, register in
PLANTS, add Stage 0 markers, train Snake.
Master data refresh. Re-run the plant's generate_*_catalog.py,
then scripts/train_*_models.py, then scripts/publish_models.py
to push to S3, then POST /matching/reload on prod.
New synonyms. Aliases live in the synonyms column of
each plant's articles JSON; regenerate and retrain.
New model. Point MODELS in config.py to
any Bedrock-hosted Anthropic model ID.