test_consumer_drains_produced_job
test_R06_queue_consumer_early.py · failed in 60% of captured runs
Forcing drain_queue to start before enqueue_job reproduced the failure on every attempt, so that ordering is a sufficient condition for the failure.
The two operations in `proven_inversion` name the same `resource`, and one has `access: 'write'` while the other has `access: 'read'`. The reader observed state the writer had not yet published.
Where the two runs diverge
The same test, twice, on a shared time axis. The outlined pair is the ordering that differs.
Outlined: drain_queue#0 starts before enqueue_job#0 in the failing run, and after it when the test passes.
enqueue_job never started in the failing run. The run flushed its spans normally, so that absence is evidence: the operation had not happened by the time the assertion read the state.
Evidence
Suspicion comes from comparing runs. The decision comes from forcing the ordering and seeing what happens.
| Ordering | Suspiciousness | When forced | Verdict |
|---|---|---|---|
| drain_queue#0 → enqueue_job#0the assertion depends on this | 1.00 | fails 100% | reproduces the failure every time it is forced |
One scheduling constraint is enough to reproduce this failure.
Policy gate
Every check the proposed patch had to pass before it was allowed to run.
All 15 checks passed. A patch runs only when every one of them does.
Refused shortcuts
- no sleep calls introduced
- no aliased sleep imports introduced
- no timeout marker added or inflated
- no retry or flaky decorator added
- no retry loop wrapped around the assertion
- no assertion removed or weakened
- no exception handler swallowing the failure
- no test skipped, xfailed or renamed out of collection
Required substance
- a real synchronization primitive was added
- the primitive is reachable from both the signal and the wait site
- the patch is not a no-op
Structural safety
- the proposed wait edge creates no wait-for cycle
- no production-scope file modified without opt-in
- no third-party or vendored file modified
- the patched module parses
Verification
What was established, and at which strength. A weaker check is never presented as proof.
Reproduced the exact interleaving on demand
before the fix it failed every time under the forced ordering; after the fix it passed every time under the identical ordering (confirmed)
Adversarial schedules
not attempted for this incident, and so not claimed
Residual flake check
20 of 20 ordinary runs stable, against 9 failures in the same number of runs before the fix
- Measured overhead
- +0.151 msno fixed delay introduced
- Isolation
- one process per run
- Reproduction seed
- random_seed_base 1729random_seed_sweep 1729..1733pythonhashseed 0python_version 3.12.13forced_order drain_queue#0 -> enqueue_job#0
- Regression guard (executed and confirmed)
- benchmark/cases/R06_queue_consumer_early/test_R06_queue_consumer_early.py::test_chronotrace_regression_dbe0093b
Proposed change
Nothing is merged automatically. This is a diff for a human to review.
--- a/benchmark/cases/R06_queue_consumer_early/test_R06_queue_consumer_early.py+++ b/benchmark/cases/R06_queue_consumer_early/test_R06_queue_consumer_early.py@@ -6,6 +6,18 @@from benchmark.support import io_latencyfrom chronotrace.capture.instrument import assertion, operation+from chronotrace.schedule.harness import ScheduleHarness, force_order++_chronotrace_gate_queue_items = asyncio.Event()+++@pytest.fixture(autouse=True)+def _chronotrace_reset_queue_items():+ """Provide a fresh synchronization gate for each test."""+ global _chronotrace_gate_queue_items+ _chronotrace_gate_queue_items = asyncio.Event()+ yield+QUEUE: list[str] = []@@ -14,11 +26,13 @@async def enqueue_job(job: str) -> None:"""Append a job to the work queue."""QUEUE.append(job)+ _chronotrace_gate_queue_items.set()@operation("drain_queue", resource="queue.items", access="read")async def drain_queue() -> list[str]:"""Take everything currently queued."""+ await _chronotrace_gate_queue_items.wait()taken = list(QUEUE)QUEUE.clear()return taken@@ -39,3 +53,19 @@with assertion("queue.items"):assert drained == ["job-1"]await task+++@pytest.mark.asyncio+async def test_chronotrace_regression_dbe0093b() -> None:+ """Reproduce the interleaving that used to fail, deterministically.++ Generated by ChronoTrace for incident dbe0093b. Before the repair this+ race appeared in roughly 60% of runs; this guard forces the+ exact ordering that caused it, so a regression fails here on every run+ rather than once in a while.+ """+ forced_order = ['drain_queue#0', 'enqueue_job#0']+ harness = ScheduleHarness(forced_order, timeout_s=5.0)+ with force_order(harness):+ await test_consumer_drains_produced_job()+ assert harness.reached == forced_order