Changelog
All notable changes to the LC-JSON (Learning Content JSON) specification are documented in this file.
The format is based on Keep a Changelog, and this project adheres to the versioning policy described in NORMATIVE.md §8.
[1.0-rc.3] — 2026-06-13
Second publicly announced release candidate. Adds the localization model (LOCALIZATION.md) and a conformance-corpus expansion; removes two prototype-era sentenceTransformation fields from the schema (the change that requires a new immutable path — /1.0-rc.2/ cannot be mutated). Backwards-compatible with 1.0-rc.2: every rc.2-valid document remains valid under rc.3. Published at immutable /1.0-rc.3/ URLs; /1.0-rc.1/ and /1.0-rc.2/ stay served and frozen.
Removed
allowedFillerWordsandprohibitExtraWordsBetweenChunksproperty declarations removed fromsentence-transformation.schema.json. Completes the removal documented in the 2026-05-26 rc.1 doc revisions: the reference docs,VALIDATION.md§9.9, and the shipped fixtures dropped both fields then; the working schema was the last surface still declaring them. NoadditionalProperties: falseadded —1.0-rc.2documents carrying the fields continue to validate as unknown members perNORMATIVE.md§5.4 and are dropped on re-emit by conforming consumers. The frozen/1.0-rc.1/and/1.0-rc.2/schemas are unchanged.
Added
LOCALIZATION.md— language model. New normative-and-informative document specifying the three roles of language —language(delivery),lang/dir(language of parts, WCAG 3.1.2), andsupportLanguage(optional pedagogical L1 layer) — and stating explicitly that LC-JSON 1.x is single-language-per-document (translations are separate documents, not localized field bundles). Bound by newNORMATIVE.md§13 (sections renumbered: Validation surface §13→§14, References §14→§15).GLOSSARY.mdgains a “Language and localization” group.- Language tags are BCP 47.
language,supportLanguage, and HTMLlangaccept BCP 47 tags; bare ISO 639-1 (en,es) is the common case, region/script subtags (pt-BR,zh-Hant) are permitted, and a consumer MAY act on only the primary subtag. The reference validator’ssupportLanguagecheck was widened from “2-letter ISO 639-1” to a BCP 47 plausibility check (WARN), and the same check now also coverslanguage.ACCESSIBILITY.md§6.1 wording aligned. - Screen-reader pronunciation expectations (informative).
LOCALIZATION.md§7 andACCESSIBILITY.md§6.3 state thatlangis necessary but not sufficient for correct pronunciation: automatic language switching and installed voices vary across screen readers (NVDA, JAWS, Narrator, VoiceOver) and are outside the format’s control.langremains required where parts differ — it is the floor, not optional. - GitHub issue and PR templates.
bug_report.mdandspec_change_proposal.mdunder.github/ISSUE_TEMPLATE/, pluspull_request_template.mdmirroringCONTRIBUTING.md’s pre-merge checklist. RATIONALE.mdadded to the published book. The positioning page was linked from the landing page but missing from the site navigation and sync set; it now ships as a chapter (“Rationale and positioning”).globalIddocument-wide uniqueness made explicit and enforced.NORMATIVE.md§4.4: within a single document,globalIdvalues MUST be unique across all entities (Units, Lessons, Items, and Questions share one namespace); comparison is case-insensitive. Previously implied by “identify the entity across re-imports” but stated nowhere and enforced by no published artifact. Reference validator gains a document-wide duplicate check (ERROR-tier) on both the course and questionSet paths; reference fields that point at aglobalId(contentItemId,relatedItemIds) are exempt as non-declarations. NewVALIDATION.md§12.7 catalog row. Fixture:tests/invalid/40-duplicate-global-id.json(case-varied duplicate).- Validator: WARN on course-root
author(singular). Course author credits are carried by theauthorsarray; a singularauthorat the course root is not declared bycourse.schema.json(it belongs to the QuestionSet artifact) and conforming consumers discard it. Tolerated as an unknown field perNORMATIVE.md§5.4; the reference validator now surfaces it as a likely authoring mistake. The QuestionSet artifact’sauthorfield is unaffected. - Accessibility: base-vs-Profile authoring split made explicit. Base conformance is now stated as preservation only (
NORMATIVE.md§12.1) — it never requires a producer to authoralttext, captions, or transcripts, so a small or non-institutional producer is never non-conforming for omitting them (the validator surfaces omissions as non-blocking warnings). Authoring obligations are bound by the opt-in Accessibility Profile (§12.2): under a Profile claim, a producer MUST emitalton every<img>(ACCESSIBILITY.md§2.1), captions and a transcript on prerecorded instructional video carrying speech, and a transcript on prerecorded audio-only instructional content (§3.1, WCAG 1.2.1 / 1.2.2 / 1.2.3). Transcripts were previously SHOULD; they are now MUST under the Profile. No schema change — normative prose only. - Conformance corpus expanded 38 → 64 fixtures. Per-type coverage for all 12 implemented question types: 12 new valid fixtures (
valid/14–25) including bothmatchingsub-shapes (pairs,classification),orderingwithscoringMode: "kendall", and a grading combination matrix (valid/25) exercising all four graded/ungraded × exercise/quiz combinations with a resolvable objectives pool. 14 new invalid fixtures (invalid/27–40) pinning schema-tier rules (missing required fields, gap-marker pattern,matchingModesub-shape selection andpairs/categoriescollision,itemsminItems,scoringModeenum, emptywordBank, question-level missingglobalId) and domain-tier rules (non-booleancorrectAnswer, comma in amultiGapClozeaccepted answer,ContentSequencerelatedItemIdsreferential integrity, duplicateglobalId).tests/manifest.jsonupdated;tools/run_corpus.pyreports 64/64.
[1.0-rc.2] — 2026-05-30
First formally announced public release candidate. Corrects the prompt-field definition from the (never-announced) internal 1.0-rc.1 candidate. Backwards-compatible widening: every 1.0-rc.1-valid document remains valid under 1.0-rc.2. Published at immutable /1.0-rc.2/ URLs; /1.0-rc.1/ stays served and frozen.
Changed
prompt:minLength1→0; defined as non-authoritative for the symbolic question types. Required on every question. Authoritative fortrueFalseQuestion,multipleChoice,shortAnswer, andessay. Non-authoritative for the symbolic types (gap-fill family,sentenceTransformation,matching,ordering,placement): MAY be empty or carry a producer-derived summary; consumers MUST NOT rely on its content for scoring, rendering, equality, or deduplication. Affected:question-base.schema.json,question-types-reference.md, eight symbolic examples; newexamples/01b-simple-gap-fill-readable-prompt.json. Object shape unchanged.
Added
- Real-content empty-prompt domain rule.
validate_course.pyflags empty/whitespacepromptontrueFalseQuestion,multipleChoice,shortAnswer, andessayas an ERROR. Symbolic types pass; reserved types unconstrained (deferred tov1.1). Fixtures:tests/valid/13-symbolic-empty-prompt.json,tests/invalid/26-real-content-empty-prompt.json. Corpus: 38/38. GOVERNANCE.md: masterdoc principle + Release Candidate Policy. Single-living-source model: published releases are immutable versioned artifacts; the git tag is the historical source for prior versions. RC policy: RC releases MAY introduce backwards-compatible corrections and clarify language; MUST NOT silently modify previously published artifacts; v1.0 final establishes the stable contract.
Documentation
- NORMATIVE §5 (Consumer Conformance): preamble + forward-compatibility worked example. Preamble at top of §5: schema validation is necessary but not sufficient; cross-references §5.3–§5.6, §6, §10.3. New informative subsection at end of §5 (“Forward compatibility: three look-alike situations”) covers three JSON-layer cases governed by different consumer obligations: unknown top-level field (§5.4), extension-namespaced field (§7), unknown
typediscriminator value (§5.1 Exception + §6 fallback). Cites §6.1’s “reserved and unknown types are handled identically.” - NORMATIVE §5 case 3: design-choice note on points handling for unsupported types. Earned
0; possible points stay in the item total; item maximum is consumer-independent. Open question logged in the rc.2 release notes’ “Areas still under discussion.” tests/README.md: Behavioral conformance (informative) section. Three-step round-trip self-test recipe (load → re-emit → diff) for the existing fixtures tagged inmanifest.jsonas demonstrating §6.4, §7, and §12.1 preservation obligations. No new fixtures or runner.- Scope clarification. Release notes intro,
src/index.md, andREADME-public.mdnow state that LC-JSON is a content-layer format complementary to LTI, OneRoster, xAPI, and SCORM, with a pointer toRATIONALE.md’s Scope and Limits. README.md: count + listing corrections. Example count31→32; removed the directory-tree reference to non-existentexamples/course-legacy-wrapped.json; addedplacement.schema.jsonto the Question Type Schemas list.tests/manifest.json: two stale § references.valid/01-course-minimal.json§4.4 camelCase property naming→§4.5.valid/06-html-with-video-track.json§10→§11(HTML Safety Profile). Sweep confirms no further stale NORMATIVE § refs in the manifest.- Accessibility severity alignment.
ACCESSIBILITY.md§8 listed video-without-<track>as “informational note”;VALIDATION.md§12.2 andvalidate_course.pyenforce it asWARN.ACCESSIBILITY.mdis now aligned toWARN. - “rc.1 baseline” wording → “current baseline (established in rc.1)”. Affected:
ACCESSIBILITY.md§8 heading, §11 heading, §11 inline;VALIDATION.md§12.2 + §14. The accessibility severity policy is unchanged; only the labeling is brought into the current package’s framing. - UUID prose: “RFC 4122 UUID” → “RFC 4122 UUID (any version; shape-only validation)”. Brings prose into line with the schema regex (which checks shape only, not version/variant bits). Affected:
GLOSSARY.md(globalId entry),README.md(Common Validation Errors),VALIDATION.md(six catalog rows across §4, §5, §6, §7, §8, §10),question-types-reference.md(intro requirement, Common Properties table, Validation Rules).NORMATIVE.md§4.4 already carried “(any version)” and is unchanged. Open question for v1.0 (whether to enforce strict v4/variant) logged in the rc.2 release notes’ “Areas still under discussion.” - Reserved/unknown-type preservation language: “verbatim” / “byte-equivalent” → semantic preservation.
NORMATIVE.md§6.2 and §6.4 now require preservation of every member, value, and nested structure across read/write cycles; key order within JSON objects is producer-discretion (SHOULD for authoring ergonomics, not MUST for consumers) per RFC 8259 §4. §5 forward-compatibility case 3 “preserved byte-equivalent” → “preserved with every member, value, and nested structure intact.” Tracked throughGLOSSARY.md,VALIDATION.md(two catalog rows),HTML_SAFETY.md§9,ACCESSIBILITY.md,question-types-reference.md(8 reserved-type Status lines), andtests/manifest.jsonvalid/05. - TrueFalseQuestion
correctAnswerimport normalization: explicitly labeled as pre-1.0 lenient migration affordance, not conforming behavior.question-types-reference.mdpreviously documented value-coercion ("true","correct","tick","✓",1→true; symmetric forfalse) without saying it was non-conforming. The schema requires a JSON boolean andNORMATIVE.md§5.1 binds consumers to reject schema-validation failures (strict mode). The section now states: conforming producers MUST emit a JSON boolean; conforming consumers in strict mode MUST reject non-boolean values; the coercion is a transitional ingestion aid for pre-1.0 documents that does not survive into a--strict-conforming re-export. - Release notes (“Areas still under discussion”) — three further open questions logged for 1.0 final: normative authority of the reference validator’s ERROR-tier domain rules; HTML processing-model split between strict-validation rejection and recovery-rendering sanitization; language-tag model (ISO 639-1 root vs. BCP 47 inline). None block rc.2.
Note
1.0-rc.1was never publicly announced;1.0-rc.2is the first announced prerelease. The/1.0-rc.1/schema set remains served and byte-frozen at its immutable URL.
[1.0-rc.1 doc revisions] — 2026-05-27
Doc-only follow-up revisions to the rc.1 publication. No schema or wire-format changes; the rc.1 contract at /1.0-rc.1/ is unchanged.
Added
- GOVERNANCE.md: canonical sources identified. New paragraph in the Trademark and naming section names
github.com/lc-json/specificationandlc-json.orgas the canonical sources for the LC-JSON specification, distinguishing them from forks and mirrors (which remain permitted under Apache 2.0 but should be named as derivative works rather than as “LC-JSON” without qualification). README-public.md trademark paragraph extended with a one-line pointer.
[1.0-rc.1 doc revisions] — 2026-05-26
Doc-only follow-up revisions to the rc.1 publication. No schema or wire-format changes; the rc.1 contract at /1.0-rc.1/ is unchanged.
Removed
allowedFillerWordsandprohibitExtraWordsBetweenChunks(sentenceTransformation) — prototype-era optionals, removed from the public spec surface. Both fields paired to permit specific words between chunks — a degree of leniency that practice never used. Every authored example emitted the empty default (allowedFillerWords: []) and the strict default (prohibitExtraWordsBetweenChunks: true); the off-stance for either was not a real authoring use case. The same intent — accepting a chunk with a permitted filler — is better expressed by adding the filler-bearing variant to the chunk’sacceptedChunks[N]array (rare edge case). The/1.0-rc.1/sentence-transformation.schema.jsonstill declares both properties because rc.1 schemas are immutable; the properties have been dropped from the reference docs (question-types-reference.mdJSON example and property table), fromVALIDATION.md§9.9, and from the shipped fixtures (examples/09-sentence-transformation.json,tests/invalid/25-sentence-transformation-multiple-markers.json). The/1.0/schema MUST omit both when finalized.
Fixed
- Editorial polish pass on rc.1 documentation. Count consistency across
question-types-reference.md(19 question types; reserved-types numbered 13–19),VALIDATION.mdrule-catalog completeness rows for optional schema fields, vendor-neutral phrasing inITEM_PATTERNS.md§3, US-English normalization gap closure,IMPLEMENTATIONS.mdstandard header block, internal-rationale generalization, elimination of redundant audience-targeted guidance in favor of single-source rules inOverview/Common Properties/Validation Rules, and markdown hygiene throughout. No normative changes; the wire format and JSON Schemas are unchanged.
1.0-rc.1 — 2026-05-25
Release-candidate hardening pass before 1.0 final. Closes contract-drift issues identified in the external evaluation while keeping the wire format additive (no breaking changes vs unreleased 1.0 baseline).
Added
placementquestion type — full schema, four examples, validator domain rules, conformance corpus. New top-level type with aplacements: [{gap, item}]explicit-relationship shape (mirrors the matching-redesign principle). Three modes viaplacementUnit:sentence(inline gaps),paragraph(block-level gaps), andsectionLabel(label slots above sections — covers IELTS Matching Headings and analytical meta-labels). Decoy gaps (extra@@@Nmarkers withoutplacements[]entries) natively express TOEFL Sentence Insertion. Word-level placement is covered bywordBankCloze. Four canonical examples: 17a (Cambridge B2 sentence-mode missing-sentences), 17b (Cambridge C1 paragraph-mode reorder), 17c (IELTS Matching Headings + analytical meta-labels), 17d (TOEFL Sentence Insertion with 4 candidate positions). Validator: hard-error rules onplacements[].gapreferences and duplicates; soft-warning rules on marker-placement convention violations perplacementUnitand on non-sequential@@@Nnumbering. Conformance corpus extended with 4 valid + 6 invalid placement fixtures. Reference-runtime scoring:pointsEarned = pointsPossible × correctCount / gapCountunder partial credit; strict zero-or-full otherwise. Decoy-gap rule: an item placed at an unlisted gap marks the question incorrect but does not subtract from credit earned on correctly-filled gaps when partial credit is allowed; under all-or-nothing it fails the strict check. Discriminator enum extended.- Ordering: Kendall tau partial-credit scoring. The reference runtime implements Kendall tau over the learner’s permutation; with N items and k inversions,
pointsEarned = pointsPossible × (1 − k / (N × (N−1) / 2)). Distractors placed in the answer area drop the question to incorrect at the strict-mode level but partial credit is still awarded over the in-bounds correct indices. A new helper resolves the conditional default at scoring time. - Matching question —
matchingModediscriminator with two sub-shapes. Replaces the legacystems[]/targets[]parallel-array shape entirely.matchingMode: "pairs"selectspairs: [{ item, match }]for 1:1 matching;matchingMode: "classification"selectscategories: [{ label, items }]for many-to-one classification. The discriminator is required (no default). Mixed shapes (bothpairsandcategoriespresent, ormatchingModeomitted) are rejected by the schema. Eachpairs[i].{item,match}andcategories[i].{label,items}is required andminLength: 1;categories[i].itemshasminItems: 1. New canonical example15b-matching-classification.json(time expressions → tense). A one-off migration script rewrites legacy on-disk content; the new shape replaces the legacy one entirely with no back-compat path. - NORMATIVE §6 — Reserved and Unknown Types. Full fallback contract: consumers MUST preserve reserved/unknown question types verbatim across read/write cycles, MUST NOT silently drop, MUST treat earned points as 0, SHOULD render a non-interactive placeholder. Producers MUST satisfy
question-base.schema.jsonif emitting reserved types and SHOULD NOT emit them in cross-implementation distribution. Closes the round-trip preservation gap that broke portability for tool-specific extensions. - NORMATIVE §7 — Extensions (namespaced
x-members). Defines a forward-compatible, collision-free mechanism for tools to attach data outside the interchange contract (authoring provenance, internal identifiers, editor state). Extension members are keyedx-<namespace>(e.g.x-acme-reviewState), MAY appear on the document root and any Course/Unit/Lesson/Item/Question object, and are strictly additive — removing allx-members MUST leave a conforming document with equivalent learner-facing meaning. Consumers MUST NOT reject documents for carrying them, MUST NOT interpret members outside namespaces they own, and SHOULD preserve unrecognized members across a round trip (defining an extension-preserving consumer). This is the contract that lets a tool use LC-JSON as a faithful transfer/backup format for its own tool-specific state.IMPLEMENTATIONS.mdregisters thex-lessoncommonsnamespace (question lineage / authoring provenance). Sections §7–§11 (was §6–§10 after Reserved Types) renumbered to §8–§12. - NORMATIVE §11 + new sibling
HTML_SAFETY.md— HTML safety profile. Normative allowlist forContentItem.htmlandSignpostItem.customHtml: allowed elements (block, inline, media including<video>,<audio>,<source>,<track>,<h1>–<h6>,<div>,<blockquote>,<figure>); per-element attribute table; URL-scheme allowlist (http:,https:,mailto:,tel:, relative —javascript:/vbscript:/data:etc. forbidden); link normalization (target="_blank"→rel="noopener noreferrer"); inlinestyleCSS-property allowlist (sizing, spacing, borders, alignment); class attribute permitted unconstrained (author-defined CSS hooks); sanitization obligation; unknown-element strip-while-preserving-text per §6.2 (mirrors §6 reserved-types philosophy — degrade gracefully, never fail-closed); validator severity split (ERROR for XSS-class violations like<script>andon*, WARN for sanitizable cases). Closes the largest public-spec gap from the 2026-05-02 external evaluation. unitLevelhint onorderingquestions —"word"(default),"sentence","paragraph". Enables sentence-in-text and paragraph-in-text ordering tasks under the same discriminator. Existingorderingexamples continue to validate (default ="word").- Two ordering examples:
16b-sentence-ordering.json(cellular respiration stages withscoringMode: "kendall") and16c-paragraph-ordering.json(Enlightenment essay withscoringMode: "strict"). - Authored-text line-break rendering convention —
\n\n→ paragraph,\n→ line break.ITEM_PATTERNS.md§3 gains a non-normative subsection documenting the affordance for plain-text authored fields (description,prompt,passage,hint,feedback.correct,feedback.incorrect, etc.). Producers using this convention get portable rendering across consumers that align with the affordance; consumers may legitimately collapse all whitespace and treat the field as a single block. Lesson Commons Learn implements this convention as the reference behavior. Wire format unchanged — JSON strings continue to escape newlines per RFC 8259; no schema change. Trusted-HTML fields (ContentItem.html,SignpostItem.customHtml) keep their existing sanitizer pipeline and stay outside this convention. - NORMATIVE §5.6 — Randomization requirements for
matchingandplacement. Consumers MUST present two surfaces in randomized order: (1) the choice pool (authored answer values + distractors) for both matching and placement, and (2) the row order in matching classification mode (where source order is grouped by category and would directly expose the answer). Source order is forbidden on these surfaces. The randomization algorithm and any seeding strategy are consumer-defined. The requirement does not apply tomultipleChoice(whereshuffleOptionsper question still governs), to matching pairs-mode rows (each item has a distinct match, so source order doesn’t leak), or toorderingsource tiles (already shuffled structurally). Schema descriptions onmatching.distractors,matching.categories, andplacement.distractorscross-reference §5.6. tagsarrays on Unit, Lesson, and Item. Five-tier tagging now uniform across Course, Unit, Lesson, Item, and Question.ITEM_PATTERNS.md— informative authoring guide covering policy fields, common patterns, signposts + learning objectives, consumer-policy variance. §3 gains atel:consumer-policy example showing how the same wire-level construct (atel:link) is gated differently across consumer audiences.- Conformance test corpus expansion:
valid/05-reserved-type-with-extensions.json(round-trip preservation case for §6.4),valid/06-html-with-video-track.json(HTML safety §7 media handling),invalid/12-unit-missing-global-id.json(§4.4 enforcement),invalid/13-html-with-script.json(HTML safety §2.4 + §3.5 — forbidden<script>element andonclickevent handler). - Validator
[NOTE]tier — informational lines for intentional weighted-points overrides, distinct from warnings. validate_course.py --strictmode — public-conformance mode that rejects pre-1.0 document shapes (wrapped envelope{"course":{...}}, bare payload{"units":[...]}with nodocumentType) as fatal errors. Default mode remains lenient for legacy/pre-1.0 document ingestion during migration.NORMATIVE.md§10 conformance claims are evaluated in--strictmode.tools/run_corpus.py— conformance corpus harness. Readstests/manifest.jsonand asserts every valid fixture passes and every invalid fixture fails (the harness invokesvalidate_course.py --stricton every fixture internally). Wired into.github/workflows/publish.ymlas a required job — a corpus regression blocks deployment. Closes the gap betweenCONTRIBUTING.md’s “CI runs the corpus” promise and the previous behavior (3 invalid fixtures silently passing).ACCESSIBILITY.md(rc.1 release) — producer/consumer accessibility profile covering image alt text, video/audio (captions/transcripts/descriptions), keyboard alternatives for structured-task question types, feedback not conveyed by color alone, language and direction, and reserved-type placeholder accessibility. The rc.1 release (2026-05-23) carries per-section WCAG 2.1 AA SC cross-references, recommended ARIA patterns for the structured-task question types, the two-layer format/consumer duty framing, EN 301 549 + DOJ ADA Title II legal context, the ATAG vs WCAG split for producers vs consumers, the five claim-level gates for an AA claim, and selected WCAG 2.2 criteria designed-in (2.5.7 Dragging Movements, 2.5.8 Target Size). RTL producer wording precisely distinguishes RTL-primary documents from LTR documents with embedded RTL passages. Caption requirements split: SHOULD for generic video, MUST for prerecorded instructional video with speech when claiming Accessibility Profile conformance (WCAG 1.2.2). Additive deepenings (per-criterion normative cross-reference table, expanded ARIA patterns, screen-reader timing requirements, expanded accessibility conformance fixtures,--accessibilityvalidator flag) land in1.0final on 2026-06-30 — every deferral is an explicit §-level callout. Closes theHTML_SAFETY.mddangling-reference issue flagged by the v2 audit.- NORMATIVE.md §12 — Accessibility Profile binding (hybrid: preservation in base conformance + opt-in claim for delivery). Splits the accessibility obligation into two layers per the 2026-05-23 accessibility audit Finding 1 and the consultant’s “must survive transformation” framing. §12.1 codifies the base-conformance accessibility-preservation floor (every conforming consumer MUST round-trip
alt,<track>,lang,dir,language,supportLanguage, reserved-type accessibility metadata, andx--namespaced accessibility extensions). §12.2 defines the opt-in LC-JSON 1.0 Accessibility Profile claim binding all MUST-level items inACCESSIBILITY.md§§2–8 (keyboard, ARIA, feedback, language-aware rendering, placeholder accessibility). §12.3 codifies the relationship to WCAG: LC-JSON enables WCAG 2.1 AA delivery via the affordances and consumer obligations; the WCAG claim itself remains the delivering consumer’s responsibility, not LC-JSON’s. Closes accessibility-audit Finding 1. - NORMATIVE.md §10 — Conformance Claims expanded with marketing wording. §10.1 lists base-conformance claim forms; §10.2 lists Accessibility Profile claim forms; §10.3 codifies three claim-accuracy rules (producer≠consumer; Accessibility Profile is fully bound; LC-JSON does not certify WCAG); §10.4 provides suggested badge/sentence/formal-claim wording for both tiers (Tier 1 badge: “LC-JSON 1.0 Compatible”; Tier 2 badge: “LC-JSON 1.0 Accessibility Profile”); §10.5 reaffirms the trademark stance. The marketing wording is informative and freely usable.
languageis now a required root field oncourse.schema.jsonandquestion-set.schema.json(per accessibility-audit Finding 2 — the spec saidlanguagewas schema-enforced but the schemas didn’t require it). All 31 existing root-level course/questionSet examples and conformance fixtures already carriedlanguage; no migration burden. New invalid fixturetests/invalid/20-missing-language.jsonpins the constraint.- Two new accessibility conformance fixtures.
tests/valid/12-accessibility-round-trip.jsondemonstrates §12.1 base-conformance accessibility preservation:alton<img>,<track>on<video>,lang/diron inline spans, document-rootlanguage/supportLanguage, andx--namespaced accessibility metadata on a reserved-type question MUST all round-trip. Paired with thetests/invalid/20-missing-language.jsoninvalid fixture from the previous entry, the two additions bring the conformance corpus toward its rc.1 total of 12 valid + 24 invalid = 36 fixtures;run_corpus.pyreports 36/36 behave as expected. VALIDATION.md— schema-vs-domain-vs-advisory rule catalog. New sibling document referenced fromNORMATIVE.md§13 (“Validation surface”) and listed inREADME.md’s directory tree. Catalogs every documented validation rule across the 23 JSON Schemas,tools/validate_course.py(domain pass, ERROR/WARN/NOTE severities), and prose inNORMATIVE.md/HTML_SAFETY.md/ACCESSIBILITY.md/question-types-reference.md/ITEM_PATTERNS.md. Each rule is tagged with its enforcement tier and a precise citation (schemas/<file>.schema.json: <json-pointer>orvalidate_course.py: <function-name>+ NORMATIVE §). Organized by document scope (root → course → unit → lesson → item-base → per item type → question-base → per question type → reserved types → question sets → cross-cutting). Cross-cutting section covers HTML safety severity table, accessibility preservation + validator severities, randomization (§5.6), extensions (x-namespacing), versioning / URL stability, and discriminator casing. Closes the external evaluation’s “validation appendix” gap (2026-05-02 §3) — consumers that only run JSON Schema validation can now see at a glance which rules they would otherwise miss. The inventory pass surfaced eight documented-but-unenforced rules; all eight were closed in the same rc.1-polish session by extendingtools/validate_course.py(see next entry). The catalog reflects the rc.1 enforced state, not a gaps list. §14 “Forward-looking deepenings” tracks what’s scheduled for1.0final (the--accessibilityvalidator flag, tag namespace conventions, and reserved-type per-type schemas).- Validator gap closures — 8 documented rules promoted from prose to enforced. Extends
tools/validate_course.pywith no schema changes — all rules were already documented inNORMATIVE.md/question-types-reference.md/README.md/ACCESSIBILITY.mdbut enforced nowhere. New domain-validator functions:validate_multiple_choice(KG-3: MCQ MUST have ≥1 positiveoptionsAndPointsvalue; KG-4:optionsAndPointsMUST cover every entry inoptions, with WARN for orphan entries);validate_word_bank_clozeandvalidate_multiple_choice_cloze(KG-1:passage@@@Nmarker set MUST equal the answer/option dictionary key set; KG-2: marker numbers SHOULD be sequential from 1; KG-5:correctAnswers[N]MUST be in bounds ofgapOptions[N]; new ERROR forgapOptions/correctAnswerskey-set mismatch);validate_essay(maxWords >= minWordswhen both > 0, WARN). Extendedvalidate_multi_gap_clozewith the same KG-1/KG-2 checks via the new shared_check_cloze_gap_consistencyhelper. New_collect_objective_id_violationswalker (KG-6: WARN ifcourseObjectiveIds[*]/unit.objectiveIds[*]/lesson.objectiveIds[*]reference an id not declared incourse.objectives[]— closes the referential-integrity gap on objective references).validate_html_contentgains a post-pass that scans for<video>blocks without a<track kind="captions"\|"subtitles">child element (KG-8 — WARN at rc.1; ERROR-tier promotion under the--accessibilityflag is targeted for 1.0 final). Internal: renamed_placement_marker_numbers→_gap_marker_numberssince the helper is now shared across all cloze types. Four new invalid conformance fixtures pin the ERROR-tier checks (tests/invalid/21-mcq-no-correct-option.json,22-mcq-options-points-missing-entry.json,23-word-bank-cloze-gap-count-mismatch.json,24-multiple-choice-cloze-index-out-of-bounds.json);tests/manifest.jsonupdated;python tools/run_corpus.pyreports 36/36 fixtures behave as expected (the harness invokesvalidate_course.py --stricton every fixture internally). KG-7 was a false alarm during inventory (validator and schema agree onrelatedItemIds) and is dropped from the catalog. No new normative rules; no schema changes. - Language Policy (editorial). Specification text is written in US English as a single editorial register; example content should vary across English regional varieties (British, American, Australian, Indian, Irish, Canadian, South African, and others); non-English content in examples is reserved for demonstrating language-specific or multilingual capabilities (RTL rendering, non-Latin scripts, bilingual
[L1:]tag rendering,language/dirbehavior). The wire format is language-neutral — the policy governs only the editorial language of the specification and its examples.
Changed
- Ordering: renamed
unitLevel→orderingUnitfor teacher readability. Pre-publication rename, non-breaking. Schema, examples (16b,16c), reference docs, andITEM_PATTERNS.mdall updated. Placement’s parallelplacementUnitfield-name reads naturally alongside. - Ordering:
scoringModedefault is now conditional onorderingUnit. Schema description prose now states: whenscoringModeis omitted, consumers SHOULD default to"strict"fororderingUnit: "word"and"kendall"for"sentence"/"paragraph". The literal"default": "strict"keyword is removed from the schema property since JSON Schema draft-07 can’t cleanly express conditional defaults; the conditional guidance lives in the description, where consumers actually read it. Existing examples are unaffected:16-ordering.json(word) carries noscoringModeand inheritsstrict;16band16csetkendallexplicitly. globalIdis now required on every Unit, Lesson, Item, and Question schema (was nullable + not-required on Unit/Lesson/Item, despite being normatively MUST under §4.4). Pattern unchanged (RFC 4122 any version).$schemais now required at the document root (producer MUST emit; consumer SHOULD tolerate omission for re-import flexibility). Updatedcourse.schema.jsonandquestion-set.schema.jsonrequired[].scoringModeandorderingUnit(formerlyunitLevel) remain optional onordering.schema.json—orderingUnitdefaults to"word";scoringMode’s default is the conditional rule above (description prose, no literal default keyword).exercise/quizdecoupled from grading policy.quiz-item.schema.jsonno longer has"isGraded": {"const": true}. All four combinations of{exercise, quiz} × {graded, ungraded}are valid; new NORMATIVE §4.3 codifies this.- Brand consistency: schema descriptions now say “LC-JSON spec version” (was “LC.JSON”).
question-types-reference.md: matching reference entry rewritten as a real type (was labeled stub);pointsconstraint corrected to≥ 0allowingnull; reserved-type entries (11 total) reframed under §6 fallback contract;Phase 4: Advanced Typesheading split intoStructured & Reserved Types; casing references corrected to NORMATIVE §5.3.README.md(specification): Reserved Types section now describes consumer obligations under §6 explicitly; example count updated to 30 across the file (placement adds 17a–17d to the example set).ACCESSIBILITY.md: keyboard interaction obligations split per matching mode (pairsvsclassification) and extended with aplacementrow;unitLevelreference updated toorderingUnit.- NORMATIVE §5.1 carve-out for §6 fallback. Resolved an internal contradiction between §5.1 (“consumer MUST reject documents that fail schema validation”), §5.2 (“consumer MUST accept any 1.x
specVersion”), and §6 (“consumer MUST preserve unknown-type questions verbatim and apply fallback, do not reject”). Applied literally, the three together made the forward-compat case impossible: a 1.0-only consumer reading a 1.1 document with a future-minor question type was bound to both reject (§5.1) and preserve (§6). §5.1 now carries an explicit exception: schema-validation failures whose only cause is one or moretypediscriminator values not in the consumer’s implementedquestion-base.schema.jsonenum do not trigger rejection; the consumer applies §6 fallback to those questions and validates the rest of the document under §5.1. All other schema failures (missing required fields, type mismatches, pattern violations on known fields,additionalPropertiesviolations) still trigger rejection. Doc-only NORMATIVE change; no schema change, no validator change —tools/run_corpus.pycontinues to report 36/36 fixtures behave as expected. Closes the consultant’s 2026-05-24 third-pass note on VALIDATION.md. - URL policy clarified — release candidates get their own immutable URL paths (NORMATIVE §3.1, §4.7, §8.1, §8.3). Each release candidate of an upcoming version
X.Yis published at/X.Y-rc.N/, immutable once published. The/X.Y/URL path is reserved for the accepted finalX.Yrelease and MUST NOT be populated until that release is published. A document pinned via$schemato/1.0-rc.1/continues to validate against rc.1 forever; adoption of/1.0/final is an explicit re-export, not an automatic promotion. Producers MUST emit a$schemaURL matching the spec version they conform to (/1.0-rc.1/for an rc.1 producer,/1.0/for a 1.0-final producer). This closes the audit’s “Release Candidate URL Immutability Wording” concern and preserves the §8.3 immutability guarantee across the rc.1 → 1.0 transition.
Deprecated
- None.
Removed
course-walkthrough.json(was excluded from publication via build-time SKIP; deleted to remove residual maintenance noise).
Fixed
TrueFalseQuestionexports no longer leakchoiceFeedback: {}(TF v2 architecture forbids the field; previousnew()default emitted empty dict on every TF question).- Course/QuestionSet
Versionis now mandatory + numeric on producer side (^[0-9]+(\.[0-9]+){0,2}$); previously could ship as blank or free-form, breaking sortability across consumers. - Python authoring tools emit canonical camelCase question discriminators; prior PascalCase emissions are gone.
- Cross-references in
README-public.md,IMPLEMENTATIONS.md, and the test corpus updated for the §5.5 collapse + §6→§7 / §8→§9 renumber driven by the new §6 insertion. - Reference Runtime (consumer-side): bilingual tag rendering on question
promptis now applied uniformly across all 12 question types. PreviouslyShortAnswer,Essay,SentenceTransformation,WordBankCloze, andMultiGapClozeskipped the bilingual transform onprompt; all 12 types skipped it onhint. Adopting a unified line-break renderer (which composes the bilingual transform) closes the gap. No spec or schema change; behavior change in the reference runtime only. HTML_SAFETY.md§8.1 / §2.4 alignment. The §8.1 “validator MUST reject” enumeration of forbidden elements had drifted from the §2.4 source list — six elements were missing (<select>,<textarea>,<applet>,<frame>,<frameset>,<noframes>). §8.1 now references §2.4 directly (“Any forbidden element listed in §2.4.”) so the two lists cannot drift in future revisions.HTML_SAFETY.md§3.5 cleanup. Removed a misleadingdata:cross-listing in the forbidden-attributes section. The rule lives in §4.2’s URL-scheme allowlist; the §3.5 line carried an empty “except as permitted in §4.1” carve-out that didn’t reflect any actual permission (§4.1 permits nodata:URLs). §3.5 now cross-references §4.2 instead of duplicating the rule.ACCESSIBILITY.md§8 validator-severity table — root field name. The “Missinglangat document root” row swapped the LC-JSON root field (language, ISO 639-1, schema-enforced) for the HTML attribute (lang). Schemas enforcelanguage;langis the HTML attribute used inline for WCAG 3.1.2 Language of Parts. Table now reads “Missinglanguageat document root.”
Notes
- All 31 spec examples + 12 valid + 24 invalid conformance fixtures validate clean against the tightened schemas (run
python LC.JSON/tools/run_corpus.py— expects “36/36 fixtures behaved as expected”). - Wire format is forward-compatible with
1.0baseline: every change either softens a constraint, adds an optional field, or codifies behavior consumers were already expected to provide.
[1.0-internal] — 2026-04-29
Internal milestone — not publicly released. Captured here as the wire-format baseline that the 1.0-rc.x release-candidate line builds on. 1.0-rc.2 (2026-05-30) was the first publicly announced candidate; public consumers should target it or later (the earlier 1.0-rc.1 is served for transparency but was never announced). The 1.0-rc.1 schemas are published at lc-json.org/1.0-rc.1/; the /1.0/ URL space is reserved for the accepted final 1.0 release (target 2026-06-30) and does not resolve until then.
Added
- Two artifact types under a common flat root:
course(hierarchical) andquestionSet(flat). - 11 user-facing question types:
simpleGapFill,trueFalseQuestion,multipleChoice,wordBankCloze,multiGapCloze,multipleChoiceCloze,shortAnswer,essay,sentenceTransformation,matching,ordering. All schema-validated. - 7 reserved question types declared in the discriminator enum for forward compatibility, with full implementation targeted for 2027:
association,hotspot,graphicGapMatch,graphicAssociate,graphicOrder,fileUpload,mediaPromptedEssay. - 22 JSON Schemas (Draft 7) covering every artifact, item type, and question type.
- 25 example documents covering every artifact and per-type fragments.
- Conformance test corpus under
tests/(4 valid + 10 invalid cases) with a machine-readablemanifest.jsonmapping each file to the clause it tests. NORMATIVE.md— RFC 2119 conformance requirements, producer/consumer roles, versioning policy, deprecation rules, conformance-claim language.- Reference Python tools:
validate_course.py(validator). The fixture-scaffolding helper used during internal development was reclassified as internal authoring infrastructure for 1.0-rc.1 publication and is not shipped to the public repo. - Schema URL stability guarantee codified in
NORMATIVE.md§8.3 (each published version path is immutable for the lifetime of the spec). Public publication oflc-json.org/1.0/*.schema.jsonis deferred to the accepted 1.0 final release;1.0-rc.1publishes atlc-json.org/1.0-rc.1/*.schema.json. - Apache License 2.0 throughout.
Notes
- LC-JSON 1.0 distils approximately 12 months of internal format iteration. Earlier internal versions were never publicly released and are not part of this version history.