Repository navigation
Effect Service Conventions: 1 issue found
1 finding
apps/desktop/src/computerHistory/manager.ts—ComputerHistoryOperationErrorcaptures onlyoperationplus an opaqueSchema.Defect()cause. The resolved Computer History root (fromstateDir) and, forremoveMemory/revealMemory, the memorypathare known at every wrapping site and should be retained as stable structural attributes so failures are diagnosable without unwrappingcause. Inline comment posted with a suggested field shape.
Everything else in scope matched the conventions.
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 examined
apps/desktop/src/computerHistory/manager.ts(new service),resolveBinary.tsapps/desktop/src/ipc/methods/computerHistory.ts,computerUse.ts,DesktopIpcHandlers.ts,DesktopApp.ts,main.tsapps/server/src/computerHistory/service.ts,apps/server/src/desktopControl/desktopMcpBinary.ts,desktopMcpLaunch.ts(+ tests)- Affected adapter call sites:
CodexAdapter.ts,CodexSessionRuntime.ts,ClaudeAdapter.ts,CursorAdapter.ts,GrokAdapter.ts,server.ts packages/contracts/*,packages/shared/src/computerHistory/*,packages/effect-codex-app-server/src/client.ts
Checks that passed
- Imports: Effect modules imported as subpath namespaces (
effect/Effect,effect/Layer,effect/Context,effect/Schema); no consolidatedfrom "effect"imports introduced. Local service modules are imported as namespaces (* as ComputerHistoryManager,* as ServerSettings,* as ComputerHistoryService); named imports are limited to contracts schemas and pure helpers, which the conventions allow. - Service definition:
ComputerHistoryManagerdeclares its interface inline inContext.Service, with no standaloneFooShape; module order is imports → error → tag →make→layer;makeis real construction andlayer = Layer.effect(...)is appropriate (finalizer registered viaEffect.addFinalizer, matching existing services in this repo). - Dependency acquisition / runtime boundaries: no
ManagedRuntime.make,runPromise, orrunPromiseExitadded in domain services;stateDir/ComputerHistorySettingsparameters are pure configuration, not service injection;makeResolveEnabledDesktopMcpand theCodexAdaptercontext loader acquire services viayield* Serviceand re-provide captured instances to keep session methods atR = never, matching the established pattern in this codebase. - Errors: single service-level error with a multi-value
operationdiscriminator and a generic message derived from it (an explicitly allowed model);causepreserves the underlying failure;Effect.catchTagsused at the bootstrap recovery site rather thancatchTag/catchIf. - Change discipline: tests added are behavioral (approval mapping, permissions, binary resolution, build staging), not tests to prove a mechanical refactor; no compatibility re-export shims introduced.
🔍 Agent activity — 1 tool call
💭 I need to switch approaches since the stat_only flag didn't work as expected and gave me the full diff anyway. Let me pull the list of changed files directly from the GitHub API instead. I need to look at the .tsx files too since the TypeScript analysis was incomplete — those React components likely contain the ManagedRuntime and runPromise patterns I'm tracking. From what I've gathered so far, the desktop manager service uses a Schema.TaggedErrorClass with Schema.Defect() for error handling, following a specific convention. The error tagging here is acceptable — it uses a generic
ComputerHistoryOperationErrorwith anoperationdiscriminator and derives the message from that structural attribute, preserving the cause. However, there's a gap: the error doesn't capture path or resource context like stateDir or the actual file paths involved, which the convention says should be retained when available. That's a minor violation worth flagging. The service also uses plain mutable state with a comment referencing Macroscope conventions, and internally relies on imperative Promise-based machinery within the constructor using E. tryPromise, which is acceptable. The layer setup looks correct with Layer.effect and a real make function, but there's a question about whethermakeusesEffect.addFinalizer— if it does, that requires Scope, which means the code should useLayer.scopedinstead ofLayer.effect. The type annotation declares no requirements, so if Scope leaked it wouldn't compile. In Effect v4, layers automatically provide scope access during construction, soLayer.effectshould handle this, but I should verify against similar patterns in the repo. ThecomputerHistory/service.tsmodule exports standalone Effect functions and a layer rather than wrapping them in a Context.Service tag — it's more of a helpers module than a formal service, which might be acceptable depending on the conventions being followed. FordesktopMcpLaunch.ts, themakeResolveEnabledDesktopMcpfunction captures services and usesEffect.provideServiceto close over them, which raises a question about whether this violates the principle of not hiding dependencies in closures over singleton services. However, looking at how it's actually implemented — the dependencies are acquired from the environment at construction time viayield*rather than passed as parameters — this pattern seems legitimate and consistent with the codebase's approach. The same pattern appears inCodexAdapter.tswhere services are acquired from the environment at construction and then provided to per-session effects, which also looks acceptable. Now I need to check the TypeScript changes and other files that were in the truncated diff, particularly the web components. Let me try to get a list of all changed files, maybe using git diff with stats only for TypeScript files to keep the output manageable. I'll use a git diff command to scan the TypeScript files directly, filtering for just the .tsx files without pulling full context to keep the payload minimal. Looking at the Effect service conventions violations in the changed TypeScript files, particularly in the desktop app's computer history manager. The code uses mutable state within the service constructor closure, which the comments suggest violates Macroscope conventions around hiding dependencies in module globals, though it's not technically a module-level global violation. I'm also checking whetherEffect.addFinalizerwithLayer.effectmatches the codebase pattern — need to see if other services useLayer.scopedinstead. There's also a potential issue with error handling inrevealMemoryandremoveMemorywhere thepathparameter is available but omitted from the error context, which violates the guidance to retain real path/resource context at the wrapping site. In the server-side computer history service,Effect.tryPromiseis being used without a catch handler, which needs verification against the error handling conventions. Looking at the desktop control and adapter modules, the dependency injection patterns check out — services are properly acquired from the environment, and error handling usesEffect.catchTagscorrectly. The logging does capture the full error cause, which could be verbose but appears intentional. Now I need to verify whether the check-run instructions around dependency acquisition and runtime boundaries catch anything — searching forManagedRuntimeandrunPromiseusage in the diff, and checking ifLayer.scopedpatterns with finalizers are valid in this Effect version. I see that Layer.scoped isn't in the repo, so Layer.effect handles scoping by default in this version of Effect. Now I'm checking whether Effect.addFinalizer gets used inside make functions provided by Layer.effect elsewhere in the codebase. Looking at whether there are actual convention violations to report, I'm examining the error handling more closely. TheComputerHistoryOperationErrorfollows the accepted pattern—it includes a cause with schema defects and the operation itself, with a generic message derived from the operation type. However, there's a legitimate finding here: the convention says to "retain any real path, resource, request, or entity context available at the wrapping site," and while root/path context is available, it's being omitted from the error. Addingrootandpathto the error would be a moderate-confidence improvement. ForrunDaemonOp, it's not just a pure error factory—it wraps a promise withEffect.tryPromiseand has real behavior, so that's fine. Thelayerexport in the service module usesLayer.effectDiscardfor a background loop, which doesn't require a service tag, and theEffect.tryPromisecall catches intoUnknownErrorwhich then gets ignored or succeeds, so errors are being swallowed there. Looking at the bigger picture inserver.ts, the layer wiring is composingServerSettingsLayerLivetwice, but since Effect memoizes layers by reference within a single build, that should be fine. The real question is whether this violates the convention about not creating per-feature managed runtimes. Then there'smakeResolveEnabledDesktopMcp— it captures services and re-provides them, which could look like "fake dependency injection" or closures over singletons. But it's actually acquiring from the environment legitimately, which is the documented pattern for keepingR=neveron adapter session methods. I should check if this pattern already exists elsewhere in the codebase to see if it's an accepted local convention. The captured-service-and-reprovide pattern is already established in this codebase, so that's not a concern. Now I'm checking the "Imports and module namespaces" rule against the modified Effect service code. InDesktopApp.ts, the addition of named imports from@t3tools/contracts/settingsfor schema and config values is actually allowed by the guidelines, which explicitly permit named imports from whole packages like@t3tools/contracts. Looking at the other files,manager.tsimports pure helpers from@t3tools/shared/computerHistory, which is fine. IndesktopMcpBinary.ts, the named imports ofHostProcessEnvironmentandHostProcessPlatformfrom@t3tools/shared/hostProcessneed checking—the rule allows namespace imports when callers access service/tag members, but it's optional ("may"), so I should verify what convention the repo already uses for this module. The helper imports inClaudeAdapter.tsandCodexAdapter.tsare straightforward named imports from non-service modules, which are allowed. InCodexAdapter.ts, there's a namespace import from the computer history service module, which follows the correct pattern. Now I'm checking the test files and other imports:GrokAdapter.test.tsimportsServerSettingsServiceby name directly fromserverSettings.ts, which seems to violate the namespace import rule at service boundaries—though the rule doesn't explicitly exempt tests. I need to see how existing tests in the repo handle service imports to determine if this is acceptable or if it should be a namespace import instead. I'm deciding to skip the style issue since it's a legacy pattern and the guidelines say not to fail on optional preferences. For the desktopMcpLaunch test, I see it's using a test seam with a failing service injected through the Effect provider, which is an allowed testing pattern. Let me dig deeper into the strongest possible findings here. Looking at the dependency acquisition and runtime boundaries in manager.ts, I notice it uses a sync helper for resolving the desktop MCP binary path with fs.existsSync — that's imperative but wrapped inside Effect.tryPromise rather than hidden in a Layer.succeed, so it doesn't violate the convention. The server side uses proper FileSystem and Path services while the desktop deliberately uses a sync version for Electron main, which is intentional and acceptable. Node fs operations are allowed with diagnostics off. Now I need to check if there's any runPromise or ManagedRuntime usage in the changed files. Let me check the git history to see if this file was already reviewed in earlier commits on this branch, since the Macroscope Effect Service Conventions mention suggests the author has already addressed prior feedback. I should also look at existing review comments on the PR to understand what's been flagged and resolved so I don't duplicate any concerns. I'm checking whether the TypeScript file diff was complete or if there were any truncated sections I might have missed in my review. Now I'm evaluating the strongest findings to report. TheComputerHistoryOperationErrorstands out as a genuine violation — it wraps a multi-step pipeline (layout ensure, read, compose) in a single generic error without capturing resource context like the state directory or file path, which violates the convention of including stable, serializable domain context in errors. The message derivation andSchema.Defect()usage both check out fine — the operation field provides structural identification. In DesktopApp.ts, there's some redundancy with nestedEffect.catchTagsfollowed by an outerEffect.catch, but that's not a violation since the outer catch is intentionally handling the entire channel. Looking at the computerHistory service module, it exports a layer and standalone Effect functions without a Context.Service, which is appropriate since it's a helper module rather than a service — no need for amakefunction when the module doesn't own service construction. ThedesktopMcpLaunch.tsmodule correctly has both a resolver function and a maker variant that captures services. In computerHistory, failures are kept typed in Effect withorElseSucceedrather than bypassing the layer, which follows the convention. ThetryPromisecall converts errors to UnknownError and immediately swallows them to undefined, so defining a structured TaggedErrorClass would be pointless given the result is discarded anyway. The desktop manager has some dead code and uses a mutable state object in the service closure instead ofRef, but neither violates stated conventions. That leaves only Finding 1 as a potential violation — I need to examine it more closely to determine if it's substantial enough to fail the check, since the instructions say to only fail on clear convention violations, not optional style preferences. Looking at the error handling guidance more carefully: the rules call for capturing stable, serializable context like operation, stage, resource path, and normalized status. Here the error class only capturesoperationandcause, missing thestateDirandpaththat are available at every call site. That's a concrete gap against the stated conventions, not just a style preference. I should add an inline comment suggesting the error class includerootand optionalpathattributes. Beyond that,Effect.catchTagsin DesktopApp looks correct, and the Context imports in the client and session runtime files check out — those are using the right patterns. Looking at the schema predicates in CodexSessionRuntime, the privateisMcpToolApprovalMetawrapped byisMcpToolApprovalisn't redundant since the wrapper adds a mode check and takes different parameters. The meta schema declaration and other approval-related constants are fine too. Now I'll check the errors file in effect-codex-app-server. For the newComputerHistoryManagerservice inapps/desktop/src/computerHistory/manager.ts, the file layout follows conventions — it's a new file so the hoisting rule doesn't apply, and the namespace import alias correctly uses the module namespace even though it differs from the filename. TheLayer.Layer<ComputerHistoryManager>type annotation works fine sinceLayer.effectprovides the layer's scope, making requirementsnever. On the production service construction side, the manager takesstateDiras a parameter from callers rather than acquiringDesktopEnvironmentdirectly — sincestateDiris just a pure configuration value (a string path), passing it as a parameter is explicitly allowed and doesn't violate the dependency acquisition rule. I need to resolve the conflict between the check's default-to-failure instruction and the JSON schema requirement. Since I do have a finding to report, I'll output the JSON response with a failure state rather than the plain "All clear" text. Let me verify the finding is solid and get the exact line numbers from the file to include in my report. I'm considering adding arootfield and optionalpathfield to the schema alongside the existingoperationandcausefields, though I'm realizing this might require multiple changes across the file rather than a single inline suggestion.
1. modify_pr — Reviewed the new/changed Effect service code (apps/desktop/src/computerHistory/manager.ts, apps/desktop/src/ipc/methods/*, apps/server/src/computerHistory/service.ts, apps/server/src/desktopControl/*, adapter call sites). Module namespacing, Context.Service shape, make/layer exports, Effect.catchTags usage and runtime boundaries all look consistent with the conventions. One finding on error context.
Agent Credits: 293 credits