getStudentsWithoutAssignment missing ur.deletedAt IS NULL -- 6 of 7 rows on the live student-assignment picker are reclassified docentes/admins, not students
MEASURED 2026-07-31 (read-only, prod). src/lib/admin-actions.ts getStudentsWithoutAssignment joins userRoles with NO ur.deletedAt IS NULL, so a user whose alumno role was REVOKED still lists as an assignable unassigned student. LIVE EXPOSURE on the only active periodo (2026 Anual): live query returns 7 rows, correct query returns 1 -- 6 of 7 (86%) are phantoms. All 6 are people deliberately reclassified OUT of alumno and now holding another ACTIVE role: 5 docente_ayudante_primera, 1 administrador. Revocations are explicit and reasoned (admin:user:revokeRole 'no es alumno'; ticket-0bcef08e vargasGiron-alumno-to-ayudante; support:SOP-4 Elazar-authorized student->docente reclassification; WI#139 role corrections). CONSEQUENCE: an admin on the student-assignment picker is offered 6 teachers/admins as assignable students and 1 real student; assigning one writes a studentAssignments row for a docente. Corpus: 8 revoked alumno userRoles total, 6 on live users (2 on soft-deleted users, already excluded by vUsers). 0 users hold both an active and a revoked alumno row, so no duplicate-row effect today -- but the same missing predicate would double-list any such user. FIX already written and audit-PASSed as PLUTO-665 lane A: fn_getStudentsWithoutAssignment (migration 089, live) carries the active-role predicate, so moving the caller to the fn corrects it. This WI exists so the correction ships attributable rather than as an unremarked side effect of the postgres-boundary refactor (pm-pluto-cc decision 2026-07-31). Same class as PLUTO-640 (raw userRoles reads missing soft-delete filter) and the PLUTO-639 orphaned-role hygiene tail. NOT MEASURED: whether any existing studentAssignments row was already created for one of these 6 via this path -- worth a follow-on check.
Questions
Activity
-
Follow-on check CLOSED, read-only prod 2026-07-31: ZERO live studentAssignments rows are held by a user lacking an active alumno role (0 rows; filter sa.deletedAt IS NULL AND u.deletedAt IS NULL, NOT EXISTS active alumno userRole). The picker offered the 6 phantoms but no admin ever assigned one. Coverage limit: point-in-time read of CURRENT role state on LIVE rows only -- cannot see an assignment created while the user was still an alumno, nor one since soft-deleted.
-
getStudentsWithoutAssignment missing active-role predicate: 6/7 phantom rows on student-assignment picker (docentes/admin offered as assignable students). Zero live studentAssignments rows created through the gap (verified). Fixed in 406a16f as part of PLUTO-665 lane A.
-
Shipped in 406a16f / v2.22.42 (PLUTO-665 lane A). getStudentsWithoutAssignment now calls fn_getStudentsWithoutAssignment (mig 089), which carries the active-role predicate the inline query lacked. Audit PASS re-confirmed by audit-pluto-ca with the behaviour change explicitly recorded as intentional. PTD: live /api/app-version served 2.22.42 then 2.22.43, deploy READY on correct SHA, prod alias present, build clean, 0 runtime errors in 1h.
-
Fixed and live at 406a16f. Picker no longer lists revoked-alumno users: was 7 rows / 6 phantoms on the active periodo, now 1 correct row. Zero remediation needed -- no studentAssignments row had ever been written for any of the 6. Coverage limit on that check retained in the verified event (current role state, live rows only).