Skip to content

fix(desktop): validate distro IP candidates against Windows interfaces

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 27, 2026 in 1m 17s

Effect Service Conventions: 1 issue found

apps/desktop/src/wsl/DesktopWslEnvironment.ts — the new windowsIpv4Interfaces() helper calls NodeOS.networkInterfaces() directly inside the production service implementation, hiding a runtime-backed dependency instead of acquiring the existing DesktopNetworkInterfaces Effect service with yield* DesktopNetworkInterfaces.DesktopNetworkInterfaces. As a result neither getDistroIpImpl's requirements nor DesktopWslEnvironment.layer's type expose the dependency, and the new behavior can only be tested through the pure pickDistroIp helper.

An inline comment with the suggested fix has been posted on the affected range.

Details

Note

Your check run agent prompt is: .macroscope/check-run-agents/effect-service-conventions.md
More information about how Check Run Agents work can be found in our Help Center.

Reviewed files in scope: apps/desktop/src/wsl/DesktopWslEnvironment.ts and apps/desktop/src/wsl/DesktopWslEnvironment.test.ts.

Checked and found compliant:

  • Effect modules imported as subpath namespaces (effect/Effect, effect/Option, effect/Layer, ...); no consolidated named imports from "effect".
  • Canonical module order preserved; inline Context.Service interface, single make-equivalent construction and export const layer unchanged.
  • No ManagedRuntime.make, runPromise, or runPromiseExit introduced; the only Layer.succeed in the file is the pre-existing layerTest seam.
  • No new error classes, predicates, or catchTag/catchIf usage; existing DesktopWslDistroListError untouched.
  • Behavior change (distro IP selection) is covered by focused unit tests on the extracted pure helpers, and the removed hostname -I rationale comment was replaced with equivalent documentation.

Supporting evidence for the finding: apps/desktop/src/backend/DesktopNetworkInterfaces.ts defines a Context.Service wrapping NodeOS.networkInterfaces() with make/layer, and apps/desktop/src/backend/DesktopServerExposure.ts consumes it via yield* DesktopNetworkInterfaces.DesktopNetworkInterfaces with a Layer.succeed test double in DesktopServerExposure.test.ts — showing the established pattern this change bypasses.


🔍 Agent activity — 6 tool calls

💭 I'm looking at the diff to check conventions—it adds pure helpers, a WindowsIpv4Interface interface, and a windowsIpv4Interfaces() function that calls NodeOS.networkInterfaces() imperatively inside an Effect generator, and I'm weighing whether that synchronous OS read counts as a hidden side effect. The rules against hiding dependencies mention module globals, closures over singleton services, or Layer.succeed implementations calling imperative APIs, but this isn't a Layer.succeed, so there may be a platform service abstraction elsewhere in the repo worth checking.

1. browse_code — apps/desktop/src/wsl/DesktopWslEnvironment.ts

2. browse_code — apps/desktop/src/wsl/DesktopWslEnvironment.ts

💭 I'm checking the repo's conventions around imports and logging, and looking for whether there's an existing pattern for accessing network interfaces elsewhere in the codebase before using node:os directly.

3. git_tools — networkInterfaces

💭 I notice there's an existing DesktopNetworkInterfaces Effect service that properly wraps NodeOS.networkInterfaces() with error handling, but the new DesktopWslEnvironment.ts code calls the native API directly instead, bypassing that service and hiding a dependency that should be surfaced through Effect's yield pattern. Now I want to look more closely at how the WSL environment layer is composed to see whether wiring in the proper dependency is straightforward.

4. browse_code — apps/desktop/src/backend/DesktopNetworkInterfaces.ts

5. browse_code — apps/desktop/src/wsl/DesktopWslEnvironment.ts

💭 I've confirmed there's already a dedicated DesktopNetworkInterfaces Effect service designed to wrap NodeOS.networkInterfaces() with proper structured error handling. The PR sidesteps this entirely by importing node:os directly and calling windowsIpv4Interfaces() imperatively inside the service implementation, creating a hidden dependency on an imperative API when the convention requires acquiring Effect service dependencies from the environment via yield*. I notice DesktopBackendConfiguration.ts does the same thing, but that's legacy code, and per the convention I should only flag newly introduced violations — this one is new and there's an existing service that should be used instead. The tests cover pure helpers well, but there's no service-level integration test since the dependency isn't injectable, which ties back to the same core issue: with proper dependency injection this would be testable via a Layer. I'm also noting that getDistroIpImpl's type signature only exposes ChildProcessSpawner as a requirement, omitting the network interfaces dependency it actually uses — violating the convention that make/layer types must expose all their requirements. I'm confirming this is a single, clear finding worth failing the check on: a hidden imperative dependency where an existing Effect service should be used instead. The fix would require touching multiple places (the getDistroIpImpl signature and its layer), so I'll describe the fix in prose rather than providing a diff, and point the comment at the windowsIpv4Interfaces function around lines 768-783. Time to write up the review comment and post it.

6. modify_pr — One convention violation found: the new distro-IP probe reads the Windows network interfaces through a direct node:os call inside the Effect service implementation instead of acquiring the existing DesktopNetworkInterfaces service from the environment.


Agent Credits: 53 credits