From 7c5021110257ff97a77dc726df3ea4d85562b7ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 1 Jul 2026 20:26:32 +0200 Subject: [PATCH] fix: project doctor output platform to the public leaf after the collapse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Platform collapse projected most `doctor` output but missed the device inventory breakdown: `deviceInventoryEvidence` keyed `byPlatform` by the raw internal `device.platform`, so an Apple session emitted `byPlatform: { apple: … }` in the doctor response — a machine-facing `apple` leak (approach b keeps output leaf `ios`/`macos`). Key it by `publicPlatformString(device)` instead (now `Map`, so an `apple` key is compile-impossible), which also splits Apple devices into ios vs macos in the breakdown. Also project two doctor command SUGGESTION strings (`apps --platform …`, `close --platform …`) to the leaf — `--platform apple` was valid but broader than the session's actual device. The doctor descriptor routing (command-descriptor `daemon` block) and its lack of a platform-specific `supports` gate are already correct; toolchain checks already accept `apple`. Verified: tsc, oxlint, oxfmt, layering, fallow, provider-integration 82/82; full unit green except the known android fillAndroid contention flake (passes 92/92 in isolation). --- src/daemon/handlers/session-doctor-app.ts | 2 +- src/daemon/handlers/session-doctor-device.ts | 12 ++++++++---- src/daemon/handlers/session-doctor-options.ts | 3 ++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/daemon/handlers/session-doctor-app.ts b/src/daemon/handlers/session-doctor-app.ts index 983cb07ca..7b328725f 100644 --- a/src/daemon/handlers/session-doctor-app.ts +++ b/src/daemon/handlers/session-doctor-app.ts @@ -43,7 +43,7 @@ export async function appendAppChecks( status: 'fail', summary: `Target app check failed: ${normalized.message}`, hint: normalized.hint ?? 'Install the app or pass an exact package/bundle id or app name.', - command: `agent-device apps --platform ${device.platform} --all`, + command: `agent-device apps --platform ${publicPlatformString(device)} --all`, evidence: { code: normalized.code, message: normalized.message }, }); } diff --git a/src/daemon/handlers/session-doctor-device.ts b/src/daemon/handlers/session-doctor-device.ts index 2aa118dc4..88aa206a6 100644 --- a/src/daemon/handlers/session-doctor-device.ts +++ b/src/daemon/handlers/session-doctor-device.ts @@ -13,8 +13,8 @@ import { publicPlatformString, type DeviceInfo, type DeviceTarget, - type Platform, type PlatformSelector, + type PublicPlatform, } from '../../kernel/device.ts'; import { normalizeError } from '../../kernel/errors.ts'; import type { DaemonRequest, SessionState } from '../types.ts'; @@ -267,12 +267,16 @@ function deviceInventoryEvidence( devices: DeviceInfo[], failures: DoctorInventoryFailure[], ): Record { - const byPlatform = new Map(); + // Key by the PUBLIC leaf platform (ios/macos/android/...), never the internal + // collapsed `apple`, so the doctor breakdown stays a machine-stable output and + // Apple devices split into ios vs macos. + const byPlatform = new Map(); for (const device of devices) { - const entry = byPlatform.get(device.platform) ?? { available: 0, booted: 0 }; + const key = publicPlatformString(device); + const entry = byPlatform.get(key) ?? { available: 0, booted: 0 }; entry.available += 1; if (device.booted === true) entry.booted += 1; - byPlatform.set(device.platform, entry); + byPlatform.set(key, entry); } return { available: devices.length, diff --git a/src/daemon/handlers/session-doctor-options.ts b/src/daemon/handlers/session-doctor-options.ts index 85ca805ea..e446e8322 100644 --- a/src/daemon/handlers/session-doctor-options.ts +++ b/src/daemon/handlers/session-doctor-options.ts @@ -1,4 +1,5 @@ import { detectProjectRuntimeKind } from '../../utils/project-runtime.ts'; +import { publicPlatformString } from '../../kernel/device.ts'; import type { SessionStore } from '../session-store.ts'; import type { DaemonRequest, SessionState } from '../types.ts'; import type { DoctorCheck, DoctorKind, DoctorOptions } from './session-doctor-types.ts'; @@ -116,7 +117,7 @@ export function sessionChecks( : undefined, command: sameDeviceSessions.length > 0 - ? `agent-device close --session ${sameDeviceSessions[0]} --platform ${session.device.platform}` + ? `agent-device close --session ${sameDeviceSessions[0]} --platform ${publicPlatformString(session.device)}` : undefined, evidence: { session: session.name,