test_batch_is_complete
test_R14_batch_completion_lifecycle.py · failed in 90% of captured runs
Forcing read_batch to start before record_item 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: read_batch#0 starts before record_item#2 in the failing run, and after it when the test passes.
record_item 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 |
|---|---|---|---|
| read_batch#0 → record_item#2the assertion depends on this | 1.00 | fails 100% | reproduces the failure every time it is forced |
| read_batch#0 → record_item#1the assertion depends on this | 0.94 | — | not forced (an earlier candidate already decided it) |
| read_batch#0 → record_item#0the assertion depends on this | 0.58 | — | not forced (an earlier candidate already decided it) |
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 (not confirmed)
Adversarial schedules
not attempted for this incident, and so not claimed
Residual flake check
9 of 20 ordinary runs stable, against 18 failures in the same number of runs before the fix
- Measured overhead
- -0.017 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 read_batch#0 -> record_item#2
Proposed change
Nothing is merged automatically. This is a diff for a human to review.
--- a/benchmark/cases/R14_batch_completion_lifecycle/test_R14_batch_completion_lifecycle.py+++ b/benchmark/cases/R14_batch_completion_lifecycle/test_R14_batch_completion_lifecycle.py@@ -17,6 +17,18 @@from benchmark.support import io_latencyfrom chronotrace.capture.instrument import assertion, operation+from chronotrace.schedule.harness import ScheduleHarness, force_order++_chronotrace_gate_batch_items = asyncio.Event()+++@pytest.fixture(autouse=True)+def _chronotrace_reset_batch_items():+ """Provide a fresh synchronization gate for each test."""+ global _chronotrace_gate_batch_items+ _chronotrace_gate_batch_items = asyncio.Event()+ yield+BATCH: list[str] = []EXPECTED = ["alpha", "beta", "gamma"]@@ -26,11 +38,13 @@async def record_item(item: str) -> None:"""Publish one item into the batch."""BATCH.append(item)+ _chronotrace_gate_batch_items.set()@operation("read_batch", resource="batch.items", access="read")async def read_batch() -> list[str]:"""Read everything published so far."""+ await _chronotrace_gate_batch_items.wait()return list(BATCH)@@ -50,3 +64,19 @@with assertion("batch.items"):assert observed == EXPECTEDawait handle+++@pytest.mark.asyncio+async def test_chronotrace_regression_782a134d() -> None:+ """Reproduce the interleaving that used to fail, deterministically.++ Generated by ChronoTrace for incident 782a134d. Before the repair this+ race appeared in roughly 90% 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 = ['read_batch#0', 'record_item#2']+ harness = ScheduleHarness(forced_order, timeout_s=5.0)+ with force_order(harness):+ await test_batch_is_complete()+ assert harness.reached == forced_order