Skip to content

fix(usage): address review findings for opencode integration

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 31, 2026 in 2m 40s

Effect Service Conventions: 2 issues found

  • apps/server/src/usage/usageOpenCodeDb.ts:1 — new file-wide // @effect-diagnostics nodeBuiltinImport:off has no adjacent comment explaining why the diagnostic must be disabled there.
  • apps/server/src/usage/usageTranscripts.ts:500 — new parseOpenCodeMessage backend parsing behavior ships without focused tests, unlike the sibling Claude/Codex/Grok parsers covered in usageTranscripts.test.ts.

The three findings from the prior run are resolved: UsageService now uses the Effect Path service (the node:path import and its file-level suppression are gone), resolveOpenCodeDbPath receives HostProcessEnvironment from the service, and the turn.completed payload spreads only defined keys without the as never cast.

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/usage/UsageService.ts, apps/server/src/usage/usageOpenCodeDb.ts, apps/server/src/usage/usageTranscripts.ts, apps/server/src/usage/usageScanCache.ts, apps/server/src/provider/Layers/OpenCodeAdapter.ts, packages/contracts/src/usage.ts, plus the web/mobile provider presentation maps.

Checked and considered acceptable:

  • usageOpenCodeDb.ts following the existing usageTranscriptReader.ts pattern (Promise helper module bridged via Effect.promise from the service, null for unreadable sources so the caller can report a failed source instead of caching an empty result). This matches established usage-module precedent and is not fake dependency injection or a hidden runtime.
  • No ManagedRuntime.make, runPromise, runPromiseExit, Layer.succeed, or service-instance parameters were introduced in the changed code.
  • turn.completed payload construction now type-checks against TurnCompletedPayload (usage: Schema.optional(Schema.Unknown), modelUsage: Schema.optional(UnknownRecordSchema)), with optional keys conditionally spread.
  • Contract version bump to 6 with USAGE_MERGE_COMPATIBLE_SINCE unchanged, and the usageScanCache provider guard extended for opencode.

Minor observation not posted (outside this check's concrete-violation bar): resolveOpenCodeDbPath still defaults its env parameter to process.env, so a future caller that omits the argument bypasses HostProcessEnvironment; the service call site passes it correctly today. Also, the new mightCarryUsage branch for "opencode" is unreachable because OpenCode usage is read from the SQLite database rather than line scanning.


🔍 Agent activity — 15 tool calls

💭 I'm checking whether the prior review's three concerns were addressed between commit b9e723c and the current head at 8aeb626. It looks like the env parameter is now threaded through, with UsageService passing hostEnvironment instead of relying solely on the default process.env. I'm also verifying whether the turn.completed payload construction was cleaned up to avoid unsafe type casting, and whether path/os module usage in UsageService is using the Effect Path service correctly rather than the raw node modules. I want to pull up the actual files to confirm.

1. git_tools — NodeOS|NodePath|node:path|node:os|nodeBuiltinImport",|nodeBuiltinImport

2. browse_code — apps/server/src/usage/usageOpenCodeDb.ts

💭 Good, the path service, env threading, and cast fixes are all confirmed addressed. Now I'm checking the remaining item at the top of usageOpenCodeDb.ts. line 1, which has a file-wide nodeBuiltinImport:off suppression directive with no adjacent explanation — that violates the requirement that every new suppression needs a comment justifying it. I need to trace whether this suppression was already flagged elsewhere or is tied to a different file, since a grep of UsageService.ts shows it no longer has that directive. This particular file's suppression seems new and unflagged so far, but I want to check whether similar files in the repo, like usageTranscriptReader.ts, follow the same pattern with or without explanations before treating this as a clear-cut violation.

3. git_tools — effect-diagnostics nodeBuiltinImport

4. browse_code — apps/server/src/usage/UsageService.ts

💭 I'm noticing the bare directive without explanation is common elsewhere in the repo too, like usageTranscriptReader.ts. The module docstring nearby does hint at why node builtins are needed since it reads the SQLite file directly, though it's not an explicit justification tied to the directive itself. I should focus on whether this new module actually breaks Effect service conventions. It uses Promise-based code wrapped in Effect.promise rather than going through Effect's FileSystem the way the sibling reader module does, which could be a real inconsistency worth flagging. I'm also weighing whether defaulting the env parameter to process.env counts as hiding a dependency, though since it's threaded in from the calling service rather than accessed globally, it may be a lesser concern. Now I want to check how UsageService actually passes the host environment into resolveOpenCodeDbPath, and compare the error-handling pattern in the new reader against the existing transcript reader to see if swallowing errors as null is already an established convention or a genuine deviation from the tagged-error approach.

5. browse_code — apps/server/src/usage/usageTranscriptReader.ts

6. browse_code — apps/server/src/usage/UsageService.ts

💭 I'm noticing the new file mirrors the sibling module's style but omits the justification for using node builtins instead of Effect FileSystem that the sibling explicitly includes in its docstring. I also recall a prior comment referenced UsageService.ts's suppression directive, not this file's, so this particular directive hasn't been flagged yet — it's a new file, so I'll note it with a suggestion to add justification. Now I want to check the OpenCodeAdapter changes for any service convention issues.

7. browse_code — apps/server/src/provider/Layers/OpenCodeAdapter.ts

8. browse_code — apps/server/src/provider/Layers/OpenCodeAdapter.ts

💭 I'm questioning whether the usage object passed into turn.completed actually matches the expected shape, since it's the raw OpenCodeTokens structure rather than whatever format the contract expects for Claude—now that the as never cast is gone, TypeScript should catch this mismatch if it's real. This feels like a correctness concern outside the scope of Effect service conventions, so I'll only flag it if the type check clearly fails; otherwise I should stay focused on the conventions review and check the contract's actual definition for turn.completed's usage field.

9. git_tools — modelUsage

💭 The raw promise usage in usageOpenCodeDb.ts seems acceptable given the sibling module follows the same pattern and isn't a service. The bare suppression directive without explanation is a real violation of the change discipline convention, though the sibling file has the same bare form, so precedent may excuse it. The resolveOpenCodeDbPath default of process.env is a mild leftover from my earlier feedback -- the caller does pass hostEnvironment properly now, so re-flagging feels nitpicky and I'll skip it. I want to double check that the UsageService correctly passes hostEnvironment as a HostProcessEnvironment service by tracing its type back to where it's yielded.

10. git_tools — HostProcessEnvironment

11. browse_code — apps/server/src/usage/UsageService.ts

💭 With findings 1 and 3 resolved and finding 2 partly handled, I'm checking what else in this file still violates the rules. I notice a bare suppression comment in usageOpenCodeDb.ts without justification, but since it was present unchanged in the prior commit and wasn't flagged then, I shouldn't raise it now to avoid duplicating past feedback. I'm also weighing whether the module's docstring counts as sufficient explanation for disabling the node builtin import check, since it justifies the DB-scanning approach but not the specific suppression choice—so I'd lightly flag it with a suggested rationale addition. I'm also looking at the empty catch blocks around error handling and connection closing, but these seem consistent with existing patterns elsewhere in the codebase, so probably not worth flagging. Now I'm considering whether the significant new parsing logic added in this PR—message parsing, token extraction, and DB reading—requires focused tests, since this isn't a mechanical refactor but genuinely new backend behavior. I want to check whether existing parser tests exist for the other adapters, so I can point to where a corresponding OpenCode parser test should live.

12. browse_code — apps/server/src/usage/*.test.ts

13. git_tools — parseGrokLine|parseCodexLine

💭 I notice the new parseOpenCodeMessage function lacks the focused unit tests that other provider parsers have in usageTranscripts.test.ts, which violates the existing testing convention. I'm also spotting that mightCarryUsage's new "opencode" branch is effectively dead code since OpenCode uses the DB reader path rather than line-based parsing. Deciding what to flag: the file-wide nodeBuiltinImport:off in usageOpenCodeDb.ts needs an inline comment suggesting rationale, and the missing tests for parseOpenCodeMessage deserve their own inline comment. Now I need to pin down the exact diff line numbers for both files to post these as inline review comments.

14. git_tools — export function parseOpenCodeMessage

💭 The node builtin imports in usageOpenCodeDb.ts genuinely need the suppression since it's importing node:fs, node:os, node:path, and node:sqlite, but the file lacks any rationale explaining why. Confirming this is a new file so the whole thing falls within the diff, I'm drafting a comment flagging that the suppression at line 1 needs justification. For the second finding, I'm noting that the new parser in usageTranscripts.ts around line 500 lacks focused tests, unlike its sibling parsers which are covered — I want to ask for specific test cases around role handling, cache-exclusive tokens, reasoning clamps, and timestamp fallbacks. Given both findings are concrete violations, I'm setting the review state to failure rather than passing, and then posting the review.

15. modify_pr — Two findings on this revision. The three items from the previous run (Effect Path in UsageService, threading HostProcessEnvironment into resolveOpenCodeDbPath, and the as never cast on the turn.completed payload) are resolved.


Agent Credits: 104 credits

Token usage: 20 uncached input · 545,849 cache-read input · 76,731 cache-write input · 9,440 output
Agent Credits may also include non-token charges from external tools such as web research.