Chapitre 4.3 — Le modèle de données CMI
⏱️ TL;DR — Entre l’ouverture et la fermeture de session, ton SCO lit et écrit un ensemble de champs standardisés : le modèle de données CMI. Chaque champ a un nom en notation pointée (
cmi.core.lesson_status,cmi.completion_status…), un type attendu, et un droit d’accès : certains sont en lecture seule (l’identité de l’apprenant, fournie par le LMS), d’autres en écriture (le statut, le score), quelques-uns en écriture seule (la durée de session). On accède à tout par deux méthodes seulement :GetValue(elt)pour lire,SetValue(elt, val)pour écrire. Le vocabulaire change entre 1.2 et 2004 — c’est la source d’erreur n°1 quand on porte un contenu d’une version à l’autre. Ce chapitre te donne les éléments clés des deux versions et leurs droits d’accès.
🎯 Objectifs
- Comprendre la structure
cmi.*en notation pointée et la notion de collection (cmi.objectives.n.*). - Lire et écrire avec
GetValue/SetValue(et leurs préfixesLMSen 1.2). - Connaître les éléments clés de SCORM 1.2 et de SCORM 2004, avec leurs droits d’accès.
- Ne plus confondre
cmi.core.lesson_status(1.2) et le couplecmi.completion_status+cmi.success_status(2004).
Un dictionnaire à notation pointée
Le modèle CMI est un dictionnaire de champs nommés hiérarchiquement. Le préfixe est toujours cmi ; le reste décrit la donnée : cmi.core.score.raw = « le score brut, dans le sous-ensemble core ». Tout se lit et s’écrit avec deux verbes :
// SCORM 1.2 : méthodes préfixées LMS
const nom = api.LMSGetValue("cmi.core.student_name"); // lecture
api.LMSSetValue("cmi.core.score.raw", "85"); // écriture
// SCORM 2004 : mêmes verbes sans le préfixe LMS
const nom2 = api.GetValue("cmi.learner_name");
api.SetValue("cmi.score.raw", "85");Trois principes valent pour tout le modèle :
- Les valeurs sont des chaînes.
SetValueattend unestring."85", pas85;"completed", pas un booléen. Le LMS validera le type logique (nombre, vocabulaire fermé…) mais l’échange se fait en texte. - Certains champs sont des collections indexées.
cmi.objectives.n.id,cmi.interactions.n.result: lenest un indice (0,1,2…). On lit le nombre d’éléments via un champ_countet on écrit en incrémentant l’indice. - Chaque champ a un droit d’accès. Lecture seule (RO), lecture-écriture (RW), ou écriture seule (WO). Écrire un RO ou lire un WO échoue avec une erreur dédiée (chapitre 4.5).
⚠️ Piège — Écrire dans un champ en lecture seule, typiquement
cmi.core.student_name. C’est le LMS qui te donne l’identité de l’apprenant ; tu la lis, tu ne la poses pas. UnSetValuedessus renvoiefalseet pose l’erreur « element is read only ». Même logique inverse pourcmi.core.session_time(écriture seule) : tu l’écris, tu ne le relis pas.
Les éléments clés de SCORM 1.2
Sous-ensemble cmi.core pour l’essentiel de l’exécution, plus quelques champs hors core.
| Élément (SCORM 1.2) | Accès | Rôle |
|---|---|---|
cmi.core.student_id | RO | Identifiant de l’apprenant (fourni par le LMS). |
cmi.core.student_name | RO | Nom de l’apprenant. |
cmi.core.lesson_status | RW | Le statut : passed, completed, failed, incomplete, browsed, not attempted. |
cmi.core.score.raw | RW | Score brut (souvent 0–100). |
cmi.core.score.min | RW | Borne basse du score. |
cmi.core.score.max | RW | Borne haute du score. |
cmi.core.lesson_location | RW | Signet : où reprendre (page, écran…). |
cmi.core.entry | RO | Contexte d’entrée : première fois vs reprise. |
cmi.core.exit | WO | Comment on quitte : suspend, logout, time-out, "". |
cmi.core.session_time | WO | Durée de cette session (format HHHH:MM:SS.SS). |
cmi.core.total_time | RO | Temps cumulé sur toutes les sessions. |
cmi.suspend_data | RW | Mémoire libre du SCO (max 4096 caractères). |
cmi.launch_data | RO | Données de lancement définies dans le manifeste. |
cmi.objectives.n.* | RW | Sous-objectifs (id, statut, score). |
Le champ pivot, c’est cmi.core.lesson_status : en SCORM 1.2, un seul champ porte à la fois la complétion et la réussite. C’est simple, mais ambigu — on ne peut pas dire « terminé mais échoué » proprement. SCORM 2004 corrige exactement ce point.
Les éléments clés de SCORM 2004
Le modèle 2004 sépare la complétion (a-t-on parcouru ?) de la réussite (a-t-on réussi ?), abandonne le sous-ensemble core, et enrichit le score et les interactions.
| Élément (SCORM 2004) | Accès | Rôle |
|---|---|---|
cmi.learner_id | RO | Identifiant de l’apprenant (équivaut à student_id). |
cmi.learner_name | RO | Nom de l’apprenant. |
cmi.completion_status | RW | Complétion : completed, incomplete, not attempted, unknown. |
cmi.success_status | RW | Réussite : passed, failed, unknown. |
cmi.score.scaled | RW | Score normalisé de -1 à 1 (le plus important en 2004). |
cmi.score.raw | RW | Score brut. |
cmi.score.min / cmi.score.max | RW | Bornes du score brut. |
cmi.progress_measure | RW | Avancement de 0 à 1 (barre de progression). |
cmi.location | RW | Signet de reprise (équivaut à lesson_location). |
cmi.entry | RO | Contexte d’entrée (première fois vs reprise). |
cmi.exit | WO | Sortie : suspend, normal, time-out, logout, "". |
cmi.session_time | WO | Durée de session au format ISO 8601 (ex. PT30M). |
cmi.suspend_data | RW | Mémoire libre du SCO (max 64000 caractères). |
cmi.interactions.n.* | RW | Détail des interactions (questions/réponses). |
cmi.objectives.n.* | RW | Objectifs (id, statut, score, mesure). |
adl.nav.request | WO | Demande de navigation (continue, previous… — Partie 5). |
Deux différences à graver :
- Un seul statut (1.2) vs deux (2004).
cmi.core.lesson_statusporte tout en 1.2 ; en 2004 tu posescmi.completion_statusETcmi.success_statusséparément. C’est le sujet du chapitre 4.4. - Le score de référence change. En 1.2, on raisonne
cmi.core.score.raw(0–100). En 2004, le champ canonique estcmi.score.scaled, un ratio de-1à1(0,85 pour 85 %). On peut poser les deux, mais c’est lescaledqui pilote souvent les règles.
💡 Réflexe — Ne jamais porter un SCO 1.2 vers 2004 par un simple copier-coller. Les noms changent (
cmi.core.lesson_status→cmi.completion_status/cmi.success_status;cmi.core.score.raw→cmi.score.raw+cmi.score.scaled;cmi.core.lesson_location→cmi.location). Passe par une couche d’abstraction (comme les adaptateurssetValue()du chapitre 4.2) qui traduit selon la version détectée.
🔌 Côté intégration — Le format de la durée de session piège souvent :
HHHH:MM:SS.SSen 1.2, ISO 8601 en 2004 (PT1H30M). Un SCO qui envoie une durée au mauvais format se voit rejeter la valeur par un LMS strict — la session passe, mais le temps affiché est faux ou nul. Vérifie toujours le format attendu par la version que tu cibles.
Lire l’identité, écrire le résultat
Le schéma mental le plus utile : le LMS te prête l’identité et le contexte (champs RO), tu lui rends le résultat (champs RW/WO).
// SCORM 1.2 — ce que je LIS (le LMS me le donne)
const id = api.LMSGetValue("cmi.core.student_id");
const nom = api.LMSGetValue("cmi.core.student_name");
const repr = api.LMSGetValue("cmi.core.entry"); // "ab-initio" = 1re fois, "resume" = reprise
// ... ce que j'ÉCRIS (je rends le résultat)
api.LMSSetValue("cmi.core.lesson_status", "completed");
api.LMSSetValue("cmi.core.score.raw", "85");
api.LMSSetValue("cmi.core.score.min", "0");
api.LMSSetValue("cmi.core.score.max", "100");
api.LMSCommit("");Tenter l’inverse — écrire student_name, ou lire session_time — n’a pas de sens et déclenche une erreur. Respecter les droits d’accès, c’est déjà éliminer une famille entière de bugs.
🧭 Sur FormaCampus — En inspectant le module fautif, on confirme que l’API répond bien à
LMSGetValue("cmi.core.student_name")(l’apprenant est identifié) et que l’écriture du score fonctionne. Le modèle de données est donc accessible. Le problème n’est pas « le SCO ne sait pas parler CMI » : c’est quelle valeur decmi.core.lesson_statusil pose, et quand il clôt. On resserre le diagnostic sur le statut — chapitre 4.4.
📚 La spec — Le modèle CMI complet (noms d’éléments, types, vocabulaires fermés, droits d’accès) est le cœur du livre RTE de chaque version SCORM, publié par ADL (
adlnet.gov). Les tableaux ci-dessus en donnent les éléments les plus utilisés au quotidien ; pour la liste exhaustive (dontcmi.comments,cmi.student_preference, le détail desinteractions…), se reporter à la spec de la version ciblée.
✏️ Exercices
Exercice 1 — Traduire un SCO 1.2 en 2004. Voici trois lignes d’un SCO 1.2 :
api.LMSSetValue("cmi.core.lesson_status", "passed");
api.LMSSetValue("cmi.core.score.raw", "82");
api.LMSSetValue("cmi.core.lesson_location", "ecran-7");Écris l’équivalent SCORM 2004 correct.
✅ Solution
// "passed" en 1.2 sous-entend à la fois terminé ET réussi :
// en 2004 on sépare les deux.
api.SetValue("cmi.completion_status", "completed");
api.SetValue("cmi.success_status", "passed");
// Score : on pose le brut ET le scaled (canonique en 2004).
api.SetValue("cmi.score.raw", "82");
api.SetValue("cmi.score.scaled", "0.82"); // ratio -1..1
// Le signet change de nom.
api.SetValue("cmi.location", "ecran-7");Le piège classique : garder cmi.core.lesson_status (inexistant en 2004) ou oublier le scaled. La séparation complétion/réussite est le point de bascule 1.2 → 2004.
Exercice 2 — Droit d’accès. Un dev veut « personnaliser l’accueil » avec le prénom, alors il écrit :
api.LMSSetValue("cmi.core.student_name", "Bonjour Léa");Pourquoi est-ce faux, et que faire à la place ?
✅ Solution
cmi.core.student_name est en lecture seule (RO) : c’est le LMS qui fournit le nom. Un SetValue dessus renvoie false et pose l’erreur « element is read only » (code 403 en 1.2). Pour afficher un accueil personnalisé, il faut lire la valeur, pas l’écrire :
const nom = api.LMSGetValue("cmi.core.student_name"); // ex. "Martin, Léa"
document.querySelector("#accueil").textContent = `Bonjour ${nom}`;🧠 Quiz de révision
1. Avec quelles méthodes lit-on et écrit-on le modèle CMI ?
GetValue(elt) pour lire, SetValue(elt, val) pour écrire — préfixées LMS en SCORM 1.2 (LMSGetValue, LMSSetValue). Deux verbes couvrent tout le modèle. Les valeurs échangées sont des chaînes.
2. Quelle est la grande différence de statut entre 1.2 et 2004 ?
SCORM 1.2 a un seul champ, cmi.core.lesson_status, qui mélange complétion et réussite. SCORM 2004 sépare en deux : cmi.completion_status (parcouru ?) et cmi.success_status (réussi ?).
3. Quel est le score « canonique » en SCORM 2004 et quelle est sa plage ?
cmi.score.scaled, un ratio de -1 à 1 (0,85 = 85 %). On peut aussi poser cmi.score.raw/min/max, mais le scaled est souvent celui qui pilote les règles.
4. Que se passe-t-il si on écrit dans cmi.core.student_name ?
cmi.core.student_name ?Échec : ce champ est en lecture seule. SetValue renvoie false et pose une erreur « read only » (code 403 en 1.2). L’identité est fournie par le LMS ; on la lit.
5. Comment porter proprement un contenu de 1.2 vers 2004 ?
Via une couche d’abstraction qui traduit les noms selon la version détectée : cmi.core.lesson_status → cmi.completion_status/cmi.success_status, cmi.core.score.raw → cmi.score.raw + cmi.score.scaled, cmi.core.lesson_location → cmi.location, formats de durée différents… Jamais un simple copier-coller.
Chapitre suivant : 4.4 — Statut, score & suspend_data — le trio qui décide si ta complétion remonte, si ton score compte, et si la reprise fonctionne.