Module 13 deliberately teaches stdlib unittest, runs python -m unittest, and justifies the choice with two promises: the test file drops into Module 14 CI "without a pip install step first," and CI runs "this exact python -m unittest command." Module 14 instead runs pip install pytest ruff and pytest -q (repeated in M16); its lab test_tasks.py is plain-function pytest style; and no bridge explains that pytest auto-discovers unittest.TestCase tests. M5 also forward-references pytest before testing is introduced. So pytest is the de-facto course runner everywhere except the module that teaches a runner, and M13's headline rationale is falsified by the next module.
Evidence
M13: "We use unittest here so … you can drop into CI in Module 14 without a pip install step first" and "runs this exact python -m unittest command" (~line 164).
M14: pip install pytest ruff / pytest -q (README ~lines 123/127; lab/ci-starter.yml ~lines 38/46). lab/ci-starter.yml comment also misattributes pytest/ruff to "Module 13". modules/14-.../lab/test_tasks.py is plain-function pytest style.
M5 ~line 179: "Optionally pytest (pip install pytest)".
Why it matters
A falsified stated rationale on the load-bearing M13→M14 chain, against a non-beginner audience that will notice — breaks the honesty promise and the dependency chain.
Proposed change
Pick one runner and align the chain. Cleanest (keep pytest):
Add a bridge sentence in M13/M14: "pytest is a drop-in runner that discovers your unittest.TestCase tests; CI installs it."
Retract M13's "without a pip install step first" and "this exact python -m unittest command" claims.
Make M5's example command match (don't forward-reference pytest as the runner before testing is introduced, or clearly mark it optional/forward-referenced).
Fix the ci-starter.yml comment that attributes pytest/ruff to Module 13, and the test_tasks.py docstring claiming it is "the kind of suite Module 13 has you write".
Equally valid alternative: standardize on unittest and have M14 run python -m unittest (no pip install) — but then make M14's lab file and M16 consistent.
Acceptance criteria
One runner is consistent from M13 through M16, or a correct bridge explains pytest discovering unittest tests.
M13 no longer claims "no pip install"/"exact unittest" if CI uses pytest.
ci-starter.yml comment and test_tasks.py docstring are accurate.
Filed from an adversarial multi-agent course review (217 raw findings → 54 adversarially-verified survivors). Scoped for manual review; intentionally not auto-assigned to an agent.
## Problem
Module 13 deliberately teaches stdlib `unittest`, runs `python -m unittest`, and justifies the choice with two promises: the test file drops into Module 14 CI "without a pip install step first," and CI runs "this exact `python -m unittest` command." Module 14 instead runs `pip install pytest ruff` and `pytest -q` (repeated in M16); its lab `test_tasks.py` is plain-function pytest style; and no bridge explains that pytest auto-discovers `unittest.TestCase` tests. M5 also forward-references pytest before testing is introduced. So pytest is the de-facto course runner everywhere except the module that teaches a runner, and M13's headline rationale is falsified by the next module.
## Evidence
M13: "We use `unittest` here so … you can drop into CI in Module 14 without a pip install step first" and "runs this exact `python -m unittest` command" (~line 164).
M14: `pip install pytest ruff` / `pytest -q` (README ~lines 123/127; `lab/ci-starter.yml` ~lines 38/46). `lab/ci-starter.yml` comment also misattributes pytest/ruff to "Module 13". `modules/14-.../lab/test_tasks.py` is plain-function pytest style.
M5 ~line 179: "Optionally pytest (`pip install pytest`)".
## Why it matters
A falsified stated rationale on the load-bearing M13→M14 chain, against a non-beginner audience that will notice — breaks the honesty promise and the dependency chain.
## Proposed change
Pick one runner and align the chain. Cleanest (keep pytest):
1. Add a bridge sentence in M13/M14: "pytest is a drop-in runner that discovers your `unittest.TestCase` tests; CI installs it."
2. Retract M13's "without a pip install step first" and "this exact `python -m unittest` command" claims.
3. Make M5's example command match (don't forward-reference pytest as the runner before testing is introduced, or clearly mark it optional/forward-referenced).
4. Fix the `ci-starter.yml` comment that attributes pytest/ruff to Module 13, and the `test_tasks.py` docstring claiming it is "the kind of suite Module 13 has you write".
Equally valid alternative: standardize on `unittest` and have M14 run `python -m unittest` (no pip install) — but then make M14's lab file and M16 consistent.
## Acceptance criteria
- [ ] One runner is consistent from M13 through M16, or a correct bridge explains pytest discovering unittest tests.
- [ ] M13 no longer claims "no pip install"/"exact unittest" if CI uses pytest.
- [ ] `ci-starter.yml` comment and `test_tasks.py` docstring are accurate.
## Affected files
- `modules/13-testing-in-the-ai-era/README.md`, `modules/14-continuous-integration/README.md`, `modules/14-.../lab/ci-starter.yml`, `modules/14-.../lab/test_tasks.py`, `modules/05-commit-the-ai-config/README.md`, `modules/16-containers-and-reproducible-environments/README.md`
## References
Source finding F8 (realVotes 3/3).
---
*Filed from an adversarial multi-agent course review (217 raw findings → 54 adversarially-verified survivors). Scoped for manual review; intentionally not auto-assigned to an agent.*
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Module 13 deliberately teaches stdlib
unittest, runspython -m unittest, and justifies the choice with two promises: the test file drops into Module 14 CI "without a pip install step first," and CI runs "this exactpython -m unittestcommand." Module 14 instead runspip install pytest ruffandpytest -q(repeated in M16); its labtest_tasks.pyis plain-function pytest style; and no bridge explains that pytest auto-discoversunittest.TestCasetests. M5 also forward-references pytest before testing is introduced. So pytest is the de-facto course runner everywhere except the module that teaches a runner, and M13's headline rationale is falsified by the next module.Evidence
M13: "We use
unittesthere so … you can drop into CI in Module 14 without a pip install step first" and "runs this exactpython -m unittestcommand" (~line 164).M14:
pip install pytest ruff/pytest -q(README ~lines 123/127;lab/ci-starter.yml~lines 38/46).lab/ci-starter.ymlcomment also misattributes pytest/ruff to "Module 13".modules/14-.../lab/test_tasks.pyis plain-function pytest style.M5 ~line 179: "Optionally pytest (
pip install pytest)".Why it matters
A falsified stated rationale on the load-bearing M13→M14 chain, against a non-beginner audience that will notice — breaks the honesty promise and the dependency chain.
Proposed change
Pick one runner and align the chain. Cleanest (keep pytest):
unittest.TestCasetests; CI installs it."python -m unittestcommand" claims.ci-starter.ymlcomment that attributes pytest/ruff to Module 13, and thetest_tasks.pydocstring claiming it is "the kind of suite Module 13 has you write".Equally valid alternative: standardize on
unittestand have M14 runpython -m unittest(no pip install) — but then make M14's lab file and M16 consistent.Acceptance criteria
ci-starter.ymlcomment andtest_tasks.pydocstring are accurate.Affected files
modules/13-testing-in-the-ai-era/README.md,modules/14-continuous-integration/README.md,modules/14-.../lab/ci-starter.yml,modules/14-.../lab/test_tasks.py,modules/05-commit-the-ai-config/README.md,modules/16-containers-and-reproducible-environments/README.mdReferences
Source finding F8 (realVotes 3/3).
Filed from an adversarial multi-agent course review (217 raw findings → 54 adversarially-verified survivors). Scoped for manual review; intentionally not auto-assigned to an agent.