Repository navigation
Effect Service Conventions: 5 issues found
Five concrete issues were found in the changed scope and posted as inline review comments.
apps/desktop/src/shell/DesktopShellEnvironment.ts
- L395-397:
Effect.catchAlldoes not exist in Effect v4 ([email protected]); useEffect.orElseSucceed(() => false)as elsewhere in this file. - L428: same removed
Effect.catchAllAPI; useEffect.orElseSucceed(() => true). - L418:
catchIfpredicate checkserr._tag === "SystemError" && err.reason === "NotFound", butPlatformErrorcarries_tag: "PlatformError"and a nestedreasonobject — the platform code iserr.reason._tag. As written it is a type error and would never recover a missing profile, permanently disabling the new fast path.
apps/desktop/src/shell/DesktopShellEnvironment.test.ts
- L363 (and L445):
PlatformError.systemErrortakes_tag: SystemErrorTag(e.g."NotFound") and has noreasonoption, so the stub fails to typecheck. - L358 (and L440): env omits
USERPROFILE, socheckProfileMentionsFnmshort-circuits totrue, both PowerShell probes run, and thecommands.length === 0assertions fail — the fast-path branch stays uncovered.
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.
Scope reviewed: the two changed TypeScript files under apps/desktop/src/shell/, plus the service make/layer at the end of DesktopShellEnvironment.ts and the test harness runShellEnvironment.
Conventions verified as satisfied:
- Subpath namespace imports (
effect/Effect,effect/FileSystem,effect/Layer, ...) are used consistently in both files, including the newly addedeffect/FileSystemimport. installWindowsEnvironmentacquiresFileSystemfrom the environment viayield* FileSystem.FileSystemand declares it inEffect.fn.Return<..., ChildProcessSpawner.ChildProcessSpawner | FileSystem.FileSystem>;installShellEnvironment,make, andlayercontinue to expose that requirement. No service instances are threaded as constructor parameters in production code.- The test-only
Effect.provideService(FileSystem.FileSystem, input.fs)seam andLayer.succeedstubs are legitimate test seams, not hidden runtimes; noManagedRuntime.make/runPromisewas introduced. - Error class definitions (
Schema.TaggedErrorClass, structuralmessagegetters,Effect.catchTagsinrunCommandOutput) are unchanged and still conform. - The dropped concurrency rationale comment was restored alongside the new fast-path note, so the previously flagged comment-preservation issue is resolved.
API facts were confirmed against the vendored upstream reference in .repos/effect-smol (migration/error-handling.md renames catchAll → catch; PlatformError.ts shows systemError(options) with _tag: SystemErrorTag and a nested reason, and FileSystem.exists itself matches e.reason._tag === "NotFound").
🔍 Agent activity — 1 tool call
💭 I'm checking the current state of the files to see what's changed. The test file is now importing FileSystem from the effect library, and the program variable has been refactored into a const-based ternary expression. Let me examine the actual code at head to understand the full picture. Looking at the main service changes in that section. I'm checking whether
catchIfwith a structural predicate on_tag === "SystemError"combined withreason === "NotFound"aligns with the convention—the tag check alone would violate it, but the platform error code inspection might justify the approach. Looking at alternatives likecatchTagsseems more verbose, and I'm also noticing the pattern elsewhere in the file usesorElseSucceedfor existence checks, plus acatchAllthat wipes the error channel entirely, which the convention says is appropriate when the entire error path is intentionally handled. I should verify whether this codebase is using Effect v4, wherecatchAllwas renamed tocatch— if that's the case, this would be a compile error. Let me search the repo to see howcatchAllis actually being used. I'm noticing thatEffect.catchAllonly appears in the new code, which suggests it might not exist in this version of Effect (v4 alpha) —Effect.catchis likely the correct API name here. Let me search the repo to confirm howEffect.catchis actually being used. I'm noticing thatEffect.catchAllappears at lines 396 and 428, but this is effect v4 beta where that API was removed and replaced withEffect.catch— so these are compile errors. Let me check the actual effect v4 version to confirm whethercatchAllmight still exist as a deprecated alias. Looking at the conventions in the codebase, when the entire error channel is handled intentionally, the pattern should beEffect.orElseSucceed(() => false)like what's already used at line 555 for theexistsfunction. For thecatchIfusage that discriminates on_tagandreason, the more idiomatic approach would beEffect.catchTagswith a handler that can re-fail if needed, though that gets a bit complex with the reason filtering. Let me verify whetherEffect.catchAllactually exists in effect v4 beta 103 by checking the patch files or searching the docs, and also confirm whether previous review comments already flagged this issue. I'm flagging twoEffect.catchAllcompile errors under the "Errors and predicates" section since they fall within the catch conventions check. I also need to look into howerr._tag === "SystemError"maps to v4's PlatformError type—readFileStringfails with a PlatformError union ofBadArgumentandSystemError, so I should verify the shape in the effect v4 module. The test file constructsPlatformError.systemErrorwith specific fields, but I need to check if that API actually accepts those arguments in the real implementation. I'm realizing the error predicate in production is checking for the wrong tag and structure — it's looking for_tag === "SystemError"with areasonstring, but the actual error has_tag === "PlatformError"andreasonis an object instead. Since the predicate never matches, file read failures fall through to a catch-all handler that returns true, which means missing profile files incorrectly trigger the fast path when they shouldn't. The type system would also catch these issues — comparing_tagto a string literal when it's narrowed to"PlatformError"is a TS error, and comparingreason(an object) to a string is another type error. The fix is to usecatchTagswith the correct structure: checkingerr.reason._tag === "NotFound"instead. The test file has similar issues — it's constructing the error with invalid parameters like_tag: "SystemError"and areasonfield that shouldn't exist. This falls squarely within the "Errors and predicates" section of the Effect Service Conventions check, so I should flag both the catch-API predicate issue and the test file's malformed error construction as part of the same finding. Now I need to verify the layer dependency chain —DesktopShellEnvironment.layeris provided first, leaving FileSystem unmet, thenprovideServicesatisfies it downstream in the pipe. That's valid. But I should check whether the layer internally provides NodeServices or if the mock filesystem actually gets used by the layer's requirements. There are a few other things to verify: whether providing NodeServices after provideService causes any duplication, the timeout duration and concurrency settings look fine, and the fast path's mutation ofconfig.env.PATHwith the static paths — the original code merged these the same way, so that should be okay. Now I need to check the layer definition to make sure the FileSystem requirement is properly exposed in the service's layer declaration. I've identified two instances in the DesktopShellEnvironment file whereEffect.catchAllis being used, but this method was renamed toEffect.catchin Effect v4. The codebase usesEffect.orElseSucceed(() => false)as the standard pattern for handling existence checks, so I'll flag both occurrences and suggest the appropriate fix. For the first suggestion, I'm replacing the removedcatchAllAPI withorElseSucceed, wrapping the false return in a function. For the second comment, thecatchIfpredicate is checking the wrong path—since errors here are alwaysPlatformError, I just need to checkerr.reason._tag === "NotFound"directly, removing the redundant_tagcheck on the error itself. Now I'm looking at the test file to identify wherePlatformError.systemErroris being constructed incorrectly. The current code is passing_tagandreasonas separate fields, but the actual constructor expects_tagto be the error tag directly (like "NotFound") along with metadata fields likemodule,method, andpathOrDescriptor. I need to find the exact line numbers for the two occurrences in the test file to comment on them. Looking at test 437, I'm tracing through the logic where LOCALAPPDATA points to the mock directory and the node.exe path exists within it. The test expects this to return true, which checks out. But then I notice USERPROFILE isn't set in this test case, and the checkProfileMentionsFnm function returns true when the profile is missing—which means skipProfile gets set to false, not true as I'd expect for an unsafe condition. This causes the probes to run when they shouldn't, resulting in 2 commands instead of 0, so the test fails. This is the same pattern as the PROGRAMFILES issue flagged before, just hitting a different environment variable. The code was updated in response to that earlier flag, but USERPROFILE still has the same problem. I should probably mention this since it's a distinct issue, though I'm weighing whether test logic falls within the scope of checking Effect service conventions—the prior runs did flag test issues, so it seems fair to include it briefly. I'm realizing both test 1 and test 4 fail for the same reason — neither sets USERPROFILE, socheckProfileMentionsFnmshort-circuits to true on line 408, leaving skipProfile false and causing both probe runs to execute. I should consolidate this into a single comment anchored at line 358 that covers both failing assertions and suggests adding USERPROFILE to the test environments. However, test 1 has an additional wrinkle: the fs mock's readFileString fails with a PlatformError, and the predicate check is broken, so it falls through to catchAll and returns true anyway. That means test 1 would also need the predicate fix from the other comment to properly yield an empty string. I'll note this interdependency when describing the fix. For test 2, when USERPROFILE is set and readFileString returns the fnm content, profileMentionsFnm becomes true, the probes run, and we get 2 commands—test passes. Test 3 checks the profile-without-fnm case: nodeFound sees node.exe in the path, staticPaths combines PATH with the known Windows directories from USERPROFILE, so the skip triggers and we get 0 commands—also passes. There's a minor issue with unused parameters in the readFileString mocks at lines 389 and 420 where thepathargument isn't used, which could trigger a noUnusedParameters lint error, but that's probably out of scope here. Now I'm identifying the exact line numbers for the review comments—these are all added lines in the diff. I need to post 4 comments targeting the specific production lines that were added, starting with line 396 in DesktopShellEnvironment.ts for the catchAll logic. I'll add separate inline comments for each fix rather than grouping them together—that keeps things clearer. So line 428 gets its own suggestion to useEffect.orElseSucceed(() => true)instead ofEffect.catchAll, and I'm aiming for around 5 comments total across the different issues to avoid cluttering the response. I've identified five issues total across the review. Now I'll write up the findings with the title "Effect Service Conventions: 5 issues found".
1. modify_pr — Reviewed the new Windows fast-path against the Effect service conventions. The service definition/layer shape is fine (FileSystem is acquired from the environment and surfaced in Effect.fn.Return), but the new error-handling code uses APIs/predicates that do not exist in this repo's Effect v4 line, and two of the new tests cannot pass as written.
Agent Credits: 262 credits