fix(samples): settle samples an aborted seed run left behind - #92
Conversation
A seed run aborted midway left a sample in NEW/PROCESSING/ERROR that stayed in the list forever: the UI cannot reject it (only from REVIEW) and reprocessing a sample is refused on purpose. Samples are never queued, so these states only mean the run broke off. The seed now first rejects such leftovers through a dedicated status event (sample.retired), with a fixed reason and an audit event - never deleting a row. Fixes #84 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…eftovers-84 # Conflicts: # CHANGELOG.md
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The fresh review of #92 found that the leftover step rejected every sample in ERROR - including an approved one whose export failed, which may already be in the ERP and can be exported again. Only NEW, PROCESSING and ERROR from processing mean an aborted run. The rule now lives in the requests module (isSampleLeftover, retireSampleLeftover), re-checked under the row lock, so no other caller can apply it to an ordinary request. Concurrent seed runs are a follow-up (#93). Refs #84 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Frischer Review (/review-pr) – unabhängiger Reviewer-Agent ohne Umsetzungskontext, 2026-09-28
Ohne Befund geprüft: AK von #84 (Statusmaschine mit Audit, kein Löschen, Test, Runbook §6); Tenant-Scoping von Urteil: changes requested – ein Seed-Lauf könnte eine freigegebene, bewusst weiter exportierbare Beispiel-Anfrage ablehnen; der Fix ist klein. Bearbeitung (eaf94e1): 1 → Regel |
sample-leftover.ts took RequestRow from repository.ts, which imports the rule - dependency-cruiser's no-circular failed in CI. The rule now types its input from the schema. Refs #84 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merge auf Freigabe des Orchestrators (2026-09-28: „merge getestetes“) – CI grün, Review-Befunde bearbeitet. |
Warum
Fixes #84 · Folge aus dem Re-Review von #83
Arbeitsstand
sample.retired(test-first); RegelisSampleLeftoverim requests-Modul (Beispiel in NEW, PROCESSING oder ERROR aus der Verarbeitung – nie ERROR aus dem Export), angewendet überretireSampleLeftoverunter Zeilensperre; der Seed setzt Reste vor dem Anlegen auf abgelehnt, mit fester Begründung und Audit-Ereignis; Ergebnis{ seeded, retired }; Runbook §6, CHANGELOG; Review-Befunde eingearbeitet.Was ist passiert (Klartext)
Bricht das Anlegen der Beispiel-Anfragen mittendrin ab, blieb bisher ein halbfertiges Beispiel („in Verarbeitung“ oder „Fehler“) für immer in der Liste stehen – in der Oberfläche ließ es sich weder ablehnen noch neu verarbeiten (Letzteres ist absichtlich gesperrt, weil es die Live-KI aufrufen würde). Jetzt räumt der nächste Lauf solche Reste zuerst auf: Sie werden mit dem Grund „Beispiel durch einen neuen Lauf ersetzt – das Anlegen war abgebrochen.“ abgelehnt und im Verlauf festgehalten. Gelöscht wird nichts. Ein bereits freigegebenes Beispiel, dessen Übergabe ans ERP gescheitert ist, bleibt dagegen stehen – es kann weiter erneut exportiert werden.
Plan-Pflicht (SYSTEM.md §4)
Impact Manifest
requests(Statusmaschine: Ereignissample.retired; RegelisSampleLeftover;listSampleLeftoverIds(),retireSampleLeftover()),samples(Seed räumt Reste auf); Operator-Skriptsrc/seed-samples.ts(Ausgabe); Doku.sample.retired– nur überretireSampleLeftover, dasisSampleLeftoverunter der Zeilensperre prüft (Beispiel; ERROR nur aus der Verarbeitung). Keine Migration, keine API-Änderung. Audit-Aktionrequest.sample_retired.sample.retiredaus NEW/PROCESSING/ERROR und verbietet es aus REVIEW/APPROVED/EXPORTED/REJECTED;isSampleLeftover(9 Fälle, u. a. ERROR aus dem Export und Uploads nie). Integration – abgebrochener Lauf (Speicher fällt aus) → Rest in ERROR; nächster Lauf → Rest REJECTED mit Begründung, genau ein Audit-Ereignis; ein freigegebenes Beispiel in ERROR aus dem Export übersteht einen Lauf; Idempotenz mit{ seeded: [], retired: 0 }.reprocessRequestlehnt Beispiele nur in der Verarbeitungsstufe ab.Geändert
src/features/requests/status.ts(+ Test): Ereignissample.retiredsrc/features/requests/sample-leftover.ts(+ Test, neu):isSampleLeftover(Eingabetyp aus dem Schema, kein Import aus dem Repository – vermeidet einen Zirkel)src/features/requests/repository.ts,index.ts:listSampleLeftoverIds(tx),retireSampleLeftover(tx, row, reason)src/features/samples/seed.ts,index.ts: Reste vor dem Anlegen ablehnen (Begründung, Audit), RückgabeSeedResult { seeded, retired }src/seed-samples.ts: Ausgabe der abgelehnten Restetests/integration/samples.test.ts: Abbruch-Fall prüft das Aufräumen; neuer Fall „freigegebenes Beispiel mit Export-Fehler bleibt“; Rückgabetyp angepasstdocs/technical/deployment-vercel.md§6,CHANGELOG.mdNachweis (SYSTEM.md §11)
verify:changed: grün –vitest status.test.ts36/36, zuerst rot (7 neue Fälle: unbekanntes Ereignis);sample-leftover.test.tszuerst rot (Modul fehlte);vitest src/features/samples src/features/requests58/58;typecheck,lintgrünverify: grün – CI am PR: Unit 253/253, Integration 19 Dateien grün (daruntersamples.test.ts7/7),depcruise,build,audit. Ein erster CI-Lauf fiel anno-circular(sample-leftover.ts↔repository.ts) – lokal hatte ichdepcruisenicht laufen lassen; behoben durch einen Schema-Typ, lokaldepcruisejetzt ohne Verletzungenverify:full/ E2E-Spec: nicht betroffen (die E2E-Spec der Beispiele prüft Kennzeichnung und Export; ein frischer Lauf hat keine Reste)Doku-Entscheidung (genau eine)
docs/technical/deployment-vercel.md§6[Unreleased](sichtbares Feature oder Verhalten – im selben PR, nie „später"): Changed-Eintrag chore(samples): settle samples left over by an aborted seed run #84Entferntes oder Umbenanntes:
docs/+ README gegrept, Treffer bereinigt: Rückgabetyp vonseedSamplesgeändert – nur im Code referenziertDateigröß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:
Subagent-Einsätze
Keine.
Risiken / offene Punkte
🤖 Generated with Claude Code