Repository navigation
Effect Service Conventions: 2 issues found
Two findings, both in apps/server/src/provider/Layers/OpenCodeAdapter.ts:
- Dead helper (lines 588-593):
tryExtractOpenCodeTokensFromRecordis introduced but never called; all call sites usereadOpenCodeTokensdirectly. Suggested removal so the new token-extraction path has one entry point. - New backend behavior without focused tests (line 750 onward): per-turn
thread.token-usage.updatedemission, the deliberate skip of cumulativesession.updatedtotals, andusage/modelUsage/totalCostUsdonturn.completedare all untested, althoughOpenCodeAdapter.test.tsalready feeds syntheticmessage.updated/message.part.updatedevents through the adapter.
Previously flagged items are resolved: the node:sqlite suppression now carries an adjacent rationale, resolveOpenCodeDbPath receives the env from HostProcessEnvironment, UsageService uses Effect's Path instead of a new node:path import, the turn.completed payload no longer uses a Record<string, unknown> / as never cast, and parseOpenCodeMessage now has focused tests in usageTranscripts.test.ts.
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 reviewed: apps/server/src/provider/Layers/OpenCodeAdapter.ts, apps/server/src/usage/usageOpenCodeDb.ts, apps/server/src/usage/UsageService.ts, apps/server/src/usage/usageTranscripts.ts (+ test), apps/server/src/usage/usageScanCache.ts, apps/web/src/components/usage/usageProviders.ts, apps/mobile/src/features/usage/usageProviders.ts, packages/contracts/src/usage.ts, packages/shared/src/usageMerge.test.ts.
Checks that passed:
- Effect modules are imported as subpath namespaces; no consolidated
from "effect"imports added. - No new
Context.Service/make/layerdefinitions, no new error classes, so definition-order,Schema.TaggedErrorClass, and predicate rules are not engaged. - No
ManagedRuntime.make,runPromise,runPromiseExit,Layer.succeed, or service-instance parameters introduced;Effect.promisewrappers around the SQLite reader mirror the existingreadTranscriptRecords/readDirectoryVolumeIdpattern inUsageService.make. usageOpenCodeDb.tsisolating Node built-ins follows the documented precedent inusageTranscriptReader.ts, and its file-widenodeBuiltinImport:offdirective now states the reason (node:sqlitehas no Effect wrapper). Theeslint-disable-next-line no-await-in-loopat line 153 has an adjacent explanatory comment (event-loop yielding on cold scans).OpenCodeIconreferenced byapps/web/src/components/usage/usageProviders.tsalready exists inIcons.tsx.
Note (not reported as a violation): resolveOpenCodeDbPath retains a = process.env default parameter, but the only production caller passes HostProcessEnvironment, so the environment dependency is explicit at the service boundary.
🔍 Agent activity — 18 tool calls
💭 I'm checking the current PR state for previously flagged issues—confirming the suppression comment now includes a rationale and tests were added, then examining the UsageService's path import usage to verify it's correctly using
path.joinandpath.dirname. I also want to verify the OpenCodeAdapter payload cast that usedas neverseems resolved with a spread of defined keys, but let me check the actual files to confirm.
1. git_tools — ^import|NodeOS|NodePath|effect-diagnostics
2. git_tools — process.env|hostEnvironment
💭 Good, the env threading looks fixed now, with the default parameter fallback being a minor concern but not a real violation since callers already pass the env explicitly. The OpenCodeAdapter's turn.completed payload also seems resolved, so I'm moving on to check what else changed in this diff version. I want to look at usageOpenCodeDb.ts's node builtin imports — it uses node:fs, node:os, and node:path with a suppression comment referencing only node:sqlite, which raises the question of whether those other imports should route through Effect's FileSystem/Path instead. I should compare against usageTranscriptReader.ts to see if there's precedent for this isolated-file pattern, and also check whether readOpenCodeDbRecords wraps its plain async function in Effect.promise in a way consistent with existing conventions.
3. git_tools — 8aeb626..52f99f6
4. browse_code — apps/server/src/usage/usageTranscriptReader.ts
💭 The new file matches the existing pattern, so now I want to check the OpenCodeAdapter changes for conventions by looking at the head of the relevant sections.
5. browse_code — apps/server/src/provider/Layers/OpenCodeAdapter.ts
💭 I'm noticing there's an unused function being added, but dead code isn't really covered by the Effect service convention checks I'm scoped to, so I don't think it's worth flagging here.
6. git_tools — tryExtractOpenCodeTokensFromRecord
7. browse_code — apps/server/src/usage/usageOpenCodeDb.ts
💭 I notice
tryExtractOpenCodeTokensFromRecordis defined but never called, which is dead code and would likely trigger a lint failure. It's not explicitly covered by the listed conventions though, so I'm weighing whether this counts as a reportable violation or falls outside scope. I'm also checking the neweslint-disable-next-line no-await-in-loopsuppression in usageOpenCodeDb.ts to see if it has an adjacent explanation, since the convention requires new suppressions to be justified—there's a comment about yielding to the event loop periodically that may satisfy this.
8. browse_code — {eslint.config.,.eslintrc,tsconfig*.json,biome.json*,oxlint*}
9. git_tools — eslint-disable
10. browse_code — tsconfig.base.json
💭 I'm wondering whether the globalTimers diagnostic actually flags setImmediate usage, since that file only disables nodeBuiltinImport and the call sits in a plain async function rather than inside an Effect. promise. Since it's more of a build-time concern than a convention violation, I'll set it aside. Next I want to verify whether JSON.parse in parseOpenCodeMessage matches existing parser patterns in usageTranscripts.ts, and also check whether Effect.promise is used elsewhere for the transcript reader in a way that swallows errors similarly. I should also confirm that OpenCodeIcon actually exists in the web Icons module, since a missing import there would be a real correctness issue worth flagging.
11. git_tools — OpenCodeIcon
12. git_tools — Effect.promise|Effect.tryPromise
💭 I confirm OpenCodeIcon predates this PR, so that's fine. I'm now flagging remaining concerns: an unused helper function
tryExtractOpenCodeTokensFromRecordin OpenCodeAdapter.ts, and some heavy type casts in the default case that seem worth reviewing. Theenv = process.envdefault remains a hidden dependency, but since callers already pass it and this was previously flagged, re-raising it would be duplicative — I'll skip it. I'm also considering whether the token usage emission behavior changed without corresponding test coverage, so I want to check if existing tests cover OpenCodeAdapter.
13. browse_code — apps/server/src/provider/**/OpenCode
14. browse_code — apps/server/src/usage/*.test.ts
💭 I notice there's an existing OpenCodeAdapter.test.ts that the PR doesn't touch, yet the new token-usage emission behavior in turn.completed isn't covered by any test. Since backend behavior changed, this seems like a legitimate gap worth flagging — I want to check whether the test file already handles similar events like message.updated so adding a token-usage test would fit naturally.
15. git_tools — token-usage|turn.completed|message.updated|message.part.updated
💭 The test infrastructure already supports feeding synthetic events, so flagging the missing focused test for token-usage emission and turn.completed usage is a valid finding. I also want to flag the dead helper
tryExtractOpenCodeTokensFromRecord, and now I need to check exact line numbers around 580-600 of the adapter and confirm diff line positions so my comments land correctly. Looking at the diff hunks, the dead helper sits within the added range at lines 588-592, so it's commentable on the right side. For the missing-test finding, I'll anchor on theemitOpenCodeTokenUsagedefinition around line 750, which falls within another added block. Let me verify the exact content at those lines before finalizing.
16. browse_code — apps/server/src/provider/Layers/OpenCodeAdapter.ts
17. browse_code — apps/server/src/provider/Layers/OpenCodeAdapter.ts
💭 Both anchors check out, so I'll post two comments. For the dead helper, I'll suggest deleting it using an empty suggestion block covering those lines, since GitHub supports that for deletions. For the second comment about missing tests on the new adapter behavior, I'll just flag it without a diff suggestion. Time to post both.
18. modify_pr — Effect Service Conventions: two findings on apps/server/src/provider/Layers/OpenCodeAdapter.ts. The previously flagged items (missing suppression rationale, process.env in the DB path resolver, node:path in UsageService, the as never payload cast, and the missing parseOpenCodeMessage tests) all look addressed.
Agent Credits: 86 credits
Token usage: 24 uncached input · 521,366 cache-read input · 55,121 cache-write input · 8,439 output
Agent Credits may also include non-token charges from external tools such as web research.