feat(validate): language tags and set metadata are engine rules (#190) - #223
Merged
Merged
Conversation
The language-pair and set-metadata checks move from the content template's validator into the engine, in the version decided on 2026-09-25: - E-LANG-TAG: a target/source language (set or lesson) is not a well-formed BCP 47 tag; W-LANG-TAG-CANONICAL: well-formed but not canonical, naming the canonical form. Checked with Intl.getCanonicalLocales; gsw, yue, fil are valid (the template's two-letter rule rejected them). - W-LANG-PAIR-SAME and W-SET-TITLE-NATIVE for language sets (errors in the template, warnings here: both can be intended). - W-CARD-BACK-SCRIPT: card backs with letters but none in the CLDR likely script of a non-Latin source language, one warning per lesson, for every language instead of a table of six. validateLesson / validateLessonRules take the set's source language as options.sourceLanguage; a lesson's own source_language wins. Measured with this build over the 53 sets and 631 lessons of the ten content repositories: 0 findings; seeded faults in real content are found. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #190. The language-pair and set-metadata rules move into the engine, in the version from the decision brief in the issue (owner, 2026-09-25: "deine Empfehlungen hören sich gut an").
E-LANG-TAG: not a well-formed BCP 47 tagtarget_language/source_languageW-LANG-TAG-CANONICAL: well-formed, not canonical (deu,EN,iw), naming the canonical formW-LANG-PAIR-SAME: source and target are one language, in alanguagesetW-SET-TITLE-NATIVE: alanguageset withouttitle_nativeW-CARD-BACK-SCRIPT: card backs with letters but none in the script of a non-Latin source language, one warning per lessonIntl.getCanonicalLocales. Three-letter subtags without a two-letter code (gsw,yue,fil) are valid.Intl.Locale(...).maximize().script), with a small mapping for the composite scriptsJpan,Kore,Hans/Hant. That covers every language, includinghi,he,kaandth, which the template's table skipped.validateLessonandvalidateLessonRulestakeoptions.sourceLanguage(the set's). A lesson's ownsource_languagewins over it.src/language-rules.ts) has no ajv and nonode:*, so it is on the/rulesentry.Measured
This build ran over the 53 sets and 631 lessons of the ten content repositories. Every lesson was matched to its set, and each set's source language was passed in.
W-CARD-BACK-SCRIPTonbonjour;deuin the hub manifest, asW-LANG-TAG-CANONICAL;en_US, asE-LANG-TAG;title_native, asW-SET-TITLE-NATIVE.title_nativechecks were errors in the template and are warnings here. A repo that needs them blocking gets that from adaptive-learner-content-template#83.Test plan
src/language-rules.test.ts: 43 tests, written RED first (21 failed before). The cases:gswis valid,en_USis an error, a Hindi source is checked;languagealias and a lesson's own tags;de-AT/de, theendefault, non-language sets, and silence behind a malformed tag;title_nativeabsent, empty or null, and non-language sets;el,ru,ja(kana and kanji),ko,zh,zh-TW,hi,he,ka;validateLessonRulestaking the option.make release-check,make prose-checkandnpm run docs:api:checkpass./rulesentry is 27.3 kB (+2.4 kB), re-measured and documented.Docs
lesson-format.md: a new "Language tags" section, catalog rows and params rows.validation.md: a Layer 2 row, the lint list with thesourceLanguageoption, and the/rulessize.architecture.md: engine side done, the dropped severities, the open item and the/rulessize.CHANGELOG.md.Downstream (for the release PR)
validate_set_metaandback_looks_like_source, and passes each set'ssource_languagetovalidateLessoninvalidate_with_engine.mjs. This is mirrored into the ten repos.^[a-z]{2,3}(-[A-Za-z0-9]{2,8})?$rejectszh-Hant-TW).🤖 Generated with Claude Code