Repository navigation
Effect Service Conventions: 2 issues found
Two convention violations were posted as inline comments:
apps/server/src/provider/Drivers/CodexDriver.ts—NodeCrypto.randomUUID()is called inside an Effect whileCrypto.Cryptois already a declared driver requirement; the idempotency key should come from the environment service (crypto.randomUUIDv4).apps/server/src/ws.ts— the newprovider.consumeResetCredithandler mapsProviderDriverErrorintoProviderSetupErrorcarrying onlydetail, dropping the underlying failure; pass the wrapped error ascause.
Additionally noted in the review body: the new backend redemption path (single-flight, idempotency-key reuse, snapshot refresh) has no focused test; only the pure summary mapping is covered.
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: changed .ts files under apps/**, packages/**, infra/**, excluding *.test.ts (so apps/web/src/components/usage/UsageLimits.tsx and codexUsageLimits.test.ts were used as context only).
Checked and found compliant:
effect/*subpath namespace imports (Ref,Semaphore) and named imports from@t3tools/contracts/ local pure-helper and schema modules.withCodexAppServerClientextraction inapps/server/src/provider/Layers/CodexProvider.ts: old inline probe bodies were removed rather than left as shims, and the shared helper stays scoped withChildProcessSpawnerin its requirements.ProviderDriverErrorconstruction in the driver uses a static, boundeddetailplus the realcause; no wire payloads, command output, or credentials in attributes.- New contract schemas (
ServerProviderResetCredits,ProviderConsumeResetCredit*) and the purecodexResetCreditsToContracthelper introduce no service-definition or runtime-boundary concerns; noManagedRuntime/runPromisein domain code, and no new lint/type-checker suppression directives.
🔍 Agent activity — 8 tool calls
💭 I'm checking CodexDriver.ts's use of Effect's Semaphore module to see if that import path is even valid in this version of the library. Now I'm scrutinizing the error handling: whether
detailfields are static strings versus copyingcause.message, and whether ws.ts's error-wrapping drops the originalcausechain when it should be preserved for stack traces. I'm also flagging the imperativeNodeCrypto.randomUUID()call as a potential hidden dependency issue. I'm also weighing whetherprocess.cwd()usage and the closure-captured spawner service follow existing repo patterns, checking thatEffect.scopedproperly kills the child process after the request, and confirming thatRef.set(pendingResetKey, null)intentionally only fires on success per the accompanying comment.
1. browse_code — apps/server/src/provider/Drivers/CodexDriver.ts
2. browse_code — apps/server/src/provider/ProviderDriver.ts
💭 I notice CodexDriver already declares Crypto as an Effect service dependency, yet the new code calls node:crypto's randomUUID directly instead — that's exactly the kind of imperative API usage the convention warns against when a proper Effect service is already available. Let me search the file and repo for how Crypto is actually used elsewhere to confirm this pattern.
3. browse_code — How is Crypto from "effect/Crypto" used in apps/server (e.g. randomUUID)? Show examples where the Crypto service is yielded and used to generate UUIDs, and whether node:crypto randomUUID is used anywhere in apps/server or packages.
4. browse_code — Show the definition of ProviderSetupError and ProviderDriverError in apps/server/src/provider/Errors.ts, including all fields (does it have a cause field?), and show 2-3 examples in apps/server/src/ws.ts where a driver error is mapped into ProviderSetupError (do they pass cause?).
💭 I'm noticing CodexDriver uses NodeCrypto.randomUUID() even though Crypto.Crypto is already available in its environment, and it's missing the nodeBuiltinImport suppression comment that other files like attachmentStore.ts have—yet CI still passed, so maybe that diagnostic rule only applies to certain files or globs. I'm also thinking about the convention that production services should acquire dependencies via yield* from the environment rather than hiding them in closures or singleton Layer.succeed implementations, which seems relevant to how Crypto is being handled here. Calling the imperative randomUUID function directly is a real violation since Crypto is already declared in the driver's environment with a proper randomUUIDv4 method available — I'll flag that finding. I'm noting process.cwd() usage too but that's likely idiomatic elsewhere in the repo, so I'll skip it. Looking at ws.ts, I see mapError dropping the cause when wrapping a failure, which conflicts with the convention of preserving the underlying error as cause — though similar existing code at line 1713 does the same thing, so it's a pre-existing pattern rather than a new violation. I'm also checking whether the detail field on ProviderDriverError is copying from cause.message, which the conventions warn against, but here it looks like a static domain-specific string rather than a copied message. Even though the pattern mimics existing code, since these are new lines they still count as a legitimate finding, so I'll suggest attaching the original error as cause. Since ProviderDriverError isn't part of the target error channel here, wrapping it into ProviderSetupError is correct, but the cause should still be preserved. I'm now checking whether Semaphore.make exists in this effect-smol version being used. Moving on, I'm scanning CodexDriver's error handling, the optional homePath parameter change, and the pure helper functions in codexUsageLimits.ts — these all look fine and consistent with conventions. I'm also considering whether tapping snapshot.refresh after mapError could widen the error channel beyond ProviderDriverError, though this seems to typecheck fine given the interface constraints, so it's not a convention violation. Now I'm looking at how the idempotency key Ref is being used. createEnvironmentRpc command looks fine. Now I'm checking whether nodeBuiltinImport suppression is needed for the crypto import — since CI passed without it, either the rule isn't enforced globally or there's suppression elsewhere, so I want to check the diagnostics config and confirm whether Crypto.Crypto is actually used downstream in the environment union rather than just declared.
5. browse_code — Is there an @effect/language-service / effect diagnostics configuration (tsconfig "plugins" with effect diagnostics severity for nodeBuiltinImport)? Show the config and whether nodeBuiltinImport is set to error/warning repo-wide. Also list files containing @effect-diagnostics nodeBuiltinImport:off in apps/server.
💭 I'm checking whether the repo-wide cryptoRandomUUID lint rules actually catch calls made through the node:crypto namespace, since attachmentStore.ts uses NodeCrypto.randomUUID() without triggering a flag — suggesting the rule may only target the global crypto object. Given the repo's convention of using the Crypto service in Effect contexts, the fix would be to yield the Crypto.Crypto dependency and use crypto.randomUUIDv4 instead of NodeCrypto.randomUUID(), though that introduces a PlatformError that needs handling and complicates the existing Ref.modify pattern. Since this touches multiple parts of the code (imports, dependency injection, and the modify logic), I'm leaning toward describing the fix conceptually rather than providing a clean single-hunk diff. Since this requires two separate hunks that don't fit a clean unified diff, I'll just describe the fix in prose with a guiding code snippet rather than proposing a formal diff — noting the extra
cryptoacquisition needed alongside the Ref.modify change. For the second finding, I'm looking at ws.ts where the cause is dropped from the error construction, and I want to propose an inline fix preserving the error'scauseanddetail. I need to check the exact line numbers around the 1749-1776 range in ws.ts to position the suggestion correctly, and also consider whetheroperation: "consume-reset-credit"might be redundant with the error tag per the codebase's conventions. I'm also weighing whether the driver's new consumeResetCredit and ws handler logic count as backend behavior changes requiring focused tests, since only the purecodexResetCreditsToContractfunction currently has test coverage.
6. browse_code — apps/server/src/ws.ts
7. browse_code — apps/server/src/provider/**/*.test.ts
💭 I see other drivers have test coverage through test spawner layers, but the new backend behavior—single-flight redemption, idempotency key reuse, snapshot refresh—lacks tests entirely. Given the convention requiring focused tests for backend behavior changes, this seems worth flagging, though I'll note it as a lower-priority inline comment rather than a blocking issue. Since test coverage spans both CodexDriver.ts and ws.ts, I think it makes more sense to raise it in the review body as a cross-cutting concern rather than pin it to one line. I'll keep two precise inline comments—one for the crypto issue, one for the ws.ts root cause—and address the missing tests separately in the body, judging its severity against the stated conventions around dependency boundaries and avoiding hidden runtime-backed dependencies. Confirming the exact diff line numbers for each inline comment: line 247 for the
NodeCrypto.randomUUID()call in CodexDriver.ts, and line 1769 for theerror.detailfield in ws.ts, both within the added hunks. I'm drafting a suggestion block for the ws.ts line to show the corrected field. Writing the fix... For the second comment, I'm noting that wrapping the error drops the underlying ProviderDriverError's cause/stack chain, so I should suggest passingcause: errorexplicitly. I'm also weighing whether to flag missing focused tests for the new backend path, since the behavior change adds a new RPC method and driver operation but tests only cover part of it. I'm now debating severity: is the node:crypto usage a clear enough violation to fail the check, and whether missing cause chaining rises to the same level, or if these are more like notable findings than blocking issues.
8. modify_pr — Backend behavior added here (driver-level reset-credit redemption plus the new provider.consumeResetCredit RPC) is currently covered only by the pure codexResetCreditsToContract unit test. Consider a focused test for the redemption path — single-flight under the semaphore, idempotency-key reuse across a failed attempt, and the follow-up snapshot.refresh — using the existing child-process test layers (see apps/server/src/provider/Layers/CodexProvider.test.ts / Drivers/AntigravityDriver.test.ts), so the external app-server is the only thing stubbed.
Agent Credits: 465 credits
Token usage: 80 uncached input · 1,822,440 cache-read input · 371,385 cache-write input · 47,782 output
Agent Credits may also include non-token charges from external tools such as web research.