// lrs-xapi.js — the one implementation of the xAPI producer contract. // // Normative reference: docs/specs/xapi-producer-contract-v1.md. Where this file and // that document disagree, the document wins and this file is a bug. // // WHY THIS EXISTS // --------------- // Four emitters had independently re-implemented the same ~60 lines — UUID, ISO-8601 // duration, the actor block, the log panel, and the canonical-IRI rule: // // docs/js/quiz-xapi.js derived the page IRI from location.pathname // docs/sims/bouncing-ball/*.js hardcoded ACTIVITY_BASE_ID // docs/sims/sine-wave/*.js hardcoded it // docs/sims/scientific-method/script.js hardcoded it // // They already disagreed. That is not a style problem: sine-wave's hardcoded IRI was // wrong twice (wrong site AND `main.html` instead of the page), and contract §1 records // that fixing it surfaced five more wrong URLs in the same file. The hardcoded ones that // are correct are correct BY LUCK, not by construction — nothing stops the next // copy-paste from carrying a stale base into a new sim. // // This module makes §1 true by construction: an emitter cannot supply a page IRI at all, // so it cannot supply a wrong one. As of 2026-09-26 all of them go through it: every sim and // the chapter quizzes call lrs-sim.js, which builds every statement here with LRS.build(). // The statement log that used to live here (LRS.emitter) moved to lrs-sim.js with them. // // LOADS IN TWO CONTEXTS // --------------------- // site pages — mkdocs.yml `extra_javascript` // sim iframes —