| name | exercise-testing |
| description | Comprehensive validation for Pixels2GenAI v2 lessons. Use when validating ported v1 Python scripts, checking copied lesson assets, type-checking MDX frontmatter, running the Astro build, or performing quality audits on a lesson. Activate after porting a lesson, before marking a lesson as shipped, or when debugging build/render errors. |
Lesson Testing & Validation Skill (v2)
Skill Overview
This skill provides comprehensive validation protocols for v2 lessons. A "lesson" in v2 is the combination of an MDX file under src/content/lessons/, the assets it references under public/lesson-media/<lesson-path>/, and the leaf entry in src/data/curriculum/subtopics.ts. Validation makes sure every layer is consistent before the lesson goes live.
Path convention — <lesson-path> means the v1-mirrored relative path Module_NN_<topic>/X.Y_<subtopic>/X.Y.Z_<exercise>: the MDX is the file src/content/lessons/<lesson-path>.mdx, its assets sit in the folder public/lesson-media/<lesson-path>/, and the page URL is /lessons/<id> (numeric leaf id). npm run check validates all of this wiring automatically — run it first.
When to Use This Skill
- After porting a v1 lesson (RST → MDX) — use alongside the
lesson-port skill
- After authoring a new MDX lesson from scratch
- Before marking a lesson as shipped (i.e. before adding
lessonSlug in subtopics.ts)
- When debugging build / render errors
- During quality assurance reviews
Testing Hierarchy
Level 1: Source Python Execution (MUST PASS for ported lessons)
↓
Level 2: Asset Migration & Validation (MUST PASS)
↓
Level 3: MDX Frontmatter + Content (MUST PASS)
↓
Level 4: Astro Build + Render (MUST PASS)
↓
Level 5: Quality Audit (CHECKLIST)
Level 1: Source Python Execution
Goal: Verify the v1-source Python scripts still execute, since their outputs are the static images embedded in the v2 lesson.
This applies only when porting a lesson from v1. For lessons authored natively in v2, skip to Level 2.
Manual Testing
# Navigate to the v1 exercise directory
$v1 = "C:\Users\User\Desktop\git-repos\numpy-to-genAI"
Set-Location "$v1\content\Module_XX_topic\X.Y_subtopic\X.Y.Z_exercise"
# Activate the v1 venv (Python 3.11.9)
& "$v1\.venv\Scripts\Activate.ps1"
# Run each script
python exercise1_execute.py
python exercise2_modify.py
python exercise3_create.py
# Exit code 0 = pass
Common Source Errors
ModuleNotFoundError — venv missing a dependency. Compare against <v1>\requirements.txt.
FileNotFoundError — script depends on a relative path. Confirm the working directory matches the exercise folder.
Array dimension mismatch — usually a NumPy version skew between v1's venv and a fresh Python.
If a v1 script fails, do not silently fix it in v1 (v1 is treated as read-only). Instead: document the failure, port the current working output PNG/GIF, and either skip the broken example in the MDX or write a v2-equivalent script under public/lesson-media/<lesson-path>/.
Level 2: Asset Migration & Validation
Goal: Verify that every image, GIF, and downloadable .py referenced from the MDX exists under public/lesson-media/<lesson-path>/.
Step 2.1 — Run the migrator
The migrator is inventory-driven (docs/reports/migration-inventory.json); run it for the lesson under test:
npm run copy-assets -- --only=<id>
The script copies PNG/GIF/JPG/SVG/PY/PTH/TXT into public/lesson-media/<lesson-path>/ and is idempotent — re-running overwrites destination files. It deliberately skips README.rst because the MDX hand-port is canonical.
Step 2.2 — Cross-reference MDX assets
For every src="/lesson-media/<lesson-path>/…" in the MDX, verify the file exists:
# Inside the lesson dir, list everything that was copied
Get-ChildItem -Recurse "public/lesson-media/<lesson-path>/"
Then grep the MDX for every /lesson-media/ reference and confirm each filename appears in the directory listing (npm run check does exactly this across all lessons).
Step 2.3 — Image sanity checks
For each PNG / GIF / JPG in public/lesson-media/<lesson-path>/:
- Opens cleanly (no zero-byte / truncated files)
- File size <= 500 KB for PNGs, <= 2 MB for GIFs (see
docs/references/visual-guidelines.md)
- Dimensions between 10×10 and 4096×4096
Quick PowerShell check:
Get-ChildItem "public/lesson-media/<lesson-path>/*.png" | ForEach-Object {
$kb = [math]::Round($_.Length / 1KB, 1)
"$($_.Name): $kb KB"
}
Checklist
Level 3: MDX Frontmatter + Content
Goal: Verify the MDX file is valid against the Zod schema in src/content/config.ts and uses the custom MDX components correctly.
Step 3.1 — Frontmatter schema check
The schema (in src/content/config.ts) requires:
---
module: "M 04"
cycle: "I"
title: "Fractal Square"
objective: "One-sentence italic lead."
framework: "hands-on"
duration: "20–25 min"
level: "beginner"
load: "3 core concepts"
prereqs: "Basic Python"
prev: { slug: "1.1.1", title: "Images as Arrays & RGB" }
next: { slug: "12.1.2", title: "DCGAN Art" }
backLink: { href: "/#curriculum", label: "Back to Curriculum" }
---
The build fails fast if any required field is missing or has the wrong shape — npm run build is the authoritative check (Astro runs Zod under the hood).
Step 3.2 — Custom component sanity
Required components (defined in src/components/lesson/):
| Component | Usage |
|---|
<CodeBlock lang="python" file="…"> | Wraps fenced code blocks |
<Admonition type="tip|note|important|dyk" title="…"> | Pull-out boxes; dyk = "Did You Know" but PREFER a specific title |
<Figure src=… alt=… caption=… num={N} role="diagram|output"> | All images |
<Exercise n={1} kicker="EXECUTE" title="…"> | Exercise wrappers (kickers: EXECUTE, MODIFY, CREATE) |
<Dropdown summary="…"> | Collapsible hint/solution blocks |
<Download href=… label=…> | Asset download links |
Step 3.3 — Sectionize check
The Astro config (astro.config.mjs) auto-wraps content between ## h2 headings into <section class="lesson-section">. Confirm:
- Lesson has clear
## h2 headings (typically: Overview, Quick start, Core concepts, Exercises, Downloads, Summary, References)
- Content before the first
h2 (e.g. an opening <Figure>) is intentional — it stays unwrapped at article level
Content Completeness Checklist (matches scaffolding-rules.md)
Hands-on (F1) lessons must have:
Conceptual (F2) lessons must have:
Level 4: Astro Build + Render
Goal: Verify the lesson builds, renders, and is reachable.
Step 4.1 — Full build
npm run build
Look for:
- Zero MDX compilation errors
- Zero broken
<Figure src=…> paths (npm run check fails the build if a /lesson-media/… file is missing from public/)
- TypeScript strict passes (
@astrojs/check runs as part of build)
- Output written to
dist/lessons/<slug>/index.html
Step 4.2 — Dev server render
npm run dev
Open http://localhost:4321/lessons/<slug> and verify:
- Page loads with no console errors
- All figures display (right-click → "open in new tab" any that look broken)
- All
<Dropdown> blocks expand
- All
<CodeBlock> blocks render with the dual-theme Shiki highlighting
- The lesson-section side-rail (manuscript-margin gloss) tracks each
<h2> section
- The stage tracker shows the right module window (driven by
module: frontmatter)
prev / next navigation links resolve to existing lessons
Step 4.3 — Lighthouse / accessibility quick check (optional)
In Chrome DevTools, run Lighthouse on the rendered page. Watch for missing alt text on images — every <Figure> should have a meaningful alt.
Level 5: Quality Audit
Goal: Comprehensive review of content quality.
Pedagogical Quality Checklist (from CLAUDE.md)
Code Quality Checklist (for downloadable .py files)
AI-pattern check
Before final approval, run the ai-revision skill against the MDX file. Aim for overall risk LOW or MINIMAL.
Success Criteria
A lesson is ready to ship (i.e. ready to receive its lessonSlug in src/data/curriculum/subtopics.ts) when:
- ✅ Source Python scripts execute cleanly (Level 1 — for ported lessons)
- ✅ Assets are copied and every MDX reference resolves (Level 2)
- ✅ MDX is schema-valid and uses components correctly (Level 3)
- ✅
npm run build succeeds with no errors or asset warnings (Level 4)
- ✅ Dev-server render passes visual + interaction checks (Level 4)
- ✅ Content meets pedagogical and AI-pattern quality bars (Level 5)
Only then should you update src/data/curriculum/subtopics.ts to add lessonSlug for the leaf, and src/data/curriculum/modules.ts to update firstLesson if this is the module's first ported lesson.
Use the lesson-port skill for the porting workflow itself and ai-revision for the prose quality pass. This skill is the gate that ensures everything fits together before going live.