Skip to content

feat(course): add Final Analytics Epilogue - #72

Merged
michalmaj merged 2 commits into
mainfrom
feature/final-analytics-epilogue
Oct 2, 2026
Merged

michalmaj merged 2 commits into
mainfrom
feature/final-analytics-epilogue

Conversation

@michalmaj

Copy link
Copy Markdown
Owner

Summary

Implements the last integration piece of the NumPy/Pandas plan: a mandatory Final Analytics Epilogue after Level 7 (not an eighth level) that closes the "is the game balanced?" question Level 1 opened. Student uses NumPy a third time on a deep-dive battle log, and Pandas a third time on a multi-run tournament history — both generated by really running Level 7 Project 03's BattleService.

Levels 1-7 and the Data Recall Checkpoint are untouched (git diff --stat against the merge base is empty for all of them).

Key findings from verifying the real L7 contract

  • rpg.domain/rpg.services/rpg.repositories in level_7.../projects/03_concurrent_tournament_runner/ are fully complete and importable (only the API router layer has student TODOs) — used directly, no reimplementation.
  • BattleService.simulate() calls the stdlib random module's global functions (random.randint(...)), not an injected RNG — confirmed empirically that random.seed(n) before a sequence of calls makes it exactly reproducible with zero changes to frozen code.
  • Structural finding: given the frozen hero/monster stat table, every one of the 9 class×monster matchups is deterministically 100% or 0% (margins are too wide for randint(1,6) noise to ever flip an outcome — confirmed via both margin analysis and 150-trial-per-matchup empirical testing with zero flips). This makes per-class/per-monster win rates seed-invariant. The variant fixture therefore uses a genuinely different (but equally real, still fully simulated) tournament run-allocation — not a different seed alone — to produce different win_rate_by_class values and a different most_balanced_class answer. Full details and honest reporting of which conclusions are structurally invariant (hardest_monster, rank_monsters, unfavorable_matchups) vs. which genuinely change are in the task's final report.

What's added

  • final_analytics_epilogue/{README.md, task.py, check.py, data/*.{json,csv}, scripts/generate_fixtures.py}
  • 8 functions: 3 NumPy (load_battle_arrays, deep_dive_stats, battle_matrix_summary), 5 Pandas (load_tournament_history, win_rate_by_class, rank_monsters, unfavorable_matchups, balance_conclusions), 1 synthesis (build_final_report)
  • Dual-fixture-pair behavioral checker (ground truth via stdlib json/csv/statistics/math only) plus technique gates: AST-based for NumPy reductions/boolean-mask-work/2D-axis-construction (percentile/quantile via runtime spy, following the Data Recall Checkpoint precedent) and for pandas groupby across the three grouping functions.
  • generate_fixtures.py is an author-only provenance tool; verified byte-for-byte reproducible across two independent clean regenerations.
  • Course-flow integration: root README, COURSE_MAP.md, tools/course_status.py (new mandatory checkpoint tracked via the existing print_checkpoint() helper — course no longer reports "complete" until the epilogue is also done), tools/author_check.py (new check_epilogue() + doc-coverage registration).

Test plan

  • Scaffold → FAIL
  • Reference solution → PASS (both fixture pairs)
  • Alternative-valid Variant B (np.asarray/np.quantile/np.count_nonzero/np.stack/.query/named .agg/different helper names) → PASS
  • Fake A (hardcoded everything) → PASS primary, FAIL variant
  • Fake B (ceremonial NumPy arrays, stats via plain Python) → FAIL (all gaps reported)
  • Fake C (only percentile real NumPy) → FAIL
  • Fake D (real 2D matrix, manual row loop instead of axis) → FAIL
  • Fake E (DataFrame real, groupby replaced by .unique() loop) → FAIL technique gate specifically (isolated from tie-break order)
  • Fake F (only half the rows analyzed) → FAIL on values
  • Fake G (hardcoded conclusions) → PASS primary, FAIL variant
  • Fake H (build_final_report ignores input, returns primary's answer) → PASS primary, FAIL variant
  • tools/author_check.py → 750 checks passed, 0 errors
  • tools/course_status.py → epilogue tracked, "course complete" gated correctly (verified via temporary .progress simulation, cleaned up after)
  • Data Recall Checkpoint checker still runs correctly (smoke test)
  • Levels 1-7 and Data Recall Checkpoint untouched (git diff --stat against merge base empty)
  • Fixture generator: two independent clean regenerations produce byte-for-byte identical output across all 4 files
  • Scaffold restored byte-for-byte after every test run; no leftover .progress/cache/temp generator output in the working tree

🤖 Generated with Claude Code

michalmaj and others added 2 commits October 2, 2026 15:37
Mandatory epilogue after Level 7 closing the "is the game balanced?"
question Level 1 opened: NumPy on a deep-dive battle log, Pandas on a
multi-run tournament history, both generated by really running Level 7
Project 03's BattleService (no combat-rule reimplementation) — verified
byte-for-byte reproducible across clean regenerations.

Checker reuses the Data Recall Checkpoint's dual-fixture, independent-
ground-truth pattern, extended with technique gates for NumPy reductions/
percentile-or-quantile/boolean-mask-work/2D-axis-aggregation and for
pandas groupby across the three grouping functions — each accepting
multiple equivalent idioms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Registers the Final Analytics Epilogue as the mandatory last step after
Level 7: root README and COURSE_MAP.md document it, author_check.py
verifies its structure/fixtures/doc-coverage, and course_status.py tracks
it with the same print_checkpoint() mechanism as the Data Recall
Checkpoint — "course complete" no longer shows until the epilogue is
also done. Levels 1-7 and the Data Recall Checkpoint are untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@michalmaj
michalmaj merged commit 5e96d4e into main Oct 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant