Repository navigation
feat(course): add mandatory Data Recall Checkpoint (L3→L4) - #69
Merged
Merged
Conversation
New mandatory, standalone checkpoint between Level 3 and Level 4 — 30-60 minutes, no new concepts, reactivating NumPy/Pandas from Level 1 on the real combat log schema Level 3 Mission 06 introduced (CombatLogRow: battle_id, turn, hero_name, hero_class, monster, action, damage_dealt, damage_taken, hero_hp, monster_hp, result). Four tasks: load_combat_log (real pd.DataFrame), win_rate_by_class (terminal rows grouped by hero_class — groupby is an explicit learning objective here, not just a means to a number), damage_stats (NumPy mean/std/p75/boolean-mask over attack-only damage, excluding potion-turn zeros which aren't weak hits), and rank_monsters_by_difficulty (same win-rate idea, grouped by monster, sorted). check.py runs every function against two fixtures and compares values against ground truth computed independently with stdlib csv + plain Python (never by re-running the student's own pandas/numpy code). The variant fixture has a genuinely different win-rate ranking and damage distribution, so hardcoded answers that happen to match the primary fixture fail on the variant. Because groupby and NumPy array work are explicit learning objectives (not just "get the right number"), two functions also get a light technique gate: an AST check that groupby is actually called inside win_rate_by_class, and a monkeypatch spy confirming np.percentile is actually called inside damage_stats — neither cares about variable names, chaining style, or lambda usage. Both fixtures are generated from real, Pydantic-validated CombatLogRow instances (imported directly from the frozen Level 3 Mission 06 task.py), not hand-typed CSV rows — 42 battles each, 3 hero classes, 4 monsters, both wins and losses, both attack and potion turns. Verified: reference solution and an alternative-valid solution (different chaining, .query/.agg/np.asarray/np.greater/np.count_nonzero style) both PASS; four fakes (hardcoded answers incl. one that exactly matches the primary fixture, groupby avoided via a per-class loop, np.array created ceremonially with real work done in plain Python, analysis of only the first half of the dataset) all FAIL at the gate they're meant to trip; scaffold FAILs cleanly; deterministic across 3 repeated runs.
- COURSE_MAP.md / README.md: document the new mandatory checkpoint between Level 3 and Level 4. No link to a Final Analytics Epilogue — that doesn't exist yet; README only notes in prose that data skills get tied together again later, after Level 7. - tools/course_status.py: new print_checkpoint() helper (the checkpoint is flat — one README/task.py/check.py, no missions/projects subdirectory — so it doesn't fit print_level()'s path convention) wired in between Level 3 and Level 4. Reuses the existing "projects" progress bucket so completion is tracked the same way other mandatory units are; existing levels' print_level() calls and path semantics are untouched. - tools/author_check.py: new check_data_checkpoint() verifies the checkpoint's required files and check.py hygiene, and it's added to the existing COURSE_MAP.md/README.md documentation-coverage sweep. Verified end-to-end: course_status.py correctly shows the checkpoint between Level 3 and Level 4, correctly resolves "next up" to it once L1-L3 are complete, and correctly flips to [✓] after a real passing check.py run (confirmed via a temporary reference solution, then reverted to scaffold). author_check.py passes with the new checks included (737 checks, 0 errors). No changes to any level_1...level_7 file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First element of the final NumPy/Pandas integration: a mandatory, standalone Data Recall Checkpoint placed between Level 3 and Level 4. Levels 1–7 remain completely untouched — no existing mission, project, or checker was modified.
load_combat_log,win_rate_by_class(groupby is an explicit learning objective),damage_stats(NumPy mean/std/p75/boolean mask, attack-only),rank_monsters_by_difficulty.csv— never by re-running the student's pandas/numpy code. Two light technique gates (AST check forgroupby, monkeypatch spy fornp.percentile) catch the "library imported ceremonially, real work done in plain Python" class of fake, since those two APIs are explicit learning objectives here, not just a means to a number.CombatLogRowinstances imported directly from the frozen Level 3 Mission 06task.py— not hand-typed numbers.COURSE_MAP.md/README.mddocument it between Level 3 and Level 4;tools/course_status.pytracks its completion the same way as other mandatory units (newprint_checkpoint()helper, since it's a flat unit with no missions/projects subdirectory);tools/author_check.pyverifies its required files and is part of the existing doc-coverage sweep.Explicitly not in this PR
The Final Analytics Epilogue (after Level 7) — separate, future batch. No dead links added for it; README only mentions in prose that data skills are tied together again later.
Test plan
load_combat_log is not implemented yet).query/.agg/named aggregation/np.asarray/np.greater/np.count_nonzero) → PASSgroupbyavoided via a per-class Python loop (numerically correct) → FAIL at the technique gatenp.arraycreated ceremonially, real stats computed in plain Python (values coincidentally correct) → FAIL at thenp.percentilespytools/author_check.py→ 737 checks passed, 0 errorstools/course_status.py→ checkpoint shows between L3/L4, "next up" resolves correctly, flips to[✓]after a real passing rungit diffconfirms zero changes under anylevel_1...level_7directory__pycache__, no leftover.progress, no temporary fixture-generator script committed; working tree clean except the intended patch🤖 Generated with Claude Code