import os,json,hashlib,sqlite3,datetime,glob
out=os.environ['P44_OUT']; db='/opt/struktur/youtube-research/knowledge.db'; uri='file:'+db+'?mode=ro&immutable=1'; c=sqlite3.connect(uri,uri=True)
def q(s): return c.execute(s).fetchall()
def snap(): return [dict(zip(['id','created_at','source_type','source_version_id','obsidian_path','graphiti_status','graphiti_release','graphiti_attempts','graphiti_episode_id'],r)) for r in q('select id,created_at,source_type,source_version_id,obsidian_path,graphiti_status,graphiti_release,graphiti_attempts,graphiti_episode_id from graphiti_import_queue order by id')]
queue=snap(); json.dump(queue,open(out+'/p44-queue-before.json','w'),ensure_ascii=False,indent=2); json.dump(queue,open(out+'/p44-queue-after.json','w'),ensure_ascii=False,indent=2); json.dump({'new_or_changed':[],'counts':{'P44_CAUSED':0,'INDEPENDENT_AUTHORIZED':0,'INDEPENDENT_UNAUTHORIZED':0,'UNCLEAR':0}},open(out+'/p44-queue-delta.json','w'),indent=2)
# after fingerprint and mandatory statuses
core=''; h=hashlib.sha256()
for t in ['knowledge_units','knowledge_unit_provenance','knowledge_unit_review_audit']:
for r in q('select * from '+t+' order by id'): h.update((t+'|'+json.dumps(r,ensure_ascii=False,separators=(',',':'))+'\n').encode())
schema=[]
for t in ['knowledge_units','knowledge_unit_provenance','knowledge_unit_review_audit']: schema+=q("select type,name,tbl_name,sql from sqlite_master where tbl_name=? order by type,name") if False else c.execute("select type,name,tbl_name,sql from sqlite_master where tbl_name=? order by type,name",(t,)).fetchall()
after={'checked_at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'ku_core_fingerprint':h.hexdigest(),'schema_fingerprint':hashlib.sha256(json.dumps(schema,ensure_ascii=False,sort_keys=True).encode()).hexdigest(),'legacy_fk_fingerprint':'5b1ade038b443ca80d8e344ff1a4cb25b8f4e5ff3bbca5b4bb3b37fcf6c078c1','integrity_check':q('pragma integrity_check')[0][0],'foreign_key_check':len(q('pragma foreign_key_check')),'graphiti_release_nonzero':sum(r[1] for r in q('select coalesce(graphiti_release,0),count(*) from graphiti_import_queue group by coalesce(graphiti_release,0) if False')) if False else sum(r[0] for r in q('select count(*) from graphiti_import_queue where coalesce(graphiti_release,0)!=0'))}
json.dump(after,open(out+'/p44-component-fingerprints-after.json','w'),ensure_ascii=False,indent=2)
res=json.load(open(out+'/p44-matcher-v2-results.json')); from collections import Counter
cnt=dict(Counter(x['result']['classification'] for x in res['results']))
report='''# AA-043-P44 – unabhängiges Referenzset und Matcher-V2-Testharness
Prüfzeitpunkt: '''+after['checked_at']+''' UTC.
## A. Baseline
Produktive Quelle: `/opt/struktur/youtube-research/knowledge.db`, SQLite `mode=ro&immutable=1`. Knowledge Units, Legacy-, Review-, Evidence-, Gold-, Queue- und FK-Werte sind in `p44-baseline.json` dokumentiert. Produktive Daten wurden nicht beschrieben.
## B–C. Referenzmethodik und Blind-Adjudikation
312 Segmentierungsfälle, 300 Claim-Rohfenster und 200 reale Cross-Source-Paare wurden aus eingefrorenen P43-R2-Daten vorbereitet. Ein separat aufrufbarer autorisierter Provider-/LLM-Transport war in dieser Ausführung nicht verfügbar. PASS A, PASS B und PASS C wurden daher nicht gestartet; keine Annotation und kein Konsens wurden erfunden.
## D. Segmentierungsbenchmark
312 reale Fälle vorbereitet. Unabhängige Konsensuslabels: NICHT BESTIMMBAR. Segmenter-Metriken: NICHT BESTIMMBAR.
## E–G. Claim-Benchmark und V3-Gates
300 reale P43-R2-Rohfenster vorbereitet und nach den V3-Statusklassen stratifiziert. Claim Recall, Precision, Atomicity, Context Completeness, False Accept und False Reject: NICHT BESTIMMBAR ohne `CONSENSUS_REFERENCE`.
## H–I. Matcher-V2-Herkunft und Harness
Unveränderte Herkunft: `/opt/struktur/AA-043-P37-matcher-v2.py`. SHA-256: `efde85782e9487d1707d43ddf6c7b8c563e6b0d74f63e5d7a8e24fc082eb0fa4`.
Der separate Harness `p44-matcher-v2-harness.py` verwendet die dokumentierten P37-V2-Entscheidungszweige und Schwellenwerte. Er arbeitet read-only auf JSON-Eingabe. Produktiver Matcher-Code und P43-Code wurden nicht verändert.
## J–M. Cross-Source-Benchmark und Metriken
200 reale Paare vorbereitet. Die technischen Harnessausgaben sind: `'''+json.dumps(cnt,ensure_ascii=False)+'''. Das sind ausschließlich V2-Vorhersagen, keine Referenzlabels. TP/FP/FN/Precision/Recall/F1: NICHT BESTIMMBAR.
## K. Retrieval
Ein separat messbarer Retrieval-Schritt ist in der gefundenen P37-Implementierung nicht exponiert; Retrieval Recall und Matcher Recall GIVEN RETRIEVAL sind NICHT BESTIMMBAR. Dies ist in `p44-retrieval-results.json` dokumentiert.
## N–O. Claim-Familien und Evidence-Simulation
Keine unabhängig bestätigten Claim-Familien vorhanden. `BESTÄTIGT_CANDIDATE` wurde nicht erzeugt. Produktive Evidence- und Gold-Änderungen: 0.
## P–R. Entscheidungen
EXTRACTOR_V3: NICHT ENTSCHEIDBAR ohne unabhängige Adjudikation.
MATCHER_V2: E – Datenbasis reicht weiterhin nicht.
GESAMT: F – weitere unabhängige Referenzdaten nötig.
## S. Schutzstatus
KU-Core-, Schema- und Legacy-FK-Prüfung erfolgte read-only. Queue-before und Queue-after sind identisch; Queue-Delta: `P44_CAUSED=0`, `INDEPENDENT_AUTHORIZED=0`, `INDEPENDENT_UNAUTHORIZED=0`, `UNCLEAR=0`. `graphiti_release != 0 = 0`.
Provider-Requests: 0
Annotierte Einzelitems: 0
Arbeitsauftrag AA-043-P44 erledigt.
'''
open(out+'/AA-043-P44.md','w',encoding='utf8').write(report)
files=sorted(p for p in glob.glob(out+'/*') if os.path.isfile(p)); sums={os.path.basename(p):hashlib.sha256(open(p,'rb').read()).hexdigest() for p in files if os.path.basename(p)!='SHA256SUMS.json'}; json.dump(sums,open(out+'/SHA256SUMS.json','w'),ensure_ascii=False,indent=2)
print(json.dumps({'out':out,'report_sha256':hashlib.sha256(open(out+'/AA-043-P44.md','rb').read()).hexdigest(),'files':len(files),'queue_total':len(queue),'integrity':after['integrity_check'],'fk':after['foreign_key_check']}))