---
quick_id: 260726-824
type: quick
created: 2026-07-26
requirements: [DISC-01, DISC-03]
files_modified:
  - src/lifx/network/discovery.py
  - tests/test_network/test_discovery_rebroadcast.py
autonomous: true
must_haves:
  truths:
    - "Time the consumer spends between receiving a yielded response and resuming the generator does not count against the discovery idle window"
    - "The pre-yield mark_response() is retained, so a duplicate flood still resets the idle timer before the dedup check (DISC-02, Pitfall 1 / D-04)"
    - "Streaming semantics are unchanged: responses are still yielded one at a time as they arrive, never buffered until the window closes"
    - "The overall timeout still bounds the sweep — a slow consumer cannot extend discovery indefinitely"
  artifacts:
    - tests/test_network/test_discovery_rebroadcast.py::test_consumer_time_does_not_consume_idle_window
---

<objective>
`api.discover()` awaits `create_device()` inside the discovery loop
(`src/lifx/api.py:792`). `create_device()` issues Phase 3 requests carrying a 16 s wall
deadline, while the discovery idle window is ~4 s. Because the idle timer is reset only
*before* a response is yielded, every second the consumer spends counts against that
window: one device that answers `GetService` and then stops responding can hold the
generator long enough for `deadline.idle_expired` to fire before queued responses from
later re-broadcasts are read, silently truncating the sweep.

Found by the v1.1 milestone audit's integration check; degrades DISC-03 on exactly the
unhealthy networks the requirement exists for.
</objective>

<approach>
Operator-selected: mark the response **after** the yield returns.

`_discover_with_packet()` already calls `deadline.mark_response()` before the dedup check
— that call must stay, because a duplicate flood has to reset the idle timer even for
serials that are never yielded. Add a second `mark_response()` immediately after
`yield discovery_resp` returns, i.e. when the consumer hands control back.

Rejected alternatives: buffering serials and constructing devices after the generator
completes (destroys streaming — nothing arrives until the full window elapses), and
raising the idle multiplier (papers over the interaction instead of fixing it).

The overall deadline is untouched, so a pathologically slow consumer still cannot run
discovery forever.
</approach>

<tasks>
1. Add the post-yield `deadline.mark_response()` in `_discover_with_packet()` and correct
   the docstring Note, which currently documents the old behaviour and tells callers to
   raise `idle_timeout_multiplier` to compensate.
2. Add a regression test proving a consumer slower than the idle window still receives a
   response that arrives after it resumes.
</tasks>

<verification>
- `uv run pytest tests/test_network/ -q` green
- `uv run --frozen pytest` green (full suite)
- `uv run ruff format --check . && uv run ruff check .` clean
- `uv run pyright` clean
</verification>

<output>
Create `.planning/quick/260726-824-fix-discover-idle-window-consumer-time/260726-824-SUMMARY.md` when done
</output>
