Repository navigation
Effect Service Conventions: 1 issue found
One convention violation found in the changed Effect code:
apps/server/src/cloud/CliTokenManager.ts(line 224):outOfBandOAuthLoginrecovers the statically knownTimeoutErrortag withEffect.catchIf(Cause.isTimeoutError, …). The convention requires catching statically known tagged failures withEffect.catchTags. The siblingloginflow in the same file already does this for the identicalTimeoutErrorafter its ownEffect.timeout, so the two paths are inconsistent. Switching also removes the last use of theCauseimport added in this PR, which should then be dropped.
An inline review comment with a suggested fix has been posted.
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.
Prior-run findings were re-checked and are all resolved at the reviewed head (5b707d7):
apps/server/src/cli/connect.tsnow usesEffect.catchTagsinauthorizeCli,disconnectCloud, andofferBootService.apps/server/src/cloud/CliTokenManager.tsloginflow now usesEffect.catchTags({ TimeoutError }).BootServiceCommandErrorno longer carries adetailfield that copiedcause.message; it now captures structural attributes (step,exitCode,stdoutLength,stderrLength) withcause, and derives its message fromstep/exitCode.
Other areas reviewed and found compliant:
- Namespace imports for Effect subpaths and local service modules (
BootService,ProcessRunner); named imports retained only for pure helpers/constants/types from@t3tools/shared/connectAuth. bootService.tsservice definition: inlineContext.Serviceinterface, real exportedmake, exportedlayer,BootService["Service"][...]type annotations, dependencies (ProcessRunner,FileSystem,Path, host references) acquired from the environment; the optionalhostparameter is a pure value seam, not service injection.- Error classes use
Schema.TaggedErrorClasswith messages derived from structural attributes and preservecause.
Methodology: reviewed the full diff plus the current contents of bootService.ts, cli/connect.ts, and cloud/CliTokenManager.ts; confirmed Cause. is referenced only at line 224.
🔍 Agent activity — 1 tool call
💭 I'm reviewing this PR against the Effect service conventions to see if previous issues have been resolved. The prior run flagged problems with
catchTagusage and aBootServiceCommandErrordetailfield issue, so I'm checking the current diff to determine whether those have been addressed. Looking at the changes inapps/server/src/cli/connect.ts, I can see the code is now usingEffect.catchTagsin multiple locations, which suggests an attempt to fix the earlier flagged issues. The message getter now properly constructs the error message based on the step and exit code, addressing the earlier concern about exposing raw content. Now I'm examining the current imports inCliTokenManager.tsto check for any new violations in how dependencies are being pulled in. Looking at the error handling inauthorizeCli, I see it's translating errors at a boundary—passing through structured domain errors like quit errors and token manager errors while wrapping anything unknown in a new authorization error. Thestoreoperation was also added to CloudCliTokenManager, and I'm checking whether the previouswrapErrorremoval was handled correctly. The diff removes that curried helper and replaces it with an inlineEffect.mapError, which aligns with the convention against single-use error wrapper helpers. Now I'm examining the structure ofbootService.tsto verify it follows the service definition conventions—checking the order of imports, constants, error definitions, and the Context.Service setup. The error class wraps multiple filesystem operations without capturing specific context like the operation type or file path, which violates the convention of mapping failures with stable domain context rather than bundling an entire multi-step pipeline into one generic error. However, I need to consider whether this is actually a clear violation worth flagging—the convention does allow semantically precise error tags to preserve real causes without inventing redundant fields, and path context is technically available at the wrapping site even if it's not being captured. This feels borderline, so I should focus on the clearest violations instead. Let me search through the actual current code to see if there are any remaining instances of singularcatchTagthat I might have missed, since the diff represents the full scope of changes. Let me pull up those files to see what's actually there. I need to restructure the repo parameter as an object that includes the URL. Checking whether the previous issues with catchTag have been resolved in the current code—I see connect.ts is now using catchTags, and I need to verify that CliTokenManager.ts has the fix applied as well. I'm also noting that the store method was added to CloudCliTokenManager in connect.ts, and the test file is mocking it with an unused operation. Looking at the isCloudCliTokenManagerError constant, it's a direct Schema.is call used locally in connect.ts without being wrapped in a redundant function, so that doesn't violate the convention about exporting schema predicates. Now I need to check CliTokenManager.ts to see its current state and look for any remaining issues. I'm checking the codebase for any new convention violations introduced in the current version, starting with the imports in connect.ts to see if they're following the expected patterns. The PR adds namespace imports for Terminal, Crypto, and Schema which follow the convention correctly. However, I'm noticing that CloudCliAuthorizationError stores a validation message string as its cause field rather than an underlying error object, which is a borderline case—the convention expects the exact underlying value as cause, but here it's a domain-level validation message instead. More concerning is BootServiceInstallError, which wraps about eight different filesystem operations (directory creation, file existence checks, reads/writes) all under a single generic error with just a cause field and no context about which operation failed or what path was involved. The convention explicitly discourages this pattern of wrapping multi-step pipelines in one generic error without capturing stable domain context like operation type or resource identifiers. This is a genuine violation worth flagging, though I should check how BootServiceComm handles similar scenarios first. The cause field actually preserves the path context through Effect's FileSystem errors, so the generic message is defensible even without an explicitstepfield. This probably isn't a clear enough violation to flag. Let me look for stronger violations elsewhere, like howEffect.ignoreis being used. TokenManager captures the services context and re-provides them to dependent operations—this is a legitimate pattern since the dependencies are still declared in the make function's requirements, not hidden away. Let me verify theEffect.catchusage at line 398 in connect.ts to see if there are any remaining issues. The error handler aftercatchTagsprocesses the remaining error channel (BootServiceCommandError | BootServiceInstallError) withEffect.catch, which aligns with the convention that this operator is appropriate when handling the entire remaining error channel intentionally. The earliercatchTagsat line 395-397 correctly handles the BootServiceUnsupportedError case specifically, so that's properly addressed. Now I'm checking whether there are any new convention violations introduced in the current version compared to the prior commit, and reviewing a few additional spots like theCloudCliTokenManagerErrorunion predicate to ensure everything's consistent. The three error classes—BootServiceCommandError,BootServiceInstallError, andBootServiceUnsupportedError—are genuinely distinct and handled separately in the catch block, so that's fine.BootServiceCommandErroruses its multi-valuestepfield to drive the user-facing message, which follows the acceptable pattern of a service-level error with an operation discriminator. I'm leaning toward not flaggingBootServiceInstallErrorsince the underlying cause is an Effect PlatformError. But actually, the convention is pretty clear: I should map failures where context is known rather than wrapping an entire pipeline in one generic error, and each wrapping site does have a known path. The inconsistency bothers me—command errors capturestepfor context, but install and filesystem errors don't, even though they could. That's worth addressing. I'm weighing whether this is a concrete enough violation to flag given the "defaults to failure" check. The prior run's findings on BootServiceCommandError were addressed thoroughly, which suggests the author is responsive to feedback. Let me verify whether the current code is the same version that was reviewed before or if there's been an update. Checking the newly added imports in publicConfig.ts — those are also pure helper constants from the connectAuth module, which follows the allowed pattern for named imports. TheHostProcessExecutablePathandHostProcessArgumentsare Context references imported as named imports in bootService.ts and connect.ts, which aligns with how the existingHostProcessEnvironmentandHostProcessPlatformare already handled. For the service modules, I'm using namespace imports likeProcessRunnerto access the service and its layer, which follows the established pattern. Looking at the structure of bootService.ts, the order flows through imports, constants, pure helpers, then the BootServicePlan interface before moving into error classes, the Context.Service tag with its inline interface definition, the make function, and finally the layer export. This arrangement is fine since pure helpers and plan interfaces don't conflict with the convention around error and schema declarations. The interface is properly defined inline within Context.Service without a separate shape type, and the type annotations use the correctBootService["Service"]["install"]pattern. Both make and layer are properly exported, with layer correctly usingLayer.effectto wrap the service creation. For the test file addition, the stub store dependency is acceptable since BootServiceHost is just pure configuration values rather than an actual service dependency. ProcessRunner is correctly acquired from the environment viayield* ProcessRunner.ProcessRunnerrather than being injected as a parameter, which maintains proper dependency handling. Everything appears to align with the established conventions. Now I'm reconsidering the BootServiceInstallError one more time — Effect's FileSystem operations fail with PlatformError that includes the path in the cause, and the generic user-facing message is appropriate for a CLI context. The structural details are preserved in the error cause, so this is defensible and doesn't constitute a clear violation. Given all this analysis, the review looks clean. But I'm hitting a conflict in the instructions: the customer's check definition says to respond with exactly "All clear" when there are no findings, yet the outer system requires JSON output conforming to a specific schema. The JSON schema is the mandatory infrastructure format, so I need to set the AA_state to "success" with a concise summary rather than just the plain text response. Since the check defaults to failure and I found no findings, success is the appropriate conclusion. Let me verify I'm being thorough though—I should double-check the diff between the prior run and current state to confirm the previous issues were actually fixed and nothing new was introduced. Looking at the helper functions likecheckConnectAuthCodereturning a union type and the timeout handling inoutOfBandOAuthLogin, these don't violate the service error conventions since they're pure functions or properly using the Effect error channel. Actually, I'm spotting an inconsistency in how timeouts are handled. Thelogin()function usesEffect.catchTagsto handleTimeoutError, butoutOfBandOAuthLoginusesEffect.catchIf(Cause.isTimeoutError, ...)instead. The convention is clear that statically known tagged failures should usecatchTags, notcatchIfwith a predicate—even thoughCause.isTimeoutErroris a structural predicate on the Cause level rather than a schema predicate. SoCause.isTimeoutErroris a type guard that checks if a value is a TimeoutError, and when used as thecatchIfpredicate, it's really just checking the_tagfield. The convention says to usecatchTagsfor known tag variants instead, so this should be refactored toEffect.catchTags({ TimeoutError: ... })to match the pattern used elsewhere in the same file at lines 332-334. This is a clear inconsistency worth flagging. The convention's intent is clearly about usingcatchTagsfor known tagged failures, and the inconsistency is reinforced by the fact that the same file handles the identical error type withcatchTagsjust a few functions down. WhileCause.isTimeoutErroris technically a built-in structural guard rather than a schema predicate, the spirit of the convention and the codebase's own pattern suggest this warrants a note about the inconsistency. The previous run flagged four catchTag issues, so this single catchIf case is analogous and consistency suggests I should report it as well. Let me think through whether usingCause.isTimeoutErroras a catchIf predicate is actually problematic here. done with catchTags elsewhere in the same file, and TimeoutError is a statically-known tagged failure that should follow the same pattern as other tagged errors in the codebase. The inline comment here is legitimate and actionable—it aligns with the convention of using precise, focused feedback on the smallest relevant line range, which matches what the previous review established. Now I'm weighing whether to post comments directly to the PR or just include findings in the check summary. The customer's instructions don't explicitly mandate posting review comments, but the prior run did post them, so I should verify what the check's actual requirements are. I'm checking whether the catchIf at line 224 in outOfBandOAuthLogin was flagged in the prior run or if it's a new finding. The previous run caught a different issue at line 227 in the login flow (now fixed to use catchTags), so this appears to be a separate location that wasn't previously reviewed. chTags({ ... }), including when handling only one tag. Do not usecatchIfwith a schema predicate merely to recover one or more known_tagvariants, and do not usecatchTag. ...catchIfremains appropriate for genuinely structural predicates such as inspecting an underlying platform error code."Cause.isTimeoutError— is it a "schema predicate"? No, it's from the Cause module. Is it recovering a known_tagvariant? Yes, TimeoutError. The rule "Do not use catchIf with a schema predicate merely to recover... known _tag variants" — the qualifier "with a schema predicate" limits the prohibition to schema predicates.Cause.isTimeoutErroris not a schema predicate, so strictly it's not prohibited by that specific clause. But wait, the convention also says "Do not usecatchIf... to recover one or more known_tagvariants" — that's a separate prohibition without the schema predicate qualifier. SocatchIfwithCause.isTimeoutErrorviolates this broader rule, making line 224 genuinely inconsistent with the convention. The strongest argument is consistency: TimeoutError is a statically known tagged failure, andcatchTagsis the prescribed tool for exactly this pattern. I'll flag this as a finding but frame it as a suggestion rather than a strict violation, keeping the tone aligned with how I've handled similar cases, and mark it as a failure to match the prior behavior. I can verify thatCause.isTimeoutErrorexists andcatchTags({ TimeoutError })is the proper equivalent — line 332 already demonstrates this exact pattern afterEffect.timeout, so applying it to line 224 is straightforward and consistent with the codebase. The handler parameter at line 224 is labeledcausebut actually receives the TimeoutError value itself, which I should clarify in my comment. Writing the inline suggestion... I'm realizing that swapping tocatchTagswould leave theCauseimport unused, which means this wouldn't be a fully self-contained inline suggestion since it would require removing that import as well. That violates the constraint that inline suggestions shouldn't require other changes. I'll go with an inline suggestion for the catchTags change on line 224 and explicitly call out in prose that the Cause import added in this PR becomes unused and should be removed. That way the suggestion is actionable and the import cleanup is clear. I'll post the review comment and mark the check as failed. I'll post the inline comment through the GitHub PR review API, setting the appropriate fields for a single-line comment on the right side of the diff. Now I'm verifying that line 224 is actually part of the diff — sinceoutOfBandOAuthLoginis entirely new code added in this PR, lines 206-242 should all be on the RIGHT side. I'll write the comment explaining thatEffect.catchIfwith a predicate should follow the convention of usingEffect.catchTagsfor known tagged failures instead. The suggestion replaces the predicate-based catch with a tagged catch that handlesTimeoutErrordirectly, which matches what the siblingloginflow already does. This also makes theCauseimport unnecessary, so I should note that it can be removed. I'm checking whether thecatchIfat line 224 inoutOfBandOAuthLoginwas already present before this rename commit, or if it's something new that should've been flagged in the prior review. The previous feedback focused oncatchTagat line 227, so I need to verify if thiscatchIfusage is actually a separate concern that wasn't addressed yet. I've confirmed thatCause` is only referenced once at line 224, so removing it from the imports is necessary. Now I'm drafting the GitHub PR review with an inline comment spanning lines 224-226 on the right side, and I'll include a suggestion block to show the fix. Since the suggestion alone won't cover the import removal, I'll note that in the comment text and flag it clearly so reviewers know to delete the unused import after applying the suggestion. Let me write the review body concisely.
1. modify_pr — One Effect convention issue found in the out-of-band OAuth flow. Prior findings (catchTag usages and the BootServiceCommandError detail field) have all been resolved.
💭 I'm preparing to output the JSON validation result, which shows a failure with one finding that I need to document with a title and summary.
Agent Credits: 90 credits