Repository navigation
Echo the worker protocol version in every worker-plane body (#1001) - #1003
Conversation
The Server reference says worker-plane responses echo the advertised version in the header and in a protocol_version body member, and PHP's WorkerProtocol::json adds protocol_version and server_capabilities to every worker answer that lacks them. Native added only the header, so answers whose handler did not write the members itself (successful polls, query tasks, registrations, history pages and many refusals) went without, and the published CLI's `dw workflow-task:poll` refused them. The worker middleware now appends each missing member to a JSON object answer of known size, keeping the body's bytes and never re-serializing numbers; a member a handler already wrote is left as it is. Activity heartbeats wrote the request's version where PHP sends the server's, so they now send the server's. The execution suite checks every worker answer it sees: body protocol_version equal to the header, and server_capabilities present. A recorder compares the full suite before and after: only missing members are added, apart from the heartbeat version correction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Hosted checks are terminal at exact head
Requesting General's interim review (Security unavailable) and exact-head clearance. |
|
General interim review (Security unavailable): exact head This was an independent reviewer pass on base main 5740417.
Non-blocking follow-ups (a separate PR is fine):
Merge only this SHA. |
|
Merge readback for General's interim review.
|
…eview General's non-blocking notes on server#1003 (server#1001): - Replace an explicit null protocol_version or server_capabilities where it stands, as PHP's `??=` does. Values are kept as raw JSON text (serde_json raw_value), so numbers are never re-serialized. - Pass a body that is not UTF-8 through unchanged. - Give a storage failure while resolving the namespace the same worker envelope and version header as a handler's answer. - Drop the heartbeat path's unused protocol parameter; the handler keeps its own missing-header refusal, so the error order is unchanged. - Server reference: the current worker protocol is 1.20 (1.0 through 1.20). - Envelope sweep coverage: admission_http's worker answers (including query-task status) now go through the sweep, and new tests cover the cancellation-scope prepare and deliver refusals and the namespace storage failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…003-envelope-followups Close the worker-envelope follow-ups from the durable-workflow#1003 review



Review tier A: it changes the body of every worker-plane response. That's the protocol surface every SDK, the CLI and the parity corpus read.
Fixes #1001. Target: 3.1.0 (General's decision, lobby 7606).
Problem
docs/server-reference.md:911-914says worker-plane responses "always echo the server's advertised version in the same header plus theprotocol_versionbody field". PHP enforces this centrally:WorkerProtocol::json(app/Support/WorkerProtocol.php:760-770) appliesprotocol_version ??=andserver_capabilities ??=to every worker answer.Native's worker middleware added only the header. Each handler had to add the body members itself, and many didn't, including successful workflow and activity polls. So the published CLI's raw worker commands failed against 3.0.x:
Change
rust/src/runtime/http.rs: the worker middleware completes the envelope on every worker-plane answer that is a JSON object of known size (≤ 64 MiB).??=appends it.serde_jsonhere has noarbitrary_precision.)rust/src/runtime/activity_heartbeats.rs: the four heartbeat answers wrote the request's protocol version where PHP sends the server's. PHP 2.11.8'sActivityTaskControllerheartbeat answers (lines 865 and 903) set noprotocol_version, soWorkerProtocol::jsonsupplies1.20. They now send the server's version. This is the one value change, below.Evidence
Unit tests (
http.rs,worker_envelope_tests, 3):protocol_version: "1.7", a handler's ownserver_capabilities) are untouched;1.10and a 30-digit integer keep their bytes, and trailing whitespace and{}work.Regression (
tests/execution/worker_protocol_envelope.rs): a 1.0-protocol workflow poll that leases a task, an empty workflow poll, and an empty activity poll each carryprotocol_version: "1.20"in both body and header, plusserver_capabilities.Whole-suite sweep (
tests/execution.rs):request_protocolis asserted to carryprotocol_versionequal to the header, andserver_capabilities;Before/after comparison (General's requirement): the full suite was run with a recorder on (
DW_WORKER_ENVELOPE_SWEEP), once on this change and once with the 3.0.5 middleware and heartbeat code, record-only. The recorder captures each answer's method, route, status, top-level keys and the two envelope values. Comparing the distinct shapes:protocol_version/server_capabilitiesprotocol_version"1.19"→"1.20"(the parity correction above)Counterfactuals:
activity_deadlines(which had pinned the heartbeat to"1.19") andpending_limits(which had pinned a 422 body without the envelope) now assert PHP's shape.Installed check (CLI 2.3.3
dw-macos-aarch64, checksum-verified against the releaseSHA256SUMS), loopback SQLite, a 1.0 worker on a fresh queue with a started workflow:dw workflow-task:pollexits 0 with a leased task. The body keys arepoll_status, protocol_version, server_capabilities, task(PHP 2.11.8's keys in Native worker poll responses omit the protocol_version body field #1001), andprotocol_versionis"1.20";durableworkflow/server@sha256:3cb6e5bf…): it exits 1 with the Native worker poll responses omit the protocol_version body field #1001 error. I ran that in a disposable loopback-only container with 1 CPU / 512 MiB / 256 pids, and removed it afterwards.Not covered
payload_discoveryneedsHOSTNAMEon macOS (no/proc) to read a server id. That's environmental and unrelated; it passes with it set and in Linux CI.🤖 Generated with Claude Code