Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ jobs:
python-version: "3.12"
cache: "pip"
cache-dependency-path: pyproject.toml
- run: pip install -e ".[dev]" "pytest-xdist>=3.6" "pytest-cov>=5.0"
- run: pip install -e ".[dev]" "pytest-xdist>=3.6" "pytest-cov>=5.0" "pytest-rerunfailures>=14.0,<16.0"
# Single Python leg for coverage — multi-version coverage
# reports don't add signal and double the runner time. 3.12
# is the modern floor for typing-only changes.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ name = "nullrun"
# by ``@protect`` were missing ``tokens``/``execution_id`` so
# the backend's SdkTrackRequest rejected them. See CHANGELOG.md
# for the full per-commit description.
version = "0.14.5"
version = "0.14.6"
# Kept under the 200-char preview threshold so the full line is visible
# without an "expand" click. Keywords are matched against likely search
# queries ("AI agent cost control", "LLM circuit breaker", etc.).
Expand Down
53 changes: 52 additions & 1 deletion src/nullrun/__version__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,56 @@
"""NullRun Platform SDK.

v3.31.5 / 0.14.6 (2026-08-01) — CI coverage-job flakefix +
actions.cooldown window-of-zero race.

Two CI-only fixes that surfaced as red matrix runs on shared
GitHub Actions runners after the 0.14.5 release:

1. ``.github/workflows/ci.yml:74`` — the ``coverage`` job install
line now pulls ``pytest-rerunfailures>=14.0,<16.0`` alongside
``pytest-cov>=5.0``. The marker
``@pytest.mark.rerunfailures(reruns=2)`` on
``tests/test_approval_timeout_field.py::TestApprovalTimeoutResolution
::test_env_fallback_when_server_value_is_zero`` (a thread-scheduling
race in the approval-wait fixture under ``-n auto`` on shared CI
runners — local sequential runs pass 15/15) was a silent no-op
on the coverage job, and the first race in the spawn-vs-release
window turned the run red even when the ``test`` (3.10/3.11/3.12)
matrix was fully green. The marker itself
(``reruns=2``, ``release_after_ms=200``) was already in place
from the Sprint 0 audit — the missing piece was the plugin on
the coverage leg. This release matches the install on
``ci.yml:41-45``.

2. ``tests/test_actions.py::TestPauseAction::test_is_paused_respects_cooldown``
closed a second pre-existing flake flagged in the 0.13.7
changelog. The test asserted ``is_paused(..., cooldown_seconds=0.0)``
returns ``False`` immediately after a ``PAUSE`` action — but the
underlying ``is_paused`` computes ``elapsed = time.time() - paused_at``
and returns ``True`` while ``elapsed > cooldown`` (strict greater
than). On any platform where ``time.time()`` rounds to the same
integer as ``paused_at`` within the test body — Windows, WSL1,
and the shared CI runner when the OS scheduler happens to round
down — ``elapsed == 0.0`` and the workflow stays "paused" forever,
failing the assertion. Pre-0.14.6 this was rare-flaky
(``1 in 1142`` per 0.13.7 changelog); on the 0.14.5 runner pool
it became ``5 in 5``. The test now sleeps ``0.01s`` between the
``PAUSE`` handle and the post-cooldown assertion to make the
``elapsed > 0.0`` check deterministic. No production behaviour
change: the only call site that uses ``cooldown_seconds=0.0`` is
this test, and ``ActionHandler.is_paused`` is an internal helper.

Tests:

* Full suite green on local ``pytest tests/`` after both fixes:
1417 passed, 7 skipped, 10 warnings.
* ``ruff check src/ tests/`` -- All checks passed.
* ``mypy src/`` -- Success: no issues found in 37 source files.

No public API change. No on-wire change. No SDK_MIN_VERSION bump.

--

v3.31.4 / 0.14.5 (2026-08-01) — MCP metadata and tool-argument
forwarding.

Expand Down Expand Up @@ -1048,5 +1099,5 @@

"""

__version__ = "0.14.5"
__version__ = "0.14.6"
__platform_version__ = "1.0.0"
10 changes: 9 additions & 1 deletion tests/test_actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,15 @@ def test_is_paused_respects_cooldown(self):
handler.handle(ActionType.PAUSE, "wf-cooldown", "Test")
# Within cooldown
assert handler.is_paused("wf-cooldown", cooldown_seconds=60.0)
# After cooldown
# After cooldown. ``time.sleep(0.01)`` before the post-cooldown
# check guarantees ``time.time() - paused_at > 0.0`` regardless
# of the platform's time.time() rounding; the pre-fix code used
# ``cooldown_seconds=0.0`` directly which was a race against the
# 1-second time.time() resolution on Windows / WSL1 and produced
# ``elapsed == 0.0`` -> ``elapsed > cooldown`` False -> the
# workflow stays "paused" forever. Tracked as the pre-existing
# flake in 0.13.7 changelog; closed here.
time.sleep(0.01)
assert not handler.is_paused("wf-cooldown", cooldown_seconds=0.0)


Expand Down
Loading
Loading