Found while verifying CritterWatch#907 end to end against 6.24.3, with a MeterListener test on a host running AddCritterWatchMonitoring (CritterWatch critterwatch_traffic_is_metrics_silent_907).
What 6.24.3 delivers, verified
Sending a ServiceUpdates (an ICritterWatchMessage, so INotToBeRouted) over the System-role CritterWatch endpoint records no wolverine-messages-sent, wolverine-messages-received, or wolverine-execution-time — the construction-time tracker selection from 2c0aea2 works on the send, listen, and execution paths.
The gap
The same delivery still records:
wolverine-messages-succeeded => 1
wolverine-effective-time => 1
Root cause: MessageSucceededContinuation.ExecuteAsync reports completion through the runtime's global tracker —
runtime.MessageTracking.MessageSucceeded(lifecycle.Envelope!); // MessageSucceededContinuation.cs:26
— bypassing the executor-resolved metrics-silent tracker entirely. NoHandlerContinuation.cs:55 has the same shape (reproduced: an unhandled system message also records succeeded + effective-time), and the MessageFailed path deserves the same audit.
Why it matters beyond the counters
WolverineRuntime.Tracking.MessageSucceeded is also where RecordEffectiveTime is posted to the accumulator, guarded only by the legacy string-match IsSystemEndpoint(envelope.Destination). A monitored service handling a console round-trip (dlq-operation, request_*) has its own application queue as the destination, so the accumulator is still fed — which means CritterWatch#880 (Avg Effective Time in the tens of millions of ms for exactly those message types, from now − SentAt on an unset SentAt) is not resolved by 6.24.3, contrary to what the executor-level exclusion suggests. Closing this bypass closes #880's producer.
Suggested shape
Same principle as the rest of GH-907 — resolve once, not per envelope: let the executor stamp its resolved tracker on the MessageContext when it rents one, and have MessageSucceededContinuation / NoHandlerContinuation / the failure continuations report through that instead of runtime.MessageTracking. (No-handler has no executor; a per-envelope resolve there is fine — it is the cold path.)
🤖 Generated with Claude Code
Found while verifying CritterWatch#907 end to end against 6.24.3, with a MeterListener test on a host running
AddCritterWatchMonitoring(CritterWatchcritterwatch_traffic_is_metrics_silent_907).What 6.24.3 delivers, verified
Sending a
ServiceUpdates(anICritterWatchMessage, soINotToBeRouted) over the System-role CritterWatch endpoint records nowolverine-messages-sent,wolverine-messages-received, orwolverine-execution-time— the construction-time tracker selection from 2c0aea2 works on the send, listen, and execution paths.The gap
The same delivery still records:
Root cause:
MessageSucceededContinuation.ExecuteAsyncreports completion through the runtime's global tracker —— bypassing the executor-resolved metrics-silent tracker entirely.
NoHandlerContinuation.cs:55has the same shape (reproduced: an unhandled system message also records succeeded + effective-time), and theMessageFailedpath deserves the same audit.Why it matters beyond the counters
WolverineRuntime.Tracking.MessageSucceededis also whereRecordEffectiveTimeis posted to the accumulator, guarded only by the legacy string-matchIsSystemEndpoint(envelope.Destination). A monitored service handling a console round-trip (dlq-operation,request_*) has its own application queue as the destination, so the accumulator is still fed — which means CritterWatch#880 (Avg Effective Time in the tens of millions of ms for exactly those message types, fromnow − SentAton an unsetSentAt) is not resolved by 6.24.3, contrary to what the executor-level exclusion suggests. Closing this bypass closes #880's producer.Suggested shape
Same principle as the rest of GH-907 — resolve once, not per envelope: let the executor stamp its resolved tracker on the
MessageContextwhen it rents one, and haveMessageSucceededContinuation/NoHandlerContinuation/ the failure continuations report through that instead ofruntime.MessageTracking. (No-handler has no executor; a per-envelope resolve there is fine — it is the cold path.)🤖 Generated with Claude Code