gwoe-antragspruefer/app/repositories/bewertung_repository.py
Dotty Dotter 8f0f6d6e32 refactor(#136): DDD-Lightweight Tag 1-4 (Ports, Adapter, Repositories, Domain-Verhalten)
ADR 0008: Lightweight-Migration ohne Package-Split

- ports/llm_bewerter.py: Protocol + LlmRequest-Dataclass
- adapters/qwen_bewerter.py: Qwen/DashScope-Adapter mit Retry-Loop
- repositories/{antrag,bewertung,abonnement}_repository.py: Protocol + Sqlite-Impl + InMemory-Fake
- analyzer.py refactored: nimmt Optional[LlmBewerter], AsyncOpenAI-Import raus
- models.py: 5 Domain-Methoden auf Bewertung/MatrixEntry
  (ist_ablehnung, hat_fundamental_kritisches_feld, verletzt_score_cap, ...)
- analyzer loggt WARNING wenn LLM Score-Cap-Invariante verletzt

Folge-PR: Callsite-Migration in main.py (~21 direkte database.*-Aufrufe)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 20:55:16 +02:00

65 lines
1.9 KiB
Python

"""BewertungRepository — Port für die Versionshistorie einer Bewertung.
Eine „Bewertung" ist die vollständige Assessment-Instanz; der
`BewertungRepository` greift auf die Snapshot-Tabelle
``assessment_versions`` zu. Für die aktuellste Bewertung siehe
``AntragRepository``.
"""
from __future__ import annotations
from typing import Protocol, runtime_checkable
from .. import database
@runtime_checkable
class BewertungRepository(Protocol):
async def versions(self, drucksache: str) -> list[dict]: ...
class SqliteBewertungRepository:
"""Produktions-Implementation. Delegiert an ``database.py``."""
async def versions(self, drucksache: str) -> list[dict]:
return await database.get_assessment_history(drucksache)
class InMemoryBewertungRepository:
"""Test-Fake. Erlaubt per ``add_version`` händisches Bestücken.
Die produktive Versionierung passiert implizit in ``upsert_assessment``
(siehe database.py:580-598). Im Fake trennen wir das bewusst, weil
Tests oft explizit Versionshistorie befüllen wollen.
"""
def __init__(self) -> None:
self._versions: dict[str, list[dict]] = {}
def add_version(
self,
drucksache: str,
version: int,
gwoe_score: float,
model: str,
created_at: str = "",
) -> None:
self._versions.setdefault(drucksache, []).append({
"version": version,
"gwoe_score": gwoe_score,
"model": model,
"created_at": created_at,
})
async def versions(self, drucksache: str) -> list[dict]:
rows = list(self._versions.get(drucksache, []))
rows.sort(key=lambda r: r["version"], reverse=True)
return rows
_default_bewertung_repo: BewertungRepository = SqliteBewertungRepository()
def get_bewertung_repository() -> BewertungRepository:
return _default_bewertung_repo