/** * Boundary between the crawl runtime (context, documents, scheduling) and the ingest layer * (reconciliation, persistence, provenance, events). Both sides implement against this file. */ import type { NormalizedEntity, DetectedChange } from "@dci/core"; export interface IngestRun { connectorId: string; sourceId: string; runId: string; sourceKind: string; sourcePriority: number; dryRun: boolean; } export interface IngestDocRef { documentId: string; url: string; pageType: string; fetchedAt: string; } export interface IngestStats { received: number; created: number; updated: number; unchanged: number; merged: number; pendingMatches: number; rejected: number; events: number; provenanceRows: number; byType: Record; changes: DetectedChange[]; /** entity ids touched: [{type,id}] for documents.entity_refs */ refs: Array<{ type: string; id: string }>; /** data-quality counters (optional, additive): operators inferred from a canonical name prefix */ inferredOperators?: number; /** coordinates dropped because the point lies in another country than the one the source states */ geoCountryMismatch?: number; /** field values kept in provenance but not written to a column (e.g. pre-1980 opening dates from OSM) */ implausibleDropped?: number; /** projects folded into an already-known announcement (same operator, city, MW ±10 %, within 30 days) */ projectDedup?: number; /** claims rows written */ claims?: number; /** quality flags written */ qualityFlags?: number; /** figures kept as claims but not assigned to a column (portfolio / company / unknown scope, market statistics) */ unscopedClaims?: number; /** project candidates vetoed by the announcement classifier (appointments, financing, PPAs, market research…) */ projectsVetoed?: number; /** building records linked to their campus record instead of being flagged as duplicates */ campusLinks?: number; /** hidden projects restored because a re-extraction qualified them again */ projectsRequalified?: number; } export type IngestFn = (run: IngestRun, entities: NormalizedEntity[], doc: IngestDocRef | null) => Promise;