Skip to content

docs(server): clarify that update-check opt-out gates fetches, not ca…

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 25, 2026 in 3m 18s

Effect Service Conventions: 1 issue found

1 finding

  • apps/server/src/provider/ModelManifest.test.ts (lines 8-9, 114-118): the new test reaches ServerConfig and ServerSettingsService through their deprecated Context.Service static layerTest shims instead of importing the service modules as namespaces and using their module-level layerTest. Both statics are explicitly annotated @deprecated Import and use "layerTest" from this module.

Everything else in the changed scope matches the conventions: ModelManifest.ts follows the canonical single-file order, defines its interface inline in Context.Service, exports a real make that acquires FileSystem, Path, ServerConfig, ServerSettingsService, and HttpClient from the environment, and exports layer/layerTest (Layer.succeed over a pure constant service is a legitimate test seam). No ManagedRuntime.make, runPromise, or service-instance parameters were introduced, driver dependencies are surfaced in ClaudeDriverEnv/CodexDriverEnv, and server.ts provides the layer once at the application boundary.

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.

Files examined: apps/server/src/provider/ModelManifest.ts, apps/server/src/provider/ModelManifest.test.ts, apps/server/src/provider/Drivers/ClaudeDriver.ts, apps/server/src/provider/Drivers/CodexDriver.ts, apps/server/src/provider/Layers/{ClaudeProvider,CodexProvider}.ts and their tests, apps/server/src/provider/Layers/{ProviderRegistry,ProviderInstanceRegistryLive}.test.ts, apps/server/src/server.ts.

Checks performed and cleared:

  • Import style: Effect modules use subpath namespace imports; HttpClient/HttpClientResponse named imports from effect/unstable/http match repo-wide usage; ServerSettings is imported as a namespace in the service module.
  • Service definition: schemas, tag, make, layer live in one canonical module; interface is inline; ModelManifest["Service"] is used for the constant implementation.
  • Runtime boundaries: no ManagedRuntime.make, runPromise, or runPromiseExit; the single Layer.succeed is a pure bundled-data test layer; the closure state is per-instance and guarded by a semaphore rather than a module global.
  • Errors: the service is failure-free by design (Effect.catchCause fallbacks match the existing UsageService/providerMaintenance idiom), so no new error classes were required.
  • Behavior change is covered by focused tests (fetch preference, malformed payload, opt-out), and removed isLegacy* helper tests were migrated rather than deleted.

Non-blocking observation (outside this check's convention scope, not posted to the PR): current and refreshed share one semaphore permit, so a pending snapshot's current read can block behind an in-flight refresh fetch (up to FETCH_TIMEOUT_MS), which is in tension with the documented "never fetches / publishes instantly" intent for current.


🔍 Agent activity — 13 tool calls

💭 I'm reviewing the new ModelManifest.ts file against the codebase conventions—checking whether the named imports from the effect/unstable/http subpath violate the namespace-import pattern, and looking at whether the service's use of mutable module-level closure state for manifest caching fits the established style. The layerTest export using Layer.succeed with a pure constant looks like a legitimate test seam, and the catchCause error swallowing doesn't clearly violate the catch-appropriateness guideline since it handles the full error channel intentionally. The file's overall structure—imports, schemas, helper functions, Context.Service tag, then constructors and layers—roughly follows the canonical layout order I'd expect. Now I want to verify import conventions against the rest of the repo: how HttpClient gets imported elsewhere, whether ServerConfig should be imported as a namespace since it's a service module rather than a named import, and whether the suspicious Schema.Codec cast in the manifest cache file has precedent elsewhere. I should look at these patterns across the codebase before flagging anything.

1. git_tools — from "effect/unstable/http"

2. git_tools — import .*ServerConfig.*from "../config.ts"

💭 The mixed import style isn't worth flagging since it's only used for a config value. Now I'm turning to ModelManifest.ts, checking the test-only layer export first, then looking at how make manages mutable state through a semaphore and pulls its dependencies from the environment. I notice several places where catchCause swallows errors and returns null, which handles the whole error channel but also masks defects — borderline flaggable since the conventions suggest catch is meant for intentional full-channel handling, not defect suppression. I also check that the timeout wraps the full decode pipeline correctly, confirm there's no need for a dedicated error type since the service never fails, and start reviewing whether the file's overall structure follows the canonical ordering of schemas, helpers, service tag, and implementation. Now I'm looking at whether the drivers correctly consume the ModelManifest service — they use named imports instead of namespace imports at what looks like a service boundary, which conflicts with the convention of importing local service modules as namespaces and referencing their public shape. I'm noting that server.ts and the tests follow the namespace pattern correctly, but the drivers don't, so I'm weighing whether this inconsistency is worth flagging.

3. browse_code — apps/server/src/provider/Drivers/ClaudeDriver.ts

4. browse_code — apps/server/src/provider/ModelManifest.ts

💭 Checking convention violations now—the ClaudeDriver/CodexDriver import from ModelManifest should use namespace-style import instead of named imports, matching the pattern already used elsewhere in server.ts and the tests. This looks like a legitimate finding against the stated service boundary rules. But I notice the same file already imports other services like ProviderEventLoggers and ServerSettingsService using named imports, so flagging only ModelManifest for this seems inconsistent with the existing local pattern. Given that nuance, I'm inclined to hold off on flagging this one since it matches the file's established style even if it diverges from the newer convention. Now checking other findings — the test file's import looks fine, and using Layer.effect(ModelManifest, make) is standard. The ordering of layerTest relative to make isn't specified in conventions, so I'll skip that. There's no explicit error handling issue since the service swallows failures via catchCause, which doesn't cleanly map to the "keep failure typed" convention. But I'm noticing a more substantive concern: the semaphore is shared between current and refreshed, meaning a slow refresh fetch could hold the permit and block urgent snapshot reads that need to publish instantly — that's worth flagging as a real correctness issue. Since the review scope is about Effect service conventions rather than general correctness, I'm weighing whether to raise this as an inline comment despite it not mapping directly to a listed convention violation, since it contradicts documented behavior expectations. I'll also check the test file's it.live tests to make sure they're not just testing trivial mechanics. Checking a few more consistency points: make usage in tests is fine since it's provided through layers, the HttpClient named import matches allowed patterns for service modules, and the manifest/layer test imports look consistent with conventions. I'm also confirming that applyModelManifest only needs to apply to Codex and Claude drivers, and now checking whether the driver env types properly include the ModelManifest dependency. Since ClaudeDriverEnv and CodexDriverEnv both include ModelManifest, that should propagate through BuiltInDriversEnv correctly, and any missing layer elsewhere would surface as a compile error anyway, so I'm not too worried there. I'm now scanning for other entry points beyond server.ts that construct drivers to make sure the manifest layer is always provided, and glancing at how ServerSettings swallows errors via catchCause, which seems acceptable. Now I'm checking the convention about not hiding dependencies in closures or singleton-style Layer.succeed implementations. The BundledOnlyModelManifest built with Layer.succeed is just a pure constant so that's fine, but the catchCause swallowing everything under the fetch/timeout logic concerns me more, since catching all causes could also absorb interruption or genuine defects rather than just the expected tagged failures the conventions call out. If a fiber gets interrupted mid-fetch, catchCause would turn that into a plain null result instead of respecting the interrupt — I want to check how the rest of the repo uses catchCause to see if this is an established idiom before flagging it.

5. git_tools — Effect.catchCause(() =>

6. git_tools — Semaphore.make|withPermits

💭 The error-handling idiom matches existing UsageService patterns, so that's not worth flagging. I'm checking the layerTest and BundledOnlyModelManifest naming against repo conventions—layerTest matches ServerSettingsService and ServerConfig, so that's fine too. Now I'm looking at whether the ModelManifest.ts module naming aligns with the class it exports. More concerning is the named import of ModelManifest (the tag itself, not just types) in ClaudeDriver/CodexDriver, since the tag is actually used rather than just being a pure helper import—this looks like a genuine violation of the namespace-import convention at service boundaries. But I want to check whether the test file's imports of ServerConfig and ServerSettingsService for layerTest follow a similar pattern, since the repo seems to tolerate both styles in tests.

7. git_tools — layerTest

8. git_tools — layerTest|class ServerSettingsService|export const make

💭 I notice both layerTest static methods on ServerConfig and ServerSettingsService are marked deprecated in favor of importing layerTest directly from the module, yet the new ModelManifest.test.ts file still uses these deprecated static forms to build its test layers. The convention makes clear this should instead follow the module-namespace pattern like WorkspacePaths.layer, so I'm treating this as a solid first finding backed by the JSDoc deprecation itself. For a second finding, I'm considering whether the drivers' named import of the ModelManifest service tag is worth flagging separately — the guidance specifically calls out aliased imports like layer as workspacePathsLayer that hide the module namespace, so I want to check if the driver imports fall into that same pattern before adding comments on those specific lines.

9. git_tools — namespace import

💭 There's no service-namespace lint rule, so I'll skip that nit. Checking other convention issues: the make-order placement isn't strictly specified, so that's fine too. The shared semaphore between current and refreshed is a real behavioral concern worth flagging—it could mean current blocks behind a 10s fetch, contradicting the documented instant-publish invariant—but I'm weighing whether that's actually in scope for "Effect service conventions" versus a correctness comment. Thinking it through more: with multiple provider instances, one instance's refresh could delay another's pending snapshot by up to 10s, which is a genuine regression against instant publish. It's tempting to flag it since it falls within the changed scope, but the check's stated purpose is conventions, not general correctness bugs, so raising it risks going off-spec. I'll consider surfacing it only as a non-blocking note rather than a violation. Weighing this against the deprecated static method finding — I want to confirm layerTest on ServerConfig is indeed the deprecated method being invoked in ModelManifest.test.ts, since that's a cleaner convention violation to report on its own. I should check whether any production files besides ModelManifest.ts use layerTest or BundledOnlyModelManifest, so let me grep for those usages outside test files.

10. git_tools — ModelManifest

💭 Other tests constructing drivers aren't my responsibility if they fail typecheck from missing the ModelManifest layer. I'm also checking that production services correctly acquire dependencies via yield* from the environment, which ModelManifest follows, though I should double-check BundledOnlyModelManifest against this convention too. I'm confirming the deprecated statics finding holds by checking repo-wide precedent — many tests use module-level layerTest calls, and the JSDoc explicitly deprecates the static approach, so this finding is solid. Now I want to verify the exact import structure and line numbers in ModelManifest.test.ts to accurately place my comment, so I'll look at the actual file for serviceLayers.

11. browse_code — apps/server/src/provider/ModelManifest.test.ts

12. browse_code — apps/server/src/provider/ModelManifest.test.ts

💭 I'm deciding how best to comment on this—since the fix spans multiple hunks (the import lines and the deprecated static call sites at 114, 116, 118), a single inline suggestion won't work cleanly. I'll provide a small unified diff for the imports and separately flag the call sites that need to reference the module-level layerTest. Finishing the import diff... Now I'm weighing whether this deprecated-API/namespace-shape issue is significant enough to fail the check. It's a minor nitpick confined to a new test file, but since the check defaults to failure whenever there's a finding and guidance exists here, I'm leaning toward marking it as a failure rather than treating it as neutral — though I want to double check this really counts as a genuine convention violation before committing to that verdict. The listed convention requires importing the service as a namespace and using its public shape rather than deprecated statics, and this test violates that explicitly, so it's a concrete, in-scope finding. I'm deciding not to flag the driver's named tag import though, since using a tag for yield* is normal repo-wide practice — my finding is specifically about deprecated statics and module shape, not tag imports in general, so I can draw that distinction cleanly. I also want to check whether the ModelManifest.ts import of ServerConfig needs flagging. I'll post one inline comment for the main issue, then decide on the final check status. I'm also weighing whether to note the semaphore/blocking observation somewhere — the conventions don't explicitly cover it, so rather than posting it on the PR, I'll consider adding a brief non-blocking line in the check details only, keeping it short and clearly labeled so it doesn't read as scope creep.

13. modify_pr — Reviewed the new ModelManifest service, its drivers wiring, and the touched tests against the Effect service conventions. One finding: the new test file reaches services through the deprecated Context.Service static shims instead of the modules' public shape.


Agent Credits: 102 credits