Nobody has started this yet — be first.
Business impact
BACKUP_CODES_COUNT (10) is the number of recovery codes the product promises a user when they enable 2FA -- likely displayed in the UI as "codes 1-10." Only 9 are actually created. If a user methodically uses codes in order and treats "#10" as still available, they will hit a dead end at the worst possible time: locked out of their account, out of a working recovery code, forced into a support-assisted account-recovery flow.
Problem
generate_backup_codes(user_id, count) always produces count - 1 codes, silently one short of what was requested, so POST /auth/2fa/confirm returns 9 codes when BACKUP_CODES_COUNT is 10.
Current behavior
The function's loop is for _ in range(count - 1): instead of range(count):, even though its own docstring says it "generates count fresh plaintext codes."
Expected behavior
POST /auth/2fa/confirm returns exactly BACKUP_CODES_COUNT backup codes (10 by default), all independently valid and one-time-use.
Steps to reproduce
Why this matters
A range(count - 1) where the intent was range(count) is the most common shape of off-by-one bug there is -- it is worth building the habit of reading a loop bound against its stated purpose rather than trusting that a function does what its docstring claims.
Suggested approach
Compare the loop bound in generate_backup_codes() against its own docstring's claim, and against BACKUP_CODES_COUNT's value as read from config in routes.py::confirm_2fa().
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_02.py -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
Sign in to create it automatically, or do it yourself:
$git checkout -b fix/backup-codes-countFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/backup-codes-countSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign inhttp://localhost:5000make seedpyotpmake docker-prod-upYou do not need Docker running at all to work the tickets -- the test suite uses an in-memory SQLite database (via StaticPool, an isolated DB per test function) and fakeredis (TestingConfig.USE_FAKE_REDIS), so everything runs against a plain virtualenv:
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
pytest practice_tickets/tests/test_ticket_01.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
All 15 tests fail at the start; as you fix each ticket in app/, its test (and only its test) should flip to passing. make test (pytest -q) runs the project's own main suite -- as of writing it shows 9 pre-existing failures caused by ticket bugs 02, 03, 07, 11, and 15; fixing those tickets fixes those failures too, not a separate task. Do not look at git diff / version control history to find the bugs if this repo is ever put under source control -- the point is to find them the way you would find a real bug: from a failing test and a description of broken behavior, not a diff.
Level 1
Fix a bug
Read existing behaviour, correct it.