Chapitre 6.4 — Result & context
⏱️ TL;DR — Le noyau
actor–verb–objectdit ce qui s’est passé. Deux champs optionnels le rendent exploitable. Leresultporte la mesure :score(scaledde-1à1, plusraw/min/max),success(réussi ?),completion(terminé ?),duration(au format ISO 8601, ex.PT1H15M) etresponse(la réponse donnée). Lecontextporte le où ça se situe :registration(l’UUID de la tentative, ce qui relie tous les statements d’une même session),instructor,contextActivities(parent/grouping/category— la hiérarchie qui rattache un statement à un module, un parcours, un profil) etextensions(tes données maison, clés en IRI). Leresultte donne des chiffres ; lecontextte donne du sens en reliant les statements entre eux.
🎯 Objectifs
- Renseigner correctement un
result: la bonne échelle de score,successvscompletion, unedurationISO 8601 valide. - Ne pas confondre
success(réussi) etcompletion(terminé) — la même distinction qu’en SCORM 2004 (Partie 5). - Utiliser
registrationpour regrouper les statements d’une même tentative. - Structurer
contextActivities(parent,grouping,category) pour relier un statement à sa hiérarchie. - Ranger tes données spécifiques dans
extensionssans polluer le noyau.
Le result : la mesure de l’expérience
result répond à « avec quel résultat ? ». Tous ses sous-champs sont optionnels ; on met ceux qui ont un sens.
"result": {
"score": {
"scaled": 0.92, // ratio de -1 à 1 (ici 92 %) — LE champ portable
"raw": 46, // score brut
"min": 0, // borne basse
"max": 50 // borne haute
},
"success": true, // a-t-il RÉUSSI ? (au-dessus du seuil)
"completion": true, // a-t-il TERMINÉ ? (parcouru l'activité)
"duration": "PT1H15M", // durée ISO 8601 : 1 h 15 min
"response": "soudure conforme, angle 90°, pénétration correcte" // la réponse/production
}Le score : scaled, raw, min, max
Comme en SCORM 2004 (ce n’est pas un hasard, même famille ADL), scaled est un ratio de -1 à 1, pas un pourcentage entier :
- 92 % s’écrit
0.92, jamais92. Un92dansscaledest hors plage et invalide. raw,min,maxdonnent le score brut et ses bornes. Unrawde46n’a de sens que si on sait qu’il est sur 50 (min: 0,max: 50).scaledest le champ portable : il compare des activités de barèmes différents (46/50 et 18/20 valent tous deux ≈ 0,9). Privilégie-le pour l’agrégation ; ajouteraw/min/maxpour la traçabilité fine.
⚠️ Piège — Mettre
92dansscaled(au lieu de0.92), ou envoyer unrawsansmin/max. Le premier produit un score invalide (hors-1..1) ; le second produit un score ininterprétable (46 sur combien ?). Règle :scaled= ratio décimal ;raw= toujours accompagné de ses bornes.
success ≠ completion
C’est exactement la distinction complétion/réussite de SCORM 2004 (Partie 5), portée en xAPI :
| Champ | Question | Exemple « terminé mais raté » |
|---|---|---|
completion | A-t-il parcouru / achevé l’activité ? | true |
success | A-t-il atteint le seuil de réussite ? | false |
Les deux sont indépendants. On peut avoir completion: true + success: false (a tout fait, mais échoué), ou completion: false + success: true (a réussi une partie sans finir le reste). Ne les fusionne jamais : ce sont deux informations distinctes que les rapports exploitent séparément.
💡 Réflexe — Choisis consciemment le verbe et les champs de result. « A réussi » se dit idéalement avec le verbe
passedetsuccess: true: verbe et result se confirment. De mêmecompletedva aveccompletion: true. Garde verbe et result cohérents — un statementpassedavecsuccess: falseest un signal contradictoire qui trahit un bug.
duration : le format ISO 8601
duration suit le format durée ISO 8601 : préfixe P (période), T avant la partie horaire, puis heures/minutes/secondes.
| Durée réelle | Écriture ISO 8601 |
|---|---|
| 10 minutes | PT10M |
| 1 h 15 min | PT1H15M |
| 1 h 30 min 45 s | PT1H30M45S |
| 90 secondes | PT1M30S (ou PT90S) |
Le T n’est pas optionnel devant les heures/minutes/secondes : PT10M = 10 minutes, alors que P10M (sans T) voudrait dire 10 mois. Cette lettre change tout.
⚠️ Piège — Oublier le
Tou envoyer une durée en secondes brutes (4500).durationn’est pas un nombre : c’est une chaîne ISO 8601.4500est refusé ;PT1H15M(ouPT4500S) est correct. EtP10M≠PT10M: le premier, ce sont dix mois.
Le context : ce qui relie et situe
context répond à « dans quel cadre ? ». C’est lui qui transforme une collection de phrases isolées en un récit cohérent.
"context": {
"registration": "3d6d3e0c-1f2b-4b8a-8c1a-9e2f7a6b5c4d", // UUID de LA tentative
"instructor": { // le formateur qui encadre/atteste
"objectType": "Agent",
"name": "Karim Benali",
"mbox": "mailto:karim.benali@formacampus.fr"
},
"contextActivities": {
"parent": [ { "id": "https://formacampus.fr/xapi/activities/module-soudure" } ],
"grouping": [ { "id": "https://formacampus.fr/xapi/activities/cpjs-metallerie-2026" } ],
"category": [ { "id": "https://formacampus.fr/xapi/profiles/atelier-presentiel" } ]
},
"extensions": {
"https://formacampus.fr/xapi/extensions/poste-soudure": "P12",
"https://formacampus.fr/xapi/extensions/site": "Atelier Lyon-Est"
}
}registration : l’UUID de la tentative
registration est un UUID qui identifie une inscription / une tentative à une activité. Son rôle : regrouper tous les statements produits pendant la même session d’apprentissage.
- L’appli émet
attempted, puis dixanswered, puiscompletedetpassed: si tous portent le mêmeregistration, le LRS (et ton tableau de bord) sait que c’est une tentative cohérente. - Une nouvelle tentative de la même activité par la même personne = un nouveau
registration. On distingue ainsi « a repassé l’évaluation » de « premier passage ».
C’est le pendant xAPI de ce qu’on ne doit pas mettre dans l’id d’activité (chapitre 6.3) : le volatil (la session, la tentative) vit dans registration, pas dans l’id de l’activité.
contextActivities : parent, grouping, category
contextActivities rattache le statement à d’autres activités, selon trois relations :
| Relation | Sens | Exemple FormaCampus |
|---|---|---|
parent | L’activité directement au-dessus dont fait partie l’objet. | L’atelier appartient au module soudure. |
grouping | Un regroupement plus large, pas forcément direct. | Le parcours métallerie 2026 englobant plusieurs modules. |
category | Ce qui catégorise / caractérise le statement (souvent un profil xAPI). | Le profil « atelier présentiel » qui cadre ce type de statement. |
Ces relations sont ce qui permet de répondre à « montre-moi tout ce qu’a fait Léa dans le parcours métallerie » ou « agrège les résultats par module ». Sans elles, tu n’as que des phrases plates, sans hiérarchie.
💡 Réflexe —
categoryest le champ où l’on déclare le profil xAPI que suit le statement (une convention de verbes et de structures pour un usage donné — évoqué en Partie 6). Quand tu adoptes un profil (cmi5, ou un profil maison documenté), tu le déclares encategory: c’est ainsi qu’un outil sait « ce statement suit telles règles » et l’interprète correctement.
extensions : tes données, proprement rangées
extensions est l’échappatoire propre pour les données spécifiques à ton métier que le noyau ne prévoit pas : le numéro de poste de soudure, le site, la version de l’app, un identifiant de capteur… Les clés sont des IRI (comme les verbes), les valeurs sont libres (chaîne, nombre, objet JSON).
- Avantage : tu enrichis sans polluer ni détourner les champs standard.
- Règle : une clé = une IRI que tu contrôles (
https://formacampus.fr/xapi/extensions/…), documentée. On peut mettre desextensionsdansresultet danscontextselon que la donnée qualifie le résultat ou le cadre.
⚠️ Piège — Détourner un champ standard faute de connaître
extensions. Mettre le numéro de poste dansresult.response, ou le site dans lenamede l’activité, corrompt des champs qui ont un sens précis et casse les rapports. Toute donnée maison va dansextensions, avec une clé IRI documentée. Jamais dans un champ standard « parce qu’il était libre ».
📚 La spec — Les sous-champs de
result(score.scaledde-1à1,score.raw/min/max,success,completion,durationen ISO 8601,response) et decontext(registration,instructor,contextActivitiesparent/grouping/category,extensions) sont définis par xAPI (ADL,adlnet.gov; IEEE 9274.1.1 pour la 2.0). Les IRI d’extensionset decategory(profils) sont des vocabulaires que tu déclares et documentes.
🧭 Sur FormaCampus — Le statement de l’atelier prend toute sa richesse. Léa réalise sa soudure : l’appli tablette émet un
passedavec unresultcomplet (scaled: 0.92,raw: 46/50,success: true,completion: true,duration: "PT1H15M", et enresponsela description du geste conforme). Lecontextfait le lien :registrationregroupe cette tentative (si Léa repasse, ce sera un autre UUID) ;instructornomme Karim qui atteste ;contextActivities.parentrattache l’atelier au module soudure,groupingau parcours métallerie 2026,categoryau profil « atelier présentiel » de FormaCampus ; etextensionsnote le poste P12 et le site Lyon-Est. Résultat : le tableau de bord de l’école peut afficher « progression de Léa dans le parcours métallerie », comparer les tentatives, filtrer par site — tout ça parce que lecontexta relié les phrases au lieu de les laisser flotter.
✏️ Exercices
Exercice 1 — Corrige le result. Un dev envoie ceci pour un score de 85 % obtenu en 20 minutes :
"result": { "score": { "scaled": 85 }, "duration": "20" }Repère les deux erreurs et corrige.
✅ Solution
Deux erreurs : (1) scaled est un ratio de -1 à 1 → 85 % s’écrit 0.85, pas 85 (qui est hors plage, invalide) ; (2) duration est une chaîne ISO 8601, pas un nombre → 20 minutes = "PT20M", pas "20". Corrigé :
"result": {
"score": { "scaled": 0.85, "raw": 85, "min": 0, "max": 100 },
"duration": "PT20M"
}On en profite pour ajouter raw/min/max : le score devient traçable et portable.
Exercice 2 — success vs completion. Un apprenant a parcouru entièrement l’évaluation mais a obtenu un score sous le seuil. Écris le result (score 0.55, seuil 0.7) et choisis le verbe cohérent.
✅ Solution
Il a terminé (completion: true) mais échoué (success: false). Verbe cohérent : failed.
"verb": {
"id": "http://adlnet.gov/expapi/verbs/failed",
"display": { "fr-FR": "a échoué" }
},
"result": {
"score": { "scaled": 0.55, "raw": 55, "min": 0, "max": 100 },
"completion": true,
"success": false
}C’est le cas type « terminé mais raté » : les deux booléens sont indépendants, et le verbe (failed) confirme success: false. Les fusionner ferait perdre l’info « il est bien allé au bout ».
Exercice 3 — Relier une tentative. Léa fait une évaluation en trois écrans : elle répond à Q1, Q2, Q3 (trois statements answered), puis le module émet completed. Comment garantir que ces quatre statements sont vus comme une seule tentative, et comment distinguer une deuxième tentative plus tard ?
✅ Solution
On met le même context.registration (un UUID) sur les quatre statements : le LRS les regroupe alors comme une tentative cohérente. Pour une deuxième tentative (Léa repasse l’évaluation), on génère un nouveau registration : même acteur, même activité (même id), mais tentative distincte. C’est registration — et non l’id d’activité — qui porte le volatil de la session. Bonus : contextActivities.parent peut rattacher chaque answered à l’évaluation parente pour l’agrégation par activité.
🧠 Quiz de révision
1. Comment s’écrit un score de 78 % dans result.score ?
result.score ?scaled: 0.78 (ratio de -1 à 1), idéalement accompagné de raw, min, max (ex. raw: 78, min: 0, max: 100). Jamais scaled: 78 : ce serait hors plage et invalide. scaled est un ratio décimal, pas un pourcentage entier.
2. Quelle différence entre success et completion ?
success et completion ?completion = a parcouru/achevé l’activité ; success = a atteint le seuil de réussite. Ils sont indépendants : on peut être completion: true + success: false (terminé mais raté). C’est la même distinction qu’en SCORM 2004. Il ne faut jamais les fusionner.
3. Écris « 1 heure 5 minutes » au format duration. Et pourquoi le T est-il crucial ?
duration. Et pourquoi le T est-il crucial ?PT1H5M. Le T sépare la partie date de la partie horaire : sans lui, P1H5M est invalide, et surtout P10M (sans T) signifie 10 mois alors que PT10M signifie 10 minutes. Le T est obligatoire devant heures/minutes/secondes.
4. À quoi sert context.registration ?
context.registration ?C’est l’UUID d’une tentative : il regroupe tous les statements produits pendant la même session d’apprentissage (un attempted, plusieurs answered, un completed…). Une nouvelle tentative = un nouveau registration. Le volatil de session vit ici, pas dans l’id d’activité.
5. Que mettre dans parent, grouping, category, et où rangerais-tu un numéro de poste de travail ?
parent, grouping, category, et où rangerais-tu un numéro de poste de travail ?parent = l’activité directement au-dessus (le module) ; grouping = un regroupement plus large (le parcours) ; category = ce qui catégorise le statement (souvent un profil xAPI). Un numéro de poste est une donnée maison → il va dans extensions, avec une clé IRI documentée, jamais dans un champ standard détourné.
Chapitre suivant : 6.5 — Le LRS — le magasin qui reçoit et sert tous ces statements : son API REST, l’immutabilité, le voiding, et pourquoi un LRS n’est pas un LMS.