From c4e993e3f82a96f0f6bf620af1840d8a244affff Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Tue, 14 Apr 2026 06:59:47 +0200 Subject: [PATCH] fix: Leere Controls (title/objective=None) filtern vor Store - Batch-Postprocessing: Controls mit title/objective = None/null/"" werden gefiltert und nicht gespeichert. Title wird aus Objective abgeleitet falls nur Title fehlt. - _store_control: Pre-store Quality Guard lehnt leere Controls ab - Verhindert "None"-Controls die durch LLM-Parsing-Fehler entstehen Co-Authored-By: Claude Opus 4.6 (1M context) --- .../services/control_generator.py | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/control-pipeline/services/control_generator.py b/control-pipeline/services/control_generator.py index 1f99ca1..f65ec66 100644 --- a/control-pipeline/services/control_generator.py +++ b/control-pipeline/services/control_generator.py @@ -1526,9 +1526,22 @@ Gib ein JSON-Array zurueck mit GENAU {len(chunks)} Elementen. Fuer Aspekte ohne final: list[Optional[GeneratedControl]] = [] for i in range(len(batch_items)): control = all_controls.get(i) - if not control or (not control.title and not control.objective): + # Filter empty or invalid controls (LLM returned None/empty) + if not control: final.append(None) continue + title_invalid = not control.title or control.title.strip().lower() in ("none", "null", "") + obj_invalid = not control.objective or control.objective.strip().lower() in ("none", "null", "") + if title_invalid and obj_invalid: + logger.warning("Leerer Control gefiltert (title=%s, objective=%s) — wird nicht gespeichert", + control.title, control.objective) + final.append(None) + continue + # Clean up "None" strings from LLM + if title_invalid: + control.title = control.objective[:120] if control.objective else "Unbenannt" + if obj_invalid: + control.objective = control.title if control.release_state == "too_close": final.append(control) @@ -1931,6 +1944,14 @@ Kategorien: {CATEGORY_LIST_STR}""" def _store_control(self, control: GeneratedControl, job_id: str) -> Optional[str]: """Persist a generated control to DB. Returns the control UUID or None.""" + # Pre-store quality guard — reject empty/invalid controls + if not control.title or control.title.strip().lower() in ("none", "null", ""): + logger.warning("Rejected control with empty/None title: %s", control.control_id) + return None + if not control.objective or control.objective.strip().lower() in ("none", "null", ""): + logger.warning("Rejected control with empty/None objective: %s — %s", control.control_id, control.title) + return None + try: # Get framework UUID fw_result = self.db.execute(