fix(agent-v2): include Win32_Process key (Handle) in WMI GetOwner projection

SELECT ProcessId omitted the key property Handle, so WMI could not construct
__PATH and InvokeMethod("GetOwner") throws under classic WMI — the entire WMI
fallback in ProcessOwnerLookup.ViaWmi would have been silently dead
(throw → catch → wmiErrored=true → null), a regression vs the old SELECT *.
SELECT Handle, ProcessId restores method-callability. Not caught by tests: the
WMI path has no direct coverage (DAD tests inject the ProcessOwnerResolver seam).

V2.Core 1467/1467 green, build 0 warnings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-06-16 16:07:43 +02:00
parent a0a380ea29
commit a55a7c65af
@@ -69,8 +69,8 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Interop
/// count the failure rate. A process that simply vanished between enumeration and query
/// (zero rows) is NOT counted as an error.
/// <para>
/// Projects only <c>ProcessId</c>: <c>GetOwner</c> binds through the object's <c>__PATH</c>,
/// which WMI always returns regardless of the SELECT list, so this avoids materializing the
/// Projects only <c>Handle</c> + <c>ProcessId</c>: <c>Handle</c> is the key property WMI
/// needs for <c>GetOwner</c> method invocation, while still avoiding materializing the
/// ~45 unused properties that <c>SELECT *</c> would.
/// </para>
/// </summary>
@@ -80,7 +80,7 @@ namespace AutopilotMonitor.Agent.V2.Core.Monitoring.Interop
try
{
using (var searcher = new ManagementObjectSearcher(
$"SELECT ProcessId FROM Win32_Process WHERE ProcessId = {processId}"))
$"SELECT Handle, ProcessId FROM Win32_Process WHERE ProcessId = {processId}"))
{
foreach (ManagementObject obj in searcher.Get())
{