model.mjs: état versionné, calculs, validation, CSV, collage et listes d’élèves.app.mjs: interface, historique (60 modifications), sauvegarde locale, clavier.style.css: styles isolés par le préfixe bm.- Page Astro :
/outils/feuille-bareme.
Le mode relatif/absolu concerne les questions ; les compétences restent indépendantes et les ajustements sont toujours des points directs. Les bonus et les barèmes négatifs n’augmentent pas le maximum. Seule la somme finale est bornée à zéro. Les conversions utilisent la somme avant arrondi. Les statistiques portent sur les notes affichées, avec écart-type d’échantillon et quartiles interpolés.
Le CSV v2 utilise le point-virgule, des champs entre guillemets et un BOM UTF-8. La première colonne contient la structure sur la deuxième ligne, puis {id,reportId,nullValues} sur chaque ligne élève. nullValues conserve les valeurs explicitement nulles, distinctes des cellules absentes et des zéros. Le commentaire est une dernière colonne texte éditable, après les trois notes calculées. Noms, classes, libellés et commentaires sont préfixés par une apostrophe contre les formules de tableur ; les notes calculées sont ignorées à l’import. Les retours à la ligne et guillemets sont conservés.
importCSV lit v1/v2 sans migration implicite, vérifie la concordance marqueur/version et retourne la version lue. exportCSV préserve la version reçue ; l’interface travaille uniquement en v2. Une ancienne application v1 ne peut pas reprendre un CSV v2. Conserver un ancien export avant migration si un retour au logiciel antérieur est nécessaire. Les listes d’élèves acceptent TXT/CSV/TSV, nom complet et classe facultative. Pas de lecture XLSX native.
La clé locale est esuong-bareme-v1. Une seule feuille est conservée par navigateur ; le CSV permet de conserver plusieurs évaluations. Aucun résultat n’est envoyé à un serveur. Limites : 500 élèves, 200 critères, 100 exercices, fichiers de 5 Mo. Pour une utilisation simultanée, éviter plusieurs onglets modifiant la même feuille.
Tests : node --test tests/bareme.test.mjs.
Les cellules acceptent tout nombre fini (décimales, négatifs, dépassements) ; le relatif applique toujours valeur × points / 4. Les compétences hors des niveaux entiers 0–3 sont conservées, signalées séparément et exclues de la répartition colorée. La conversion vers le relatif accepte les décimales ; un barème nul avec des points absolus non nuls reste non convertible.
grid.mjs définit les colonnes sélectionnables, la copie tabulée avec virgules décimales et les parcours clavier. Les notes finales précèdent les exercices et restent en lecture seule. Entrée parcourt les colonnes, Tab les lignes, Maj inverse le parcours ; aux extrémités de la feuille, le focus reste sur la dernière cellule accessible. Le cliquer-glisser et Maj + clic/flèches sélectionnent des rectangles. Les sous-totaux des exercices sont inclus dans la sélection, la copie et le parcours clavier, en lecture seule. Le tableau des statistiques utilise la même sélection rectangulaire, libellés compris ; la copie reproduit les nombres affichés (trois décimales maximum) au format tabulé.
Document v2 et migration (lot B)
Champs ajoutés : assessmentId (UUID), revision (entier positif), createdAt (instant UTC canonique), subjectLabel, assessmentType, coefficient. Chaque élève conserve son id local et reçoit un reportId UUID et comment (10 000 caractères maximum). Matière/type : 500 caractères maximum ; coefficient fini non négatif, 1 par défaut, zéro et décimaux conservés. Le champ historique date reste la date d’évaluation. Matière/type/date peuvent rester vides en cours de saisie, mais sont requis pour extraire un bilan. Le coefficient ne modifie aucun calcul ou statistique.
validate accepte v1 et v2 sans transformer son entrée. Ce maintien de v1 est indispensable : student/contracts.mjs::validateReport construit toujours un document v1 et utilise les mêmes fonctions grade et points. Le socle et le contrat public n’ont pas été modifiés ; bareme-v1 reste la convention de calcul.
migrateDocument(v1, {assessmentId,createdAt,revision?,reportIds}): migration pure, identité fournie explicitement, copie validée. Défauts : coefficient absent → 1, commentaire absent → vide, matière/type absents → vide. Ne modifie aucun identifiant existant d’exercice/colonne/élève. Déjà v2 : copie inchangée, idempotente.upgradeDocument(document, reuse = null): allocation à la frontière de l’application. Nouvelle identité pour un v1 ; sauvegarder le résultat immédiatement.reuseest réservé à un rattachement confirmé à une feuille v2 : reprend assessmentId/createdAt et reportIds des mêmes ids élèves, sans rapprochement par nom. Les métadonnées absentes du v1 reprennent celles de la feuille choisie, mais les anciens résultats/commentaires sont remplacés par le fichier.- Chargement local : migration v1 puis sauvegarde immédiate sous la même clé
esuong-bareme-v1. Si lecture/validation échoue, l’ancienne sauvegarde n’est pas écrasée. Si l’écriture échoue, avertissement et export CSV nécessaire pour conserver les nouvelles identités. - Import v1 : dialogue proposant une nouvelle évaluation ou le rattachement à la feuille courante ; annulation possible. Aucun rattachement automatique par titre. Import v2 : identité portée par le fichier. Import et migration terminent avant remplacement.
reviseDocument(previous,candidate,minimumRevision)incrémente la révision lors d’une modification de la même évaluation. L’interface garde les plus hautes révisions rencontrées dans l’historique pour Annuler/Rétablir, y compris entre deux feuilles. Un export seul ne change pas la révision. Reprendre un ancien CSV de la même évaluation avance la révision. Deux copies modifiées indépendamment restent susceptibles de conflit : le futur distributeur doit gérer ce cas, sans supposer ces révisions globalement synchronisées.
Extraction individuelle
report.mjs::extractReport(documentV2, studentId) est pure, sans stockage ni réseau. Elle construit une enveloppe assessmentReport, puis appelle le vrai validateReport et renvoie sa copie validée. Identités, révision et createdAt viennent du document enregistré ; aucun UUID ni horodatage n’est généré lors de l’extraction. Le reportId reste stable quand le nom, l’ordre ou les résultats changent. Supprimer/recréer une ligne crée un nouveau bilan.
L’extraction sélectionne explicitement la définition et le seul résultat demandé. Ni noms, ni classe, ni id élève local, ni codes, ni autres élèves. Le commentaire est du texte inerte et doit rester échappé par tout lecteur. Les libellés et commentaires saisis par le professeur peuvent naturellement contenir des informations personnelles : l’extraction n’en fait pas une anonymisation sémantique.
Sous-totaux : somme brute non arrondie de points, y compris négative et zéro pour un exercice de compétences ; null si absent. Grade : résultat exact de grade, null si absent ou compétences seules. Valeurs manquantes/nulles/zéro conservées. Dépassements numériques non finis refusés par le socle. Libellés vides ou identifiants réservés incompatibles avec le socle sont refusés à l’extraction, sans altérer la feuille locale.
L’onglet « Bilans individuels » permet la saisie et le téléchargement explicite JSON d’un bilan, nommé avec son reportId. Il ne publie rien. Le futur lot D peut appeler cette fonction après import/migration sans toucher à la feuille de travail ; il doit conserver la feuille migrée et ses identités dans son propre stockage. Pas d’annuaire/code élève, de moyenne inter-évaluations ou de serveur dans ce lot.
Vérifications lot B
node --test tests/bareme*.test.mjs tests/boxplot-state.test.mjs couvre migrations, CSV, coefficient 0/décimal, commentaires multiligne, identités, révisions, absence, valeurs nulles, compétences hors plage, arrondis, bonus, ajustements, et extraction avec le validateur réel. Voir le compte rendu docs/BAREME_PUBLIC_LIVRAISON.md pour les tests réellement exécutés et les limites.
Périmètre public préparé le 29 octobre 2026
Les deux modules purs student/contracts.mjs et student/validation.mjs sont repris sans modification de f68542e pour valider les bilans. Aucun écran, stockage élève, endpoint serveur ou outil de distribution QR n’est livré. Le bouton de distribution est absent ; seul le téléchargement explicite JSON reste proposé. La présence des validateurs ne rend pas les autres fonctions du socle disponibles.