Repository navigation
Effect Service Conventions: 2 issues found
Two error-modeling convention violations in apps/desktop/src/app/DesktopLinuxUrlHandler.ts:
- Manufactured
Errorto satisfy a requiredcause(lines 30-32 / 135-139): the non-zeroxdg-mimeexit has no underlying failure, sonew Error("xdg-mime exited with code ...")is created purely to populatecause: Schema.Defect(). The exit code should be a structured attribute (exitCode) withcausemade optional, matchingapps/server/src/cloud/pinnedRuntime.tsandbootService.ts. - Missing path context on the write step (lines 111-118):
writeDesktopEntrywrapsmakeDirectory+writeFileStringin a generic error carrying onlystepandscheme, discarding the desktop-entry path that is known at the wrapping site (compare theDesktopConnectionCatalogStore*errors, which carrypath/catalogPath).
Both findings were posted as inline review comments.
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.
Conventions verified as compliant:
- Namespace subpath imports for all Effect modules (
effect/Effect,effect/Layer,effect/Schema,effect/unstable/process/*); local service modules imported as namespaces (DesktopEnvironment,ElectronProtocol);makeComponentLoggerkept as a named import for a pure helper. - Canonical single-file order: imports, error declaration,
Context.Servicetag with inline interface,make,layer; no standaloneFooShapetype;export const layer = Layer.effect(DesktopLinuxUrlHandler, make)with a realmake. - Dependencies acquired from the environment (
yield* DesktopEnvironment.DesktopEnvironment,FileSystem.FileSystem,ChildProcessSpawner.ChildProcessSpawner); no service-instance parameters,ManagedRuntime.make, orrunPromise/runPromiseExitin the service. Layer.succeedoccurrences appear only in the test file as legitimate test seams; the test usesDesktopEnvironment.DesktopEnvironment["Service"]for the inferred interface.stepis a multi-value discriminator feeding one generic message, so no redundant singleton discriminator;Effect.catchis used where the whole error channel is intentionally handled (best-effort registration), which the conventions permit.- Behavior change (new Linux scheme registration) is covered by focused tests, so the added test file is appropriate rather than test padding.
Files examined: apps/desktop/src/app/DesktopLinuxUrlHandler.ts, apps/desktop/src/app/DesktopLinuxUrlHandler.test.ts, apps/desktop/src/app/DesktopEnvironment.ts, apps/desktop/src/app/DesktopConfig.ts, apps/desktop/src/app/DesktopApp.ts, apps/desktop/src/main.ts, plus repository-wide error-schema patterns for comparison.
🔍 Agent activity — 1 tool call
💭 I'm reviewing the DesktopLinuxUrlHandler.ts file to ensure it follows the established conventions—checking that imports use namespace syntax from effect subpaths, the service definition follows the right order with imports, constants, logger, errors, and the Context.Service tag, and verifying the structure matches the pattern. Looking at the error handling, I notice
isRegistrationErroris a private Schema.is constant rather than an exported predicate, which slightly deviates from the convention of exporting direct schema predicates, though it's not wrapped in a redundant function so it's a minor concern. The error class itself usesSchema.TaggedErrorClasswith the appropriate fields likestep,scheme, andcause, with the message derived from attributes, which is correct. For the error handling patterns,Effect.catchis being used to intentionally handle the entire error channel with a warning log, which is appropriate. ThenEffect.mapErrorwraps the multi-step operation (directory creation and file writing) to transform any errors into the customDesktopLinuxUrlHandlerRegistrationError. However, there's a gap here: the error class captures thestepandschemecontext but doesn't preserve the actual file path that's available at the wrapping site (linuxApplicationsDirand the entry path). According to the conventions, stable domain context like resource paths should be captured in the error. That's a legitimate issue — the path information is known but lost. ForsetDefaultHandler, the error mapping uses a pass-through pattern where existing registration errors are preserved while others are wrapped, which is fine, though it could potentially be simplified by applyingmapErroronly to the spawn operation itself. Looking at the dependency setup, the layer correctly yieldsDesktopEnvironment,FileSystem, andChildProcessSpawnerthrough the closure, so theregistereffect doesn't need external requirements. The test file appropriately adds tests for this behavior change rather than just mechanical refactoring. Now I need to verify some conventions in the actual codebase — checking how other services model errors, whetherDesktopEnvironment.pathfollows an existing shape, and confirming thatElectronProtocol.getDesktopSchemeexists and aligns with platform-specific patterns already in use. I'm looking at conventions in similar code to see how other services handle Schema.is exports and error predicates. It seems the pattern is to export direct schema predicates likeexport const isFoo = Schema.is(Foo), but hereisRegistrationErroris private and wraps aSchema.isconstant with a redundant function that has the same signature — that's the issue to flag. For the write-desktop-entry error, the convention says to retain path context when available, but herestepandschememight not be enough since the actual path is deterministic from the environment. Though wrappingmakeDirectoryandwriteFileStringinto a single logical operation seems reasonable. The real concern is whethersetDefaultHandleris properly re-checking the error withisRegistrationErrorafter it's already been raised. There's also a solid issue with how the non-zero exit code from xdg-mime is handled — they're manufacturing a new Error just to populate thecausefield, which violates the convention that you shouldn't create an Error merely to fill a required cause unless there's an actual underlying failure. The exit code itself isn't a failure that needs wrapping; it's just a status code. The better approach would be to capture the exit code as a structured field in the error schema and makecauseoptional instead. This also reveals another problem: the log message doesn't include the exit code, so that information gets lost entirely since only the message is logged, not the cause. Looking at the rest of the code, the test setup with the layer seam and the error handling withEffect.catchlook fine. The logging is also properly sanitized, pulling from structural attributes. I'm noticing themakefunction usesEffect.genhere, whereas other services in the repo seem to useEffect.fn— worth checking if there's an inconsistency in the pattern. Now I'm searching through the codebase to see if there's an existing convention for error schemas that includecause: Schema.optional(Schema.Defect()). The repo's convention for handling exit codes favors capturing it as a structured field with an optionalcauseproperty, so manufacturing an Error just to satisfy that requirement violates the principle against creating errors for schema compliance and obscures the actual exit code information. I should also look for a second issue around missing path context in the write-desktop-entry error, since the codebase typically includes file paths when reporting filesystem errors. I'll consolidate into a single comment on the Error instantiation (lines 135-139) that covers both the exitCode field addition and making cause optional, then add a brief separate note about the write path. Let me search the desktop codebase to see if there's already a pattern for error fields with path information I should follow. The repo pattern is showing up consistently in filesystem errors, so both findings check out. Now I need to write the review with two inline comments—one targeting the error field definition around lines 30-32 and another on the manufactured Error at line 138, where I'll need to add anexitCodefield and optional cause. Since this fix spans multiple sections, I'll anchor the comment on the return block at lines 135-139. For the second comment, I'm flagging the write-desktop-entry error that's missing the actual desktop entry path in the message, anchoring that around lines 111-118. Let me draft these comments now, starting with the error structure issue. Since we found violations, I need to return a JSON response indicating failure rather than the "All clear" message.
1. modify_pr — Reviewed the new DesktopLinuxUrlHandler service against the Effect service conventions. The service/tag/make/layer shape, namespace imports, dependency acquisition (yield* Foo.Foo), and Effect.catch on a fully-handled channel all look right. Two error-modeling issues below.
Agent Credits: 94 credits