Repository navigation
Effect Service Conventions: 1 issue found
One convention violation found in the PR's changed scope.
apps/server/src/orchestration/importThread.ts(lines 36-37):importFailureis a pure error-construction helper ((message) => (cause) => new OrchestrationImportThreadError({ message, cause })) used only as a curriedmapErroralias. The conventions prohibit helpers whose only behavior is(...args) => new SomeError({ ...args }); construct the error at the failure boundary so its attributes andcausestay visible. The rest of this codebase already builds theseOrchestration*Errors inline (e.g.ws.ts,Normalizer.ts), so inlining here is both convention-compliant and consistent.
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/changed TypeScript under the configured include patterns, focusing on the new importThread.ts/importedMessages.ts service helpers, the ProviderService readThread addition, the new OrchestrationImportThreadError, and the contracts/RPC wiring.
Checked and found acceptable (not flagged):
- Dependency acquisition:
makeImportThreadis a plain factory composed inside thews.tsRPC layer, which acquiresProviderService,OrchestrationEngine, andProjectionSnapshotQueryfrom the environment viayield*and passes them in. This is legitimate boundary composition, not fake DI or a hidden runtime; noManagedRuntime.make/runPromise/Layer.succeedsmuggling was introduced. - Imports: Effect modules are imported as subpath namespaces;
@t3tools/contractsuses named imports as allowed. - Error class:
OrchestrationImportThreadErrormirrors the establishedOrchestration*Errorfamily (message+ optionalcause) exactly, so its message-only shape was treated as the existing repo convention rather than a new violation, per the instruction not to demand repository-wide cleanup. - Wrapper messages are derived from static strings / input identifiers, not from
cause.message.
🔍 Agent activity — 1 tool call
💭 I'm reviewing this PR to check if it follows Effect service conventions, starting with the new files like
importThread.tsandimportedMessages.ts. The imports look correct—they're using namespace imports from Effect subpaths likeimport * as Crypto from "effect/Crypto". Now I need to examine the dependency architecture and how the services are structured. Looking atmakeImportThread, it accepts dependencies as parameters—orchestrationEngine,projectionSnapshotQuery,providerService—rather than acquiring them from the environment. Inws.ts, these dependencies are yielded from their respective services and then passed intomakeImportThread. The question is whethermakeImportThreaditself violates the convention by accepting service implementations as parameters, or if this is acceptable since it's not a Context.Service but just a factory function. anding unrelated cleanup. The convention says not to retain standaloneFooServiceShapetypes, butProviderServiceShapealready exists in the codebase. Since the PR only addsreadThreadto it rather than introducing the type itself, flagging this would be demanding repository-wide cleanup outside the PR's scope. Let me examine the actual files to understand the existing patterns and see whetherProviderService.tsandOrchestrationEngine.tsfollow the Shape convention or use the Context.Service approach. I should use the commit hash to reference the branch head. I'm checking the conventions around error constructors—specifically whether a curried helper that just wrapsnew OrchestrationImportThreadErroris necessary, or if I should construct the error directly at the failure boundary to keep the attributes and cause visible. The convention is explicit that pure error-construction helpers should be avoided unless they perform real normalization, pass through domain errors, or add reusable context—importFailuredoes none of these, so it's technically a violation. The reuse across many call sites does reduce boilerplate, but that's not enough to justify it under the stated rules. I should flag this as a legitimate finding, though I need to weigh whether it's worth raising given the practical benefit of the repetition reduction. Now I'm looking at the error modeling forOrchestrationImportThreadErroritself to see if there are deeper concerns there. The core issue is that this error stores only an unstructured message and optional cause, which directly violates the convention that messages should be derived from structured attributes rather than stored as free-text data. This feels like a legitimate finding, though I'm weighing whether it's significant enough to flag given that the error does preserve the underlying cause. Looking more carefully, the real problem is that the messages embed variable context—externalId, driver, workspaceRoot, projectId—as formatted strings instead of capturing them as structured fields. That's a concrete violation of the convention's requirement to capture stable, serializable domain context. I need to identify which findings are strongest and most clearly introduced or retained in the pull request's scope, avoiding over-flagging optional style preferences. The clearest violation isimportFailure, a pure error-construction helper that violates the explicit convention against adding helpers whose only behavior is wrappingnew SomeError(...). The convention says to construct errors at the failure boundary so attributes and cause remain visible, and to keep mappers only when they perform real normalization or add reusable context—not just for syntactic convenience. The target error channel only acceptsOrchestrationImportThreadError, so wrapping is appropriate. The real issue is thatimportFailureis a curried factory that just saves typing—it doesn't add reusable context since the message is provided at each call site, making it a textbook example of the anti-pattern. I need to verify whether the error design itself (message-only structure) violates the guidelines. in the ws layer, so maybe the convention doesn't strictly apply here. Let me think about whether this needs to be flagged or if it's acceptable as-is. The key distinction is whethermakeImportThreadis truly hiding dependencies or just composing them locally within the layer. Since the layer itself acquires the services throughyield*and exposes those requirements, passing them into a pure helper function is a standard pattern — the dependencies aren't hidden, they're just organized at a finer granularity within the boundary. The stronger finding isimportFailure, which introduces the anti-pattern explicitly called out by convention and wasn't present before this PR. That's worth flagging. I should also verify the error message naming convention more carefully to make sure I'm applying it consistently. I'm noticing thatOrchestrationImportThreadErrorfollows the same pattern as the other orchestration errors throughout the codebase, all using a consistent structure with a message field and an optional cause field. This appears to be the established convention for how these errors are defined in the repo. The instructions say to avoid flagging style preferences that are already pervasive in the codebase, and since this error design mirrors what's used everywhere in this error family, flagging it would be demanding repository-wide cleanup rather than addressing a concrete violation in this PR. So I shouldn't flag the error class design itself. Now I'm looking at theimportFailurehelper that's new in this PR. I need to check if similar curried error factory patterns exist elsewhere for orchestration errors to understand whether this is an established convention or a deviation from the codebase style. I'm looking at how the existing orchestration service handles error mapping to see what patterns are already established for converting errors to OrchestrationXXXError types. I'm noticing the codebase follows a consistent pattern of constructing errors inline at failure boundaries—like in ws.ts and Normalizer.ts—where they useEffect.mapErrorto build the error with its message and cause right where it fails. The PR'simportFailurehelper breaks from this by creating a separate error-construction function, which actually goes against the convention's guidance about keeping error attributes and cause visible at the failure point. The convention explicitly warns against helpers that just wrap error construction, and whileimportFailuredoes get reused about 10 times, it doesn't really add meaningful normalization, pass through domain errors, or provide reusable context—it just centralizes a pattern where the message gets passed in each time anyway. Given how specific and strong the convention's language is on this exact anti-pattern, I think this is worth flagging as a clear violation rather than just a style preference. I should be careful not to be overly aggressive though. The reuse does reduce boilerplate, but the codebase itself constructs these errors inline elsewhere, so the pattern isn't consistent. I'll frame it as a primary finding but keep it as a suggestion. Now I'm checking whether there are other issues worth raising. The DI pattern inmakeImportThreadseems reasonable since ws.ts is the application boundary where services are acquired from the environment. Looking back at the imports in importThread.ts, the effect imports are all using namespace subpath imports as expected, Contracts is a named import which is allowed, and the local service modules are imported as types. Let me verify the namespace convention is being followed throughout. Actually, I'm noticing that the code usesPick<ProviderServiceShape, ...>but the convention prefersProviderService["Service"]. However, these Shape interfaces are pre-existing in the codebase, not introduced by this PR, so flagging their consumption would require repo-wide cleanup that's outside the scope here. Since ProviderService is already defined with a separate ProviderServiceShape interface, using that shape is consistent with the existing pattern, so I'll skip this as a violation. For error handling, I'm checking whether messages are derived from cause or cause.message — the existing code in Normalizer.ts already does this, but in importThread.ts the messages are static strings or templates with input values, not derived from the cause, so that's fine. The main finding is stillimportFailure, and I need to decide if it's significant enough to fail the check. Looking at the convention more carefully,importFailureis a curried helper that returns a function taking cause and constructing the error — exactly the anti-pattern the convention warns against when used with mapError. The attributes are visible at the call site, but the convention specifically flags this pattern as problematic, so this seems like a legitimate finding worth reporting. I need to decide on the check state. The convention is explicitly listed as a "Do not," so it's a real rule, not optional. I'll post a comment flagging the violation. For the state itself, the guidance says a clear convention violation may fail the check, but I should also consider whether to set it to neutral given this is a relatively minor stylistic issue. The schema description seems to be cut off, but I'm leaning toward posting the finding and setting the state based on the severity of the violation. There's a tension between the system prompt requiring JSON output and the customer instruction to return exactly "All clear" as plain text when there are no findings. The system format takes precedence, so I'll reconcile this by outputting JSON with a success state and "All clear" as the summary when there are no findings, and JSON with a failure state when findings exist. Since I've identified an importFailure violation, I should report it as a single finding. I'm second-guessing whether this is worth flagging though. The importFailure function is reused across multiple call sites in the module as a consistent wrapper for mapping lower-level failures into the module's domain error. That could arguably qualify as "reusable context/control flow," but it doesn't really add meaningful context since each message is custom. I think flagging it is the most defensible approach. Let me scan once more to make sure there's nothing more serious I'm overlooking. Looking at the ws.ts wiring, I can see it's a legitimate application boundary — dependencies are pulled from the environment at the layer and passed to a pure factory function, not fake DI. That's fine. But I'm still curious about importFailure — is it wrapping already-structured domain errors from orchestrationEngine.dispatch, or is it doing something else? Actually, looking closer, the dispatch returns OrchestrationDispatchCommandError, which is a structured domain error. When it gets wrapped into OrchestrationImportThreadError with the cause preserved, that follows the right pattern: at a translation boundary, if the target error channel can't accommodate a pass-through, wrapping is the only option. So that's legitimate too. My single finding is the importFailure convention itself. Let me add an inline comment to flag it. I need the head commit hash for the review — that's e48610f. Since importFailure is used about ten times across the codebase, a multi-site diff suggestion won't work, so I'll just describe the issue without proposing a specific change. Writing the comment... The convention violation is explicit and introduced in this PR, so failing the check is justified. I'll post an inline comment with the expected fix and request changes on the review. I'll post an inline comment on line 37 where the new error is being thrown, making sure to include all the required fields for the review tool. The dependencies are properly composed through the factory function, so that's not an issue. My only real finding is theimportFailurecase, which I'm going to flag with an inline comment. I keep second-guessing whether it's worth failing on, but the convention is clear and this pattern is established in the codebase, so I'll stick with it.
1. modify_pr — Effect Service Conventions — 1 finding. The importFailure helper in apps/server/src/orchestration/importThread.ts is a pure error-construction mapper, which the conventions ask to avoid. See the inline comment.
💭 I'm returning the JSON response with a failure state for the check run.
Agent Credits: 79 credits