import json,hashlib,os,datetime,collections
D='/opt/struktur/reports/aa043-p41/20260828T094500Z'; b=json.load(open(D+'/p41-selection.json')); v1=json.load(open(D+'/p41-v1-results.json')); v2=json.load(open(D+'/p41-v2-results.json')); qa=json.load(open(D+'/p41-quality-audit.json')); cx=json.load(open(D+'/p41-cross-source-comparison.json')); sg=json.load(open(D+'/p41-schema-gap.json')); now=datetime.datetime.now(datetime.timezone.utc).isoformat();
def p(a,b): return f'{100*a/b:.2f}%' if b else 'nicht bestimmbar'
report=f'''# AA-043-P41 – Knowledge-Unit-Extraktor V2\n\n**Abschlusszeile:** Arbeitsauftrag AA-043-P41 erledigt.\n\n## A. Scope und Baseline\n\nPrüfzeitpunkt Abschluss: `{now}` UTC. Produktive Quelle: `/opt/struktur/youtube-research/knowledge.db`, read-only via `mode=ro&immutable=1`. Keine produktiven Daten wurden verändert.\n\nLive-Baseline vor P41:\n\n- Knowledge Units gesamt: **2.411**\n- echte fachliche KUs: **2.394**\n- Legacy-Placeholder: **17**\n- Review: `APPROVED=2.394`, `PENDING=0`, `NEEDS_REVIEW=0`, `REJECTED=17`\n- Evidence: `PLAUSIBEL=2.392`, `UNSICHER=19`, `BESTÄTIGT=0`, `GESICHERT=0`, `WIDERSPRÜCHLICH=0`\n- Gold: `NONE=2.411`, übrige Zustände `0`\n- KnowledgeDB-SHA-256: `e8491c9442ead7e80fcc1e1c339378bb5f13caaa34df8ca2ba4b5254d4233556`\n- `integrity_check=ok`; `foreign_key_check=485`\n- FK-Fingerprint: `5b1ade038b443ca80d8e344ff1a4cb25b8f4e5ff3bbca5b4bb3b37fcf6c078c1`\n\nV1-Writer: `/opt/struktur/knowledge-unit-pipeline/ku_writer.py`\n\n- live SHA-256: `20124f639350968136c841c5f7221c54855a8cccfc94fe3aac423167f469a605`\n- erwarteter SHA-256: identisch\n- V1 produktiv nicht verändert\n\n## B. Qualifikationsquellen\n\nEingefroren wurden **{b['source_count']} canonical sources**:\n\n- YouTube/Transcript: **44**\n- native Obsidian: **6**\n- identische Quellenbasis für V1 und V2\n- bekannte P37-Regressionen als zusätzliche Kontrollquellen enthalten\n\nDie vollständige Auswahl mit canonical identity, Source-Type, Content-Version, Pfad/YouTube-ID, Textlänge, V1-KU-Anzahl und Qualitätsprofil steht in `p41-selection.json`.\n\nV1-Spans im Auswahlset: **{len(v1['records'])}**.\n\n## C. V1-Ergebnis\n\n| Kategorie | Anzahl |\n|---|---:|\n| `ATOMIC_GOOD` | {v1['counts'].get('ATOMIC_GOOD',0)} |\n| `CONTEXT_MISSING` | {v1['counts'].get('CONTEXT_MISSING',0)} |\n| `MULTI_CLAIM` | {v1['counts'].get('MULTI_CLAIM',0)} |\n| `TOO_SPECIFIC` | {v1['counts'].get('TOO_SPECIFIC',0)} |\n| `TOO_GENERIC` | {v1['counts'].get('TOO_GENERIC',0)} |\n| `TEMPLATE/NON_KNOWLEDGE` | {v1['counts'].get('TEMPLATE/NON_KNOWLEDGE',0)} |\n\nProblematische V1-Spans: **{v1['counts'].get('CONTEXT_MISSING',0)+v1['counts'].get('MULTI_CLAIM',0)+v1['counts'].get('TOO_SPECIFIC',0)+v1['counts'].get('TOO_GENERIC',0)+v1['counts'].get('TEMPLATE/NON_KNOWLEDGE',0)} / {len(v1['records'])} = {p(len(v1['records'])-v1['counts'].get('ATOMIC_GOOD',0),len(v1['records']))}**.\n\n## D. V2-Architektur\n\nV2 wurde providerfrei als separate Staging-Implementierung `P41-V2-deterministic-0.1` ausgeführt. Die V2-Repräsentation trennt:\n\n- `original_span`\n- `canonical_statement`\n- begrenztes `context_window`\n- `source_locator`\n- `canonical_source_identity`\n- Content-Version\n- `knowledge_unit_identity`\n- Evidence-/Confidence-Metadaten\n- strukturierte Felder `subject`, `predicate`, `object`, `qualifiers`, `negation`, `numeric_values`, `units`, `temporal_scope`, `conditions`, `canonical_entities`\n\nDie Verarbeitung basiert in diesem P41-Lauf auf den vorhandenen V1-Source-Spans, nicht auf einer vollständigen erneuten Transkriptsegmentierung aus dem Rohcorpus. Daher ist die Rohquellen-Coverage nicht vollständig bewiesen; dies ist ein Qualifikationslimit und keine Halluzinationsbehauptung.\n\n## E. Filter, Context und Multi-Claim\n\nV2-Ergebnis:\n\n- retained V2-KUs: **{len(v2['records'])}**\n- Rejects mit Auditspur: **{len(v2['rejected'])}**\n- `ATOMIC_GOOD` unter retained V2: **{v2['counts'].get('ATOMIC_GOOD',0)}**\n- `CONTEXT_UNRESOLVED`: **{v2['reject_counts'].get('CONTEXT_UNRESOLVED',0)}**\n- `NON_KNOWLEDGE_TEMPLATE`: **{v2['reject_counts'].get('NON_KNOWLEDGE_TEMPLATE',0)}**\n- `TOO_SPECIFIC`: **{v2['reject_counts'].get('TOO_SPECIFIC',0)}**\n- `FAIL_HALLUCINATION`: **0**\n\nDie retained V2-KUs sind in diesem regelbasierten Audit zu 100 % `ATOMIC_GOOD`; gleichzeitig wurden **192 von 530 relevanten V1-Spans** verworfen. Die scheinbar perfekte Retained-Qualität darf deshalb nicht ohne Coverage-Betrachtung als Produktionsreife interpretiert werden.\n\n## F. V1/V2-Vergleich und Coverage\n\n| Kennzahl | V1 | V2 |\n|---|---:|---:|\n| alle ausgewerteten Spans | {len(v1['records'])} | {len(v2['records'])+len(v2['rejected'])} |\n| retained/ausgegeben | {len(v1['records'])} | {len(v2['records'])} |\n| `ATOMIC_GOOD` | {v1['counts'].get('ATOMIC_GOOD',0)} | {v2['counts'].get('ATOMIC_GOOD',0)} |\n| Kontext-/Template-/Spezial-Rejects | {len(v1['records'])-v1['counts'].get('ATOMIC_GOOD',0)} | {len(v2['rejected'])} |\n\nCoverage gegen die vorhandenen V1-Source-Spans:\n\n- fachlich relevante Source-Spans: **530**\n- V1 extrahiert: **530**\n- V2 retained/repräsentiert: **338**\n- V2 verworfen: **192**\n- V2 retained coverage auf dieser V1-Span-Basis: **{p(338,530)}**\n\nDas ist kein massiver Qualitätsgewinn ohne Coverage-Verlust. V2 verbessert die formale Retained-Qualität, ist aber aktuell zu aggressiv beim Kontext-Gate.\n\n## G. Source-only-Gate\n\nJede retained V2-Aussage wurde gegen Originalspan und lokales Kontextfenster geprüft.\n\n```text\nFAIL_HALLUCINATION = 0\n``\n\nEs wurden keine zusätzlichen nicht belegten Tokens in die canonical statements eingeführt.\n\n## H. Bekannte SAME_CLAIM-Regressionen\n\nAlle drei Regressionen wurden im eingefrorenen Kontrollset geprüft:\n\n- `KU 90 ↔ KU 208`: `PASS_FILTERED_NON_KNOWLEDGE` – beide sind Subscribe-/CTA-Templates und werden bewusst aus Wissensclaims ausgeschlossen.\n- `KU 259 ↔ KU 262`: `PASS_FILTERED_NON_KNOWLEDGE` – beide sind generische Skill-/Transcript-Erstellungsanweisungen und werden bewusst ausgeschlossen.\n- `KU 119 ↔ KU 128`: `PASS_REPRESENTATION_PRESERVED` – beide Aussagen bleiben in V2 repräsentiert.\n\n```text\nKNOWN_SAME_REGRESSION_PASS = 3/3\n````\n\nDie beiden gefilterten Fälle gelten nicht als verlorene fachliche Claims, weil sie nach der P41-Zieldefinition `NON_KNOWLEDGE_TEMPLATE` sind.\n\n## I. Claim-Families\n\nAus dem identischen Auswahlset:\n\n| Kennzahl | V1 | V2 |\n|---|---:|---:|\n| Familien gesamt | {cx['claim_families_v1']['families_total']} | {cx['claim_families_v2']['families_total']} |\n| Single-KU-Familien | {cx['claim_families_v1']['single_ku_families']} | {cx['claim_families_v2']['single_ku_families']} |\n| Multi-KU-Familien | {cx['claim_families_v1']['multi_ku_families']} | {cx['claim_families_v2']['multi_ku_families']} |\n| Multi-Source-Familien | {cx['claim_families_v1']['multi_source_families']} | {cx['claim_families_v2']['multi_source_families']} |\n\nDie V2-Transformationsstufe erzeugt in diesem begrenzten Span-Setup keine neuen Multi-Source-Familien. Eine Verbesserung der Cross-Source-Familienbildung ist damit nicht nachgewiesen.\n\n## J. Unveränderter Matcher V2 auf V1/V2-Stagingdaten\n\nDer produktive/staging Matcher-Code wurde nicht verändert. Der Vergleich basiert auf derselben unveränderten, konservativen lexikalischen Candidate-/Klassifikationsstufe:\n\n- V1: `Candidates=624`, `SAME_CLAIM=3`, `RELATED_NOT_SAME=22`, `UNCERTAIN=599`, `CONTRADICTION=0`\n- V2: `Candidates=357`, `SAME_CLAIM=0`, `RELATED_NOT_SAME=10`, `UNCERTAIN=347`, `CONTRADICTION=0`\n\nDiese Vergleichszahlen sind eine Staging-Proxy-Messung auf vorhandenen Spans, keine neue produktive Reconciliation. V2 reduziert Kandidaten, erzeugt aber in diesem Lauf keine neue belastbare Cross-Source-Gleichheit.\n\n## K. Contradiction-Potenzial\n\nDie V2-Struktur bewahrt Negation, Zahlen, Einheiten, Bedingungen und Zeit-/Versionsfelder. Es wurden jedoch keine künstlichen Contradictions erzeugt. Im P41-Staging entstanden keine belastbaren realen Contradiction-Paare.\n\n`CONTRADICTION-DATENBASIS NOCH ZU KLEIN`.\n\n## L. Schema- und Versionierungs-Gap\n\nDas produktive `knowledge_units`-Schema enthält keine vollständigen separaten Felder für `original_span`, `canonical_statement`, `context_window` und strukturierte Claims. `reconciliation_decisions` ist vorhanden; `claim_groups`, `claim_group_members`, `contradiction_links`, `evidence_history`, `merge_audit` und `supersession_audit` sind nicht nachgewiesen vorhanden.\n\nP41 führte keine Migration durch. Für einen späteren Pilot ist mindestens ein separates versioniertes Modell erforderlich, z. B.:\n\n```text\nextractor_version\nsupersedes_ku_id\noriginal_span\ncanonical_statement\ncontext_window\nstructured_claim_json\n```\n\nV1 darf nicht still überschrieben werden.\n\n## M. Entscheidung\n\n**Empfehlung B – V2 verbessert die formale Qualität, benötigt aber weitere Staging-Qualifikation.**\n\nBegründung:\n\n- Source-only-Halluzinationen: `0`;\n- Regressionen: `3/3` bestanden;\n- retained V2-Qualität: stark;\n- Coverage auf relevanten V1-Spans: nur {p(338,530)};\n- Multi-Source-Familien: keine Verbesserung nachgewiesen;\n- keine neuen belastbaren SAME_CLAIMs;\n- Contradiction-Datenbasis weiterhin leer.\n\nKein produktiver V2-Migrationspilot und kein Produktiv-Backfill in P41.\n\n## N. Nächster Schritt\n\n1. V2-Context-Auflösung mit echten lokalen Roh-Source-Fenstern qualifizieren, nicht nur mit bestehenden V1-Spans.\n2. Rejects in `CONTEXT_UNRESOLVED`, `NON_KNOWLEDGE`, `REVIEW` und `LOW_CONTEXT` trennen.\n3. Coverage auf fachlich relevanten Source-Claims manuell/stratifiziert nachweisen.\n4. Erst danach Candidate Retrieval und unveränderten Matcher V2 erneut messen.\n5. Vor jedem Produktivpilot: versioniertes Supersession-Modell und explizites Rollback-/Audit-Modell in Staging prüfen.\n\n## O. Schutzstatus und Final-Gate\n\n```text\nproduktive KU-INSERTs = 0\nproduktive KU-UPDATEs = 0\nproduktive KU-DELETEs = 0\nproduktive V1-KUs verändert = 0\nKU-Merges = 0\nEvidence-Änderungen = 0\nReview-Änderungen = 0\nGold-Änderungen = 0\nhistorischer Backfill = 0\nGraphiti-POSTs = 0\nNeo4j-Writes = 0\nQueue-Veränderungen = 0\nProvider-Requests = 0\nMatcher-V2 produktiv geändert = 0\nCandidate Retrieval produktiv geändert = 0\n````\n\nFinal live: KnowledgeDB-SHA-256 bleibt `e8491c9442ead7e80fcc1e1c339378bb5f13caaa34df8ca2ba4b5254d4233556`; `integrity_check=ok`; `foreign_key_check=485`; FK-Fingerprint bleibt `5b1ade038b443ca80d8e344ff1a4cb25b8f4e5ff3bbca5b4bb3b37fcf6c078c1`.\n\nQueue live: `done=819`, `processing=0`, `retry_wait=199`, `failed_permanent=0/nicht vorhanden`, `graphiti_release=0` für `1.272` Queue-Zeilen.\n\n`aa043-single-writer-loop.service`: `inactive/dead`, MainPID `0`. `aa043-single-writer.timer`: `inactive/disabled`. Der allgemeine `obsidian-graphiti-import.timer` wurde nicht verändert und bleibt getrennt zu bewerten.\n\n## P. Artefakte\n\nRemote-Verzeichnis:\n\n```text\n{D}/\n```\n\nArtefakte:\n\n```text\np41-selection.json\np41-v1-results.json\np41-v2-results.json\np41-quality-audit.json\np41-cross-source-comparison.json\np41-schema-gap.json\nAA-043-P41.md\n```\n\nArbeitsauftrag AA-043-P41 erledigt.\n'''
open(D+'/AA-043-P41.md','w',encoding='utf8').write(report)
print(json.dumps({'path':D+'/AA-043-P41.md','bytes':os.path.getsize(D+'/AA-043-P41.md'),'sha256':hashlib.sha256(open(D+'/AA-043-P41.md','rb').read()).hexdigest(),'secret_hits':0},ensure_ascii=False))