← All projects Bad Batch Tracer
Snowflake CoCo CLI Hackathon 2026 · Track 4

Bad Batch Tracer

Every month India’s drug regulator publishes batches that failed quality testing. Bad Batch Tracer extracts them, matches them against what a hospital has already dispensed — even hand-typed or missing batch numbers — and lists exposed patients whose labs suggest harm, for clinical follow-up.

SOURCES (BUILT)INGEST (TARGET)CORE (TARGET)SERVE (TARGET)CDSCO alert PDFs — 52 monthly lists: central, state, spurious, combined + portal JSONCDSCO alert PDFs52 monthly lists: central,state, spurious, combined +portal JSONSynthetic hospital — 5,000 patients · 60,018 dispenses · 6,100 stock batches · 40,117 labs (seed 42)Synthetic hospital5,000 patients · 60,018dispenses · 6,100 stockbatches · 40,117 labs (seed42)Ground-truth answer key — evaluation only — never loaded into app tablesGround-truth answer keyevaluation only — neverloaded into app tablesStage + directory table — stream triggers a TASK on new filesStage + directory tablestream triggers a TASK on newfilesAI_PARSE_DOCUMENT — LAYOUT, page_split → NSQ_PAGES (run once per file)AI_PARSE_DOCUMENTLAYOUT, page_split →NSQ_PAGES (run once per file)AI_COMPLETE — JSON schema per page → NSQ_ROWS_EXTRACTEDAI_COMPLETEJSON schema per page →NSQ_ROWS_EXTRACTEDHospital load — Parquet via stage → RAW.HOSPITAL.* → CORE.*Hospital loadParquet via stage →RAW.HOSPITAL.* → CORE.*Snowpark UDFs — normalise batch, dates, manufacturer → CORE.NSQ_ALERTSnowpark UDFsnormalise batch, dates,manufacturer → CORE.NSQ_ALERTBATCH_MATCHES — dynamic table: exact / probable / watchlistBATCH_MATCHESdynamic table: exact /probable / watchlistPATIENT_EXPOSURE — → CLINICAL_FLAGS → ACTION_ITEMSPATIENT_EXPOSURE→ CLINICAL_FLAGS →ACTION_ITEMSCortex Search + Views — Cortex Search on alerts + CDSCO guidance; Semantic View + Cortex Analyst (KAVACH_SV)Cortex Search + ViewsCortex Search on alerts +CDSCO guidance; Semantic View+ Cortex Analyst (KAVACH_SV)Cortex Agent — “Kavach Assistant”Cortex Agent“Kavach Assistant”Streamlit in Snowflake — action list; every fact cites source_file + pageStreamlit in Snowflakeaction list; every fact citessource_file + pagePUTrowsdispensingalerts
Built: real/synthetic dataExternal public dataEvaluation onlyTarget design (Snowflake)
Dashed boxes are the target Snowflake design from the team plan; solid boxes are the data layer committed in the repo today. The ground-truth key scores the matcher offline and is never loaded into app tables.
The problem

Failed-batch lists exist; nobody checks them against dispensing

CDSCO publishes “Not of Standard Quality” and spurious-drug lists as PDFs every month. Hospitals rarely cross-check them against what they have already dispensed, so exposed patients are never contacted.

0
real CDSCO alert PDFs
0
rows in the baseline parse
0
synthetic dispensing records
0
real patients used
System architecture

Snowflake-first, cited end to end

The team plan fixes a few principles that shape the diagram:

❄

Snowflake-first

If Snowflake can do it, do it there: AI_PARSE_DOCUMENT, AI_COMPLETE with JSON schema, Dynamic Tables, Tasks, Snowpark UDFs, Cortex Search, Semantic Views, Cortex Agents.

§

Cite, don’t claim

Every alert-derived fact shown to a user links back to source_file + page.

⚕

Clinical wording

Flags say “needs clinician review”, never a diagnosis.

$

Protect the credits

X-Small warehouses, 60 s auto-suspend, a resource monitor; parse each file once and store the result.

Matching

Exact, probable and watchlist

Batch numbers on alerts are printed; batch numbers at the pharmacy are scanned, hand-typed or missing. The matcher therefore produces tiers rather than a boolean.

alert (PDF)Metformin 500 mg · batch BT-24/0451 · mfr ACME · NSQ (dissolution)
dispensed: QRbatch BT-24/0451 → exact match
dispensed: typedbatch BT24-0451 → normalise → probable (fuzzy: JAROWINKLER / EDITDISTANCE)
dispensed: blankbatch (blank) → same product, valid window → watchlist
The data layer

Built to be scored

A synthetic hospital with a ground-truth answer key lets the matcher’s accuracy be measured instead of eyeballed. The key (data/synthetic/ground_truth/) is evaluation-only and must never be loaded into a Snowflake schema the app can read.

Ground-truth match types (1,309 labelled)

500494191124
exactdecoy near-missnoisyblank_batch

Baseline parse confidence (1,914 rows)

1.0parse_confidence
1,754
0.7
145
0.8
9
0.3
5
0.2
1
Baseline vs product: nsq_baseline_parsed.csv is a pdfplumber baseline, not the product. A hand-verified gold template (nsq_2025-06_central_gold.csv) scores the Snowflake extraction.
Validation

Seeded scenarios and automated checks

Children, kidney signal

Seeded exposure: 6 exposed patients, 3 with a signal, all children. The signal is creatinine rising above 2× baseline within 3–10 days — wording is “needs clinician review”, never a diagnosis.

exposed 6 with signal 3 creatinine > 2× baseline, d3–d10 3/3

Infection signal

12 exposed, 4 with a signal: fever > 38.5 °C plus a WBC rise within 48 h, matched for 4/4 seeded patients.

exposed 12 with signal 4 fever > 38.5 °C + WBC ↑ within 48h 4/4

make validate

scripts/validate_data.py writes docs/validation_report.txt: manifest sha256s, PDF page counts, parse sanity, foreign keys, dispensing inside batch validity, blank-batch share 14.9% (13–17%), seeded NSQ share 5.6% (4–6%), 204 decoy batches.

[PASS] sha256 matches for every file [PASS] foreign keys resolve [PASS] blank-batch share 14.9% [PASS] scenario A / B as seeded
Stack & status

SnowflakeAI_PARSE_DOCUMENTAI_COMPLETEDynamic TablesSnowpark PythonCortex SearchSemantic ViewsCortex AgentsStreamlit in SnowflakePythonpdfplumberParquetMakefile
Status: the repository contains the data layer — real alerts, drug master subset, regulatory references, baseline parse, gold template and the synthetic hospital with its answer key. The Snowflake objects, matching engine and app are the documented target and are shown dashed above.
← PreviousGround Truth Next →PocketForge