Skip to content

Fix(gradebook): la regle 5 (doublons) est sensible a la casse de l'adresse, contrairement au miroir C# #24276

Closed

Description

@jsboige

Sans parent : defaut adjacent decouvert pendant #24246 (meme famille -- chaine non normalisee -- mais perimetre distinct : la regle 5, pas la regle 3).

Constat

La regle 5 de GradeBookApp/gradebook.py (rejet des evaluations doubles, l.262-267) prend l'adresse brute comme cle :

evaluator_id = eval_record.email          # gradebook.py:263
if evaluator_id in seen_evaluators:
    ...
seen_evaluators.add(evaluation.email)     # gradebook.py:273

seen_evaluators est un set Python ordinaire : comparaison sensible a la casse, et aucune normalisation des espaces.

Mesure (2026-11-02, po-2024)

Deux evaluations de la meme personne, adresses ecrites differemment :

a = "Jean.Dupont@example.org"
b = " jean.dupont@example.org "
1re eval acceptee : True
2e  eval acceptee : True      # le doublon passe

Consequence : deux evaluations identiques du meme evaluateur comptent deux fois dans la moyenne du groupe, alors que la regle 5 existe precisement pour l'empecher.

Divergence avec le miroir C#

GradeBookApp/ProjectModel.cs fait la meme detection en insensible a la casse :

var seenEvaluatorsForGroup = new HashSet<string>(StringComparer.OrdinalIgnoreCase);   // l.126
var evaluatorEmail = eval.Email ?? $"{eval.Nom}{eval.Prénom}";                        // l.130

Deux ecarts entre les deux implementations :

Point C# (ProjectModel.cs) Python (gradebook.py)
Casse de l'adresse insensible (OrdinalIgnoreCase) sensible
Espaces autour de l'adresse non normalises non normalises (meme ecart, des deux cotes)
Cle de repli si adresse absente Nom + Prenom (l.130) aucune (l'adresse seule)

Le troisieme point n'est pas mesure comme un defaut : pandas.read_csv rend le singleton np.nan, et l'identite d'objet fait que les lignes sans adresse sont bien vues comme doublons (verifie). Il est cite parce qu'un futur chargement produisant des float('nan') distincts casserait silencieusement la detection.

Correctif propose

Normaliser la cle des deux cotes de la comparaison, sans changer la semantique de rejet :

evaluator_id = str(eval_record.email or "").strip().lower()

(str(...) pour absorber les valeurs non-chaine ; or "" pour le None.)

A verifier avant merge : que .strip().lower() suffit sur les exports reels (colonne Adresse e-mail du formulaire), et que le meme .Trim() est ajoute cote C# pour supprimer le second ecart.

Pourquoi en issue separee

#24246 traite la regle 3 et le rapprochement par noms ; toucher la regle 5 dans la meme PR changerait le decompte des doublons sur les carnets de notes deja calcules, sans rapport avec le defaut corrige. Un sujet par PR.

Criteres d'acceptation

  1. Deux evaluations dont l'adresse ne differe que par la casse ou les espaces de bord sont comptees comme un doublon (test unitaire dans GradeBookApp/).
  2. Deux evaluations d'adresses reellement differentes restent acceptees (controle negatif).
  3. La decision sur le troisieme ecart (cle de repli Nom + Prenom cote Python, comme l.130 du C#) est ecrite dans la PR : alignee ou explicitement refusee.

Activity

  1. jsboige commented on Nov 2, 2026

    @jsboige
    OwnerAuthor

    [CLAIMED] lane myia-po-2024:CoursIA -- normaliser la cle de doublon de la regle 5 (strip + lower) et aligner le repli sur le miroir C# -- paths: GradeBookApp/gradebook.py, GradeBookApp/test_project_name.py

  2. jsboige commented on Nov 2, 2026

    @jsboige
    OwnerAuthor

    [DELIVERED] lane myia-po-2024:CoursIA -- PR #24281 — clé de la règle 5 normalisée (casse + espaces de bord) et repli sur Nom + Prénom quand l'adresse manque ; miroir C# aligné (.Trim() + IsNullOrWhiteSpace) — paths: GradeBookApp/gradebook.py, GradeBookApp/ProjectModel.cs, GradeBookApp/test_evaluator_key.py

    Les trois critères d'acceptation sont couverts :

    1. Doublon sur casse / espaces — filter_evaluations conserve une seule des deux évaluations Jean.Dupont@… et jean.dupont@… (tests de bout en bout, pas seulement unitaires).
    2. Contrôle négatif — deux adresses réellement différentes restent acceptées, y compris jean.dupont@ vs jean.dupont2@.
    3. Troisième écart : aligné, pas refusé — repli Nom + Prénom comme ProjectModel.cs:130, avec la raison mesurée : sans lui, toutes les lignes sans adresse partagent une clé unique et une seule évaluation est retenue par groupe. Le C# gagne au passage la couverture de l'adresse vide (""), qui collapsait aussi.

    Mesures : 36 tests verts côté Python (dont 21 nouveaux), dotnet build 0 erreur. Contrôle négatif sur le gradebook.py d'origin/main : 8 échecs comportementaux, les cas qui portent le défaut.

    Écart résiduel signalé dans la PR et non corrigé : une ligne avec adresse et une ligne du même évaluateur sans adresse restent deux clés distinctes — comportement identique au C#, et le corriger changerait la sémantique de la règle 5.

    La clôture revient au coordinateur (Closes #24276 dans le body de la PR).

  3. added a commit that references this issue on Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions