Nobody has started this yet — be first.
Business impact
gateway_circuit_breaker_state is the numeric metric an alerting rule or dashboard would graph to know when an upstream's breaker trips (its own doc comment says "0=closed, 1=open, 2=half_open"). Right now open and half_open are swapped in the lookup table that feeds this gauge -- so a dashboard built against the documented mapping shows an upstream as merely probing recovery (2, half-open) at the exact moment it is fully open and rejecting all traffic, and shows it as fully open (1) during the brief, mostly-harmless half-open probing window. Anyone paging off this metric with "alert if value == 1" would get paged for the wrong condition, or miss the real outage.
Problem
GET /admin/breakers (string-based, reading BreakerState values directly) correctly reports "open" for an open breaker. /metrics (numeric, going through set_breaker_state_metric) reports 2 for that same breaker at the same moment -- which the gauge's own help text says means half-open.
Current behavior
_BREAKER_STATE_VALUE maps "open" to 2 and "half_open" to 1 -- the two values are swapped relative to the gauge's own documented mapping (0=closed, 1=open, 2=half_open) three lines above it.
Expected behavior
The numeric value /metrics reports for a given upstream always agrees with what GET /admin/breakers reports for that same upstream, using the mapping documented in gateway_circuit_breaker_state's help text: 0=closed, 1=open, 2=half_open.
Steps to reproduce
Why this matters
This is a two-systems-disagree-about-one-fact bug: the string-based snapshot (BreakerRegistry.snapshot()) and the numeric metric (set_breaker_state_metric) are two independent representations of the exact same underlying BreakerState, fed by two independent lookup tables that are supposed to agree and do not. Nothing in either code path would ever notice the mismatch on its own -- only comparing the two against each other (or against the documented mapping) surfaces it.
Suggested approach
Compare _BREAKER_STATE_VALUE in app/metrics.py against the numbers documented in circuit_breaker_state's own Gauge(...) help text three lines above it.
Acceptance criteria
Verification
pytest practice_tickets/tests/test_ticket_10_metrics_breaker_state_swapped.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/metrics-breaker-state-swappedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/metrics-breaker-state-swappedSubmit 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:8080fast_echo/echo/.../large/{size_mb}slow_upstream/delay/{s}/flaky/always-downroutes.yamlcurl localhost:8080/healthzcurl localhost:8080/readyz/admin/*Authorization: Bearer <GATEWAY_ADMIN_TOKEN>You do not need Docker running at all to work the tickets — the test suite fakes Redis with fakeredis (plus lupa for real Lua-script support), so everything runs against a plain virtualenv:
python3 -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
.venv/bin/pytest practice_tickets/tests/test_ticket_09_breaker_threshold_off_by_one.py -v # a single ticket
./practice_tickets/run_tickets.sh # all 15, clean pass/fail summary
./practice_tickets/run_tickets.sh 06 09 15 # just a few, by number
All 15 tests fail at the start; as you fix each ticket in app/, its test (and only its test) should flip to passing. .venv/bin/pytest tests/ runs the project's own main suite — as of writing it shows 8 pre-existing failures caused by ticket bugs 02, 04, 06, and 09; fixing those tickets fixes those failures too, not a separate task.
Level 1
Fix a bug
Read existing behaviour, correct it.