74c00166e2
6 plans (INGEST-02/03/07, SCHEMA-03) + Nyquist validation. Core (registry, fingerprint, dedup, TenderSource, backfill) lands first and is green independent of live scraping (D-01). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 KiB
11 KiB
phase, slug, status, nyquist_compliant, wave_0_complete, created
| phase | slug | status | nyquist_compliant | wave_0_complete | created |
|---|---|---|---|---|---|
| 13 | scraping-adapters-cross-source-dedup | draft | true | false | 2026-07-23 |
Phase 13 — Validation Strategy
Per-phase validation contract for feedback sampling during execution. Extracted from 13-RESEARCH.md § Validation Architecture (Test framework, Requirements→Test map, Sampling rate, Wave-0 gaps).
Test Infrastructure
| Property | Value |
|---|---|
| Framework | Vitest (API 3.x, Web 4.x — beide vorhanden, kein Install) |
| Config file | apps/api/vitest.config.ts + apps/web vitest (bestehend — nicht von dieser Phase geaendert) |
| Quick run (API slice) | pnpm --filter @tessera/api test -- <spec> |
| Quick run (API tenders) | pnpm --filter @tessera/api test -- src/tenders |
| Quick run (Web slice) | pnpm --filter web test -- <spec> |
| Full suite | pnpm test (turbo) bzw. pnpm --filter @tessera/api test && pnpm --filter web test |
| Estimated runtime | ~10-15 s (scoped) |
Ein neues Package: node-html-parser (oder cheerio) — NUR nach blockierendem Package-Legitimacy-Checkpoint (Plan 13-04). Der Kern (Registry, Fingerprint, Dedup, TenderSource, Backfill) braucht KEIN Scraping-Package und ist unabhaengig davon voll testbar (D-01). prisma/crypto/fetch bereits vorhanden.
Sampling Rate
- Nach jedem Task-Commit: betroffene Slice-Spec (
pnpm --filter @tessera/api test -- <spec>). - Nach jeder Plan-Wave:
pnpm --filter @tessera/api test && pnpm --filter web test. - Vor
/gsd-verify-work:pnpm testgruen + Backfill-Migration lokal gegen die Dev-DB verifiziert. - Max Feedback-Latenz: ~15 s (scoped).
Per-Task Verification Map
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 13-01-01 | 01 | 1 | SCHEMA-03 | T-13-01-01/03 | TenderSource (1:n, @@unique[sourcePortal,sourceNoticeId]) + Tender.fingerprint additiv; 2-Schritt-Migration + Backfill lokal | integration | cd apps/api && npx prisma validate && npx prisma generate (+ psql-Count, manual) |
⚠️ migration | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-01-02 | 01 | 1 | SCHEMA-03 | — | tenderFingerprint pure, NULL-tolerant (Wert/Frist NULL -> Match), kollisionsarm (Titel im Hash), sha256 | unit | pnpm --filter @tessera/api test -- tender-fingerprint |
❌ W0 | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-01-03 | 01 | 1 | SCHEMA-03 | — | SourceType-Union offen + NormalizedTenderFields.fingerprint; typecheck | typecheck | cd apps/api && npx tsc --noEmit -p tsconfig.json |
n/a | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-02-01 | 02 | 1 | INGEST-07 | — | Adapter-Interface um portals[] generalisiert; DoeOpenDataAdapter deklariert portals | typecheck | cd apps/api && npx tsc --noEmit -p tsconfig.json |
n/a | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-02-02 | 02 | 1 | INGEST-07 | T-13-02-01/02 | SourceRegistry.register wirft DeniedPortalError fuer vergabe24 UND aumass (Erfolgskriterium 4); legitime Registrierung/get funktionieren | unit | pnpm --filter @tessera/api test -- source-registry |
❌ W0 | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-03-01 | 03 | 2 | SCHEMA-03 | T-13-03-02/03/04 | 3-Stufen-Resolver OCID→source:noticeId→fingerprint; inert bei 1 Quelle (D-05), Merge->TenderSource anhaengen ab 2 (D-03); plain Prisma (kein RLS) | unit | pnpm --filter @tessera/api test -- tender-dedup |
❌ W0 | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-03-02 | 03 | 2 | SCHEMA-03 | T-13-03-01/02 | pollDueSources fan-out (findMany isActive), catch-per-source, dedupActive=activePortalCount>=2, Delta-Boundary erhalten | unit | pnpm --filter @tessera/api test -- tender-ingestion.service |
⚠️ extend | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-03-03 | 03 | 2 | SCHEMA-03 | — | Modul-Wiring: SourceRegistry + TenderDedupService Provider + DoeOpenDataAdapter bei Boot registriert; DI aufloesbar | typecheck+suite | cd apps/api && npx tsc --noEmit && pnpm --filter @tessera/api test -- src/tenders |
n/a | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-06-01 | 06 | 2 | SCHEMA-03 | T-13-06-03 | getTender include sources[]; Route-Order unveraendert (:id zuletzt) | integration | pnpm --filter @tessera/api test -- tenders.controller |
⚠️ extend | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-06-02 | 06 | 2 | SCHEMA-03 | T-13-06-01/02 | TenderDetail rendert alle Quell-Links (Text-escaped, rel=noopener), Fallback bei fehlendem sources | component | cd apps/web && npx tsc --noEmit && pnpm --filter web test -- TenderDetail |
⚠️ extend | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-04-CP | 04 | 3 | INGEST-02 | T-13-04-SC | Package-Legitimacy-Checkpoint (blocking-human) VOR Install node-html-parser/cheerio | manual-gate | Human verify via gsd-tools query package-legitimacy check --ecosystem npm node-html-parser cheerio |
n/a | ⬜ pending | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 13-04-01 | 04 | 3 | INGEST-02 | T-13-04-01/02/03 | NetServer-Adapter config-getrieben (3 Portale), parst -Fixture, []-Fallback, SSRF-sichere Konstanten, 15s-Timeout
Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky Wave 0 Requirements
Vitest-Framework existiert bereits (api + web) — keine Framework-Installation. HTML-Fixtures live speichern fuer stabile Adapter-Tests. Manual-Only Verifications
Validation Sign-OffApproval: draft — pending execution (wave_0_complete: false) |