diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 289069dbbd..eb2ce9d6d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -146,6 +146,17 @@ repos: types: [yaml] pass_filenames: true + - id: check_yaml_content_new_activities_unique_uuid + name: Check new_activity.yml files for unique uuid + description: | + This hook checks new_activity.yml files for unique uuid + entry: python3 Tools/Hooks/check_yaml_content_new_activities_unique_uuid.py + language: python + files: .*\.new_activity\.yml + types: [yaml] + pass_filenames: false + always_run: true + # - id: check_yaml_content_activities # name: Check activity.yml files # description: | @@ -201,6 +212,19 @@ repos: types: [yaml] pass_filenames: false + - id: check_yaml_content_curations + name: Check curation.yml files + description: | + This hook checks curation.yml files for: + - uuid and filename consistency + - jtd schema validation + - curation item reference integrity + entry: python3 Tools/Hooks/check_yaml_content_curations.py + language: python + additional_dependencies: ["ruamel.yaml"] + files: .*\.curation\.yml + types: [yaml] + - id: check_yaml_content_stories name: Check story.yml files description: | @@ -223,6 +247,18 @@ repos: types: [yaml] pass_filenames: false + - id: check_yaml_content_cross_type_unique_uuid + name: Check content files for cross-type UUID collisions + description: | + This hook checks all content types (activities, curriculums, stories, curations) + for UUID collisions across different content types + entry: python3 Tools/Hooks/check_yaml_content_cross_type_unique_uuid.py + language: python + files: .*\.(new_activity|curriculum|story|curation)\.yml + types: [yaml] + pass_filenames: false + always_run: true + - id: check_binary_not_executable name: Check binary files are not executable description: | diff --git a/AGENTS.md b/AGENTS.md index b07acab405..af54fd7717 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -154,3 +154,10 @@ bundle exec fastlane release target:LekaApp - Minimum iOS version is 17.4. - Destinations include iPad and Mac (Catalyst via iPad design). + +## Content System + +The educational content system is documented in detail in the hierarchical AGENTS.md file: +- `Modules/ContentKit/Resources/Content/AGENTS.md` - Full content schema reference (activities, curriculums, stories, curations, definitions) + +This file is auto-loaded by oh-my-opencode when working on content files. It is also referenced in `opencode.json` instructions for global access. diff --git a/Modules/ContentKit/QA/README.md b/Modules/ContentKit/QA/README.md new file mode 100644 index 0000000000..3c17df3645 --- /dev/null +++ b/Modules/ContentKit/QA/README.md @@ -0,0 +1,72 @@ +# Leka - iOS Monorepo +# Copyright APF France handicap +# SPDX-License-Identifier: Apache-2.0 + +## What the QA Audit Checks + +The content QA audit validates three areas: + +1. **Structural validation** — YAML schema compliance, UUID uniqueness, locale completeness (crash risk if missing), asset references +2. **Text quality review** — Bilingual text (fr_FR + en_US) for typos, encoding errors, placeholder text, untranslated content, truncated strings, empty fields +3. **Cross-reference integrity** — Curation items pointing to non-existent curricula/activities/stories; orphaned content not reachable via any curation + +## How to Run Automated Checks + +Run a single hook: + +```bash +pre-commit run check_yaml_content_new_activities --all-files +``` + +Run all content hooks: + +```bash +pre-commit run --all-files +``` + +**Note:** Activity hooks can be slow on large content directories. For rapid iteration, run only the hook targeting your file type. + +## What Needs Manual Review + +Automated checks do not cover text quality. Reviewers should flag these 7 issue types: + +1. **Typos** — Spelling errors in titles, descriptions, instructions +2. **Encoding errors** — Mojibake, invalid UTF-8, corrupted characters +3. **Placeholder text** — Lorem ipsum, "TODO", "FIXME", "XXX", "temp" +4. **Empty fields** — Missing required l10n details (title, subtitle, description) +5. **Untranslated content** — Text in one locale only (e.g., French title with English description) +6. **Truncated strings** — Text cut off mid-word or mid-sentence +7. **Broken formatting** — Misaligned line breaks, unescaped special characters, malformed markdown + +**Do NOT flag:** +- Disability-domain terminology (e.g., "handicap", "special needs") — intentional and appropriate +- Style differences between authors — acceptable variation + +## Severity Definitions + +| Severity | Definition | Examples | +|----------|-----------|----------| +| critical | Crash or content loss risk | Missing locale, invalid UUID, schema violation, broken curation reference | +| warning | Inconsistency or broken reference | Typo, encoding error, orphaned activity, mismatched asset | +| info | Style or formatting issue | Inconsistent capitalization, extra whitespace, minor formatting | + +## Hook Inventory + +| Hook ID | Targets | What It Checks | +|---------|---------|----------------| +| check_yaml_definitions_avatars | avatars.yml | Non-unique IDs, schema validation, filename/image consistency | +| check_yaml_definitions_professions | professions.yml | Non-unique IDs, schema validation, entry sorting | +| check_yaml_definitions_authors | authors.yml | Non-unique IDs, schema validation, entry sorting | +| check_yaml_definitions_skills | skills.yml | Non-unique IDs, schema validation, entry sorting | +| check_yaml_definitions_robot_assets | robot_assets.yml | Non-unique IDs, schema validation, entry sorting | +| check_yaml_definitions_tags | tags.yml | Non-unique IDs, schema validation, entry sorting | +| check_yaml_content_new_activities | *.new_activity.yml | UUID/filename consistency, schema validation | +| check_yaml_content_new_activities_unique_uuid | *.new_activity.yml | UUID uniqueness across all new activities | +| check_yaml_content_activities_unique_uuid | *.activity.yml | UUID uniqueness across all legacy activities | +| check_yaml_content_activities_assets | *.activity.asset.* | Asset file duplicates | +| check_yaml_content_curriculums | *.curriculum.yml | UUID/filename consistency, schema validation | +| check_yaml_content_curriculums_unique_uuid | *.curriculum.yml | UUID uniqueness across all curriculums | +| check_yaml_content_curations | *.curation.yml | UUID/filename consistency, schema validation, item reference integrity | +| check_yaml_content_stories | *.story.yml | UUID/filename consistency, schema validation | +| check_yaml_content_stories_unique_uuid | *.story.yml | UUID uniqueness across all stories | +| check_yaml_content_cross_type_unique_uuid | *.new_activity.yml, *.curriculum.yml, *.story.yml, *.curation.yml | UUID collisions across all content types | diff --git a/Modules/ContentKit/QA/reports/2026_03_03/integration.md b/Modules/ContentKit/QA/reports/2026_03_03/integration.md new file mode 100644 index 0000000000..b0f57451ac --- /dev/null +++ b/Modules/ContentKit/QA/reports/2026_03_03/integration.md @@ -0,0 +1,154 @@ +# Wave 3 — Integration Audit Report + +> Generated: 2026-03-03 +> Auditor: Sisyphus QA Agent (task-15) +> Scope: `Modules/ContentKit/Resources/Content/` + +--- + +## Directory Naming Audit + +### Summary + +**78 curriculum directories checked, 9 anomalies found across 8 unique directories.** + +Anomaly breakdown: +- 3 directories missing `curriculum_` prefix (warning) +- 3 directories using deprecated `.curriculum` bundle suffix (warning) +- 2 directories whose name does not match their contained `.curriculum.yml` filename (warning) +- 1 directory with a hyphen in the name portion — `flower-petals` (info) +- 2 directories missing a `new_activities/` subdirectory (info) + +### Findings + +| Directory | Issue | Severity | +|-----------|-------|----------| +| `color_bingo-69760D1DA61849E3926E3A939BBEF0CE` | Missing `curriculum_` prefix | warning | +| `super_simon-C6EABAC161CD44C290B32202DFDCDAF6` | Missing `curriculum_` prefix | warning | +| `templates` | Not a content directory (contains template YML only, no UUID) | warning | +| `curriculum_find_ingredients_for_recipes-B477244ADFED4735BA1159A76E25001A.curriculum` | Uses deprecated `.curriculum` bundle suffix | warning | +| `curriculum_recognition_emotions_in_context-A135163C8D8646DE95D0854FD5E155EB.curriculum` | Uses deprecated `.curriculum` bundle suffix | warning | +| `curriculum_recognition_weather_and_time-1D8E1AB667DB40B199479D731EF96F2E.curriculum` | Uses deprecated `.curriculum` bundle suffix | warning | +| `curriculum_categorization_sorting_fruits_vegetables_basket-E6A322DC7A6E48518CED2CA2D3D2A595` | Dir name contains `curriculum_categorization_` prefix but YML name inside is `sorting_fruits_vegetables_basket-E6A322DC7A6E48518CED2CA2D3D2A595` (missing `curriculum_` in YML name) | warning | +| `curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1` | Dir uses hyphen `flower-petals`; YML inside is `curriculum_counting_flower_petals-...` (underscore). Dir name ≠ YML name | warning | +| `super_simon-C6EABAC161CD44C290B32202DFDCDAF6` | No `new_activities/` subdirectory | info | +| `templates` | No `new_activities/` subdirectory | info | +| `curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1` | Hyphen in name portion (`flower-petals`); all other dirs use underscores | info | + +### Bonus: Stale/Broken Curation References + +3 references in curation files point to UUIDs that do **not** match any known published content (dead references): + +| Curation File | Stale Reference | Issue | +|---------------|-----------------|-------| +| `curriculums-2685B06A51324C31A255B50D8A2AD064.curation.yml` (line 35) | `curriculum_recognition_alphabet_letters_a_to_f-50DC12AA75AA4ED48928FBAFB73CA7EF` | UUID does not exist in any curriculum file | +| `curriculums-2685B06A51324C31A255B50D8A2AD064.curation.yml` (lines 379, 427) | `curriculum_recognition_cooked_fruits-723490A27448424EAFCB7D75444E0480` | Ghost UUID — published curriculum uses UUID `C0D2DAE8152F4CAE863EAEBF815354BA` | +| `sandbox-4B476A0DFDC044B98DCBC631FF4EA27B.curation.yml` (line 290) | `by_theme-F83E2947CE8F40D1B6B8798042F3D31A` | No matching curation file exists for this UUID | + +Additionally, these name-mismatched references resolve by UUID but use inconsistent names (warning for content authoring): + +| Curation Value (mismatched name) | Correct name (from YML `name:` field) | UUID | +|----------------------------------|---------------------------------------|------| +| `curriculum_christmas_memory-EFC444BBDEF24E08813FF472FFA5365D` | `curriculum_memory_christmas` | `EFC444BBDEF24E08813FF472FFA5365D` | +| `curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978` | `curriculum_alphabetical_order` | `F9A2F6E76AE449999B1F76AA7E2D2978` | +| `curriculum_order_by_size-1FAED1FF14134571849325B6EC9197B5` | `curriculum_order_by_size_animals` | `1FAED1FF14134571849325B6EC9197B5` | +| `curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1` | `curriculum_counting_flower_petals` | `3F83E1E0F3094DC787258B9CEEF227A1` | +| `magic_card_belt_color_recognition-D3E24B95730848329B122769B077E65C` | `magic_card_color_recognition_belt` | `D3E24B95730848329B122769B077E65C` | +| `magic_card_screen_color_recognition-64C2CDF7DAA240CEB195F1BBE13941E3` | `magic_card_color_recognition_screen` | `64C2CDF7DAA240CEB195F1BBE13941E3` | +| `magic_card_child_emotion_recognition-A40CA9F3F50A4FD58DB9FF40B7DC69BB` | `magic_card_emotion_recognition_child` | `A40CA9F3F50A4FD58DB9FF40B7DC69BB` | +| `magic_card_leka_emotion_recognition-6BFDE930EBA7462AAC828D09843D7747` | `magic_card_emotion_recognition_leka` | `6BFDE930EBA7462AAC828D09843D7747` | + +--- + +## Orphaned Content Detection + +> **Methodology:** Curation reference graph built from all 40 `.curation.yml` files +> (8 top-level + 32 subcurations). All `items[].value` fields extracted. +> Content is "orphaned" when its `name-UUID` identifier (from its YML `name:` field) +> does not appear in any curation's items. +> +> **Note:** Most orphaned activities are curriculum-member activities (e.g., `_2`, `_4`, `_6` +> difficulty variants). They are accessible to users via their parent curriculum, which IS +> referenced in curations. Direct curation reference is only required for standalone activities. +> Severity is `info` — orphaned content may be intentional. + +### Summary + +**368 published activities checked, 298 orphaned (81%)** +**77 published curricula checked, 1 orphaned (1%)** + +### Orphaned Curricula + +| Curriculum | Status | Notes | +|------------|--------|-------| +| `curriculum_find_ingredients_for_recipes-B477244ADFED4735BA1159A76E25001A` | published | Not referenced in any curation; directory also uses deprecated `.curriculum` suffix | + +### Orphaned Activities + +> 298 published activities not directly referenced in any curation. +> See the `.sisyphus/evidence/` directory in the repo root for raw backing data. +> Summary by topic group below. + +| Topic Group | Orphaned Count | Example | +|-------------|---------------|---------| +| `alphabet_letters_sounds` | 20 | `alphabet_letters_sounds_1_1` through `_5_5` (all 5 series × 4 exercises) | +| `alphabetical_order` | 5 | `alphabetical_order_a_to_f`, `g_to_k`, `l_to_p`, `q_to_u`, `v_to_z` | +| `animal_recognition` (variants) | 18 | `_2`, `_4`, `_6` variants for farm/forest/insects/pets/sea/savannah | +| `animal_memory` | 3 | `1_pair`, `2_pairs`, `4_pairs` | +| `categorization_sort_through` (variants) | 6 | 3-category, functional-category variants | +| `categorization_sorting_fruits_vegetables` (variants) | 3 | `_2_two_choices`, `_3_three_choices`, `_4_four_choices` | +| `color_bingo` | 3 | `color_bingo_4`, `_5`, `_6` | +| `counting_candies` | 2 | `from_1_to_5`, `from_5_to_10` | +| `counting_flower_petals` | 2 | `from_10_to_15`, `from_15_to_20` | +| `counting_robot` | 3 | `animals`, `fruits`, `musical_instruments` | +| `find_ingredients_for_recipes` | 2 | `with_one_intruder`, `without_intruder` | +| `fruits_and_vegetables_generalization` | 2 | `with_3_intruders`, `without_intruder` | +| `generalization_fruits_robot` | 4 | `fruits_robot_1/2`, `vegetables_robot_1/2` | +| `magic_card` (variants) | 4 | `color_recognition_belt/screen`, `emotion_recognition_child/leka` | +| `memory_christmas` | 3 | `1_pair`, `2_pairs`, `4_pairs` | +| `order_by_size_animals` | 9 | bear, cow, dolphin, fish, giraffe, koala, ladybug, rabbit, snail | +| `order_by_size_different_animals` | 1 | single variant | +| `ordering_of_life_stages` | 2 | `boy`, `girl` | +| `ordering_steps_of_session_with_leka` | 3 | `_2`, `_3`, `_4` | +| `ordering_steps_to_bake_a_cake` | 3 | `_3`, `_4`, `_6` | +| `receptive_language` (all) | 14 | identify_familiar_nouns, ing_verbs, number_quantity, objects_by_color, by_function, opposites, positional_concepts | +| `recognition_alphabet_letters` (variants) | 15 | `_2`, `_4`, `_6` for all 5 series | +| `recognition_basic_physiological_needs` | 3 | 1/2/4 images | +| `recognition_body_parts` (variants) | 3 | `_2`, `_4`, `_6` | +| `recognition_christmas` (variants) | 2 | `_2`, `_4` | +| `recognition_cooked_fruits` (variants) | 3 | 2/4/6 images | +| `recognition_cooked_vegetables` (variants) | 3 | 2/4/6 images | +| `recognition_digital_constellations` (variants) | 3 | dice_numbers, dice, objects | +| `recognition_emotions_drawings` (all variants) | 22 | all moussa/oscar/zoe/multi-character variants | +| `recognition_emotions_generalization` | 6 | 2/3-type × 3/4/6 images | +| `recognition_emotions_pictograms` (variants) | 3 | `_2_leka`, `_3_leka`, `_4_leka` | +| `recognition_emotions_pictures` (all variants) | 22 | all ladislas/lucie/yann/multi-person variants | +| `recognition_emotions_robot` (variants) | 9 | generalization + image/picture variants | +| `recognition_family_members` (variants) | 3 | `_2`, `_4`, `_6` | +| `recognition_garden_items` (variants) | 3 | `_2`, `_4`, `_6` | +| `recognition_halloween` (variants) | 2 | `_2`, `_4` | +| `recognition_modes_of_transportation` (variants) | 3 | `_2`, `_4`, `_6` | +| `recognition_professions_drawings` | 6 | 1–6 images | +| `recognition_seaside_holidays` (variants) | 5 | `_2` through `_6` | +| `recognition_sounds_animals` | 6 | 1–6 images | +| `recognition_sounds_emotions` | 16 | all person+count combinations | +| `recognition_sounds_musical_instruments` | 6 | 1–6 images | +| `recognition_sports_drawings` | 6 | 1–6 images | +| `recognition_the_ice_floe` (variants) | 2 | `_2`, `_4` | +| `recognition_winter_holidays` (variants) | 3 | `_2`, `_4`, `_6` | +| `shape_recognition` (variants) | 6 | 2/4-images for plain, filled/unfilled, identical | +| `sort_objects_by_location` (variants) | 6 | 1/2 zones × 1/2/4/6 choices | +| `sort_sweet_and_salty` (variants) | 4 | 1/2 zones × 1/2/4 choices | +| `visual_discrimination_shapes_and_colors` | 4 | shapes/colors × 2/4 images | +| `weather_with_leka` | 3 | `_1`, `_2`, `_3` | + +--- + +## Key Findings + +1. **6 warning-level naming anomalies** in curriculum directories (3 missing prefix, 3 using deprecated `.curriculum` suffix). +2. **2 warning-level name-mismatch** directories where dir name ≠ YML `name:` field — this may cause curation resolution failures at runtime if the system ever resolves by name rather than UUID. +3. **3 dead curation references** (ghost UUIDs / missing subcuration): `curriculum_recognition_alphabet_letters_a_to_f-50DC12AA…`, `curriculum_recognition_cooked_fruits-723490A2…`, `by_theme-F83E2947…` — these will silently fail to resolve at runtime. +4. **4 curation name-mismatches** (same UUID, different human-readable name) — functional but causes content-authoring confusion. +5. **1 orphaned published curriculum**: `curriculum_find_ingredients_for_recipes-B477244A…` — not linked from any curation; coincides with the deprecated `.curriculum` suffix issue on its directory. +6. **298 orphaned published activities** — expected pattern; these are curriculum-member variants (difficulty levels `_2`, `_4`, `_6`) accessible only through parent curricula which ARE curation-linked. Not actionable unless standalone accessibility is desired. diff --git a/Modules/ContentKit/QA/reports/2026_03_03/structural.md b/Modules/ContentKit/QA/reports/2026_03_03/structural.md new file mode 100644 index 0000000000..76c5985386 --- /dev/null +++ b/Modules/ContentKit/QA/reports/2026_03_03/structural.md @@ -0,0 +1,332 @@ +# Wave 1 — Structural Baseline Report + +Generated: 2026-03-03 +Scope: All pre-commit content hooks run against all files +QA Mode: REPORT ONLY — zero content modifications made + +--- + +## Summary Table + +| Hook | Status | Findings | +|------|--------|----------| +| `check_yaml_content_new_activities` | ✅ PASS | 0 issues | +| `check_yaml_content_curriculums` | ✅ PASS | 0 issues | +| `check_yaml_content_stories` | ✅ PASS | 0 issues | +| `check_yaml_content_curations` | ❌ FAIL | 2 schema violations + 6 unresolved refs groups | +| `check_yaml_content_new_activities_unique_uuid` | ✅ PASS | 0 collisions | +| `check_yaml_content_curriculums_unique_uuid` | ✅ PASS | 0 collisions | +| `check_yaml_content_stories_unique_uuid` | ✅ PASS | 0 collisions | +| `check_yaml_content_cross_type_unique_uuid` | ✅ PASS | 0 cross-type collisions | +| `check_yaml_content_activities_assets` | ✅ PASS | 0 issues | +| `check_yaml_definitions_skills` | ✅ PASS | 0 issues | +| `check_yaml_definitions_tags` | ✅ PASS | 0 issues | +| `check_yaml_definitions_authors` | ✅ PASS | 0 issues | + +**Overall: 1 hook FAILING out of 12** + +--- + +## Critical Issues (crash risk) + +### CRITICAL-1: Schema violation — `story` is not a valid curation item type + +**Severity:** CRITICAL +**Hook:** `check_yaml_content_curations` +**Files affected:** +- `curations/stories-EA36F26CEE7A495B878EB1285AFBA4D3.curation.yml` — 6 items with `type: story` +- `curations/subcurations/quiet_time-7A47BF7D73694FA9A364A256511EE809.curation.yml` — 6 items with `type: story` + +**Detail:** The JTD schema `Specs/jtd/curation.jtd.json` only permits `type` values of `curriculum`, `activity`, or `curation`. Both files use `type: story` for their items. This will cause decoding failures at runtime when the app tries to load these curations — the `type` field cannot be decoded into the enum. + +**Impact:** The Stories tab curation and the `quiet_time` subcuration will fail to load, resulting in empty or crash screens for those sections. + +--- + +## Warnings + +### WARNING-1: Unresolved curriculum references in `curriculums-2685B06A51324C31A255B50D8A2AD064.curation.yml` + +**Severity:** WARNING +**Hook:** `check_yaml_content_curations` +**File:** `curations/curriculums-2685B06A51324C31A255B50D8A2AD064.curation.yml` + +**Missing curricula (9 references):** +- `content/0/items/0` → `curriculum_recognition_alphabet_letters_a_to_f-50DC12AA75AA4ED48928FBAFB73CA7EF` +- `content/0/items/1` → `curriculum_alphabet_letters_sounds_a_to_f-C157BAD4AA044EE89A941B1D868FFEB7` +- `content/0/items/2` → `curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978` +- `content/2/items/2` → `curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978` (duplicate ref) +- `content/2/items/5` → `curriculum_order_by_size-1FAED1FF14134571849325B6EC9197B5` +- `content/8/items/8` → `curriculum_order_by_size-1FAED1FF14134571849325B6EC9197B5` (duplicate ref) +- `content/14/items/3` → `curriculum_recognition_cooked_fruits-723490A27448424EAFCB7D75444E0480` +- `content/16/items/5` → `curriculum_recognition_cooked_fruits-723490A27448424EAFCB7D75444E0480` (duplicate ref) +- `content/17/items/0` → `curriculum_christmas_memory-EFC444BBDEF24E08813FF472FFA5365D` + +**Impact:** These items will not render in the Curriculums tab. Content appears missing to users but no crash expected (items silently skipped or empty). + +--- + +### WARNING-2: Unresolved curriculum reference in `mathematics-9D3BC84542E44614922FE450EC2F7F58.curation.yml` + +**Severity:** WARNING +**Hook:** `check_yaml_content_curations` +**File:** `curations/subcurations/mathematics-9D3BC84542E44614922FE450EC2F7F58.curation.yml` + +**Missing curriculum (1 reference):** +- `content/0/items/3` → `curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1` + +**Additional note (INFO):** The name `curriculum_counting_flower-petals` contains multiple hyphens. The hook warns that `CurationItemModel` splits on all hyphens and may truncate the name to `curriculum_counting_flower`, causing a lookup failure even if the curriculum existed. + +**Impact:** One missing curriculum item in the Mathematics subcuration. + +--- + +### WARNING-3: Unresolved references in `categorize_associate_organize-3B7D4928FF4B498F9DAA16FF50933979.curation.yml` + +**Severity:** WARNING +**Hook:** `check_yaml_content_curations` +**File:** `curations/subcurations/categorize_associate_organize-3B7D4928FF4B498F9DAA16FF50933979.curation.yml` + +**Missing references (2):** +- `content/0/items/8` → `curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978` (curriculum) +- `content/1/items/0` → `curriculum_categorization_sorting_fruits_vegetables_basket-E6A322DC7A6E48518CED2CA2D3D2A595` (curriculum) + +**Impact:** Two missing items in this categorization/sorting subcuration. + +--- + +### WARNING-4: Unresolved `magic_card_*` activity references in `magic_card_content-E6AEC63DF38F467E9C9974931017E47A.curation.yml` + +**Severity:** WARNING +**Hook:** `check_yaml_content_curations` +**File:** `curations/subcurations/magic_card_content-E6AEC63DF38F467E9C9974931017E47A.curation.yml` + +**Missing activities (4):** +- `content/0/items/1` → `magic_card_belt_color_recognition-D3E24B95730848329B122769B077E65C` +- `content/0/items/2` → `magic_card_screen_color_recognition-64C2CDF7DAA240CEB195F1BBE13941E3` +- `content/0/items/3` → `magic_card_leka_emotion_recognition-6BFDE930EBA7462AAC828D09843D7747` +- `content/0/items/4` → `magic_card_child_emotion_recognition-A40CA9F3F50A4FD58DB9FF40B7DC69BB` + +**Note:** Per inherited wisdom, these are known real content gaps — the `magic_card_*` activities are referenced but not yet created as v2 activities. + +**Impact:** Magic card content subcuration shows 4 missing activity items. + +--- + +### WARNING-5: Unresolved `magic_card_*` activity references in `fine_motor_skills-EFBB68F0B3D84A32B08A688CC2F9B8F0.curation.yml` + +**Severity:** WARNING +**Hook:** `check_yaml_content_curations` +**File:** `curations/subcurations/fine_motor_skills-EFBB68F0B3D84A32B08A688CC2F9B8F0.curation.yml` + +**Missing activities (4, same as WARNING-4):** +- `content/2/items/1` → `magic_card_belt_color_recognition-D3E24B95730848329B122769B077E65C` +- `content/2/items/2` → `magic_card_screen_color_recognition-64C2CDF7DAA240CEB195F1BBE13941E3` +- `content/2/items/3` → `magic_card_leka_emotion_recognition-6BFDE930EBA7462AAC828D09843D7747` +- `content/2/items/4` → `magic_card_child_emotion_recognition-A40CA9F3F50A4FD58DB9FF40B7DC69BB` + +**Impact:** Same magic card activities missing in the Fine Motor Skills subcuration. + +--- + +### WARNING-6: Unresolved curation reference in `sandbox-4B476A0DFDC044B98DCBC631FF4EA27B.curation.yml` + +**Severity:** WARNING +**Hook:** `check_yaml_content_curations` +**File:** `curations/sandbox-4B476A0DFDC044B98DCBC631FF4EA27B.curation.yml` + +**Missing curation (1):** +- `content/7/items/5` → `by_theme-F83E2947CE8F40D1B6B8798042F3D31A` (curation) + +**Impact:** One missing subcuration item in the Sandbox tab. + +--- + +## Info + +### INFO-1: Multi-hyphen name parsing caveat + +`CurationItemModel` splits on all hyphens to separate name from UUID. Any curriculum/activity name containing hyphens (e.g., `curriculum_counting_flower-petals-`) will be parsed incorrectly — the name will be truncated at the first internal hyphen. This is a structural parsing bug, not a content bug. Only `curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1` is flagged in this scan. + +--- + +## Per-Hook Output + +### check_yaml_content_new_activities +``` +Check new_activity.yml files.............................................Passed +``` + +### check_yaml_content_curriculums +``` +Check curriculum.yml files...............................................Passed +``` + +### check_yaml_content_stories +``` +Check story.yml files....................................................Passed +``` + +### check_yaml_content_curations +``` +Check curation.yml files.................................................Failed +- hook id: check_yaml_content_curations +- exit code: 1 + +Checking 4 curation files... + +✅ All curation files are valid! + +Checking 4 curation files... + +✅ All curation files are valid! + +Checking 4 curation files... + +❌ Found unresolved curation item references in Modules/ContentKit/Resources/Content/curations/subcurations/mathematics-9D3BC84542E44614922FE450EC2F7F58.curation.yml + - content/0/items/3: curriculum -> curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1 + +ℹ️ Found multi-hyphen curation item names in Modules/ContentKit/Resources/Content/curations/subcurations/mathematics-9D3BC84542E44614922FE450EC2F7F58.curation.yml + CurationItemModel splits on all hyphens and may truncate names. + - content/0/items/3/value: curriculum_counting_flower-petals-3F83E1E0F3094DC787258B9CEEF227A1 + +Checking 4 curation files... + +❌ Found unresolved curation item references in Modules/ContentKit/Resources/Content/curations/curriculums-2685B06A51324C31A255B50D8A2AD064.curation.yml + - content/0/items/0: curriculum -> curriculum_recognition_alphabet_letters_a_to_f-50DC12AA75AA4ED48928FBAFB73CA7EF + - content/0/items/1: curriculum -> curriculum_alphabet_letters_sounds_a_to_f-C157BAD4AA044EE89A941B1D868FFEB7 + - content/0/items/2: curriculum -> curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978 + - content/2/items/2: curriculum -> curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978 + - content/2/items/5: curriculum -> curriculum_order_by_size-1FAED1FF14134571849325B6EC9197B5 + - content/8/items/8: curriculum -> curriculum_order_by_size-1FAED1FF14134571849325B6EC9197B5 + - content/14/items/3: curriculum -> curriculum_recognition_cooked_fruits-723490A27448424EAFCB7D75444E0480 + - content/16/items/5: curriculum -> curriculum_recognition_cooked_fruits-723490A27448424EAFCB7D75444E0480 + - content/17/items/0: curriculum -> curriculum_christmas_memory-EFC444BBDEF24E08813FF472FFA5365D + +❌ File does not match the schema Specs/jtd/curation.jtd.json +Modules/ContentKit/Resources/Content/curations/stories-EA36F26CEE7A495B878EB1285AFBA4D3.curation.yml invalid +[ + { + instancePath: '/content/0/items/0/type', + schemaPath: '/definitions/$item/properties/type/enum', + keyword: 'enum', + params: { allowedValues: [Array] }, + message: 'must be equal to one of the allowed values', + schema: [ 'curriculum', 'activity', 'curation' ], + parentSchema: { enum: [Array] }, + data: 'story' + }, + { instancePath: '/content/0/items/1/type', ... data: 'story' }, + { instancePath: '/content/0/items/2/type', ... data: 'story' }, + { instancePath: '/content/0/items/3/type', ... data: 'story' }, + { instancePath: '/content/0/items/4/type', ... data: 'story' }, + { instancePath: '/content/0/items/5/type', ... data: 'story' } +] + +❌ Schema validation failed for Modules/ContentKit/Resources/Content/curations/stories-EA36F26CEE7A495B878EB1285AFBA4D3.curation.yml + +Checking 4 curation files... + +❌ Found unresolved curation item references in Modules/ContentKit/Resources/Content/curations/subcurations/categorize_associate_organize-3B7D4928FF4B498F9DAA16FF50933979.curation.yml + - content/0/items/8: curriculum -> curriculum_alphabetical_order_a_to_f-F9A2F6E76AE449999B1F76AA7E2D2978 + - content/1/items/0: curriculum -> curriculum_categorization_sorting_fruits_vegetables_basket-E6A322DC7A6E48518CED2CA2D3D2A595 + +Checking 4 curation files... + +❌ File does not match the schema Specs/jtd/curation.jtd.json +Modules/ContentKit/Resources/Content/curations/subcurations/quiet_time-7A47BF7D73694FA9A364A256511EE809.curation.yml invalid +[ + { instancePath: '/content/0/items/0/type', ... data: 'story' }, + { instancePath: '/content/0/items/1/type', ... data: 'story' }, + { instancePath: '/content/0/items/2/type', ... data: 'story' }, + { instancePath: '/content/0/items/3/type', ... data: 'story' }, + { instancePath: '/content/0/items/4/type', ... data: 'story' }, + { instancePath: '/content/0/items/5/type', ... data: 'story' } +] + +❌ Schema validation failed for Modules/ContentKit/Resources/Content/curations/subcurations/quiet_time-7A47BF7D73694FA9A364A256511EE809.curation.yml + +❌ Found unresolved curation item references in Modules/ContentKit/Resources/Content/curations/sandbox-4B476A0DFDC044B98DCBC631FF4EA27B.curation.yml + - content/7/items/5: curation -> by_theme-F83E2947CE8F40D1B6B8798042F3D31A + +Checking 4 curation files... + +❌ Found unresolved curation item references in Modules/ContentKit/Resources/Content/curations/subcurations/magic_card_content-E6AEC63DF38F467E9C9974931017E47A.curation.yml + - content/0/items/1: activity -> magic_card_belt_color_recognition-D3E24B95730848329B122769B077E65C + - content/0/items/2: activity -> magic_card_screen_color_recognition-64C2CDF7DAA240CEB195F1BBE13941E3 + - content/0/items/3: activity -> magic_card_leka_emotion_recognition-6BFDE930EBA7462AAC828D09843D7747 + - content/0/items/4: activity -> magic_card_child_emotion_recognition-A40CA9F3F50A4FD58DB9FF40B7DC69BB + +Checking 4 curation files... + +❌ Found unresolved curation item references in Modules/ContentKit/Resources/Content/curations/subcurations/fine_motor_skills-EFBB68F0B3D84A32B08A688CC2F9B8F0.curation.yml + - content/2/items/1: activity -> magic_card_belt_color_recognition-D3E24B95730848329B122769B077E65C + - content/2/items/2: activity -> magic_card_screen_color_recognition-64C2CDF7DAA240CEB195F1BBE13941E3 + - content/2/items/3: activity -> magic_card_leka_emotion_recognition-6BFDE930EBA7462AAC828D09843D7747 + - content/2/items/4: activity -> magic_card_child_emotion_recognition-A40CA9F3F50A4FD58DB9FF40B7DC69BB + +Checking 4 curation files... + +✅ All curation files are valid! +``` + +### check_yaml_content_new_activities_unique_uuid +``` +Check new_activity.yml files for unique uuid.............................Passed +``` + +### check_yaml_content_curriculums_unique_uuid +``` +Check curriculum.yml files for unique uuid...............................Passed +``` + +### check_yaml_content_stories_unique_uuid +``` +Check story.yml files for unique uuid....................................Passed +``` + +### check_yaml_content_cross_type_unique_uuid +``` +Check content files for cross-type UUID collisions.......................Passed +``` + +### check_yaml_content_activities_assets +``` +Check activity.asset.* files.............................................Passed +``` + +### check_yaml_definitions_skills +``` +Check skills.yml.........................................................Passed +``` + +### check_yaml_definitions_tags +``` +Check tags.yml...........................................................Passed +``` + +### check_yaml_definitions_authors +``` +Check authors.yml........................................................Passed +``` + +--- + +## Issue Tally + +| Severity | Count | Description | +|----------|-------|-------------| +| CRITICAL | 2 | Schema violations: `story` type not in JTD enum (stories curation + quiet_time subcuration) | +| WARNING | 21 | Unresolved references across 6 curation files (missing curricula, missing activities, missing subcuration) | +| INFO | 1 | Multi-hyphen name parsing caveat in mathematics subcuration | + +**Files failing validation:** 2 (schema) + 6 (unresolved refs) = **8 curation files with issues** +**Unique missing items:** +- 9 missing curricula in `curriculums-2685B06A51324C31A255B50D8A2AD064` +- 1 missing curriculum in `mathematics-9D3BC84542E44614922FE450EC2F7F58` +- 2 missing curricula in `categorize_associate_organize-3B7D4928FF4B498F9DAA16FF50933979` +- 4 missing activities in `magic_card_content-E6AEC63DF38F467E9C9974931017E47A` (known gap) +- 4 missing activities in `fine_motor_skills-EFBB68F0B3D84A32B08A688CC2F9B8F0` (same known gap) +- 1 missing curation in `sandbox-4B476A0DFDC044B98DCBC631FF4EA27B` +- 6 invalid type in `stories-EA36F26CEE7A495B878EB1285AFBA4D3` (CRITICAL) +- 6 invalid type in `quiet_time-7A47BF7D73694FA9A364A256511EE809` (CRITICAL) diff --git a/Modules/ContentKit/QA/reports/2026_03_03/summary.md b/Modules/ContentKit/QA/reports/2026_03_03/summary.md new file mode 100644 index 0000000000..dd8edffb7d --- /dev/null +++ b/Modules/ContentKit/QA/reports/2026_03_03/summary.md @@ -0,0 +1,211 @@ +# Content QA Master Summary + +> Generated: 2026-03-03 +> Scope: All content under `Modules/ContentKit/Resources/Content/` +> Audit tasks: T8 (hooks), T9–T14 (text quality), T15 (integration) +> QA Mode: REPORT ONLY — zero content files modified + +--- + +## Executive Summary + +| Metric | Value | +|--------|-------| +| Total content files scanned | ~556 files | +| Total issues found (all waves) | **126** | +| Critical issues | **3** | +| Warning issues | **73** | +| Info issues | **50** | +| Pre-commit hooks evaluated | 12 | +| Hooks passing | 11 / 12 | +| Hook failing | 1 (`check_yaml_content_curations`) | +| Content files modified | **0** (audit-only) | + +> **File count breakdown:** 78 curricula + 353 curriculum activities + 33 standalone/template/gamepad activities + 6 stories + 40 curations + 6 definitions + 40 other (YML infra) ≈ 556 files + +--- + +## Severity Breakdown (All Waves) + +| Severity | Count | Origin | Description | +|----------|-------|--------|-------------| +| **critical** | 3 | W1 (2), W2 (1) | Schema violations causing runtime failures; 154 unfilled Lorem ipsum fields in tags.yml | +| **warning** | 73 | W1 (21), W2 (39), W3 (13) | Typos, grammar errors, broken references, naming mismatches, stale curation links | +| **info** | 50 | W1 (1), W2 (49), W3 (up to 307+) | Extra whitespace, template placeholders, typography conventions, orphaned content | + +> W3 (Wave 3) info counts are not fully itemised here; the 302 orphaned activities are expected/intentional and listed in wave-3-integration.md. Orphaned items are excluded from the 50-info total above, which covers only Wave 1 and Wave 2 info findings. + +--- + +## Per-Content-Type Breakdown (Wave 2 Text Quality) + +| Content Type | Files | Critical | Warning | Info | Total | +|-------------|-------|----------|---------|------|-------| +| Curriculum activities — Batch A (curricula 1–26) | 100 | 0 | 5 | 0 | 5 | +| Curriculum activities — Batch B (curricula 27–52) | 104 | 0 | 0 | 24 | 24 | +| Curriculum activities — Batch C (curricula 53–78) | 149 | 0 | 0 | 0 | 0 | +| Curricula (YML files themselves) | 78 | 0 | 0 | 0 | 0 | +| Standalone/Template/Gamepad activities | 33 | 0 | 19 | 20 | 39 | +| Stories | 6 | 0 | 6 | 2 | 8 | +| Curations | 40 | 0 | 6 | 3 | 9 | +| Definitions | 6 | 1 | 3 | 0 | 4 | +| **Wave 2 Total** | **516** | **1** | **39** | **49** | **89** | + +--- + +## Wave 1 (Structural) Breakdown — Pre-commit Hook Results + +| Hook | Status | Findings | +|------|--------|----------| +| `check_yaml_content_new_activities` | ✅ PASS | 0 | +| `check_yaml_content_curriculums` | ✅ PASS | 0 | +| `check_yaml_content_stories` | ✅ PASS | 0 | +| `check_yaml_content_curations` | ❌ FAIL | 2 schema + 21 unresolved refs + 1 info | +| `check_yaml_content_new_activities_unique_uuid` | ✅ PASS | 0 | +| `check_yaml_content_curriculums_unique_uuid` | ✅ PASS | 0 | +| `check_yaml_content_stories_unique_uuid` | ✅ PASS | 0 | +| `check_yaml_content_cross_type_unique_uuid` | ✅ PASS | 0 | +| `check_yaml_content_activities_assets` | ✅ PASS | 0 | +| `check_yaml_definitions_skills` | ✅ PASS | 0 | +| `check_yaml_definitions_tags` | ✅ PASS | 0 | +| `check_yaml_definitions_authors` | ✅ PASS | 0 | + +**Wave 1 total: 2 critical, 21 warning, 1 info** + +--- + +## Wave 3 (Integration) Breakdown — Directory + Orphan Audit + +| Finding Type | Count | Severity | +|-------------|-------|----------| +| Curriculum directories missing `curriculum_` prefix | 3 | warning | +| Curriculum directories using deprecated `.curriculum` suffix | 3 | warning | +| Directory name ≠ YML `name:` field (resolution mismatch) | 2 | warning | +| Stale/duplicate curation references (incl. 1 ghost UUID) | 4 | warning | +| Orphaned published curriculum (not referenced in any curation) | 1 | warning | +| Directory with hyphen in name portion (parsing risk) | 1 | info | +| Curriculum directories missing `new_activities/` subdir | 2 | info | +| Orphaned published activities (curriculum-member variants) | 302 | info | + +**Wave 3 total: 0 critical, 13 warning, 305 info** (302 orphaned activities are expected/intentional) + +--- + +## Top Critical Issues — Fix First + +### CRITICAL-1: `story` type not in curation JTD schema (Wave 1) +**Crash risk.** 2 curation files use `type: story` for their items, but the JTD schema only permits `curriculum`, `activity`, or `curation`. These curations will fail to decode at runtime. +- `curations/stories-EA36F26CEE7A495B878EB1285AFBA4D3.curation.yml` (6 items) +- `curations/subcurations/quiet_time-7A47BF7D73694FA9A364A256511EE809.curation.yml` (6 items) +**Fix:** Add `"story"` to the `type` enum in `Specs/jtd/curation.jtd.json`. Content team to coordinate with dev team to ensure story-type curation items are handled correctly at runtime. + +### CRITICAL-2: Lorem ipsum in `definitions/tags.yml` (Wave 2) +**User-facing placeholder text.** All 77 tag descriptions contain `"Lorem ipsum"` in both `fr_FR` and `en_US` — 154 unfilled fields total. If tag descriptions are ever surfaced in the UI, users will see placeholder text. +**File:** `definitions/tags.yml` +**Fix:** Write real descriptions for all 77 tags, or mark the `description` field as optional in the schema if descriptions are not intended to be shown. + +--- + +## Top Warnings — Fix Soon + +### Warning Group A: Broken curation references (Wave 1 — 21 total) +Curations reference curricula/activities/subcurations that do not exist. Affected items silently disappear from the UI. + +| File | Missing Items | Impact | +|------|--------------|--------| +| `curriculums-2685B06A....curation.yml` | 9 missing curricula (alphabet, order_by_size, cooked_fruits, christmas_memory) | Curriculums tab missing items | +| `mathematics-9D3BC845....curation.yml` | 1 missing curriculum (`counting_flower-petals`) | Mathematics subcuration missing item | +| `categorize_associate_organize-3B7D4928....curation.yml` | 2 missing curricula | Categorization subcuration incomplete | +| `magic_card_content-E6AEC63D....curation.yml` | 4 missing activities (magic_card_*) | Magic Card subcuration shows 4 gaps | +| `fine_motor_skills-EFBB68F0....curation.yml` | 4 missing activities (same magic_card_*) | Fine Motor Skills subcuration incomplete | +| `sandbox-4B476A0D....curation.yml` | 1 missing curation (`by_theme`) | Sandbox tab missing item | + +### Warning Group B: Naming mismatches causing resolution failures (Wave 3 — 4 refs) +Stale names in curations no longer match actual content `name:` fields: +1. `curriculum_christmas_memory` → correct is `curriculum_memory_christmas` +2. `curriculum_recognition_cooked_fruits-723490A2...` → ghost UUID (does not exist; correct UUID is `C0D2DAE8...`) +3. `curriculum_categorization_sorting_fruits_vegetables_basket-E6A322DC...` → YML `name:` is `sorting_fruits_vegetables_basket-...` +4. `curriculum_counting_flower-petals-...` → YML `name:` uses underscore, not hyphen + +### Warning Group C: French grammar/spelling in definitions (Wave 2 — 4 occurrences) +- `skills.yml`: Wrong EN name for `written_expression` skill (copy-pasted from sibling) +- `skills.yml`: Missing word in EN `generalization` description (`"colors shapes"` → `"colors or shapes"`) +- `skills.yml`: Mixed conjugation in FR `sensory_integration/touch` description +- `activity_types.yml`: Typo `"accommpagnées"` in FR group description + +### Warning Group D: Recurring template text errors (Wave 2) +- 3 files: `"Ecoute"` → `"Écoute"` (6 occurrences in `_action_listen` templates) +- 3 files: Truncated Super Simon instructions (6 occurrences, all difficulty levels) +- 2 files: `"Touch"` → `"Touche"` (4 occurrences, fr_FR imperatives) +- 2 files: `"throw the reinforcer"` → better EN translation in gamepad activities +- 2 curation files: `"autours"` → `"autour"` (6 section title occurrences) + +--- + +## Hook Infrastructure Improvements (Added During QA) + +The following pre-commit hooks and schemas were added or fixed during this QA cycle (T1–T8): + +| Hook / Change | Purpose | Before | +|--------------|---------|--------| +| `check_yaml_content_curations` | Validates curation YAML against JTD schema + checks cross-references | No validation existed | +| `Specs/jtd/curation.jtd.json` | JTD schema for curation files | Did not exist | +| `check_yaml_content_new_activities_unique_uuid` | Detects duplicate UUIDs in v2 activity files | Did not exist | +| `check_yaml_content_cross_type_unique_uuid` | Detects UUID collisions across content types | Did not exist | +| Fixed unreferenced-activities hook | Now checks `new_activities/` (not old `activities/`) | Was checking deprecated path | +| Fixed author enum in 3 JTD schemas | Matches actual `authors.yml` values | Was rejecting valid authors | + +**Hook coverage after QA:** 12 hooks running, 11/12 passing. The single failing hook (`check_yaml_content_curations`) surfaces real content issues (schema violations + broken references) documented in Wave 1. + +--- + +## Known Structural Issues (from Wave 1) + +1. **JTD enum missing `story` type** → 2 curations fail schema validation → crash/empty screen risk +2. **9 curricula referenced but not created** (alphabet series, order_by_size, etc.) → gaps in Curriculums tab +3. **4 `magic_card_*` activities referenced but not created** → known content gap, affects 2 subcurations +4. **1 ghost UUID** (`curriculum_recognition_cooked_fruits-723490A2...`) → stale reference +5. **Multi-hyphen name parsing** in `CurationItemModel` → structural code bug, only `counting_flower-petals` currently affected + +--- + +## Recommendations (Priority Order) + +### Priority 1 — CRITICAL (crash/blank screen risk) +1. **Add `story` to curation JTD enum** (`Specs/jtd/curation.jtd.json`): Add `"story"` to the `type` enum. Content team to coordinate with dev team to ensure story-type curation items are handled correctly at runtime. Affects `stories-EA36F26C` and `quiet_time-7A47BF7D` curations. + +### Priority 2 — HIGH (broken references causing missing UI content) +2. **Create missing curricula** referenced in `curriculums-2685B06A` curation: `curriculum_recognition_alphabet_letters_a_to_f`, `curriculum_alphabet_letters_sounds_a_to_f`, `curriculum_alphabetical_order_a_to_f`, `curriculum_order_by_size`, `curriculum_recognition_cooked_fruits`, `curriculum_christmas_memory`. +3. **Fix stale curation references**: Update `curriculum_christmas_memory` → `curriculum_memory_christmas`, fix ghost UUID for `cooked_fruits`, and correct the `sorting_fruits_vegetables_basket` and `counting_flower-petals` reference formats. +4. **Create or remove the missing `by_theme` subcuration** referenced in `sandbox-4B476A0D`. + +### Priority 3 — MEDIUM (content quality / user trust) +5. **Fill in `definitions/tags.yml` descriptions**: Replace all 154 Lorem ipsum placeholder values with real descriptions in both `fr_FR` and `en_US`. +6. **Fix skills.yml errors** (4 issues): wrong `written_expression` EN name, missing word in `generalization` description, mixed conjugation in `touch` FR description. +7. **Fix `"Écoute"` accent** in 3 `_action_listen` template files (6 occurrences). +8. **Complete Super Simon instructions**: All 3 difficulty variants have truncated last bullet in both FR and EN. +9. **Fix `"autours"` typo** in `autonomy_and_daily_life` and `weather_and_environment` subcuration titles (6 occurrences). + +### Priority 4 — LOW (polish) +10. **Replace `sfsymbol` in `memory` template** instructions with user-friendly text. +11. **Fix `"Touch"` → `"Touche"`** in `activity_template` and `touch_to_select_vanilla` (4 occurrences). +12. **Fix `"throw the reinforcer"`** EN translation in 2 gamepad files. +13. **Normalize `fine_motor_skills` curation section title** (EN copy-paste from wrong section). +14. **Rename `sandbox` curation title** from `"Accueil"/"Home"` to correct sandbox label. +15. **Fix minor story text issues**: `"with his car"` → `"in his car"`, `"had a great fun"` → `"had great fun"`, inverted word order in pancakes story, `"puit"` → `"puits"`. +16. **Standardize EN typography**: Remove `" !"` (space-exclamation) in 2 curation titles; remove space before `:` in story instructions boilerplate. +17. **Fix extra spaces** in subtitle/description of alphabet recognition curricula and `order_by_size_different_animals` curriculum (24 info items). + +### Priority 5 — STRUCTURAL (code-level fixes, not content) +18. **Rename curriculum directory** to avoid internal hyphen in name portion: rename `curriculum_counting_flower-petals` to `curriculum_counting_flower_petals` (affects 1 directory). Content team to coordinate with dev team on the rename. +19. **Standardize curriculum directory naming**: Add `curriculum_` prefix to `color_bingo` and `super_simon` directories; migrate 3 `.curriculum` bundle-suffix directories to plain directories. + +--- + +## Related Reports + +| Report | Location | Contents | +|--------|----------|----------| +| Wave 1 — Structural | `structural.md` | Full hook output, all structural findings with detail | +| Wave 2 — Text Quality | `text-quality.md` | All 89 text quality findings across 516 files | +| Wave 3 — Integration | `integration.md` | Directory naming audit + orphaned content detection | diff --git a/Modules/ContentKit/QA/reports/2026_03_03/text-quality.md b/Modules/ContentKit/QA/reports/2026_03_03/text-quality.md new file mode 100644 index 0000000000..daeda455ea --- /dev/null +++ b/Modules/ContentKit/QA/reports/2026_03_03/text-quality.md @@ -0,0 +1,205 @@ +# Wave 2 — Text Quality Report + +> Generated: 2026-03-03 +> Scope: Text quality audit of all published content — curriculum activities (Batches A–C), standalone/template/gamepad activities, stories, curations, and global definitions +> Source tasks: T9 (Batch A), T10 (Batch B), T11 (Batch C), T12 (Standalones), T13 (Stories), T14 (Curations + Definitions) +> QA Mode: REPORT ONLY — zero content modifications made + +--- + +## Summary + +| Source | Files Scanned | Critical | Warning | Info | Total | +|--------|--------------|----------|---------|------|-------| +| T9 — Batch A (curriculums 1–26) | 26 curricula + 100 activities | 0 | 5 | 0 | 5 | +| T10 — Batch B (curriculums 27–52) | 26 curricula + 104 activities | 0 | 0 | 24 | 24 | +| T11 — Batch C (curriculums 53–78) | 26 curricula + 149 activities | 0 | 0 | 0 | 0 | +| T12 — Standalone/Template/Gamepad | 11 + 18 + 4 = 33 activities | 0 | 19 | 20 | 39 | +| T13 — Stories | 6 stories (52 pages) | 0 | 6 | 2 | 8 | +| T14 — Curations + Definitions | 40 curations + 6 definitions | 1 | 9 | 3 | 13 | +| **TOTAL** | **516 files** | **1** | **39** | **49** | **89** | + +**Overall health: 1 critical issue, 39 warnings, 49 info notices across 516 files.** + +--- + +## Findings by Content Type + +### 1. Curriculum Activities — Batch A (T9) + +**26 curricula + 100 activities scanned | 5 findings (0 critical, 5 warning, 0 info)** + +All 5 findings are concentrated in a single curriculum: `curriculum_categorization_sort_through_functional_category-64388748AF714B4880B8C7B6DD6D93F3`. + +| # | File (relative to `curriculums/`) | Field | Locale | Severity | Issue | +|---|----------------------------------|-------|--------|----------|-------| +| 1 | `curriculum_categorization_sort_through_functional_category-64388.../new_activities/categorization_sort_through_functional_category_1_image-DA072AA2...yml` | `l10n[fr_FR].details.instructions` | fr_FR | warning | Typo: `"Lorsque la réponse est correct"` → `"correcte"` (feminine agreement) | +| 2 | `curriculum_categorization_sort_through_functional_category-64388.../new_activities/categorization_sort_through_functional_category_2_images-F617D5D9...yml` | `l10n[fr_FR].details.instructions` | fr_FR | warning | Same typo: `"réponse est correct"` → `"correcte"` | +| 3 | `curriculum_categorization_sort_through_functional_category-64388.../new_activities/categorization_sort_through_functional_category_without_error-4AD006AA...yml` | `l10n[fr_FR].details.instructions` | fr_FR | warning | Same typo: `"réponse est correct"` → `"correcte"` | +| 4 | `curriculum_categorization_sort_through_functional_category-64388.../new_activities/categorization_sort_through_functional_category_6_images-DA01E28D...yml` | `l10n[en_US].details.instructions` | en_US | warning | Corrupted/truncated sentence with internal token: `"dropzone_pictograms-objects-house-bedroom-bed_blue-01A5room"` | +| 5 | `curriculum_categorization_sort_through_functional_category-64388.../new_activities/categorization_sort_through_functional_category_without_error-4AD006AA...yml` | `l10n[en_US].details.instructions` | en_US | warning | Grammar error: `"they that have to be grouped"` → `"that have to be grouped"` or `"which have to be grouped"` | + +--- + +### 2. Curriculum Activities — Batch B (T10) + +**26 curricula + 104 activities scanned | 24 findings (0 critical, 0 warning, 24 info)** + +All 24 findings are "extra spaces" in subtitle or description fields. Three curricula are affected: `order_by_size_different_animals`, `recognition_alphabet_letters_3`, `recognition_alphabet_letters_4`, and `recognition_alphabet_letters_5`. + +| # | File (relative to `curriculums/`) | Field | Locale | Severity | Issue | +|---|----------------------------------|-------|--------|----------|-------| +| 6 | `curriculum_order_by_size_different_animals-3158E58D.../curriculum_order_by_size_different_animals-3158E58D....curriculum.yml` | `l10n.details.description` | fr_FR | info | Extra spaces detected | +| 7 | `curriculum_order_by_size_different_animals-3158E58D.../curriculum_order_by_size_different_animals-3158E58D....curriculum.yml` | `l10n.details.description` | en_US | info | Extra spaces detected | +| 8 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../curriculum_recognition_alphabet_letters_3-ECDA6859....curriculum.yml` | `l10n.details.abstract` | fr_FR | info | Extra spaces detected | +| 9 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../curriculum_recognition_alphabet_letters_3-ECDA6859....curriculum.yml` | `l10n.details.abstract` | en_US | info | Extra spaces detected | +| 10 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../new_activities/recognition_alphabet_letters_3_2-B4D3D782...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 11 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../new_activities/recognition_alphabet_letters_3_2-B4D3D782...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 12 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../new_activities/recognition_alphabet_letters_3_4-3163D002...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 13 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../new_activities/recognition_alphabet_letters_3_4-3163D002...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 14 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../new_activities/recognition_alphabet_letters_3_6-9EA46A77...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 15 | `curriculum_recognition_alphabet_letters_3-ECDA6859.../new_activities/recognition_alphabet_letters_3_6-9EA46A77...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 16 | `curriculum_recognition_alphabet_letters_4-23997B52.../curriculum_recognition_alphabet_letters_4-23997B52....curriculum.yml` | `l10n.details.abstract` | fr_FR | info | Extra spaces detected | +| 17 | `curriculum_recognition_alphabet_letters_4-23997B52.../curriculum_recognition_alphabet_letters_4-23997B52....curriculum.yml` | `l10n.details.abstract` | en_US | info | Extra spaces detected | +| 18 | `curriculum_recognition_alphabet_letters_4-23997B52.../new_activities/recognition_alphabet_letters_4_2-12C97237...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 19 | `curriculum_recognition_alphabet_letters_4-23997B52.../new_activities/recognition_alphabet_letters_4_2-12C97237...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 20 | `curriculum_recognition_alphabet_letters_4-23997B52.../new_activities/recognition_alphabet_letters_4_4-0F187A5F...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 21 | `curriculum_recognition_alphabet_letters_4-23997B52.../new_activities/recognition_alphabet_letters_4_4-0F187A5F...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 22 | `curriculum_recognition_alphabet_letters_4-23997B52.../new_activities/recognition_alphabet_letters_4_6-D255CFBB...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 23 | `curriculum_recognition_alphabet_letters_4-23997B52.../new_activities/recognition_alphabet_letters_4_6-D255CFBB...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 24 | `curriculum_recognition_alphabet_letters_5-2B6FFBF9.../new_activities/recognition_alphabet_letters_5_2-6C29041B...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 25 | `curriculum_recognition_alphabet_letters_5-2B6FFBF9.../new_activities/recognition_alphabet_letters_5_2-6C29041B...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 26 | `curriculum_recognition_alphabet_letters_5-2B6FFBF9.../new_activities/recognition_alphabet_letters_5_4-AAF4E779...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 27 | `curriculum_recognition_alphabet_letters_5-2B6FFBF9.../new_activities/recognition_alphabet_letters_5_4-AAF4E779...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | +| 28 | `curriculum_recognition_alphabet_letters_5-2B6FFBF9.../new_activities/recognition_alphabet_letters_5_6-FFD60233...yml` | `l10n.details.subtitle` | fr_FR | info | Extra spaces detected | +| 29 | `curriculum_recognition_alphabet_letters_5-2B6FFBF9.../new_activities/recognition_alphabet_letters_5_6-FFD60233...yml` | `l10n.details.subtitle` | en_US | info | Extra spaces detected | + +--- + +### 3. Curriculum Activities — Batch C (T11) + +**26 curricula + 149 activities scanned | 0 findings** + +> No issues found. Batch C is fully clean across all text fields reviewed. + +--- + +### 4. Standalone Activities / Templates / Gamepads (T12) + +**11 standalones + 18 templates + 4 gamepads = 33 activities scanned | 39 findings (0 critical, 19 warning, 20 info)** + +| # | File | Field | Locale | Severity | Issue | +|---|------|-------|--------|----------|-------| +| 30 | `super_simon_2_colors` | `instructions` (last bullet) | fr_FR | warning | Truncated sentence: `"...Leka initiera un renforçateur pour encourager la personne"` — no object, no period | +| 31 | `super_simon_2_colors` | `instructions` (last bullet) | en_US | warning | Truncated sentence: `"...Leka will initiate a reinforcer to encourage the care receiver"` — dangling, no period | +| 32 | `super_simon_4_colors` | `instructions` (last bullet) | fr_FR | warning | Same truncation as finding #30 | +| 33 | `super_simon_4_colors` | `instructions` (last bullet) | en_US | warning | Same truncation as finding #31 | +| 34 | `super_simon_6_colors` | `instructions` (last bullet) | fr_FR | warning | Same truncation as finding #30 | +| 35 | `super_simon_6_colors` | `instructions` (last bullet) | en_US | warning | Same truncation as finding #31 | +| 36 | `activity_template` | exercise instruction #2 | fr_FR | warning | `"Touch le rond jaune"` — missing final 'e'; imperative is `"Touche"` | +| 37 | `activity_template` | exercise instruction #3 | fr_FR | warning | `"Touch la pastèque"` — missing final 'e'; imperative is `"Touche"` | +| 38 | `activity_template` | exercise instruction #4 | fr_FR | warning | `"Touch le carré"` — missing final 'e'; imperative is `"Touche"` | +| 39 | `touch_to_select_vanilla` | exercise instruction #3 | fr_FR | warning | `"Touch les symboles"` — missing final 'e'; imperative is `"Touche"` | +| 40 | `touch_to_select_action_listen` | exercise instruction #1 | fr_FR | warning | `"Ecoute et suis les instructions"` — missing capital accent É; should be `"Écoute"` | +| 41 | `touch_to_select_action_listen` | exercise instruction #2 | fr_FR | warning | `"Ecoute et choisis tous les bons éléments"` — missing É accent | +| 42 | `drag_and_drop_into_zones_action_listen` | exercise instruction #1 | fr_FR | warning | `"Ecoute et suis les instructions"` — missing É accent | +| 43 | `drag_and_drop_into_zones_action_listen` | exercise instruction #2 | fr_FR | warning | `"Ecoute et glisse l'animal dans le panier"` — missing É accent | +| 44 | `drag_and_drop_to_associate_action_listen` | exercise instruction #1 | fr_FR | warning | `"Ecoute et suis les instructions"` — missing É accent | +| 45 | `drag_and_drop_to_associate_action_listen` | exercise instruction #2 | fr_FR | warning | `"Ecoute et groupe les mêmes animaux ensemble"` — missing É accent | +| 46 | `memory` | exercise instruction #3 | fr_FR | warning | `"...trouve les paires de sfsymbol identiques"` — internal technical term `sfsymbol` exposed in user-facing text | +| 47 | `memory` | exercise instruction #3 | en_US | warning | `"...find the identical sfsymbol pairs"` — internal technical term `sfsymbol` exposed in user-facing text | +| 48 | `gamepad_joystick_color_pad` | exercise instruction | fr_FR | warning | `"fais le se déplacer"` — missing hyphen; should be `"fais-le se déplacer"` | +| 49 | `gamepad_arrow_pad_color_pad` | exercise instruction | en_US | warning | `"throw the reinforcer of your choice"` — awkward translation of `"lance le renforçateur"`; better: `"trigger"` / `"activate"` / `"launch"` | +| 50 | `gamepad_joystick_color_pad` | exercise instruction | en_US | warning | `"throw the reinforcer of your choice"` — same awkward translation | +| 51 | `activity_template` | `short_description`, `description`, `instructions` | both | info | Template placeholder text present (`"Courte description de l'activité"`, `"bla bla bla"`) — intentional for template | +| 52 | `touch_to_select_vanilla` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 53 | `touch_to_select_action_listen` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 54 | `touch_to_select_action_observe` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 55 | `touch_to_select_action_robot` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 56 | `0_touch_to_select_0_find_the_right_answers` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 57 | `0_touch_to_select_1_find_the_right_order` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 58 | `0_touch_to_select_2_associate_categories` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 59 | `drag_and_drop_in_order_vanilla` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 60 | `drag_and_drop_into_zones_vanilla` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 61 | `drag_and_drop_into_zones_action_listen` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 62 | `drag_and_drop_into_zones_action_observe` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 63 | `drag_and_drop_into_zones_action_robot` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 64 | `drag_and_drop_to_associate_vanilla` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 65 | `drag_and_drop_to_associate_action_listen` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 66 | `drag_and_drop_to_associate_action_observe` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 67 | `drag_and_drop_to_associate_action_robot` | `short_description`, `description`, `instructions` | both | info | Lorem ipsum placeholder text — intentional for template | +| 68 | `memory` | `subtitle` | both | info | Empty subtitle field (`subtitle:` with no value) — consistent with template status | + +--- + +### 5. Stories (T13) + +**6 stories (52 pages) scanned | 8 findings (0 critical, 6 warning, 2 info)** + +| # | File | Field | Locale | Severity | Issue | +|---|------|-------|--------|----------|-------| +| 69 | all 6 stories (shared boilerplate) | `instructions` bullet 1–3 | en_US | info | French typographic space before colon carried into English: `"Explore the story :"` → `"Explore the story:"` | +| 70 | `first_day_of_school-8DE906A4...story.yml` | page 9 `items[4].payload.text` | en_US | warning | `"drives Hanna to school with his car"` — unnatural; standard phrasing is `"in his car"` | +| 71 | `hanna_at_the_beach-60C133CB...story.yml` | page 2 vs page 3 character label | en_US | warning | Same character (Nagib) labelled `"Father"` (page 2) then `"Dad"` (page 3) within the same story; FR uses `"Papa"` consistently | +| 72 | `hanna_at_the_beach-60C133CB...story.yml` | page 7 `items[4].payload.text` | en_US | warning | `"had a great fun"` — grammatically incorrect; `fun` is uncountable here; → `"had great fun"` or `"had a great time"` | +| 73 | `hanna_dances_with_leka-47509B00...story.yml` | `l10n[].details.title` | en_US | warning | FR title `"Hanna Danse avec Leka"` vs EN title `"Let's Dance"` — EN omits both character names; significant divergence | +| 74 | `hanna_makes_pancakes-5213404A...story.yml` | page 6 `items[1].payload.text` | en_US | warning | `"puts also 2 tablespoons of sugar"` — inverted word order; → `"also puts 2 tablespoons of sugar"` | +| 75 | `hanna_makes_pancakes-5213404A...story.yml` | page 7 `items[2].payload.text` | fr_FR | warning | `"fait un puit dans le saladier"` — misspelling; `"puit"` → `"puits"` (always written with final -s) | +| 76 | `hanna_makes_pancakes-5213404A...story.yml` | page 12 vs page 14 character label | en_US | info | Same character labelled `"Dad"` (page 12) then `"Daddy"` (page 14) — both valid but inconsistent within a single story | + +--- + +### 6. Curations + Global Definitions (T14) + +**40 curations + 6 definitions scanned | 13 findings (1 critical, 9 warning, 3 info)** + +| # | File | Field | Locale | Severity | Issue | +|---|------|-------|--------|----------|-------| +| 77 | `definitions/tags.yml` | `description` (all 77 tags) | fr_FR + en_US | **critical** | Every tag description contains `"Lorem ipsum"` placeholder — 77 tags × 2 locales = 154 unfilled description fields | +| 78 | `definitions/activity_types.yml` | `list[id=group].l10n[fr_FR].description` | fr_FR | warning | Typo: `"accommpagnées"` (double 'm') → `"accompagnées"` | +| 79 | `definitions/skills.yml` | `communication/verbal_communication/expressive_language/written_expression.l10n[en_US].name` | en_US | warning | Wrong name copy-pasted from sibling skill: `"Written comprehension (reading)"` should be `"Written expression (writing)"` | +| 80 | `definitions/skills.yml` | `generalization.l10n[en_US].description` | en_US | warning | Missing word: `"different colors shapes"` → `"different colors or shapes"` | +| 81 | `definitions/skills.yml` | `sensory_integration/touch.l10n[fr_FR].description` | fr_FR | warning | Mixed conjugation: `"manipule ou jouer"` (indicative + infinitive) → `"manipule ou joue"` | +| 82 | `curations/curriculums-2685B06A....curation.yml` | `content[Festivités].l10n[en_US].details.description` | en_US | warning | Trailing double period: `"for the holidays.."` — extra period | +| 83 | `curations/sandbox-4B476A0D....curation.yml` | `l10n.details.title` | fr_FR + en_US | warning | Top-level title is `"Accueil"` / `"Home"` — same as home curation; appears copy-pasted and not updated for sandbox context | +| 84 | `curations/subcurations/autonomy_and_daily_life-D680A316....curation.yml` | section titles (3 occurrences, lines 26/56/78) | fr_FR | warning | Typo `"autours"` in 3 section titles — not a standard French word; → `"autour"` | +| 85 | `curations/subcurations/weather_and_environment-572F710A....curation.yml` | section titles (3 occurrences, lines 26/44/60) | fr_FR | warning | Same typo `"autours"` in 3 section titles → `"autour"` | +| 86 | `curations/subcurations/fine_motor_skills-EFBB68F0....curation.yml` | `content[2].l10n[en_US].details.title` | en_US | warning | Wrong EN section title — copy-pasted from drag-and-drop section; FR title is about préhension (grasping), not drag-and-drop | +| 87 | `curations/subcurations/gross_motor_skills-63BB71F5....curation.yml` | `content[0].l10n[en_US].details.title` | en_US | info | Non-standard EN typography: `"Activities to move with Leka !"` — space before `!` is French convention, not English | +| 88 | `curations/subcurations/in_group-9D0EBC77....curation.yml` | `content[0].l10n[en_US].details.title` | en_US | info | Same non-standard EN spacing: `"Activities to move with Leka !"` | +| 89 | `curations/sandbox-4B476A0D....curation.yml` | `content[vertical_curation_grid].l10n[en_US].details.title` | en_US | info | Inconsistent capitalization: `"by learning objective"` — all other EN section titles start with uppercase | + +--- + +## Recurring Issue Patterns + +### Pattern 1: French gender agreement — `"correct"` instead of `"correcte"` (3 occurrences, fr_FR) +Files `categorization_sort_through_functional_category_1_image`, `_2_images`, `_without_error`. All share the same boilerplate instruction text. Fix: replace `"est correct"` with `"est correcte"` in the `fr_FR` instructions block of all three activities. + +### Pattern 2: Missing capital accent — `"Ecoute"` instead of `"Écoute"` (6 occurrences, 3 template files, fr_FR) +Affects all three `_action_listen` template variants (`touch_to_select_action_listen`, `drag_and_drop_into_zones_action_listen`, `drag_and_drop_to_associate_action_listen`), 2 occurrences each. The shared boilerplate uses an unaccented capital E. + +### Pattern 3: Truncated French imperative — `"Touch"` instead of `"Touche"` (4 occurrences, 2 files, fr_FR) +Affects `activity_template` (3 exercises) and `touch_to_select_vanilla` (1 exercise). English `"Touch"` is correct; the error is only in the French imperative form. + +### Pattern 4: Truncated Super Simon instructions (3 × 2 locales = 6 occurrences) +All three `super_simon_*_colors` variants share identical instruction text with the last bullet syntactically incomplete in both FR and EN. Appears to be a copy-paste truncation never corrected across difficulty levels. + +### Pattern 5: `"autours"` misspelling (6 occurrences, 2 curation files, fr_FR) +Repeated across `autonomy_and_daily_life` (3 section titles) and `weather_and_environment` (3 section titles). Standard French is `"autour"` (invariable). + +### Pattern 6: `"throw the reinforcer"` awkward EN translation (2 occurrences) +Both `gamepad_arrow_pad_color_pad` and `gamepad_joystick_color_pad` use this literal translation of `"lance le renforçateur"`. Better English: `"trigger"`, `"activate"`, or `"launch"`. + +### Pattern 7: Template placeholder text (18 template files, info-level) +All `new_templates/` files contain Lorem ipsum or equivalent placeholder text. This is intentional design for template files but flagged as info in case any template is accidentally referenced in production curations. + +--- + +## Clean Areas (No Issues Found) + +- **Batch C** (26 curricula, 149 activities): Fully clean across all reviewed text fields. +- **Standalone activities** — `color_mediator`, `dance_freeze`, `discover_leka`, `gamepad_arrow_pad_big`, `gamepad_color_pad`, `xylophone_heptatonic`, `xylophone_pentatonic`, `hide_and_seek`, `melody`, `color_music_pad`: All clean. +- **`definitions/`** — `authors.yml`, `robot_assets.yml`, `hmi.yml`: No issues. +- **Stories** — `hanna_meets_leka`, `hanna_plays_music`, `hanna_dances_with_leka` (except title divergence): Clean body text. +- **Extra spaces (T10)**: The 24 info-level findings are cosmetic whitespace only (no missing text, no wrong text). No user-facing impact. diff --git a/Modules/ContentKit/Resources/Content/AGENTS.md b/Modules/ContentKit/Resources/Content/AGENTS.md new file mode 100644 index 0000000000..7f29a383ca --- /dev/null +++ b/Modules/ContentKit/Resources/Content/AGENTS.md @@ -0,0 +1,492 @@ +# ContentKit Content System + +This document describes the educational content system used by the Leka app. All content lives in `Modules/ContentKit/Resources/Content/` and is defined in YAML files. + +**Important:** Only the v2 activity format (`.new_activity.yml`, `version: 2.0.0`) is current. The old v1 format (`.activity.yml`, `version: 1.0.0`) is deprecated and will be removed. + +## Directory Structure + +``` +Content/ +├── definitions/ # Global taxonomies (skills, tags, authors, etc.) +│ ├── skills.yml # Hierarchical skill definitions +│ ├── tags.yml # Flat topic tags +│ ├── authors.yml # Content author profiles +│ ├── activity_types.yml # one_on_one, group +│ ├── hmi.yml # Interaction mediums +│ ├── robot_assets.yml # Magic card / robot screen asset hex IDs +│ ├── cardAssets/ # Card PNG images per locale (en/, fr/) +│ └── icons/ # Skill icon PNGs +│ +├── interaction/ # Icon PNGs for interaction classification +│ ├── attention/ # listen, look, mixed +│ ├── input/ # drag_and_drop, magic_card, touch_to_select, mixed +│ └── medium/ # robot, tablet, tablet_robot +│ +├── curations/ # UI layout/navigation files (.curation.yml) +│ ├── home-*.curation.yml +│ ├── explore-*.curation.yml +│ ├── curriculums-*.curation.yml +│ ├── educational_games-*.curation.yml +│ ├── stories-*.curation.yml +│ ├── gamepads-*.curation.yml +│ ├── sandbox-*.curation.yml +│ ├── learning_objectives-*.curation.yml +│ └── subcurations/ # ~30 themed subcurations (animals, emotions, colors, etc.) +│ +├── newActivities/ # Standalone/template v2 activities +│ ├── new_standalones/ # Standalone activities (dance_freeze, melody, etc.) +│ ├── new_templates/ # Template activities for reference +│ └── new_gamepads/ # Gamepad controller activities +│ +├── curriculums/ # ~70 curriculum directories +│ └── curriculum_-/ +│ ├── -.curriculum.yml +│ ├── new_activities/ # v2 activities belonging to this curriculum +│ │ ├── icons/ # Activity icon PNGs +│ │ └── assets/ # Activity asset PNGs +│ └── activities/ # DEPRECATED v1 activities (ignore) +│ +└── stories/ # Interactive story files (.story.yml) +``` + +## ID and Reference System + +Every content item has an ID in the format: `-<32_CHAR_HEX_UUID>` + +Examples: +- `curriculum_recognition_body_parts-80761A1D62BF4C6980BF20E7D9BE52B8` +- `recognition_body_parts_1-756B84801C32483FABEA6E5BC5DF7081` +- `dance_freeze-6E2F7D56726C419EA534C614F777D934` + +The UUID is a 32-character uppercase hex string (no hyphens). File names follow the same pattern: `-..yml`. + +### Reference Chain + +``` +Curation --[items.value]--> Curriculum | Activity | Curation (subcuration) +Curriculum --[activities]--> Activity (by name-UUID) +Story --[pages.items.action]--> Activity (inline) | Robot actions +Activity --[authors]--> authors.yml IDs +Activity --[skills]--> skills.yml IDs (slash-path like "sensory_integration/vision") +Activity --[tags]--> tags.yml IDs +Activity --[types]--> activity_types.yml IDs +Activity --[interaction.medium]--> hmi.yml IDs +``` + +## Localization (l10n) + +All content supports two locales: `fr_FR` and `en_US`. Localized data appears in `l10n` arrays: + +```yaml +l10n: + - locale: fr_FR + details: + title: Les parties du corps + subtitle: 1 image + ... + - locale: en_US + details: + title: Body Parts + subtitle: 1 image + ... +``` + +## YAML File Header + +All YAML files must start with: + +```yaml +# Leka - iOS Monorepo +# Copyright APF France handicap +# SPDX-License-Identifier: Apache-2.0 +``` + +--- + +## Activity Schema (v2 - `.new_activity.yml`) + +```yaml +version: 2.0.0 + +uuid: <32_CHAR_HEX_UUID> +name: + +created_at: "" +last_edited_at: "" +status: published # published | draft | template + +authors: + - leka # References authors.yml + +skills: # References skills.yml (slash-path for subskills) + - recognition + - sensory_integration/vision + +tags: # References tags.yml + - body_parts + +interaction: + medium: tablet # tablet | robot | tablet_robot + input: touch_to_select # touch_to_select | drag_and_drop | magic_card | mixed + attention: listen # listen | look | mixed (optional) + +types: + - one_on_one # one_on_one | group + +locales: + - en_US + - fr_FR + +l10n: + - locale: fr_FR + details: + icon: # PNG filename (no extension) in icons/ + title: + subtitle: + short_description: | + + description: | + + instructions: | + + - locale: en_US + details: ... + +payload: + options: + shuffle_exercises: true # Shuffle order of exercises + shuffle_groups: false # Shuffle order of exercise groups + + exercise_groups: + - group: + - # See Exercise Schema below + - + - group: + - +``` + +### Exercise Schema + +Each exercise within a group has this structure: + +```yaml +instructions: # Optional, per-locale instructions for this exercise + - locale: fr_FR + value: + - locale: en_US + value: + +interface: # See Interface Types below +gameplay: # See Gameplay Types below + +action: # Optional, triggered action + type: ipad | robot + value: + type: speech | color | motion | random | activity + value: # Speech: l10n utterances, Color: color name, etc. + +options: # Optional + shuffle_choices: true + +payload: + choices: # For general interfaces + - value: # Image name, emoji, SF Symbol, or color name + type: image | emoji | sfsymbol | color + is_right_answer: true # Optional, marks correct answer + is_dropzone: true # Optional, for drag-and-drop zones + category: catA # Optional, for association/memory (catA, catB, catC...) + dropZone: zoneA # Optional, target zone for drag-and-drop + songs: # For danceFreeze interface + - audio: + labels: + - locale: fr_FR + value: + name: + icon: +``` + +### Interface Types + +**General (tablet-based):** +- `touchToSelect` - Tap the correct choice from options +- `dragAndDropIntoZones` - Drag items into labeled drop zones +- `dragAndDropGrid` - Drag items into a grid layout +- `dragAndDropOneToOne` - Drag items to order them sequentially +- `dragAndDropGridWithZones` - Grid-based drag with category zones +- `memory` - Flip cards to find matching pairs +- `magicCards` - Use physical NFC magic cards scanned by robot + +**Specialized (robot-integrated):** +- `danceFreeze` - Robot dances to music, freezes randomly +- `superSimon` - Simon Says color memory game with robot LEDs +- `hideAndSeek` - Robot plays hide and seek with sound/light +- `melody` - Music creation/playback +- `musicalInstruments` - Xylophone (pentatonic/heptatonic) +- `colorMusicPad` - Color-sound association pad +- `colorMediator` - Robot lights up colors for group games +- `gamepadArrowPad` - Directional control of robot movement +- `gamepadColorPad` - Color-button control of robot +- `gamepadJoyStickColorPad` - Joystick + color control +- `gamepadArrowPadColorPad` - Arrow + color pad combined +- `pairing` - Pairing interaction +- `discoverLeka` - Introduction to the robot + +### Gameplay Types + +- `findTheRightAnswers` - Select correct answers from choices +- `findTheRightOrder` - Arrange items in correct sequence +- `associateCategories` - Match items by category (used with memory, drag-and-drop zones) +- `openPlay` - Free play without scoring + +### Choice Types + +- `image` - PNG asset reference (filename without extension, located in curriculum's assets/) +- `emoji` - Unicode emoji character (e.g., `🍌`) +- `sfsymbol` - SF Symbols name (e.g., `circle`, `square`) +- `color` - Color name (e.g., `red`, `yellow`, `blue`, `green`, `pink`) + +### Action Types + +**iPad actions:** +```yaml +action: + type: ipad + value: + type: speech + value: + - locale: fr_FR + utterance: "le bras" + - locale: en_US + utterance: "the arm" +``` + +**Robot actions:** +```yaml +action: + type: robot + value: + type: color # color | motion | random + value: blue # color name, motion name, or "color" +``` + +--- + +## Curriculum Schema (`.curriculum.yml`) + +```yaml +uuid: <32_CHAR_HEX_UUID> +name: curriculum_ +status: published # published | draft | template + +created_at: "" +last_edited_at: "" + +authors: + - leka + +skills: + - recognition + +tags: + - body_parts + +locales: + - en_US + - fr_FR + +l10n: + - locale: fr_FR + details: + icon: + title: + subtitle: + abstract: | + + description: | + + - locale: en_US + details: ... + +activities: # Ordered list of activity name-UUID references + - - + - - +``` + +Curriculums live in `curriculums/curriculum_-/` directories. Their activities live in the `new_activities/` subdirectory within. + +--- + +## Story Schema (`.story.yml`) + +```yaml +version: 1.0.0 + +uuid: <32_CHAR_HEX_UUID> +name: + +created_at: "" +last_edited_at: "" +status: published + +authors: + - hanna_and_nagib + - leka + +skills: + - familiarization_with_leka + +interaction: + medium: tablet_robot + input: touch_to_select + +types: + - one_on_one + +tags: + - hanna + - story + +locales: + - en_US + - fr_FR + +l10n: + - locale: fr_FR + details: + icon: + title: + subtitle: + short_description: | + + description: | + + instructions: | + + - locale: en_US + details: ... + +pages: + - background: + l10n: + - locale: fr_FR + items: + - type: text # text | image | button_image + payload: + text: "Some text" + - type: button_image + payload: + idle: # Image when not pressed + pressed: # Image when pressed + text: