Nobody has started this yet — be first.
Business impact
This single flipped function call breaks two guarantees the whole API is built around, at the same time. First, a wait above the server's cap is supposed to be capped at it -- with max() instead of min(), a caller asking for more than the cap gets exactly what they asked for, uncapped, so the entire proxy-safety mechanism does nothing. Second, a wait below the cap -- including 0, including omitting wait entirely -- gets silently forced up to the cap. wait being optional exists specifically so a plain status check never hangs; with this bug it always hangs, for up to max_wait_seconds. Any monitoring dashboard, health-check script, or simple client library polling the "naive" way silently turns into a long-poller itself, and a client library with a small connection pool making frequent "just check the status" calls would exhaust that pool under normal use.
Problem
max() raises any wait_seconds below the ceiling up to the ceiling, instead of leaving values under the ceiling alone and only clamping values above it.
Current behavior
get_job() computes wait_seconds = max(wait_seconds, settings.max_wait_seconds) -- max() instead of min() -- so any wait below the ceiling (including 0 or omitted) gets forced up to it, and any wait above the ceiling passes through uncapped.
Expected behavior
A wait above max_wait_seconds is capped down to it. A wait below max_wait_seconds -- including 0 or omitted -- is left alone.
Steps to reproduce
pytest practice_tickets/tests/test_ticket_07_wait_seconds_never_capped.py -vSettings(max_wait_seconds=10.0), submit a job with duration_seconds: 20, then GET /jobs/{id} with no wait param at all.Why this matters
min/max mixups are an easy typo to make and an easy one to miss on review, because both read as grammatically plausible: "clamp the wait to the max" sounds right whether you mean "cap it at the max" (min) or "raise it to the max" (max). The two only diverge in behavior for inputs on one specific side of the ceiling, which is exactly why casual testing (submit a job, poll it with a reasonable wait a few times, see it work) can miss this entirely -- it also fails two tests in the project's own tests/ suite, including the naive-vs-long-poll signature comparison, because this bug turns every plain, un-waited GET into an accidental long-poll too.
Suggested approach
Work out, from first principles, what each of min(requested, ceiling) and max(requested, ceiling) does at both ends of the range: a requested value below ceiling, and one above it. Compare that against what app/config.py's comments say both max_wait_seconds and default_wait_seconds are for.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_07_wait_seconds_never_capped.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/wait-seconds-never-cappedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/wait-seconds-never-cappedSubmit 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 inwait should return in milliseconds.http://localhost:8000localhost:6379curl localhost:8000/healthz{"status": "ok", "redis": true}Work the tickets in practice_tickets/tickets/ (ordered easy → hard); each names one dedicated pytest file in practice_tickets/tests/:
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
pytest practice_tickets/tests/test_ticket_01_completed_jobs_counted_as_failed.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
Each ticket test runs in its own pytest process with a 60s timeout, so one hung/crashed ticket can't take down the whole run or hide another ticket's result. Run pytest tests/ (the project's own suite, against fakeredis, hermetic and fast) after each fix to check for regressions -- the README documents exactly which fixes are expected to change that suite's results.
Level 1
Fix a bug
Read existing behaviour, correct it.