
    `jL                       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
mZ ddlmZmZ ddlmZ ddlmZ  ee      j'                         j(                  ZdZd	Zh d
Zh dZh dZd"dZd#dZd$dZd%dZd&d'dZd(dZ d)dZ!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(d0dZ)d1dZ*d2dZ+d3d Z,e-d!k(  r e. e,             y)4zKnowledge Curator 0.2.0: deterministic, strictly read-only dry-run.

This module intentionally has no Neo4j write transaction and no persistence
other than stdout. Credentials are read from the environment only.
    )annotationsN)defaultdict)datetimetimezone)Path)Anyzknowledge-curator-ro/0.3.0z
kc-norm-v3>   failedtestedassumedplannedproposedreported	confirmed	withdrawnrecommendedrolled_backfactual_currentfactual_historical>   mixedunknownnegativepositive>	   DocumentScopeKnowledgeRuleCandidateGroupKnowledgeClaimKnowledgeEventDocumentVersionFactStatusModelDocumentMetadataKnowledgeRuleGroupc                p   t        j                  d|       j                         j                         }t	        j
                  dd|      }t	        j
                  dd|      }t	        j
                  dd|      }t	        j
                  dd	|t        j                  
      }t	        j
                  dd	|      j                         }|j                  di       j                         D ]O  \  }}t	        j
                  dt	        j                  |j                                d|j                         |      }Q |S )NNFKCz\bv\s*(\d+(?:\.\d+)*)\bz
version \1z'\b(\d{1,2})[./-](\d{1,2})[./-](\d{4})\bz\3-\2-\1z[\u2010-\u2015\-]+-z[^\w\s./:-] )flagsz\s+synonymsz\b)
unicodedata	normalizecasefoldstripresubUNICODEgetitemsescape)valuerulestextsourcetargets        */opt/struktur/knowledge-curator/curator.pyr)   r)   "   s      /88:@@BD66,mTBD66<k4PD66'd3D66.#t2::>D66&#t$**,D))J399; WvvBIIfoo&789<foo>OQUVWK    c                     t        j                  dj                  |       j                  d            j	                         S )N|zutf-8)hashlibsha256joinencode	hexdigest)partss    r7   digestrA   .   s-    >>#((5/009:DDFFr8   c                p   | d   xs d}| d   | d   | d   | j                  d      xs1 t        j                  |j                               j	                         |dt        |      dt        j                  |j                               j	                         | j                  d	      | d
   dt        t        dS )Nr4    document_import_keycontent_hash	chunk_key	text_hashr   analyzed_chunk_textheadingpathzkc-rules-v2)source_document_import_keysource_content_hashsource_chunk_keysource_text_hashevidence_textevidence_start_offsetevidence_end_offsetevidence_offset_basisevidence_hashrI   relative_pathextraction_rule_versioncurator_versionnormalization_version)r/   r;   r<   r>   r?   lenCURATOR_VERSIONNORMALIZATION_VERSION)rowr4   s     r7   evidencer\   2   s    v;"D&)*?&@">2,GGK0]GNN4;;=4Q4[4[4]!""4y!6 6@@B779%V#0*!6 r8   c                   |  d| j                         }dD ]+  }||v st        d |d   D              }|d   |d   d| fc S  |d   D ]9  }|d   dk(  r|d	   D ]&  }|j                         |v s|d   |d   d| fc c S  ; y
)N
)   unbestätigt
unverifieduser_stated	vermutungc              3  2   K   | ]  }|d    dk(  s|  yw)nameunverified_claimN .0xs     r7   	<genexpr>z!source_quality.<locals>.<genexpr>L   s     ^aaiK]>]^s   source_classesrd   qualityzsignal:re   signals)r   r   z$no deterministic source-class signal)r*   next)rJ   r4   r3   lowmarkeritemsignals          r7   source_qualityrs   F   s    F"TF

$
$
&C M ES=^5)9#:^^D<iGF82DDDE &' I<--9o 	IF C'F|T)_x6HHH	II @r8   c                     | rdnd|| xs dddS )Nneeds_review	candidatez0Keine automatische autoritative Statuszuweisung.T)statusproposed_statusproposed_reasonrequires_human_approvalrf   )reasonr   s     r7   status_proposalr|   W   s"    $*.#!W%W#'	 r8   c                |    t         | d   | d   | d   | d   | d   | d   | d   | d   | d	   g
}t        fd
|D         S )N
claim_typesubject	predicateobjectobject_typemodalitypolarityauthority_scopetemporal_scopec              3  6   K   | ]  }t        |        y wN)r)   )rh   ri   r3   s     r7   rj   zclaim_key.<locals>.<genexpr>e   s     8AIa'8s   )rZ   rA   )claimr3   fieldss    ` r7   	claim_keyr   `   sc    #U<%8%	:JK %/53GJz!2E:K4L$%'F 8899r8   c                "    ||ddd d d d d d d d|dS )Ng        r`   r   )source_typers   claim_confidenceverification_stateasserted_atobserved_at
valid_fromvalid_torecorded_atverified_atsuperseded_atr   source_signalrf   )r[   r   rl   rr   s       r7   	base_metar   h   s,    &' #<DT$!i#% %r8   r   )r   r   r   object_valuer   c          
        t        | d   | d   |      \  }
}}dd|xs |d   |xs |d   |xs |d   d|||d	t        | |
||      |	d	d
t        |       d|d   i}t        ||      |d<   |j	                  t        d             |S )NrJ   r4   r   state_or_relationr   r   r   )	candidate_typer~   r   r   r   r   r   r   r   z9Dry-Run-Kandidat; keine automatische Wahrheitseinstufung.)r   decision_reasonextraction_ruleruler   z5Human-Review vor jeder autoritativen Statuszuweisung.)rs   r   r\   r   updater|   )r[   r   r3   r   r   r   r   r   r   r   strl   rr   cs                 r7   
make_claimr   q   s     )Vc&k5IB+;N.tIY=[${J[14>&8~	; S"gv.		; DSW	; C=	; ,T&\	;A q%(AkNHH_TUVHr8   c                :   t        | d   | d   |      \  }}}dd|d   |d   |d   ddd d dd|||d	t        |       d
|d   i}t        t        dt	        |d   |      t	        |d   |      t	        |d   |            |d<   |j                  t        d             |S )NrJ   r4   r   normative_policyr   r   r   r   )r   	rule_typer   r   r   	authorityr   r   r   approval_stateversionr   rs   r   r   r   rule_keyuK   Normative Regel; Autorität und Freigabe müssen manuell bestätigt werden.)rs   r\   rA   rZ   r)   r   r|   )r[   r   r3   r   rl   rr   bodys          r7   	make_ruler      s    (Vc&k5IB-<NIT+5F8n9($'I6> sm> /V>D 3_iPTU^P_afFg(k):EBIdS[n^cDdfDKK mnoKr8   c                    dd|d   ddd ||dt        |       d|d   i}t        t        dt        |d   |      |d	   t        |d
   |      t        |d   |            |d<   |j	                  t        d             |S )Nr   provider_replacementr   zdeepseek/deepseek-chatzopenrouter/auto)r   
event_typer   from_object	to_objectevent_atold_state_claim_keynew_state_claim_keyr   r   r   r   r   	event_keyuI   Änderungsereignis; zeitliche und autoritative Bestätigung erforderlich.r\   rA   rZ   r)   r   r|   )r[   r   r3   old_keynew_keyr   s         r7   
make_eventr      s    .>TI7O*#*7> sm	> /V	>D
 46F	RVW`RachHi#L19T-=PRW3X(k):EBDD 	KK klmKr8   c           	         |d   }d|d   |d | d   d ddt        |       d|d   i}t        t        dt        |d	   |      t        ||      | d         |d
<   |j	                  t        d             |S )Nr   r   r   rE   r   )r   document_identityr   revision_daterE   previous_versionrevision_relationr   r   r   document_version_keyuI   Dokumentrevision; kein Wissenskonflikt ohne widersprüchliche Fachclaims.r   )r[   r   r3   r   r   s        r7   make_versionr      s    8nG/d9os>GZ $9-HPQT- tF|-D $**?AR+4T:M5NPU+VXabikpXq+.~+>$@D	  	KK klmKr8   c                   |d   }|dv rt        | ||      gS |dk(  rt        | ||      gS |dk(  rOt        | i |d|d   i|ddd	|d   d
d	      }t        | ||ddd|d   dd	      }||t        | |||d   |d         gS |dk(  rt        | ||dddd      gS |dk(  rt        | ||dddd      gS t        | ||dd      gS )Nr   >   human_review_gatedirect_system_evidenceversion_headingexplicit_replacementr   r   r   r   used_provider
historicalr   )r   r   r   r   r   r   r   uses_providerr   historical_decisionz2026-05)r   r   r   r   explicit_user_stated_factr   )r   r   )r   r   r   r   )r[   r   r3   kindoldnews         r7   candidates_forr      s>   <D>>#tU+,,  S$.//%%AAxiA5"6#2i(4iQ dE4EPZ#2h(19N S*S$s;7G[IYZ[[$$3e6JU_*3YP Q 	Q**3ej:*3YP Q 	QsD%*zRSSr8   c                "   | j                         5 }|j                  d      j                         }|j                  d      j                         }|j                  d      j                         d   }|j                  d      j                         d   }i }dD ]+  }|j                  d| d      j                         d	   ||<   - |j                  d
|      D 	cg c]  }	t	        |	       }
}	d d d        
dS c c}	w # 1 sw Y   xY w)Nz8CALL db.labels() YIELD label RETURN label ORDER BY labelzdCALL db.relationshipTypes() YIELD relationshipType RETURN relationshipType ORDER BY relationshipTypez/MATCH (n:ObsidianDocument) RETURN count(n) AS nnz,MATCH (n:ObsidianChunk) RETURN count(n) AS n)ObsidianDocumentObsidianChunkz	MATCH (n:z8) UNWIND keys(n) AS k RETURN collect(distinct k) AS keyskeysaI  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)r   )labelsrelationship_types	documentschunks
propertiesrows)sessionrundatasingledict)driverr   sr   relsdocsr   propslabelrr   s              r7   read_inventoryr      s:   		 MQQRWWYuu{|  B  B  DuuFGNNPQTUEFMMOPST: 	E559UG3k!lmttvw}~E%L	!" (@ GK "' "L MAQ M MM DtW]/ /	MM Ms   C
DD -D DDc                   | j                         }|j                         t        t        j                  d|            }| xs9 |d d j                         xs$ |j                  d      xs |j                  d      }|sdv s|sd| v sj                  d      rd d d dd	d
S dv sdv sdv sdv sdv sdv rd\  }}nt        fddD              rddv rdnd}}nvdvrdv r
dv rd\  }}ndd}dv sd| v rd}nWd v sd!v rd}nLd"v sd#v rd$}nAt        fd%d&D              rd'}n*d(v sd)v rd*}nd+v rd,}nd-v sd.v rd/}nd0v sd1v rd}nd2}t        j                  d3      rd4nd5}d6}||||d7d
S )8N#{1,6}\s+[^\n]+   u   t —zdian-)(u   —...zohne aussage?)zfrage:z	question:Fnoner   r   r   reviewconflictzpolicy:mussz
darf nichtz	darf erstznur nachz
nie vorher)r   Nc              3  &   K   | ]  }|v  
 y wr   rf   rh   ri   ro   s     r7   rj   z classify_test.<locals>.<genexpr>   s     s!Q#Xs   )z wurde durch u    wurde zurückgerolltz wurde aktualisiertz wurde ersetztr   u   zurückgerolltr   r   	behauptetr   businessplan)r   Nr   zzitat:"r   r_   r`   	verworfenu   zurückgezogenr   c              3  &   K   | ]  }|v  
 y wr   rf   r   s     r7   rj   z classify_test.<locals>.<genexpr>   s     KacKr   )plantzsoll solltegeplantr   u   könnte
vielleichtr   getestetr
   u
   bestätigt	produktivr   zwar 
historischr   z\b(nicht|kein|keine|nie)\br   r   Tmanual)
r+   r*   boolr,   	fullmatchislower
startswithendswithanysearch)	r4   rawheading_onlyfragmenttypr   r   r   ro   s	           @r7   classify_testr     s   
**,C
,,.C%7=>L 53r7??, 5?Q0R 5<< 34 ~,C4K3>>ZqKr"&DdV[ioppSFcM\S-@3*"3|s7J-X	srs	s(;Ks;R-XlX	C	I$439N/Xs?cTkj8s"lc&9j8C#3s#:{HK#JKKXaX#!4h38S K3$6;s]lc1>R8*hYY'DcJzPZHF!xXY_muvvr8   c                   | j                  d      }t        | j                  d      xs d      j                         g }|dv r=t        | j                  d      xs d      j                         s|j                  d       t	        j
                  d      r|j                  d       d	d
 j                         sj                  d      r|j                  d       | j                  d      dv r|j                  d       t        | j                  d      t              r3| d   j                         j                  d      r|j                  d       |t        vr|j                  d       | j                  d      dk(  r%t        fddD              r|j                  d       | j                  d      dk(  r#dj                         v r|j                  d       || d<   |rdn| j                  dd      | d<   d|v | d <   | S )!zGReturn deterministic quality flags; never changes a candidate silently.r   rO   rC   >   r   r   r   r   empty_subjectr   r  Nr   r   fragment_at_startr   )NrC   empty_object)u   …r   truncated_objectunknown_typer   r   c              3  B   K   | ]  }|j                         v   y wr   )r*   )rh   ri   r4   s     r7   rj   z+validate_candidate_shape.<locals>.<genexpr>  s#       >dWXa4==?>R  >ds   )r  zaus sessions rekonstruiertnicht live verifizierthistorical_marked_currentr   verifiedr  unverified_marked_verifiedquality_issues
incompleteextraction_statecompletesubject_needs_review)r/   strr+   appendr,   r  r  r  
isinstancerstripr  DOMAIN_TYPESr  r*   )rv   r  issuesr4   s      @r7   validate_candidate_shaper%     s   
--(
)Cy}}_-34::<DF
CCCPYP]P]^gPhPnlnLoLuLuLwo&	||&-n%BQxT__-?@)*}}X*,n%)--)3/Ih4G4N4N4P4Y4YZh4i()
,n%}}Z $55#  >d  ]c  >d  ;d12}})*j8=UY]YfYfYh=h23"(I4:L	N`bl@mI !(76(AI$%r8   c           	     H   t        j                  | j                               }g }|D ]G  }t        |d         |d   t	        fddD              }|j                  |d   |d   |d       I t        |      t        d |D              t        d |D              |d	S )
Nr4   expectedc              3  d   K   | ]'  }j                  |      j                  |      k(   ) y wr   )r/   )rh   kactualr'  s     r7   rj   z"run_adversarial.<locals>.<genexpr>  s,       A!VZZ]hll1o5  As   -0r   id)r+  r4   r'  r*  passedc              3  &   K   | ]	  }|d      ywr,  Nrf   rg   s     r7   rj   z"run_adversarial.<locals>.<genexpr>  s     0N80Ns   c              3  (   K   | ]
  }|d       ywr.  rf   rg   s     r7   rj   z"run_adversarial.<locals>.<genexpr>  s     ;aak/;s   )totalr,  r	   results)jsonloads	read_textr  allr   rX   sum)rJ   testsr1  rq   r,  r*  r'  s        @@r7   run_adversarialr8    s    JJt~~'(EG +tF|,
#  A?  A  Ad4j$v,H`f"(* 	+	+ \S0Ng0N-N;7;;Q Qr8   c           	        | d   }t        dt        j                         t        d| d    d| d    t        j                         t        d|d	    d
|d    d|d    t        j                         t        d| d    d| d    t        j                         d| v r7t        dt        j                  | d   dd      z   t        j                         t        dt        j                         y )Nadversarial_testsz
READ-ONLY REPORT)filezcurator=rV   z normalization=rW   zadversarial=r,  /r0  z passed; failed=r	   zautomatic_current=automatic_current_assignmentsz automatic_verified=automatic_verified_assignmentssummaryzcandidates=FT)ensure_ascii	sort_keyszAwrite_path=absent; graphiti=absent; openrouter=absent; llm=absent)printsysstderrr2  dumps)outr7  s     r7   readable_reportrG    s    #$E	
SZZ0	HS*+,OC@W<X;Y
Zadakakl	Lx)5>*::J5QY?J[
\cfcmcmn	s#BCDDXY\]}Y~X  A  HK  HR  HR  SCmdjjYeW[\\cfcmcmn	
MTWT^T^_r8   c                 
	   t        j                         } | j                  dt        j                  d             | j                  dt        j                  d             | j                  dt        t        dz               | j                  dt        t        d	z               | j                  d
d       | j                         }t        j                  t        |j                        j                               }t        t        |j                              }dt        j                   t"        j$                        j'                  d      z   t(        t*        ddd|d}|j,                  r5t/        t        j0                  |dd             t3        |       |d   sdS dS |j4                  r!|j6                  rt        j                  d      st9        d      ddlm} |d   }|j?                  |j4                  |j6                  t        j@                  d   f      }	 tC        ||D cg c]  }|d   	 c}      }	|	jE                  d      D 
ci c]  }
|
d   |

 }}
g }|D ]O  }|jG                  |d         }|d   jG                  |d         }|s1|s4|jI                  tK        |||             Q |D cg c]  }|d   dk(  s| }}tM        tN              }|D ]&  }||d    |d!   |d"   |d#   f   jQ                  |       ( g }g }|jS                         D ]  }|D ch c]  }tU        |d$   |       }}tW        |      d%kD  r0tW        |      d%k(  r"|jQ                  |D cg c]  }|d&   	 c}       tW        |      d%kD  sl|jQ                  |D cg c]  }|d&   	 c}        |jY                  |	|||tW        |      t[        d' |D              t[        d( |D              t[        d) |D              t[        d* |D              ddd+d,       t/        t        j0                  |dd             t3        |       |j]                          yc c}w c c}
w c c}w c c}w c c}w c c}w # |j]                          w xY w)-Nz--uri	NEO4J_URI)defaultz--user
NEO4J_USERz--rulesz
rules.jsonz--testszadversarial_tests.jsonz--offline-tests
store_true)actionzkc-ro-z%Y%m%dT%H%M%SZTr   )run_idrV   rW   	read_onlyr=  r>  r:  F   )r@  indentr	   NEO4J_PASSWORDuZ   Fehlende Neo4j-Credentials: NEO4J_URI, NEO4J_USER und NEO4J_PASSWORD müssen gesetzt sein.)GraphDatabase
selections)authrF   r   manual_claim_rulesr   r   r   r   r   r   r   r   r   c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nrf   rg   s     r7   rj   zmain.<locals>.<genexpr>S  s     8yef;K9LP`9`8y   c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nrf   rg   s     r7   rj   zmain.<locals>.<genexpr>T  s     7wcd:J8K8^7wrX  c              3  ,   K   | ]  }|d    dk(    yw)r   r   Nrf   rg   s     r7   rj   zmain.<locals>.<genexpr>U  s%       DFqrAFVDW[lDl  DFrX  c              3  ,   K   | ]  }|d    dk(    yw)rw   ru   Nrf   rg   s     r7   rj   zmain.<locals>.<genexpr>V  s     4kWXQx[N5R4krX  )claim_candidatesevent_candidatesrule_candidatesdocument_version_candidatesru   automatic_currentautomatic_verified)neo4j_inventory
candidatesidentical_claim_groups	conflictsr?  )/argparseArgumentParseradd_argumentosgetenvr  ROOT
parse_argsr2  r3  r   r3   r4  r8  r7  r   nowr   utcstrftimerY   rZ   offline_testsrB  rE  rG  uriuser
SystemExitneo4jrS  r   environr   popr/   extendr   r   listr   valuesr)   rX   r   r6  close)apargsr3   test_reportrF  rS  selectedr   ri   	inventoryr   bykeyall_candidates	selectionr[   r   claimsgroupsr   re  	identicalgroupobjectss                          r7   mainr  '  s   		 	 	"BOOGRYY{%;O<OOHbii&=O>OOIs4,+>'?O@OOIs42J+J'KOLOO%lO;==?DJJtDJJ'1134E!$tzz"23K%-X\\0J0S0STd0e%e.=Xm(,q=>U`bC djj5;<oc>R#H-q41488499BII6F,Guvv#\"H!!$(($))RZZHX=Y1Z![F"6H+MqAkN+MN	,5MM&,ABq;"BB! 	HI))Ik23C-.229[3IJDt%%nS$&FG		H
 ,Wq1A/BFV/V!WWT" 	hAAiL!K.!4E2FJZH[\]ddefg	h		]]_ 	SE>CDy8e4DGD5zA~#g,!"3Y5E5E_dFeZ[q~Fe5f7|a!1!152Qa1[>2Q!R	S 	

y.7i47K588yjx8y5y477whv7w4w@C  DF  wE  DF  AF144k\j4k1k67q RS 	T 	djj5;<oc>R; ,NB X EFe2Q 	st   "
Q0 ,Q
8Q0 Q6Q0 Q0 "Q0 ;Q	QAQ0 $Q!:-Q0 'Q&
3Q0 	Q0 Q+
$BQ0 Q0 0R__main__)r2   r  r3   dict[str, Any]returnr  )r@   r  r  r  )r[   r  r  r  )rJ   r  r4   r  r3   r  r  ztuple[str, int, str])ru   )r{   r  r   r  r  r  )r   r  r3   r  r  r  )
r[   r  r   r  rl   intrr   r  r  r  )r[   r  r   r  r3   r  r   r  r   r  r   r  r   
str | Noner   r  r   r  r   r  r  r  )r[   r  r   r  r3   r  r  r  )r[   r  r   r  r3   r  r   r  r   r  r  r  )r[   r  r   r  r3   r  r  zlist[dict[str, Any]])r   z	list[str]r  r  )r4   r  r  r  )rv   r  r  r  )rJ   r   r  r  )rF  r  r  None)r  r  )/__doc__
__future__r   rf  r;   r2  ri  r,   rC  r(   collectionsr   r   r   pathlibr   typingr   __file__resolveparentrk  rY   rZ   
MODALITIES
POLARITIESr#  r)   rA   r\   rs   r|   r   r   r   r   r   r   r   r   r  r%  r8  rG  r  __name__rs  rf   r8   r7   <module>r     sZ  
 #    	 	 
  # '   H~&&.$ 4
 :
"
	G(@":% GP%)4*.y+.@C"6@ ( BE Vd"&).<
T0/"w>6
Q`4n z
TV
 r8   