Files

95 lines
6.0 KiB
Markdown

---
phase: 10
slug: ausschreibungs-radar-foundation-d-e-ingestion
status: draft
nyquist_compliant: true
wave_0_complete: false
created: 2026-07-21
---
# Phase 10 — Validation Strategy
> Per-phase validation contract for feedback sampling during execution.
---
## Test Infrastructure
| Property | Value |
|----------|-------|
| **Framework** | Vitest 3.x (existing, `apps/api/vitest.config.ts`) |
| **Config file** | `apps/api/vitest.config.ts` (existing — not modified by this phase) |
| **Quick run command** | `pnpm --filter @tessera/api test -- tenders` |
| **Full suite command** | `pnpm --filter @tessera/api test` |
| **Estimated runtime** | ~10 seconds (scoped) |
---
## Sampling Rate
- **After every task commit:** Run `pnpm --filter @tessera/api test -- tenders`
- **After every plan wave:** Run `pnpm --filter @tessera/api test`
- **Before `/gsd-verify-work`:** Full suite must be green
- **Max feedback latency:** ~10 seconds (scoped run)
---
## Per-Task Verification Map
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
| 10-01-01 | 01 | 1 | SCHEMA-01 | T-10-SC | adm-zip verified before install (supply chain) | manual-gate | checkpoint:human-verify (blocking-human) | n/a | ⬜ pending |
| 10-01-02 | 01 | 1 | SCHEMA-01 | T-10-01 | Tender has no tenantId (global data) | build | `grep -c "model Tender" schema.prisma`; `tsc --noEmit` | ❌ W0 | ⬜ pending |
| 10-01-03 | 01 | 1 | SCHEMA-01 | T-10-01 | [BLOCKING] migration applied to DB | integration | `pnpm --filter @tessera/api exec prisma migrate status` | ❌ W0 | ⬜ pending |
| 10-02-01 | 02 | 2 | CONFIG-01 | T-10-05 | idempotent registry seed + singleton config | build | `tsc --noEmit`; `grep -c "TendersModule" app.module.ts` | ❌ W0 | ⬜ pending |
| 10-02-02 | 02 | 2 | CONFIG-01 | T-10-03 | whitelisted slug only | build | `grep -c "tender-radar" module-loader.ts`; web `tsc --noEmit` | ❌ W0 | ⬜ pending |
| 10-02-03 | 02 | 2 | CONFIG-01 | T-10-04 | seed asserts slug + isSystem | unit | `pnpm --filter @tessera/api test -- tenders.seed` | ❌ W0 | ⬜ pending |
| 10-03-01 | 03 | 3 | INGEST-01/SCHEMA-01 | T-10-06/07 | real fixtures + failing specs (RED) | unit | `pnpm --filter @tessera/api test -- doe-opendata.adapter tender-normalizer` | ❌ W0 | ⬜ pending |
| 10-03-02 | 03 | 3 | INGEST-01 | T-10-06/07 | fixed host fetch + zip-bomb ceiling + D-02 filter | unit | `pnpm --filter @tessera/api test -- doe-opendata.adapter` | ❌ W0 | ⬜ pending |
| 10-03-03 | 03 | 3 | SCHEMA-01 | T-10-08 | eForms-primary deadline, nullable value, dedupKey/hash | unit | `pnpm --filter @tessera/api test -- tender-normalizer` | ❌ W0 | ⬜ pending |
| 10-04-01 | 04 | 4 | SCHEMA-02 | T-10-09/11 | day-cursor no-op; update-not-duplicate; D-05 prune skips null | integration | `pnpm --filter @tessera/api test -- tender-ingestion` | ❌ W0 | ⬜ pending |
| 10-04-02 | 04 | 4 | INGEST-06 | T-10-10 | single global cron, no activeTenantId | build | `tsc --noEmit`; `grep -c "activeTenantId" tender-scheduler.service.ts` == 0 | ❌ W0 | ⬜ pending |
| 10-04-03 | 04 | 4 | INGEST-06 | T-10-10 | 2nd-tenant activation → 0 extra calls/jobs/rows | integration | `pnpm --filter @tessera/api test -- tender-scheduler` | ❌ W0 | ⬜ pending |
| 10-05-01 | 05 | 5 | INGEST-06 | T-10-15 | DTO bounds (interval floor, limit cap) | build | `tsc --noEmit` | ❌ W0 | ⬜ pending |
| 10-05-02 | 05 | 5 | INGEST-06 | T-10-13/14 | ModuleGuard read (not tenant-scoped) + admin Roles | build | `tsc --noEmit`; `grep -c "UseModule" tenders.controller.ts` | ❌ W0 | ⬜ pending |
| 10-05-03 | 05 | 5 | INGEST-06 | T-10-14 | read where has no tenantId; save drives scheduler | unit | `pnpm --filter @tessera/api test -- tenders.controller` | ❌ W0 | ⬜ pending |
| 10-06-01 | 06 | 6 | INGEST-06 | T-10-16/17 | admin form clamps interval 5..1440; server Roles-guarded | build | web `tsc --noEmit`; `grep -c "saveSourceConfig" tender-radar-api.ts` | ❌ W0 | ⬜ pending |
| 10-06-02 | 06 | 6 | INGEST-06 | T-10-16 | fetch-on-mount + save payload; out-of-bounds no save | unit | `pnpm --filter @tessera/web test -- SourceConfigForm` | ❌ W0 | ⬜ pending |
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
---
## Wave 0 Requirements
- [ ] `apps/api/src/tenders/__fixtures__/doe-eforms-sample.zip` + `doe-ocds-sample.zip` — real captured, trimmed fixtures (Plan 03 Task 1)
- [ ] `apps/api/src/tenders/tenders.seed.spec.ts` (Plan 02 Task 3)
- [ ] `apps/api/src/tenders/adapters/doe-opendata.adapter.spec.ts`, `tender-normalizer.service.spec.ts` (Plan 03 Task 1 — RED first)
- [ ] `apps/api/src/tenders/tender-ingestion.service.spec.ts`, `tender-scheduler.service.spec.ts` (Plan 04)
- [ ] `apps/api/src/tenders/tenders.controller.spec.ts` (Plan 05 Task 3)
- [ ] `apps/web/src/app/(portal)/modules/tender-radar/settings/components/SourceConfigForm.test.tsx` (Plan 06 Task 2)
Vitest framework already exists (api + web) — no framework install needed.
---
## Manual-Only Verifications
| Behavior | Requirement | Why Manual | Test Instructions |
|----------|-------------|------------|-------------------|
| adm-zip package legitimacy | (supply chain / T-10-SC) | Human judgment on package provenance ([ASSUMED]) | Plan 01 Task 1 checkpoint: verify on npmjs.com + github.com/cthackers/adm-zip |
| Marketplace activation opens module page | CONFIG-01 | Full portal round-trip (marketplace → activate → page render) is a browser flow | Activate Ausschreibungs-Radar for a tenant, open `/modules/tender-radar`, confirm no 404 |
---
## Validation Sign-Off
- [x] All tasks have `<automated>` verify or a documented Wave 0 / manual-gate dependency
- [x] Sampling continuity: no 3 consecutive tasks without automated verify
- [x] Wave 0 covers all MISSING references (fixtures + spec scaffolds)
- [x] No watch-mode flags (all use `vitest run` via `pnpm test`)
- [x] Feedback latency < 10s (scoped runs)
- [x] `nyquist_compliant: true` set in frontmatter
**Approval:** approved 2026-07-21