@@ -387,6 +387,68 @@ public function testSnapshotSummarizesDurableBacklogRepairCompatibilityAndWorker
387387 $ this ->assertSame (10 * 1000 , $ taskTransport ['data ' ]['max_dispatch_overdue_age_ms ' ]);
388388 }
389389
390+ public function testHealthSnapshotScopesOperatorMetricsToRequestedNamespace (): void
391+ {
392+ Carbon::setTestNow ('2026-04-09 12:00:00 ' );
393+ $ this ->beforeApplicationDestroyed (static function (): void {
394+ Carbon::setTestNow ();
395+ });
396+
397+ $ alphaRun = $ this ->createRunWithSummary (
398+ instanceId: 'health-scope-alpha-instance ' ,
399+ runId: '01JHEALTHSCOPEALPHA000001 ' ,
400+ status: 'running ' ,
401+ statusBucket: 'running ' ,
402+ livenessState: 'running ' ,
403+ namespace: 'alpha ' ,
404+ );
405+ $ betaRun = $ this ->createRunWithSummary (
406+ instanceId: 'health-scope-beta-instance ' ,
407+ runId: '01JHEALTHSCOPEBETA000002X ' ,
408+ status: 'waiting ' ,
409+ statusBucket: 'running ' ,
410+ livenessState: 'repair_needed ' ,
411+ namespace: 'beta ' ,
412+ );
413+
414+ $ this ->createTask ($ alphaRun , '01JHTASKSCOPEALPHA000001X ' , TaskStatus::Ready->value , [
415+ 'available_at ' => now ()
416+ ->subSecond (),
417+ ]);
418+ $ this ->createTask ($ betaRun , '01JHTASKSCOPEBETA000002XX ' , TaskStatus::Ready->value , [
419+ 'available_at ' => now ()
420+ ->subSeconds (10 ),
421+ 'last_dispatch_attempt_at ' => now ()
422+ ->subSecond (),
423+ 'last_dispatch_error ' => 'Queue transport unavailable. ' ,
424+ ]);
425+
426+ $ alphaSnapshot = HealthCheck::snapshot (Carbon::now (), 'alpha ' );
427+ $ betaSnapshot = HealthCheck::snapshot (Carbon::now (), 'beta ' );
428+
429+ $ this ->assertSame (1 , $ alphaSnapshot ['operator_metrics ' ]['runs ' ]['total ' ]);
430+ $ this ->assertSame (0 , $ alphaSnapshot ['operator_metrics ' ]['runs ' ]['repair_needed ' ]);
431+ $ this ->assertSame (1 , $ alphaSnapshot ['operator_metrics ' ]['tasks ' ]['ready_due ' ]);
432+ $ this ->assertSame (0 , $ alphaSnapshot ['operator_metrics ' ]['tasks ' ]['dispatch_failed ' ]);
433+ $ this ->assertSame (
434+ now ()
435+ ->subSecond ()
436+ ->toJSON (),
437+ $ alphaSnapshot ['operator_metrics ' ]['tasks ' ]['oldest_ready_due_at ' ]
438+ );
439+
440+ $ this ->assertSame (1 , $ betaSnapshot ['operator_metrics ' ]['runs ' ]['total ' ]);
441+ $ this ->assertSame (1 , $ betaSnapshot ['operator_metrics ' ]['runs ' ]['repair_needed ' ]);
442+ $ this ->assertSame (1 , $ betaSnapshot ['operator_metrics ' ]['tasks ' ]['dispatch_failed ' ]);
443+ $ this ->assertSame (1 , $ betaSnapshot ['operator_metrics ' ]['tasks ' ]['ready_due ' ]);
444+ $ this ->assertSame (
445+ now ()
446+ ->subSeconds (10 )
447+ ->toJSON (),
448+ $ betaSnapshot ['operator_metrics ' ]['tasks ' ]['oldest_ready_due_at ' ]
449+ );
450+ }
451+
390452 public function testSnapshotCountsStaleRunSummaryProjectionRows (): void
391453 {
392454 $ run = $ this ->createRunWithSummary (
@@ -2247,9 +2309,11 @@ private function createRunWithSummary(
22472309 ?string $ connection = null ,
22482310 ?string $ queue = null ,
22492311 ?string $ compatibility = null ,
2312+ ?string $ namespace = null ,
22502313 ): WorkflowRun {
22512314 $ instance = WorkflowInstance::query ()->create ([
22522315 'id ' => $ instanceId ,
2316+ 'namespace ' => $ namespace ,
22532317 'workflow_class ' => 'WorkflowClass ' ,
22542318 'workflow_type ' => 'workflow.test ' ,
22552319 'run_count ' => 1 ,
@@ -2263,6 +2327,7 @@ private function createRunWithSummary(
22632327 'workflow_class ' => 'WorkflowClass ' ,
22642328 'workflow_type ' => 'workflow.test ' ,
22652329 'status ' => $ status ,
2330+ 'namespace ' => $ namespace ,
22662331 'connection ' => $ connection ,
22672332 'queue ' => $ queue ,
22682333 'compatibility ' => $ compatibility ,
@@ -2286,6 +2351,7 @@ private function createRunWithSummary(
22862351 'workflow_type ' => 'workflow.test ' ,
22872352 'status ' => $ status ,
22882353 'status_bucket ' => $ statusBucket ,
2354+ 'namespace ' => $ namespace ,
22892355 'started_at ' => now ()
22902356 ->subMinutes (10 ),
22912357 'liveness_state ' => $ livenessState ,
0 commit comments