From c2a60212fecabc4e3d2a638c5420df793666fbec Mon Sep 17 00:00:00 2001 From: Schalli Date: Thu, 23 Jul 2026 08:38:59 +0200 Subject: [PATCH] feat(13-01): widen SourceType to open union, add NormalizedTenderFields.fingerprint SourceType now covers 'doe-opendata' | 'ai-netserver' | 'cosinex-dtvp' (13-RESEARCH Pattern 1) so the Plan 13-04/05 adapters can register without further type-contract changes. NormalizedTenderFields gains an optional fingerprint field for the SCHEMA-03 dedup resolver (Plan 13-03) to populate later. tsc --noEmit clean; full API suite green. Co-Authored-By: Claude Opus 4.8 (1M context) --- apps/api/src/tenders/tender.types.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/api/src/tenders/tender.types.ts b/apps/api/src/tenders/tender.types.ts index 52025a9..c11f8aa 100644 --- a/apps/api/src/tenders/tender.types.ts +++ b/apps/api/src/tenders/tender.types.ts @@ -8,10 +8,13 @@ /** * Identifies which upstream source a raw record originated from. - * Only 'doe-opendata' exists in this phase (Phase 10); scraping/RSS/email - * sources are added in later phases (13/14) without changing this contract. + * Extended in Phase 13 (13-RESEARCH Pattern 1) from a single-literal type + * to an open union so the NetServer (Plan 13-04) and cosinex/DTVP + * (Plan 13-05) adapters can be added without further breaking changes. + * This union widening is the only breaking type change in Plan 13-01, + * and it's contained locally (no runtime behavior change here). */ -export type SourceType = 'doe-opendata'; +export type SourceType = 'doe-opendata' | 'ai-netserver' | 'cosinex-dtvp'; /** * A single notice as fetched and lightly parsed from a source, before @@ -80,4 +83,12 @@ export interface NormalizedTenderFields { /** sha256(title + deadlineAt + estimatedValue + status) — SCHEMA-02 change-detection hook. */ contentHash: string; publishedAt: Date; + /** + * SCHEMA-03 (D-04) — cross-source dedup key, computed by tenderFingerprint() + * (Plan 13-01 Task 1). Optional here: the normalizer does not set it yet + * (that wiring lands in Plan 13-03's dedup resolver) — kept optional so + * this additive field doesn't break the Phase-10/11 normalizer contract + * before the resolver exists. + */ + fingerprint?: string; }