Skip to content

Legacy version fallback fails offline replay when a step already occupies the marker position #641

Description

@vanducng

Version: workflow 2.4.5, SDK 2.1.6.

A workflow history recorded before a new patched() call continues correctly through WorkflowExecutor, but ReplayDiff::diffExport() reports shape_mismatch for the same history. QueryStateReplayer asserts a version-marker shape before VersionResolver can return the legacy default. The legacy default records no marker and does not advance the workflow sequence, so the existing activity or timer at that position is valid.

Reproduction:

  1. Record an embedded workflow history that completes an activity and waits on a timer.
  2. Add patched('change-id') before an already-recorded activity or timer, retaining the old branch when it returns false. Ensure the workflow definition fingerprint changes.
  3. Import the original bundle and continue with sticky execution disabled. The runtime keeps the old branch and completes.
  4. Run ReplayDiff::diffExport() against the unchanged bundle. It returns drifted, reason=shape_mismatch, expected_shape=version marker, with the original activity/timer event types at that position.

Expected: offline replay applies the same conservative fallback as the runtime and matches the existing step.

Source: QueryStateReplayer, lines 325-334 asserts first. WorkflowExecutor, lines 704-734 resolves first and asserts only when advancesSequence is true.

Suggested fix: resolve the version before asserting its shape in QueryStateReplayer; assert only when the resolution occupies a history slot. Add a frozen pre-marker offline replay regression while retaining malformed-marker and genuine step-drift refusals.

Activity

  1. added
    authority:githubGitHub is the authoritative lifecycle record for this work
    completion:evidence-requiredClose only after all explicit acceptance and operational evidence is public
    priority:untriagedMaintainers have not assigned a priority
    status:triageAwaiting maintainer classification
    intake:approvedCurrent issue title and body revision is approved for authority intake
    priority:P1High-priority product or release risk
    bugSomething isn't working
    kind:defectA public product behavior is incorrect
    status:in-progressApproved work is actively being implemented or validated
    and removed
    priority:untriagedMaintainers have not assigned a priority
    status:triageAwaiting maintainer classification
    on Oct 7, 2026
  2. rmcdaniel commented on Oct 7, 2026

    @rmcdaniel
    Member

    Fixed and verified in Workflow 2.5.1 and Server 2.5.7.

    Legacy fallback preserves the existing activity or timer position during queries and offline replay. Malformed markers and genuine step drift remain rejected.

    The registry-installed package passes all 20 frozen-history cases with 216 assertions and published Laravel 9–13 upgrade checks. The published Server image passes 31 PHP/Python/Rust replay scenarios and all 15 schedule cells without findings. Sample App, Waterline qualification and the live website installation defaults are updated and verified.

    Implementation and regression coverage: #643. Published image and consumer qualification: Server #309.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    authority:githubGitHub is the authoritative lifecycle record for this workbugSomething isn't workingcompletion:evidence-requiredClose only after all explicit acceptance and operational evidence is publicintake:approvedCurrent issue title and body revision is approved for authority intakekind:defectA public product behavior is incorrectpriority:P1High-priority product or release riskstatus:in-progressApproved work is actively being implemented or validated

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions