Files
certain/backend/scripts/pruefe_schlagwoerter.py
GuidoandClaude Opus 4.8 3948d98273 feat: Diagnose-Skript für fehlende Schlagwörter
Die Kategorie-Liste zeigt nur manuelle, einer bestehenden Kategorie zugeordnete
Regeln. Bleibt sie leer, obwohl Regeln in der Datenbank stehen, sagt das Skript
warum: Es schlüsselt den Bestand nach source, kind und is_transfer auf, zählt
Regeln ohne Kategorie sowie solche, deren Kategorie nicht mehr existiert, und
nennt die Zahl der tatsächlich sichtbaren.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-21 14:33:05 +02:00

67 lines
2.5 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Zeigt, warum Schlagwörter in der Oberfläche fehlen könnten.
Die Liste einer Kategorie zeigt nur Regeln mit ``source='manual'``, die einer
Kategorie zugeordnet und keine Transfer-Regel sind. Automatisch gelernte Regeln
tauchen dort bewusst nicht auf. Dieses Skript schlüsselt den Bestand danach auf.
Aufruf: pruefe_schlagwoerter.py [pfad/zur/app.db]
"""
import sqlite3
import sys
from collections import Counter
DB = sys.argv[1] if len(sys.argv) > 1 else "/var/lib/certain-finance/app.db"
con = sqlite3.connect(f"file:{DB}?mode=ro", uri=True)
con.row_factory = sqlite3.Row
def spalten(tabelle: str) -> set[str]:
return {r["name"] for r in con.execute(f"PRAGMA table_info({tabelle})")}
vorhanden = spalten("categorization_rules")
print(f"Datenbank: {DB}")
print(f"Spalten in categorization_rules: {', '.join(sorted(vorhanden))}\n")
gesamt = con.execute("SELECT COUNT(*) FROM categorization_rules").fetchone()[0]
print(f"Regeln insgesamt: {gesamt}")
for feld in ("source", "kind", "is_transfer", "match_field"):
if feld not in vorhanden:
print(f" {feld:<12} – Spalte fehlt")
continue
verteilung = Counter(
r[0] for r in con.execute(f"SELECT {feld} FROM categorization_rules")
)
print(f" {feld:<12} {dict(verteilung)}")
ohne_kat = con.execute(
"SELECT COUNT(*) FROM categorization_rules WHERE category_id IS NULL"
).fetchone()[0]
verwaist = con.execute(
"SELECT COUNT(*) FROM categorization_rules r WHERE r.category_id IS NOT NULL"
" AND NOT EXISTS (SELECT 1 FROM categories c WHERE c.id = r.category_id)"
).fetchone()[0]
print(f" ohne Kategorie: {ohne_kat}")
print(f" Kategorie zeigt ins Leere: {verwaist} <-- solche erscheinen nirgends")
# Genau die Bedingung, die die Oberfläche für die Kategorie-Liste nutzt.
sichtbar = con.execute(
"SELECT COUNT(*) FROM categorization_rules r"
" JOIN categories c ON c.id = r.category_id"
" WHERE r.source = 'manual' AND r.is_transfer = 0"
).fetchone()[0]
print(f"\nIn der Kategorie-Liste sichtbar: {sichtbar} von {gesamt}")
print("\nBeispiele (die ersten 12):")
print(f" {'Muster':<26}{'source':<10}{'kind':<10}{'transfer':<9}{'Kategorie'}")
for r in con.execute(
"SELECT r.pattern, r.source, r.kind, r.is_transfer, c.name AS kat"
" FROM categorization_rules r LEFT JOIN categories c ON c.id = r.category_id"
" ORDER BY r.id LIMIT 12"
):
print(f" {r['pattern'][:24]:<26}{str(r['source']):<10}{str(r['kind']):<10}"
f"{str(r['is_transfer']):<9}{r['kat'] or '— fehlt —'}")
con.close()