diff --git a/docker-compose.published.yml b/docker-compose.published.yml index 3e1481089..0f20cd119 100644 --- a/docker-compose.published.yml +++ b/docker-compose.published.yml @@ -16,7 +16,7 @@ name: durable-workflow-server # release whose default names another image). Set DW_SERVER_IMAGE to run # any other native image, by tag or digest; pin a digest for production # change control. -x-server-image: &server-image ${DW_SERVER_IMAGE:-durableworkflow/server:3.9.1} +x-server-image: &server-image ${DW_SERVER_IMAGE:-durableworkflow/server:3.9.2} services: server: diff --git a/docs/releases/3.9.2.md b/docs/releases/3.9.2.md new file mode 100644 index 000000000..2cacd2b56 --- /dev/null +++ b/docs/releases/3.9.2.md @@ -0,0 +1,81 @@ +# Durable Workflow Server 3.9.2 (native) + +Server 3.9.2 corrects Unicode signal/update command keys and makes keyed +admission receipts explicit. It also hardens the owner check on storage-admission +observation files. Its immutable images are `durableworkflow/server:3.9.2` and +`ghcr.io/durable-workflow/server:3.9.2`; the published Compose default selects +3.9.2. Rolling aliases move separately after published-image qualification. + +## Upgrade and rollback + +**From 3.9.0 or 3.9.1, no schema step is needed.** Stop Server replicas, back up +the database and external-payload storage, select the new image, restart and +verify readiness, reported version and worker registration. The physical schema +and existing command/intent rows are unchanged. + +Upgrades from 3.8.x or earlier still require the explicit 3.9 schema upgrade: +SQLite 12 → 13, PostgreSQL and MariaDB 13 → 14, and MySQL 14 → 15. Follow the +[3.9.1 upgrade procedure](https://github.com/durable-workflow/server/releases/tag/3.9.1#upgrade), +using the 3.9.2 image for `schema-upgrade` and every restarted replica. Older +steps are applied where needed. Rollback to 3.8.x requires restoring the backup. + +A rollback to 3.9.1 uses the same schema but restores the Unicode-key and receipt +metadata defects described below and removes the observation-owner hardening. +The worker protocol remains `1.20` and the control plane remains version `2`. + +## Command keys and receipts + +[Installed CLI and SDK controls](https://github.com/durable-workflow/server/issues/934) +found that 3.9.1 accepted a 255-character multibyte `request_id` at the HTTP +boundary but then refused it with `422 invalid_request_id` at the store's +255-byte check. The store now applies the existing **255 Unicode code-point** +limit. A 255-character key made of two-byte or four-byte characters is accepted; +256 characters are refused without admission. Existing normalization, byte-exact +identity and hashed storage remain unchanged. The body `request_id` is the +command key; the HTTP `X-Request-Id` header is not a retry key. + +Fresh keyed signal and accepted update receipts now echo the literal +`request_id` and report `retained:false`, `intent_verified:true`. A retained +receipt echoes that key with `retained:true` and preserves its original command, +run and update identities. A modern intent proof reports `intent_verified:true`; +a compatible pre-intent legacy readback reports `intent_verified:false`, without +fabricating equality. Unkeyed and bridge receipts keep their existing behavior. + +The same-key intent/conflict, close/continue lookup and zero-write authority +boundaries from 3.9.1 remain. A raw/token or collation-only identity ambiguity +still fails closed as `409 request_id_ambiguous`, `retryable:false`, with no +selected receipt or writes. A retained update does not claim a retry's external +payload reference. The accepted +[legacy-key vectors and upgrade procedure](../../resources/platform-protocol-specs/command-key-legacy-v1-vectors.json) +separate synthetic legacy shapes, physical upgrades and committed-response loss. +Source tests do not establish the installed client cohorts under shared #216. + +## Storage-admission observation ownership + +When storage admission is enabled, the already-opened observation descriptor +must belong to root or the effective Server UID. A foreign owner fails closed +through the existing unavailable/fenced admission outcome. The check uses the +same descriptor as the bounded type/mode/content read, avoiding a separate path +lookup ([#1206](https://github.com/durable-workflow/server/pull/1206)). + +Operators must still provide trusted ancestors and the intended read-only +container mapping. The runtime does not enforce ancestor ownership. Cloud's +physical collector, UID/mount mapping and adoption acceptance remain separate. +Draining completion-upload allowances are not added by this patch; see +[#951](https://github.com/durable-workflow/server/issues/951). + +## Retained limits and qualification + +The 3.9.1 encoded completion budget, discovery field and bounded 64 MiB/two-second +refusal delivery remain unchanged. This patch grants no new external-payload or +continuation-command authority. Installed PHP/Python/Rust Worker completion +qualification is recorded separately under +[shared #228](https://github.com/durable-workflow/.github/issues/228); installed +command-key cohorts remain under +[shared #216](https://github.com/durable-workflow/.github/issues/216). + +The independent #1194 20-execution gate is complete. The MariaDB re-registration +pool-timeout investigation [#1204](https://github.com/durable-workflow/server/issues/1204) +remains open and is not fixed here. Pending, aborted and infrastructure-blocked +checks are not counted as qualification passes. This release does not enable +Cloud native adoption or publish the later dispatch-summary schema feature.