Skip to content

fix(level7): final quality batch — meaningful tests, Ruff gate, hygiene - #68

Merged
michalmaj merged 2 commits into
mainfrom
feature/level7-final-quality-fixes
Oct 1, 2026
Merged

michalmaj merged 2 commits into
mainfrom
feature/level7-final-quality-fixes

Conversation

@michalmaj

Copy link
Copy Markdown
Owner

Summary

Second and final targeted-rework batch for Level 7, scoped to exactly 6 items from the full-level audit. No changes to M02/M03/M04/M06 checker/M07 checker-or-README/P01/P02/ProcessPoolTournamentWorker/the P03 CLI contract from Batch 1/seeding/HTTP 425/any new concurrency concepts.

  • M08 check.py: replaced the structural-only check (SyncWorker imported, no time.sleep, pytest passes) with a 6-mutant behavioral gate against InMemoryJobRepository/SyncWorker — one mutant per behavior in the README's test table.
  • M05 check.py: the API integration check now verifies result.total_battles matches the request exactly and hero_wins + monster_wins sums correctly — not just that status is "completed".
  • M01 check.py: added a spy wrapping (not replacing) _svc.simulate_tournament to confirm time_tournament() actually calls it with the real battle count, instead of just shaping a plausible-looking dict.
  • P03 check.py: added a Gate 12 running ruff check api/ tests/ — the two directories that actually contain student-written code in this boss fight.
  • P03: added data/jobs/.gitignore (*.json / !.gitkeep) after confirming empirically that real CLI usage creates job files there.
  • M06 README.md: reworded the slightly-off "multiple threads on one CPU core don't run in parallel because the GIL..." sentence to drop the redundant "on one CPU core" framing, without adding new material.

Test plan

  • M08: Variant A (reference-like) → PASS; Variant B (different fixture/names/order/assertion style) → PASS; 6× assert True → FAIL; 1 real + 5 tautologies → FAIL; mutation gate deterministic across 3 runs with byte-identical file restores
  • M05: correct SyncWorker lifecycle + real result → PASS; fake completed status + {"fake": True} result → FAIL; repository/JsonJobRepository/SyncWorker unit tests unaffected
  • M01: correct implementation → PASS; fake never calling the service → FAIL; fake calling the service with a hardcoded battle count (ignoring the real n) → FAIL
  • P03 Ruff: correct final project → PASS; unused import in student-owned api/routers/tournaments.py → FAIL; unrelated violation injected into provided jobs/jobs.py (out of scope) → does not block
  • P03 hygiene: real cli.py start run creates a job JSON file in data/jobs/; git status --short stays clean
  • All 8 missions + P01/P02/P03 scaffolds → correctly FAIL
  • tools/author_check.py → 727 checks passed, 0 errors
  • tools/course_status.py → runs clean
  • No zombie processes, no hanging threads, no __pycache__, no .pytest_cache, no unintended job files, working tree clean except the intended patch

🤖 Generated with Claude Code

- M08 check.py: the checker only confirmed SyncWorker was imported, no
  time.sleep() was used, and pytest passed — a suite of six
  `assert True` tests satisfied all three. Added a mutation gate with six
  single-behavior mutants against task/jobs.py's InMemoryJobRepository
  and task/workers.py's SyncWorker (new job not pending, submit never
  completes, exception swallowed, result not stored, two jobs sharing
  state, unknown job fabricated instead of None) — one per behavior the
  README's test table requires. Verified against two structurally
  different correct suites (different fixture layout, names, assertion
  style) and both the all-tautological and partial-tautological fakes;
  deterministic across 3 repeated runs with byte-identical restores.
- M05 check.py: the API integration check only asserted job status was
  "completed", never inspected the result — a worker that marks the job
  completed but writes `{"fake": True}` passed. Added a check that
  result.total_battles matches the request's battle count exactly
  (deterministic) and hero_wins + monster_wins sums to the same count
  (not exact values, since individual battle outcomes are random).
- M01 check.py: time_tournament() could return a result shaped correctly
  without ever calling the service. Added a spy that wraps (not
  replaces) _svc.simulate_tournament, confirming it was actually called
  and with the requested battle count passed through — not hardcoded.
- P03 check.py: added a Gate 12 running `ruff check api/ tests/` — the
  two directories that actually contain student-written code in this
  boss fight (main.py/dependencies.py/schemas.py/jobs/rpg are pre-wired
  and untouched by the student). Scoped there after confirming the
  correct reference solution is clean under that scope. A real lint
  violation in student-owned code now fails the boss fight; an
  out-of-scope violation (e.g. in jobs/jobs.py) does not. README gets a
  one-line closing note pointing at the same command — no new lesson,
  no Mypy/Pyright/coverage/CI.
- P03: added data/jobs/.gitignore (*.json, keep .gitkeep) — confirmed
  empirically that a real `cli.py start` run creates a job file there;
  with the ignore rule in place the file still gets created but
  `git status` stays clean, matching the pattern already used for
  session-file directories elsewhere in the course.
- M06 README: reworded "multiple threads on one CPU core don't run in
  parallel because the GIL..." — the "on one CPU core" framing was
  redundant/confusing (the GIL constraint isn't about core count). Now:
  "for CPU-bound pure-Python work, the GIL prevents multiple threads in
  the same process from running Python bytecode in parallel." Same
  meaning, no new material (free-threading/C-extension nuance) added.
@michalmaj
michalmaj merged commit 44a68c0 into main Oct 1, 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