Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/ownership.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"tests/test_export_quiz_pdf.py": "template",
"tests/test_from_cards_pairs_gate.py": "template",
"tests/test_generate_exercises.py": "template",
"tests/test_hint_length_rule.py": "template",
"tests/test_mc_only_exemption.py": "template",
"tests/test_quality_state.py": "template",
"tests/test_shape_parity.py": "template",
Expand Down Expand Up @@ -96,8 +95,6 @@
"tests/test_export_set.py": "repo",
"tests/test_hub_generated_sets.py": "repo",
"tests/test_ki_einsteiger_ai_validated.py": "repo",
"tests/test_known_domain.py": "repo",
"tests/test_prompt_duplication_rule.py": "repo",
"tests/test_readme_set_table.py": "repo",
"schema/content-manifest.schema.json": "engine",
"schema/lesson.schema.json": "engine",
Expand Down
2 changes: 1 addition & 1 deletion schema/engine-version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.28.0
0.29.0
55 changes: 4 additions & 51 deletions scripts/validate_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,45 +56,10 @@

ISO_639_1 = re.compile(r"^[a-z]{2}$")

# Answer-length statements in exercise/blank hints (adaptive-learner-content#100).
# The app shows the answer's length automatically (the system hint), so an
# authored hint stating a letter/character count ("Vier Buchstaben.") is
# redundant at best and contradicts the system hint when it is wrong. Card
# hints are NOT covered: a character count there can be legitimate teaching
# content (e.g. explaining that ``s[0:3]`` yields 3 characters). Compounds
# like "Leerzeichen" do not match (no word boundary inside the compound),
# so indentation advice passes.
#
# The count words also cover the English number words (one to twelve;
# hyphenated adjectives like "five-letter" match via the ``[-\s]+`` joiner)
# and the single-character adjectives ("ein einzelnes Zeichen", "a single
# character" state answer length 1), adaptive-learner-content#102. Compounds
# still pass: "Ein einzelner Kleinbuchstabe" conveys CASE, which the system
# hint does not show, and "the letter she wrote" has no count word before the
# noun.
_HINT_COUNT_WORDS = (
r"\d+|ein(?:e[nmrs]?)?|zwei|drei|vier|f(?:ü|ue)nf|sechs|sieben|acht|neun"
r"|zehn|elf|zw(?:ö|oe)lf"
r"|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve"
r"|einzeln\w*|single"
)
HINT_LENGTH_PATTERN = re.compile(
rf"\b(?:{_HINT_COUNT_WORDS})[-\s]+(?:buchstaben?|zeichen|letters?|characters?)\b"
r"|\w*buchstabig",
re.IGNORECASE,
)


def hint_states_answer_length(hint: object) -> bool:
"""True when an authored hint states the answer's letter/character count.

Matches a digit, a German or English number word, or a single-character
adjective ("einzeln..."/"single") followed by "Buchstabe(n)"/"Zeichen"/
"letter(s)"/"character(s)" (plus the "-buchstabig" adjectives). Applied to
exercise-level and blank-level hints only - see the note on
``HINT_LENGTH_PATTERN``.
"""
return isinstance(hint, str) and bool(HINT_LENGTH_PATTERN.search(hint))
# Answer-length statements in hints are the engine's rule: W-HINT-LENGTH
# (learn-content-engine#186, since 0.29.0) checks exercise and blank hints with
# the forms this validator used to check, and reports them in the engine gate's
# warning step. Content rules belong to the engine, not to a second copy here.

# Scripts we can distinguish from Latin (mirror the TS validator).
SCRIPT_RANGES = {
Expand Down Expand Up @@ -285,18 +250,6 @@ def validate_lesson_quality(lesson: dict, source: str, label: str, errors: list[

for ex in exercises:
eid = ex.get("id", "?")
if hint_states_answer_length(ex.get("hint")):
errors.append(
f"{label}: exercise '{eid}' hint states a letter/character count "
"(redundant to the app's automatic length hint) - use a content hint"
)
for blank_index, blank in enumerate(ex.get("blanks") or []):
if isinstance(blank, dict) and hint_states_answer_length(blank.get("hint")):
errors.append(
f"{label}: exercise '{eid}' blanks[{blank_index}] hint states a "
"letter/character count (redundant to the app's automatic "
"length hint) - use a content hint"
)
if ex.get("type") == "free_text":
if len(ex.get("accept") or []) < MIN_FREE_TEXT_ACCEPTS:
errors.append(f"{label}: free_text '{eid}' needs >= {MIN_FREE_TEXT_ACCEPTS} accepts")
Expand Down
235 changes: 0 additions & 235 deletions tests/test_hint_length_rule.py

This file was deleted.

Loading