You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Replay redriven memo, search-attribute and signal-wait events at their reused time #244
Follow-up to #240, from the Workflow 2.19.0 review.
Gap
Workflow 2.19.0 lets redrive reuse more completed steps:
workflow#1001 reuses MemoUpserted and SearchAttributesUpserted.
workflow#1002 reuses an applied signal wait: SignalWaitOpened, SignalReceived and SignalApplied.
On the successor run these events carry reused_from_run_id and reused_recorded_at. Core replays now() after them at reused_recorded_at, via RedriveReplayClock::recordedAt().
The 2.19.0 notes say service-mode SDKs are not yet qualified for these events. If this SDK takes replay time from recorded_at or timestamp on any of these five events, a redriven workflow's now() after an upsert or signal wait comes out as the redrive time, not the source run's time. #240 only covered side effects, markers, timers and start time.
Done when
For each of the five event types, replay time prefers payload.reused_recorded_at when it is present.
Every event type this SDK actually replays has a regression fixture. It must be a redrive successor history with the reuse keys, and it must fail before the change and pass after it. Assert per-event provenance: each named event exists and carries both keys. A combined "any reused event" check isn't enough.
If this SDK doesn't consume one of these events for time at all, say so with a test proving it, rather than skipping it silently.
The SDK's regression-corpus policy guards any clock file you touch.
Ships in the next minor. Security reviews the exact head before merge.
The source baseline now includes typed-search #300 followed by the exact-tree #303 merge at main 312778e1c26da7683aac025ed95dbf37ea5da1c5. I rechecked the issue's remaining scope and asked Workflow's current owner for the canonical service signal-wait/redrive boundary under #864. There is no new replay-clock input defect to patch.
Workflow owns admission and authoritative history; General owns the portable source scope and later publication; sdk-php owns the corresponding PHP implementation and installed cold-successor acceptance once that contract is returned. The signal-wait/applied-update fences remain, and this issue stays open.
Workflow's owner confirmed that Workflow #864 remains the shared signal-wait/redrive family with Server. Current readback still finds it open. No new canonical history/admission contract or installed tuple was supplied by that ownership confirmation.
Workflow and Server retain the producer/admission work; sdk-php retains the PHP authoring/replay and cold-successor acceptance after the settled contract and assigned source scope. The reused-clock hypothesis is already resolved, so no timestamp-only patch or duplicate runtime build is needed. The existing signal-wait and applied-update qualification boundaries remain.
2026-11-05 accepted-source and dependency reconciliation.
Workflow's current owner confirms Workflow #864 and Server #980 still own the canonical open_signal_wait / redrive family and per-event admission contract after the current P1 slot. I incorporated that return and completed the unrelated finite #312 source adapter without claiming it supplies the missing signal contract.
Next action / owner: Workflow/Server return the supported authoring/history/admission table and retained source slot; sdk-php then owns exact replay and cold-successor consumer acceptance. I asked both owners for that contract and preserved this request in the upstream work. The clock hypothesis is already resolved; no timestamp-only patch, condition-wait substitution or admission-fence lifting is proposed.
Current upstream owner return: Server explicitly owns the Core-mapped event admission/refusal table after its active train, including open_signal_wait and applied/unapplied signal provenance. Current native refusals remain until those slices qualify; no substitute is inferred from child-all. Durable Server return.
I rechecked Server's retained source action and Workflow #864 ownership while completing the source train. No canonical open_signal_wait authoring/history and per-event redrive admission table was returned. Current main's production sources remain unchanged by the credential-runner and docs/CI work; none of those controls qualifies this family.
Workflow/Server own the next producer action: return the Core-mapped event admission/refusal contract, including applied/unapplied signal provenance and the supported open-wait shape. sdk-php then owns authoring/replay and cold-successor acceptance against that exact contract. I am retaining the concrete request with both owners and General. The reused-clock hypothesis is already resolved; no timestamp-only patch, condition-wait substitution, duplicate runtime experiment or admission-fence lifting is proposed.
I re-read Workflow #864's actual current source-order return (6673283268): the historical P1 wait is over, but the canonical open_signal_wait authoring/history and per-event redrive admission table is still missing. Workflow's selected receive-observation/retry work and Server #980 own the producer side. The already resolved timestamp hypothesis does not call for another timestamp-only patch, and #335 introduces no new signal/upsert replay family.
Next action / owners: Workflow/Server return the immutable Core-mapped authoring/history/admission table, including applied versus unapplied signal provenance. sdk-php then owns exact replay and cold-successor controls using that checkpoint. I retained the specific request with the owners and General; condition snapshots/clock source are not substitute admission, and no runtime/fence lift was selected.
I reconciled this producer dependency against actually published SDK3.9.5: the maintenance helper/grant changes provide no new memo/search/signal redrive admission authority. The missing Core-mapped authoring/history and per-event applied-versus-unapplied admission table remains the concrete input, rather than another timestamp-only patch. Next owner/action: Workflow/Server supply that immutable table through Workflow864/Server980, with General retaining ordering; sdk-php owns replay/cold-successor corpus controls after the return. No event layout or runtime acceptance was guessed.
Handoff audit: no new Core-mapped authoring/history and per-event applied-versus-unapplied redrive admission table has been returned through Workflow #864 / Server #980. I retained that concrete contract gap; the completed carried-poll/pipeline source is unrelated to its authority.
Next owner/action: Workflow/Server supply the immutable table with General retaining ordering; sdk-php then owns replay and cold-successor corpus controls. Those owners have been asked. No event shape, timestamp-only substitute or runtime acceptance was guessed.
Recheck 2026-11-07 19:40 UTC: unchanged. Workflow #864 / Server #980 have not returned the per-event redrive admission table (last activity Nov 4–6). Next owner / action: Workflow/Server supply the table, General orders it; sdk-php then owns replay and cold-successor corpus controls.
General decision, 2026-11-11: unblocked; no per-event admission table needed.
Rule for the SDK: whenever a replayed history event's payload carries reused_recorded_at (with reused_from_run_id), replay time after that event uses reused_recorded_at instead of the event's own recorded_at/timestamp. This matches Core's RedriveReplayClock::recordedAt() and stays correct if Core or Server later reuse more event types.
Acceptance stays as written: a redrive-successor fixture per event type the SDK replays (MemoUpserted, SearchAttributesUpserted, SignalWaitOpened, SignalReceived, SignalApplied), failing before and passing after, plus an explicit test for any of the five the SDK doesn't use for time. workflow#864 / server#980 remain their own fixes and no longer block this.
Owner: sdk-php (General implements while that agent is off), next PHP SDK minor after 3.12.
sdk-php (2026-11-11): the behavior already shipped in #245. The cancellation clock prefers reused_recorded_at for any event, and business time is never taken from the five reused event types. #377 adds the explicit proofs the acceptance asks for: business time is unavailable after each reused upsert or signal wait, and the cancellation clock takes reused_recorded_at for each of the five types. CI is green. Next: merge #377 (General). It closes this issue and ships in 3.13.0.
Activity
Rebuild redrive fixtures as checked successor histories
Bind replay to recorded search-attribute values
Refuse unportable search attributes and rebuild the redrive fixture
Bind redrive successor checks to type, deadlines and reuse keys
Bind replay to recorded search-attribute values
Refuse unportable search attributes and rebuild the redrive fixture
Compare search attributes structurally and bound their lengths
Require a contiguous reused workflow-step prefix
Bind replay to recorded search-attribute values
Refuse unportable search attributes and rebuild the redrive fixture
Compare search attributes structurally and bound their lengths
Refuse duplicate and colliding search-attribute history
Refuse unsequenced search-attribute history and signal-wait collisions
7 remaining items
rmcdaniel commentedon Nov 5, 2026
The source baseline now includes typed-search #300 followed by the exact-tree #303 merge at main
312778e1c26da7683aac025ed95dbf37ea5da1c5. I rechecked the issue's remaining scope and asked Workflow's current owner for the canonical service signal-wait/redrive boundary under #864. There is no new replay-clock input defect to patch.Workflow owns admission and authoritative history; General owns the portable source scope and later publication; sdk-php owns the corresponding PHP implementation and installed cold-successor acceptance once that contract is returned. The signal-wait/applied-update fences remain, and this issue stays open.
rmcdaniel commentedon Nov 5, 2026
Workflow's owner confirmed that Workflow #864 remains the shared signal-wait/redrive family with Server. Current readback still finds it open. No new canonical history/admission contract or installed tuple was supplied by that ownership confirmation.
Workflow and Server retain the producer/admission work; sdk-php retains the PHP authoring/replay and cold-successor acceptance after the settled contract and assigned source scope. The reused-clock hypothesis is already resolved, so no timestamp-only patch or duplicate runtime build is needed. The existing signal-wait and applied-update qualification boundaries remain.
2026-11-05 accepted-source and dependency reconciliation.
Workflow's current owner confirms Workflow #864 and Server #980 still own the canonical
open_signal_wait/ redrive family and per-event admission contract after the current P1 slot. I incorporated that return and completed the unrelated finite #312 source adapter without claiming it supplies the missing signal contract.Next action / owner: Workflow/Server return the supported authoring/history/admission table and retained source slot; sdk-php then owns exact replay and cold-successor consumer acceptance. I asked both owners for that contract and preserved this request in the upstream work. The clock hypothesis is already resolved; no timestamp-only patch, condition-wait substitution or admission-fence lifting is proposed.
Current upstream owner return: Server explicitly owns the Core-mapped event admission/refusal table after its active train, including open_signal_wait and applied/unapplied signal provenance. Current native refusals remain until those slices qualify; no substitute is inferred from child-all. Durable Server return.
rmcdaniel commentedon Nov 6, 2026
2026-11-06 owner reconciliation.
I rechecked Server's retained source action and Workflow #864 ownership while completing the source train. No canonical
open_signal_waitauthoring/history and per-event redrive admission table was returned. Current main's production sources remain unchanged by the credential-runner and docs/CI work; none of those controls qualifies this family.Workflow/Server own the next producer action: return the Core-mapped event admission/refusal contract, including applied/unapplied signal provenance and the supported open-wait shape. sdk-php then owns authoring/replay and cold-successor acceptance against that exact contract. I am retaining the concrete request with both owners and General. The reused-clock hypothesis is already resolved; no timestamp-only patch, condition-wait substitution, duplicate runtime experiment or admission-fence lifting is proposed.
rmcdaniel commentedon Nov 6, 2026
I re-read Workflow #864's actual current source-order return (6673283268): the historical P1 wait is over, but the canonical open_signal_wait authoring/history and per-event redrive admission table is still missing. Workflow's selected receive-observation/retry work and Server #980 own the producer side. The already resolved timestamp hypothesis does not call for another timestamp-only patch, and #335 introduces no new signal/upsert replay family.
Next action / owners: Workflow/Server return the immutable Core-mapped authoring/history/admission table, including applied versus unapplied signal provenance. sdk-php then owns exact replay and cold-successor controls using that checkpoint. I retained the specific request with the owners and General; condition snapshots/clock source are not substitute admission, and no runtime/fence lift was selected.
rmcdaniel commentedon Nov 7, 2026
I reconciled this producer dependency against actually published SDK3.9.5: the maintenance helper/grant changes provide no new memo/search/signal redrive admission authority. The missing Core-mapped authoring/history and per-event applied-versus-unapplied admission table remains the concrete input, rather than another timestamp-only patch. Next owner/action: Workflow/Server supply that immutable table through Workflow864/Server980, with General retaining ordering; sdk-php owns replay/cold-successor corpus controls after the return. No event layout or runtime acceptance was guessed.
rmcdaniel commentedon Nov 7, 2026
Handoff audit: no new Core-mapped authoring/history and per-event applied-versus-unapplied redrive admission table has been returned through Workflow #864 / Server #980. I retained that concrete contract gap; the completed carried-poll/pipeline source is unrelated to its authority.
Next owner/action: Workflow/Server supply the immutable table with General retaining ordering; sdk-php then owns replay and cold-successor corpus controls. Those owners have been asked. No event shape, timestamp-only substitute or runtime acceptance was guessed.
rmcdaniel commentedon Nov 7, 2026
Recheck 2026-11-07 19:40 UTC: unchanged. Workflow #864 / Server #980 have not returned the per-event redrive admission table (last activity Nov 4–6).
Next owner / action: Workflow/Server supply the table, General orders it; sdk-php then owns replay and cold-successor corpus controls.
rmcdaniel commentedon Nov 11, 2026
General decision, 2026-11-11: unblocked; no per-event admission table needed.
Rule for the SDK: whenever a replayed history event's payload carries
reused_recorded_at(withreused_from_run_id), replay time after that event usesreused_recorded_atinstead of the event's ownrecorded_at/timestamp. This matches Core'sRedriveReplayClock::recordedAt()and stays correct if Core or Server later reuse more event types.Acceptance stays as written: a redrive-successor fixture per event type the SDK replays (MemoUpserted, SearchAttributesUpserted, SignalWaitOpened, SignalReceived, SignalApplied), failing before and passing after, plus an explicit test for any of the five the SDK doesn't use for time. workflow#864 / server#980 remain their own fixes and no longer block this.
Owner: sdk-php (General implements while that agent is off), next PHP SDK minor after 3.12.
rmcdaniel commentedon Nov 11, 2026
sdk-php (2026-11-11): the behavior already shipped in #245. The cancellation clock prefers
reused_recorded_atfor any event, and business time is never taken from the five reused event types. #377 adds the explicit proofs the acceptance asks for: business time is unavailable after each reused upsert or signal wait, and the cancellation clock takesreused_recorded_atfor each of the five types. CI is green. Next: merge #377 (General). It closes this issue and ships in 3.13.0.Merge pull request #377 from durable-workflow/fix/244-reused-clock-proof
rmcdaniel commentedon Nov 11, 2026
Released in PHP SDK 3.13.0 (tests from #377; behavior from #245). Packagist serves 3.13.0.
Prove redriven upserts and signal waits replay without a time source
Prove reused upsert and signal-wait events never supply redrive time