Needs investigationNot verifiedno claim made

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.

The same test twice on a shared time axis. Each operation is anchored at the moment it started. In the failing run read_batch#0 starts before record_item#2, and record_item never ran at all.
Passing run5 operations in 2.42 ms
record_item
record_item
record_item
read_batch
assert
Failing run2 operations in 0.30 ms
read_batch
assert
record_item — never ran
0 ms1.21 ms2.42 ms

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.

OrderingSuspiciousnessWhen forcedVerdict
read_batch#0 → record_item#2the assertion depends on this1.00fails 100%reproduces the failure every time it is forced
read_batch#0 → record_item#1the assertion depends on this0.94—not forced (an earlier candidate already decided it)
read_batch#0 → record_item#0the assertion depends on this0.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_latency
from 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 == EXPECTED
await 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
← All incidents