feat(usage): show subscription limits - #8327
mackinleysmith wants to merge 20 commits into
Effect Service Conventions: Complete
All clear
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.
🔍 Agent activity — 6 tool calls
💭 I'm checking whether the previous process.env issue was fixed, and now reviewing the diff for Effect convention violations—looking at the usage contracts and schema defaults, then moving to check the UsageService imports. I notice the ClaudeProvider function properly exposes FileSystem and Path as requirements rather than hardcoding them, which is good practice. But then I'm scrutinizing how UsageService manually re-provides FileSystem, Path, and ChildProcessSpawner services when forking within a scope—questioning whether this manual re-provisioning is actually necessary or a deviation from idiomatic Effect patterns, since the effect should already carry these requirements in its environment. I'm concluding that re-providing services already present in the environment is redundant but not a real convention violation, since it preserves type-level requirements. I'm also checking error handling patterns like swallowing failures with
catchCausefor optional subscription meters and returningundefinedon failure in the codex rate limits probe—neither seems to clearly break stated conventions. I'm now scanningusageTranscriptReader.ts, which uses raw Node fs promises instead of Effect, but this matches the file's existing established style rather than being a service that needs Effect patterns. I'm also verifying the timeout usage and checking whetherprobeCodexRateLimitsrelies on any default environment values. Looking more closely, the function has default parameters that fall back toprocess.envandprocess.cwd()— since these are module globals, I want to check if callers actually pass explicit values or rely on these defaults, and whether similar functions likeprobeCodexAppServerProviderhandle this the same way. I should check the actual repository files to confirm this pattern.
1. git_tools — b430e27..c902fe1
2. browse_code — apps/server/src/usage/UsageService.ts
💭 With those findings resolved, I'm now checking probeCodexRateLimits's use of process.env and process.cwd() as fallback defaults, and whether that counts as hiding dependencies in module globals given it has explicit signature defaults and callers pass hostEnvironment. I want to compare how other probes in CodexProvider structure their signatures for consistency.
3. git_tools — process.(env|cwd)
4. browse_code — apps/server/src/provider/Layers/CodexProvider.ts
💭 That env default matches existing patterns elsewhere in the file, so it's not a new issue worth flagging. The usageSubscriptionLimits module looks clean too, no tagged errors and the helper functions check out fine. I'm now looking at how contracts/usage.ts imports Effect for its decoding default. Checking probeClaudeUsage, the tryPromise call and the subsequent timeout/result handling correctly collapse the error channel to never, so that's fine. There's also a raw promise for waitForAbortSignal that isn't a convention concern, and UsageService's use of NodeOS.hostname is a pre-existing pattern too. Now I want to verify the Scope usage — if make() calls Scope.make and addFinalizer, the layer needs to be Layer.scoped rather than Layer.effect for UsageService, so I'm checking how that layer is actually constructed at the bottom of the file.
5. git_tools — export const layer
6. browse_code — apps/server/src/usage/UsageService.ts
💭 I notice the grep results show a different line number than the actual file view, suggesting the grep may be running against a different revision. Looking at head, the layer definition uses
Layer.effect(UsageService, make), andmakecallsEffect.addFinalizer, which needs a Scope—so I'm checking whetherLayer.effectactually provides that Scope in this version of Effect. Given signs likeeffect/unstable/http,Context.Service, andEffect.result, this looks like Effect v4, where I believeLayer.effectmay allow the underlying effect to require Scope, unlike v3 where you'd needLayer.scopedinstead. Since the PR presumably compiles, this probably isn't a real issue, so I'm moving on to check for actual convention violations, like how FileSystem and Path services are being provided in UsageService. Looking closer, that provideService pattern is deliberate — the code comment explains readSummary needs to stay context-free, so providing already-acquired services satisfies resolvers without adding requirements. That's consistent with the file's existing approach, not a violation. Checking usage.ts's import ordering and the subscription limits file for other issues — Effect.fn usage looks fine, no stray ManagedRuntime or runPromise calls added, and the raw async Node call wrapped in Effect.promise matches an existing pattern already used elsewhere in the file for listing transcript files. No new error classes are introduced, and UsageReadError's reason/detail fields were already there before this change. I'm now looking at ClaudeProvider's probeClaudeUsage, checking whether Effect.tryPromise without an error mapper is acceptable in this version of Effect, and confirming Effect.result only catches failures rather than defects, which seems correct here. I also want to verify whether the contracts package pulling in Effect at runtime creates any issue. I notice UsagePage.tsx and UsageRouteScreen.tsx both duplicate a usageLimitWindowLabel helper, but that's a code duplication concern rather than an Effect service convention issue, so it's out of scope. I want to confirm the earlier review comments were actually addressed by checking that hostEnvironment is referenced at the right lines, and I should double check whether HostProcessEnvironment's typing actually includes the T3CODE_DEV_USAGE_LIMITS_FIXTURE field to avoid a type error. I'm confirming HostProcessEnvironment is accessed as an existing service via yield*, and this code predates the diff rather than being newly introduced. Scanning the rest of the diff, I don't see any new Layer.succeed definitions or service registrations beyond the pre-existing test layer gaining one extra field, and the new usageSubscriptionLimits.ts module holding pure helpers looks fine. With no actual findings, I need to decide how to format the final response—the schema calls for structured JSON output with a title and summary, so despite instincts to just say "All clear" plainly, I'll express that conclusion within the JSON structure, marking it as success since there are no issues to report.
Agent Credits: 81 credits