Skip to content

feat(usage): redeem Codex reset credits from the Limits tab

MacroscopeApp / Macroscope - Effect Service Conventions failed Sep 4, 2026 in 11m 44s

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 while Crypto.Crypto is already a declared driver requirement; the idempotency key should come from the environment service (crypto.randomUUIDv4).
  • apps/server/src/ws.ts — the new provider.consumeResetCredit handler maps ProviderDriverError into ProviderSetupError carrying only detail, dropping the underlying failure; pass the wrapped error as cause.

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.
  • withCodexAppServerClient extraction in apps/server/src/provider/Layers/CodexProvider.ts: old inline probe bodies were removed rather than left as shims, and the shared helper stays scoped with ChildProcessSpawner in its requirements.
  • ProviderDriverError construction in the driver uses a static, bounded detail plus the real cause; no wire payloads, command output, or credentials in attributes.
  • New contract schemas (ServerProviderResetCredits, ProviderConsumeResetCredit*) and the pure codexResetCreditsToContract helper introduce no service-definition or runtime-boundary concerns; no ManagedRuntime/runPromise in 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 detail fields are static strings versus copying cause.message, and whether ws.ts's error-wrapping drops the original cause chain when it should be preserved for stack traces. I'm also flagging the imperative NodeCrypto.randomUUID() call as a potential hidden dependency issue. I'm also weighing whether process.cwd() usage and the closure-captured spawner service follow existing repo patterns, checking that Effect.scoped properly kills the child process after the request, and confirming that Ref.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 crypto acquisition 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's cause and detail. I need to check the exact line numbers around the 1749-1776 range in ws.ts to position the suggestion correctly, and also consider whether operation: "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 pure codexResetCreditsToContract function 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 the error.detail field 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 passing cause: error explicitly. 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.