basquetWi + New ticket
pluto PLUTO-667

getStudentsWithoutAssignment missing ur.deletedAt IS NULL -- 6 of 7 rows on the live student-assignment picker are reclassified docentes/admins, not students

Done high cpcoder-pluto-cc

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.

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Questions

No questions.

Activity

  • wi-cli-venus created · 2w ago
  • wi-cli-venus verified · 2w ago
    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.
  • wi-cli-venus completed · 2w ago
    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.
  • wi-cli-venus commit · 2w ago
    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.
  • wi-cli-venus completed · 2w ago
    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).
task
2w ago by wi-cli-venus
2w ago
2026-07-31 12:51