feat: Untis-Hub-Kadenzkopplung, anpassbarer Statusvorschlag + KI-/MCP-Unterstuetzung beim Fehlzeitenabgleich (Nutzer-Feedback)
CI / build-and-test (push) Canceled after 0s
CI / build-and-test (push) Canceled after 0s
- UntisHubService.RecordRun: ein abgeschlossener Langzeit-Fehlzeitenabgleich schliesst die kurzfristige Kadenz derselben Gruppe automatisch mit ab (nicht umgekehrt). - Fehlzeitenabgleich-Dialog: neue "Uebernahme als"-ComboBox statt starrem Zielstatus, vorbelegt mit dem berechneten Vorschlag, aber frei aenderbar. - Neuer ai-backend-Endpunkt untis-status.php + AiPlanningService.RequestUntisStatusSuggestionsAsync: gebuendelter, anonymisierter KI-Statusvorschlag (nur Positions-Id + Rohsignale, nie Name/Klasse/ Datum), mit hartem Id-Mengen-Abgleich gegen Verwechslung. - Neue MCP-Tools (UntisComparisonTools): get_untis_hub_status, get_untis_absence_rows/ apply_untis_absence_status (anonymer Weg ueber ENr-Zuordnung) sowie get_named_untis_absence_pattern als bewusste, eng begrenzte Ausnahme (Name+Fehlzeiten fuer explizit angegebene Schueler-IDs, mit Bestaetigung ohne Sitzungsfreigabe - dafuer IMcpConfirmationService.ConfirmAsync um allowSessionTrust erweitert). - MapStatus/ENr-Zuordnung aus dem ViewModel in das neue, geteilte UntisLessonAbsenceHelper gezogen, damit Dialog und MCP-Tool nie unterschiedliche Statusvorschlaege berechnen. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2023,6 +2023,69 @@ WebUntis auffallen").
|
||||
Der Fehlzeitenabgleich-Button in der einzelnen Lerngruppe (`GroupDetailView`) blieb unverändert,
|
||||
da kontextgebunden.
|
||||
|
||||
**Nachtrag zum Untis-Hub (September 2026):** Nutzer-Feedback aus der ersten echten Nutzung — fast
|
||||
alle Zeilen liefen anfangs noch nie, dabei fiel auf, dass ein soeben abgeschlossener Langzeit-
|
||||
Fehlzeitenabgleich die kurzfristige Kadenz derselben Gruppe unverändert als fällig stehen ließ,
|
||||
obwohl deren Zeitfenster (seit Schuljahresbeginn) das kurzfristige (letzte 14 Tage) als Teilmenge
|
||||
vollständig enthält.
|
||||
- `UntisHubService.RecordRun` schließt bei `FehlzeitenLang` jetzt automatisch auch
|
||||
`FehlzeitenKurz` derselben Gruppe mit demselben Zeitstempel ab (eigener `LastResultSummary`-Text
|
||||
"durch Abgleich seit Schuljahresbeginn mit erledigt"). Nicht symmetrisch: ein Kurz-Lauf deckt das
|
||||
lange Fenster nicht ab und lässt `FehlzeitenLang` deshalb unangetastet.
|
||||
- Im Fehlzeitenabgleich je Unterricht ([WebUntisLessonAbsenceComparisonViewModel.cs](LehrerApp.Desktop/ViewModels/Groups/WebUntisLessonAbsenceComparisonViewModel.cs))
|
||||
war der aus dem WebUntis-Datensatz abgeleitete Zielstatus (`MapStatus`) bisher nur als Text
|
||||
sichtbar und wurde 1:1 übernommen oder gar nicht — Nutzer-Feedback: der Status-String aus WebUntis
|
||||
ließ oft nicht erkennen, wohin die automatische Übernahme führt, eine Zeile wurde deshalb öfter
|
||||
abgelehnt und der Status danach manuell außerhalb des Dialogs nachgetragen. Spalte "Übernahme als"
|
||||
ist jetzt eine ComboBox (`WebUntisLessonAbsenceRow.StatusOptions`/`SelectedStatusName`, gleiches
|
||||
String-Wrapper-Muster wie `GradeCategoryDisplay`), vorbelegt mit dem berechneten Zielstatus, aber
|
||||
vor dem Übernehmen frei auf einen von sechs plausiblen Status änderbar (die WebUntis hier nie
|
||||
meldet — "Geschwänzt", "Suspendiert" usw. — bleiben bewusst außen vor).
|
||||
- KI-gestützter Statusvorschlag über das bestehende ai-backend (bisher nur für die
|
||||
Unterrichtsplanung genutzt) ergänzt: neuer Endpunkt `ai-backend/untis-status.php` (gleiches
|
||||
Auth-/Abrechnungsmuster wie `explain.php`) und `AiPlanningService.RequestUntisStatusSuggestionsAsync`.
|
||||
Bewusst ohne jeden Personenbezug im Payload (Nutzer-Vorgabe: "keimfrei", solange kein Name
|
||||
mitgeschickt wird) — jede Zeile bekommt nur eine rein technische Positions-Id sowie die
|
||||
strukturierten Rohsignale (Fehlminuten, "bereits bearbeitet"-Kennzeichen, ENr-Klammerung) und den
|
||||
Freitext-Grund, nie Name/Klasse/Datum. Alle fraglichen Zeilen eines Abgleichslaufs gehen in
|
||||
**einer** gebündelten Anfrage raus statt je Zeile einzeln (Kosten/Latenz-Überlegung aus der
|
||||
Nutzerdiskussion — der Fix-Overhead pro Anfrage dominiert sonst die kurze Nutzlast). Gegen
|
||||
Verwechslung (Nutzer-Sorge: "die KI könnte was vermischen") wird nicht auf Reihenfolge vertraut,
|
||||
sondern hart auf Id-Mengengleichheit geprüft — weicht die zurückgegebene Id-Menge auch nur
|
||||
minimal ab (fehlend/zusätzlich/doppelt), wird die gesamte Antwort verworfen, siehe die vier neuen
|
||||
Tests in `AiPlanningServiceTests.cs`. Der Vorschlag setzt nur die "Übernahme als"-ComboBox vor
|
||||
(neuer Button "KI-Vorschlag für Übernahme laden" im Fehlzeitenabgleich), übernimmt nie
|
||||
eigenständig etwas — "Markierte übernehmen" bleibt der einzige schreibende Schritt.
|
||||
- MCP-Zugriff von außen auf die Untis-Abgleiche umgesetzt, zweigleisig wie vom Nutzer entschieden —
|
||||
neue Klasse [UntisComparisonTools.cs](LehrerApp.Desktop/Services/Mcp/Tools/UntisComparisonTools.cs):
|
||||
- `get_untis_hub_status` (Read): reine Delegation an `UntisHubService.GetRows()`, kein eigener
|
||||
WebUntis-Zugriff.
|
||||
- `get_untis_absence_rows`/`apply_untis_absence_status` (bevorzugter, anonymer Weg): eine rein
|
||||
technische `row-id` (In-Memory, pro Prozesslaufzeit) ordnet zurück, nie ein Schülername verlässt
|
||||
die App. Nur Zeilen, die WebUntis über die externe Schülernummer (ENr) eindeutig einem
|
||||
Kursmitglied zuordnet, werden überhaupt gelistet — die namensbasierte Fallback-Zuordnung des
|
||||
interaktiven Dialogs bleibt dafür bewusst außen vor (eine autonome KI-Schreibaktion ohne Mensch,
|
||||
der eine Namensauflösung visuell gegenprüft, wäre sonst riskanter als im Dialog). Das schreibende
|
||||
Tool bestätigt wie jedes andere Write-Tool, die Bestätigungsmeldung nennt aber bewusst nur Datum/
|
||||
Lerngruppe/Zielstatus, nie den Namen.
|
||||
- `get_named_untis_absence_pattern` (bewusste, eng begrenzte Ausnahme von der sonst in
|
||||
`McpToolScope.cs` beschriebenen Regel): verknüpft Name UND Fehlzeiten für explizit angegebene
|
||||
Schüler-IDs, z.B. für einen Fehlmuster-Vergleich zwischen zwei Schülern — Datensparsamkeit über
|
||||
den Aufrufparameter (nur die angefragten IDs, nicht der ganze Kurs) statt einer Auswahl-UI, um
|
||||
keinen weiteren Dialogtyp einzuführen. Erfordert JEDES MAL eine gesonderte Bestätigung ohne
|
||||
Sitzungsfreigabe (neuer Parameter `allowSessionTrust` auf `IMcpConfirmationService.ConfirmAsync`,
|
||||
Standard weiterhin `true` für alle bestehenden Write-Tools) — `AvaloniaMcpConfirmationService`
|
||||
prüft und setzt die Sitzungsfreigabe dafür gar nicht erst, `McpConfirmDialog` blendet die beiden
|
||||
"nicht mehr nachfragen"-Kontrollkästchen für diesen Fall aus.
|
||||
- `MapStatus`/die ENr-Zuordnung wurden aus `WebUntisLessonAbsenceComparisonViewModel` in das neue,
|
||||
framework-freie `UntisLessonAbsenceHelper` (LehrerApp.Desktop/Services/) verschoben, damit Dialog
|
||||
und MCP-Tool niemals unterschiedliche Statusvorschläge für dieselbe Fehlzeile berechnen.
|
||||
- Bewusst ohne Tests für `GetUntisAbsenceRows`/`GetNamedUntisAbsencePattern` gelassen (gleiche
|
||||
Begründung wie bei den drei bestehenden Abgleichs-ViewModels: brauchen einen echten WebUntis-
|
||||
JSON-RPC-Zugriff) — `GetUntisHubStatus` und die Validierungspfade von `ApplyUntisAbsenceStatus`
|
||||
(unbekannter/nicht zulässiger Status, unbekannte/abgelaufene row-id, jeweils ohne Bestätigung
|
||||
erreicht) sind in `UntisComparisonToolsTests.cs` abgedeckt.
|
||||
|
||||
### 4.4 Wochen-/Tagesansicht
|
||||
- [x] **4.4.1** Kalenderansicht über alle Gruppen: Woche und Tag — siehe Nachtrag zu 4.3
|
||||
("Heute"-Tab: Tagesliste unten angedockt, gruppenübergreifendes Wochenraster darüber, inkl.
|
||||
|
||||
Reference in New Issue
Block a user