Übersicht: Empfehlung nur aus AKTUELLER Leistung (Recency)
Denkfehler behoben — eine Empfehlung reagiert auf das Zuletzt-Gesehene, nicht auf einen Allzeit-Rückblick. live.php cockpit liefert jetzt recentErfolg (Ø letzte 3 Läufe), earlyErfolg (frühere Läufe), daysSince, recentPlays. Triage rechnet darauf: >14 Tage weg → Nachfassen; recent schwach → Fördern; recent+viel → Begleiten; recent stark, kaum gefordert → Fordern; recent > früher → Bestätigen. Neue Spalte „Zuletzt", Legende erklärt: Erfolg = letzte Läufe, Verlauf = nur Historie. 4b-Daten mit kontrollierter Recency neu (jede Gruppe besetzt). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -605,6 +605,39 @@ if ($method === 'GET') {
|
||||
$benchByStudent[$sid]['n']++;
|
||||
}
|
||||
|
||||
// 4b) RECENCY — Grundlage für die Interventions-Empfehlung: nur die AKTUELLE
|
||||
// Leistung zählt (kein Allzeit-Rückblick). Aus student_results:
|
||||
// recentErfolg = Ø der letzten 3 Läufe · daysSince = Tage seit letztem Lauf
|
||||
// recentPlays = Läufe der letzten 14 Tage
|
||||
$recentByStudent = [];
|
||||
foreach ($db->fetchAll(
|
||||
"SELECT student_id,
|
||||
DATEDIFF(NOW(), MAX(completed_at)) AS days_since,
|
||||
SUM(completed_at >= NOW() - INTERVAL 14 DAY) AS recent_plays
|
||||
FROM student_results WHERE class_id = ? GROUP BY student_id",
|
||||
[$classId]) as $r) {
|
||||
$recentByStudent[(int)$r['student_id']] = [
|
||||
'daysSince' => $r['days_since'] !== null ? (int)$r['days_since'] : null,
|
||||
'recentPlays' => (int)$r['recent_plays'],
|
||||
'recentErfolg' => null,
|
||||
];
|
||||
}
|
||||
foreach ($db->fetchAll(
|
||||
"SELECT student_id,
|
||||
ROUND(AVG(CASE WHEN rn <= 3 THEN score END)) AS recent_erfolg,
|
||||
ROUND(AVG(CASE WHEN rn > 3 THEN score END)) AS early_erfolg
|
||||
FROM (
|
||||
SELECT student_id, score,
|
||||
ROW_NUMBER() OVER (PARTITION BY student_id ORDER BY completed_at DESC, id DESC) rn
|
||||
FROM student_results WHERE class_id = ?
|
||||
) x GROUP BY student_id",
|
||||
[$classId]) as $r) {
|
||||
$sid = (int)$r['student_id'];
|
||||
if (!isset($recentByStudent[$sid])) $recentByStudent[$sid] = ['daysSince'=>null,'recentPlays'=>0,'recentErfolg'=>null];
|
||||
$recentByStudent[$sid]['recentErfolg'] = $r['recent_erfolg'] !== null ? (int)$r['recent_erfolg'] : null;
|
||||
$recentByStudent[$sid]['earlyErfolg'] = $r['early_erfolg'] !== null ? (int)$r['early_erfolg'] : null;
|
||||
}
|
||||
|
||||
// 5) needsHelp-Heuristik aus Live-State (pro aktivem Schüler:in)
|
||||
$needsHelp = function($simId, $state) {
|
||||
if (!is_array($state)) return false;
|
||||
@@ -701,6 +734,10 @@ if ($method === 'GET') {
|
||||
'lastSeen' => $lastSeen,
|
||||
'lastSeenTs' => $lastSeen ? strtotime($lastSeen) : null,
|
||||
'benchmarkPct' => $bench,
|
||||
'recentErfolg' => $recentByStudent[$sid]['recentErfolg'] ?? null,
|
||||
'earlyErfolg' => $recentByStudent[$sid]['earlyErfolg'] ?? null,
|
||||
'daysSince' => $recentByStudent[$sid]['daysSince'] ?? null,
|
||||
'recentPlays' => $recentByStudent[$sid]['recentPlays'] ?? 0,
|
||||
'activeSim' => $active ? $active['module_id'] : null,
|
||||
'activeSimName'=> $active && isset($moduleMap[$active['module_id']]) ? $moduleMap[$active['module_id']]['title'] : null,
|
||||
'activeSimIcon'=> $active && isset($moduleMap[$active['module_id']]) ? $moduleMap[$active['module_id']]['icon'] : null,
|
||||
|
||||
Reference in New Issue
Block a user