chore(release): 0.13.13 — Разрыв 1c SDK sync#75
Merged
Conversation
…c SDK sync)
Backend commit 0ad03b9 (Разрыв 1c, gate hot-path trigger) added
`approval_timeout_seconds: Option<i64>` and
`approval_expires_at: Option<String>` to the GateResponse wire
format. Before this SDK fix, the approval wait path used
`NULLRUN_APPROVAL_TIMEOUT_SECONDS` env default (default 300s) as
the ONLY source of wait duration — which is exactly the Разрыв 3
class of bug that the backend sweeper was written to prevent on
the backend side.
Concretely: a backend approval rule configured with
`expires_in_seconds=20` (short-approval use case) would
have the backend's expiry sweeper close the row at 20s, but the
SDK would have timed out the parked gate call at 300s — a silent
desync. The 300s/300s coincidence worked only because no UI-1
yet exists to set non-default expirations, and because the env
default matched the backend default.
This commit closes the SDK side of the Разрыв 1c contract:
## Changes
### `_wait_for_approval_resolution` (runtime.py:1225)
New optional kwarg `timeout_seconds: float | None = None`:
- When set to a positive number, used as the event.wait() timeout
(server-authoritative, takes precedence over the env default).
- When `None` (legacy backend without Разрыв 1c field, or
malformed response), falls back to
`self._approval_timeout_seconds` (the env default) —
pre-Разрыв 1c behaviour preserved.
- When set to a non-positive number (0 or negative), also falls
back to env default; we explicitly reject these because
`event.wait(timeout=0)` deadlocks on the very first call.
The effective timeout is also stored on the pending entry as
`entry["timeout_seconds"]` so callers / tests can inspect which
value actually drove the wait.
When the server value diverges from the env default, a DEBUG
log line is emitted ("approval {id}: using server timeout={X}s
(env default would have been {Y}s)") so an operator inspecting
logs can see which value actually drove the wait — useful for
diagnosing 'why did this approval time out earlier than I
configured' tickets.
### `check_workflow_budget` (runtime.py:1611)
Reads `response["approval_timeout_seconds"]` (server value),
validates the type (must be a number) and sign (must be positive),
and falls back to `None` (which then triggers env-default in
_wait_for_approval_resolution) on any validation failure. The
existing env-default path is preserved as the explicit fallback
contract.
`approval_expires_at` is intentionally not parsed in the SDK:
the field is documented as informational (UI/logs) and isn't
required for the SDK's wait math. If a future backend draft
sends only the ISO8601 string, the SDK will fall through to the
env default — same behaviour as the field being absent.
The approval-required INFO log line now includes which timeout
drove the wait ("env-default" vs the server value) for
diagnostic visibility.
## Tests (6 new in tests/test_approval_timeout_field.py)
- `test_server_timeout_used_when_response_has_valid_value`:
server timeout=15s is stored on the entry, env default 300s
is NOT used.
- `test_env_fallback_when_response_omits_field`: pre-Разрыв 1c
behaviour preserved when server sends no timeout field.
- `test_env_fallback_when_server_value_is_zero`: 0/0.0/-1/-100.0
all fall back to env default (regression guard against the
`event.wait(timeout=0)` deadlock footgun).
- `test_env_fallback_when_server_value_is_non_numeric`: pre-
validated None falls back to env default.
- `test_timeout_sentinel_returned_when_no_ws_push`: timeout
fires at the SERVER timeout, not the env default (0.1s
server, 300s env, 300s timeout would mean a 5-min test run).
- `test_diverging_server_value_logs_at_debug`: caplog captures
the 'using server timeout=Xs (env default would have been Ys)'
DEBUG line when values diverge.
## Verification
```
pytest tests/test_approval_timeout_field.py → 6 passed
pytest -n auto --cov=src/nullrun --cov-branch
--cov-report=xml --cov-fail-under=0
→ 1243 passed, 7 skipped, 28 warnings
in 34.44s (coverage 80.92%)
```
No public API change (new optional kwarg, backward compatible).
No SDK_MIN_VERSION bump. No on-wire change.
## SDK release note (for CHANGELOG.md follow-up)
When the SDK version is bumped, add:
```
### Fixed
- approval wait: SDK now uses server-authoritative
`approval_timeout_seconds` from the /gate response when
available, falling back to `NULLRUN_APPROVAL_TIMEOUT_SECONDS`
env default only on missing/non-positive/non-numeric values
(Разрыв 1c SDK sync; matches backend commit 0ad03b9).
```
(CHANGELOG.md edit deferred to release PR — this commit is
behaviour-only.)
Bump SDK 0.13.12 -> 0.13.13. Behaviour change (backward compatible): the approval wait now uses the server-authoritative approval_timeout_seconds from the /gate response when present, falling back to the NULLRUN_APPROVAL_TIMEOUT_SECONDS env default only on missing/non-positive/non-numeric values. Pairs with backend commit 0ad03b9 (Разрыв 1c, gate hot-path trigger). Changes: - pyproject.toml version + comment history bumped to 0.13.13. - src/nullrun/__version__.py docstring adds the v3.27 / 0.13.13 entry with full Разрыв 1c rationale, fix details, tests summary, and verification commands. - CHANGELOG.md adds the ## [0.13.13] - 2026-07-21 section (Fixed / Tests / Compatibility) ahead of 0.13.12. The runtime fix (src/nullrun/runtime.py:_wait_for_approval_resolution, _check_workflow_budget) and the 6-test contract suite landed in PR #74 (commit bde45c3). This release commit is the version-bump + changelog half. Verified: pytest -n auto --cov=src/nullrun --cov-branch --cov-report=xml --cov-fail-under=0 → 1243 passed, 7 skipped, 29 warnings in 33.15s, cov 80.92% ruff check src/ tests/ → All checks passed mypy src/ → Success: no issues found in 34 source files
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bump SDK 0.13.12 → 0.13.13. Behaviour change (backward compatible): the approval wait now uses the server-authoritative
approval_timeout_secondsfrom the/gateresponse when present, falling back toNULLRUN_APPROVAL_TIMEOUT_SECONDSenv default only on missing/non-positive/non-numeric values.Pairs with backend commit
0ad03b9(Разрыв 1c, gate hot-path trigger).The runtime fix and the 6-test contract suite landed in PR #74 (commit
bde45c3). This PR is the version-bump + changelog half.Changes
pyproject.toml—version = "0.13.13", comment history extended.src/nullrun/__version__.py— new docstring blockv3.27 / 0.13.13 (2026-07-21) — Разрыв 1c SDK syncwith full rationale, fix details, tests summary, verification commands.CHANGELOG.md— new## [0.13.13] - 2026-07-21section (Fixed / Tests / Compatibility) ahead of 0.13.12.Verification
Compatibility
timeout_secondskwarg defaults toNone; existing callers are unaffected.Test plan
ruff check src/ tests/— All checks passedmypy src/— Successpublish-testworkflow_dispatch to push 0.13.13 to Test PyPIDiff: +110/-1, 3 files (pyproject.toml, src/nullrun/version.py, CHANGELOG.md).