Skip to content

fix(citation): /Title bei Dateiname-Autor-Mismatch quarantaenisieren (#234) - #256

Merged
TillQuandel merged 2 commits into
masterfrom
fix/234-title-cross-check
Jul 13, 2026
Merged

fix(citation): /Title bei Dateiname-Autor-Mismatch quarantaenisieren (#234)#256
TillQuandel merged 2 commits into
masterfrom
fix/234-title-cross-check

Conversation

@TillQuandel

Copy link
Copy Markdown
Owner

Befund (Scout-verifiziert)

Trust-Asymmetrie: Die Pipeline quarantaenisiert den eingebetteten Info-Dict-/Author bereits (pdf_chunker._parse_pdfinfo_output: nur diagnostisch als InfoDictAuthor), vertraute dem /Title aber ungeprueft. _TITLE_LOOKS_BAD faengt nur Zahlenmuell, keine plausiblen Falsch-Titel.

Schlebbe-Afzal-Poisoning: Ein frueherer enrich(rename=True)-Lauf hatte beim Schlebbe-PDF ALLE eingebetteten Metadaten von Afzal 2017 (aus dem Literaturverzeichnis) zurueckgeschrieben. Folge: beide Schlebbe-Notes zitierten „Conceptualisation and Measurement of Information Needs" (Afzal) statt Schlebbe & Greifeneder 2022. Die finale Zitation liest pdf_meta.get("Title") direkt (citation.py:126) — ein reiner q_title-Filter haette die Fehlattribution NICHT behoben.

Gewaehlter Ansatz (Richtung A: Dateiname-Cross-Check analog /Author)

Titel lassen sich nicht per Nachname matchen; das robusteste vorhandene Signal ist der Embedded-Autor. Widerspricht InfoDictAuthor dem Dateiname-Autor, ist der GESAMTE eingebettete Block unglaubwuerdig — inkl. /Title.

  • _filename_contradicts_embedded_author (pdf_enrich.py): Gegenstueck zum bestehenden _zotero_author_matches_embedded. Meldet einen positiven Widerspruch NUR bei parsbarem Dateiname UND echtem Nachname-Mismatch. Fehlender Embedded-Autor / unparsbarer Dateiname → False (kein Overreach auf sauberen Bestand).
  • _quarantine_poisoned_embedded_title (orchestrator.py): leert pdf_meta["Title"] in place. Aufgerufen im Normalpfad (vor dem Enrichment, damit der Merge-Guard orchestrator.py:1993 einen legitim angereicherten Titel setzen kann) UND im --load-drafts-Reload-Pfad (zweiter, unabhaengiger Trust-Punkt). Danach greift die vorhandene Fallback-Kaskade (Merge-Guard / q_title / vault_writer:167) auf den dateinamen-abgeleiteten Titel „Information Need, Informationsbedarf und -bedürfnis".

Locus-Begründung: Der Titel wird direkt in pdf_meta quarantaenisiert (nicht nur q_title), weil build_citation_meta pdf_meta["Title"] direkt liest — nur so wird die tatsaechliche Zitation korrigiert.

TDD RED → GREEN

  • RED (vor Fix): test_title_trust_cross_check.pyAttributeError/AssertionError; test_without_quarantine_citation_carries_poison_title reproduziert die Fehlattribution (cite.title == POISON_TITLE). Reload-Poison-Test schlug fehl (Gift-Titel ueberlebte Resume).
  • GREEN: Schlebbe-Realfall zitiert Dateiname-Titel; 3 Positiv-Kontrollen (passender Autor / kein Embedded-Autor / unparsbarer Dateiname) belegen keinen Overreach; 5 Guard-Unit-Tests in test_pdf_enrich.py; Reload-Poison-Test gruen.
  • Bestandstest: test_load_draft_state_roundtrip.py:172-177 — Clean-Input-Assertion bleibt gueltig (kein widersprechender InfoDictAuthor → Verhalten unveraendert); Kommentar an neue Ableitung angepasst + neuer Poison-Reload-Test ergaenzt.

Abnahme

  • Voll-Suite pytest generative lib/decision_engine/tests shared/tests -q: 5800 passed, 3 skipped, 4 deselected, 0 failed.
  • ruff check + ruff format --check: sauber.

Schlebbe-PDF-Bereinigung (einmalig, ausserhalb Repo)

Backup ZUERST: C:/tmp/schlebbe-2022-bak-vor-234-cleanup.pdf (106760 bytes, verifiziert identisch). Korrigiert via _write_pdf_metadata mit dateinamen-abgeleiteten Werten (kein Raten; Afzal-DOI entfernt, Schlebbe-DOI unbekannt → leer).

Feld before after
Title Conceptualisation and Measurement of Information Needs: A Literature Review Information Need, Informationsbedarf und -bedürfnis
Author Afzal Schlebbe und Greifeneder
Subject 2017 2022
Keywords 10.1080/24750158.2017.1306165 (leer)
Pages 9 9

Pipeline-Gegencheck auf der korrigierten Datei: _quarantine_poisoned_embedded_titleFalse (self-consistent, korrekter Titel bleibt).

Hinweis: Die zwei bereits generierten Schlebbe-Notes im Vault tragen weiterhin die alte Afzal-Zitation — Neu-Generierung ist ein separater Pipeline-Lauf (ausserhalb dieses Issues).

Closes #234

…— Selbst-Vergiftung durch enrich (#234)

Die Pipeline quarantaenisierte den eingebetteten Info-Dict-/Author bereits
(pdf_chunker: nur diagnostisch als InfoDictAuthor), vertraute dem /Title aber
ungeprueft (Trust-Asymmetrie). Ein frueherer enrich(rename=True)-Lauf hatte beim
Schlebbe-PDF alle eingebetteten Metadaten von Afzal 2017 zurueckgeschrieben
(Selbst-Vergiftung) -> beide Schlebbe-Notes zitierten den Afzal-Titel statt
Schlebbe & Greifeneder 2022.

Fix (Richtung A, Dateiname-Cross-Check analog /Author): Widerspricht der
eingebettete Info-Dict-Autor dem Dateiname-Autor, ist der GESAMTE Embedded-Block
unglaubwuerdig -> /Title verwerfen. Damit greift die vorhandene Fallback-Kaskade
(enrich-Merge / q_title / vault_writer) auf den dateinamen-abgeleiteten Titel.

- _filename_contradicts_embedded_author (pdf_enrich): Gegenstueck zum bestehenden
  _zotero_author_matches_embedded — meldet einen POSITIVEN Widerspruch NUR bei
  parsbarem Dateiname UND echtem Nachname-Mismatch (kein Overreach bei fehlendem
  Embedded-Autor / unparsbarem Dateiname).
- _quarantine_poisoned_embedded_title (orchestrator): leert pdf_meta["Title"] in
  place; aufgerufen im Normalpfad (vor dem Enrichment, damit der Merge-Guard einen
  legitim angereicherten Titel setzen kann) UND im --load-drafts-Reload-Pfad
  (zweiter, unabhaengiger Trust-Punkt).

Tests: RED->GREEN in test_title_trust_cross_check.py (Schlebbe-Realfall + 3
Positiv-Kontrollen), 5 Guard-Unit-Tests in test_pdf_enrich.py, Reload-Poison-Test
in test_load_draft_state_roundtrip.py (Bestandstest-Kommentar an neues Verhalten
angepasst). Voll-Suite gruen.
…s-Check (#234)

Review von PR #256 fand einen HIGH-Bug in _filename_contradicts_embedded_author,
an 4 realen Literatur-PDFs verifiziert: Der beidseitige Nur-letztes-Token-Vergleich
brach in zwei Klassen und quarantaenisierte korrekte Titel faelschlich:
1. Mehrautoren: Bei "Autor1 und Autor2 - Jahr - Titel" wurde nur Autor2 geprueft;
   ein legitimer Embedded-ERSTautor (= Autor1) erzeugte einen falschen Widerspruch
   (Ebner und Gegenfurtner / Klingenberg und Weber / Deci und Ryan / Ayaz und Yanartaş).
2. Diakritika: Reine Diakritik-Differenz brach den Match auch bei Ein-Autor
   (Yanartaş vs. Yanartas).

Fix (Vergleichs-Heuristik, kein Kern-Umbau):
- Neuer Helper _author_surnames: zerlegt Autor-String an _AUTHOR_SEP_RE
  (';'/'und'/'and'/'&') in Einzelautoren, Nachname = letztes Token (bzw. Teil vor
  Komma bei "Nachname, Vorname" — Deci-Fall), diakritik-gefaltet.
- Widerspruch nur noch, wenn KEIN Embedded-Nachname zu IRGENDEINEM Dateiname-
  Nachnamen passt (Mengen-isdisjoint). Grosszuegig gegen Overreach.
- Diakritik-Fold in Helper _strip_diacritics extrahiert (aus _significant_tokens,
  verhaltensgleich) und beidseitig genutzt.

Schlebbe/Afzal bleibt korrekt Widerspruch (True): 'Afzal' passt zu weder 'Schlebbe'
noch 'Greifeneder'. Neue Tests: 5-fach parametrisierte Overreach-Faelle + Diakritik-
Ein-Autor + Regressions-Erhalt; RED->GREEN. Voll-Suite 5807 passed, ruff sauber.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants