diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bbf7d5..0c516fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.15.0] - 2026-11-04 + ### Added - Worker schedule-to-start histogram `durable_workflow_worker_task_schedule_to_start_seconds` for workflow and activity dispatches, tagged only with `task_kind` and `task_queue`. It requires Server's `claimed_task_ready_age` capability and a valid integer `ready_age_ms`, records Server-computed milliseconds as seconds, preserves real zero and omits missing/invalid samples. The shared metrics contract is pinned at revision 2. Published-Server and installed-package acceptance remains pending in #188. @@ -18,6 +20,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Replay consumes an already-open duplicate of a condition wait when the older physical wait is satisfied with a true predicate. A wait opened after that satisfaction remains a separate authored call with its own timeout. (#256) +## [2.14.1] - 2026-11-04 + +### Fixed + - `wait_condition` predicate fingerprints no longer change across Python versions or worker processes. Every earlier release hashed the predicate's bytecode and the `repr` of its constants. So upgrading Python (for example 3.12 to 3.13) failed replay of every in-flight run at its first wait, and a predicate containing a nested function (a generator expression, a nested lambda, or a comprehension on 3.10 and 3.11) got a new fingerprint in every process, so a restart or cache loss failed replay with `condition_fingerprint_changed`. New waits record a v2 fingerprint (`dwpy2:sha256:...`) computed from the predicate's module, qualified name and a canonical form of its source AST, with no bytecode, addresses, paths or line numbers. Without source (for example `eval` or a REPL) no fingerprint is sent, and the wait is identified by its key and call order. A v1 value recorded by an earlier release still matches when this process computes the same v1; otherwise it is accepted as unverifiable instead of failing replay, so drift in those predicates is no longer detected. A reopen sends the fingerprint its first open recorded, so a wait opened before the upgrade keeps its v1 value, and a keyless wait links a v1 value only within its own chain. A keyless wait without source links its false-wake reopens within its chain, as before. **Rollback and mixed fleets:** a run that opened a wait under this release records a v2 fingerprint, which 2.14.0 and earlier refuse on replay. Don't roll a task queue back below this release once such waits exist, and upgrade every worker on a queue together. (#258) - Same-line `wait_condition` lambdas whose bodies contain list, dict or set comprehensions share one combined fingerprint on every Python version. Put those predicates on separate lines to detect a change from one candidate to another. (#258) diff --git a/docs/reference/metrics.md b/docs/reference/metrics.md index d6e33ca..08e8acd 100644 --- a/docs/reference/metrics.md +++ b/docs/reference/metrics.md @@ -41,10 +41,10 @@ to use this adapter. Applications own scrape/export configuration and additional resource labels. Custom recorders should remain fast and handle their exporter failures without throwing into the client or worker. -### Schedule-to-start latency (unreleased) +### Schedule-to-start latency (SDK 2.15.0) -This unreleased feature adds the histogram below. Package and published-Server -acceptance remains pending in +SDK 2.15.0 includes the histogram below. An authoritative published Server +implementation and installed-runtime acceptance remain pending in [#188](https://github.com/durable-workflow/sdk-python/issues/188). | Recorder name | Instrument / unit | Tag keys | Measurement | diff --git a/docs/sdk-reference.md b/docs/sdk-reference.md index c746b5a..a2f6041 100644 --- a/docs/sdk-reference.md +++ b/docs/sdk-reference.md @@ -959,6 +959,10 @@ is a workflow compatibility change. ## Typed activity values +Typed activity arguments and activity `result_type` are available from SDK +2.14.0. Typed workflow/handler arguments, child results and client results +require SDK 2.15.0. Decoding is opt-in on each surface described below. + Activity boundaries can carry dataclasses and enums without hand-written conversion. The wire format stays the neutral map, so PHP and Rust workers read and write the same values. diff --git a/pyproject.toml b/pyproject.toml index b2e87a1..5fbc165 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "durable-workflow" -version = "2.14.0" +version = "2.15.0" description = "Python client and worker SDK for Durable Workflow Cloud and self-hosted Server" readme = "README.md" requires-python = ">=3.10" @@ -79,8 +79,8 @@ durable-workflow-replay-conformance = "durable_workflow.replay_conformance:main" durable-workflow-workflow-updates-conformance = "durable_workflow.workflow_updates_conformance:main" [tool.durable-workflow] -product-train = "2.14.0" -registry-version = "2.14.0" +product-train = "2.15.0" +registry-version = "2.15.0" supported-server-versions = "2.8.0" supported-server-release-baselines = { "2" = "2.8.0", "3" = "3.0.0" } worker-protocol-version = "1.20"