
    L`j z                       d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlmZmZ ddlmZ ddlmZ  ee      j%                         j&                  Ze	j*                  j-                  d ee             ddlmZmZmZmZmZ g dZg d	Zd
ddddddddddddZ d)dZ!d*dZ"d+dZ#d,dZ$d-dZ%d.dZ&d/dZ'd0dZ(d1dZ)d2d Z*d3d!Z+d4d"Z,	 	 	 	 	 	 d5d#Z-d3d$Z.d6d%Z/d7d&Z0d8d'Z1e2d(k(  r e3 e1             y)9zPrepare and optionally conduct a local, human-only review pilot.

Neo4j access in this file is one read-only MATCH query. The only writes are
to the explicitly local review_pilot.db and the Markdown report.
    )annotationsN)datetimetimezone)Path)Any)CURATOR_VERSIONNORMALIZATION_VERSIONdigest	normalizesource_quality)ArchitecturezAgent-Solutions	SolutionsRunbooksSystemstrukturzKI-Kursez
01-Kontextz05-Ressourcen)approved_for_pilotrejectedneeds_more_context	duplicate
wrong_typewrong_subjectwrong_predicatewrong_objectwrong_modalitywrong_polarity
wrong_timeinsufficient_evidencer   r   r   r   r   r   r   r   r   r   r   r   )arcdtspomnzec                 d    t        j                  t        j                        j	                         S N)r   nowr   utc	isoformat     //opt/struktur/knowledge-curator/review_pilot.pyr+   r+   %   s    <<%//11r/   c                ,    | j                  dd      d   S )N/   r   )split)paths    r0   arear6   )   s    ::c1a  r/   c                   g d}g }|D ]7  }|j                  t        j                  || t        j                               9 t	        t
        j                  d |D                    }t        d |D              }t        d |D              }||rdj                  |      nd|rdn|rd	nd
t        |xs |xr |       dS )N)z\b\d{4}-\d{2}-\d{2}\bz\b\d{1,2}\.\d{1,2}\.\d{4}\buc   \b(?:januar|februar|märz|april|mai|juni|juli|august|september|oktober|november|dezember)\s+\d{4}\bz+\b(?:seit|bis)\s+(?:dem?\s+)?[^,.;\n]{1,30}u7   \b(?:zuvor|aktuell|künftig|historisch|gestern|heute)\b)flagsc              3  <   K   | ]  }|j                           y wr*   )strip.0xs     r0   	<genexpr>zextract_time.<locals>.<genexpr>5   s     8Qqwwy8s   c              3  H   K   | ]  }t        j                  d |        yw)z)\d{4}-\d{2}-\d{2}|\d{1,2}\.\d{1,2}\.\d{4}N)re	fullmatchr;   s     r0   r>   zextract_time.<locals>.<genexpr>6   s     `UV2<< LaP`s    "c              3  @   K   | ]  }|j                         d v   yw)>      künftigheutezuvoraktuellgesternN)casefoldr;   s     r0   r>   zextract_time.<locals>.<genexpr>7   s     g\]1::<#WWgs   z; unknowng      ??g        )extracted_time_textproposed_temporal_scopetime_confidencetime_needs_review)
extendr@   findall
IGNORECASElistdictfromkeysanyjoinbool)textpatternsfoundpatternabsoluterelatives         r0   extract_timer^   -   s    LH E ERZZR]]CDE8%889E`Z_``HgafggH#(;@tyy'7i&.sUT!%h&J53I\!KM Mr/   c                P   | j                  d      xs dj                         }|j                         | d   j                         }|r&t        |      dk  sj	                  d      sd|d d v ryd	v sd
v ryd|v sdv ryd|v sdv rt        j                  d      st        j                  d      ryt        fddD              rdv sdv rdnd}d|dddfS dv sdv ryt        fd d!D              r"d"d t        j                  d#      rd$dd%fS ddd%fS t        fd&d'D              r^t        fd(d)D              rd*}n&d+v rd,}nd-v rd.}nd/v sd0v rd1}nd2v sd3v rd}nd4}t        j                  d5      rd$nd}d6||dd7fS t        j                  d8      ry9y:);NrX    r5      )zfrage:z	question:?   )NNrI   rI   no_claim_or_questionwunschu   ich möchte)NNrI   rI   wish_not_fact"zzitat:)KnowledgeClaimreportedpositiverI   quoted_or_reported_claimbusinessplanz(?:version|[_ -]v)\s*\dz\bversion\s*\d)DocumentVersionNrj   rI   document_version_signalc              3  &   K   | ]  }|v  
 y wr*   r.   r<   r=   lows     r0   r>   zclassify.<locals>.<genexpr>J   s     
18
   )z wurde durch z wurde ersetztu    zurückgerolltz	 rollbackz	 migriertz aktualisiertrollbacku   zurückgerolltrolled_backfactual_historicalKnowledgeEventrj   rI   change_event_signal	verworfenu   zurückgezogen)rh   	withdrawnrj   rI   withdrawn_plan_signalc              3  &   K   | ]  }|v  
 y wr*   r.   rp   s     r0   r>   zclassify.<locals>.<genexpr>O   s     
f18
frr   )zmuss z
darf nichtpolicyzregel:z
erfordert verbindlichKnowledgeRulez\b(nicht|kein|keine)\bnegativenormative_signalc              3  &   K   | ]  }|v  
 y wr*   r.   rp   s     r0   r>   zclassify.<locals>.<genexpr>Q   s       i18  irr   )zist zsind war zwurde u   läuftaktiv	verwendetu   unterstützt
   bestätigtgeplantplant   könntestatusc              3  &   K   | ]  }|v  
 y wr*   r.   rp   s     r0   r>   zclassify.<locals>.<genexpr>R   s     IAqCxIrr   )r   r   zsoll sollteplannedr   proposedgetestettestedr   	produktiv	confirmedr   
historischfactual_currentz\b(nicht|kein|keine|nie)\brh   state_or_capability_signalz#\b(behauptet|vermutet|laut|notiz)\b)rh   ri   rj   rI   reported_claim_signal)NNrI   rI   no_deterministic_signal)getr:   rH   len
startswithr@   searchrU   )rowrX   r5   modalitypolarityrq   s        @r0   classifyr   >   s   GGFO!r((*D
--/Cv;!D3t9r>S^^4K%LPSW[\`]`WaPaG3-3.@
d{h#o^	4	>S#8biiHbdg>hmomvmv  xI  KN  nOX

~
$.#$59IS9P=Vj:yBWWWc-4\

fe
ffBII>WY\4]jox  {M  M  	Mcmox  {M  M  	M
  i  h  i  iI!HIIV_8#*x38S K3$6;s]lc1>R8*h!#+H#!N:T^8Y@\\\	yy7=[Fr/   c                   | j                  d      xs d}t        j                  |j                               j	                         }i d| d   d| d   d| d   d	| j                  d
      xs |d| d   d| j                  d      d| j                  d      d|d d dddt        t        |      d      dddt        |      dt        |      dkD  ddd|ddddt        t        dS ) NrX   r`   source_document_import_keydocument_import_keysource_content_hashcontent_hashsource_chunk_key	chunk_keysource_text_hash	text_hashrelative_pathr5   headingchunk_indexevidence_text  evidence_start_offsetr   evidence_end_offsetevidence_offset_basisanalyzed_chunk_textevidence_lengthevidence_truncatedfull_evidence_availableTevidence_hashextraction_rulereview_pilot_heuristic_v2extraction_rule_versionzkc-rules-v2)curator_versionnormalization_version)	r   hashlibsha256encode	hexdigestminr   r   r	   )r   rX   hs      r0   evidencer   _   sc   776? bDt{{}%//1A
<(#.C*D 
<!3~#6
<8JCP[L\
< 4 9
<;JCPVK
< swwy)
< ,9#''-:P
< T$3Z	
< *A!	
<
 "3s4y##6
<
 9PQf
< s4y
< +?D	C
< &t
< Q
< !23N
< &}
< JY%:
< 
<r/   c                   t        |       \  }}}}}|sy | j                  d      xs dj                         }| j                  d      xs t        | d         j                  }	ddddj                  |d	      }
|j                  d
d      d   d d }t        | d   |      \  }}}|dk(  r|dk(  rd}n	|dv rd}nd}i dt        || d   |      d|d|	d d d|
d|ddd|d|ddd|d d!d"|d#|d$d d%d d&d d'd d d d d d(d)d*||d+	t        |       t        |      }t        ||	|
|d|xs d,||dg
}d-d.d/d0d1|   }t        fd2|D         ||<   |S )3NrX   r`   r   r5   change_eventrequires_or_prohibitsdocument_version)rv   r~   rm   states
r3   r   rc   rh   ri   gffffff?)rw   rn   g?rJ   candidate_idr   candidate_typesubject	predicateobjectobject_typer   r   temporal_scoperI   authority_scopeverification_state
unverifiedr   claim_confidenceasserted_atobserved_at
valid_fromvalid_toneeds_reviewu=   Heuristischer Pilotkandidat; fachliche Prüfung erforderlich.T)	recorded_atverified_atsuperseded_atevent_atproposed_statusproposed_reasonrequires_human_approvalrun_idsource_signalnone	claim_key	event_keyrule_keydocument_version_keyrh   rv   r~   rm   c              3  6   K   | ]  }t        |        y wr*   )r   )r<   r=   ruless     r0   r>   z"build_candidate.<locals>.<genexpr>   s     Fai51Fs   )r   r   r:   r   stemr4   r   r
   r   r^   r	   )r   r   r   typr   r   scoperulerX   r   r   objstqualitysignal
confidencebody
key_fieldskey_names     `                r0   build_candidater   o   sL   +3C=(C8UDGGFO!r((*Dggi :DV$5$:$:G#1D[$688;C8J 
**T1
a
 #
&C(VdEBB
8z#9:	C	CRVZ*
3NF63{+;SA 
3CSUX 
3wt}
3&19
3>F
36
3#-x
39CX
3 i
3 *;E
3 !,	
3 1A'	
3
 

3
 -:4
3
 BOPT
3 $
3 !+D
3 BF$D-  CB'+vPV
3 sm
3  ,D1
3D (gy#vxOa[aE9.J"-!+@VXX[]HF:FGDNKr/   c                    | j                  d       | j                  d      D ch c]  }|d   	 }}d|vr| j                  d       y y c c}w )Na~  
    CREATE TABLE IF NOT EXISTS review_runs (
      run_id TEXT PRIMARY KEY, curator_version TEXT NOT NULL, normalization_version TEXT NOT NULL,
      started_at TEXT NOT NULL, completed_at TEXT, candidate_count INTEGER NOT NULL,
      reviewer TEXT NOT NULL, status TEXT NOT NULL
    );
    CREATE TABLE IF NOT EXISTS review_candidates (
      candidate_id TEXT PRIMARY KEY, run_id TEXT NOT NULL, candidate_type TEXT NOT NULL,
      candidate_json TEXT NOT NULL, source_chunk_key TEXT NOT NULL, evidence_hash TEXT NOT NULL,
      created_at TEXT NOT NULL, review_batch INTEGER
    );
    CREATE TABLE IF NOT EXISTS review_decisions (
      decision_id TEXT PRIMARY KEY, candidate_id TEXT NOT NULL, reviewer TEXT NOT NULL,
      decision TEXT NOT NULL, reason TEXT NOT NULL, corrected_candidate_json TEXT,
      reviewed_at TEXT NOT NULL, review_duration_seconds REAL
    );
    CREATE TABLE IF NOT EXISTS review_audit (
      audit_id TEXT PRIMARY KEY, candidate_id TEXT NOT NULL, previous_state TEXT NOT NULL,
      new_state TEXT NOT NULL, action TEXT NOT NULL, actor TEXT NOT NULL,
      reason TEXT NOT NULL, created_at TEXT NOT NULL
    );
    z$PRAGMA table_info(review_candidates)r3   review_batchz=ALTER TABLE review_candidates ADD COLUMN review_batch INTEGER)executescriptexecute)dbr   columnss      r0   schemar      sX      	, "$,R!ST#s1vTGTW$


RS % Us   A
c           	        ddl m} |j                  | ||f      }	 |j                         5 }|j	                  d      j                         d   |j	                  d      j                         d   |j	                  d      j                         d   |j	                  d      j                         d   |j	                  d	      j                         d
   |j	                  d      j                         d
   d}|j	                  d      D cg c]  }t        |       }}d d d        f|j                          S c c}w # 1 sw Y   "xY w# |j                          w xY w)Nr   GraphDatabaseauthz/MATCH (n:ObsidianDocument) RETURN count(n) AS nr&   z,MATCH (n:ObsidianChunk) RETURN count(n) AS nz'MATCH (n:Episodic) RETURN count(n) AS nz%MATCH (n:Entity) RETURN count(n) AS nz7CALL db.labels() YIELD label RETURN collect(label) AS xr=   z5SHOW CONSTRAINTS YIELD name RETURN collect(name) AS x)	documentschunksepisodicentitylabelsconstraintsaO  MATCH (d:ObsidianDocument)-[:HAS_CHUNK]->(c:ObsidianChunk)
              RETURN d.relative_path AS path,d.import_key AS document_import_key,d.content_hash AS content_hash,
              c.chunk_key AS chunk_key,c.chunk_index AS chunk_index,c.heading AS heading,c.text AS text,c.text_hash AS text_hash
              ORDER BY c.chunk_key)neo4jr   driversessionrunsinglerS   close)	uriuserpasswordr   r  r"   	inventoryr=   rowss	            r0   
fetch_rowsr     sD   #!!#T8,<!=F^^ 	(UU#TU\\^_bc%% NOVVXY\]EE"KLSSUVYZ%% GHOOQRUV%% YZaacdgh uu%\]ddfgjkI &'UU ,& &' (DG (D (	( $(	( 	( 	s5   E CD?
D:D?E :D??EE Ec                R   ddl m} |j                  | ||f      }	 |j                         5 }|j	                  d|      D cg c]  }t        |       c}cd d d        |j                          S c c}w # 1 sw Y   nxY w	 |j                          y # |j                          w xY w)Nr   r   r   a  MATCH (d:ObsidianDocument)-[:HAS_CHUNK]->(c:ObsidianChunk)
              WHERE c.chunk_key IN $keys
              RETURN d.relative_path AS path,d.import_key AS document_import_key,d.content_hash AS content_hash,
              c.chunk_key AS chunk_key,c.chunk_index AS chunk_index,c.heading AS heading,c.text AS text,c.text_hash AS text_hash
              ORDER BY d.import_key,c.chunk_index)keysr  r   r  r	  r
  rS   r  )r  r  r  r  r   r  r"   r=   s           r0   fetch_source_rowsr     s    #!!#T8,<!=F^^ 	B%&UU ,5 <@	 &+ &A BDG B	B 	B 	B	B 	B 	B 	4   B A6A1A6	B 1A66A?;B B&c                   i }| D ]n  }|j                  |d   t        |j                  dd      |      t        |j                  dd      |      |j                  dd      fg       j                  |       p | D ]x  }g g g }}}|d   t        |j                  dd      |      t        |j                  dd      |      |j                  dd      f}||   D ]  }|d   |d   k(  rt        |j                  dd      |      t        |j                  dd      |      k(  }	|j                  d	      |j                  d	      k(  }
|j                  d
      |j                  d
      k(  }|	r|
r|r|j                  |d          |j                  |d          |d   dk7  s|	r)|
r'|j                  d
      s|j                  d
      s|r|j                  |d           ||d<   ||d<   ||d<   d|d<   { y )Nr   r   r`   r   r   rI   r   r   r   r   rm   possible_duplicatespossible_similarpossible_conflictszsame type+normalized subject/predicate+authority; unknown time overlaps; object/polarity/modal difference is only a conflict candidate; DocumentVersion excludedcomparison_rule)
setdefaultr   r   append)
candidatesr   groupsr   
duplicatessimilar	conflictsckeyothersame_objectsame_polaritysame_modalitys               r0   comparison_metadatar)     s2   DFF y1-.	!%%	2:NPU0V$QUU;%;UCQUUK\^gEhjkm	oououvwoxy  B)+RYG
"#YquuY/CU%K!%%R0%8!%%@QS\:]_D\ 
	<E^$.(998#AEE(B$7?9UYYW_acMdfkCllKEE*-:1FFMEE*-:1FFM}!!%"78u^45%&*;;[Xejkjojopzj{  AF  AJ  AJ  KU  AV  _l$$U>%:;
	< $.
  '
"+
  B
%Br/   c                   t        j                  | j                        }	 t        |       |j	                  d      D cg c]  }t        j                  |d          }}t        |      dk7  rt        dt        |             | j                  r!| j                  rt        j                  d      st        d      t        | j                  | j                  t        j                  d   |D cg c]  }|d   	 c}      }|D ci c]  }|d   |
 }}|D ]`  }|j                  |d         }|s|j!                  t#        |             |j!                  t%        |j                  d	      xs d
             b t'        |t        j                  t)        | j*                        j-                                      dD 	ci c]  }	|	|D cg c]  }|d   |	k(  s| c} }
}	}g }|j/                  |
d   d d        |j/                  |
d   d d        |j/                  |
d   d d        t1        |
d   d       }|j/                  |d d        |D ch c]  }|d   	 }}|D ]?  }t        |      dk\  r n/|d   |vs|j3                  |       |j5                  |d          A |d d D ch c]  }|d   	 c}|j	                  d       |D ]?  }|d   v rdnd }||d<   |j	                  dt        j6                  |d      ||d   f       A |j9                          g d}t;        |D cg c]  }|d   v s| c}d      D ]  \  }}|d| d|d    d|d    d d!|d"    d#|d$    d#|d%    d&|j                  d'       d(|j                  d)       d d*|j                  d+       d,|j                  d-       d.|j                  d/       d0|d1    d2|d    d3|j                  d4       d d5|d6   j=                  t?        d      d7       d d8d9jA                  |j                  d:g             xs d; d<d9jA                  |j                  d=g             xs d; d>d
gz  }! t)        | jB                        jE                  d?jA                  |      d@A       dBd
dCd
dDt        |       dEt               dFd
dGd
g}t;        |d      D ]  \  }}|dH| d|d    d|d    dI|j                  dJ       dK|j                  d       d d!|d"    d#|d$    d#|d%    d*|j                  d+       dLd9jA                  |j                  dMg             xs d; dN|j                  dO       d dP|j                  d-       dQ|j                  d/       dR|d1    d(|d    d 	dSt        |j                  d:g              dTt        |j                  d=g              d
gz  } t)        | jF                        jE                  d?jA                  |      d@A       tI        t        j6                  dt              |
D ci c]  tK        fdU|D               c}| j                  | jB                  dVddWX             	 |jM                          yc c}w c c}w c c}w c c}w c c}}	w c c}w c c}w c c}w c c}w # |jM                          w xY w)YNzBSELECT candidate_json FROM review_candidates ORDER BY candidate_idr   (   z.Erwartet wurden 40 Pilotkandidaten, gefunden: NEO4J_PASSWORDua   Für Evidence-/Zeit-Reconciliation müssen NEO4J_URI, NEO4J_USER und NEO4J_PASSWORD gesetzt sein.r   r   rX   r`   )rh   r~   rv   rm   r   rv   r3   rm   r~      rh   c                f    | j                  dd       t        | j                  d             | d   fS )Nr   Fr  r   )r   rW   )r   s    r0   <lambda>z&prepare_review_batch.<locals>.<lambda>   sZ    aeeL`bgFhBhnrstsxsx  zN  tO  oP  kP  RS  Tb  Rc  Bd r/   )keyr   
   z.UPDATE review_candidates SET review_batch=NULLr   zQUPDATE review_candidates SET candidate_json=?,review_batch=? WHERE candidate_id=?Fensure_ascii)z# Review Batch 1r`   Status: `prepared_unreviewed`r`   zXNur lokale Reviewdaten; keine fachlichen Entscheidungen und keine Neo4j-Schreibfreigabe.r`   z## . - Typ: ``- Aussage: r    / r   r      - Modalität/Polarität: `r   ` / `r   z	- Zeit: `rL   u   `; Evidence-Länge: r   u    Zeichen; gekürzt: r   - Quelle: `r   z
`; Chunk `z`; Heading `r   - Evidence: `r    u   - mögliche Duplikate: , r  keineu   - mögliche Konflikte: r  u>   - Offener Prüfpunkt: fachliche Entscheidung durch den Nutzer.r   utf-8encodingu1   # Knowledge-Curator Review-Pilot – aktualisiertr4  zKandidaten: z; Review-Batch 1: z); automatische Wahrheitsentscheidungen: 0u   ## Kandidatenübersicht### z`; Status: `r   z`; review_batch: `z`; erkannt: `rK   u   `; Review nötig: `rN   z- Evidence: u    Zeichen; gekürzt: `z`; Quelle: `z- Duplikate: u   ; mögliche Konflikte: c              3  >   K   | ]  }|d    v s|d   k(    yw)r   r   Nr.   )r<   r   
chosen_idsr=   s     r0   r>   z'prepare_review_batch.<locals>.<genexpr>$  s+     *uUVWeUfjtUt1-=+>!+C*us   )r   selectedtypesr   report   r3  indent)'sqlite3connectr   r   r   jsonloadsr   
SystemExitr  r  osgetenvr  environr   updater   r^   r)  r   r   	read_textrO   sortedr  adddumpscommit	enumeratereplacechrrV   batch_report
write_textrI  printsumr  )argsr   r=   r  r   source_rowsr   source_by_keysourcer   by_typechosenclaimsusedbatchlinesifullrF  s     `               @r0   prepare_review_batchrn     s3   		!B=r
*,**5y*z{Q

1Q4 {{t9?McRVi[YZZxxtyy		:J0K  A  B  B'$))RZZHX=Y{  \Avw\]^p\q  \A  B4?@q;*@@ 	]A"&&q);'<=F&)*AHH\&**VBTBZXZ5[,\	] 	D$**T$**-=-G-G-I"JK T\  ]C3DGqA.>,?3,FGG  ]  ]g./34g/0!45go.r23 01  8d  efRaj!+12a.!22 	\A6{b % ,fmmA.>>IZ@[	\ 28=Aa'=



CD 	VA>*j8AdE %AnJJj

1595!NBSTV	V
 			q$RQ!N2Cz2QqRTUV 		\DAqA3b>!2 34CSAT@UUV6W#AiL>Q{^4DC(}U21553D2EU155Q[K\J]]^_!!%%(A"B!CCWXYX]X]^oXpWq  rF  GH  GL  GL  Ma  Gb  Fc  d#Ao$6#7z!DVBWAXXdefejejkteudvvwx%a&8&@&@R#&N%OqQ/		!%%@UWY:Z0[0f_f/gh/		!%%@TVX:Y0Z0e^e/fgVXZ\ \E		\ 	T**499U+;g*NCRIhjls4yk);C
O;LLuvxz)2/ dA& 	ODAqtA3b>!2 34CSAT@UUabcbgbghybza{  |N  OP  OT  OT  Uc  Od  Ne  ef  7g"1Y<.AkN3C3q{mT '@!A B-PTPYPYZ[Z_Z_`uwyZzP{  QG  @G  PH  H[  \]  \a  \a  bu  \v  [w  wx  y#AEE*;$<#==RSTSXSXYmSnRoo{|}  N  }O  |P  PU  VW  Xj  Vk  Ul  lm  n$S/Db)I%J$KKbcfghglgl  nB  DF  hG  dH  cI  J  LN	O OD	O 	T[[$$TYYt_w$Gdjj!Z-4$6() %&s*uT*u'u$u $6=AWWPTPaPacqv  @AB 	C 

w |
 \A@ H  ] 3 > S,$6 	
s   Z9 Z BZ9 0Z<Z9 ZZ9 2BZ9  
Z
ZZZ!A3Z9 Z% Z9 ?.Z9 -Z*9A5Z9 .Z/;Z/?K7Z9 6Z4&Z9 Z9 ZZ9 9[c                R   g }| D ]%  }t        |d|      }|s|j                  ||f       ' t        D ci c]  }|g  }}|D ]9  }t        |d   d         |v s|t        |d   d            j                  |       ; g }	t	               dD ]C  t        fd|D        d       }|s|	j                  |       j                  |d   d          E t        D ]I  }
||
   s	||
   d   d   d   vs||
   d   }|	j                  |       j                  |d   d          K t        |      D cg c]  \  }}|dz  dk(  s|d   d   vs| c}}D ]:  }t        |	      |k\  r n*|	j                  |       j                  |d   d          < |D ]E  }t        |	      |k\  r n5|d   d   vs|	j                  |       j                  |d   d          G t        |      |t        |	      t        fd|	D              t        |	D ch c]  }t        |d   d          c}      t        D cg c]&  }||	D ch c]  }t        |d   d          c}vs%|( c}}d	}|	D cg c]  }|d
   d|d   iz   c}|fS c c}w c c}}w c c}w c c}w c c}}w c c}w )N	selectionr   r5   )rv   r~   rm   rh   c              3  P   K   | ]  }|d    d   k(  s|d   d   vs|  yw)r3   r   r   r   Nr.   )r<   r#   ri  wanteds     r0   r>   z$select_population.<locals>.<genexpr>8  s7     o1AaD1A,Bf,LQRSTQUVaQbjnQnQos   &
&&r      c              3  ,   K   | ]  }|v sd   yw)r3   Nr.   )r<   r#   
systematics     r0   r>   z$select_population.<locals>.<genexpr>I  s     Ck![\`j[jACks   	)eligible_with_candidatetargetrG  systematic_selectedareas_presentareas_missingr3   _row)r   r  
AREA_NAMESr6   setnextrX  r[  r   ra  rW  )r  r   rw  eligibler   	candidater=   by_areapairrG  namerl  r#   methodru  ri  rr  s                 @@@r0   select_populationr  +  s   H .#Ce<	OOS),-. WaFaQRq"uFaGFa YQ G+WT$q'&/5J-K-R-RSW-XY<>H5DZ BooquvOOD!488DGK,@#AB
  [4=WT]1-a0=TI4=#DX__T%:DHHT!W[EY<Z[ '0&9m71dQUaZDQRGT_L`hlLl$mJ >x=F"EtxxQ(<=>  Bx=F"E7;t+OOD!488DGK,@#AB *-X&h-CkxCk@k%8&LatAaDL'9&LM+5ia_gBhZ[4!VCUBh9hikF ,44aAaDFAaD>!4f<<7 Gb n 'MBhi4sA   
J	6J
JJJ;
JJJ"J0J$Jc                `   dD ci c]  t        fd|D               }}d| dddddddd|d	    d
|d    d|d    d|d    dt        |       d|d    ddj                  |d          ddj                  |d         xs d dddgd |j                         D        dt        |       dddd}t	        |d      D ]o  \  }	}
|
d   j                  d d!      }|d"|	 d#|
d$    d%|
d&    d'd(|
d)    d*|
d+    d*|
d,    d-|
d.    d/|
d0    d'd1|
d2    d3|
d4    d5|
d6    d7|d d8  d'd9dgz  }q |d:dg|D cg c],  }d;|d<    d=|d>   rd?nd@ dA|dB    dC|dD    dE|dF    dC|dG    . c}z   z  }| j                  d j                  |      d z   dHI       y c c}w c c}w )JNr   c              3  .   K   | ]  }|d    k(    ywr   Nr.   r<   r   r=   s     r0   r>   zwrite_report.<locals>.<genexpr>Q  s     B!Q'(A-B   z!# Knowledge-Curator Review-Pilot r`   r4  uD   Dieser Bericht enthält Kandidaten, keine fachlichen Entscheidungen.z$## Population und Sicherheitsbestandz- ObsidianDocument: r  z- ObsidianChunk: r  z- Episodic: r  z
- Entity: r  u   - ausgewählte Kandidaten: z- systematische Stichprobe: rx  z- Bereiche: r?  ry  z!- nicht vorhandene Zielbereiche: rz  r@  z## Typenc              3  2   K   | ]  \  }}d | d|   yw)- : Nr.   )r<   kvs      r0   r>   zwrite_report.<locals>.<genexpr>[  s      HAA3b}Hs   z- needs_review: z)- automatische Wahrheitsentscheidungen: 0z## Kandidatenr3   r   r   r>  rD  r5  r   r6  r   r7  r8  r   r9  r   r   r:  r   r;  r   r<  r   u   ` · Chunk `r   u   ` · Index r   r=  r   u7   - Entscheidung: offen; fachliche Prüfung erforderlich.u   ## Kontrollfäller  idr  passed	bestandenfehlgeschlagenz; erwartet=expected_typer2   expected_modalityu   , tatsächlich=actual_typeactual_modalityrA  rB  )ra  r   rV   itemsr[  r\  r_  )r5   r   r  r  r  controlsr=   countsrk  rl  r   r(   s         `     r0   write_reportr  O  sG    `a BzBBB aF a092?^`bSUW3R#Ik$:#;<@QR[\dReQf>gIj123z)HBUAV5W*3z?*;<@\]cdy]z\{>|DIIf_&=>?@06/;R1S1^W^0_`bd
" IH
"  J01
" 4_
" ac
" 
" !
"E *a( m1o&&tS1D2a/01Xa@P>Q=RRS3T)~S;0@AhK=Q.q}oU1Z=/QRS/ 23<BT@U?VVabcdqbrast!!DS'!,.gik	m 	mm 
!2&  go  *p  bcBqwir8+Zj9kkvwx  zI  xJ  wK  KL  MN  Ob  Mc  Ld  ds  tu  vC  tD  sE  EF  GH  IZ  G[  F\  +]  *p  p  pEOODIIe$t+gO>+a( *ps   F&1F+c                n   | j                   r!| j                  rt        j                  d      st	        d      t        j                  t        | j                        j                               }t        | j                   | j                  t        j                  d         \  }}dt        j                  t        j                        j!                  d      z   }t#        ||t%        dt'        d| j(                                    \  }}g }|D ]@  }|j+                  dd        ||d<   t-        ||d	   |d
         |d<   |j/                  |       B g }	g d}
|
D ]?  \  }}}}t1        d|d      \  }}}}}|	j/                  |||||||||k(  xr ||k(  d       A t        | j2                        }|j4                  j7                  dd       t9        j:                  |      }	 t=        |       |j?                  d|t@        tB        t               t               tE        |      ddf       |D ]D  }|j?                  d|d   ||d
   t        jF                  |d      |d	   |d   t               f       F |jI                          |jK                          tM        t        | jN                        |||||	       tQ        t        jF                  |d||tE        |      dD ci c]  tS        fd|D               c}tU        |      | jN                  dd	dd             y# |jK                          w xY wc c}w )Nr,  uZ   Fehlende Neo4j-Credentials: NEO4J_URI, NEO4J_USER und NEO4J_PASSWORD müssen gesetzt sein.z
kc-review-z%Y%m%dT%H%M%SZ   2   r{  r   r   r   r   )
)no_claimu   Nur eine Überschrift.NN)questionu   Frage: Läuft Dienst X?NN)quoteu#   Zitat: "Dienst X läuft produktiv."rh   ri   )negationu#   Dienst X läuft nicht auf Server Y.rh   r   )wishu.   Ich möchte, dass Dienst X später aktiv wird.NN)planzDas Team plant den Import.rh   r   )rejected_planzDer Plan wurde verworfen.rh   ry   )rs   u    Der Dienst wurde zurückgerollt.rv   rt   )
historicalzIm Mai 2026 war Dienst X aktiv.rh   ru   )version_no_conflictz*Businessplan Version 3 wurde dokumentiert.rm   Nz
control.md)r5   rX   )r  rX   r  r  r  r  r   r  T)parentsexist_okz0INSERT INTO review_runs VALUES (?,?,?,?,?,?,?,?)
unassignedprepared_unreviewedzINSERT INTO review_candidates(candidate_id,run_id,candidate_type,candidate_json,source_chunk_key,evidence_hash,created_at,review_batch) VALUES (?,?,?,?,?,?,?,NULL)Fr2  r   r   c              3  .   K   | ]  }|d    k(    ywr  r.   r  s     r0   r>   zrun_pilot.<locals>.<genexpr>  s     0^a3C1D1I0^r  )	r   read_only_neo4jr  rp  candidate_countcandidate_types	review_dbrI  r   rJ  rK  r   )+r  r  rR  rS  rQ  rO  rP  r   r   rV  r  rT  r   r+   r   r,   strftimer  maxr   limitpopr
   r  r   r   parentmkdirrM  rN  r   r   r   r	   r   rY  rZ  r  r  rI  r`  ra  str)rb  r   r  r  r   rG  r  r  itemr  control_casescidrX   r  r  r  r  _r   dbpathr   r   r=   s                         `r0   	run_pilotr  i  s   88499BII6F,GuvvJJtDJJ'1134E 499bjjAQ6RSOItHLL6??@PQQF(uc"c"djj>Q6RSHfJ  X%fd3E.FM]H^_^$	 
 HM 8E k3T="33;\[_<`3a0_aDsD=.?P[,;T#.-#?#hOWhDhj 	kk $'']F
MMt4		 B
r



EP_(#%JWlHn 	o 	3AJJ  }  @A  BP  @Q  SY)*DJJqu,MqQcOd)352 3	3 			

dkk"FIvz8T	$**4i#)c*o3{*}./ +,S0^S]0^-^*^ *}#&v;$++Qf	h
 "!- .  	
*}s   !BL L2L/c                R   ddl m} |j                  | ||f      }	 |j                         5 }|j	                  d|      D cg c]  }t        |       c}cd d d        |j                          S c c}w # 1 sw Y   nxY w	 |j                          y # |j                          w xY w)Nr   r   r   zMATCH (d:ObsidianDocument)-[:HAS_CHUNK]->(c:ObsidianChunk)
              WHERE d.import_key=$import_key RETURN c.chunk_index AS chunk_index,c.heading AS heading,c.text AS text
              ORDER BY c.chunk_index)
import_keyr  )r  r  r  r  r   r  r"   r=   s           r0   fetch_document_contextr    s    #!!#T8,<!=F^^ 	A%&UU ,(4> &+ &@ ADG A	A 	A
 		A	A 	A 	A
 	r  c                   t        j                  |       }|rdnd}|j                  d|z   dz         j                         }t	        |d      D ]  \  }\  }}	t        j                  |	      }
t        j                         }t        d| dt        |       d|
d	           t        t        j                  d
D ci c]  }||
j                  |       c}dd             t        d       t        d      j                         j                         }|dv r|r|rt!        j"                  d      st        d       n|dk(  rIt%        ||t         j&                  d   |
d   g      }t        |r|d   j                  d      ndxs d       nbt)        ||t         j&                  d   |
d         }|D ];  }t        d|d    d|j                  d       d|j                  d      xs d        = t        d      j                         j                         }|dv r|dk(  r n7|dk(  s|st*        j                  ||      }|t,        vrt        d        t        d!      j                         }t        d"      j                         xs d#}d }|j/                  d$      rt        d%      j                         xs d }t1        t        j                         |z
  d&      }|j                  d't3        |t5                     |||||t5               |f       |j                  d(t3        ||t5                     |d)|d*||t5               f       |j7                          	 |j9                          yc c}w )+Nr`   z AND review_batch=1zSELECT candidate_id,candidate_json FROM review_candidates WHERE candidate_id NOT IN (SELECT candidate_id FROM review_decisions)z ORDER BY candidate_idr3   z
[r2   z] r   )r   r   r   r   r   r   rK   rL   rM   rN   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  FrJ  rK  ud   Befehl: a/r/c/d/t/s/p/o/m/n/z/e Entscheidung, v Evidence, x Dokumentkontext, k überspringen, q Endez> >   r  r=   r,  u*   Für v/x fehlen sichere Neo4j-Credentials.r  r   r   rX   zEvidence nicht gefunden.r   z
--- Chunk r   z | r   z ---
qr  u   Ungültig; übersprungen.u   Begründung: z
Reviewer: 	unbekanntwrong_z*Korrigierte Kandidaten-JSON (leer=keine):    z5INSERT INTO review_decisions VALUES (?,?,?,?,?,?,?,?)z1INSERT INTO review_audit VALUES (?,?,?,?,?,?,?,?)r   human_review)rM  rN  r   fetchallr[  rO  rP  time	monotonicr`  r   rY  r   inputr:   rH   rR  rS  r  rT  r  DECISION_CODES	DECISIONSr   roundr
   r+   rZ  r  )r  show_allr  r  r   batch_clauser  numberr   rawr   startedr  decisionre  contextr  reasonreviewer	correcteddurations                        r0   
review_clir    sb   		 B!2'<L::  X  [g  g  jB  B  C  L  L  ND'0q'9  ##sJJsO.."F81SYKr!N*;)<=>djj  0}  ~!!QUU1X+  ~  MR  [\  ]  	^tu;$$&//1*$d"))4D*EBCS*3bjjAQ6RUVWiUjTklvay}}V,<V][]^0dBJJGW<XZ[\xZyz# vDLm)<(=S)AT@UU[\`\d\dek\l\rpr[stuvT{((*335H *$ s?Es?(H!%%h99$e,G&H('--/&,,.=+	x(JKQQS[W[I)G3Q7


JVT`bebgMhjvh	35(ML 	M


FP\^fhkhmInp|"HnhPSPUIW 	X
		A B HHJq; ~s   8M(c                    t        j                         } | j                  dd       | j                  dd       | j                  ddd       | j                  dd       | j                  d	t        j                  d
             | j                  dt        j                  d             | j                  dt        t        dz               | j                  dt        d       | j                  dt        t        dz               | j                  dt        t        dz               | j                  dt        t        dz               | j                         }|j                  rt        |      S |j                  r?t        t        |j                        |j                  |j                   |j"                        S |j$                  st'        d      t)        |      S )Nz--review-pilot
store_true)actionz--reviewz--allz7im Review alle Kandidaten statt review_batch=1 anzeigen)r  helpz--prepare-batchz--uri	NEO4J_URI)defaultz--user
NEO4J_USERz--rulesz
rules.jsonz--limitr+  )typer  z--dbzreview_pilot.dbz--reportzreview_pilot_report.mdz--batch-reportzreview_batch_1.mdz&Verwende --review-pilot oder --review.)argparseArgumentParseradd_argumentrR  rS  r  ROOTint
parse_argsprepare_batchrn  reviewr  r   r   allr  r  review_pilotrQ  r  )aprb  s     r0   mainr    s   		 	 	"BOO$\O:OOJ|O4OOGL7pOqOO%lO;OOGRYY{%;O<booh`b`i`ijv`wo>xOOIs4,+>'?O@"//R[beoq/BrOOFC/@(@$AOBBOOT^hklp  tL  mL  iMO  ENOO$c$9L2L.MON==?D#D)){{$tww-488TYYGGJ/W$XXT?r/   __main__)returnr  )r5   r  r  r  )rX   r  r  dict[str, Any])r   r  r  z,tuple[str | None, str | None, str, str, str])r   r  r  r  )r   r  r   r  r   r  r  zdict[str, Any] | None)r   zsqlite3.Connectionr  None)r  r  r  r  r  r  r  z+tuple[dict[str, Any], list[dict[str, Any]]])
r  r  r  r  r  r  r  z	list[str]r  list[dict[str, Any]])r  r  r   r  r  r  )rb  zargparse.Namespacer  r  )r  r  r   r  rw  r  r  z+tuple[list[dict[str, Any]], dict[str, Any]])r5   r   r   r  r  r  r  r  r  r  r  r  r  r  )
r  r  r  r  r  r  r  r  r  r  )
r  r   r  rW   r  
str | Noner  r  r  r  )r  r  )4__doc__
__future__r   r  r   rO  rR  r@   rM  sysr  r   r   pathlibr   typingr   __file__resolver  r  r5   insertr  curatorr   r	   r
   r   r   r|  r  r  r+   r6   r^   r   r   r   r   r  r  r)  rn  r  r  r  r  r  r  __name__rQ  r.   r/   r0   <module>r     s1  
 #    	 	  
  '  H~&& 3t9 % %K
X	 ,*CW"O(~DT'lAXZ2!M"GB< @T8,B4?D!=H?1?=Q?VZ?45p	%P& zDF!33r/   