import sqlite3,json,re,datetime,urllib.request,subprocess,os
from pathlib import Path
RID='req-52b794da1db59085b964d4cd'; Q='/opt/struktur/obsidian-graphiti_import.db'; Q='/opt/struktur/obsidian-graphiti-import/obsidian_graphiti_import.db'; R='/opt/struktur/graphiti/request-data/requests.db'; EV='/opt/struktur/graphiti/request-data/processing-events.jsonl'
def san(s):
s=str(s or '')
s=re.sub(r'(user_id|api[_-]?key|authorization|token)\s*[:=]\s*[^,}\s]+',r'\1=[REDACTED]',s,flags=re.I)
return s[:4000]
print('NOW',datetime.datetime.now(datetime.timezone.utc).isoformat())
q=sqlite3.connect('file:'+Q+'?mode=ro',uri=True); q.row_factory=sqlite3.Row; print('QUEUE17',dict(q.execute('select id,relative_path,status,attempts,last_error,last_error_phase,graphiti_episode_uuid from files where id=17').fetchone())); q.close()
r=sqlite3.connect('file:'+R+'?mode=ro',uri=True); r.row_factory=sqlite3.Row
row=r.execute('select * from graphiti_requests where request_id=?',(RID,)).fetchone(); print('REQUEST17',json.dumps({k:(san(row[k]) if k in ('error_message','error_phase') else row[k]) for k in row.keys()},ensure_ascii=False,default=str))
print('SCHEMA_REQUESTS',r.execute('pragma table_info(graphiti_requests)').fetchall())
print('AFTER_REQUESTS',[(x['request_id'],x['queue_id'],x['status'],x['http_status'],x['started_at'],x['completed_at'],x['model'],x['provider']) for x in r.execute("select request_id,queue_id,status,http_status,started_at,completed_at,model,provider from graphiti_requests where started_at>? order by rowid",(row['started_at'],)).fetchall()])
r.close()
# events for target and later provider calls
all_ev=[]
for line in Path(EV).read_text(errors='replace').splitlines():
try:
x=json.loads(line)
if x.get('request_id')==RID or (x.get('phase','').startswith('llm_call') and x.get('outcome') in ('completed','failed')): all_ev.append(x)
except: pass
target=[x for x in all_ev if x.get('request_id')==RID]
print('TARGET_EVENTS')
for x in target:
if x.get('outcome')=='failed' or x.get('graphiti_phase')=='edge_resolution' or x.get('phase')=='edge_operation_failed': print(json.dumps({k:san(x.get(k)) for k in ['timestamp','phase','outcome','llm_call_index','graphiti_phase','operation','error_class','timeout_reason','error','http_status','finish_reason','native_finish_reason','max_tokens','model','provider','provider_request_id']},ensure_ascii=False))
# all event calls after target start with timestamps, sanitized summaries
later=[]
for x in all_ev:
if x.get('request_id')!=RID and x.get('phase','').startswith('llm_call') and x.get('outcome') in ('completed','failed') and x.get('timestamp','')>=row['started_at']:
later.append({k:san(x.get(k)) for k in ['request_id','timestamp','outcome','llm_call_index','graphiti_phase','error_class','timeout_reason','error','model','provider','output_tokens','max_tokens']})
print('LATER_EVENTS_COUNT',len(later)); print('LATER_EVENTS_SAMPLE',json.dumps(later[-30:],ensure_ascii=False))
for p in ['/opt/struktur/graphiti/provider_state.json','/opt/struktur/obsidian-graphiti-import/provider_state.json']:
if os.path.exists(p): print('PROVIDER_STATE',p,Path(p).read_text())
print('HEALTH',urllib.request.urlopen('http://127.0.0.1:8644/health',timeout=20).read().decode())
print('OPENROUTER_ENV_NAMES',subprocess.check_output(['bash','-lc',"docker inspect graphiti-service --format '{{range .Config.Env}}{{println .}}{{end}}' | cut -d= -f1 | grep -Ei 'OPENROUTER|RATE|LIMIT|LLM|MODEL|PROVIDER' | sort"],text=True))
# search docker logs without printing raw secrets
log=subprocess.check_output(['bash','-lc',"docker logs --since 2026-08-18T18:20:00Z graphiti-service 2>&1 | grep -Ei 'rate.?limit|429|req-52b794da1db59085b964d4cd|reset' | tail -100 || true"],text=True)
print('DOCKER_LOG_MATCHES',san(log))