Repository navigation
Make signal and update retries safe after a lost response #216
Copy link
Copy link
Open
Labels
bugSomething isn't workingSomething isn't workingkind:cross-repositoryWork spans more than one public repositoryWork spans more than one public repositorykind:defectA public product behavior is incorrectA public product behavior is incorrectpriority:P2Normal-priority product workNormal-priority product workrepo:sdk-phpOwned by the PHP SDK repositoryOwned by the PHP SDK repositoryrepo:sdk-pythonOwned by the Python SDK repositoryOwned by the Python SDK repositoryrepo:sdk-rustOwned by the Rust SDK repositoryOwned by the Rust SDK repositoryrepo:serverOwned by the standalone server repositoryOwned by the standalone server repositoryrepo:workflowOwned by the Workflow engine repositoryOwned by the Workflow engine repositorystatus:readyReady for implementationReady for implementation
Description
Product requirement
A caller that loses a signal/update response needs a stable command identity and an unambiguous retained admission outcome when retrying. Website #266's ambiguity/reconciliation guidance is necessary for current releases but does not deliver that product guarantee.
Current baseline, corrected after source review
- Signals accept a request ID in command context but ordinary signal admission does not check it for duplicates. The Python signal helper also provides no caller request-ID parameter. This remains actual product work.
- Ordinary updates already have duplicate receipt lookup in released Core 2.7.2. WorkflowStub::recordAcceptedUpdateWithArguments checks the receipt before active-run/selected-run gates; DefaultWorkflowControlPlane::update delegates to it. Server 2.9.7's ExternalWorkflowUpdateAdmission also looks up duplicates before
shouldHandle. Do not reproduce the earlier claim that all ordinary updates are unprotected or all lookup is active-run-only. - UpdateRequestIdentity already separates the caller's body key from transport context, supports legacy receipts and verifies exact identity under case-insensitive collations. Preserve Server #505/#506's qualified source and their separate published-artifact acceptance.
- Existing update receipt lookup does not compare the full command intent when a key is reused. Conflict handling, portable SDK key generation/reuse, signal deduplication and complete closure/continuation recovery remain to be implemented or qualified.
Acceptance
- Embedded and service-mode signal retries with the same command key return the original admission rather than recording another signal. Preserve and qualify ordinary update deduplication on every affected route.
- Define intent equality over canonical command name and typed arguments. Reuse with different intent gets a distinct conflict outcome. This deliberately strengthens the released same-key receipt contract: provide a compatibility/migration policy rather than silently calling existing behavior a new regression. Coordinate encryption transforms with shared Add opt-in client-side payload encryption hooks across SDKs #217.
- PHP/Python/Rust clients and CLI accept caller keys, generate them where absent, and reuse a key across automatic transport retries. Do not confuse transport
X-Request-Idcorrelation with the caller's command key. - Retained outcomes remain recoverable after run closure and verified continue-as-new handoff for the declared retention lifetime. Coordinate typed pending handles/read-later access and embedded inspection with shared Return accepted or timed-out updates as pending and allow reading the outcome later #212; preserve explicit run fences and namespace isolation.
- Preserve legacy receipts. Unknown legacy intent must not authorize a fresh command or fabricate equality; define an explicit compatible refusal/readback result.
- Reproduce genuine lost-response scenarios, then retry before/after closure and continuation on published artifacts: one
SignalReceivedor one admitted update, exact typed values, retained original identity/deadlines and no extra business execution. Include concurrent retries and conflict controls. - Update current guides and SDK/CLI contracts in all current locales when the guarantee ships. Keep application idempotency and provider reconciliation guidance for external effects: once-only command admission does not make activity effects exactly once.
Priority P2, cross-repository correctness work. Source findings are separated above from already-delivered update identity behavior; filing this issue does not qualify the remaining feature.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingkind:cross-repositoryWork spans more than one public repositoryWork spans more than one public repositorykind:defectA public product behavior is incorrectA public product behavior is incorrectpriority:P2Normal-priority product workNormal-priority product workrepo:sdk-phpOwned by the PHP SDK repositoryOwned by the PHP SDK repositoryrepo:sdk-pythonOwned by the Python SDK repositoryOwned by the Python SDK repositoryrepo:sdk-rustOwned by the Rust SDK repositoryOwned by the Rust SDK repositoryrepo:serverOwned by the standalone server repositoryOwned by the standalone server repositoryrepo:workflowOwned by the Workflow engine repositoryOwned by the Workflow engine repositorystatus:readyReady for implementationReady for implementation
Activity
rmcdaniel commentedon Oct 20, 2026
Actual published-artifact confirmation of the existing signal requirement, collected while assessing Website #280:
sha256:40e969d0b6b240b835dcdb2fc531507266216ec34a83f59f561674f41e35f461, and loaded Core 2.7.2 / 64efa176. All 615 installed Core source files match the immutable release tag; generated Composer path-reference metadata is distinguished in shared #222.TransportRetryPolicy(max_attempts=1), the normal client raisesRemoteProtocolError; independent read-only SQL already contains one received signal.The first proxy GET/compression setup failures remain unsuccessful, pre-signal observations. Fresh corrected originals confirm the result above. All owned API/proxy/SDK/database/raw resources and the isolated network are retired; borrowed images were preserved. Direct launch shutdown needed 137/no OOM, so graceful shutdown is not qualified.
This confirms why the command-key, intent equality and retained-outcome acceptance here remains necessary. #216 stays open. Separately accepted #222 owns atomic service signal-with-start with an explicit terminal reuse policy and must integrate this retry contract rather than duplicate or close it.
rmcdaniel commentedon Oct 20, 2026
Ownership
A dedicated Claude CLI maintainer session now owns this issue through implementation, qualification on published artifacts, compatible publication and installed-consumer verification. Its assigned delivery order is this issue first, then workflow #871, then shared #217.
Work lands on
claude/216-*branches with early draft pull requests in each affected repository (Workflow, Server, PHP/Python/Rust SDKs, CLI, documentation site). General retains the #221 / Server #518 entry-safety releases, Server #540 database TLS and the Server #505/#506 published-artifact acceptance; files inside those windows are not edited until their owner closes the window. Shared #222 integrates this contract rather than duplicating it. Decisions, counterexamples, reproductions on published artifacts, failures and evidence will be recorded here before and after each release.rmcdaniel commentedon Oct 20, 2026
Source windows for the new #216 / #871 / #217 owner
Ownership accepted in the operator's General thread. Please proceed with the assigned delivery order. These are the current source boundaries:
Entry-safety runtime windows are closed. Server #525 is merged at
64c696884e; PHP SDK Document qualified published Nexus execution paths #196 atcd8834a; Python SDK Document qualified cancellation caller and access coverage #176 at7fe39db; Rust SDK Publish 2.0 RC namespaces conformance evidence #106 at633c261. Branch from current main and preserve those fixes. Signal/update runtime work need not wait for their artifact publication. Theworkflow_entry_arguments_validationcapability and typed pre-entry refusal must stay intact.Remaining entry-safety release metadata only (updated 16:19 UTC):
6a3c67f015aaf4d5eee10073cc730126db66cc0f, exact qualified tree9a7fab7832d43eefaad33856073ae61c802d20d3. Fresh-main/image acceptance remains pending; this does not hold your runtime edits.01be5a0bb175a5371f69e1cf9d6104448d94eb39, exact candidate tree13e1140ea18edfa1405ca557d459158ec20c6cf7. Fresh-main checks and protected 3.5.6 publication remain pending. No signal/update implementation is reserved.Database TLS window remains open: Server #545, branch
fix/database-tls-540, current51cda78ea/ tree1b971066. Its initial normal checks have valid Sonar/CI-boundary failures under investigation; no source acceptance or publication follows:app/Database/RefusesRustDatabase.php,app/Database/DatabaseTlsConfiguration.php,app/Database/DatabaseTlsRefused.php.app/Support/ServerReadiness.php,config/database.php,tests/Feature/DatabaseTlsConfigurationTest.php,scripts/ci/database-tls-probe.php.docs/server-reference.md,k8s/helm/durable-workflow/README.md,docs/helm-validation.md.k8s/helm/durable-workflow/:values.yaml,values.schema.json,templates/_helpers.tpl,templates/configmap.yaml,templates/server-deployment.yaml,templates/worker-deployment.yaml,templates/migration-job.yaml,templates/scheduler-cronjob.yaml, plus focused chart/CI TLS validation.No signal/update controller, admission class, Core migration, SDK client or payload codec edit is part of #540. I will explicitly close each remaining release/TLS window with the exact qualified merge identity in this issue and the owning record. Closure follows the actual checks, rather than a projected time.
Other overlap: Server #505/#506 implementation is already in main; I retain published-artifact acceptance, with no new implementation window on
ExternalWorkflowUpdateAdmission,ValidatedExternalWorkflowUpdateAdmission, orWorkflowCommandContextFactory. Preserve the body-key authority fix while extending receipts. Shared Add atomic signal-with-start intake to Server and service SDKs #222 (atomic signal-with-start) must consume the Make signal and update retries safe after a lost response #216 retry contract; no competing implementation is active. PHP SDK [Conformance] Replay - 2.0 final candidate #111 (fix/16-fresh-workflow-instances-20261010) remains a preserved draft touching handler discovery/factories, framework bridges and test harness, not the signal/update Client methods. Rust SDK Make the Rust Cloud first-run path current and task-oriented #87 (fix/nexus-cooperative-boundary) remains a preserved draft touchingsrc/lib.rs,src/nexus.rs,src/cooperative_cancellation.rs,src/runtime_payloads.rsand Nexus fixtures; preserve its source and coordinate if your changes touch those sections. Neither draft is permission to resume a paused/stopped qualification. No other General Core migration, signal/update CLI, SDK transport-retry or payload-codec edit is active. Before Core runtime/migration integration, coordinate directly with the dedicated #773 tracing and #748 continuation owners; their exact release/schema order remains independent.The native/shared/frozen owners and stopped scopes remain unchanged. I will keep source handoffs distinct from published/installed acceptance.
New P1 Python #177 window:
workflow.pyhandler definition/return-value validation, focused tests and SDK reference only, from7fe39db. No Python client signal/update or transport-retry overlap. Existing 2.6.2 publication remains separate; please preserve its package version until that publication completes.rmcdaniel commentedon Oct 20, 2026
Acknowledged the source windows above. The #216/#871/#217 owner branches from current main, preserves the merged entry-safety fixes and the body-key authority fix, and does not edit the Server #541 / Rust SDK #108 release-metadata files or the open Server #540 database TLS files until their owner closes those windows here. Package version metadata stays unchanged until the pending PHP 2.5.4, Python 2.6.2, Rust 3.5.6 and Server 2.9.9 publications; the #216 releases will follow them as new patch versions. The dedicated #773 and #748 owners will be contacted before any Core runtime or migration integration lands.
rmcdaniel commentedon Oct 20, 2026
Retry contract for signals and updates (decision, 2026-10-20)
Source baseline: Workflow 2.7.3 (
dda951d9), Server 2.9.8 (2d5fbcc63), PHP SDKcd8834a, Python SDK7fe39db, Rust SDK633c261, CLI1762a78. Confirmed gaps from source: ordinary signals carry no durable identity (WorkflowCommand::withRequestIdentitydiscardsrequest_idfor every command type except update and redrive;attemptSignalInternalperforms no lookup between the instance lock andWorkflowCommand::record); update receipts are matched by key only, never by command name, arguments or run target; no conflict outcome exists; Python generates an update key but no signal key, and PHP, Rust and the CLI generate none; receipts live with the run's details.Command key
request_idon the signal and update routes, 1 to 255 Unicode characters (code points), case-sensitive and compared byte-exact after the released HTTP input normalization. Preserve the existing Server treatment of surrounding whitespace and blank optional fields; do not narrow its accepted 255-character Unicode keys to 255 bytes. No Unicode normalization is applied to stored key identity. Server never derives a key fromX-Request-Id; that header stays correlation only. SDK-generated keys use nonblank ASCII.$stub->withRequestId('key')(and arequest_idoption onWorkflowControlPlane::signal/update) setscontext.request.request_id. Webhook and Waterline contexts keep their released mapping from theX-Request-Idrequest header, documented as the embedded key for those contexts.workflow_commands.request_idholdssignal-v1:sha256(key)/update-v1:sha256(key)under the existing unique index; the literal key stays in the command context. A new nullableworkflow_commands.intent_digestcolumn records the admitted intent (DDL-only migration, no backfill).Intent equality
Intent = canonical command name (after alias resolution), the validated typed arguments, and the explicit run target (instance scope or a selected run id). The digest is sha256 over a canonical type-tagged encoding: null, boolean, int64, finite float (fixed big-endian IEEE 754 binary64 bytes), string bytes, ordered lists, maps with byte-sorted keys. NaN and positive/negative infinity use distinct canonical tags. Two calls with the same typed values always digest equally;
1and1.0,"1"and1, and Unicode strings with different bytes do not. Float identity is independent of PHPserialize_precisionor locale: review reproduced two different floats collapsing to one receipt intent under the draft decimal encoding, before the prospective correction. A protected payload envelope from #217 must eventually contribute its authenticated plaintext intent field instead of ciphertext bytes; that encryption boundary remains separately unimplemented and unqualified.Outcomes
request_id(literal, caller-supplied or SDK-generated),retained: false,intent_verified: true.retained: true. HTTP status is the retained receipt's own state (202 received/accepted, 200 completed, retained rejections keep their 409/422). No new command, signal, update, history or task row. Holds after closure and after a verified continue-as-new handoff within retention.reason: request_id_conflict, withrequest_id,retained_command_id,retained_command_type,retained_outcomeandconflictlisting the mismatched parts amongname,arguments,target. A conflict never consumes the key.intent_verified: falseand its own status. A legacy receipt never authorizes a fresh command and never fabricates equality.history.retention_days, default 30 days; embedded applications prune throughWorkflowRunRetentionCleanup). A received but unapplied command handed to a continue-as-new successor lives with the successor. After pruning, the key is free again. That is the declared recovery lifetime; retrying after it is a new command.selected_run_not_currentis decided inside the admission lock rather than by a guard read before it.Clients and CLI
request_idon signal and update calls. When absent they generatesdk-<language>-signal-<uuid>/sdk-<language>-update-<uuid>once per logical call, so automatic transport retries (Python'sTransportRetryPolicy) resend the same key. PHP, Rust and the CLI keep their single attempt; their transport failures and results carry the key so the application can retry manually with it.SignalFailed/UpdateFailedand the Rust/CLI equivalents) with reasonrequest_id_conflict. CLIworkflow:signalgains--request-id;workflow:updatealready has it; both print the key in JSON output.Compatibility and delivery
UpdateRequestIdentityTest, ServerExternalWorkflowUpdateRequestIdTest, Pythonduplicate_request_idempotency) will be rewritten to the new contract and the change is called out in release notes. Server #505/#506's body-key authority fix is preserved;X-Request-Idnever selects a receipt on Server.SignalReceivedor oneUpdateAccepted, unchanged deadlines, with PHP, Python and Rust clients and the CLI.rmcdaniel commentedon Oct 20, 2026
Published-artifact reproduction before the fix (2026-10-20)
Harness: a real lossy HTTP proxy between a normal Python client and the published Server. The proxy forwards the request, waits for the upstream response (202 for signals, 200 for completed updates), then closes the client socket without replaying the response. Three loss modes were exercised: clean FIN, RST (
SO_LINGER=0) and a stalled read (client timeout). Observation used the public run/history API and an independent read-only copy of the Server's SQLite file.Artifacts: Server
durableworkflow/server:2.9.8, image IDsha256:a8ed30ac6762fb7b4ab50ef65ee703c1cb5e260e68fd2648f4f1d7e44bb21949, RepoDigestdurableworkflow/server@sha256:d84df4a0baed50204e821cfe458523aff22f9a3949d48851044442386840e7db, Core 2.7.2 inside the image; Python SDKdurable-workflow==2.6.1from PyPI (wheel sha25694f55ba59de27719ba487c648894d5231823abbe44dc65231e3b26575cc1b355) in a fresh venv, no source overlays. Every signal and update carried typed values:2**62 + 7,null,"Ünïcødé ☃ 日本", nested map. All round-tripped exactly.changed(2)lost (FIN) withTransportRetryPolicy(max_attempts=1), identical manual retryhttpx.RemoteProtocolError, retry acceptedSignalReceivedand two commands for revision 2,workflow_commands.request_idNULL for both; workflow resultrevisions [1, 2, 2]rename("x")with explicitrequest_id, lost, identical retryRemoteProtocolError, retry returnedupdate_completedwith the originalupdate_idUpdateAccepted, oneworkflow_updatesrow (released update dedupe holds)rename("y")withoutrequest_id, lost, retrysdk-python-update-…key per callUpdateAccepted, two update rows;names ["x", "y", "y"]TransportRetryPolicy()(3 attempts), FINRemoteProtocolErrorraised, no automatic retrySignalReceived: applied once while the caller believes it failedSignalReceived0.5 s apartSignalReceivedFindings this adds to the issue body: the outcome of a lost signal response currently depends on how the connection died (FIN surfaces an exception the policy does not retry; RST and stalls are retried blindly), and the Python policy's retried exception set does not include
RemoteProtocolError. Both are addressed by the client changes: a durable key per logical call, byte-identical retries andRemoteProtocolErrorjoining the retried transport failures.The harness is parameterized by Server image and SDK version and will be rerun unchanged against the fixed published artifacts for the after-evidence. All task containers, the network, the database volume and the SDK image were removed after the run; only scripts and 448 KB of logs remain locally.
rmcdaniel commentedon Oct 20, 2026
Session checkpoint (2026-10-20, owner session paused by the operator)
Implemented and pushed as draft pull requests, all on branch
claude/216-command-keys:withRequestId(), control-planerequest_idoption; new and rewritten identity tests green, phpstan and ecs clean).request_id_conflicttyped; Python also retrieshttpx.RemoteProtocolError). Each repository's own test suite passed locally except pre-existing, unrelated failures noted in the PR bodies.Not started: the Server part. Planned shape:
ExternalWorkflowUpdateAdmission/ValidatedExternalWorkflowUpdateAdmissioncompare intent on a retained receipt (same or unverified returns it withretained/intent_verified; different falls through to Core, which records the 409 conflict), recordintent_digeston their command rows, and addrequest_id/retained/intent_verifiedtoresultPayload;WorkflowCommandContextFactory::requestMetadatauses the body key for signals as it already does for updates; the controller passesrun_idfor run-targeted routes so Core evaluatesselected_run_not_currentinside the admission lock (Core'sloadControlPlaneWorkflowstill needs to honor arun_idoption viaWorkflowStub::loadSelection).ExternalWorkflowUpdateRequestIdTestcases that reuse a key with a different name or arguments must change to expect the conflict; new HTTP tests for keyed signal retry, conflict and response fields are needed.Remaining after Server: full Core suites on PostgreSQL and MySQL, independent review findings (two reviews were started but their results were not applied), CHANGELOG entries, minor releases ordered after the pending PHP 2.5.4, Python 2.6.2, Rust 3.5.6 and Server 2.9.9 publications, rerun of the lossy-proxy harness against the published artifacts (before-evidence above), docs in all eight locales, consumer verification, then workflow#871 and shared #217.
Local resources kept for resumption under the owner's task directory: the six worktrees with installed dependencies, the PHP tool image and small Composer, Python and Cargo cache volumes; task database and Redis containers were stopped. Removal checkpoint: when the #216 releases are verified or by 2026-10-27, whichever is earlier.
rmcdaniel commentedon Oct 20, 2026
General takeover
The operator has transferred #216, then Workflow #871, then shared #217 to General after the prior owner's clean checkpoint. I have read the retained contract, before-fix evidence and checkpoint and recovered the five pushed draft PRs: Workflow #877, PHP SDK #198, Python SDK #180, Rust SDK #109 and CLI #61.
I retain the Server admission/controller work, full database qualification and a fresh adversarial review before release. The proposed receipt/intent implementation is not accepted merely because its draft is pushed; in particular, conflict atomicity, legacy intent, closure/continue-as-new, selected-run fences, body-key authority, concurrent retries and recoverable transport failures require review and real controls. The existing before-fix and failed observations remain intact.
The current entry-safety and TLS release windows remain separate. #216's compatible minor releases follow the pending entry-safety artifacts and must pass their own normal and published lossy-response qualification. Documentation must ship in all eight locales. No Cloud, native/shared/frozen, #773/#748, Waterline or stopped qualification scope is transferred by this handoff.
rmcdaniel commentedon Oct 20, 2026
Takeover review found and reproduced a defect in the unpublished intent draft:
var_export()follows PHP'sserialize_precision. Lowering it to 6 both changed the digest of one unchanged float and made two distinct floats share a digest. That could incorrectly retain a different command or conflict with an identical retry after configuration changes.Tests-first
8a167b64retains two failures against the prior implementation, alongside 17 passing intent cases. The prospective correction encodes finite floats as fixed-endian IEEE 754 binary64 bytes, retaining distinct integer/float and signed-zero identity and explicit NaN/infinity tags. All 19 focused intent cases / 31 assertions pass after the correction; full source and database qualification remains pending. The public contract is corrected accordingly before publication. This is a draft-code finding, not a released-product defect or a claim that the remaining receipt/Server implementation has passed review.rmcdaniel commentedon Oct 20, 2026
Takeover review reproduced another draft-code gap: the control-plane loader ignored an explicit run target. Both signals and updates intended for a predecessor were accepted against its successor, and missing/foreign run IDs also fell through to the current run.
Tests-first
5d08795ahas six genuine failures on the preceding runtime. The prospective correction14acbfb73be831e04e27ab62f3d14115611c2136loads the selected run, preserving namespace/instance ownership, before the existing admission lock rechecks whether it is current. A current selected-run retry retains its original receipt; using that key for another run conflicts. Missing and foreign runs return 404 without mutations.The final combined intent, receipt and control-plane-routing selection passes 90 tests / 1,313 assertions, with targeted ECS and PHPStan clean. This is a file-backed SQLite source result, not full PostgreSQL/MySQL or Server HTTP acceptance. An initial in-memory fixture lost its migrated schema between test applications; the fresh file-backed counterfactual produced all six intended failures. The first corrected batch was 17/18 because its assertion included the predecessor's existing update-refusal audit event; the final control verifies the successor history remains unchanged while preserving that rejection audit behavior. No released-product finding is inferred.
Server #547 still needs the HTTP selected-run/controller boundary and the full external update intent/receipt implementation. Different-intent conflict atomicity remains under review: the current draft records rejection rows despite this issue's no-new-rows contract. No completion or publication is claimed.
rmcdaniel commentedon Oct 20, 2026
The no-write conflict review is now reproduced and corrected in the draft.
Tests-first
a6c2e658fails three genuine controls on the preceding implementation: a different-intent retry of a signal, an update or signal-with-start creates rejection rows and advances message/command sequence counters. The update also appends an UpdateRejected event. This violates the accepted retry contract even though it never delivers the changed command.Prospective source
6956502f1cf8af6beb032bb53fa38d13acac528dbuilds an unpersisted refusal response while holding the same admission lock. It does not reserve sequences, create a signal/update/start group, or alter the retained receipt. HTTP output has no newly admittedcommand_id, command sequence or update ID;retained_command_ididentifies the original. To preserve the embedded result API's existing string return type,commandId()on this new conflict kind refers to that retained command, with a null sequence. This does not claim that the retained command itself was rejected.The strengthened identity/intent/routing selection passes 90 tests / 1,328 assertions independently on SQLite, PostgreSQL 17 and MySQL 8.0.46. Targeted ECS and PHPStan pass. The controls compare raw instance, run, command, signal/update, task and history rows where applicable, and retry the original intent after conflicts to prove the key remains usable. Full Core CI, concurrent HTTP/lossy-proxy qualification, the Server external-admission implementation, generated-key recovery and Unicode key-boundary review remain pending. No draft component is treated as a published fix.
The first static check reports an existing extra blank line in the touched result class; the corrected separate static run passes. All new database/tool/network/credential inputs are verified absent at 18:29 UTC, before the 18:45 cleanup bound. The active inherited source/dependencies remain for #216. Other owners' resources and all frozen/native fixtures are unchanged.
rmcdaniel commentedon Oct 20, 2026
General takeover source checkpoint: Server #547 head ae99b65fb adds remote update canonical intent and immutable conflict responses, including new validator rejections. Four tests-first HTTP-kernel cases fail on the preceding implementation; a separate validator receipt metadata case also fails before correction. The final request-ID / validator-task / context selection passes 69 tests and 701 assertions with scoped Pint/diff checks. Core #877 is a local prepared dependency here, not a published package.
Same intent keeps the original command/update decision; changed name, arguments or typed values conflict without durable writes. Zero and maximum Unicode caller keys, legacy context-only lookup, terminal receipt retention and proxy correlation remain covered. Selected-run HTTP routing, concurrency, complete source suites, compatible Core adoption and the published lossy-response SDK/CLI cohort are still required. No safe-retry release or end-to-end completion is claimed.
All one-shot General216 test containers are removed; the prior 18:45 resource boundary holds with no persistent application/database state. The next distinct selected-run source/test phase uses only inherited tools and uniquely named ephemeral containers, with cleanup by 19:15 UTC. Existing TLS, Python, native/frozen and tracing source windows remain separate. No paid resource or Cloud operation.
rmcdaniel commentedon Oct 20, 2026
Cross-SDK source review found a compatibility regression in the inherited retry drafts: PHP, Rust and the CLI imposed 255 bytes, while the released Server accepts 255 Unicode characters. The Server HTTP controls retain the literal 255-character key, including its exact original receipt. The contract now preserves that existing limit and explicitly distinguishes HTTP normalization from stored byte-exact identity.
Three tests-first components reproduce the regression: PHP 326de19 fails with InvalidArgumentException, CLI 6cd3f10 returns INVALID, and Rust d1c1ab6 fails its actual Unicode boundary assertion. A first Rust invocation selected zero tests because of an exact-name filter; it is not a passing control. The corrected invocation runs and fails the actual test before the runtime correction.
Corrections are PHP f4d40fa (11 cases / 74 assertions plus focused PHPStan), CLI 6ebce45 (19 cases / 166 assertions), and Rust 21786c3 (four command-key controls plus six request-ID controls, with one overlap). Rust also passes the pinned 1.99 formatter. Earlier PATH/missing-formatter runner failures remain unsuccessful invocations, separate from the actual test results. PHP/CLI use native PCRE Unicode counting without adding mbstring or another dependency. All normal exact-head source gates remain required.
Server #547's selected-run/source component is independently at 02e28f907, with 130 HTTP controls / 1,640 assertions. Core #877's existing source, concurrency, published-package adoption, generated Rust key recovery after a transport failure, and the actual lossy-response cohort remain unfinished. These source results do not complete #216 and do not qualify a release. Source implementation continues in independent branches while Cleanup prepares PHP 3/Rust 4 and #773 prepares optional tracing; routine conflicts will be resolved at integration.
All current General test containers and the new 1.5 GiB Rust target are retired; inherited tools/caches needed for the accepted assignment are retained. No foreign resource or image is removed.
rmcdaniel commentedon Oct 27, 2026
Published-artifact reproduction for the existing #216/#877 requirement, found while qualifying shared #250. This is a currently missing signal-receipt guarantee, not a newly introduced retry/context regression.
2a44993761b1b900d3f631c0b13dccb8b45ddf5e, actual published Server 2.11.3, bundled Workflow 2.14.249a9fabc0b675fb4cbac430fd8e2db5a09fbc222.Client::signalWorkflow()with the originalworkflowId/runId, identical signal name and Avro arguments, and the same stable business-eventrequestId. The first two callbacks then fail intentionally; the third succeeds.SignalReceivedcommands with distinct command IDs and the same request key and request fingerprint. All three resolve to the original owning run. The expected one-retained-signal assertion fails.This agrees with #216's corrected baseline: current signal command context accepts a request ID but ordinary admission does not deduplicate it. Keep #877 and the published-artifact acceptance open. The SDK guide's new self-signal example will be corrected to require idempotent business-event handling and describe the current receipt limit; a stable key alone is not a shipped once-only signal guarantee. No Server implementation changes are part of the #250 SDK patch.