Skip to content

refactor(server): separate compression platform wiring

MacroscopeApp / Macroscope - Effect Service Conventions failed Jul 28, 2026 in 8m 44s

Effect Service Conventions: 1 issue found

One convention violation found in the changed scope.

  • apps/server/src/http.ts (line 33): The new HttpResponseCompression service module is imported with a named import (import { HttpResponseCompression }), which erases the module namespace at a service boundary. The convention requires importing the local service module as a namespace (import * as HttpResponseCompression from ...) and consuming it via its public module shape (HttpResponseCompression.HttpResponseCompression). The rest of this PR — server.ts, server.test.ts, and http.test.ts — already imports the module as a namespace, so this line is inconsistent with both the codebase and the PR's own convention.

An inline review comment with the 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.

Reviewed the new service module apps/server/src/httpCompression/HttpResponseCompression.ts and its call sites.

Items checked and found compliant:

  • Effect library modules imported as namespaces from subpaths (Context, Effect, Layer, HttpServerResponse).
  • Service defined via Context.Service with an inline interface; no standalone FooShape type.
  • layerNode/layerBun are legitimate implementation-specific layer names for an abstract port with multiple platform implementations, so a generic make/layer is not required.
  • layerBun uses Layer.succeed appropriately: CompressionStream is a synchronous global Web API and the method body runs lazily on invocation, so no asynchronous dependency is hidden in the layer. layerNode correctly uses Layer.effect because it must dynamically import node:stream/node:zlib.
  • compressHttpResponse acquires the dependency from the environment via yield* HttpResponseCompression; no fake dependency injection, ManagedRuntime.make, or runPromise in service code.
  • No error/predicate conventions in scope (service defines no tagged errors).

Only the namespace-import convention at the http.ts service boundary was violated.


🔍 Agent activity — 1 tool call

💭 I'm examining this PR to see how it implements a new HttpResponseCompression service module and whether it follows Effect's service conventions. Looking at the imports and the beginning of the class definition, it's setting up a Context-based service that extends from the HTTP server response module. Defining the service implementation... er.succeedworks fine because it's using synchronous global Web APIs rather than async imports. The distinction is that the Node version needs async module imports, so it properly usesLayer.effect, while Bun's CompressionStreamis available globally without async dependencies—soLayer.succeedis appropriate here. I need to examine the http.ts file more closely to see if there are any convention violations in how the code is structured. I'm checking theHttpResponseCompression.tsservice definition against the project conventions. The module structure looks solid with proper namespace imports and a Context.Service with an inline interface, but I'm noticing there's nomakeexport. The convention typically requires exporting a realmakefunction when a module owns construction, though for abstract ports with multiple implementations like this one, implementation-specific names are allowed. Since the service construction is straightforward—just wrapping a function—I need to determine if the absence ofmakeviolates the convention or if it's acceptable given the module's abstract nature. Looking at thelayerBunimplementation, it usesLayer.succeedwith a method that callsnew CompressionStream("gzip"), which is a synchronous Web API available globally in Bun. The convention warns against Layer.succeedimplementations that hide async dependencies, but here the service method does its work lazily when called rather than during layer construction, so there's no hidden async service—this is a legitimate synchronous implementation. Now I'm noticing an inconsistency in how the service is imported:http.tsuses a named import{ HttpResponseCompression }while the test files andserver.tsuse a namespace importimport * as HttpResponseCompression. The convention specifies importing the local service module as a namespace to use its public module shape, so this named import in http.tscould be flagged as a violation. The convention explicitly states that namespace imports should be used at service boundaries, and this module is indeed a service being consumed for its service tag. The named import ofHttpResponseCompressionin http.ts was added in this PR, so it's a concrete violation introduced in the changed scope that should be flagged. The Bun layer correctly usesLayer.succeedsinceCompressionStreamis synchronous, while the Node version appropriately usesLayer.effectfor dynamic imports — that's consistent. Now I'm checking whether the named import violation in http.ts is actually worth flagging by looking at how other services are imported across the file to see if namespace imports are the established pattern. Looking at the imports in http.ts, I see everything else uses namespace imports likeimport * as ServerConfigandimport * as BrowserTraceCollector. The new HttpResponseCompressionnamed import breaks that convention, so this is a concrete inconsistency I should flag. The fix would be to switch to a namespace import and update the usage site accordingly at line 91. I need to verify this is a clear convention violation worth failing the check. The named import ofHttpResponseCompressionat the service boundary directly contradicts the requirement to use namespace imports, which is meant to preserve the module namespace. This is the exact anti-pattern the convention warns against, so I'll fail the review. Now I'll write the inline comment with a concrete diff suggestion. I'm seeing thatserver.tsuses a namespace import whilehttp.tsuses a named import, which breaks the established convention. Looking at theHttpResponseCompression` service module, it exposes multiple exports and sits at a service boundary, so it should follow the namespace import pattern. I'll add an inline comment flagging this inconsistency.

1. modify_pr — Effect Service Conventions — 1 finding. At a service boundary the local service module should be imported as a namespace (import * as HttpResponseCompression from ...) and consumed via its public module shape (HttpResponseCompression.HttpResponseCompression), matching how server.ts and the test files in this same PR already import it. See the inline comment.

💭 I'm generating the JSON output for the check run with a failure state since a finding was detected.


Agent Credits: 61 credits