Diagnostic codes
On this page
Generated from packages/core/src/diagnostics/codes.ts by pnpm run docs. Codes are stable: agents can branch on them. rule names a pedagogical guardrail (A1…I1) or a line of the LMS delivery checklist (LMS-n): see Rules. An error under a rule stops a build but not a preview (elabora preview, the app’s Aperçu): the course runs without what the rule asks, and the preview shows it as it is.
Errors (block the build)
| Code | Title | Fix | Rule |
|---|---|---|---|
E_FILE_MISSING |
Required file missing | Create the file (elabora init scaffolds a project). | |
E_JSON_PARSE |
Invalid JSON | Fix the JSON syntax at the reported position. | |
E_SCHEMA |
Does not match the schema | Read the schema named in the message (or call get_block_schema) and correct the value at path. | |
E_FORMAT_NEWER |
Course in a newer format than this Elabora reads | Update Elabora (the app, or the elabora command) to work on this course; this version reads its own format and migrates older ones. Do not lower the format by hand: what the newer format added would be lost or misread. | |
E_DUPLICATE_ID |
Duplicate id | Ids of sections, screens, blocks, layers and events share one namespace: each must be unique in the whole course (a section cannot have the id of a screen). Rename the new element, never a published one. | |
E_SCREEN_ID_MISMATCH |
Screen id differs from its file name | Rename the file to screens/<id>.json or fix the id. | |
E_SCREEN_NOT_FOUND |
Screen listed in course.json has no file | Create screens/<id>.json or remove the id from course.json sections. | |
E_SCREEN_LISTED_TWICE |
Screen listed more than once in course.json | Each screen appears exactly once in sections. | |
E_UNKNOWN_REFERENCE |
Reference to an unknown element | Use an existing id (see the message for the kind of element expected). | |
E_ASSET_MISSING |
Asset file not found | Add the file under assets/ or fix the path. | |
E_SOURCE_REFERENCED |
A course file points into sources/ | sources/ holds the files the author gave (briefs, decks, recordings), which are never published and keep their metadata. Import what the course shows into assets/ (elabora media import . sources/<file> for an image, audio or video) and point to that. |
|
E_FILENAME_NOT_PORTABLE |
File name not accepted by every LMS | Use ASCII letters, digits, “-”, “_” and “.” only (RFC 3986 unreserved). No spaces or accents. | LMS-8 |
E_EXTERNAL_RESOURCE |
External resource in content | Copy the file into assets/ and reference it locally: packages must work without network access. | LMS-8 |
E_MEDIA_UNREADABLE |
Media file cannot be read | The file is damaged, incomplete (still downloading or syncing) or not media: replace it, or import the original again with elabora media import. |
|
E_MEDIA_RENDITION |
Media rendition could not be made | Builds below the high media quality encode renditions of the masters with ffmpeg: install it (or set ELABORA_FFMPEG and ELABORA_FFPROBE), read the encoder message, or build at the high quality. | |
E_PLAN_NOT_APPROVED |
No validated version of the plan | A release build needs a version of the plan the client validated. A person makes it (the app’s « Créer la V1 », elabora plan version), sends it (Exporter, elabora plan export) and records the client’s validation (« Valider… », elabora plan approve --by "<name>"); agents never do. Use –draft builds meanwhile. |
A5 |
E_PLAN_VERSION_INVALID |
A version of the plan that does not hold together | A version never changes once made: its plan must give its contentHash, and its number must be its file name (plan-versions/V<n>.json). Bring the file back from the history (elabora history, elabora undo) or a backup; never edit a version by hand, and make a new one instead (elabora plan version). |
A5 |
E_PLAN_ITEM_UNCOVERED |
Plan item not covered by any screen | Add a screen whose covers lists this item, or remove the item from the plan (elabora plan write, MCP elabora_write_plan). |
A1 |
E_PLAN_REFERENCE |
Unknown plan reference | Reference an id that exists in plan.json (objectives, items, lockedTexts, questions, sources). | A1 |
E_LOCKED_TEXT_NOT_USED |
Validated text of the plan not used | Add a text, heading or callout block with textRef set to this id on a screen covering the item. | A5 |
E_LOCKED_TEXT_OUTSIDE_ITEM |
Validated text used on a screen that does not cover its item | Use it on a screen whose covers includes the plan item that owns the text. | A1 |
E_PLAN_QUESTION_NOT_USED |
Validated question not used | Add a quiz block (numeric block for numeric questions) with questionRef set to this id on a screen covering the item. | A5 |
E_BLOCK_TEXT_SOURCE |
Text source ambiguous | Set exactly one of markdown/text or textRef. | |
E_QUIZ_SOURCE |
Quiz source ambiguous | Either set questionRef only, or set stem, mode and options (inline question). | |
E_PLAN_OBJECTIVE_UNUSED |
Objective not served by any plan item | Reference it from a plan item, or remove it (elabora plan write). |
A1 |
E_FEEDBACK_MISSING |
Option without elaborated feedback | Write, for every option, why it is right or wrong and what to remember (not just Correct/Incorrect). | D1 |
E_QUIZ_SINGLE_MULTIPLE_CORRECT |
Single-choice question with several correct options | Set mode to multiple or keep one correct option. | |
E_FILLIN_NO_BLANK |
Fill-in without blanks it can use | Write each blank in the Markdown as [[answer]], other accepted answers after | ([[DNS|serveur DNS]]): one to three per sentence, 12 at most, each with an answer. | |
E_SORT_TARGET |
Sort whose items and targets do not fit | Give the sort its items (4 to 8 is best). pairs: as many targets as items, each item naming a target of its own. categories: 2 to 4 targets, each item naming one of them. order: the items in the right order, without targets. Ids of items and of targets are unique in the block. | |
E_QUIZ_PICTURE |
Quiz on pictures without its pictures or zones | presentation images: give each option its image and alt. presentation image: give the quiz its image and alt, and each option its x and y (0 to 1 from the top left of the picture). A plan question (questionRef) has no pictures: write the question inline, or fork the quiz to add them to the plan’s options. | |
E_GALLERY_COMPARE |
Before and after without exactly two images | A gallery in the compare presentation shows two images, the first before and the second after: keep two, or choose grid or mosaic for more. | |
E_STEPS_FIGURE |
Scroll steps without what their figure follows | presentation scroll: figure replace and build need step images (build: transparent layers the size of figureImage); figure focus needs figureImage and a region { x, y, w, h } (0 to 1 of the picture) on the steps it outlines. | |
E_BLOCK_ITEM_DUPLICATE |
Two items of a block with the same id | Each item of a steps block or an interactive picture has its own id: visited marks, translations and conversions name items by id. Rename the new one, never one learners already saw. In a carousel, intro and summary are the ids of its first and last items. | |
E_SPEECH_SPEAKER |
A character block names a speaker the course does not have | A speech block’s speaker is a speaker of course.json speakers (its name, colour and look are read there): add the character there, or use an existing id. | |
E_IMAGE_ALT_MISSING |
Image without text alternative | Write alt as the information the image carries, or set decorative: true if it carries none. | F3 |
E_VIDEO_CAPTIONS_MISSING |
Video with sound without captions | Give the video its captions from a WebVTT or SubRip file (elabora media captions . <block> <file.vtt|.srt>, MCP elabora_set_captions): the file is written under assets/captions/, SubRip converted to WebVTT, and captions names it. A silent animation plays as a loop (loop: true, with alt); a video that carries no information is decorative: true. |
F3 |
E_MEDIA_TRANSCRIPT_MISSING |
Video or sound without transcript | Write the transcript: what is said and shown. A video without sound may give alt instead; a sound or a video that carries no information is decorative: true. | F3 |
E_VIDEO_ALT_MISSING |
Looping video without text alternative | Write alt as what the animation shows, or set decorative: true if it carries none. | F3 |
E_THEME_CONTRAST |
Insufficient colour contrast | Adjust the theme tokens to reach WCAG 2.2 AA (4.5:1 text, 3:1 focus). | F1 |
E_HEADING_ORDER |
Heading level skipped | Headings go 2 → 3 → 4 without skipping a level. | F1 |
E_OBJECT_A11Y_ALTERNATIVE |
Free object without text alternative | Fill textAlternative with an equivalent activity or a full description. | F3 |
E_PLAYER_SETTING_MOVED |
Player setting moved into course.json player | Write it in course.json player as the message says (elabora player . –enable/–disable/–set, MCP elabora_player), and remove it from navigation or narration: the outline, the progress and the bottom bar’s position are player items and options since 19 October 2026 (D58). | |
E_PLAYER_ITEM_DUPLICATE |
Player item listed twice | Each item (logo, title, progress, outline, controls, resources, glossary, credits, display, language, previous, next, exit) goes in one bar, once, and each bar has one spacer: remove the second entry (elabora player . –move <item>:<bar>[:<index>] moves it, MCP elabora_player move). | |
E_SOUND_MISSING |
A sound the course names is not in assets/sounds/ | Add the sound (elabora sound add . <file or library id> –id <id>), or name one the course has (elabora sound list .). | |
E_SOUND_LICENSE |
A sound whose licence does not let it ship | Replace the sound with one under CC0, a public-domain mark, CC BY or CC BY-SA (elabora sound search . “<words>”), or write its licence in its sidecar assets/sounds/<id>.json when you know it (license: CC0-1.0, CC-BY-4.0…, own for a sound the author made or bought with every right). Non-commercial (NC) and no-derivatives (ND) licences cannot ship: courses are sold, and sounds are cut and mixed. | |
E_SOUND_BACKGROUND |
A track of music or ambience over a range that does not work | Give the track a range of screens of the course, from before to (elabora sound background), with one track at a time on each screen: two tracks on one screen would play over each other. | |
E_SOUND_PART |
A part of a sound that is not in its file | Give start and end in seconds inside the sound, end after start (its length: elabora sound list .), or leave them out to play it whole. | |
E_DUPLICATE_ENTRY |
Two glossary entries or resources with the same id | Give each glossary entry and each resource its own id: texts link to entries by id (glossary:<id>). |
|
E_RESOURCE_URL |
Resource link that is not an https:// address | Give the resource an https:// address (https://intranet.example.com/charte), or a file of assets/ instead (asset). | |
E_GLOSSARY_TERM_UNKNOWN |
Link to a glossary entry that does not exist | Link to an entry of course.json glossary ([mot](glossary:<id>)), or add the entry with MCP elabora_player (glossary: the whole list, the new entry with them): the ids are in the message. |
|
E_EVENT_TARGET |
Trigger target of the wrong kind | click targets a button (or a component with buttons, tabs or disclosures; name is one of their names), quiz.submitted a quiz or numeric block (or a fork), decision.selected a decision, object.event a free-object block, layer.closed a layer of this screen. | |
E_VISITED_TARGET |
Visited condition on a block without that control | visited names a block with controls (a button block, or a component with data-t-click buttons, tabs or disclosures); name, when given, is one of the names of its controls (see the message). | |
E_ACTION_TARGET |
Action target invalid | Point go-to at an existing screen (or next/previous), layers and blocks at elements of this screen. | |
E_VARIABLE_TYPE |
Value does not match the variable type | Use a value of the declared type (and an allowed option for choice variables). | |
E_VARIABLE_STRING_LENGTH |
String variable without maxLength | Set maxLength so the suspend data budget can be computed. | LMS-3 |
E_OBJECT_EVENT_UNDECLARED |
Free object event not declared in its manifest | Use an event name listed in object.manifest.json events. | |
E_OBJECT_PROP_VALUE |
Free object prop value invalid | Use a declared prop with a value matching its schema (type, bounds, enum). | |
E_NARRATION_LINE_DUPLICATE |
Two narration lines with the same id | Give every line of a screen its own id (l1, l2…), every track counted: the screen’s narration, each layer’s and each dialogue’s lines (with or without a voice, replies included). Cues, translations and the audio files (assets/narration/<language>/<screen>/<line>.m4a) are named by it. | |
E_NARRATION_SPEAKER |
Narration speaker unknown | Name a speaker of course.json speakers (each declared once), or declare it there with the name learners read in captions: { “id”: “leila”, “name”: “Leïla” }. | |
E_NARRATION_STEP_ORDER |
Narration lines out of step order | Lines are spoken in the order they are written and each step is one stretch of the timeline: put the lines of a step after those of the steps before it. | |
E_TIMELINE_CUE |
Timeline cue or action without a timeline to follow | timeline.reached names a line of the screen’s narration or of a layer’s (at.line), or seconds from the start of a step on a screen without narration (at.seconds; with layer, from the opening of a layer without narration); timeline.ended and the actions pause-timeline, play-timeline and seek-timeline need a timed screen: narrated (narration.lines), or whose blocks or events are timed in seconds; with layer, a layer of the screen with a timeline of its own (a narration, or timed blocks: D62). | |
E_TIMELINE_ANCHOR_MISSING |
Anchor on a word or line the narration does not say | An anchor names a line of the screen’s narration and, with word, one or a few words that line says (case, punctuation and apostrophes aside; occurrence picks a word said more than once). The line’s text changed or the anchor is mistyped: anchor to words the line says (elabora timeline <screen> lists the lines and the anchors), or drop word to anchor to the line. Until then the block comes at the start of the line. In a translation, place the anchor’s marker on the words of that language. | |
E_TIMING_SECONDS_NARRATED |
Seconds on a narrated screen | A narrated screen anchors its moments to its lines and words, so that they hold when the voice is generated again, recorded or translated: { “line”: “l2” }, { “line”: “l2”, “word”: “imprimante” }, with offset for a delay. Seconds are for screens without narration. | |
E_TIMELINE_ANCHOR_TRACK |
Anchor on a line of another timeline | Each timeline plays on its own (D62): a block or a cue of a layer anchors to the lines of that layer’s narration (layers[].narration.lines), a block or a cue of the screen to the screen’s (narration.lines), never to a line the other one says. Anchor to a line of its own timeline, move the line into the narration it belongs to, or move the block; an event whose layer names another timeline than its line’s keeps one of the two. Until then it falls back to the start of its timeline. | |
E_TIMING_EFFECT_UNKNOWN |
Unknown effect | Use an effect of the player (none, fade, rise, slide, zoom, wipe, draw), or one the theme declares in course.json theme.effects (its stylesheet defines @keyframes t-fx-<name>). | |
E_TIMING_ORDER |
Block that leaves before it comes | Its timing.out falls at or before its timing.in (the message gives both times): learners never see it. Anchor out to a later word or line, or remove out (the block then stays until the end of the screen). | |
E_ACTIVITY_LEAVES_UNANSWERED |
Question or control that leaves before learners can use it | An activity, or a block learners click, leaves (timing.out) while playback goes on, before it stops for the learner at the end of a step: learners may not have had the time to answer or to use it. Let it stay until the end of its step’s stretch (playback waits there in learner mode, or once answered with steps that open answered), until the end of the screen, or remove its timing.out. | |
E_NARRATION_TRACK |
Narration track could not be made | The build lays the lines of a screen end to end with ffmpeg: install it (or set ELABORA_FFMPEG), check that each line’s audio plays (the message has ffmpeg’s words), or import it again. | |
E_MASTERY_SCORE_MISSING |
masteryScore required | Set completion.masteryScore (percent) or use reportAs completed-incomplete. | LMS-13 |
E_SUSPEND_DATA_BUDGET |
Worst-case suspend data exceeds the LMS limit | Reduce persisted state: fewer persisted variables, shorter string maxLength, smaller free-object persistState.maxLength, or split the course. | LMS-3 |
E_PACKAGE_TOO_LARGE |
Package larger than the LMS accepts | Lower the media quality: elabora build --media-quality medium (or low), or set delivery.mediaQuality in course.json; the message (and details) give the size at each quality, the one that fits and the heaviest files. Otherwise shorten the heaviest media, host long videos on a video platform and link to them, or split the course. |
LMS-8 |
E_PACKAGE_TOO_MANY_FILES |
Too many files for the LMS | Merge assets or split the course. | LMS-8 |
E_COMPRESSION_RATIO |
Compression ratio above the LMS limit | Store already-compressed or random-like data, or split very repetitive files. | LMS-8 |
E_LMS_UNKNOWN |
LMS unknown to Elabora | Use the id of an LMS profile (elabora profiles lists them) in delivery.lms, or leave it out. | LMS-8 |
E_FORBIDDEN_EXTENSION |
File type refused by the LMS | Remove server-side files from the package. | LMS-8 |
E_STANDARD_NOT_SUPPORTED |
Target standard not supported by the LMS profile | Build SCORM 1.2 for this LMS. | LMS-9 |
E_WEB_URL |
Web address not usable | Give the absolute address where the module’s index.html will be served, with https:// (or http://): elabora build --target web --url https://example.org/modules/gearset/. |
|
E_WEB_IMAGE |
Sharing image not usable | Give a PNG, JPEG or WebP file (1200×630 px reads well everywhere), a path in the course folder (assets/…) or an absolute path: --image assets/images/cover.jpg. |
|
E_WEB_REVIEW_ORIGIN |
Review page origin not usable | Give the origin of the review page that will show the module, https:// and its host, without a path: elabora build --target web --review-origin https://revue.elabora.studio (repeat it for a development page on http://localhost:<port>). |
|
E_MANIFEST_NOT_AT_ROOT |
imsmanifest.xml is not at the root of the ZIP | Repackage with the manifest at the root. | LMS-8 |
E_MANIFEST_INVALID |
imsmanifest.xml invalid | See the message; rebuild with elabora build. | LMS-8 |
E_UPDATE_BREAKS_RESUME |
This update will lose learner progress in the target LMS | Publish as a new course/version in the LMS, or avoid structural changes. | LMS-7 |
E_OBJECT_NOT_FOUND |
Free object folder not found | Create objects/<id>/ with object.manifest.json, object.js, object.tests.json and object.notes.md (elabora object new). | |
E_OBJECT_ID_MISMATCH |
Manifest id differs from its folder | Make the manifest id equal to the folder name. | |
E_OBJECT_PROP_DEFAULT |
Prop default invalid | Every prop needs a default that matches its own schema. | |
E_OBJECT_TOKEN |
Unknown theme token | Use an existing token of course.json theme.tokens or theme.custom (for example color.accent), or, for a material colour of the object (brass, wood), drop x-token and keep a literal default. | |
E_OBJECT_OBJECT_ID |
x-object-id refers to an undeclared object | Declare the object in manifest objects. | |
E_OBJECT_TRACKING_OBJECTIVE |
Tracking objective not in planRefs | Use an objective listed in planRefs.objectives, or add it there when the object does serve it (the plan says which objectives exist). | A5 |
E_OBJECT_PLAN_MISMATCH |
Free object placed on a screen that does not serve its objectives | Place it on a screen covering an item that lists one of its planRefs objectives. | A1 |
E_OBJECT_CODE_MISSING_MOUNT |
object.js does not export mount | export function mount(container, ctx) { … return { update, getState, setState, dispose }; } | |
E_OBJECT_FORBIDDEN_API |
Forbidden API in free object code | Free objects run in a sandbox without network or storage: use host.asset() for files, host.emit() to talk to the course, props for settings. | |
E_OBJECT_NONDETERMINISM |
Non-deterministic call in free object code | Use host.random(), host.now() and host.onFrame() instead of Math.random, Date.now and requestAnimationFrame, so tests can replay the object. | |
E_OBJECT_IMPORT |
Import not allowed | Import only “three”, the allowed three/addons, “d3” and “@elabora/charts” (charts: D60), or relative files of the object folder. | |
E_OBJECT_PARSE |
object.js does not parse | Fix the syntax error (ES2022 module). | |
E_OBJECT_TEXT_CONTRAST |
Free object text colour too close to its background | x-text-on pairs a colour prop the object draws text in with the colour that text is read on (another colour prop or a theme token): change one of them until they reach 4.5:1 (WCAG AA). | F1 |
E_OBJECT_STATE_BUDGET |
Persisted object state too large | Lower persistState.maxLength or persist less state. | LMS-3 |
E_CONTINUITY_DUPLICATE |
A continuity key used twice on one screen | A key names one block per screen: the block that carries on to the next screen with the same key. Give the other block a key of its own, or remove its continuity. | |
E_CONTINUITY_MISMATCH |
Blocks sharing a continuity key are not the same kind | Blocks with the same continuity key are one thing to the learner: give them the same type, and free objects the same object (props.object). Use another key for a block of another kind. | |
E_CONTINUITY_PLACE |
Continuity on a block that cannot carry on | A continuity key goes on a block of a screen (with the blocks of its components’ slots), never on a block of a layer; a free object that carries on has no timing (its frame stays on the screen from one screen to the next). Remove the key, or the timing. | |
E_STYLE_RULE |
Stylesheet rule not allowed | No @import and no external url(): reference files inside the course folder, such as theme/, assets/ or the component folder (packages work offline). | |
E_MATH_PARSE |
LaTeX error | Fix the TeX between $…$ or in the math block (temml syntax, close to KaTeX). Write a literal dollar as $. | |
E_CHART_ITEM_DUPLICATE |
Two items of a chart with the same id | Each item of a chart (a row, a part, a step, an event…) has its own id: highlights, voice beats and translations name items by id. Rename one of them; keep the id of an item that only moved. | |
E_CHART_ITEM_UNKNOWN |
A chart names an item it does not have | highlight, a trend’s note, a diagram’s beat or label names an item by its id (a row, a part, a point’s x, a diagram node or edge): use one of the ids the message lists, or remove it. | |
E_CHART_DATA |
Chart data that cannot be drawn | The message says what is missing. A trend needs at least two points whose x are all numbers in increasing order, or all distinct words; in predict mode, predict.from is the x of a point before the last. | |
E_DIAGRAM_TYPE |
Diagram type the diagram block does not draw | The diagram block draws these Mermaid types: flowchart, sequenceDiagram, stateDiagram-v2, mindmap, timeline, journey, ishikawa-beta and venn-beta. Data belongs in a chart block (bars, donut, trend…); another kind of drawing in a free object. | |
E_DIAGRAM_SYNTAX |
Mermaid syntax error | Fix the Mermaid text at the line and column the message gives; its first line names the type (flowchart LR, mindmap, sequenceDiagram…). elabora look --block <id> shows the drawing once it parses. |
|
E_DIALOGUE_TARGET |
A dialogue goes to a node or an ending it does not have | start, next (or a case’s go), an option’s next, an end and goto-dialogue name a node or an ending of the same dialogue by its id: use one the message lists, or add the node. elabora dialogue show <block> prints the dialogue with its node ids. |
|
E_DIALOGUE_DUPLICATE_ID |
Two parts of a dialogue with the same id | Node ids are unique in their dialogue, option ids in their node, ending and variable ids in their dialogue (a line id taken twice in the screen is E_NARRATION_LINE_DUPLICATE). Rename the new one; never an id learners already played (their saved path names options by node and id). | |
E_DIALOGUE_DEAD_END |
A dialogue node that may have nowhere to go | A list of next cases is read in order and the first whose if holds wins: end it with a case without if (the way when none holds), or give the node an end. | |
E_DIALOGUE_SPEAKER |
A dialogue names a speaker the course does not have | A line’s speaker, the dialogue’s learner and the cast name speakers of course.json speakers: add the character there (id, name, its voice, colour and look), or use an existing id. A line without speaker is a narration. | |
E_DIALOGUE_CONDITION |
A dialogue condition names what does not exist | chosen names node.option, seen a node, var a variable of the dialogue (vars), variable a variable of the course, with a value of its type: fix the name the message gives. At run time such a condition holds, so the dialogue still plays. | |
E_DIALOGUE_VAR |
An option changes a variable the dialogue does not declare | set and add change the dialogue’s own variables: declare it in vars (id and default), with a value of the same type; add takes a number variable. The course’s variables change on dialogue.ended, in an event of the screen. | |
E_DIALOGUE_ACTION |
An action a dialogue may not run | Options and cues run presentation actions only: show-block, hide-block, show-layer, hide-layer, play-media, pause-media, set-object-props, reveal-step, play-sound, stop-sound. To change the course’s variables, navigate or complete the screen, write an event of the screen on dialogue.ended (or dialogue.chosen): replaying a path must never write the course’s state twice. | |
E_DIALOGUE_CUE |
A cue whose moment is not in its line | A cue’s at names words of its own line ({ “word”: “Bonjour” }; line, when written, is that line): use words the line says, as written there, or remove the cue. Its text changed? Move the cue to the words that say the same thing. | |
E_GENERATOR |
Asset generator cannot be built | Fix the syntax or the imports of the generator (see the message). Generators may import relative files and npm packages installed in the project. | |
E_STEP_UNREACHABLE |
Step that nothing reveals | With continueRevealsSteps: false only the screen’s events reveal its steps: add a click event (a marker, a button) with { “type”: “reveal-step”, “step”: n } reaching this step, let Continue reveal the steps (remove continueRevealsSteps), or let the step open once answered (steps.<n>.opens “answered”, after an activity). A step that opens once answered needs an activity (quiz, numeric, decision, free object) in the steps before it. | |
E_COMPONENT_UNKNOWN |
Unknown block type | Use a built-in type or the id of a component of components/ (elabora_list_components). | |
E_COMPONENT_ID |
Component id problem | The id equals the folder name and is not a built-in type (heading, text, quiz…). Fork a built-in under a new id instead. | |
E_COMPONENT_EXTENDS |
Component parent problem | extends.component must name an existing component without cycle. Video, audio and free objects are rendered by code: place them in a slot instead of forking them. | |
E_COMPONENT_SCHEMA |
Props schema of a component invalid | props (or propsExtend) must be a JSON Schema of type object; x-kind is one of text, markdown, tex, asset, token; the keys of x-enum-labels (how the values of a choice read in the inspector) are values of its enum. | |
E_COMPONENT_TEMPLATE |
Template not allowed or broken | Templates hold structure, decoration and bindings only: no script, style, iframe, form, link, media, event handler or external URL. Bind only declared props; data-each needs a list prop; buttons and inputs need a behaviour hook; images bind src to an asset prop and alt to a text prop (or alt=“”). See the components page (elabora docs components). | |
E_COMPONENT_HOOK |
Behaviour hook missing or misplaced | A fork of quiz, numeric, decision or results keeps its behaviour: its template must provide the hooks listed in the message (elabora docs components), on the right elements. Behaviour hooks are not allowed elsewhere. | |
E_COMPONENT_SLOT |
Slot problem | Declare every slot in component.json and mark it with an empty data-slot=“<id>” element (not repeated, not conditional); place blocks only in declared slots that accept their type. | |
E_COMPONENT_LEVEL |
Component used at the wrong level | Screen-level components (level “screen”) are layouts: screen.layout. Block-level components are block types. | |
E_COMPONENT_PROPS |
Component props invalid | Give values matching the props schema of the component (elabora_get_schema <component id>). | |
E_COMPONENT_FALLBACK |
Fallback produces invalid native blocks | Fix the fallback templates of component.json: each item must give a built-in type and props valid for it once filled with the props. | |
E_COMPONENT_MIGRATION_PENDING |
Component instances need a migration | The definition changed version and migrations.mjs has steps the instances have not been through: run elabora component migrate (MCP elabora_migrate_components). |
|
E_COMPONENT_EXAMPLE |
Component example invalid | Examples are checked like instances: fix the props of the example. | |
E_LOCKED |
Project locked by another writer | Another Elabora tool (the app, a CLI command, the MCP server) is writing this project: run the command again in a moment. A lock left by a stopped process is broken automatically (at once on this computer, after 30 s from another one); delete the lock file named in the message only if no Elabora tool runs and it stays. | |
E_CONFLICT |
Files changed while the edit was computed | Another program (an editor, an agent’s own file tools) wrote the files this edit touches at the same moment. Run the command again: it reads the files as they are now. | |
E_BLOB_MISSING |
Content of a binary file not kept | The edit or the undo needs the bytes of a binary file that the blob store does not have and that the project no longer holds (the file changed or was deleted meanwhile). Run the command again; to bring a file back, restore it from a backup (elabora backup restore). | |
E_OP_TARGET_MISSING |
Edit target not found | The file, key, element or anchor (after) the edit names is not in the project: it was removed or renamed meanwhile, or the id is wrong. Read the current state (elabora_get_screen, elabora overview) and give existing ids. | |
E_OP_DUPLICATE |
Element already in the list | The list already holds an element with this id: choose another id for the new element, or move or update the existing one. | |
E_OP_NOT_KEYED |
List not addressable by id | The edit selects an element by id in a list whose elements are not objects with distinct ids (or distinct strings). Fix the duplicate ids first (E_DUPLICATE_ID), or replace the whole list. | |
E_OP_NOT_JSON |
File is not a JSON document | The edit changes a value inside a file that is not JSON or does not parse. Fix its syntax first (E_JSON_PARSE), or write the whole file. | |
E_OP_INVALID |
Invalid edit | See the message: a block cannot move into itself, and ids are permanent (remove the element and add it again to give it another id). | |
E_PLAN_PERSON_ONLY |
A person’s decision on the plan | Making a version of the plan and recording the client’s validation are the author’s: in Elabora (Plan › Versions) or in a terminal. An agent writes the plan, then tells the author it is ready to send. | |
E_PLAN_VERBATIM_LOCKED |
A text kept « à l’identique » is the author’s to change | The client wants this text as signed: an agent never changes its words, its flag or removes it. Leave it as it is, or ask the author, who changes it in Elabora (the text, « Déverrouiller »). | |
E_CONVERT_REFUSED |
A block that does not fit the type it is converted into | The message says what does not fit (too many items, a text too long, a picture missing). Shorten or complete the block first, or choose another target: elabora convert <screen> <block> –dry-run lists the possible ones. | |
E_GATE_SMOKE |
Gate 2 failed: mount/run/dispose | See console errors in the message. | |
E_GATE_BEHAVIOUR |
Gate 3 failed: behaviour test | Fix the code or, if the expected behaviour changed, the test (with a reason). | |
E_GATE_BUDGET |
Gate 4 failed: budget exceeded | Reduce draw calls, triangles or textures, or raise the budget with a justification. | |
E_OBJECT_STRINGS |
Object strings of a block do not match the manifest | props.strings only rewords strings the manifest declares (strings), with the same placeholders in braces: {gap}, {n, plural, …}. | |
E_OBJECT_ENUM_LABELS |
Words given for a value a setting does not take | x-enum-labels (manifest) and props.enumLabels (block) say how the values of an enum read in the editor: each key is one of its values (numbers written as text). In a block, the keys of props.enumLabels are props with an enum, or <prop>.<field> for a field of a list’s items. | |
E_OBJECT_DECORATION |
Decorative object misused | A decoration (pedagogicalRole “decoration”) only lives in theme.backdrop.object: it emits no events, keeps no state and takes no focus. A scene the learner uses or learns from is a free-object block with a role, plan objectives and a text alternative. | |
E_BACKDROP_OBJECT |
Backdrop object not usable | theme.backdrop.object.id names a free object of objects/<id>/ whose manifest has pedagogicalRole “decoration”; its props must match the manifest. | |
E_BACKDROP_VARIANT |
Unknown backdrop variant | A screen backdrop is “none” or a variant declared in theme.backdrop.variants (with its name and a one-line description). | |
E_GATE_VISUAL |
Gate 5 failed: snapshot differs from baseline | If the change is intended, accept the new baseline with –update-snapshots. | |
E_GATE_CONTEXT_LOST |
Gate 5 not run: the WebGL context was lost before a snapshot | The browser’s GPU process gave way, most often on a loaded machine; the test was run again and lost it again. Run the gates again when the machine is quieter; if it happens on a quiet machine, the object asks too much of the GPU (textures, draw calls, contexts). | |
E_GATE_A11Y |
Gate 6 failed: accessibility | See the axe rule in the message. | |
E_LMS_API_NOT_FOUND |
SCORM API not found in this launch topology | The runtime searches parents and the opener chain; report the topology if this happens with an Elabora package. | LMS-6 |
E_LMS_DATA_LOST_ON_CLOSE |
Data lost when the window closed | Commit earlier; nothing that is not committed before close survives. | LMS-1 |
E_LMS_RESUME_FAILED |
Resume did not restore the learner position | Check lesson_location and suspend_data handling. | LMS-5 |
E_LMS_STATUS |
Unexpected lesson status | See expected and measured values. | LMS-13 |
E_LMS_STATUS_REGRESSION |
Status regressed | A completed or passed status must never go back to incomplete. | LMS-13 |
E_LMS_UNLOAD_LISTENER |
Content registers unload/beforeunload | Remove it: unload no longer fires in Chrome and Edge; use visibilitychange and pagehide. | LMS-1 |
E_LMS_SET_VALUE_REJECTED |
LMS rejected a value | See the element and the SCORM error code. | LMS-3 |
E_LMS_INITIALIZE_TWICE |
LMSInitialize called twice | Never re-initialise a finished API (bfcache restore). | LMS-5 |
E_LMS_NO_FINISH_ON_QUIT |
Quit did not call LMSFinish | The Quit button must commit and call LMSFinish. | LMS-1 |
E_LMS_SCENARIO |
Emulation scenario failed | See the message. |
Warnings
| Code | Title | Fix | Rule |
|---|---|---|---|
W_SCREEN_FILE_UNUSED |
Screen file not listed in course.json | Add it to a section or delete the file. | |
W_SYNC_CONFLICT_COPY |
File left by a sync service, not loaded | Conflict copy (OneDrive, Dropbox, iCloud, Google Drive): compare it with the original, keep the right content in the original file, then delete the copy. Cloud placeholder: make the folder available offline so the file is downloaded. | |
W_MEDIA_NOT_OPTIMIZED |
Media file not in its master format | Run elabora media optimize <path>: the file becomes a web master (MP4 H.264/AAC, M4A, WebP), its metadata (GPS positions of phones included) is removed and references follow a new extension. Bring new media in with elabora media import, never by copying files into assets/. |
|
W_PLAN_DRAFT |
Plan not validated yet | Fine for drafts and previews. The plan is written at any time (elabora plan write, MCP elabora_write_plan); before a client delivery, a person makes a version of it, sends it and records the client’s validation (Elabora › Plan › Versions, or elabora plan version then elabora plan approve --by "<name>"), and you build with –release. |
A5 |
W_PLAN_MODIFIED_SINCE_VALIDATION |
Plan changed since its validated version | Fine while you work: the plan is written directly and its diff says what changed (elabora plan diff, the app’s marks); a release build lists the changes in its proof dossier and its result. To deliver them as validated, a person makes a new version, sends it and records the client’s validation. |
A5 |
W_PLAN_VERBATIM_CHANGED |
A text kept « à l’identique » changed since its validation | The client wants this text as signed. If the author changed it deliberately, the next version holds the change and the client validates it; otherwise bring the validated words back (the app’s « Revenir à la V2 », elabora plan revert text:<id>). Agents never change it. |
A5 |
W_OBJECTIVE_NOT_PRACTISED |
Objective without practice or assessment | Add a quiz, decision or free object linked to this objective (guardrail A2). | A2 |
W_OBJECTIVE_VAGUE |
Objective is not observable | Start with an action verb describing what the learner does (choose, diagnose, write…), not understand or know. | A3 |
W_SPACING_MISSING |
No spaced retrieval planned | Add plan.spacing (for example D+2, D+7, D+30) and deliver it through the LMS or emails. | B5 |
W_BUSINESS_GOAL_MISSING |
No business goal in the plan | Record the business outcome the course serves (plan.businessGoal). | A4 |
W_NEUROMYTH |
Unsupported learning claim | Learning styles and similar claims are not supported by evidence: propose an alternative to the author, who decides with the client. On a screen that names a myth to refute it, the author may ignore this finding until the words around it change; in the plan, it is the client’s (a waiver). | E7 |
W_EXPOSITION_STREAK |
Too many screens without learner activity | Insert a retrieval, decision or production activity (quiz, decision, free object) every few screens. | B1 |
W_QUIZ_OPTION_COUNT |
Unusual number of options | Three plausible options are usually best; avoid two-option items except true/false. A true/false question or a deliberate fourth distractor: the author may ignore this finding until the number of options changes. | C1 |
W_QUIZ_ALL_NONE |
“All/none of the above” option | Replace it with a plausible distractor. When the option is deliberate (the author judged it), the author may ignore this finding until the option’s text changes. | C1 |
W_QUIZ_NEGATION |
Negative stem not highlighted | Avoid negative stems or put the negation in bold. When the negation belongs to a quotation (a maxim, a source cited word for word), the author may ignore this finding (« Ignorer », or elabora ignore with its key): it comes back if the stem changes. | C1 |
W_QUIZ_LENGTH_CUE |
The correct option is noticeably the longest | Make options homogeneous in length and form. When the right answer must be precise and the distractors cannot be lengthened honestly, the author may ignore this finding until the options change. | C1 |
W_QUIZ_NO_CORRECT |
Question without correct option | Mark at least one option correct (or use a decision block for opinion questions). | C1 |
W_TEXT_DENSITY |
Dense screen | Slides: keep a screen under about 250 words; split it or move detail to an accordion or a layer. Scroll pages: break more than about 450 words of reading in a row with something to do (a knowledge check, an interaction, an accordion, a step), and split a page of more than about 1,500 words into two lessons. When the reading is the activity (a primary text, a source studied closely), the author may ignore this finding until the number of words changes. | E3 |
W_DEAD_BUTTON |
Button without click event | Add an event { on: { type: “click”, target: <block id> } } (with “name” for a named button: data-t-click=“name”) or remove the button (built-in button, or a component whose template has a data-t-click button). | |
W_DECISION_WITHOUT_CONSEQUENCE |
Decision without consequence | Give each option feedback or an event (show a layer, go to a screen). | D3 |
W_ACTIVITY_NO_FEEDBACK |
Fill-in or sort without feedback for wrong answers | Write feedback.incorrect: the rule or the clue that leads to the answers, without giving them (they show in place after the last try); and feedback.correct: why the answer holds. | D1 |
W_UNREACHABLE_LAYER |
Layer never shown | Add a show-layer action or remove the layer. | |
W_COMPLETION_MISMATCH |
Screen completes before its activity | Use completeWhen: “interactions-done” on screens with quizzes, decisions or free objects. | |
W_QUOTE_REPEATS |
Statement that repeats a text of its screen | A statement (or a quotation) whose words are also in a text block of the screen reads twice, as a decorative pull quote does: say it once. Keep the statement for the one idea to remember and cut the sentence from the text, or keep the text and remove the statement. | E4 |
W_COLUMNS_HIDDEN |
Block in a column that is not shown | Columns with count 2 show the slots first and second only: move the block into one of them, or set count to 3. | |
W_ITEMS_MANY |
More items than the block shows well | Past these counts a form of a block is hard to follow (D63): tabs over 7, a carousel’s steps over 7 (its intro and summary aside), markers on a picture over 8, cards over 12, a gallery’s carousel over 5 images. Split it into two blocks (two processes, two pictures), keep the items that matter, or choose a presentation that lists them (an accordion, a timeline). | E3 |
W_TABS_LABEL_LONG |
Tab label too long | A tab names its panel in one or two words, 24 characters at most, so that the tabs stay on one row and read at a glance: shorten the title, or choose the accordion presentation for longer titles. | |
W_HOTSPOTS_CLOSE |
Markers that overlap on a phone | Two markers of an interactive picture are closer than their 44 px on a phone 375 px wide (x and y are shares of the whole picture): move one of them onto another point of its part, merge the two, or split the picture into two (a detail on its own picture). A focal point (focus) shows the picture half as large again on phones. | F1 |
W_STEPS_SCROLL_SLIDES |
Scroll steps in slides | A steps block in the scroll presentation (« Défilé ») follows the page as it scrolls; a slide does not scroll, so its steps show one under the other, each with its picture, and the slide may overflow. Choose presentation carousel, or pace the screen with its own steps (a block per step, step: n). | |
W_IMAGE_ALT_SUSPECT |
Alt text looks like a file name or a placeholder | Describe the information, not the file. When the alt is right after all (a short name that is the information), the author may ignore this finding until the alt changes. | F2 |
W_NUMERIC_AMBIGUOUS |
Misconception accepted as correct | A misconception value lies within the tolerance of the answer: reduce the tolerance or change the misconception. | |
W_PLAYER_NO_WAY_BACK |
No way back in the player | Enable Previous or the outline (elabora player . –enable previous), so that learners can go back to a screen they saw. Ask the author before ignoring it: it is fine when every screen has its own back buttons (a go-to previous event on a button). | |
W_PLAYER_END_UNREACHABLE |
Next hidden and the end out of reach | Enable Next (elabora player . –enable next), or give each screen listed a way on that learners can reach: a button with a go-to event (next, or a later screen) in a step they see, and in slides steps that open by themselves (opens: “answered”) or by a reveal-step event. A narration that goes to the next screen by itself does not count: it stops on phones and for learners who choose « M’arrêter à chaque étape ». The details list the screens that lead nowhere. | |
W_PLAYER_AI_MENTION_HIDDEN |
AI mention hidden from learners | Enable « IA et crédits » (elabora player . –enable credits): it says which voices, images or videos were made by an AI, as the EU AI Act asks (Regulation (EU) 2024/1689, article 50(4) and (5)), and it gives the credits CC-BY voices require. The transcript of a narrated screen still says « Voix générée par IA ». | AI-50 |
W_PLAYER_CONTROLS_HIDDEN |
Narration without controls | Enable the player’s controls (elabora player . –enable controls): learners must be able to pause a voice, read its captions and its transcript (WCAG 2.2 1.2.2, 1.4.2, 2.2.2; EN 301 549 9.1.2.2, 9.1.4.2, 9.2.2.2; RGAA 4.1 criteria 4.3 and 4.10). | F3 |
W_PLAYER_TRANSCRIPT_HIDDEN |
Narration without transcript | Show the transcript (elabora player . –set controls.transcript=true): learners who cannot hear the voice need its words in text (WCAG 2.2 1.2.1 and 1.2.3; EN 301 549 9.1.2.1, 9.1.2.3; RGAA 4.1 criterion 4.1). | F3 |
W_PLAYER_EXIT_HIDDEN |
Quit hidden in an LMS package | Enable Quit (elabora player . –enable exit): it saves and ends the session in the LMS, which otherwise ends only when the window closes (D3). A module for the web never shows it. | LMS-1 |
W_SOUND_CREDITS_HIDDEN |
A sound’s credit hidden from learners | Enable « IA et crédits » (elabora player . –enable credits): a CC BY sound must credit its author where learners can read it. CREDITS.txt in the package is for the LMS’s administrators, not for learners. | |
W_SOUND_DUCK_LOOP |
An ambience asked to lower the music | Remove duck from the ambience: it is one of the sounds a duck lowers, and it plays for the whole screen. To hear it over the music, lower the music (its volume in sounds.background). duck is for a sound played once (no loop) that must be heard over the music and the ambiences. | |
W_SOUND_MUSIC_SWITCH_HIDDEN |
Music or ambiences learners cannot stop | Enable « Affichage » (elabora player . –enable display): it has « Musique et ambiances », which learners switch off (WCAG 2.2 1.4.2: audio that plays by itself for more than 3 seconds can be paused or stopped). The player’s volume alone only shows on narrated screens. | F3 |
W_RESOURCE_TYPE |
Resource in a format LMS servers may refuse | Give learners the file as PDF, an office document, text, CSV, an image, audio, video or a ZIP: formats every LMS web server serves (IIS refuses unknown extensions). Zip a file of another kind. | LMS-8 |
W_PLAYER_LOGO_CONTRAST |
Logo that would not read on its bar | Put the logo on its light plate (elabora player . –set logo.plate=true), give the bar another colour (player.top.background), or use a version of the logo made for that background. Ask the author before ignoring it. measured is the best ratio of its colours on the bar, limit the ratio it needs (3); details give the bar (top or bottom), its token, its background and the logo’s file. | |
W_EVENT_NO_ACTION |
Event without action | Give it what to do (do, or else when it has conditions), or remove it: an event without actions does nothing. | |
W_THEME_EFFECT_UNDEFINED |
Theme effect without its keyframes | course.json theme.effects declares the effect: define @keyframes t-fx-<name> in the theme stylesheet (and t-fx-<name>-out for its going, otherwise it plays backwards). Until then the player fades. | |
W_TIMING_STEP |
Block anchored before its step opens | Its timing.in falls in an earlier step’s stretch, but a block shows only once its step is reached: it comes when its step opens, not at the anchor. Anchor it to a line of its own step, or give it the anchor’s step. | |
W_TEXT_TOO_FAST |
Text shown too briefly to be read | Learners need time to read what appears: about one second for 17 characters, 1.5 s at least (the message gives the time it stays and the time it needs). Keep the block longer (anchor its out later, or remove out), or shorten its text. A line that says more than 25 characters a second goes faster than most learners read its captions: say it slower (the voice’s speed) or cut it in two. | |
W_MOTION_LONG |
Movement longer than five seconds | Effects of timed blocks run one into the other for more than five seconds (WCAG 2.2.2): learners can stop them with the bar’s Pause, but keep effects short and leave still moments between them, or let a step end in between. | |
W_STACK_UNTIMED |
Stack content without a moment | Each content of a stack after the first comes at its own moment: give it a timing.in anchored to the word that brings it. Without it, it shows with the content before it, one over the other. | |
W_NARRATION_AUDIO_MISSING |
Narration line without audio | Generate the voice (the voice tools) or import a recording: elabora narration import . <screen> <line> <file> (MCP elabora_import_narration) writes assets/narration/<language>/<screen>/<line>.m4a and its sidecar. Until every line of the screen has its audio, its timeline runs silent on estimated times, with its captions. |
|
W_NARRATION_LINE_LONG |
A narration line that runs long | A line is a few sentences, 5 to 20 seconds: past 45 s it is hard to follow, to time and to correct (the word aligner reads such a recording in pieces, and the whole line is made again for one changed word). Cut the text into several lines at its sentences, then make or import the audio of each. Nothing is blocked: a long line plays and is timed as any other. When the line is one breath on purpose, the author may ignore this finding until its audio’s length changes. | |
W_NARRATION_WORD_SWALLOWED |
A word the voice may have swallowed | The word alignment found almost nothing of this word in the audio: listen to the line. If the word is missing, make another take (elabora voice generate . <screen> –line <line>) or record it again; a word said, even badly, is not flagged. A word said as a native speaker says it, almost swallowed, may be ignored by the author in the editor (« Ignorer », kept in course.json ignored for this word of this take): an ignored finding counts no more, and agents leave it alone; another take brings it back. | |
W_NARRATION_AUDIO_STALE |
Narration audio out of date | The text, the audio file or the speaker’s voice changed since the audio was made (the message says which): generate or record the line again. Until then the voice says something else than the captions. | |
W_AUTO_ADVANCE |
Narrated screen that goes on by itself | advance: “next-screen” plays the steps one after the other and goes to the next screen by itself: a time limit learners did not choose (WCAG 2.2.1). Prefer “auto” (the steps follow each other, then the screen waits for Next) or “learner” (the default: it stops at each step and waits for Continue); learners can still turn it into learner with « M’arrêter à chaque étape ». Keep it, waived in the plan, for a screen that must run on by itself (an introduction, credits). | F1 |
W_SEGMENT_TOO_LONG |
Step of narration too long | More than about 90 seconds of voice in one step without a pause for the learner (segmenting principle): cut the lines into two steps, so Continue paces them (elabora narration split . <screen> <line>: that line starts the next step), or move part of it to another screen. | E3 |
W_NARRATION_DUPLICATED |
On-screen text repeats the narration | Learners read and hear the same words at once, which loads them more than either alone (redundancy principle): keep the words in the voice and show keywords, a figure or a diagram instead (rule E4). The captions already give the text to those who need it. When learners should read along on purpose (a text studied, a quotation read aloud), the author may ignore this finding until the line or the block changes. | E4 |
W_TIMED_INCREMENT |
Counting on a timeline cue | Cues fire again each time playback crosses them (a learner who replays a step crosses them again): increment-variable on timeline.reached counts replays. Set a value (set-variable) instead, or count something the learner does. | |
W_NO_SCORED_ITEMS |
Pass/fail reporting without scored items | Add scored quizzes (or scored decisions/objects), or report completed-incomplete. | LMS-13 |
W_SUSPEND_DATA_NEAR_LIMIT |
Worst-case suspend data above 80 % of the LMS limit | Leave headroom for future versions of the course. | LMS-3 |
W_PACKAGE_LANGUAGE_LEFT_OUT |
A translation left out of the package of every language | elabora build –languages all packages the translations whose texts are all translated and up to date and whose translated plan is approved (D59): the message says what this one lacks. Translate the texts it lists (elabora translate status . –to <lang>, MCP elabora_translation_status), have a person approve the translated plan (elabora translate approve), then build again; or build without it on purpose. | |
W_PACKAGE_TOO_LARGE_FOR_SOME_LMS |
Package larger than some LMSs accept, and no LMS chosen | Choose the LMS: delivery.lms in course.json (elabora profiles lists them), or –profile; the build then checks its own limit. If it is one of those named, lower the media quality as the message says. | LMS-8 |
W_PACKAGE_TOO_MANY_FILES_FOR_SOME_LMS |
More files than some LMSs accept, and no LMS chosen | Choose the LMS: delivery.lms in course.json, or –profile. If it is one of those named, merge assets or split the course. | LMS-8 |
W_COMPRESSION_RATIO_FOR_SOME_LMS |
Compression ratio above what some LMSs accept, and no LMS chosen | Choose the LMS: delivery.lms in course.json, or –profile. If it is one of those named, store already-compressed data or split very repetitive files. | LMS-8 |
W_PROFILE_TO_MEASURE |
LMS profile has unmeasured values | Test the package in a real instance of this LMS and update the profile. | LMS-15 |
W_WEB_IMAGE_WITHOUT_URL |
Sharing image without the module’s address | Sharing previews (LinkedIn, Slack, Teams, Facebook) only read an image at an absolute address: build with –url and the address where the module will be served. | |
W_UPDATE_BREAKS_RESUME |
This update affects learners in progress | See the per-LMS table: publish as a new version, or keep removed ids. | LMS-7 |
W_OBJECT_LITERAL_COLOR |
Hard-coded colour in free object code | Declare the colour as a prop (format color, x-control color) so authors can change it without code: bound to a theme token (x-token) when it carries the course identity, with a literal default when it is a material of the scene (brass, wood). A colour the object draws text in names its background with x-text-on. | A5 |
W_OBJECT_PROP_CONTROL |
Editor control does not fit the prop | x-control follows the type: text, textarea and asset for strings, color for a string of format color, select for a value with an enum (or an integer between a minimum and a maximum), slider (with minimum and maximum) and number for numbers, toggle for booleans, list for a list (type array with items), range for a low and a high number (two items with minimum and maximum, low first), vec2 for two numbers, vec3 and vec3-gizmo for three. | |
W_OBJECT_TESTS_MISSING |
Free object without behaviour tests | Write object.tests.json (gate 3) before integrating the object. | |
W_OBJECT_NOTES_MISSING |
Free object without reviewer notes | Write object.notes.md: its pedagogical role in two or three sentences for the client review. | |
W_OBJECT_PROP_UNUSED |
Declared prop never read by the code | Read it from ctx.props/update(nextProps) or remove it from the manifest. | |
W_OBJECT_UNUSED |
Free object placed on no screen | Place it with a free-object block on a screen covering the items it serves, or use a decoration as the course backdrop (theme.backdrop.object); otherwise delete its folder in objects/. | |
W_CONTINUITY_ALONE |
A continuity key on one block only | Continuity carries a block on to another screen whose block has the same key: give that key to the matching block of the screen it should continue on (the previous or the next one), or remove it. | |
W_STYLE_LITERAL_COLOR |
Hard-coded colour in a stylesheet | Use var(–t-…) tokens, or declare the colour in course.json theme.custom so a charter change (or an editor) can update it. | |
W_STYLE_FIXED_FONT_SIZE |
Font size in px | Write font sizes in rem (px ÷ 16 at the reference window, 1600×900): 1rem follows the size classes of the player, so text gets smaller at 1280×720 and on phones with the rest of the design. clamp() with vw is fine when its bounds are in rem. | |
W_FONT_LICENSE_MISSING |
Font file without its licence next to it | Put the licence of the font (OFL.txt, LICENSE.txt…) in the same folder as the font file: free font licences let a course embed a font when their text travels with it, and the build copies the licence files of that folder into the package. elabora font add brings a vetted font with its licence; for another font, elabora font add --from <@fontsource package folder or .tgz> or --file <font.woff2> --license <file> copies both. Check that the licence allows embedding (SIL OFL and Apache do). |
|
W_STYLE_OVERRIDES_NESTED |
@layer overrides inside another rule | Only the theme stylesheet’s top-level @layer overrides { … } blocks override the components (layer elabora.overrides). Inside @media or another rule it is a sub-layer of the theme and gives way to the components: put the block at the top level and the @media inside it. |
|
W_STYLE_COMPONENT_OVERRIDDEN |
A component’s rule overridden by the theme | Measured in the page (elabora look, elabora fit): a rule of the component’s stylesheet is overridden by a theme rule that does not name the component, so the component looks different in this course than its stylesheet says, and differently again once published to a library. In a course whose theme comes after the components (no theme.cascade), run elabora theme upgrade; then, or in an upgraded course where the theme rule sits in @layer overrides, move it out of the block if it is a course-wide default, or scope it so it leaves the component alone (:not(.t-layout--<id> *)). To restyle the component on purpose, write the rule in @layer overrides naming the component (.t-block--<id> …, .t-layout--<id> …). |
|
W_STYLE_THEME_UNDER_COMPONENT |
A theme rule for a component that the component overrides | Measured in the page: a theme rule that names a component (its .t-block–<id> or .t-layout–<id>, or its own classes) sets a property the component’s stylesheet sets too, and the theme’s rules come before the components (theme.cascade components-over-theme, D32), so it does nothing. To override the component from the theme, put the rule in the theme’s top-level @layer overrides { … } block; or change the component’s stylesheet, or a custom property it reads (var(--<name>, <default>)). |
|
W_STYLE_TEXT |
Text written in CSS | content: “…” cannot be translated or edited by authors: put the words in a block. | I1 |
W_ASSET_SVG_TEXT |
Words inside an SVG figure | Text inside an image cannot be translated, edited or reflowed on phones. Keep numbers, symbols and markers in the figure; put labels and legends in blocks next to it (a numbered list, a caption, a layout slot), or mark the image decorative. | I1 |
W_IMAGE_INLINE_NOT_SVG |
Inline image that is not an SVG | inline: true puts an SVG drawing in the page (for the draw effect and the theme’s CSS); a bitmap stays an <img>. Remove inline, or use the SVG version of the figure. | |
W_SVG_INLINE_SANITIZED |
Inline SVG with parts removed | An SVG put in the page loses what is not safe there: scripts, event handlers, foreignObject, links and references to files or sites (only #fragments and data: images stay). Draw the figure without them (change its generator) so that the page shows what the file shows. | |
W_IMAGE_INLINE_HEAVY |
Heavy SVG put in the page | An inline drawing is part of the course data every learner loads, on every screen’s first visit. Simplify it (fewer points, rounded coordinates, shared <defs> and <use>), or keep it as an image (inline: false) when it does not need the draw effect. | |
W_TIMING_DRAW_IMAGE |
Draw effect on an image the page cannot trace | draw traces the strokes of the block’s own drawing. An image block shows an <img>, whose strokes the page cannot reach: set inline: true on the block for an SVG (local or generated). A bitmap has no strokes: use wipe or fade. | |
W_CHART_ORDER |
A funnel that widens | A funnel shows what remains at each stage, so its values go down from top to bottom. Order the stages, use shape “pyramid” for levels that are not a flow, or bars to compare values. | |
W_DIAGRAM_COLOR |
Colours written in a diagram | classDef, style and linkStyle lines are left out: diagrams take the course’s colours, so that every theme, dark ones included, stays readable. Remove them; highlight brings one node forward in the accent. | |
W_DIALOGUE_UNREACHABLE |
A part of a dialogue no path reaches | No choice leads to this node or ending: link it (an option’s next, a node’s next, end) or remove it. elabora dialogue paths <block> lists what every path reaches. |
|
W_DIALOGUE_LOOP |
A dialogue loop with no way out | From these nodes no path reaches an end: give one of them an option (or a next case) that leaves the loop, or an end. Loops are fine as long as one way leaves them (a question hub with once options and a « Passer à la suite »). | |
W_DIALOGUE_OPTIONS_MANY |
More than four options in a decision | Three options (good, ok, bad) are usually best: more slows the learner down and gives the right one away less than it dilutes it. Merge or remove some, or split the decision in two. A deliberate hub of questions may keep them: the author may ignore this finding until the options change. | |
W_DIALOGUE_OPTIONS_UNEVEN |
Options of very different lengths | The longest option (button text) is more than two and a half times the shortest: learners spot it without thinking. Rewrite them to a similar length and form, or give the long one a shorter label. | |
W_DIALOGUE_LINE_LONG |
A line too long for a bubble | A bubble reads at a glance: one or two sentences (under 280 characters). Split the line in two (two lines of the same speaker follow each other), or move the explanation to the option’s feedback. | |
W_DIALOGUE_SCORE_MISSING |
A scored dialogue misses what it counts | scoring quality reads each option’s quality (good, ok, bad), points its points, ending each ending’s score: give them to every option (or ending) of the dialogue, or choose another scoring. An option without quality does not count in the quality score. | |
W_DIALOGUE_ENDINGS_UNCOVERED |
Endings that leave some scores without an ending | With end: true, the first ending whose if holds is reached; when none holds, the dialogue ends without title. Put an ending without if last, or make the thresholds cover every score from 0 to 100 (the message gives the gap). | |
W_DIALOGUE_TREE |
A dialogue that only branches | More than three decisions in a row branch without ever joining: each one multiplies the nodes to write (a fourth decision of three options adds 81). Let options join the common way (an option without next does), or bring branches back to a node they share. | |
W_DIALOGUE_NO_RETURN |
A practice dialogue that ends without a way back | In practice mode the learner should see the other consequences once the first run ends: use revisit after-end (the practice default) or anytime, so the end offers « Changer ce choix » (in the debrief, or « Reprendre d’ici » on an answer) and « Recommencer ». For a test, use mode assessment. | |
W_CHARACTER_CONVENTION |
A character that does not follow the convention | The player sets a character’s state on <g data-part=“character”> and shows its parts by their data-mouth, data-expression and data-gesture (docs/dialogues.md, characters): wrap everything that moves in that group, draw the four mouths (data-mouth=“closed|small|open|wide”, without data-expression), declare data-expressions (and data-default-expression among them) and data-gestures (name:seconds) on the root, and give each expression its parts. Copy the parts of a sample character and keep its tree. | |
W_CHARACTER_CONTENT |
A character holds what the convention forbids | A page shows a character several times (the scene, an avatar): no id (so no gradients, clip paths, masks or filters; flat shapes instead), no text (its name is in the bubbles), under 40 KB. Remove them from the SVG. | |
W_DIALOGUE_LOOK |
An expression or a gesture the character does not have | A character shows the expressions and plays the gestures its look declares: the expressions of its pictures (look.expressions), or its SVG’s data-expressions and data-gestures. Use one of those the message lists, or add it to the character’s look. | |
W_DIALOGUE_DECISION_CAP |
A dialogue path reaches the decisions cap | A path stops after 60 decisions (a loop of next without end would be endless, and the learner’s saved path must fit the LMS). Give the loop a way out that every learner takes, or once options that run out. | |
W_GENERATED_ASSET_STALE |
Generated asset out of date | Run elabora assets (MCP elabora_build_assets): the generator, a file it imports or a theme token changed since the asset was generated. |
|
W_GENERATED_ASSET_EDITED |
Generated asset edited by hand | Change the generator instead: the next elabora assets run overwrites the file. |
|
W_STEP_ORDER |
Step out of reading order | In scroll presentation each step appears below the previous ones: give this block a step at least equal to the blocks before it in the reading order (layout slots first, then block order), or move it. | |
W_STEP_SETTING_UNUSED |
Settings for a step the screen does not have | screen.steps sets how steps open, keyed by step number: give settings only to steps that blocks of the screen carry, after the first one (the first step is shown from the start). A step that opens once explored (opens “explored”) needs, in the steps above it, an activity or a block with controls (a sequence, flip cards, disclosures, tabs…) that is not optional; otherwise use opens “continue”. | |
W_STEP_PLACEMENT |
Step on a nested block | Steps apply to the blocks of the screen. Put the step on the component instance (its slots follow it) or remove it; blocks of a layer appear with the layer. | |
W_SLIDE_OVERFLOW |
Slide taller than the reference window | At the reference size (presentation.fit.reference, 1600×900 by default) the screen scrolls. Split it into two screens, tighten the layout (side-by-side slots, smaller figures), or move secondary content to a layer or an accordion. A quiz reserves the room of its tallest feedback: feedbackStyle: "compact" shows the feedback of the chosen option without repeating its text (the message names the quizzes and what it saves). Steps do not save room in slides: they keep their place. elabora fit measures again in seconds. |
F1 |
W_SCROLL_ANIMATION_UNFINISHED |
Scroll animation that cannot finish | Measured by elabora fit on scroll pages, with animations on: an animation driven by the scroll (animation-timeline: view() or scroll()) has not reached its end when the page is scrolled to the bottom, so the last blocks stay half faded, moved or turned. End its range sooner (animation-range: entry 0% cover 40%, rather than cover 100%), start it earlier, or leave room below the block. elabora look –scroll 100% –block <id> shows where it stops. | F1 |
W_TEXT_CONTRAST_MEASURED |
Text hard to read over its background | Measured by elabora fit against the pixels behind the text (backdrop, images, gradients), at the reference size and on a phone (375×812, down the page) with animations stopped: put the text on a panel (a background with enough opacity), dim the backdrop behind it (a variant for this screen), or change the text colour. WCAG 1.4.3: 4.5:1, 3:1 for large text. | F1 |
W_PLAYER_BAR_WRAPS |
A bar of the player goes onto two lines on a phone | Measured by elabora fit at 375×812: the items of the bar do not stand on one line (the Next button falls under the others). Give the bar fewer items (elabora player: progress is often the one to drop, the outline and the rail already say where the learner is) or shorter labels. | F1 |
W_SLIDE_SHIFT |
Answering moves the slide | In slides, an interaction must not push content around. The player reserves the room of activity feedback and keeps concealed blocks in place; what still grows is usually a component whose template opts out of the reserve, a free object asking for a new height, or text changed by an event. Reserve the room in the layout, show the content in a layer (presentation “panel” keeps the slide usable), or reveal it as a step. | F1 |
W_RENDER_OVERFLOW |
Content wider than a phone screen | At 375 px the screen scrolls horizontally: stack layout slots on narrow screens (container or media queries), give wide elements max-width: 100%, let tables and equations scroll inside their block. | F1 |
W_COMPONENT_FALLBACK_LOSS |
Text not carried by the fallback | Exports, text views and detach would lose this text: add the prop to the fallback of component.json. | I1 |
W_COMPONENT_TEXT |
Words in a component template | Words in a template cannot be translated or edited by authors: make them a prop, use a player label (data-t-label), or put them in a block of a slot. | I1 |
W_COMPONENT_DECORATION |
Decoration exposed to screen readers | Add aria-hidden=“true” to decorative SVG, or role=“img” with an aria-label bound to a prop. | F1 |
W_COMPONENT_ID_ATTR |
Fixed id in a template | Ids repeat when the component is used twice: write id=“name-{{@id}}” (and url(#name-{{@id}})), or rely on behaviour hooks. | |
W_COMPONENT_PROP_UNUSED |
Declared prop used neither by the template nor by the fallback | Bind it in template.html or remove it from the props schema. | |
W_COMPONENT_UNUSED |
Component never used | Place it on a screen or delete components/<id>/. | |
W_COMPONENT_DIVERGED |
Library component edited in the course | This copy differs from the library version it came from: publish it back (elabora component publish), or fork it under a new id so later upgrades do not overwrite it. | |
W_UI_LABELS_LANGUAGE |
Player labels missing for the course language | The player has labels in fr, en, de, es, it, nl and pt; in another language the missing ones fall back to English. Give every label in course.ui, with the placeholders of its English text: the message names the missing keys, and packages/player/src/labels.ts in elabora-core holds every key with its English text. | |
W_OBJECT_STRINGS_LANGUAGE |
Object words in another language than the course | The manifest strings are written in its language; give this block the wording in the course language with props.strings (every key), or translate the course with elabora translate. | |
W_OBJECT_STRING_UNDECLARED |
Object code uses an undeclared string | Declare every key read with ctx.t(key) in the manifest strings, with its text and a description for translators. | |
W_GATE_BOOT_SLOW |
Free object slow to start | Return from mount() sooner: build the scene, render a first frame, then spread heavy work (procedural textures, large geometries) over the next frames with host.onFrame. Budget: budgets.bootMsMax (3 s by default, measured with software WebGL). | |
W_GATE_VISUAL_BLANK |
Gate 5: a baseline just recorded is a single colour | The object drew nothing in that snapshot: a canvas sized from a container of no size, a WebGL context lost on a loaded machine, a drawing outside the frame. Look at the PNG; run elabora object test again on a quieter machine, or fix the drawing, then record it again with –update-snapshots. |
Information
| Code | Title | Fix | Rule |
|---|---|---|---|
I_FORMAT_OUTDATED |
Course in an older format, read migrated | Run elabora migrate to write the migration listed in the message (one change after a backup version; elabora undo reverts it). Until then Elabora reads the course migrated in memory, and the first edit through Elabora migrates it. |
|
I_EXTERNAL_LINK |
Link to an external site | Fine for references; it opens in a new tab and needs network access. | |
I_MEDIA_PROCESSING |
Media file being converted | A media job is writing this file (elabora media status); it appears when the job is done, and builds wait for it. |
|
I_MEDIA_TOOLS_MISSING |
Media files not checked: ffmpeg not found | Install ffmpeg (it includes ffprobe), or set ELABORA_FFMPEG and ELABORA_FFPROBE to the executables: media can then be checked, imported and converted. | |
I_PLAN_SOURCE_UNCITED |
Objective without source | Link factual objectives to a source of truth (G1). | G1 |
I_NUMERIC_NO_MISCONCEPTION |
Numeric question without misconceptions | Add the values learners get with typical errors (wrong formula, inverted ratio, sign), each with feedback naming the error (guardrail D1). | D1 |
I_GENERATED_MEDIA |
AI-generated media | Listed for the AI Act article 50 transparency obligation; the player marks it. | AI-50 |
I_PLAYER_SPEEDS_NONE |
Narration speed locked | Offer 0.75× to 2× (elabora player . –set controls.speeds=0.75-2): learners who go at their own pace stay with the module; a locked speed meant to make them follow makes them drop out. | |
I_TIMELINE_WORDS_ESTIMATED |
Word anchors on estimated times | The line has no word times yet (its audio has not been aligned, or it has no audio): word anchors are placed in proportion to its text. Align it: elabora narration align . <screen> (MCP elabora_align_narration); the voice tools and imports align the audio they write. | |
I_NARRATION_DIRECTIONS_IGNORED |
Stage directions the voice does not play | Words in square brackets ([chuchote], [rit]) tell an expressive voice how to say a line (docs/decisions.md D29). The speaker’s voice in this language does not play them: it says the line without them, and learners never see them. Choose an ElevenLabs voice (Eleven v4) for this speaker to hear them, or leave them for later. | |
I_THEME_CASCADE_OLD |
The theme wins over the components (the cascade before D32) | This course has no theme.cascade, so its theme still comes after its component stylesheets and overrides them whatever the specificity: a general rule of the theme (.t-figure img { width: 100% }) silently beats a component’s own rule for its images. Run elabora theme upgrade (MCP elabora_upgrade_theme): one undoable change that sets theme.cascade to components-over-theme and keeps the course’s look, the theme’s rules on properties the components set too going into a @layer overrides block. Then move out of that block the rules that are course-wide defaults. |
|
I_SLIDE_SHIFT_MINIMUM |
Answering moves the slide at the minimum window | At presentation.fit.minimum an interaction moves content. Check that the activity stays usable; see W_SLIDE_SHIFT. | F1 |
I_SLIDE_OVERFLOW_MINIMUM |
Slide scrolls at the minimum window | At presentation.fit.minimum (1280×720 by default) this slide scrolls a little. That is accepted for the smallest supported size; check that nothing important is cut and that the activity stays usable. | F1 |
I_COMPONENT_SINGLE_USE |
Component used once | A component pays off when reused. For a one-off look, a native block with a named style may be simpler to maintain. | |
I_COMPONENT_PARENT_CHANGED |
The parent of a fork has changed | Review the parent changes; update extends.version once the fork is up to date. | |
I_GATE_VISUAL_OTHER_ENGINE |
Gate 5: baselines recorded for this browser, the object has another’s | Snapshots are compared with the baselines of the same browser engine (fonts and WebGL draw differently). The object’s baselines were made with another engine: run elabora object test with that –browser to compare with them, or keep the new ones for this engine. | |
I_GATE_HUMAN_PENDING |
Human review pending (gates 7–8) | Pedagogical review and code review by a person; the client sees props and notes, not code. |
Rules
What each rule asks, as Elabora checks it (packages/core/src/diagnostics/rules.ts), and the codes that cite it.
| Rule | What it asks | Codes |
|---|---|---|
| A1 | Every screen, activity or question serves an item of the plan, and every item of the plan is covered by a screen (constructive alignment). | E_PLAN_ITEM_UNCOVERED, E_PLAN_REFERENCE, E_LOCKED_TEXT_OUTSIDE_ITEM, E_PLAN_OBJECTIVE_UNUSED, E_OBJECT_PLAN_MISMATCH |
| A2 | Each objective gets practice and an assessment at the same level as the objective. | W_OBJECTIVE_NOT_PRACTISED |
| A3 | Objectives are observable behaviours (an action verb, a condition, a criterion), never « understand » or « know » alone. | W_OBJECTIVE_VAGUE |
| A4 | The plan states the business goal the module serves; when the cause of a gap is not a skill, a performance aid may serve better than a course. | W_BUSINESS_GOAL_MISSING |
| A5 | The module follows the plan the client validated: the texts and questions it keeps are referenced, never copied, and what changed since the validated version is listed. | E_PLAN_NOT_APPROVED, W_PLAN_DRAFT, W_PLAN_MODIFIED_SINCE_VALIDATION, W_PLAN_VERBATIM_CHANGED, E_PLAN_VERSION_INVALID, E_LOCKED_TEXT_NOT_USED, E_PLAN_QUESTION_NOT_USED, E_OBJECT_TRACKING_OBJECTIVE, W_OBJECT_LITERAL_COLOR |
| AI-50 | Audio, images and video made by an AI are marked as generated (EU AI Act, article 50). | I_GENERATED_MEDIA, W_PLAYER_AI_MENTION_HIDDEN |
| B1 | No more than a few exposition screens in a row without something to retrieve, decide or produce. | W_EXPOSITION_STREAK |
| B5 | Spaced retrieval is planned after the module (for example on days 2, 7 and 30). | W_SPACING_MISSING |
| C1 | Questions follow item-writing rules: about three plausible options, no « all/none of the above », no hidden negation, homogeneous options, a correct option that is not given away. | W_QUIZ_OPTION_COUNT, W_QUIZ_ALL_NONE, W_QUIZ_NEGATION, W_QUIZ_LENGTH_CUE, W_QUIZ_NO_CORRECT |
| D1 | Each option of a question has elaborated feedback (why it is right or wrong, what to review), not only « correct » or « incorrect ». | E_FEEDBACK_MISSING, W_ACTIVITY_NO_FEEDBACK, I_NUMERIC_NO_MISCONCEPTION |
| D3 | A scenario’s feedback shows the realistic consequences of each choice. | W_DECISION_WITHOUT_CONSEQUENCE |
| E3 | Segmenting: media come in short parts the learner controls, and the text on one screen is bounded. | W_TEXT_DENSITY, W_ITEMS_MANY, W_SEGMENT_TOO_LONG |
| E4 | Redundancy: on-screen text does not repeat the narration said at the same time; captions can be switched on and off. | W_QUOTE_REPEATS, W_NARRATION_DUPLICATED |
| E5 | Signalling: headings and highlights show the structure, and key concepts come before complex content. | |
| E7 | No neuromyths (learning styles and the like); an agent points out those a request contains. | W_NEUROMYTH |
| F1 | No accessibility violation found by axe-core (WCAG 2.2 A and AA) on any screen or interactive state. | W_HOTSPOTS_CLOSE, E_THEME_CONTRAST, E_HEADING_ORDER, W_AUTO_ADVANCE, E_OBJECT_TEXT_CONTRAST, W_SLIDE_OVERFLOW, W_SCROLL_ANIMATION_UNFINISHED, W_TEXT_CONTRAST_MEASURED, W_PLAYER_BAR_WRAPS, W_SLIDE_SHIFT, I_SLIDE_SHIFT_MINIMUM, I_SLIDE_OVERFLOW_MINIMUM, W_RENDER_OVERFLOW, W_COMPONENT_DECORATION |
| F2 | What tools cannot judge is reviewed by a person (RGAA 4.1.2, WCAG 2.2): relevant text alternatives, reading order, keyboard use, target sizes. | W_IMAGE_ALT_SUSPECT |
| F3 | Every medium has captions or a transcript, and every meaningful visual a text alternative. | E_IMAGE_ALT_MISSING, E_VIDEO_CAPTIONS_MISSING, E_MEDIA_TRANSCRIPT_MISSING, E_VIDEO_ALT_MISSING, E_OBJECT_A11Y_ALTERNATIVE, W_PLAYER_CONTROLS_HIDDEN, W_PLAYER_TRANSCRIPT_HIDDEN, W_SOUND_MUSIC_SWITCH_HIDDEN |
| G1 | Every factual claim (a rule, a procedure, a figure) traces to a source of the client or an expert; otherwise it is marked to be checked. | I_PLAN_SOURCE_UNCITED |
| I1 | Words live in blocks, where authors edit them and translators find them: never in stylesheets, templates or figures. | W_STYLE_TEXT, W_ASSET_SVG_TEXT, W_COMPONENT_FALLBACK_LOSS, W_COMPONENT_TEXT |
| LMS-1 | The session ends without unload: the state is committed after every change and when the page is hidden, and Quit finishes the session. |
W_PLAYER_EXIT_HIDDEN, E_LMS_DATA_LOST_ON_CLOSE, E_LMS_UNLOAD_LISTENER, E_LMS_NO_FINISH_ON_QUIT |
| LMS-3 | The learner’s state fits the suspend-data limit of each target LMS, in the worst case. | E_VARIABLE_STRING_LENGTH, E_SUSPEND_DATA_BUDGET, W_SUSPEND_DATA_NEAR_LIMIT, E_OBJECT_STATE_BUDGET, E_LMS_SET_VALUE_REJECTED |
| LMS-5 | A page restored by the browser or launched again initialises once and resumes where the learner was. | E_LMS_RESUME_FAILED, E_LMS_INITIALIZE_TWICE |
| LMS-6 | The SCORM API is found in every launch topology of the target LMSs (iframe, popup, nested frames). | E_LMS_API_NOT_FOUND |
| LMS-7 | An update keeps the progress of learners who started, or says which LMSs will lose it. | W_UPDATE_BREAKS_RESUME, E_UPDATE_BREAKS_RESUME |
| LMS-8 | The package is defensive for each target LMS: manifest at the root, portable file names, no external resource, size, file count, compression ratio and file types within its limits. | E_FILENAME_NOT_PORTABLE, E_EXTERNAL_RESOURCE, W_RESOURCE_TYPE, E_PACKAGE_TOO_LARGE, E_PACKAGE_TOO_MANY_FILES, E_COMPRESSION_RATIO, W_PACKAGE_TOO_LARGE_FOR_SOME_LMS, W_PACKAGE_TOO_MANY_FILES_FOR_SOME_LMS, W_COMPRESSION_RATIO_FOR_SOME_LMS, E_LMS_UNKNOWN, E_FORBIDDEN_EXTENSION, E_MANIFEST_NOT_AT_ROOT, E_MANIFEST_INVALID |
| LMS-9 | The package’s standard is one the target LMS supports. | E_STANDARD_NOT_SUPPORTED |
| LMS-13 | Status and score follow one state machine: a status never regresses, and pass/fail reporting needs a mastery score and scored questions. | E_MASTERY_SCORE_MISSING, W_NO_SCORED_ITEMS, E_LMS_STATUS, E_LMS_STATUS_REGRESSION |
| LMS-14 | Times are sent in the format the standard requires (cmi.core.session_time as HHHH:MM:SS.SS in SCORM 1.2) at every commit. |
|
| LMS-15 | LMS profiles are executable facts with their sources: a value not documented is listed to be measured, never assumed. | W_PROFILE_TO_MEASURE |