cb23e3bc78
Die dritte Dedup-Stufe hashte bisher fuenf Segmente, darunter CPV-Division und geschaetzten Wert — beide werden von Nicht-DOE-Quellen systematisch nie geliefert, wodurch dieselbe Ausschreibung aus DOE und aus einem Scraper nie denselben Fingerabdruck ergab (WINDOWS.md #11). - tenderFingerprint() nimmt nur noch buyerName, title, deadlineAt entgegen - Versionsmarke FINGERPRINT_VERSION_PREFIX ("v2:") vor dem Hash, damit Task 3 veraltete Zeilen erkennen kann - valueBucketsContradict() als eigene, exportierte Funktion fuer den Wert-Veto in Task 2 — kein Hash-Bestandteil mehr - backfill-tender-source.ts an die neue Signatur angepasst - Testsuite auf das neue Verhalten umgeschrieben inkl. Goldwert-Test Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K5jtbGzC5Sf9npJ3JCjKhq
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
/**
|
|
* One-time backfill script (SCHEMA-03, D-05) — computes and persists
|
|
* `Tender.fingerprint` for every pre-existing row.
|
|
*
|
|
* The TenderSource row backfill itself lives in the migration SQL
|
|
* (20260723120000_add_tender_source/migration.sql) because it's a pure
|
|
* column copy. The fingerprint backfill does NOT belong in SQL: it needs
|
|
* the umlaut/CPV-normalization logic in tender-fingerprint.ts, which is
|
|
* code, not SQL (13-RESEARCH.md "Backfill-Migration").
|
|
*
|
|
* Run once, manually, after the migration has been applied (compiled first
|
|
* — this file uses standard extensionless TS imports, so it must run as
|
|
* built CommonJS, not as a raw .ts file):
|
|
* pnpm --filter @tessera/api build
|
|
* DATABASE_URL=... node dist/tenders/backfill-tender-source.js
|
|
*
|
|
* Idempotent: recomputes and overwrites fingerprint for every row it reads,
|
|
* so re-running is safe (same deterministic output for unchanged inputs).
|
|
*
|
|
* This script remains the manual, force-recompute-everything path. As of
|
|
* Task 3 of the WINDOWS.md #11 fix, the automatic path for ordinary
|
|
* startup is TenderFingerprintBackfillService, which recomputes only rows
|
|
* whose stored fingerprint doesn't yet carry FINGERPRINT_VERSION_PREFIX —
|
|
* this script stays useful for a deliberate full recompute (e.g. after a
|
|
* formula change) or ad-hoc verification.
|
|
*/
|
|
import { PrismaClient } from '@prisma/client';
|
|
import { tenderFingerprint } from './tender-fingerprint';
|
|
|
|
async function main(): Promise<void> {
|
|
const prisma = new PrismaClient();
|
|
try {
|
|
const tenders = await prisma.tender.findMany({
|
|
select: {
|
|
id: true,
|
|
title: true,
|
|
buyerName: true,
|
|
deadlineAt: true,
|
|
},
|
|
});
|
|
|
|
let updated = 0;
|
|
for (const t of tenders) {
|
|
const fingerprint = tenderFingerprint({
|
|
buyerName: t.buyerName,
|
|
title: t.title,
|
|
deadlineAt: t.deadlineAt,
|
|
});
|
|
await prisma.tender.update({
|
|
where: { id: t.id },
|
|
data: { fingerprint },
|
|
});
|
|
updated += 1;
|
|
}
|
|
|
|
console.log(`backfill-tender-source: fingerprint set on ${updated}/${tenders.length} tenders`);
|
|
} finally {
|
|
await prisma.$disconnect();
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error('backfill-tender-source failed:', err);
|
|
process.exitCode = 1;
|
|
});
|