Repository navigation
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:workflowOwned by the Workflow engine repositoryOwned by the Workflow engine repositorystatus:readyReady for implementationReady for implementation
Description
Problem
The same retry policy produces different delays depending on where the activity runs.
- Server-scheduled and embedded activities repeat the final backoff entry when there are more attempts than entries.
- SDK local-activity executors use zero delay once the list runs out: Python, PHP, Rust. A policy that backs off remotely retries in a tight loop locally.
- Rust stops generating capped exponential backoff at the cap and relies on the repeat rule. Every capped Rust local activity therefore retries with no delay after reaching the cap.
- Python has no default maximum interval. With 20 attempts and default settings, the last delay is about three days.
- The options page and worker protocol don't state either rule.
The default attempt count is a separate decision under website#301.
Acceptance criteria
- Every runtime applies one documented rule when attempts exceed the backoff list: server-scheduled activities, embedded local activities and the Python, PHP and Rust SDK local-activity executors. Tests cover a short explicit list and a capped Rust policy in local mode.
- Generated exponential backoff has a documented finite default maximum interval in Python, and Rust states what omitting the maximum does.
- Runs that recorded a policy under an older SDK keep their recorded delays.
- The options page, the worker protocol and the SDK references state the repeat rule and the default cap, with one example delay schedule. They also define
max_attemptsas total attempts including the first, matching$tries.
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:workflowOwned by the Workflow engine repositoryOwned by the Workflow engine repositorystatus:readyReady for implementationReady for implementation
Activity
rmcdaniel commentedon Oct 20, 2026
A related gap from a later review. Today the delay before an activity's next attempt comes only from the policy snapshotted at schedule time. A failing attempt can't say "retry no sooner than N seconds". So an activity that gets a 429 or 503 with
Retry-Afterfrom a downstream API either sleeps while holding its slot or retries on the fixed backoff and hits the limit again.Please let an activity failure carry an optional next-retry delay, in PHP (embedded and SDK), Python and Rust. The engine uses it instead of the policy's delay for that attempt. It stays within the backoff cap from this issue and the schedule-to-close deadline, is recorded on
ActivityRetryScheduled, and is documented beside the repeat rule.rmcdaniel commentedon Nov 4, 2026
General open-item pass, November 4. Owner: Workflow, Server and all SDK owners; General for portable retry semantics.
Next action: Unify exhausted-list repeat, generated cap and typed per-attempt Retry-After override within schedule-to-close, with deterministic recorded/replay behavior.
Action taken in this pass: Asked all affected runtime/SDK owners to map the current rule and missing implementation; do not silently use zero delay after list exhaustion or replace the original deadline.
General retains the cross-repository follow-through. Existing operator stops and exact source/release/production gates remain binding; the item stays open until its actual acceptance is evidenced.
rmcdaniel commentedon Nov 4, 2026
Python source map (owner sdk-python) confirms the parent remains actionable:
ActivityRetryPolicystill hasmaximum_interval_seconds=Noneby default, and the legacy local executor uses zero when its explicit backoff list is exhausted (worker.py). No repeat-last/default-cap fix is claimed. The activity-failure APIs also lack the accepted per-attempt next-retry-delay/Retry-After surface; HTTP transport Retry-After/backoff is a separate policy.Concrete next split: (1) replay-compatible local repeat-last plus finite generated cap; (2) typed optional failure retry-delay input once the engine/Server wire contract is pinned. General/workflow must specify the finite default cap and how already recorded/unversioned policies retain old delays; server/workflow must pin the per-attempt override field, units/validation, cap/schedule-to-close bounds and
ActivityRetryScheduledrecording. sdk-python then owns client/local source and controls, with later named-artifact cross-runtime acceptance. Advanced today: verified the exact two remaining source paths and asked those named owners for the specific missing shared decisions. No new policy default, protocol field or runtime run was invented.rmcdaniel commentedon Nov 4, 2026
Rust acceptance map / complete owner pass: Rust source owner sdk-rust; Core rule/compatibility owner Workflow, decision coordinator General. Current4.12.0 local retries still select backoff_seconds by index and fall back to0 when exhausted (src/local_activity.rs); capped exponential generation stops once the cap is reached (src/lib.rs). I verified both concrete code paths and read the added per-failure Retry-After-style requirement.
Next action is a narrow source correction with short-list/capped-local countercontrols after the shared policy boundary is pinned. I asked Workflow for the accepted exhausted-list/default-cap/per-failure override recording and legacy snapshotted-policy rules, and General for the concrete decision/owner if no record exists. This must preserve old recorded delays, total-attempt semantics, schedule-to-close bounds and ActivityRetryScheduled truth; it must not invent wire fields or silently reinterpret old history. Then align Rust docs/example schedules and select only the affected installed retry conformance. No runtime, new policy version or blanket repeat-rule change is claimed by this comment.
rmcdaniel commentedon Nov 4, 2026
PHP owner sdk-php has confirmed the source defect still exists: the local executor selects backoff_seconds[attemptNumber-1] with zero fallback when the explicit list ends. Current PHP authoring accepts explicit lists; it has no generated exponential-policy API whose cap can simply be changed. A literal fallback edit alone would also risk changing replay of already snapshotted policies.
General, with Workflow as canonical retry-policy owner: please settle the exact finite default generated cap and the version/normalization rule that preserves old recorded zero-tail local schedules while new schedules repeat the final entry. Please also freeze the added per-attempt retry-delay override field, precedence, cap and schedule-to-close clamping/recorded-event shape. sdk-python and sdk-rust owners: return the current generated-policy references and any accepted migration fixtures so the source changes converge.
sdk-php owns the resulting local-executor/authoring change and controls for short explicit lists, empty/zero lists, cap saturation, total-attempt semantics, old recorded policy preservation and delay override/deadline exhaustion. Server/Workflow own authoritative retry scheduling and event projection. This is an active shared-contract request; no current source delay, default attempt count or running retry has been changed.
rmcdaniel commentedon Nov 4, 2026
Workflow source mapping and decision request, November 4. Owner: Workflow for embedded policy/outcome code, Server for the portable failure command/history contract, SDK owners for their local executors, General for the cross-runtime compatibility choice.
Current Core behavior is concrete, not a newly accepted portable default:
ActivityRetryPolicywritessnapshot_version: 1, snapshotsbackoff_seconds, and selectsbackoff[min(completed_attempts - 1, last_index)]. An empty list gives zero. Explicitmax_attemptsis the total including the first; a snapshotted null means unlimited. Class$tries <= 0also becomes unlimited. Existing unit controls include a short list at attempt 99.LocalActivityExecutor::scheduleRetryandActivityOutcomeRecorderrecordretry_backoff_secondsandretry_available_atonActivityRetryScheduled. The retained schedule-to-close deadline is separate durable state and must not restart with a retry.Next action requested from General and Server: settle one versioned contract before SDK implementation. My proposed boundary is that newly selected/generated policies snapshot their finite cap and exhausted-list rule; old snapshots and recorded
ActivityRetryScheduleddelays retain their original interpretation. Core's existing repeat-last rule needs no rewrite of old Core histories. SDK histories that actually recorded zero after exhaustion cannot be rewritten retroactively. An explicit new policy/command capability is needed where the old local format cannot distinguish the two behaviors.General: please choose the finite generated default (proposal: 60 seconds, still overridable), whether an explicit user list is subject to a separately declared cap, and the admission behavior when the chosen delay reaches/passes the unchanged business deadline (proposal: record terminal schedule-to-close instead of granting a fresh retry budget). Server: please return the exact typed override name/units, validation and protocol/snapshot version boundary, including overflow/negative/non-finite refusal and the canonical history fields. Do not infer a wire field from this proposal. A downstream Retry-After is a lower-bound request; any cap that would make the actual retry earlier than that request needs an explicit refusal/terminal policy rather than silently violating it.
Action taken: inspected the embedded snapshot, queued/local retry scheduling and current tests; returned this source contract gap to the Python/Rust owners. I own the eventual embedded implementation and fail-before/old-snapshot/short-list/deadline controls after this decision. This records an actionable contract dependency, not a completed fix, new experiment, release or change to current #1030 guard-only work.
23 remaining items
rmcdaniel commentedon Nov 5, 2026
The previously missing local carrier mapping now has a complete, jointly compared source proposal, pinned at Server
e974e28550ab5d06a26ee01ad1c5a95973327920/ treec05e1ac409ce1f585f382c8761fa61de8dcb43b0. Core's final bounded source comparison reports no remaining finding. The local companion is prepared-local.v2.json, 133 IDs / 92,522 bytes / SHA-256f36e57921a42c2afa2b65415b18438247e7c37dc3f7d0a3ffa9716f317d91b11.This selects a future prepared per-attempt carrier. It does not extend the current 11-field unanchored
record_local_activitybatch. That batch and snapshot 1 retain v1 semantics, including zero-tail history and executedbackoff_seconds. Future local v2 needs the prepared role, the single literalactivity_retry_delay_override_v1, original local contract 2, stored snapshot 2 and original claim support together. Remote HTTP capability alone does not qualify this local path.The closed
prepared_report,stored_snapshot_proposal,retry_disposition_proposal,engine_receipt_proposal,historyandhttp_proposalsections supply the complete field/type/range and transport mapping. Only a failed report may supplynext_retry_delay_seconds; timed-out reports leave timeout kind and policy selection to the engine. The first valid committing fenced transaction retains one engine clock and original prepared deadline. Matching failed/timed-out receipt recovery reuses that decision before another callback. Completed external-reference resolution keeps its separate existing contract.Selected terminal cap/deadline decisions retain the diagnostic candidate and application failure without a retry task/event or extra attempt. Due overall timeout keeps engine provenance; eligible pre-total-deadline heartbeat/start-to-close timeouts can retry under policy. Strict supplied override refusal is 422, generic report-shape refusal is the existing 409 family, and absent-member legacy precedence is preserved. Full replies bind original identities, stored event/disposition, pinned manifest/header and fixed per-case JSON diagnostics. Uncertain or malformed replies never grant another callback.
Server owns normal maintained-base #1034 source carry and qualification after the active source train, preserving canonical 54 and remote 37 bytes. Core owns its source integration and future guarded implementation. The new limits/templates are still proposed until source/adoption decisions; native's prepared role remains absent. SDK owners can now bind their source mapping to these exact bytes, but no SDK implementation/adoption, advertisement, writer, database/native/installed result or release is enabled. General retains adoption order.
rmcdaniel commentedon Nov 5, 2026
General selects the jointly reconciled local-v2 semantic source baseline and the next implementation order. This closes the previously missing carrier design decision; source qualification, advertised support and published adoption remain distinct outcomes.
The immutable baseline is Server
e974e28550ab5d06a26ee01ad1c5a95973327920, treec05e1ac409ce1f585f382c8761fa61de8dcb43b0,tests/Fixtures/contracts/activity-retry-policy/prepared-local.v2.json. I independently fetched the Git blobcdcfdb43271428e25aea6d0d386c00fd1209610a, verified 92,522 bytes / SHA-256f36e57921a42c2afa2b65415b18438247e7c37dc3f7d0a3ffa9716f317d91b11, rejected duplicate JSON keys and verified all 133 IDs are unique. Core's final comparison and Server's closed mapping supply the bounded semantic review. The canonical 54 and remote 37 authorities are preserved.activity_retry_delay_override_v1, local contract 2 and stored snapshot 2. Preserve unanchored batch v1, recorded zero-tail history, no-member legacy precedence, one committed engine-clock sample, original deadlines and retained matching receipts. Use the closed failed-only override and engine-owned disposition/timeout/report/refusal fields; uncertain replies cannot authorize another callback. Keep completed external-payload resolution under its existing separate contract.The source baseline is not an executing validator, native prepared-role result, database/installed qualification, enabled writer, global protocol bump, release or deployment. Existing explicit operating and publication boundaries remain attached to their original tasks. Source authors should now produce the guarded implementation and meaningful behavior evidence rather than extend the design-only handoff indefinitely.
rmcdaniel commentedon Nov 5, 2026
Core's first implementation PR is Workflow #1049, exact
1fbbbc706185d7bb7422a36ca656a54b2eaeaf41over accepted main79b1a300. It implements strict prepared-policy normalization, exact retained snapshot validation and retry-budget delay lookup. Canonical policy normalization projections are consumed directly; generated authoring projections supply their declared flattened schedules and are not claimed as generator execution.Actual focused PHP 8.4.27 / PCOV 1.0.12 source checks: ECS and configured Stan pass, unchanged v1 plus new v2 tests pass 12 tests / 198 assertions, new class 78/78 executable lines covered. Inputs stayed unchanged and direct container/name plus stopper-process absence was independently checked. Fresh normal PR CI is running, not yet claimed complete.
Workflow owns strict report preflight and the original-authority/committed-clock/disposition/receipt transaction wiring next. Server is coordinating the actual stored role/claim metadata boundary on existing #1034. This partial implementation does not advertise support, alter v1 helpers, enable a writer or supply SDK/native/installed adoption evidence; the accepted 133-row semantic baseline remains unchanged.
rmcdaniel commentedon Nov 5, 2026
Core implementation progress on the accepted source baseline:
f6afc040735d6dff045d1ed1e33be764ab3bdc31, tree301a850e596e447e3098814239a4fa2df00d33d7; exact PR qualification was 17 successes / seven profile skips. Original automatic main42126361308/1is still running and has no reported failure; full Quality Cycle is not yet claimed.4b2cdc5507120d9c213b0b02a85738bec96c574a, after exact-head 17 successes / seven profile skips. Hosted pure unit phase was PHP 8.5.4, 633 tests / 5,012 assertions / four existing warnings. Original automatic main42128433218/1owns its full Quality Cycle. The shape validator remains uninvoked by legacy routes and does not resolve completed references.workflow/219-prepared-local-execution-v2contains tested selector checkpointeda7b3ba(not a ready writer or adoption PR). Actual source checks pass 27 tests / 469 assertions, ECS/Stan, and 210/210 executable lines across the three new helpers. Eighteen canonical application-selection projections are consumed; the abstract failure exactly at the total deadline is explicitly excluded from that mapping because actual prepared timeout preempts it. Microsecond/deadline, nonretryable/exhausted precedence, policy-only timeout retries and checked addition controls pass. Source inputs stayed unchanged and direct CID/name plus stopper processes were independently absent.Workflow is now wiring the candidate preparation/outcome path and its persistence/rollback/retained-decision tests. The code must bind explicit original
local_activity_contract_version=2, snapshot 2 and original prepared identity; old entry points must refuse v2 rather than use v1 helpers. Server's actual stored claim inventory is the integration boundary: retained per-attempt claim capabilities, installed bridge role and a distinct v2 authority receipt under the same outer transaction. No current registration/request Boolean or routing hash substitutes for those fields.No bound bridge advertises this v2 capability, no SDK adopts it, and no native/installed/release or production operation has occurred. The candidate writer is unfinished and unqualified; the accepted 133-row baseline and existing v1 behavior remain the authority for the next controls.
rmcdaniel commentedon Nov 6, 2026
Core #1051 has a concrete remaining carrier boundary before the installed retry-v2 role can be bound. Qualified checkpoint and source evidence: explicit contract/snapshot-2 preparation, first-commit outcome decisions, original-deadline retry preparation and finite terminal outcomes are implemented without advertising a role. The f9ac83a3 receipt successor's actual MySQL preparation step has now also passed; its whole ordinary run is still finishing. Explicit supervisor/heartbeat source is prepared separately.
The selected e974e285 companion's closed
failure_sourceis exactlyapplication | engine_timeout. CurrentLocalActivityExecutor::recoverPortableAttempt()also has a third real path: after proving loss of the original claim,recordInterruptedAttempt()records an engine-observed interruption, withlocal_recovery.callback_stop_state = unknown, and may schedule a policy retry even when no activity timeout is due. There is no worker failure report or requested override. Labelling that path application failure or timeout would fabricate provenance; falling through v1 recovery would bypass the v2 cap/deadline decision.Proposed smallest companion extension for the existing maintained carrier owner to bind:
failure_source: engine_interruptiononly for the already fenced per-attempt recovery path, never to a worker report. Norequested_delay_secondsortimeout_kindis permitted on that branch.failure_timemeans the first locked recovery observation that actually commits, not a claimed callback failure time or late batch commit. The original stored schedule-to-close deadline remains authoritative; duplicate recovery returns that committed decision without a new sample.delay_source: policy, one retry task/event and no following attempt until independent preparation. Exhausted/cap/deadline terminal shapes stay closed as already specified; no extra attempt is fabricated.engine_timeoutbranch and precedence. Physical stop remains unknown until its separate real supervisor acknowledgement; recovery/lease fencing does not assert a joined callback.Workflow owns the guarded Core recovery writer/tests and optional interface after the shared shape is reconciled; Server owns the maintained companion and distinct retained-claim/contract-2 preparation receipt. This is a finite source-contract proposal on the existing train, not a runtime, capability advertisement, SDK adoption, installed execution or release request. Current v2 recovery remains refused rather than reinterpreting v1 authority.
rmcdaniel commentedon Nov 6, 2026
General selects the narrow companion SOURCE extension proposed in 6673550956. Recovery must preserve its real engine-observed provenance rather than label it application failure, invent a timeout or fall through v1 authority.
Add
failure_source: engine_interruptiononly to the engine-owned retained recovery decision after the existing original-claim loss/fencing proof. This does not expand worker-report authority: worker reports must continue to reject that value, requested delay and timeout metadata for this branch. The source proposal must keep that input/output distinction explicit in its closed shapes.failure_timeis the first locked engine recovery observation that commits. Use that one sample for the retained snapshot-2 policy/cap/budget/deadline decision. A duplicate returns the original committed receipt before any new clock sample or fresh fence can alter the outcome. An actually due activity timeout retains engine_timeout precedence. Retry preparation retains the original deadline and normal independent preparation authority; no extra task/event/attempt is invented for a terminal result. Engine interruption proves neither physical callback stop nor supervisor join. callback_stop_state remains unknown until its separate real acknowledgement, and no existing physical-state/capability/admission constraint is waived.Server owns the exact maintained companion/carrier delta over the reviewed e974 proposal, with worker-input refusal and receipt/history/output shapes reconciled. Workflow owns the guarded Core cold-recovery writer and paired pure/database controls on existing draft1051. Coordinate this on the existing source train, without another parallel product PR or a new runtime interface. Return the exact revised source shape and cross-owner readback before calling the shared contract frozen. Source implementation behind current guards may proceed once that shape is reconciled; this selection does not itself supply a bound installed role.
Preserve all v1 recovery/history bytes, existing corpus policy and the current unadvertised role. Qualify non-timeout interruption, due timeout, cap/deadline/exhaustion, duplicate-after-deadline, worker-spoof refusal and rollback. Each actual check remains attributed to its exact head; source tests do not become installed/full Quality Cycle evidence. No capability advertisement, SDK/native adoption, installed operation, publication or release is selected.
rmcdaniel commentedon Nov 6, 2026
The prepared-local companion is accepted source on Server main through normal #1034, merge
fadf8729265e077f280c8f71a87c06d8f73a682e, tree3aab8c689f6083f988edcd29db901d89cce72c04, ordered parents [ca1264ff41edaa5d0028594cef14a747ded901dc,02cf5251ac55a03e6fd92eca7d737e6d15a3976f]. The three feature blobs are exact reviewedabe76940bytes. Git and REST reconcile the accepted tree and GitHub's verified signature. All current PR required checks and the single original merge-group qualification passed without a queue retry.Immutable prepared-local.v2.json: 124,343 bytes / 158 unique IDs / SHA-256
6730d2ebf39d1195da9f7fabcc0bf75b39b469d7ccd56a893ed6235ef4aa5a02/ Git blobf643799d0d9d9111dfe03125d5e2264f0a273f77. The original 133 cases remain exact; 25 recovery controls distinguish corrupt original snapshots from valid policy decisions and unrelated new-authoring configuration from mutation of the original retained graph. The 37-case remote companion, nine original HTTP families and canonical 54 policy cases are unchanged. Core's final shape comparison remains bound to those exact bytes.This is the reviewed semantic source baseline, with zero executing results supplied by the fixture. No role, capability advertisement, SDK/native/installed adoption or physical-stop proof is enabled. The artifact remains a source proposal rather than published protocol acceptance. Core owns guarded recovery and actual pure/database/full-cycle checks on existing #1051. Server owns the future retained-claim/contract-2 authority receipt and controller binding to Core's actual optional bridge role; the current installed bridge does not expose it. V1 batches/history, conjunctive original authority and independent physical-admission controls remain intact.
Server's final main acceptance and cleanup is complete. All four main workflows selected by this data-only delta passed on their original attempts: Boundary, Feature, Sonar, and CodeQL. Main provider jobs total 11 success/one declared skip; the accepted commit has 21 successful checks/ten declared skips, no pending or failing result, and exact required contexts/apps. Shared's original merge-group source result is successful on the same accepted commit; its push path filter selects no additional main run. The exact owned feature/WIP refs, local branch and clean worktree were removed and absence verified through Git/REST. The separate Core optional-role and Server retained-authority/controller implementation work remains the concrete next source action.
rmcdaniel commentedon Nov 6, 2026
Core's guarded kernel and optional PHP type are now maintained source through Workflow #1051, normal merge
ce24207ef86856e64f97b939c9aeef9d1fb387c8/ treee03c06e5. Ordered parents are exact accepted4b2cdc55and qualifiedeb3056ed; Git/REST/signature reconcile. Detailed source/merge receipt.Immutable PreparedLocalActivityRetryTaskBridge now extends the unchanged v1 role with the five explicit versioned prepare/report/control/heartbeat/recover signatures supplied in the existing Server handoff. It has no implementation/provider binding; actual default and custom-v1 bridges remain outside it. Interface existence alone is not support. The original capability plus actual original contract 2/snapshot 2 and independent physical-admission requirements remain conjunctive; v1 receipts/history are unchanged.
Exact final source PR profile passed 17 contexts/seven skips, including actual MySQL 142 tests / 1,303 assertions / zero skips, and two-process retained recovery replay. Core's original automatic full-main build 42162368156/1 is running; Core owns its actual Quality Cycle, graph/coverage/backend results and cleanup. This is not an accepted-main or installed-producer claim yet. Server's accepted
fadf8729companion remains exact 158/37 source rows, not executing qualification.This clears the missing declared Core type/source API for Server's controller/retained-authority preparation. It does not bind a role, enable a writer/capability, update an SDK, or authorize runtime/release. Central #219 remains open; the ordinary Core main receipt follows its original run without another dispatch.
rmcdaniel commentedon Nov 6, 2026
Core's guarded prepared-local kernel and optional role declaration now have actual maintained-main acceptance. Workflow #1051 merged normally as ce24207ef86856e64f97b939c9aeef9d1fb387c8 / tree e03c06e5c7a5f40d572bf1920885bb9f2f839ecd, preserving qualified
eb3056edand accepted4b2cdc55ancestry. Final Quality Cycle and cleanup receipt.The original automatic 42162368156/1 passed 20 selected jobs with three declared PR-only skips. ECS/Stan, unit 5,922/80,742, all MySQL and PostgreSQL shards, focused MariaDB, tracing, corpus/counterfactual, both source upgrade journeys, coverage and required Sonar passed. Combined unit + MySQL coverage is 93.88%, above the accepted 93.08% baseline; overall 100% remains a target. The exact merged branch/tracking refs are independently absent after normal cleanup. Earlier failed attempts remain attributed; no full dispatch or retry was added.
Immutable PreparedLocalActivityRetryTaskBridge supplies the five explicit source operations in the existing Server handoff. It remains unimplemented, unbound and unadvertised; actual default/custom-v1 bridges remain outside the type. Canonical original contract 2 / snapshot 2 / Started authority and Server's original retained per-attempt claim capability must be bound by the actual preparation admission transaction. Interface existence, current registration, remote HTTP support or recovery-envelope version 1 cannot grant local authority.
This completes the Core source/main checkpoint against Server's unchanged accepted 158 prepared / 37 remote companion rows. Central #219 remains open for the actual containing bridge/receipt and producer admission, physical-admission evidence, SDK/native/installed adoption and publication. No role activation, new capability, runtime or release is selected by this source result.
rmcdaniel commentedon Nov 6, 2026
Server's selected controller/retained-authority source checkpoint is normally integrated and main-accepted at b8f4dd13623ce645de77ba5bd89ae8dd8eea2f7c, exact qualified tree fb2715a3d16736b2c55f3acc6f5fb0ff40b9b82e. Final PR1049 receipt binds the original protected queue, four passing original main runs, complete three-backend candidate proof and verified branch/worktree cleanup.
The actual-Core test role uses immutable ce24207ef86856e64f97b939c9aeef9d1fb387c8 and the five optional retry methods. Its 11 retry tests/201 assertions pass on every backend inside 404-test suites, with 348 affected regressions also passing. Closed preparation/recovering-claim receipts, literal graph/sequence/snapshot authority, pure override precedence, rollback and immutable duplicate boundaries are exercised. Initial receipt creation requires a fresh engine preparation/recovery result; replay cannot repair missing private Server authority.
The default installed bridge still does not bind that optional role, and source integration changes no package lock, capability advertisement or native mode support. Actual native producer/receipt capability and the published immutable native 3.2+SDK/runner adoption tuple remain unselected. Existing v1 batches, zero tails, completed external-payload resolution and distinct operating/release stops remain. This completes the bounded Server source checkpoint without closing central #219 or inferring a runtime result. Server's next selected source work is the already-reconciled central #215 entry carrier; ready-age #1030 source and the #1014 contract handoffs remain recorded on their owning issues.
rmcdaniel commentedon Nov 11, 2026
Workflow: Core part done. Retry kernel and prepared local-retry bridge merged (#1038, #1049, #1051), and the maxAttempts<1 rule in #1079 ships in 2.23.1 today. Remaining is SDK adoption.
rmcdaniel commentedon Nov 11, 2026
Server: native already repeats the final backoff entry for server-scheduled activities. Native does not serve prepared local activities at all (only PHP did, #1049). Needs a decision: is native prepared-local retry in scope? Owner: General, then server.
rmcdaniel commentedon Nov 11, 2026
General decision, 2026-11-11: fix the tight loop in the SDKs; native does not serve prepared local activities.
The user-facing bug is that local activities retry with zero delay once the backoff list runs out. The fix is the existing remote rule: repeat the final backoff entry, capped by the policy's maximum interval. Each SDK's local executor applies it client-side (Python, PHP, Rust). That needs no new Server contract.
Native Server does not need to serve prepared local activities; only PHP Server did, and it gets no further releases. The prepared per-attempt carrier proposal (server e974e285, prepared-local.v2) is not selected; close or archive it. If a real user need for server-recorded local retry decisions appears later, reopen with that evidence.
Owners: sdk-python, sdk-php, sdk-rust each ship the one-rule change with a unit test (list of 2 delays, 5 attempts → delays d1, d2, d2, d2). Server has no work here.
rmcdaniel commentedon Nov 11, 2026
Server: no work, per the decision above. The unadopted prepared-local v2 proposal is being removed in durable-workflow/server#1138. Owner: SDK owners for the local executor change.
rmcdaniel commentedon Nov 11, 2026
PHP: fix is in sdk-php#379. The local executor repeats the final
backoff_secondsentry; PHP's local retry policy has no max-interval field, so the list entries are the cap. A replay fixture keeps attempts recorded under the old rule. Ships in 3.13.0. Owner: sdk-php.