session/models.py — BomSession, BomRow, NormalizedParams, ComponentCategory, RowStateingestion/parser.py — CSV + XLSX + XLS, preamble skip, footer strip, delimiter detectioningestion/column_mapper.py — heuristic synonym lookup, AI fallback, synonym persistenceingestion/column_synonyms.json — file-backed synonym table, auto-updated on AI discoveryingestion/normalizer.py — designator parsing, range expansion, DNP detection, row stateclassification/classifier.py — designator prefix map + value heuristics → ComponentCategoryclassification/param_extractor.py — value parsing, description fallback, package extraction, AI fallbackclassification/package_patterns.json — file-backed regex patterns + known_footprints dict_normalize_key collapses whitespace) — fixed Ref Des (Multi-4) mismatchComment → part_number disambiguation — passive value sampling prevents pn='100nF'"CAP CER 0.1UF 100V X7R 0603"\b → (?<![A-Za-z]) lookbehind — fixes underscore-prefixed footprints (Texas_HTSOP-8-1EP)(?:-[A-Z0-9]+)* stops at _digitElec_ prefix from package — store "6.3x5.8" not "Elec_6.3x5.8" (change capture group in package_patterns.json)suppliers/lcsc/fetch_categories.py — one-time CLI to scrape LCSC category pages → categories.json (1.5s grace period between requests)suppliers/lcsc/categories.json — committed static category tree (refresh quarterly)suppliers/lcsc/categories.py — load_categories(), get_subcategories_for(internal_cat)suppliers/lcsc/category_resolver.py — LLM (Claude Haiku) category inference + category_cache.json persistencesuppliers/lcsc/category_cache.json — file-backed cache (same pattern as package_patterns.json)suppliers/base.py — abstract SupplierAdapter(api_token=None) with search(category_id, params, page) interfacesuppliers/lcsc/lcsc.py — scraper mode: CSRF session + POST to lcsc.com/api/products/search; token mode stub for official APIapi/main.py)POST /upload — ingest file, return BomSessionGET /session/{id} — return session stateGET /session/{id}/row/{row_id}/scout — LLM category inference, return {subcategory, alternatives[]}POST /session/{id}/row/{row_id}/confirm-category — lock LCSC subcategory, advance state to filteringPOST /session/{id}/row/{row_id}/search — search within confirmed category + param filtersPOST /session/{id}/row/{row_id}/confirm — lock part pick, advance state to confirmedGET /session/{id}/export — collate confirmed picks → downloadable BOM