fix(orchestrator): n_merge aus tatsächlichem Merge-Ausgang statt Planner-Intent#302
Merged
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
pipeline_runs.n_mergewurde alssum(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):n_merge=0.n_merge=0.n_merge=2stimmte 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:
extend, aberresolve_sibling_dupssetzt ein dangling Intra-Run-extendaufcreatezurück (kein realer Vault-Bezug) → alte Zählung zählt fälschlich mit.create, aberwrite_notefindet beim Schreiben einen Title-/Alias-Match im Vault → wird zum Merge-Stub → alte Zählung übersieht es (actionbleibt"create").Fix
generative/orchestrator.py: neue Funktioncount_actual_merges(drafts, n_sibling_dedup)summiert zwei disjunkte, tatsächliche Ausgänge:n_sibausresolve_sibling_dups(bereits vorhanden, lief bisher nur ins Log, nicht in die DB).AtomicNoteDraft.is_merge_stub(Ownership:writer=vault_writer reader=orchestrator), dasvault_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ürauto_vault_recommended. Kein Signaturwechsel vonwrite_note(), keine Auswirkung auf andere Aufrufer (extractive-Pipeline, GUI).pipeline_runs.n_mergeliest jetztcount_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).eval_dashboard_server.py, DB-Fallback wenn keine lokalen.log-Dateien vorliegen): liestn_mergedirekt und unverändert aus derpipeline_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) sowieenrich_pct/success_pct.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ähltn_mergeunabhä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 nurr.n_merge/p.n_mergeaus dem server-gebautenpdf_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:pipeline_runs-Zeilen behalten für immer die alte (Intent-)Zählung im selbenn_merge-Feld — es gibt keinen rückwirkenden Recompute.pipeline_versionfiltern (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.runs_by_versionineval_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.orchestrator._auto_version_bump, code-hash-gestützt) bumptAGENT_VERSIONbeim 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 neuemn_merge, ohne manuellen Eingriff hier.Tests (TDD)
RED zuerst gezeigt (2x):
count_actual_mergesexistierte nicht →ImportErrorbeim Sammeln vontest_n_merge_actual_outcome.py.note.is_merge_stub-Mutation temporär entfernt →test_write_note_honors_extend_path_to_conceptschlug fehl (assert False is True).Neu:
generative/tests/test_n_merge_actual_outcome.py(5 Tests) — deckt u. a. den exakten Bug-Fall ab (geplantesextendohne realen Merge → 0; geplantescreate, das zum Merge-Stub wird → 1; Summe aus beiden Quellen ohne Doppelzählung).Erweitert:
generative/tests/test_typeaware_dedup.py(2 neue Assertions aufis_merge_stub).Suite:
pytest generative lib/decision_engine/tests shared/tests -q→ 5958 passed, 3 skipped, 8 deselected (alle vorbestehend, z. B. pdftotext-gated).ruff check .clean,ruff format --check .clean (286 files).Offene Punkte / Risiken
_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.pipeline_runs-Zeilen (bewusst, da Bestandsdaten read-only laut Task-Vorgabe).Fixes #283