
    |0bj?                        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m	Z	m
Z
 ddlmZmZ ddlmZ  ed      Z ed      Z ed	      Zd
ZdZdZh dZddZddZddZddZddZddZddZedk(  r e        yy)aJ  Deterministic, local AI-review resolver.

This is the versioned implementation of the Codex review policy.  It uses no
model API, Graphiti, OpenRouter or LLM.  It reads the original Obsidian source,
records two independent rule passes, and applies only terminal routing states.
It never creates TruthItems and never writes Neo4j.
    )annotationsN)Counterdefaultdict)datetimetimezone)Pathz?/opt/struktur/obsidian-knowledge-pipeline/knowledge_pipeline.dbz7/opt/struktur/knowledge-curator/minimal-human-review.dbz/opt/obsidian-vaultzai-review-resolver/1.0.0zai-rulebook/1.0.0chatgpt_codex>   	duplicatefast_index_onlyinvalid_fragmentobsolete_extractionsensitive_quarantineai_recorded_unverifiedai_structured_acceptedexcluded_non_knowledgegenerated_summary_onlyhistorical_report_onlyinsufficient_authoritytechnical_context_onlyexploratory_source_onlyconflict_observed_no_action#insufficient_evidence_no_escalationc                 d    t        j                  t        j                        j	                         S )N)r   nowr   utc	isoformat     5/opt/struktur/knowledge-curator/ai_review_resolver.pyr   r   &   s    <<%//11r   c                    t        | t              r| j                  d      } t        j                  |       j                         S )Nutf-8)
isinstancestrencodehashlibsha256	hexdigest)values    r   shar)   *   s1    %u||G'<u>>% **,,r   c                   | j                  d      D ch c]  }|d   	 }}dddddj                         D ]!  \  }}||vs| j                  d| d|        # |j                  d      D ch c]  }|d   	 }}ddddj                         D ]$  \  }}|s	||vs|j                  d	| d|        & |j                  d
       y c c}w c c}w )NzPRAGMA table_info(review_items)   TEXT)ai_review_statusai_review_versionai_reviewed_atai_decision_idz$ALTER TABLE review_items ADD COLUMN  z PRAGMA table_info(routing_items))terminal_statusresolved_atresolver_versionz%ALTER TABLE routing_items ADD COLUMN al  
      CREATE TABLE IF NOT EXISTS ai_review_runs(
        run_id TEXT PRIMARY KEY, resolver_version TEXT NOT NULL,
        rule_version TEXT NOT NULL, actor TEXT NOT NULL, started_at TEXT NOT NULL,
        completed_at TEXT, group_count INTEGER NOT NULL, candidate_count INTEGER NOT NULL,
        agreement_count INTEGER NOT NULL, conservative_count INTEGER NOT NULL,
        status TEXT NOT NULL, no_external_model INTEGER NOT NULL,
        no_neo4j_write INTEGER NOT NULL
      );
      CREATE TABLE IF NOT EXISTS ai_group_decisions(
        decision_id TEXT PRIMARY KEY, run_id TEXT NOT NULL, group_id TEXT NOT NULL,
        group_status TEXT NOT NULL, member_count INTEGER NOT NULL,
        member_statuses_json TEXT NOT NULL, pass_a_json TEXT NOT NULL,
        pass_b_json TEXT NOT NULL, agreement INTEGER NOT NULL,
        split_required INTEGER NOT NULL, sources_json TEXT NOT NULL,
        evidence_hashes_json TEXT NOT NULL, exceptions_json TEXT NOT NULL,
        rule_id TEXT NOT NULL, rule_version TEXT NOT NULL, confidence_class TEXT NOT NULL,
        rollback_reference TEXT NOT NULL, decided_at TEXT NOT NULL,
        decided_by TEXT NOT NULL
      );
      CREATE TABLE IF NOT EXISTS ai_review_decisions(
        decision_id TEXT PRIMARY KEY, run_id TEXT NOT NULL, group_id TEXT NOT NULL,
        candidate_id TEXT NOT NULL, target_status TEXT NOT NULL, reason TEXT NOT NULL,
        pass_a TEXT NOT NULL, pass_b TEXT NOT NULL, agreement INTEGER NOT NULL,
        source_path TEXT NOT NULL, source_file_sha256 TEXT, source_chunk_key TEXT,
        evidence_hash TEXT, evidence_length INTEGER NOT NULL, candidate_json TEXT NOT NULL,
        exceptions_json TEXT NOT NULL, rule_id TEXT NOT NULL, rule_version TEXT NOT NULL,
        confidence_class TEXT NOT NULL, decided_at TEXT NOT NULL,
        decided_by TEXT NOT NULL, rollback_reference TEXT NOT NULL
      );
      CREATE TABLE IF NOT EXISTS ai_review_audit(
        audit_id TEXT PRIMARY KEY, run_id TEXT NOT NULL, candidate_id TEXT,
        group_id TEXT, phase TEXT NOT NULL, old_status TEXT, new_status TEXT,
        details_json TEXT NOT NULL, created_at TEXT NOT NULL
      );
    )executeitemsexecutescript)pcmcrcolsnametyprcolss          r   ensure_schemar?   /   s   **%FGHQAaDHDH!v& eg]	c tRZZ*NtfTUVYUZ([\	]
 ::&HIJaQqTJEJ(.VW]^ddf M	cT&JJ>tfAcUKLM  # #	 I Ks   C	.Cc                   | dz   |z   dz   t        j                  |d      z   j                         }| j                  d      ryt	        j
                  d|      }|s| j                  d      s| dv ry	| j                  d
      s| j                  d      sd| v sd| v sd| v ry| j                  d      ry| j                  d      s| dv ry| j                  d      ryy)z2Return target status, pass-A, pass-B, and rule id.
Fensure_asciizYouTube-Research/)r   zNThe source contains a reported rule or recommendation in a transcript/summary.zZThe source is external and non-authoritative; no current or verified claim may be created.ai.source.exploratory.v1zapi[- ]?key|token|passwort|password|secret|credentials|zugang|berecht|oauth|zahlung|konto|kredit|rechtlich|sicherheit|irrevers|medizin|personenbezogenzEmail-Agent/>   CODEX_HANDOVER_PLAN.mdSESSION_NOTES.md)r   zJThe source describes an operational, access, security, or sensitive topic.zWAuthority and safe operational effect are not sufficient for automatic truth or action.zai.sensitive.quarantine.v1zADR/rF   zARC-zStatus-zStatus-nach-)r   zBThe source records a historical decision, event, or system status.zEHistorical context must not be promoted to current or verified truth.zai.historical.report-only.v1zSystem/AI-Skills/)r   z>The source is instructional or third-party reference material.zAIt is not an authoritative statement about the productive system.rD   zSystemstruktur/>   CODEX_TOOL_PROMPT.mdSYSTEM-ARCHITEKTUR.md)r   zHThe source provides architecture, diagnostic, or implementation context.zFIt is not sufficient authority for an automatic truth-layer assertion.zai.technical.context-only.v1z
Solutions/)r   z=The source is a design analysis or implementation comparison.zCRecommendations and design notes are not verified production facts.zai.design.context-only.v1)r   zNThe source is useful project or background information and remains searchable.zWIt has no sufficient authority or operational need for automatic truth-layer promotion.zai.low-impact.fast-index.v1)jsondumpscasefold
startswithresearch)path	candidateevidencelow	sensitives        r   classifyrT   `   s   $;!D(4::ie+TT
^
^
`C*+, 		  t  vy  zIDOON3t @ 8.
 v$//2D"ESW[dhl[lp~  CG  qG0 *+, ()T5f-f0 |$-+r   c                    t         | z  }|j                         sdd d ddS |j                         }dt        |      t	        |      |j                  dd      dS )NF )existsr&   sizetextTr!   replace)errors)VAULTrW   
read_bytesr)   lendecode)rO   fraws      r   source_inforb      sT    A88:$VXYY
,,.Cc#hC#**U\en*Joppr   c                   t        j                  t              }t         j                  |_        t        j                  t
              }t         j                  |_        t        ||       |j                          |j                          g }|j                  d      D ]6  }g }|j                  d|d   f      D ]  }|j                  d|d   f      j                         }|s+t        j                  |d         }|j                  d      xs i }	t        |	j                  d      xs |j                  d	      xs d
      }
t        |d   ||
      \  }}}}t        |d         }g }|d   s|j!                  d       d}|	j                  d      r|j!                  d       |j!                  |||
|||||||	d
        |j!                  ||d       9 t#               }dt%        j"                  t&        j(                        j+                  d      z   }g }g }t-               }d}d}|D ][  }|d   }t-        d |D              }|r|j/                  d      d   d   nd}t1        |      dkD  }|r|dz  }t3        d |D              r|dz  }t5        |D ch c]
  }|d   d    c}      }t5        |D ch c]&  }|d   j                  d      xs t7        |d         ( c}      }t5        |D ch c]  }|d   D ]  }|  c}}      } |d   d   }!d|z   dz   |!z   }"|j!                  i d |"d!|d"|!d#|d$t1        |      d%t9        |      d&d't1        |       d(d)d*d+d,d)d-| d.|d/|d0|d| d1d2d3d4d5d6|z   d7|d8t:        i       |D ]  }|d   }|d9   }#d:|z   dz   |#z   }$|j!                  i d |$d!|d"|!d9|#d;|d<   d=|d&   d>z   |d*   z   d&|d&   d*|d*   d-t=        |       d?|d   d@|dA   dB   dC|d   j                  dC      d|d   j                  d      xs t7        |d         dDt1        |d         d|d   d|d   d1|dE   t>        d4|t:        d6|z   dF       ||d<   xx   dz  cc<    ^ i d!|dGt@        dHt>        dIt:        dJt1        |      dKt1        |      dLt9        |      dM|dN|dO| dP| rdn
t1        |      dQ| rdn
t1        |      dRddSddTddUddVt5        tB              }%| s"|jE                          |jE                          |%S ||fD ]  }&|&j                  dW        	 |j                  dX|t@        t>        t:        ||t1        |      t1        |      ||dYddf       |D ]  }'|j                  dZ|'d    ||'d"   |'d#   |'d$   t        jF                  |'d%   d[\      t        jF                  |'d&   d[\      t        jF                  |'d*   d[\      t=        |'d-         t=        |'d.         t        jF                  |'d/   d[\      t        jF                  |'d0   d[\      t        jF                  |'d   d[\      |'d1   t>        d4|'d5   |t:        f        |D ]  }(|j                  d]|(d    ||(d"   |(d9   |(d;   |(d=   |(d&   |(d*   |(d-   |(d?   |(d@   |(dC   |(d   |(dD   |(d   t        jF                  |(d   d[\      |(d1   t>        |(d3   |t:        |(d5   f       |j                  d^|(d9   f      j                         })|)r|)d   d_vr|j                  d`|(d;   |(d;   |(d1   t>        |||(d;   t@        ||(d    |(d9   f       |j                  da|db|(d9   dc|)d   |(d;   t        jF                  |(d    |(d1   ddddded[\      |f       |j                  dfdg|(d    z   ||(d9   |(d"   dc|)d   |(d;   t        jF                  |(d1   dddhd[\      |f	       di|j                  dj      D *ch c]  }*|*d   	 c}*v r |j                  dk|(d;   |t@        |(d9   f      nd   |j                  dl       |j                          |j                          	 |jE                          |jE                          |%S c c}w c c}w c c}}w c c}*w # tH        $ r" |jK                          |jK                           w xY w# |jE                          |jE                          w xY w)mNzWSELECT * FROM decision_units WHERE status='pending_human_group_review' ORDER BY unit_idzTSELECT candidate_id FROM decision_unit_members WHERE unit_id=? ORDER BY candidate_idunit_idz/SELECT * FROM review_items WHERE candidate_id=?r   candidate_json
provenanceevidence_textobjectrV   rO   rW   source_missingr   evidence_truncated)
rowrP   rQ   statuspass_apass_brulesource
exceptionsprov)unitmembersz
ai-review-z%Y%m%dT%H%M%S%fZrt   c              3  &   K   | ]	  }|d      yw)rl   Nr   .0ms     r   	<genexpr>zresolve.<locals>.<genexpr>   s     .Lqq{.Ls   r+   c              3  4   K   | ]  }|d    xr |d     yw)rm   rn   Nr   rv   s     r   ry   zresolve.<locals>.<genexpr>   s      <qq{*q{*<s   rk   rr   evidence_hashrQ   rq   rs   z	ai-group--decision_idrun_idgroup_idgroup_statusmember_countmember_statusesrm   z'positive source/provenance/status checkz, candidates evaluated against original files)methodsummaryrn   z-critical authority/conflict/currentness checkz1No automatic current/verified promotion permitted	agreementsplit_requiredsourcesevidence_hashesrule_idzai.group.reconcile.v1confidence_classconservative_terminal_routingrollback_referencezai-review-rollback-
decided_at
decided_bycandidate_idzai-target_statusrl   reasonr1   source_pathsource_file_sha256rp   r&   source_chunk_keyevidence_lengthro   )rule_versionr   r   r   r   r4   r   actorgroups
candidatesstatusesagreement_groupsconservative_groupsapplyhuman_decision_units_aftergrouped_review_required_afterungrouped_pending_review_afterexternal_model_callsneo4j_writestruth_items_createdterminal_statuseszBEGIN IMMEDIATEz<INSERT INTO ai_review_runs VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?)	completedzLINSERT INTO ai_group_decisions VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)FrB   a  INSERT INTO ai_review_decisions(
                decision_id,run_id,group_id,candidate_id,target_status,reason,pass_a,pass_b,
                agreement,source_path,source_file_sha256,source_chunk_key,evidence_hash,
                evidence_length,candidate_json,exceptions_json,rule_id,rule_version,
                confidence_class,decided_at,decided_by,rollback_reference)
                VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)z4SELECT status FROM review_items WHERE candidate_id=?)grouped_pending_reviewpending_reviewzUPDATE review_items SET status=?,classification_status=?,classification_rule=?,classification_version=?,classified_at=?,updated_at=?,ai_review_status=?,ai_review_version=?,ai_reviewed_at=?,ai_decision_id=? WHERE candidate_id=?z|INSERT INTO audit(run_id,entity_type,entity_key,phase,old_status,new_status,details_json,created_at) VALUES(?,?,?,?,?,?,?,?)reviewai_review_resolveT)r}   r   no_truth_writeno_neo4j_writez5INSERT INTO ai_review_audit VALUES(?,?,?,?,?,?,?,?,?)z	ai-audit-)r   r   r2   z pragma table_info(routing_items)z`UPDATE routing_items SET terminal_status=?,resolved_at=?,resolver_version=? WHERE candidate_id=?zVUPDATE decision_units SET status='ai_closed' WHERE status='pending_human_group_review')&sqlite3connectPIPERowrow_factoryMHRr?   commitr5   fetchonerI   loadsgetr#   rT   rb   appendr   r   r   r   strftimer   most_commonr^   allsortedr)   dictACTORintRULE_VERSIONVERSIONTERMINALcloserJ   	Exceptionrollback)+r   r8   r9   r   urt   mmrk   candrr   rQ   rl   abro   srcexcstartedr~   recordsgroup_recordscounts
agreementsconservativegr   r   splitrx   r   evhasherq   giddidciddidcresultconngrrecoldxs+                                              r   resolver      s   		B		Br~"b299;		FZZqr 4**suv  xA  vB  uD  E 	iB

LbQReXV__aCC 012D,9O9USUD/2Ndhhx6HNBOH$S[h?OF1QtCK(CCx=

+,<xx,-szz:N/ONN#$(TZdeopx|  GJ  X[  cg  h  i	i 	a'234  EG,x||HLL'A'J'JK]'^^6Gb&qJq, #)w.LG.L'Lh6>X))!,Q/2Di(mAo,!#,<G<<jAoj':Q%(:;U\]PQqy}}_5KQz]9KK]^gGqG!1G1GH
fIi k&&8&<S&@#  PmC  P  P
3  P~^j  Pkyz}  F  {G  P  HY  Z^  _g  Zh  P  iq  |e  sv  w~  s  r@  @l  pm  rn  P  ow  Bq  |o  xp  P  q|  AF  }F  P  GW  X]  P  ^g  ho  P  pA  BH  P  IU  V`  P  aj  kB	  P  C	U	  V	u	  P  v	J
  K
`
  a
g
  K
g
  P  h
t
  u
|
  P  }
I  JO  P  	Q 	#A%Cc.1#fS8H8L4NN  MM$  Mx  Mz#  Mn]`  Mapqrs{q|  M  ~F  GH  IQ  GR  SV  GV  WX  Ya  Wb  Gb  M  ck  lm  nv  lw  M  x@  AB  CK  AL  M  MX  Y\  af  ]f  Yg  M  hu  vy  z@  vA  M  BV  WX  Ya  Wb  ck  Wl  M  m  @A  BH  @I  @M  @M  N`  @a  M  bq  rs  tz  r{  r  r  @O  rP  rf  TW  XY  Zd  Xe  Tf  M  gx  y|  }~  I  }J  yK  M  L\  ]`  aq  ]r  M  s  @A  BN  @O  M  PY  Z[  \b  Zc  M  s  S	r	  @
G
  U
Z
  p
E  FL  p
L  M  N1X;"	## wHV  w.w  w~l  wSZ[`  waijmntju  w  wC  DG  HO  DP  w  Q[  \`  ag  \h  w  i{  |F  w  G\  ]i  w  jq  rw  w  xT  Z_  UV  eh  io  ep  w  qP  V[  QR  ad  ek  al  w  mM  NO  w  Pf  gh  w  iw  xy  w  zO  PQ  w  Re  fl  mu  fv  wF

BHHJvB8&788


QSYZabnotu|  ~E  FI  JP  FQ  RU  V]  R^  _i  jv  wB  CD  EF  SG  	H 	g	BJJegijwgxy  AC  DN  AO  PR  Sa  Pb  ce  ft  cu  vz  v@  v@  AC  DU  AV  di  vj  ko  ku  ku  vx  yA  vB  PU  kV  W[  Wa  Wa  bd  em  bn  |A  WB  CF  GI  JU  GV  CW  X[  \^  _o  \p  Xq  rv  r|  r|  }  @I  }J  X]  r^  _c  _i  _i  jl  m~  j  MR  _S  TX  T^  T^  _a  bn  _o  }B  TC  DF  GP  DQ  R^  _~  A	  B	V	  W	  X	_	  `	e	  gf	  g		g	 	XCJJ G M"6#j/#n:McRaNbHc(mCM#k:J3}K]()#.@*A#oBVWZ[lWm$%djj\1BPU&VWZ[dWeS!34WU3G[C\H^
_ 

QSVWeSfRhirrtC#a&(SSU]JJ  |O$S%9#i.V]^efijyfz  |C  DK  LO  P]  L^  _b  cq  _r}s tJJ  V  X^  _g  hk  lz  h{  |O  PS  TU  PV  WZ  [j  Wk  lp  lv  lv  FI  JW  FX  cf  gp  cq  CG  Y]  w^  lq  lr  sz  W{  |JJNP[\_`m\nPnouvy  {I  wJ  KN  OY  KZ  [n  or  st  ou  vy  zI  vJ  KO  KU  KU  ad  en  ao  AE  VF  TY  KZ  [b  Pc  d {L  _a  _i  _i  jL  _M  PN  Z[  QR  ST  QU  PN  {NBJJy|  AP  }Q  RY  Za  be  ft  bu  |v  w  TX%	X& 	

kl
		RYY[ 	
BHHJMU ;]GB PN  ,
r{{}e, 	
BHHJs>   b
3+b
/b
J0b :bAb b +cc "c(c                 T   t        j                         } | j                  dd       | j                  dd       | j                         }|j                  |j
                  k(  r| j                  d       t        t        j                  t        |j
                        dd             y )	Nz	--dry-run
store_true)actionz--applyz)genau eine Option: --dry-run oder --applyF   )rC   indent)argparseArgumentParseradd_argument
parse_argsdry_runr   errorprintrI   rJ   r   )apr   s     r   mainr      s     B"//+\/"RTVTcTcdm  vBTc  UCmmoAyyAGGRXX&QR	$**WQWW%5
BCr   __main__)returnr#   )r(   zbytes | strr   r#   )r8   sqlite3.Connectionr9   r   r   None)rO   r#   rP   r   rQ   r#   r   ztuple[str, str, str, str])rO   r#   r   r   )r   boolr   r   )r   r   )__doc__
__future__r   r   r%   rI   rM   r   collectionsr   r   r   r   pathlibr   r   r   r\   r   r   r   r   r   r)   r?   rT   rb   r   r   __name__r   r   r   <module>r      s    #    	  , ' MN
DE"#
$"2-
.	b++\qGTD z46r   