BUG: 4 Core→Plugin-Imports in core/jobs.py DSAR-Sammlung — direkte Model-Imports statt Contracts #356

Closed
opened 2026-08-27 15:37:39 +00:00 by Leopoldadmin · 2 comments
Owner

Live gemessen 2026-08-27 (python scripts/check_cross_plugin_imports.py vor Fix: 4 Verstöße):

  • app/core/jobs.py:259 → mail.models.MailAccount
  • app/core/jobs.py:283 → tasks.models.Task
  • app/core/jobs.py:308 → calendar.models.CalendarEntry
  • app/core/jobs.py:333 → kommunikation.models.CommMessage

Kontext: Die DSAR-Datenkategorie-Sammlung (G1-b: mail_accounts, tasks, calendar_entries, comm_messages) importierte Plugin-Models direkt statt über die bestehende Contract-Registry (Kritikpunkt 15). Verstoß gegen Core→Plugin-Grenze; bei inaktivem Plugin wäre zudem der ImportError-Fallback nie sauber greifen können.

P16-Klassifizierung (manuelle Prüfung): from app.models.contact import Contact in core/jobs.py:172/377 und core/worker.py:399 sind KEINE Verstöße — Contact-Models liegen historisch im Core-Models-Layer (app/models/), nicht unter app.plugins.*. Der Checker erlaubt sie korrekt. Keine Aktion nötig.

Fix: Die 4 Blöcke nutzen jetzt get_contract("mail"|"tasks"|"calendar"|"kommunikation") (bestehende Registry, lazy-load + ARCH-014-Resurrection-Schutz). MailContract exponiert zusätzlich MailAccount (einzeilig, bestehendes Muster). ImportError-Fallback-Semantik unverändert: Plugin inaktiv → Kategorie wird übersprungen wie bisher. Queries/Serialisierung byte-identisch.

Verifikation: Checker nach Fix: 0 Verstöße (480 Dateien). DSAR-Suite test_g1_dsar.py 4/4 passed (Funktionserhalt). Ruff: nur 2 Vorbestand-N811 (PyUUID) verbleiben.

Live gemessen 2026-08-27 (`python scripts/check_cross_plugin_imports.py` vor Fix: **4 Verstöße**): - app/core/jobs.py:259 → mail.models.MailAccount - app/core/jobs.py:283 → tasks.models.Task - app/core/jobs.py:308 → calendar.models.CalendarEntry - app/core/jobs.py:333 → kommunikation.models.CommMessage **Kontext:** Die DSAR-Datenkategorie-Sammlung (G1-b: mail_accounts, tasks, calendar_entries, comm_messages) importierte Plugin-Models direkt statt über die bestehende Contract-Registry (Kritikpunkt 15). Verstoß gegen Core→Plugin-Grenze; bei inaktivem Plugin wäre zudem der ImportError-Fallback nie sauber greifen können. **P16-Klassifizierung (manuelle Prüfung):** `from app.models.contact import Contact` in core/jobs.py:172/377 und core/worker.py:399 sind KEINE Verstöße — Contact-Models liegen historisch im Core-Models-Layer (`app/models/`), nicht unter `app.plugins.*`. Der Checker erlaubt sie korrekt. Keine Aktion nötig. **Fix:** Die 4 Blöcke nutzen jetzt `get_contract("mail"|"tasks"|"calendar"|"kommunikation")` (bestehende Registry, lazy-load + ARCH-014-Resurrection-Schutz). MailContract exponiert zusätzlich `MailAccount` (einzeilig, bestehendes Muster). ImportError-Fallback-Semantik unverändert: Plugin inaktiv → Kategorie wird übersprungen wie bisher. Queries/Serialisierung byte-identisch. **Verifikation:** Checker nach Fix: **0 Verstöße** (480 Dateien). DSAR-Suite test_g1_dsar.py 4/4 passed (Funktionserhalt). Ruff: nur 2 Vorbestand-N811 (PyUUID) verbleiben.
Leopoldadmin added the bughigh labels 2026-08-27 15:37:39 +00:00
Author
Owner

Gefixt in Commit 092c2d2 — deployed und live verifiziert (2026-08-27 17:40):

Fix

  1. Contract-Zugriff statt Model-Imports: Die 4 DSAR-Blöcke in core/jobs.py nutzen jetzt get_contract("mail"/"tasks"/"calendar"/"kommunikation") über die bestehende Contract-Registry (lazy-load + ARCH-014-Resurrection-Schutz).
  2. MailContract erweitert: MailAccount exponiert (einzeilig, bestehendes Contract-Muster).
  3. Semantik bewahrt: Plugin inaktiv → get_contract() liefert None → bewusstes raise ImportError → bestehender except-Zweig überspringt die Kategorie wie bisher. Queries/Serialisierung byte-identisch.

Verifikation (Live-Messung)

  • Cross-Plugin-Checker: 4 Verstöße → 0 Verstöße (480 Dateien geprüft)
  • DSAR-Suite tests/test_g1_dsar.py: 4/4 passed (Access/Deletion/Dispatch — Funktionserhalt bewiesen)
  • Ruff modified-files: nur 2 Vorbestand-N811 (PyUUID) verbleiben; meine 4 N806 durch saubere lowercase-Names behoben
  • Full Deploy SUCCESS · Health healthy (DB/Redis/Storage/Worker up) · Alembic 0142 OK · RLS 109 OK
**Gefixt in Commit `092c2d2` — deployed und live verifiziert (2026-08-27 17:40):** ## Fix 1. **Contract-Zugriff statt Model-Imports:** Die 4 DSAR-Blöcke in `core/jobs.py` nutzen jetzt `get_contract("mail"/"tasks"/"calendar"/"kommunikation")` über die bestehende Contract-Registry (lazy-load + ARCH-014-Resurrection-Schutz). 2. **MailContract erweitert:** `MailAccount` exponiert (einzeilig, bestehendes Contract-Muster). 3. **Semantik bewahrt:** Plugin inaktiv → `get_contract()` liefert None → bewusstes `raise ImportError` → bestehender except-Zweig überspringt die Kategorie wie bisher. Queries/Serialisierung byte-identisch. ## Verifikation (Live-Messung) - Cross-Plugin-Checker: **4 Verstöße → 0 Verstöße** (480 Dateien geprüft) - DSAR-Suite `tests/test_g1_dsar.py`: **4/4 passed** (Access/Deletion/Dispatch — Funktionserhalt bewiesen) - Ruff modified-files: nur 2 Vorbestand-N811 (PyUUID) verbleiben; meine 4 N806 durch saubere lowercase-Names behoben - Full Deploy SUCCESS · Health healthy (DB/Redis/Storage/Worker up) · Alembic 0142 OK · RLS 109 OK
Author
Owner

Vertiefung nach Review-Einspruch: Plugin-Fachlogik gehört vollständig aus dem Core — umgesetzt.

Kritik berechtigt

Der erste Fix (092c2d2) bog nur den Import-Weg auf Contracts um, aber die Fachlogik (welche DSAR-Kategorien existieren, welche Felder gesammelt/gelöscht werden, mit welchen Limits) lag weiterhin hart im Core. Damit kannte der Core Plugin-Details — gegen die Architektur.

Die echte Korrektur

Core sammelt/löscht jetzt NUR Core-eigene Daten (Profil, Audit-Log, Notifications, User-Anonymisierung). Alle Plugin-Kategorien wandern in die besitzenden Contracts:

Contract Neu
ContactsContract dsar_collect() + dsar_erase() (Kontakte sind Plugin-eigen — is_core=True heißt Pflichtplugin, nicht Core-Verdrahtung)
MailContract dsar_collect() (mail_accounts)
TasksContract dsar_collect() (tasks)
CalendarContract dsar_collect() (calendar_entries)
KommunikationContract dsar_collect() (comm_messages)

core/jobs.py iteriert generisch: registry.list_discovered()get_contract() → falls dsar_collect/dsar_erase vorhanden → Kategorie beitragen. Ein neues Plugin kann DSAR-Kategorien beitragen, ohne eine einzige Core-Datei zu ändern. Inaktive Plugins tragen nichts bei (gleiche Semantik wie bisher); Fehler in einem Plugin skippen nur dessen Kategorie (warning + weiter).

Counts-/Category-Keys unverändert (contacts, mail_accounts, ..., contacts_soft_deleted) — API- und Nachrichten-Vertrag stabil.

Verifikation (Live-Messung)

  • Cross-Plugin-Checker: 0 Verstöße (480 Dateien)
  • DSAR-Suite test_g1_dsar.py: 4/4 passed — beweist u.a. dass contacts_soft_deleted via ContactsContract.dsar_erase identisch funktioniert (Art. 17 Soft-Delete) und Collect alle Core-Kategorien liefert
  • create_app() OK · ruff: nur 2 Vorbestand-N811 (PyUUID) verbleiben
  • Zusätzlich: ein durch Patch-Artefakt korrupt gewordenes tasks/contracts.py (unterminated triple-quote, von ast.parse gefangen) komplett sauber neu geschrieben
**Vertiefung nach Review-Einspruch: Plugin-Fachlogik gehört vollständig aus dem Core — umgesetzt.** ## Kritik berechtigt Der erste Fix (`092c2d2`) bog nur den Import-Weg auf Contracts um, aber die Fachlogik (welche DSAR-Kategorien existieren, welche Felder gesammelt/gelöscht werden, mit welchen Limits) lag weiterhin hart im Core. Damit kannte der Core Plugin-Details — gegen die Architektur. ## Die echte Korrektur **Core sammelt/löscht jetzt NUR Core-eigene Daten** (Profil, Audit-Log, Notifications, User-Anonymisierung). Alle Plugin-Kategorien wandern in die besitzenden Contracts: | Contract | Neu | |---|---| | `ContactsContract` | `dsar_collect()` + `dsar_erase()` (Kontakte sind Plugin-eigen — is_core=True heißt Pflichtplugin, nicht Core-Verdrahtung) | | `MailContract` | `dsar_collect()` (mail_accounts) | | `TasksContract` | `dsar_collect()` (tasks) | | `CalendarContract` | `dsar_collect()` (calendar_entries) | | `KommunikationContract` | `dsar_collect()` (comm_messages) | **core/jobs.py** iteriert generisch: `registry.list_discovered()` → `get_contract()` → falls `dsar_collect`/`dsar_erase` vorhanden → Kategorie beitragen. **Ein neues Plugin kann DSAR-Kategorien beitragen, ohne eine einzige Core-Datei zu ändern.** Inaktive Plugins tragen nichts bei (gleiche Semantik wie bisher); Fehler in einem Plugin skippen nur dessen Kategorie (warning + weiter). Counts-/Category-Keys unverändert (`contacts`, `mail_accounts`, ..., `contacts_soft_deleted`) — API- und Nachrichten-Vertrag stabil. ## Verifikation (Live-Messung) - Cross-Plugin-Checker: **0 Verstöße** (480 Dateien) - DSAR-Suite `test_g1_dsar.py`: **4/4 passed** — beweist u.a. dass `contacts_soft_deleted` via ContactsContract.dsar_erase identisch funktioniert (Art. 17 Soft-Delete) und Collect alle Core-Kategorien liefert - `create_app()` OK · ruff: nur 2 Vorbestand-N811 (PyUUID) verbleiben - Zusätzlich: ein durch Patch-Artefakt korrupt gewordenes `tasks/contracts.py` (unterminated triple-quote, von ast.parse gefangen) komplett sauber neu geschrieben
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Leopoldadmin/leocrm#356