Skip to content

Address cursor bot review: session-gate, transcript tail, mobile noise

MacroscopeApp / Macroscope - Effect Service Conventions failed Jul 2, 2026 in 8m 35s

Effect Service Conventions: 1 issue found

WorkflowInspectionError discards the underlying failure instead of preserving it as cause.

  • packages/contracts/src/workflow.ts — the new WorkflowInspectionError (fields operation, reason, detail) has no cause field. Its read-failed/not-found reasons wrap real filesystem/Node failures, so the immediate underlying error, chain, and stack are lost. The service error conventions require a wrapped real failure to preserve the immediate underlying error as cause alongside the structural fields (optional here, since invalid-path/unsupported are pure validation reasons with no underlying failure). This also diverges from the codebase's own read-from-disk pattern in assets.ts, which uses cause: Schema.Defect().
  • apps/server/src/workflow/WorkflowInspectionService.ts — every wrap site (resolveContained, readScript, readJournal, readAgentTranscript) binds cause in its catch/mapError callback but never forwards it into the constructed WorkflowInspectionError, so the platform error is dropped.

Inline comments posted with the suggested fix.

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 Effect service code under the configured include patterns, focused on the new WorkflowInspectionService and its workflow.ts contracts, plus the stopTask additions to ProviderService/ClaudeAdapter and the new thread.task.stop command/event.

Checked and found compliant:

  • Namespace imports for Effect modules (Context, Effect, FileSystem, Layer) in WorkflowInspectionService.ts; named imports from @t3tools/contracts are permitted.
  • Context.Service tag with inline interface, real make, and export const layer order in WorkflowInspectionService.ts.
  • message derived from structural attributes (operation + static detail), not from a stringified cause; detail values are human-authored constants, not copies of cause.message.
  • reason is used only for diagnostics/tests, not to select the user-facing message or drive caller control flow, so a single service-level error with a multi-value discriminator is acceptable and separate error classes are not required.
  • provider.task.stop.failed handling in ProviderCommandReactor.ts reuses the established appendProviderFailureActivity + Cause.pretty pattern already pervasive in that file (not a newly introduced deviation).
  • Existing ProviderServiceShape/ClaudeAdapterShape references are pre-existing types, not introduced by this PR, so they are out of scope for cleanup.

Reference for the expected pattern: packages/contracts/src/assets.ts (AssetWorkspaceAssetInspectionError with cause: Schema.Defect() for wrapped failures, AssetWorkspaceAssetNotFoundError without a cause for pure not-found).


🔍 Agent activity — 1 tool call

💭 I'm reviewing the new Effect service files for convention violations, starting with the WorkflowInspectionService and its contracts. I need to check that Effect modules are imported as namespaces and verify the rest of the conventions are being followed. The imports look good with proper Effect namespaces and allowed package imports. The service definition uses Context.Service with an inline interface, which is correct, and the make function is a proper constructor with Layer.effect for the layer definition. Now I'm examining the error class structure to see if it violates the convention about splitting semantically distinct failures into separate error classes when using discriminators like reason or kind. Looking at the WorkflowInspectionError, the reason field drives the test assertions but doesn't actually branch the user-facing message or control flow in the application code—the message is constructed from operation and detail instead. So reason is purely diagnostic and acceptable as a field. The detail field isn't copying cause.message either; it's a human-authored constant string like "Path must be absolute." that becomes part of the message. The real question is whether the error handling properly preserves the underlying filesystem error as a cause when wrapping failures. In the read operations, filesystem errors are being mapped to WorkflowInspectionError with a reason like "not-found" or "read-failed", but the original cause is discarded entirely. The convention requires preserving the immediate underlying error as a cause field when wrapping real failures. Since some constructions are pure validation errors without an underlying failure, cause should be optional, but it needs to be populated in the read-failed and not-found cases. Currently there's no cause field at all, so the error chain is lost—this is a legitimate violation of the convention. The core issue is that WorkflowInspectionError doesn't preserve the underlying filesystem error as a cause field when wrapping real read failures—this violates the explicit convention to maintain the immediate underlying error. Let me check how other modified services handle errors. ProviderService uses the existing toValidationError helper for its new stopTask method, which follows established patterns. Now I'm looking at ClaudeAdapter to see how it implements stopTask. The convention is clear that when wrapping real failures, I need to preserve the underlying error as cause to maintain the error chain. The readScript, readJournal, readAgentTranscript, and resolveContained functions all wrap filesystem errors into WorkflowInspectionError without capturing the cause, which breaks the error chain. I should flag this as a violation and suggest adding a cause field to the error class, then passing the underlying error when constructing these wrapped errors. I need to adjust how the repo parameter is being formatted. I'm checking how the codebase handles wrapped failures by looking at the cause field pattern—whether it uses Schema.Defect() as required or Schema.optional(Schema.Defect())—and I want to examine similar file-read error implementations in project.ts and assets to see if they follow the same structure with both cause and reason fields. Looking at how the codebase structures its error classes, I can see the pattern: errors that represent actual failures wrap the underlying issue with cause: Schema.Defect(), while not-found errors stand alone without a cause since they're not wrapping another failure. Comparing this to WorkflowInspectionError, the critical issue is that it drops the underlying filesystem errors entirely instead of preserving them as cause. The convention is clear that when translating a real failure, the original error must be kept in the chain so the complete context remains available for debugging. The cause field should be optional since some error cases like invalid-path originate without an underlying failure, while read-failed and not-found wrap real failures—so I need to mark this as a genuine convention violation where the wrapping sites drop the cause entirely. Let me locate the exact lines in the error class definition and the wrapping sites to comment on the fix needed. I'm seeing that the error handling in those catch and mapError blocks captures the cause but never actually passes it into the WorkflowInspectionError constructor — the error class doesn't even have a cause field. This breaks the pattern established elsewhere in the codebase like assets.ts, which properly preserves the underlying error. Let me check the full error class definition to understand what fields it actually supports. I'm checking whether the ProviderCommandReactor's handling of provider task failures and the provider.task.stop.failed event respects the conventions around what can go into detail fields. The reactor is using Cause.pretty(cause) to format the cause into a detail field, but I need to verify this doesn't violate the rule against copying raw wire payloads, credentials, or other sensitive data into those fields. Looking at the existing pattern in the file, this mirrors how appendProviderFailureActivity is already being used for session-stop-requested handling, so it's not introducing a new convention deviation—it's consistent with the established approach for provider failure activities in this reactor. Since this is activity payload detail meant for UI display rather than an error attribute, and it follows the pre-existing pattern, I'll move on without flagging it. The Cause.pretty(cause) pattern in detail for appendProviderFailureActivity is consistent with how it's used elsewhere in the file, including the new task-stop handler, so that's not a violation worth flagging. The only clear issue I've introduced is the missing cause parameter in WorkflowInspectionError. I've checked the other new modules—the atom factory and pure logic files follow conventions fine. Looking at whether the single WorkflowInspectionError class with a reason discriminator violates the convention: the reason field isn't driving control flow in the caller or selecting user-facing messages (those come from operation and detail), so it's diagnostic and acceptable. The real violation is the dropped cause, which assets.ts demonstrates correctly, so I'll report that and fail the check. I'm planning two focused inline comments: one on the error class definition suggesting an optional cause field, and another on the service wrap site showing where the cause gets discarded. Let me draft the suggestion for the error schema to include the cause parameter. For the GitHub review, I'll submit it with these inline comments targeting the specific lines in the workflow contracts and service files, keeping the body concise and noting that this pattern applies across all wrap sites.

1. modify_pr — One Effect service convention issue: the new WorkflowInspectionError drops the underlying failure instead of preserving it as cause. See inline comments.

💭 I'm preparing the final JSON output to report the convention violation as a failed check-run.


Agent Credits: 90 credits