Skip to content

Commit 5b6ad4e

Browse files
Prefer matching task type when resolving wait → task references
RunWaitView::preferredTasksByPayloadKey picked the single most recently updated task whose payload carried the wait's identity key, regardless of task type. Workflow-resume tasks also carry activity_execution_id / timer_id in their payloads, and their updated_at is strictly later than the activity or timer task they resume, so the activity and timer wait projections ended up reporting task_type='workflow' instead of 'activity' or 'timer' (bucket C — semantic drift in projections). Accept an optional TaskType filter so callers bind the wait kind to the matching task kind. Activity waits now require Activity tasks and timer waits require Timer tasks. Also carry the MessageCursorAdvanced event through the completed-signal run-detail timeline fixture — a real event now emitted between SignalReceived and SignalApplied as of the message-stream cursor work. Refs #399 (bucket C) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 825bf62 commit 5b6ad4e

2 files changed

Lines changed: 18 additions & 5 deletions

File tree

src/V2/Support/RunWaitView.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Workflow\V2\Enums\ActivityStatus;
99
use Workflow\V2\Enums\RunStatus;
1010
use Workflow\V2\Enums\TaskStatus;
11+
use Workflow\V2\Enums\TaskType;
1112
use Workflow\V2\Models\WorkflowCommand;
1213
use Workflow\V2\Models\WorkflowHistoryEvent;
1314
use Workflow\V2\Models\WorkflowRun;
@@ -31,8 +32,12 @@ public static function forRun(WorkflowRun $run): array
3132
'childLinks.childRun.historyEvents',
3233
]);
3334

34-
$taskByActivityExecutionId = self::preferredTasksByPayloadKey($run, 'activity_execution_id');
35-
$taskByTimerId = self::preferredTasksByPayloadKey($run, 'timer_id');
35+
$taskByActivityExecutionId = self::preferredTasksByPayloadKey(
36+
$run,
37+
'activity_execution_id',
38+
TaskType::Activity
39+
);
40+
$taskByTimerId = self::preferredTasksByPayloadKey($run, 'timer_id', TaskType::Timer);
3641
$taskByChildCallId = self::preferredTasksByPayloadKey($run, 'child_call_id');
3742
$taskByChildRunId = self::preferredTasksByPayloadKey($run, 'child_workflow_run_id');
3843
$conditionWaits = ConditionWaits::forRun($run);
@@ -521,15 +526,22 @@ private static function diagnosticOnly(?string $historyAuthority, ?string $unsup
521526
/**
522527
* @return array<string, WorkflowTask>
523528
*/
524-
private static function preferredTasksByPayloadKey(WorkflowRun $run, string $payloadKey): array
525-
{
529+
private static function preferredTasksByPayloadKey(
530+
WorkflowRun $run,
531+
string $payloadKey,
532+
?TaskType $requiredType = null,
533+
): array {
526534
$tasks = [];
527535

528536
foreach ($run->tasks as $task) {
529537
if (! $task instanceof WorkflowTask) {
530538
continue;
531539
}
532540

541+
if ($requiredType !== null && $task->task_type !== $requiredType) {
542+
continue;
543+
}
544+
533545
$payloadId = self::stringValue($task->payload[$payloadKey] ?? null);
534546

535547
if ($payloadId === null) {

tests/Feature/V2/V2RunDetailViewTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,14 +1188,15 @@ public function testRunDetailViewIncludesCommandsActivitiesAndTimelineForComplet
11881188
'WorkflowStarted',
11891189
'SignalWaitOpened',
11901190
'SignalReceived',
1191+
'MessageCursorAdvanced',
11911192
'SignalApplied',
11921193
'ActivityScheduled',
11931194
'ActivityStarted',
11941195
'ActivityCompleted',
11951196
'WorkflowCompleted',
11961197
], array_column($detail['timeline'], 'type'));
11971198
$this->assertSame(
1198-
[1, 1, null, 2, 2, null, null, null, null],
1199+
[1, 1, null, 2, null, 2, null, null, null, null],
11991200
array_column($detail['timeline'], 'command_sequence')
12001201
);
12011202
}

0 commit comments

Comments
 (0)