import json, hashlib, os, subprocess
base='/opt/struktur/reports/aa043-p44-r1p/20260828T142945Z/'
order=json.load(open(base+'p44-r1p-order-pass-a.json'))['case_ids'][:40]
seg_ids={x for x in order if x.startswith('SEG-')}; clm_ids={x for x in order if x.startswith('CLM-')}; pair_ids={x for x in order if x.startswith('PAIR-')}
S={
'SEG-0118':('CORRECT_BOUNDARY','Die Namensliste schließt die zuvor angekündigten Celebrities sinnvoll ab.'),
'SEG-0290':('SHOULD_JOIN','"Bitz." ist nur der abgetrennte Rest des Namens "Mr. Bitz".'),
'SEG-0075':('NON_CONTENT','Reine wertende Zwischenbemerkung ohne fachlichen Segmentinhalt.'),
'SEG-0131':('NON_CONTENT','Kurze Bedien-/Übergangsbemerkung ohne eigenständigen fachlichen Inhalt.'),
'SEG-0196':('CORRECT_BOUNDARY','Vollständige, eigenständig verständliche Aussage über eine Gedächtnisfunktion.'),
'SEG-0019':('SHOULD_SPLIT','Enthält mehrere eigenständige Aussagen zu autonomen, organisierten Agenten und Paperclip.'),
'SEG-0239':('CORRECT_BOUNDARY','Vollständige Aussage über Lernen und Tests der Agenten; die Grenze ist nachvollziehbar.'),
'SEG-0157':('CORRECT_BOUNDARY','Vollständige Capability-Aussage mit klarer Grenze vor der nächsten Funktion.'),
'SEG-0191':('NON_CONTENT','Reine Bestätigungsformel ohne fachliche Aussage.'),
'SEG-0109':('CORRECT_BOUNDARY','Eigenständige Leitfrage, die den folgenden Erklärungsabschnitt einleitet.'),
'SEG-0221':('SHOULD_SPLIT','Das Segment enthält mehrere eigenständige Aussagen zu MCP, JSON-Konfiguration und Einrichtung.'),
}
def c(statement,subject,predicate,obj,value='MEDIUM',num=None,units=None,conditions=None):
return {'atomic_statement':statement,'subject':subject,'predicate':predicate,'object':obj,'negation':False,'numeric_values':num or [],'units':units or [],'temporal_scope':None,'conditions':conditions,'knowledge_value':value}
C={
'CLM-0129':('YES',[c('Eine lokale Installation ist sehr schnell, kann aber das System gefährden.','lokale Installation','ist','schnell, aber potenziell systemgefährdend','HIGH'),c('Eine Sandbox erhöht die Sicherheit, schränkt aber die Möglichkeiten ein.','Sandbox','erhöht','Sicherheit bei eingeschränkter Funktionalität','HIGH'),c('Docker kann schützenswerte Dienste deaktivieren, um Risiken durch Prompt Injection zu reduzieren.','Docker','kann','Dienste deaktivieren und dadurch Schutz erhöhen','HIGH')],'LOCAL','Die genannten Installationsvarianten und ihre Vor- und Nachteile sind im Fenster ausreichend beschrieben.'),
'CLM-0156':('YES',[c('Ein lokal installiertes Tool mit Vollzugriff kann das gesamte System und Daten gefährden.','lokales Tool','kann gefährden','System und Daten','HIGH'),c('Ein Agent kann bei Fehlsteuerung unerwünschte E-Mails senden.','Agent','kann senden','unerwünschte E-Mails','MEDIUM'),c('Eine Prompt Injection in einer E-Mail kann Folgeaktionen auslösen.','Prompt Injection in E-Mail','kann auslösen','unerwünschte Agentenaktionen','HIGH')],'LOCAL','Die Sicherheitsrisiken werden im Rohfenster konkret benannt.'),
'CLM-0234':('YES',[c('Der Agent kann proaktiv nachts Software schreiben, veröffentlichen und morgens zusammenfassen.','Agent','kann','nächtliche Softwareaufgaben ausführen, publizieren und zusammenfassen','HIGH'),c('Ein konkretes Beispiel beschreibt einen Agenten, der selbständig eine Telefonnummer beschafft und einen Anruf auslöst.','Cloudbot-Assistent','hat ausgeführt','Telefonnummer beschaffen und Anruf auslösen','MEDIUM')],'LOCAL','Die behaupteten Fähigkeiten und das Beispiel stehen im bereitgestellten Fenster.'),
'CLM-0268':('YES',[c('OpenClow kann lokal installiert werden.','OpenClow','kann installiert werden','lokal','MEDIUM'),c('OpenClow kann Inbox, E-Mail, Kalender und Flüge verwalten.','OpenClow','kann verwalten','Inbox, E-Mail, Kalender und Flüge','HIGH'),c('OpenClow unterstützt Messaging-Kanäle, persistentes Gedächtnis, Browsersteuerung und PC-Befehle.','OpenClow','unterstützt','Messaging, Gedächtnis, Browser und PC-Befehle','HIGH'),c('OpenClow besitzt einen Marketplace für Skills und Plugins.','OpenClow','besitzt','Marketplace für Skills und Plugins','MEDIUM')],'NONE','Die im Fenster genannten Capabilities sind ohne externe Ergänzung bestimmbar.'),
'CLM-0020':('YES',[c('Das Tool kann Wissen visuell aufbereiten und komplexe Zusammenhänge darstellen.','Tool','kann','visuelle Wissensaufbereitung','HIGH'),c('NotebookLM kann ein neues oder ein bestehendes Notizbuch öffnen.','NotebookLM','kann','neues oder bestehendes Notizbuch öffnen','MEDIUM'),c('Für das gezeigte Feature wird empfohlen, das Stiftsymbol statt des einfachen Buttons zu wählen.','Bedienung','empfiehlt','Stiftsymbol auswählen','MEDIUM')],'LOCAL','Der lokale Kontext enthält die Funktionsbeschreibung und die konkrete Bedienempfehlung.'),
'CLM-0026':('YES',[c('Eine lokale Installation sollte ohne Betrachtung von Sicherheitslücken nicht unkritisch übernommen werden.','lokale Installation','erfordert','Berücksichtigung von Sicherheitslücken','HIGH'),c('Bei Telegram können andere Personen den Namen finden und sich mit dem Bot verbinden; Vollzugriff birgt Risiken.','Telegram-Bot','kann ermöglichen','Verbindung durch andere Personen und Vollzugriff','HIGH')],'LOCAL','Die Warnung und das Telegram-Szenario sind im Rohfenster enthalten.'),
'CLM-0086':('YES',[c('Behauptungen über schnelle große Gewinne durch Agenten sind Beispiele für Social-Media-Hype.','Gewinnversprechen über Agenten','sind','Social-Media-Hype','MEDIUM'),c('Die Aussage, dass Agenten grundsätzlich nutzlos seien, wird als Gegenposition dargestellt.','Agenten','werden dargestellt als','nutzlos','LOW'),c('Kontroverse oder übertriebene Meinungen können Klicks erzeugen.','kontroverse Meinungen','können erzeugen','Klicks','MEDIUM')],'LOCAL','Das Fenster stellt Hype, Gegenposition und vermuteten Klickanreiz ausdrücklich gegenüber.'),
'CLM-0082':('YES',[c('Ein Agent könnte bei unbeschränktem Zugriff weitreichende und unerwünschte Aktionen ausführen.','Agent mit weitreichendem Zugriff','könnte ausführen','unerwünschte Aktionen','HIGH'),c('Die aufgezählten Beispiele sind ausdrücklich überspitzt formulierte mögliche Folgen.','Beispiele','sind','überspitzte Szenarien','MEDIUM')],'LOCAL','Der Kontext kennzeichnet die Beispiele selbst als überspitzt; die Aussage ist dennoch fachlich eine Risikowarnung.'),
'CLM-0133':('YES',[c('Ein KI-Agent kann Skills installieren und Aufgaben ausführen.','KI-Agent','kann','Skills installieren und Aufgaben ausführen','HIGH'),c('Das beschriebene System ist proaktiv und verfügt über ein Forum zum Austausch von Agenten.','System','verfügt über','proaktives Verhalten und Agentenforum','MEDIUM'),c('Im Forum sind laut Fenster über 150000 Agenten beteiligt.','Agentenforum','umfasst','über 150000 Agenten', 'MEDIUM',[150000],['Agenten'])],'LOCAL','Die Aussagen und die genannte Größenordnung stehen im Rohfenster.'),
'CLM-0241':('YES',[c('Ein virtueller privater Server ist eine Installationsmöglichkeit.','virtueller privater Server','ist','Installationsmöglichkeit','MEDIUM'),c('Auf einem isolierten VPS ist ein Schaden laut Fenster begrenzter, solange kein Zugriff auf persönliche Daten gegeben wird.','VPS','begrenzt','Schadensumfang unter der Bedingung fehlender persönlicher Daten','HIGH',conditions='solange kein Zugriff auf persönliche Daten gegeben wird')],'LOCAL','Installationsoption und Bedingung werden im Fenster direkt erklärt.'),
'CLM-0291':('YES',[c('Die Nische bestimmt das Pricing stärker als die Technologie.','Nische','bestimmt','Pricing','HIGH'),c('Eine Agentur kann eine App-Idee mit geförderter Beratung prüfen und erste Designs erstellen.','Agentur','kann anbieten','geförderte Beratung und erste Designs','MEDIUM')],'LOCAL','Die beiden Aussagen sind im Rohfenster klar enthalten.'),
'CLM-0138':('YES',[c('Stärkere Modelle sollen bei Prompt Injections sicherer sein als sehr kleine Modelle.','starkes Modell','soll sein','relativ sicherer gegenüber Prompt Injections','HIGH'),c('Opus 4.5 und GPT 5.2 werden als Beispiele für relativ starke Modelle genannt.','Modelle','werden genannt als','Opus 4.5 und GPT 5.2','LOW'),c('Stärkere Modelle können teurer sein.','starke Modelle','können sein','teurer','MEDIUM')],'LOCAL','Die Empfehlung und ihre Einschränkung stehen im Fenster.'),
'CLM-0214':('YES',[c('Ein Frontend kann in kurzer Zeit implementiert werden, benötigt aber noch Funktionen.','Frontend','kann implementiert werden','in kurzer Zeit, aber zunächst ohne vollständige Funktionen','MEDIUM'),c('Ein Pull Request zeigt die Änderungen, die Entwickler prüfen können.','Pull Request','zeigt','vorgenommene Änderungen zur Entwicklerprüfung','MEDIUM')],'LOCAL','Die Aussagen beziehen sich auf die im Fenster beschriebene Entwicklungssequenz.'),
'CLM-0068':('YES',[c('Ein OpenAI-Key kann optional eingetragen oder ein Abo verbunden werden.','OpenAI-Key/Abo','kann verwendet werden','optional zur Modellnutzung','MEDIUM'),c('API-Keys können über die Zeit relativ teuer werden.','API-Keys','können verursachen','laufende Kosten','HIGH'),c('Für sehr günstige Modelle kann die Konfiguration über das Terminal erforderlich sein.','günstige Modelle','erfordern möglicherweise','Konfiguration über Terminal','MEDIUM')],'LOCAL','Optionen, Kostenwarnung und Terminal-Hinweis sind im Fenster enthalten.'),
}
# Pair labels: the repeated trigger sentence is not materially the same as any counterpart.
P={}
for cid in [x for x in order if x.startswith('PAIR-')]:
P[cid]=('UNRELATED','INDEPENDENT',False,False,False,'Die beiden Aussagen betreffen keine materiell identische oder widersprüchliche prüfbare Behauptung.')
P['PAIR-0049']=('UNCERTAIN','UNCLEAR',False,False,False,'Die zweite Aussage ist fragmentarisch und inhaltlich nicht zuverlässig bestimmbar.')
P['PAIR-0026']=('UNCERTAIN','UNCLEAR',False,False,False,'Die zweite Aussage ist stark fragmentarisch; eine belastbare Sachbeziehung ist nicht entscheidbar.')
def ann(cid,pos):
if cid in S:
lab,reason=S[cid]; return {'global_order_position':pos,'case_id':cid,'benchmark_type':'SEGMENTATION','annotation':{'label':lab,'reason':reason}}
if cid in C:
lab,claims,ctx,reason=C[cid]; return {'global_order_position':pos,'case_id':cid,'benchmark_type':'CLAIM','annotation':{'contains_knowledge_claim':lab,'atomic_claim_count':len(claims),'claims':claims,'required_context':ctx,'reason':reason}}
lab,ind,ss,sp,so,reason=P[cid]; return {'global_order_position':pos,'case_id':cid,'benchmark_type':'PAIR','annotation':{'label':lab,'source_independence':ind,'same_subject':ss,'same_predicate':sp,'same_object':so,'different_qualifier':False,'negation_difference':False,'numeric_difference':False,'unit_difference':False,'temporal_difference':False,'version_difference':False,'condition_difference':False,'reason':reason}}
rows=[ann(cid,i) for i,cid in enumerate(order,1)]
assert len(rows)==40 and [x['global_order_position'] for x in rows]==list(range(1,41))
assert len({x['case_id'] for x in rows})==40
out='/opt/struktur/reports/aa043-p44-r1a-batches/B01'; os.makedirs(out,exist_ok=True)
json.dump({'batch_id':'AA-043-P44-R1A-B01','global_order_positions':'1-40','items':rows},open(out+'/p44-r1a-b01-labels.json','w'),ensure_ascii=False,indent=2)
summary={'batch_id':'AA-043-P44-R1A-B01','expected_positions':[1,40],'annotated_cases':40,'missing_positions':0,'duplicate_positions':0,'duplicate_case_ids':0,'out_of_range_positions':0,'BATCH_COMPLETENESS':'PASS','segment_cases':len(S),'claim_cases':len(C),'pair_cases':len(P),'uncertain_cases':sum(1 for r in rows if r['annotation'].get('label')=='UNCERTAIN')+sum(1 for r in rows if r['annotation'].get('contains_knowledge_claim')=='UNCERTAIN')}
json.dump(summary,open(out+'/p44-r1a-b01-validation.json','w'),ensure_ascii=False,indent=2)
report='''# AA-043-P44-R1A-B01\n\nBlind PASS-A Batch 01; ausschließlich globale Positionen 1–40.\n\n- Annotierte Fälle: 40\n- Segmentierungsfälle: 11\n- Claim-Fälle: 14\n- Pair-Fälle: 15\n- BATCH_COMPLETENESS: PASS\n- Nested Provider Requests: 0\n- Produktive Schreibzugriffe: 0\n\nDie Annotationen wurden in globaler Reihenfolge gespeichert. Keine PASS-B-, Consensus-, Segmenter-, Extractor- oder Matcher-Ergebnisse wurden verwendet.\n'''
open(out+'/AA-043-P44-R1A-B01.md','w').write(report)
files=['p44-r1a-b01-labels.json','p44-r1a-b01-validation.json','AA-043-P44-R1A-B01.md']
h={f:hashlib.sha256(open(out+'/'+f,'rb').read()).hexdigest() for f in files}
json.dump(h,open(out+'/SHA256SUMS.json','w'),ensure_ascii=False,indent=2)
print(json.dumps({'out':out,'files':h,'summary':summary},ensure_ascii=False))