# ADR-002 — TypeScript connectors in Phase 1; Python/DuckDB workers later Status: accepted (2026-09-08) ## Context Connectors ingest from OncoTree, NCIt EVS, HGNC, CIViC, GDC, ClinVar, ClinicalTrials.gov, PubMed and CDC WONDER. In Phase 1 all of these are JSON or TSV over HTTP with pagination, rate limits and modest volumes (≤ a few million small records). The rest of the platform (schema, API, web, worker) is TypeScript in a pnpm monorepo; the ingestion SDK needs typed manifests, shared normalisation, the `CancerResolver`, drizzle access to the same schema, and fixtures-based tests in the same test runner. The bioinformatics ecosystem, however, is Python-first for HGVS parsing/normalisation, liftover between GRCh37/GRCh38, VCF handling and large columnar processing (spec §231-234). ## Decision Phase 1 connectors are TypeScript classes extending `Connector` in `packages/connectors`, sharing one SDK (manifest validation, rate-limited `HttpClient`, `RawLake`, `RunContext`, validators) and one registry. The worker (`workers/main.ts`) runs them in-process with pg-boss. Heavy genomics work is explicitly deferred to **Python workers** (planned package `workers-py/`): HGVS normalisation (`hgvs`/`biocommons`), liftover (`pyliftover`/CrossMap), VCF/ClinVar bulk parsing, and cohort-scale statistics with **DuckDB over Parquet** files in the data lake. They will consume the same raw lake, write summarised rows into PostgreSQL through the same provenance model, and be scheduled by the same pg-boss queue (pg-boss is SQL-compatible; a Python worker can claim jobs through the documented SQL API or via an HTTP proxy). ## Consequences - One language for the whole Phase 1 stack: shared types (`match_type`, provenance input), shared normalisation, one test runner, one lockfile. - Variant coordinates in Phase 1 are stored as delivered by the source with the assembly recorded (`variants.assembly`, `coordinates[]`), original and normalised strings kept, no liftover performed. Cross-assembly comparisons are not offered until the Python worker ships. - The SDK must stay language-neutral at the boundaries: manifests are plain JSON-serialisable objects (stored in `sources.manifest`), lake files are JSON Lines gzip, job payloads are JSON. - Revisit when a source requires bulk binary formats (VCF, BAM-derived) or when a connector's run time exceeds the worker time budget because of CPU-bound normalisation.