feat(demo): prepared sample requests from recorded AI answers - #83
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
A visitor of the showcase should see a whole case - original, sources, decision and export receipt - even while the model provider is overloaded. `pnpm seed:samples` creates per demo company one sample to review and one approved sample, through the real intake, processing and approval paths; only the extraction replays an answer recorded once with `pnpm samples:record`, and it runs inline instead of through the queue so no drain can ever send a sample to the live model. List and detail label them as prepared samples. Refs #71 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…elog Refs #71 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Recorded 2026-09-27 against the showcase AI service (gemini-3.5-flash): all six fields found, two line items - the clean counterpart to the review sample with its uncertain and missing values. Refs #71 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The fresh review of #83 found that the "exported" sample stopped at APPROVED until some drain ran, and that an aborted seed left a sample in NEW/PROCESSING that blocked every later run. The seed now runs the export job inline through the normal export path (ERP reference, export row, audit) and falls back to the queue when the ERP is down; the source is set in the intake transaction, only settled states count as serving, and a failed processing step ends in a visible ERROR that cannot be reprocessed live. Recordings are validated with the contract schema and their replay counts no tokens or model time. New: unit tests for the recorded client, integration tests for export, ERP outage and abort, and an E2E smoke for the labels. Refs #71 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Frischer Review (/review-pr) – unabhängiger Reviewer-Agent ohne Umsetzungskontext, 2026-09-27Geprüft und ohne Befund: kein Weg zum Live-Modell (kein processRequest-Job, „Erneut verarbeiten“ nur aus ERROR(processing)); Urteil: „changes requested“ – AK 5 (Exportbeleg) ist nicht erfüllt, und ein abgebrochener Seed blockiert sich selbst dauerhaft. Danach braucht es wegen Migration 0019 zusätzlich die menschliche Freigabe. |
…ight away The re-review of #83 found that approving with a non-queueing sender could leave a sample APPROVED without any export job when the seed was aborted during the ERP call. The approval now queues its export job in its own transaction as always; the seed remembers the job id and runs it at once, and the later delivery finds EXPORTED and skips. With an unreachable ERP the queued job simply retries - no fallback branch. Tests cover the no-op later delivery, nothing half-written on an ERP outage, and that a sample whose export failed can still be exported again (only processing is refused). Refs #71 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Frischer Re-Review (/review-pr) – unabhängiger Reviewer-Agent ohne Umsetzungskontext, 2026-09-27 (Fix 3033f21)Geprüft und ohne Befund: Export in einer Transaktion (keine halbe Exportzeile); kein doppeltes Einreihen (singleton + exclusive); kein doppelter Export (Zeilensperre, unique, Idempotency-Key);
Urteil: „changes requested“ – wegen des Important-Befunds (kleiner Fix); sonst blockiert nichts. Wegen Migration 0019 braucht es danach ohnehin die menschliche Freigabe. Bearbeitung (b71cc84): Important behoben – die Freigabe reiht den Export-Job wieder in ihrer eigenen Transaktion ein, der Seed führt genau diesen Job sofort aus; eine spätere Zustellung endet als |
|
Merge auf ausdrückliche Freigabe des Orchestrators (2026-09-27: „OK“, „Merge“) – menschliche Freigabe für Migration 0019 erteilt. |
Warum
Fixes #71 · Teil von Epic #19 (Showcase-Review 2026-09-27, P0)
Arbeitsstand
sample+ Migration 0019; Modulsamples,pnpm seed:samples,pnpm samples:record; beide Aufnahmen; Kennzeichnung in Liste und Detail; Befunde des frischen Reviews: Export: die Freigabe reiht den Export-Job wie immer ein, der Seed führt genau diesen Job sofort aus (spätere Zustellung →skipped; ERP-Ausfall → die Warteschlange wiederholt), Quelle in der Intake-Transaktion, nur „eingeschwungene“ Status zählen, Fehlerpfad → ERROR ohne Live-Reprocess, Aufnahme per Vertrags-Schema validiert, keine Tokens/Latenz für das Abspielen; Unit-, Integrations- und E2E-Tests; Doku.pnpm setup:deploy),pnpm seed:samples, Screenshots.pnpm seed:demobzw. Runbook §6).Was ist passiert (Klartext)
Bisher gab es im Showcase nur Anfragen, die jemand selbst hochgeladen hat – und wenn Googles Modell gerade überlastet ist, sieht ein Besucher nur Fehlversuche (so am 27.09. einen halben Nachmittag lang). Jetzt legt ein Befehl feste Beispiel-Anfragen an: eine zum Prüfen (mit einem unsicheren Liefertermin und einer fehlenden Angabe) und eine, die schon freigegeben und ans ERP übergeben ist, mit sichtbarer ERP-Nummer. Ihre KI-Auswertung wurde einmal aufgezeichnet und wird beim Anlegen wiederverwendet, sodass sie nie vom Modellanbieter abhängt. Beide sind in Liste und Detailansicht als „Vorbereitetes Beispiel – aufgezeichnete KI-Antwort“ gekennzeichnet. Der Befehl lässt sich jederzeit wiederholen und legt nur an, was fehlt; bricht er ab, bleibt nichts halb fertig „in Verarbeitung“ hängen. Die Datenbank bekommt dafür eine kleine zusätzliche Prüfregel (Herkunft einer Anfrage: Upload oder Beispiel).
Plan-Pflicht (SYSTEM.md §4)
Impact Manifest
samples(src/features/samples/) mit Einstiegensrc/seed-samples.tsundsrc/samples-record.ts;requests(sourcebeicreateRequest,countSamples());intake(optionale Quelle beisubmitUpload, Standardupload);jobs(markProcessingFailed= bisherigesmarkErroröffentlich;reprocessRequestlehnt die Verarbeitung eines Beispiels ab);extraction(parseExtractResponse()– derselbe Parser für Live-Antworten und Aufnahmen);app(Kennzeichnung, kein „Erneut verarbeiten“ für ein Beispiel im Verarbeitungsfehler); DB-Schema (Migration 0019). Genutzt, nicht geändert:review(Freigabe),export(Export-Job, ERP-Adapter).source in ('upload', 'sample'), alle bestehenden Zeilen sindupload. Keine API-Änderung. Der Seed legt pro Demo-Firma bis zu zwei Anfragen mitsource = 'sample'an.uncertain+missing, Laufrecorded:…, 0 Tokens/Latenz), exportiertes Beispiel mit genau einer Export-Zeile, ERP-Referenz und einem Audit-Ereignis, keine Jobs in der Warteschlange; Idempotenz; ERP-Ausfall → APPROVED + Export-Job; Abbruch → ERROR, Reprocess abgelehnt, nächster Lauf ersetzt; Constraint (SQLSTATE 23514). Unit: Aufnahmen gültig, aufgezeichneter Client, frische Message-ID. E2E: Kennzeichnung in Liste und Detail, ERP-Referenz.requests.sourceexistiert (Standardupload, ohne CHECK);processRequestJobist idempotent und nimmt den KI-Client als Abhängigkeit;submitUploadnimmt einenJobSenderals Abhängigkeit;approveRequeststellt den Export-Job transaktional ein.werk-ostenthältuncertainundmissing(geprüft); die Message-ID ist in keiner Aufzeichnung ein Segment (geprüft), der Austausch pro Seed ändert also keinen Beleg.DROP CONSTRAINT; Beispiel-Anfragen sind normale synthetische Anfragen und lassen sich ablehnen. Menschliche Freigabe vor dem Merge (Migration, SYSTEM.md §5).Geändert
src/db/schema/app.ts,src/db/migrations/0019_request_source_check.sql: Quellesample+ CHECKsource in ('upload', 'sample')src/features/samples/(neu):samples.ts(Definitionen, frische Message-ID je Seed, validierte Aufnahmen, aufgezeichneter Client: Modell-IDrecorded:…, 0 Tokens/Latenz),seed.ts(seedSamples(): Intake mit Quellesample→ Verarbeitung inline mit Aufnahme, nie eingereiht → beiexportedFreigabe (Export-Job wie immer eingereiht) und sofortige Ausführung genau dieses Jobs; Abbruch der Verarbeitung → ERROR),data/(2 synthetische Mails + Aufnahmen),samples.test.ts,index.tssrc/seed-samples.ts(pnpm seed:samples),src/samples-record.ts(pnpm samples:record [key …]): Operator-Skripte;eslint.config.mjs:no-console-Ausnahme wie fürsrc/seed.ts, Begründung ergänztsrc/features/requests/:sourceinNewRequest,countSamples()src/features/intake/submit.ts: optionale Quelle{ source }(Standardupload) in derselben Transaktionsrc/features/jobs/:markProcessingFailedexportiert (bisher privatmarkError);reprocessRequestlehnt ein Beispiel im Verarbeitungsfehler absrc/features/extraction/ai-client.ts:parseExtractResponse()– derselbe Parser für Live-Antworten und Aufnahmensrc/app/requests/sample-label.ts(neu),page.tsx,[id]/page.tsx: Kennzeichnung in Liste und Detail; kein „Erneut verarbeiten“ für ein Beispiel im Verarbeitungsfehlertests/integration/samples.test.ts(neu),tests/e2e/sample-smoke.spec.ts(neu),tests/e2e/global-setup.ts(seed:samples)docs/technical/architecture.md(Modulsamples),docs/technical/deployment-vercel.md§6,CHANGELOG.mdNachweis (SYSTEM.md §11)
verify:changed: grün –vitest unit samples.test.ts ai-client.test.ts34/34;vitest integration samples.test.ts6/6. Reihenfolge ehrlich: die Tests entstanden nach dem Code, deshalb Gegenproben – Idempotenz-Prüfung ausgeschaltet → Test rot; der Review-Test fand zudem eine wirkungslose Prüfung (Abfrage ohne Mandantenkontext lieferte 0 Zeilen,everyauf leerer Liste) – jetzt im Mandanten mit Längenprüfungverify: lokal grün bis auf den bekannten Windows-Fall –lint0,typecheck,depcruise(Exit 0) grün; Unit 226/232 (die 6 Fehlschläge ausschließlichtests/architecture/dependency-rules.test.tsunter Windows, fix(tests): architecture test cannot start dependency-cruiser on Windows #78; Linux-CI grün); Integration 141/141 gegen Postgres + S3 (Migration 0019 auf der Test-DB angewendet);buildgrünverify:full/ E2E-Spec: E2E lokal 3/3 grün (neusample-smoke.spec.ts: Kennzeichnung in Liste und Detail, Zur Prüfung mit Aufmerksamkeits-Hinweis, Exportiert mit ERP-Referenz; bestehende Smoke-Flows unverändert grün); der zweite Setup-Lauf meldete „samples still in place“ (Idempotenz im echten Ablauf)gemini-3.5-flash):werk-ost4×found, Lieferterminuncertain(„KW 48“,calendar_week_only), zusätzliche Anforderungenmissing, 3 Positionen;pumpe-p2046×found, 2 Positionen. Seed und Screenshots im Showcase nach dem Merge.reprocessRequestdie Verarbeitung eines Beispiels ab und die Liste zeigt dafür keinen Knopf – kein Live-Aufruf möglich.Doku-Entscheidung (genau eine)
pnpm seed:samples, Aufnahme, Kennzeichnung)samples[Unreleased](sichtbares Feature oder Verhalten – im selben PR, nie „später"): Added-Eintrag feat(demo): prepared sample request that is always viewable #71Entferntes oder Umbenanntes:
docs/+ README gegrept, Treffer bereinigt: nichts entferntDateigrößen und neue Bausteine (SYSTEM.md §7)
Dateien über 500 Zeilen im Diff (Ausnahmen: generierter Code, Lockfiles, Fixtures, Migrationen, Schemas, Ressourcen, Doku, Konfiguration):
Über 800 Zeilen mit neuer Fachlogik oder über 1000 Zeilen (P1/P2): nicht betroffen
Neue Shared-Komponente, Utility-Datei, Adapter oder fachlicher Service:
src/seed.ts), Test-Fixtures für KI-Antworten (syntheticExtractResponse), Replay-Modus der Evals (services/ai--replay) und Upload-/Verarbeitungspfad; gefunden:seed.tslegt nur Firmen und Konten an;syntheticExtractResponseist ein handgeschriebener Test-Stub, keine Aufzeichnung; der Eval-Replay lebt im Python-Dienst. Neu ist deshalb nur der Seed-Ablauf, der die vorhandenen Pfade (Intake, Verarbeitung, Freigabe) mit einem aufgezeichneten Client aufruft.Subagent-Einsätze
Keine.
Risiken / offene Punkte
[Unreleased]hat jetzt 101 Zeilen (Doku-Guard-Warnung): ein Release ist fällig – nicht Teil dieses PRs.pumpe-p204scheiterte in drei Anläufen (24 Versuche über ~20 min) an Gemini503(Logsrequestflow-ai:model_call_retry503 ×2 → 502model_error). Hypothese „mailspezifisch“ widerlegt: eine Probe mit beiden Mails scheiterte gleich, obwohlwerk-osteine Stunde zuvor sofort durchlief. Ursache: Überlast des Free Tiers beim Anbieter – genau der Fall, gegen den dieser PR den Showcase absichert.🤖 Generated with Claude Code