Skip to content

fix(desktop): correct mac cua packaging

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 2, 2026 in 2m 36s

Effect Service Conventions: 1 issue found

apps/desktop/src/cua/CuaDriverServerEnvironment.ts:77 — CuaDriverConfigurationError is constructed with a fabricated binaryPath: "<not configured>" for the missing-configuration case, producing the misleading message Could not configure embedded cua-driver at '<not configured>'. This pure validation failure is semantically distinct from the toFileUrl failure (which has a real path and cause) and should be its own tagged error, handled with Effect.catchTags in DesktopApp.ts.

The prior finding on the required cause field has been addressed (cause is now Schema.optional(Schema.Defect())).

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.

Files reviewed in scope:

  • apps/desktop/src/cua/CuaDriverServerEnvironment.ts (+ test)
  • apps/desktop/src/app/DesktopApp.ts
  • apps/server/src/cua/CuaDriverEmbedded.ts (+ test)
  • apps/server/src/serverRuntimeStartup.ts
  • apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts (+ test)
  • apps/server/src/provider/Layers/codexLaunchArgs.ts (+ test)
  • apps/web/src/components/settings/SettingsPanels.tsx
  • packages/contracts/src/settings.ts (+ test)

Checked and found conforming:

  • All Effect modules imported as namespaces from effect/* subpaths; named imports are limited to whole packages and pure-helper modules, matching existing repo practice (installDesktopIpcHandlers, startupAccess.ts).
  • No new Context.Service definitions, so service layout/make/layer rules do not apply; the new modules are scoped effect helpers.
  • No ManagedRuntime.make, runPromise, or runPromiseExit introduced; no service instances passed as constructor parameters. Path.Path is acquired from the environment via yield*.
  • Effect.catch uses in DesktopApp.ts, serverRuntimeStartup.ts, and monitorEmbeddedCuaDriverExit each intentionally handle the whole error channel.
  • CuaDriverStartError preserves the immediate cause at every wrapping site and derives message from binaryPath only.
  • cause: String(error.cause) in log annotations follows the existing repository-wide logging pattern and was not flagged.

🔍 Agent activity — 1 tool call

💭 I'm looking at the changed files to see what's been addressed. The previous feedback about the optional cause in CuaDriverEmbedded.ts has already been handled — the file appears to have been refactored and CuaDriverServerEnvironment.ts now properly includes cause: Schema.optional(Schema.Defect()). Let me check what the current state of the head looks like. Looking at the error modeling in CuaDriverServerEnvironment.ts, I notice it's using a sentinel value "<not configured>" as the binaryPath when the driver isn't configured. This is problematic because it conflates two distinct failure modes — the driver not being configured versus a toFileUrl failure — both using the same error class. The message would read something like "Could not configure embedded cua-driver at ''", which is semantically awkward. This violates the principle of capturing stable, serializable domain context without encoding the same distinction twice. The sentinel placeholder in a structural field is a questionable pattern that might be worth flagging. For CuaDriverEmbedded.ts, the code reads process.env directly inside Effect functions rather than acquiring it through Effect's configuration or service layer. The conventions around hiding dependencies in module globals apply when creating or consuming Effect services, and these are just plain Effect functions without a Context.Service or layer, so it's not necessarily a violation. I should check how Effect.catch is being used elsewhere to see if there's a pattern. Looking at the error handling in CuaDriverEmbedded.ts, the CuaDriverStartError wraps three distinct failures (module import, host construction, start) under a single error tag without any operation discriminator to distinguish between them. The conventions suggest either adding a multi-value stage or operation field to identify which step failed, or splitting them into separate error classes entirely. Now I need to check the actual repo to see what utilities are available and verify the error handling patterns in files like serverRuntimeStartup.ts, particularly around how causes are being logged and whether the string conversion of error causes aligns with the conventions. I'm identifying remaining violations in the error handling approach. The binaryPath: "<not configured>" sentinel is problematic because it conflates two semantically distinct failures—a missing driver configuration versus a failed module URL build. These should be split into separate error classes rather than forcing different failure modes into the same field with a placeholder value. I'm also reviewing other potential issues: Effect.catch usage appears acceptable when the entire error channel is intentionally handled, and I'm examining how error causes are stringified in log annotations to ensure they stay bounded and preserve exact error information. Passing the cause value directly instead of stringifying it would be more consistent. Looking at module-level dependencies, the code reads process.env directly in Effect code rather than through a service, which goes against the convention of avoiding hidden dependencies in module globals. The repo does use Path.Path in the desktop version, and codexLaunchArgs takes an environment parameter, but I'm not seeing a clear existing pattern for how this should be handled. That said, this isn't technically a service violation based on the rules provided. The installCodexLaunchArgs function returning a thunk that produces an Effect is fine, and since startEmbeddedCuaDriver is a scoped effect used during startup rather than a service being created or refactored, it doesn't require a Context.Service definition. For the imports, the namespace subpath imports look good, but I'm checking whether CuaDriverServerEnvironment should be imported as a namespace at the service boundary. It's just a module of pure helpers and effect functions without a Context.Service tag, so the convention about importing service modules as namespaces might not apply here. Let me look at how DesktopApp handles similar helper modules — it seems to use namespace imports for things like DesktopAppSettings. I should check what pattern other non-service modules follow in the desktop repo, and also see how serverRuntimeStartup and CodexAdapterV2 handle their imports from similar utility modules. The named imports align with how the repo handles non-service modules, so that's consistent. Now I'm weighing whether these Cua modules should be services—startEmbeddedCuaDriver reads and mutates process.env directly, which technically violates the principle about hiding dependencies in globals or singleton closures, though environment access is a bit of a gray area for these conventions. The more pressing issue is that sentinel binaryPath: "<not configured>" string. It's not real domain context—it's a placeholder masquerading as a path, and when it appears in logs like "Could not configure embedded cua-driver at ''", it's misleading. The conventions suggest splitting semantically distinct failures into separate error classes: missing configuration should be separate from file-URL construction failures. Since the prior run flagged an issue in this same area that the author fixed, I should check what's changed between those commits to see if new violations have crept in. I'm weighing whether to flag the sentinel binaryPath as a violation and considering how to handle the error class design — either making binaryPath optional or creating a separate CuaDriverNotConfiguredError class, though the latter would require updating the desktop caller that currently accesses error.binaryPath in its logging. The sentinel value might be a legitimate finding, but it's borderline nitpicking and could come across as overly strict. Let me look for stronger violations elsewhere. I'm checking the UI components and adapter code now — the CodexAdapterV2 change is interesting because it reads process.env inside a Layer factory, which could be a hidden global dependency, though it seems intentional for live environment variables. I need to examine the broader service context around this to see if there's a real convention violation. I'm spotting a couple of issues here. The main one is that sentinel value binaryPath: "<not configured>" standing out as a code smell. There's also the logging in serverRuntimeStartup.ts where it's converting error.cause to a string and mixing that unstructured text into a structured error log, which breaks the logging convention. The convention is clear: preserve the exact underlying value as cause, don't stringify arbitrary defect text into the log payload. So logging { binaryPath, cause: String(error.cause) } violates that — they're stringifying when they should be passing the raw value. Let me search the codebase to see if this pattern shows up elsewhere or if it's an isolated violation. There's an established pattern here that shouldn't be flagged. Looking at the convention more carefully—it asks for stable, serializable domain context like operation, resource path, and normalized status. Using a fake "<not configured>" path feels like a workaround rather than proper context. Plus, the guidance about splitting failures into separate error classes only applies when there's a discriminator choosing different user messages, but both cases produce the same message here. Now I need to figure out the response format. The check defaults to failure but should return "All clear" if there are no findings—which seems contradictory at first. The system requires JSON output, so I'll interpret this as: no violations means a success state with the summary "All clear" in JSON format. I'm also reconsidering whether to flag the sentinel comment and whether the desktop-side "not configured" scenario can actually occur given how the configuration function is called. Looking at the environment variable handling, the dev case requires T3CODE_CUA_DRIVER_PATH to be set or it errors, which then shows the "Cua could not start" dialog to the user—that's reasonable. The configureCuaDriverServerEnvironment function reads from process.env directly for the default parameter, which is slightly inconsistent with taking an environment parameter but acceptable. The replaceCuaDriverServerEnvironment function uses Effect.addFinalizer which requires a Scope, and I need to verify that the startup effect actually has one available. The disableCuaDriverServerEnvironment finalizer restores the inherited environment at scope close, which is semantically odd but not a convention violation. Finally, the error handling in DesktopApp catches errors, but the error channel from configureCuaDriverServerEnvironment is specifically typed as CuaDriverConfig. The CuaDriverStartError is used across three distinct stages—module import, host construction, and process start—but lacks a stage discriminator field, so logs can't distinguish which step failed. While the convention doesn't require multi-value discriminators, adding an operation or stage field would follow the principle of mapping failures with known context rather than wrapping an entire pipeline in one generic error. I'm also reconsidering the sentinel binaryPath issue more carefully against the stated rules. The rule against manufacturing placeholder data to populate required structural attributes applies here—creating a misleading message for a pure validation error violates the spirit of not fabricating data. I should flag this with a concrete fix: introduce a distinct error type like CuaDriverNotConfigured instead. Since the DesktopApp caller spreads error.binaryPath, I'll need to either make binaryPath optional in the schema or create a separate error class and update the caller. I'll post an inline comment on line 77 of CuaDriverServerEnvironment.ts describing the issue and the fix approach. The simpler approach would be making binaryPath optional in the schema with a conditional message, though that still requires tweaking the message getter. I'm leaning toward marking this as a failure since it's a genuine modeling violation, despite the single moderate finding—the explicit guidance in the instructions points that way, even if the risk of a false positive feels manageable. Let me verify the line number in the diff matches what I'm seeing: line 77 in the new 100-line file shows the error being thrown with a placeholder value, which confirms the issue. I'll post the review with the failure designation.

1. modify_pr — Effect service conventions review: one error-modeling issue found in the new Cua modules. Everything else (namespace imports from effect/*, Schema.TaggedErrorClass usage, scoped finalizers, Path.Path acquired from the environment, whole-channel Effect.catch) matches the conventions.


Agent Credits: 86 credits