Repository navigation
Effect Service Conventions: 1 issue found
Found 1 convention violation in the changed scope.
packages/contracts/src/worktree.ts(WorktreeOperationError): the error stores adetail: Schema.Stringfield populated from the wrapped error's message (errorDetail(error)inapps/server/src/mcp/toolkits/worktree/handlers.tsreturnserror.message) and derives itsmessagegetter fromthis.detail. The error conventions prohibit adetailfield that merely copiescause.messageand is then used to build the wrapper message. The underlying failure should be preserved ascause(e.g.cause: Schema.Defect()), themessagederived solely from the structuraloperationdiscriminator, andasOperationErrorshould passcause: errorrather than a stringifieddetail. The siblingpreviewAutomation.tserrors already follow this pattern (cause: Schema.Defect()plus bounded diagnostics such asremoteMessageLength).
An inline review comment with a suggested fix was posted on packages/contracts/src/worktree.ts.
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: new worktree MCP toolkit (apps/server/src/mcp/toolkits/worktree/tools.ts, handlers.ts, tests), contracts (packages/contracts/src/worktree.ts), and touched registration/context files.
Checked and found compliant:
- Namespace imports:
handlers.tsusesimport * as Effect from "effect/Effect"etc.;import { Schema } from "effect"inworktree.tsandimport { Tool, Toolkit } from "effect/unstable/ai"intools.tsmatch the established sibling modules (previewAutomation.ts,preview/tools.ts) and are allowed for schema/whole-package imports. - Error modeling:
WorktreeOperationErrorcorrectly uses a multi-valueoperationdiscriminator with a generic message (a valid single-service-error model).WorktreeCapabilityUnavailableError,WorktreeThreadNotFoundError,WorktreeHandoffAlreadyInWorktreeError, andWorktreeHandoffInvalidRequestErrorare distinct tagged errors with structured attributes and messages derived from them, consistent withpreviewAutomation.ts. Effect.catchon the setup-script step intentionally handles the whole error channel (setup failure must not fail the handoff), which is appropriate.- Tests use test/mock layers for external services rather than mocking core business logic.
The only violation is the detail/message handling in WorktreeOperationError combined with errorDetail/asOperationError, which discards the underlying cause and reintroduces a raw-message detail field the conventions call out explicitly.
🔍 Agent activity — 1 tool call
💭 I'm examining the diff to check for Effect service convention violations in the new worktree-related files, starting with the imports and module namespacing in the tools file. Looking at the handlers and contracts files, I see namespace imports from Effect subpaths like
effect/Cryptoandeffect/Effect, which follow the convention. But in the contracts file there's a consolidated named import from"effect"for Schema, which the convention flags as a violation in touched Effect service code — I need to determine if this actually qualifies as a violation or if it's acceptable in this context. Looking at theWorktreeOperationErrorclass, it's using a multi-value operation discriminator with a generic detail message, which aligns with the convention for service-level errors. But I'm noticing thedetail: Schema.Stringfield and need to check if that violates the guideline about not using generic string fields. TheasOperationErrorfunction is extracting the error message and storing it as a string detail, which is exactly what the convention warns against — it's discarding the actual error object and replacing it with just the message. This violates the principle of preserving the immediate underlying error ascause. Additionally,asOperationErroris a curried helper that's used multiple times, but it's just wrapping the error constructor without performing any real normalization or domain-specific logic, which the convention says to avoid. The real issue is thatWorktreeOperationErrorconstructs its message from the stringifieddetailfield, which came fromcause.message. The convention is clear: preserve the underlying error ascauseand derive the message only from the operation itself — keep it generic. The fix would be to add acausefield to store the original error and change the message to depend only on the operation, not on the stringified cause. Before finalizing this as a violation, I should check how similar errors are defined elsewhere in the codebase — particularly inpreviewAutomation.tsand the preview handlers — to see if this detail pattern is an established idiom or a genuine deviation from the conventions. There's a formatting issue with how the repo parameter is being handled. The Schema import pattern is consistent with the codebase conventions, so that's not an issue. The real focus is on howWorktreeOperationErrorgets populated with the error detail from the cause message. Looking at the preview pattern, it deliberately avoids putting raw messages into the detail field—instead it captures structured diagnostics like lengths and categories while preserving the original error ascause. The worktree code violates this by stringifying the message and storing it in detail without keeping the underlying error, which loses important context. TheasOperationErrorhelper does add reusable context by wrapping the operation name, but it's still part of the same problem: it's normalizing in a way that discards the cause rather than preserving it alongside the structured information. The real issue is the message getter itself—it derives the message from${this.detail}where detail is just the stringified cause message, which directly violates the convention that messages should come only from stable structural attributes like the operation discriminator. The fix is to replace the detail field with a proper cause field, update the message to derive only from operation, and have the helper pass through the original error as cause instead of stringifying it. Since the error definition lives inpackages/contracts/src/worktree.tsand that's where the detail field and message getter are defined, I should place an inline comment there to flag this violation. I'm also checking whetherSchema.Defect()is available—it's already used in previewAutomation.ts, so it's accessible here. TheWorktreeCapabilityUnavailableErrorlooks fine by comparison with the preview equivalent. And for theEffect.catchusage in handlers.ts, the convention allows it when the entire error channel is intentionally handled, which appears to be the case with the script runner failures. Now I'm looking at the imports in tools.ts to see if they match the pattern used in preview. The import pattern checks out against the established convention in preview/tools.ts. Looking at the core issue:WorktreeOperationErrorstores a rawdetail: Schema.Stringthat copieserror.message, while the preview approach is more careful—it capturesremoteMessageLengthand usescause: Schema.Defect()instead. The pattern seems to be avoiding that direct message copy in the detail field. I need to pinpoint where this violation occurs. There are two key locations: theWorktreeOperationErrordefinition itself in worktree.ts (thedetailfield and message getter), and then handlers.ts whereerrorDetailgets assigned andasOperationErrorwraps the error. The real fix spans both files, but I should focus the comment on the root cause in worktree.ts'sdetailfield, explaining how the message should derive from structural attributes rather than the underlying cause. Let me check the exact line numbers in the actual worktree.ts file. Looking at the handlers.ts file to find the exact line numbers where I can add another comment about the errorDetail/asOperationError conversion. I'm identifying the core issue:WorktreeOperationErroris storing a stringified version of the underlying error's message in adetailfield, then using that same field to construct its own message. This violates the principle of preserving the original error as thecauserather than extracting and reusing its message content. The fix requires updating both the error contract inworktree.ts(lines 135–140) to usecause: Schema.Defect()instead, and adjusting the handler mapper inhandlers.tsto stop discarding the cause when it callserrorDetail. I'll place a single focused comment on the contract error that explains the full correction, including how the handler needs to change to support it. I'm setting the review state to failure since there's a clear violation, then submitting it with an inline comment spanning lines 135-140 in worktree.ts that includes a diff showing the necessary changes.
1. modify_pr — One convention issue: WorktreeOperationError copies the underlying cause.message into a detail field and builds its message from it, instead of preserving the real failure as cause and deriving the message from structural attributes. The sibling previewAutomation.ts errors already follow the expected pattern (cause: Schema.Defect() plus bounded diagnostics). See inline comment.
💭 Generating the JSON output...
Agent Credits: 88 credits