mars
MARS-136
Re-key grading attribution to práctica-pick (jtpUserId) — reverses live-SA model
Done normal
cmcoder02-mars-cc
Activity
-
Elazar ruling 2026-06-16 (aro:mars): 'real life is SSOT, golden rule for Mars.' Canonical grading attribution = the práctica pick (práctica.jtpUserId = whoever the student selected as JTP/Docente on that práctica), NOT studentAssignments.assignedTeacherUserId. The attributions/SA table is DEMOTED: maintained but NO grading/KPI/credit decisions made from it. Whoever was picked as JTP/Docente on a práctica grades it + gets KPI/credit; an ayudante picked into the JTP slot counts as the JTP. Adjunto chases the picked person on ungraded. REVERSES feedback_live_vs_snapshot_attribution; AFFIRMS feedback_ayudante_pickable_as_jtp. Scope is system-wide (KPI Adjunto/Titular emails + grading-attribution drills + any surface deciding grading from assignedTeacherUserId). Stage: KPI email first (live complaint), other surfaces follow. Runway: next KPI cron send Mon 2026-06-22 (Mon Jun 15 was AR holiday). Interim 8e2563e all-0 suppression stays live (harmless under new rule). Plan: coder+db design/scope-map -> audit design review -> staged implement -> cross-review + PTD. Memories to update on ship: reverse feedback_live_vs_snapshot_attribution, adjust feedback_jtp_only_grading_responsibility.
-
DESIGN COMPLETE (pre-compact checkpoint), build NOT started — held pending Elazar Q1-Q4 + audit re-review of revised design. MODEL VALIDATED: practicas.jtpUserId IS a genuine student pick — required+validated field in practicas/nueva (practica-form.tsx L401, actions.ts L369-397), pre-filled from SA assignedJtp but student-overridable (the override is how ayudante-as-JTP happens); SA only last-resort fallback for blank, prevented by required-guard. Premise safe. STAGING: S0 (gates all) = retire write-path clobber replayOpenPracticaJtpToSa (practica-jtp-sync.ts) — it UPDATEs practicas.jtpUserId=newSA on every reassign, clobbering the canonical pick; FIX = backfill jtpUserId where IS NULL only, NEVER overwrite non-null, STOP touching ayudanteUserId (MARS-60), query practicas directly not vPracticasSinEvaluar (circular), unwire at updateAlumno/reassignTeacher/fixAssignmentJtp/fixAssignmentAyudante + create-cascade. S1 getJtpStats PENDING-axis + admin-delta jtp_pra flip to pr.jtpUserId (roster studentCount STAYS SA). S2 getScopedPracticas x2 (practica.ts+alumnos.ts) — flip ONLY the attribution predicate to vp.jtpUserId, access-scope EXISTS-on-SA predicate STAYS (visibility regression risk). S3 weekly-kpi ADJUNTO/TITULAR re-key inclusion=Adjuntos UNION pickers(jtpUserId) + counts by pick; removes need for 8e2563e suppress (left harmless). DB (db-mars, rides coder push, re-export schema.md+reference-data): vPracticasSinEvaluar rekey SA->pr.jtpUserId (ZERO row delta confirmed); vHealthPracticasStale DROP only stale_jtp branch (105 now-expected false-pos), keep ayudante branch; vComisionStudentsByJtp + vComisionAyudantesByJtp NO CHANGE (display-only/no-consumer, STAY SA). OPEN: Q1 graded-axis (rec A: graded keys on pick by approvalState), Q2 4 non-TCM pickers (rec A surface+flag a-solucionar), Q3 Adjunto-dual-role (rec A show both labeled), Q4 roster display stays SA (rec A) — all sent to Elazar lettered. Interim 8e2563e (v2.16.59 all-0 suppress) LIVE+PASS. Runway: next KPI cron Mon 2026-06-22. On ship: update feedback_jtp_only_grading_responsibility per Q1 outcome.
-
coder02-mars-cc
-
ALREADY SHIPPED - closing on sight per pmmaster's instruction, verified against the deployed code and not against bwi status. All four staged legs from this row's own design note landed on 2026-06-16, each an ancestor of origin/main: S0 b08b3bf - retired the SA->practica jtpUserId replay; src/lib/practica-jtp-sync.ts:6 now states the pick is canonical, and src/lib/data-health-actions.ts:63,91 carry the do-NOT-replay guards on both the jtp and ayudante paths. The clobbering write this row was gated on no longer exists in the tree: grep for replayOpenPracticaJtpToSa across src/ returns nothing. S1 a1054fd - getJtpStats PENDING axis + admin-delta keyed on the pick (src/lib/reporting.ts:224, src/lib/admin-delta-report.ts:56-68 join users on p.jtpUserId). The commit subject records Q1 as ANSWERED =B: graded stays reviewedBy, so the open design question this row was also waiting on is resolved in the shipped code rather than still pending. S2 9b8f2b2 - getScopedPracticas mias/no-mias noRevisado attribution on vp.jtpUserId with the access-scope predicate deliberately unchanged (src/lib/practica.ts:388,1010). S3 79edecc - weekly-kpi JTP/Adjunto/Titular digests re-keyed to the pick, ayudante-as-JTP counted, not-in-TCM rendered 'Sin rol' (src/lib/weekly-kpi.ts:96,156,225 + weekly-kpi-templates.ts:183,252). That covers the Q2 non-TCM-picker surfacing and the Q3 dual-role labelling in the digest, which is where this row said they mattered. Q4 (roster display stays SA) is also honoured rather than forgotten: src/lib/alumnos.ts:173 still groups the roster on the isPrimary/pickedRole='jtp' teacher row, which is the SA-side key, exactly as the design said it should stay. NOT verified: no browser walkthrough and no query of live attribution rows - what is established is that every code path this row enumerated now reads the pick, on commits published to main.
feature
2026-06-16 by wi-cli-venus
5w ago
2026-09-11 17:07