Repository navigation
Effect Service Conventions: 1 issue found
apps/server/src/usage/usageLimits.ts: the newUsageLimitsStoremodule exports its construction effect asmakeStoreinstead of the canonicalmakeused by every other service module in the repo (SessionStore.ts,CheckpointStore.ts,UsageService.ts, ...). Implementation-specificmake*names are reserved for abstract-port modules with multiple implementations.
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 reviewed (in-scope changed TypeScript): apps/server/src/usage/usageLimits.ts, apps/server/src/usage/usageLimits.test.ts, apps/server/src/usage/UsageService.ts, apps/server/src/usage/UsageService.test.ts, apps/server/src/server.ts, apps/server/src/provider/Layers/CodexProvider.ts, packages/contracts/src/usage.ts, packages/shared/src/usageFormat.ts, packages/shared/src/usageMerge.ts, apps/web/src/components/usage/UsagePage.tsx, apps/mobile/src/features/usage/UsageRouteScreen.tsx.
Checked and found compliant:
- Effect library modules imported as subpath namespaces (
effect/Effect,effect/Layer,effect/Schema,effect/unstable/process/ChildProcessSpawner); no consolidatedfrom "effect"imports. - Service interface declared inline in the
Context.Servicetag; methods typed viaUsageLimitsStore["Service"]["..."]; no standaloneFooShape. - Single canonical module holds schemas, tag, construction,
layer, andlayerTest; no compatibility shims or splitServices//Layers/files introduced. - Dependencies (
FileSystem,Path,ServerConfig,ServerSettingsService,ChildProcessSpawner,ProviderService) are acquired from the environment; noFoo["Service"]parameters, noManagedRuntime.make, norunPromise/runPromiseExit, andLayer.succeedis used only for the inert test layer. Layer.effectwithforkParkedis consistent with the repo (Effect 4 layer build has scope;Layer.scopedis unused repo-wide).Effect.catchCauseswallowing,process.env/process.cwd()usage, and theas unknown as Schema.Codec<...>cast forSchema.fromJsonStringall match established patterns inUsageService.tsandModelManifest.ts, so they were not flagged.- The only new static-analysis suppression (
@effect-diagnostics nodeBuiltinImport:offinusageLimits.test.ts) carries an adjacent explanation. - New behavior (parsers, merge/persistence, disabled-provider refresh) is covered by focused tests rather than mocks of core logic.
🔍 Agent activity — 14 tool calls
💭 I'm reviewing the new usageLimits.ts file against the codebase's conventions, checking whether the ServerConfig import follows the expected pattern of importing local service modules as namespaces rather than named tags. I'm also comparing the ordering and naming in the file against conventions—noting that
makeStoredeviates from the expectedmakenaming, and that the tag declaration appears after several parsing functions rather than following the standard imports-schemas-tag-make-layer sequence. I want to check if similar patterns exist elsewhere in the repo before flagging this. There's also a minor ordering issue — schema declarations andlayerTestare placed between the tag andmakerather than up near the other schema/error declarations at the top, which deviates from the usual import/errors/tag/make/layer order. On the dependency side,makeStorepullsChildProcessSpawnerfrom the environment and then re-provides it viaEffect.provideServiceso the refresh effect can have a dependency-free type — that's a reasonable closure pattern, not a real issue. Looking further, theEffect.catchCausethat swallows all failures intoEffect.succeed(null)isn't a documented violation either — it's a deliberate fallback design, distinct from the stricter rule about not bypassing typed failures with an imperative runtime. Now I'm considering whether the use ofprocess.envandprocess.cwd()inside the refresh logic counts as an impure dependency that should be injected instead. That double cast withas unknown asfor the codec schema is a type escape hatch without an explanation comment, though it's borderline since it's not a formal suppression directive like ts-expect-error — I'll flag it cautiously rather than fail on it. Now I should check the import ordering convention for local service modules against the repo's established pattern. I should also check theProviderServiceimport pattern to see if it matches repo conventions, and note whether Services/Layers files should be hoisted, though refactoring existing ones isn't required. I want to grep the repo for similar patterns and verify how contracts/src/usage.ts handles its schema defaults and namespace imports.
1. git_tools — from "../config.ts"
2. git_tools — ProviderService } from
💭 I'm noting that both import styles exist across the repo, but since the newer convention explicitly takes priority over older code, I should follow the guidance to flag namespace-erasing aliases and prefer namespace imports at service boundaries for this new file, without demanding a broader repo-wide cleanup. Turning to bigger candidates now: I want to check whether
makeStoreshould instead follow themake/layernaming convention used elsewhere, and I'm also looking at whether the import ordering in usageLimits.ts is correct relative to the provider imports. I also want to verify the file's overall structural order — schemas, tag, make, layer — since usageLimits.ts seems to place the LimitsFile schema after the tag, which is a mild deviation. It seems worth double-checking against the actual file contents before flagging anything else, like catch-clause usage.
3. browse_code — apps/server/src/usage/usageLimits.ts
4. git_tools — export const makeStore|export const make[A-Z]
💭 I'm checking naming conventions here—since this module owns a single service and is named after it, the convention suggests exporting a plain
makerather thanmakeStore, so this looks like a real deviation worth flagging. Looking further, I'm scanning the layer wiring in server.ts to confirm the UsageLimits dependency ordering is correct, then checking usage.ts imports and confirming UsageService.ts imports the store's tag directly by name rather than as a namespace, which violates the service-boundary convention that says to import local service modules as namespaces. Now I want to check whether theas unknown as Schema.Codec<...>cast is actually suspicious by comparing against how other files in the repo useSchema.fromJsonString, so I'm searching for similar usages to see if the cast is standard practice or a red flag.
5. git_tools — fromJsonString
6. git_tools — as unknown as Schema.Codec
💭 This casting pattern already exists elsewhere in the repo, so it's not a real finding. I'm checking whether the service construction convention applies here, but it doesn't seem to match this case, and the catchTags/catchCause distinction isn't covered by the listed rules either. I'm now weighing whether
Effect.catchCausehere could unintentionally swallow interruption signals along with actual failures, since catching the whole cause suppresses interrupts too. The conventions do call out preserving interruption during startup reconciliation specifically, so I want to check if this refresh path falls under similar concerns and whether the repo has an established pattern for using catchCause elsewhere, like in usageLimits.ts. I'm also considering whether pullingprocess.envandprocess.cwd()directly insiderefreshviolates the convention against hiding dependencies in closures rather than acquiring them through the Effect environment. I want to check whether other services in the repo do the same thing before deciding if this is a genuine violation worth flagging, so I'll search for otherprocess.envusages across the server source.
7. git_tools — process.env|process.cwd()
8. git_tools — Effect.catchCause
💭 These patterns match existing code, so catchCause and process.env are fine given UsageService.ts uses the same style. That leaves weaker remaining candidates: makeStore versus make, the ordering of layerTest and LimitsFile schema placement, and the mix of named imports versus namespace imports which is already inconsistent across the repo. I'm now weighing whether the review should actually flag anything at all. There's a tension between the check instructions saying to output exactly "All clear" when there are no findings, and the schema requiring valid JSON output — I need to reconcile these by treating "All clear" as the content of the summary/title fields within a properly structured JSON response rather than literal freeform text. Looking closer at the naming convention,
usageLimits.tsis a single canonical implementation module rather than an abstract port with multiple implementations, so its construction export should really just bemake, not something more implementation-specific likemakeStore. That's a concrete, fixable naming violation worth flagging. Since the fix would require renaming across bothusageLimits.tsand its test file, I can't offer an inline diff—it's cross-file. I want to double check this isn't just a nitpick, so I'm looking at precedent in sibling store modules like SessionStore.ts and PairingGrantStore.ts to see what naming pattern they actually use for their construction and layer exports.
9. git_tools — ^export const (make|layer)
10. git_tools — ^export const make =
💭 I notice usageLimits.ts uses
makeStoreinstead of the standardmakenaming convention, which deviates from the repo pattern of exporting plainmakeandlayer. I'm also checking whetherlayerTestappearing beforemakeis a genuine ordering violation by comparing against other modules like UsageService.ts, which follows that same order. I'm now tracing through the layering setup in server.ts, confirming thatUsageLayerLivecorrectly provides its dependencies throughRuntimeCoreDependenciesLive, and checking whether theServerSettingslayer might end up being instantiated more than once. SinceServerSettingsLayerLiveis a shared constant reference, Effect's memoization ensures it's only built once even though it's provided to bothUsageService.layerandUsageLimits.layerwithin the same composition tree, so there's no duplication concern there. Now I'm turning to whetherforkParkedinside aLayer.effectcall needs aScopeto manage the forked fiber's lifetime properly, and whetherLayer.effectimplicitly supplies that scope.
11. git_tools — export const forkParked
💭 I'm noticing forkParked needs a Scope, and usageLimits.ts uses it inside Layer.effect rather than Layer.scoped—I should check whether Layer.effect actually provides a Scope in Effect 4, and compare how forkParked is used elsewhere in the repo with these two layer constructors.
12. git_tools — forkParked
💭 I'm checking whether Layer.effect can require a Scope in this Effect version, so I'm searching the codebase for other layers that use forkParked or Layer.scoped to see the established pattern.
13. git_tools — Layer.scoped
💭 The main finding is that
makeStoreshould just be renamed tomake, and since there's no othermakein the file, the rename is trivial along with updating the test import. Looking at the CodexProvider.ts change, it introduces a new interface and connection function that both look fine with no errors. I'm also noticing a mixed import convention in usageLimits.ts — it uses destructured imports for ServerConfig and ProviderService alongside a namespace import for ServerSettings, which is inconsistent with the service-boundary namespace convention, though this isn't quite the "aliasing" violation the instructions call out explicitly. I'll keep the review focused rather than flagging this as a major issue. OnmakeStore, I'm weighing whether that single naming deviation is enough to fail the check given the repo-wide precedent ofmake/layerexports, and leaning toward flagging it as one inline comment while treating the overall check as a failure since it's a clear, non-stylistic convention violation rather than an optional preference. Checking the mobile/web files briefly - the usageFormat helpers are pure and untouched by Effect, so no violation there. Since the fix also requires updating the test file's import, this can't be a self-contained inline diff suggestion; I'll just flag the call sites in my comment instead, targeting the new usageLimits.ts line directly.
14. modify_pr — One convention finding, inline. Everything else in the new Effect service (subpath namespace imports, inline Context.Service interface, Foo["Service"] method typings, environment-acquired dependencies, layer/layerTest exports) matches the repository conventions.
Agent Credits: 180 credits
Token usage: 20 uncached input · 948,844 cache-read input · 148,011 cache-write input · 12,474 output
Agent Credits may also include non-token charges from external tools such as web research.