Skip to content

fix(orchestrator): n_merge aus tatsächlichem Merge-Ausgang statt Planner-Intent#302

Merged
TillQuandel merged 1 commit into
masterfrom
fix/283-n-merge-outcome
Jul 15, 2026
Merged

fix(orchestrator): n_merge aus tatsächlichem Merge-Ausgang statt Planner-Intent#302
TillQuandel merged 1 commit into
masterfrom
fix/283-n-merge-outcome

Conversation

@TillQuandel

Copy link
Copy Markdown
Owner

Problem

pipeline_runs.n_merge wurde als sum(1 for d in drafts if d.action == "extend") berechnet — die Planner-VORAB-Klassifikation, nicht das tatsächliche Verify-/Dedup-Ergebnis. Dadurch war der Wert zustandsabhängig falsch (Belege aus der Testlauf-Serie 2026-07-14):

  • Lauf 2 (Deci & Ryan): 1 echter Merge-Stub im Log, DB n_merge=0.
  • Lauf 5 (Dreisiebner): 2 echte Sibling-Dedup-Merges (0 "extend"-Konzepte geplant), DB n_merge=0.
  • Lauf 3 (Schüller): n_merge=2 stimmte zufällig — die geplanten "extend"-Konzepte waren identisch mit den späteren Merge-Zielen.

Ursache

Ein Konzept kann anders enden als geplant, in beide Richtungen:

  • Geplant extend, aber resolve_sibling_dups setzt ein dangling Intra-Run-extend auf create zurück (kein realer Vault-Bezug) → alte Zählung zählt fälschlich mit.
  • Geplant create, aber write_note findet beim Schreiben einen Title-/Alias-Match im Vault → wird zum Merge-Stub → alte Zählung übersieht es (action bleibt "create").

Fix

generative/orchestrator.py: neue Funktion count_actual_merges(drafts, n_sibling_dedup) summiert zwei disjunkte, tatsächliche Ausgänge:

  1. Sibling-Dedup-Absorptionn_sib aus resolve_sibling_dups (bereits vorhanden, lief bisher nur ins Log, nicht in die DB).
  2. Merge-Stub-Erzeugung beim Schreiben — neues Draft-Feld AtomicNoteDraft.is_merge_stub (Ownership: writer=vault_writer reader=orchestrator), das vault_writer.write_note() setzt, wenn der Draft als Diff-Stub zu einer bestehenden Vault-Note geschrieben wird (statt als eigene Note) — analog zum bereits etablierten Muster für auto_vault_recommended. Kein Signaturwechsel von write_note(), keine Auswirkung auf andere Aufrufer (extractive-Pipeline, GUI).

pipeline_runs.n_merge liest jetzt count_actual_merges(drafts, n_sib) statt der alten Intent-Zählung.

Konsumenten-Analyse (Scatter-Chip #275)

Geprüft: generative/eval_dashboard.py, generative/eval_dashboard_server.py, internal/dashboard/eval_dashboard.html (NUL-Byte-Check: weiterhin genau 1, unverändert — Datei nicht angefasst).

  • Live-Dashboard-Pfad (eval_dashboard_server.py, DB-Fallback wenn keine lokalen .log-Dateien vorliegen): liest n_merge direkt und unverändert aus der pipeline_runs-Zeile (r.get("n_merge", 0) or 0) — reiner Pass-through. Kein Code-Change nötig, der Fix wirkt automatisch auf alle künftigen Läufe. Das speist _accept_from_runs/_calc_pdf_table (SSoT für die "gemergt, nicht evaluiert"-Scatter-Kategorie aus fix(dashboard): ch1-Akzeptanzbalken bei 0-Eval-Lauf ehrlich kennzeichnen + Merge-Notes als eigene Scatter-Kategorie #275/Dashboard-Ehrlichkeit Rest zu #237: ch1-Akzeptanzbalken grün bei 0-Eval-Lauf + Merge-Notes-Scatter-Kategorie #249) sowie enrich_pct/success_pct.
  • Deprecated Log-Parsing-Pfad (eval_dashboard._read_all_log_runs(), hat Priorität VOR dem DB-Fallback, sobald lokale .cache/eval/baseline/*.log-Dateien existieren — z. B. auf Tills Entwicklungsmaschine nach Baseline-Läufen): zählt n_merge unabhängig über Regex auf [Merge-Stub]/XSOURCE-MERGE-Print-Zeilen. Das ist bereits Ausgabe-basiert (kein Intent-Bug), erfasst aber Sibling-Dedup-Absorptionen nicht (kein passender Print-Marker) — ein separater, vorbestehender Gap außerhalb des Issue-Scopes (Fix-Richtung [MITTEL] n_merge zählt Planner-Intent "extend" statt tatsächlicher Merges #283 nennt explizit nur die DB-Spalte). Nicht angefasst. Praktische Folge: Wer lokal gecachte .log-Dateien hat, sieht dort weiterhin die schmalere (Merge-Stub-only) Definition, bis diese Logs neu erzeugt werden.
  • internal/dashboard/eval_dashboard.html: JS liest nur r.n_merge/p.n_merge aus dem server-gebauten pdf_table — keine eigene Berechnung, keine Änderung nötig.

Alt/Neu-Skew (Bestandsdaten)

quality_history/runs/Baseline-Daten sind read-only, die Semantik-Änderung gilt nur für künftige Läufe:

  • Bestehende pipeline_runs-Zeilen behalten für immer die alte (Intent-)Zählung im selben n_merge-Feld — es gibt keinen rückwirkenden Recompute.
  • Aggregate, die NICHT nach pipeline_version filtern (z. B. eval_dashboard.pys Lifetime-total_merged = sum(r.get("n_merge", 0) for r in all_log_runs)), mischen ab jetzt zwei unterschiedliche Metrikdefinitionen über die Zeit.
  • Versions-gruppierte Ansichten (runs_by_version in eval_dashboard_server.py) bleiben pro Version intern konsistent — ein Sprung im n_merge-Chart genau an der Version, die diesen Fix enthält, ist erwartet (Definitionswechsel), kein neuer Bug.
  • Der bestehende Auto-Version-Bump-Mechanismus (orchestrator._auto_version_bump, code-hash-gestützt) bumpt AGENT_VERSION beim nächsten tatsächlichen Lauf automatisch, weil orchestrator.py/vault_writer.py/atomic_note.py sich geändert haben — das liefert eine natürliche Versionsgrenze zwischen altem und neuem n_merge, ohne manuellen Eingriff hier.

Tests (TDD)

RED zuerst gezeigt (2x):

  1. count_actual_merges existierte nicht → ImportError beim Sammeln von test_n_merge_actual_outcome.py.
  2. note.is_merge_stub-Mutation temporär entfernt → test_write_note_honors_extend_path_to_concept schlug fehl (assert False is True).

Neu: generative/tests/test_n_merge_actual_outcome.py (5 Tests) — deckt u. a. den exakten Bug-Fall ab (geplantes extend ohne realen Merge → 0; geplantes create, das zum Merge-Stub wird → 1; Summe aus beiden Quellen ohne Doppelzählung).
Erweitert: generative/tests/test_typeaware_dedup.py (2 neue Assertions auf is_merge_stub).

Suite: pytest generative lib/decision_engine/tests shared/tests -q5958 passed, 3 skipped, 8 deselected (alle vorbestehend, z. B. pdftotext-gated). ruff check . clean, ruff format --check . clean (286 files).

Offene Punkte / Risiken

  • Deprecated Log-Parsing-Pfad (_read_all_log_runs) bleibt bei der schmaleren Merge-Stub-only-Definition (siehe oben) — falls das später harmonisiert werden soll, ist das ein eigenes Ticket.
  • Kein Recompute historischer pipeline_runs-Zeilen (bewusst, da Bestandsdaten read-only laut Task-Vorgabe).

Fixes #283

…nner-Intent (#283)

pipeline_runs.n_merge zaehlte bisher sum(action == "extend") — die Planner-
Vorab-Klassifikation, nicht das tatsaechliche Verify-/Dedup-Ergebnis. Neu:
count_actual_merges() summiert Sibling-Dedup-Absorption (resolve_sibling_dups)
und Merge-Stub-Erzeugung beim Schreiben (vault_writer.write_note setzt dafuer
das neue Draft-Feld is_merge_stub, analog zu auto_vault_recommended).

Fixes #283
@TillQuandel TillQuandel merged commit 3b72609 into master Jul 15, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[MITTEL] n_merge zählt Planner-Intent "extend" statt tatsächlicher Merges

2 participants