Skip to content

Merge branch 'main' into fix/windows-path-refresh

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 30, 2026 in 4m 0s

Effect Service Conventions: 2 issues found

Two findings were posted as review comments.

  • apps/server/src/provider/Layers/ProviderRegistry.test.ts (lines 1032, 1055): two fake ProviderInstance snapshots still use the removed maintenanceCapabilities field instead of the new getMaintenanceCapabilities: Effect<...> member of ServerProviderShape, so they no longer satisfy the shape they are declared against (satisfies ReadonlyArray<ProviderInstance> at line 1068). Every other fake instance in the file was migrated.
  • apps/server/src/provider/Layers/ProviderRegistry.ts (lines 234-242): refreshWindowsPath pins FileSystem/Path from the layer's construction context but leaves HostProcessPlatform and HostProcessEnvironment (both Context.References with process.* defaults) to be resolved from the caller's context at refresh time, so the hydration step can mutate a different environment object than the one drivers captured, and can disagree with the construction-time platform === "win32" gate.

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: all changed apps/**/*.ts and packages/**/*.ts files, plus affected call sites of the renamed ServerProviderShape member and the new mergeProviderInstanceEnvironment(environment, platform, hostEnvironment) signature.

Checked and found acceptable:

  • Effect module imports in touched files use subpath namespaces (effect/Effect, effect/Layer, effect/Semaphore, ...).
  • HostProcessPlatform / HostProcessEnvironment are now acquired from the Effect environment in ClaudeDriver, CodexDriver, CursorDriver, GrokDriver, OpenCodeDriver, and ClaudeHome.makeClaudeEnvironment, replacing the previous process.env default in the merge helper (the finding from the prior run on CodexDriver has been addressed).
  • ClaudeAdapter.makeClaudeAdapter re-provides the construction-time HostProcessPlatform, SpawnExecutableResolution, and ClaudeExecutableFileCheck into the per-session resolution, which is a deliberate context pin rather than hidden injection; the test seams provided in ClaudeAdapter.test.ts are legitimate test-only service overrides.
  • No new ManagedRuntime.make, runPromise, or runPromiseExit usage in domain services; no new service-instance parameters in production constructors.
  • Search of apps/, packages/, and infra/ found no other remaining consumers of the removed ServerProviderShape.maintenanceCapabilities member besides the two test occurrences reported above.

🔍 Agent activity — 19 tool calls

💭 I'm checking that the earlier flagged issue about process.env defaults in CodexDriver was resolved—it now merges provider environment with host environment properly. Then I'm reviewing other files for conventions, starting with the pure ProviderInstanceEnvironment function and moving into ProviderRegistry's use of platform detection and path fixing. Now I'm looking at whether re-providing services that were already acquired in the same scope violates the convention against constructing services outside the environment—it seems like acceptable plumbing rather than a real violation. I'm scanning ClaudeAdapter for its executable path resolution pattern and ServerProvider for its shape interface, checking whether these are new issues or pre-existing patterns that don't need flagging. I want to actually look at these files directly, plus check the import style used for effect and layer across the changed files.

1. browse_code — apps/server/src/provider/ProviderInstanceEnvironment.ts

2. browse_code — apps/server/src/provider/Services/ServerProvider.ts

💭 ServerProviderShape already existed before this change, so I don't need to worry about it. Let me check ProviderRegistry.ts to see how it relates to the new code.

3. browse_code — apps/server/src/provider/Layers/ProviderRegistry.ts

4. browse_code — apps/server/src/provider/Layers/ProviderRegistry.ts

💭 I want to check os-jank.ts to see how fixPath handles the environment and whether it mutates process.env directly. I'm also questioning whether providing FileSystem as a service is redundant here, since the layer already includes it and refreshWindowsPath is used as a plain effect that might not have access to that context.

5. browse_code — apps/server/src/os-jank.ts

💭 I'm checking whether fixPath still needs HostProcessPlatform and HostProcessEnvironment even after FileSystem and Path are supplied — it looks like refreshWindowsPath keeps that dependency requirement since the layer only provided the file system pieces. Now I want to verify whether ProviderRegistryShape's method signatures declare R as never, since if the effects still carry leftover requirements, TypeScript would flag it where the layer builds the service. I'm going to look at the ProviderRegistry service definition to see how it types the shape, and also reconcile why HostProcessPlatform gets yielded at construction time while fixPath separately re-requires it.

6. browse_code — apps/server/src/provider/Services/ProviderRegistry.ts

💭 I'm working through whether assigning an Effect requiring HostProcessPlatform/HostProcessEnvironment to a slot typed as requiring R = never would actually type-check, considering Effect's contravariance in its requirements type parameter might allow the mismatch.

7. browse_code — packages/shared/src/hostProcess.ts

💭 These use Context.Reference with defaults, so the reference type resolves to never and falls back to process.platform/process.env at runtime when not provided, matching this codebase's convention. I'm now considering whether refreshWindowsPath's fixPath call, which reads HostProcessEnvironment from the runtime context, correctly picks up the FS and Path provided at layer construction versus resolving from the caller's context instead. Comparing this to the drivers—like ClaudeDriver, which explicitly provides HostProcessPlatform when resolving maintenance capabilities—I notice ProviderRegistry doesn't mirror that pattern for fixPath, since it re-acquires platform/env from wherever it's called rather than capturing them at construction. This looks like a real inconsistency worth flagging, though I'm weighing how severe it actually is given tests currently work because the values happen to be provided globally. I want to trace where fileSystem comes from in ClaudeDriver, since CodexDriver and OpenCodeDriver explicitly yield FileSystem and Path but ClaudeDriver's diff doesn't show that addition—likely it's already declared elsewhere in that file. I also need to check the changes to makeManagedServerProvider, and confirm whether ClaudeAdapter's new ClaudeExecutableFileCheck and SpawnExecutableResolution definitions are set up as Context.Reference.

8. browse_code — apps/server/src/provider/Drivers/ClaudeDriver.ts

9. browse_code — apps/server/src/provider/Drivers/ClaudeExecutable.ts

💭 I notice ClaudeAdapter grabs hostPlatform, spawnExecutableResolution, and claudeExecutableFileCheck at construction and re-provides them per-session—since these are references with defaults that never resolve otherwise, this seems intentional just to capture construction-time context. Now I want to check makeManagedServerProvider.ts in full to understand the union input.

10. browse_code — apps/server/src/provider/makeManagedServerProvider.ts

💭 The union type with runtime branching feels a bit off, though it's not explicitly disallowed by the conventions. I want to check whether every other consumer of snapshot.maintenanceCapabilities was actually updated, so I'm searching the repo for usages tied to ServerProviderShape.

11. git_tools — maintenanceCapabilities

💭 I'm noticing other references to maintenanceCapabilities around lines 1032 and 1055 in the test file, but those might belong to a different object like the maintenance runner input rather than ServerProviderShape. Let me check those spots to see if they'd cause type errors too.

12. browse_code — apps/server/src/provider/Layers/ProviderRegistry.test.ts

💭 I'm noticing two remaining maintenanceCapabilities entries in ProviderRegistry.test.ts (around lines 1032/1055) that weren't updated to include getMaintenanceCapabilities, so they'd fail typecheck under the new ServerProviderShape — this looks like a genuine gap the PR missed since it's a test file within scope. I've confirmed these lines weren't touched in the diff (only 909, 1178, 1309, 1607, 1702 were updated) and are still present at HEAD, so this is a real compile-breaking issue introduced by the shape change. Let me check if there are any other stale usages elsewhere across apps and packages before finalizing this as a concrete finding.

13. git_tools — maintenanceCapabilities

14. browse_code — apps/server/src/provider/Layers/ProviderRegistry.ts

💭 I'm checking whether liveSubsRef holds ProviderInstance or a snapshot source, then noticing an inconsistency: fixPath() resolves platform and environment from the caller's context at each refresh, while the layer captured platform from its own context—so if a caller runs with a different context than the default, the paths could diverge. This is a real convention violation worth flagging: FS/Path are pinned from construction context but HostProcessPlatform/HostProcessEnvironment aren't propagated the same way, so the win32 gating check could disagree with the actual hydration. Since References have defaults, nothing signals this at the type level, but I notice the drivers in this same PR already provide HostProcessPlatform captured at construction—so for consistency, this instance should do the same via Effect.provideService for both HostProcessPlatform and HostProcessEnvironment. That said, in practice the runtime context flows through to callers within the app runtime, so this is likely fine outside of tests where a caller might run with a different context. The risk is narrow but real. The more definite issue is in ProviderRegistry.test.ts around lines 1032 and 1055, which still reference maintenanceCapabilities — that would be a type error since the test object is checked against ReadonlyArray<ProviderInstance> at line 1068, requiring getMaintenanceCapabilities on the ServerProviderShape. That's a genuine compile error worth flagging.

15. git_tools — snapshot: ServerProviderShape|snapshot:.*ServerProviderShape

💭 That's confirmed, now I should check other test files that construct similar fake provider objects, searching for places using "getSnapshot: Effect.succeed" to find instances still missing getMaintenanceCapabilities.

16. git_tools — streamChanges: Stream.empty

💭 I've confirmed the two stale references in ProviderRegistry.test.ts will break tsc, worth flagging inline since it's in scope. Now I'm double-checking the import conventions too—specifically whether the new named imports from the hostProcess subpath align with expected patterns for a Context.References module rather than a service with make/layer. Reviewing the other changes: mergeProviderInstanceEnvironment looks like a clean pure function, and ClaudeHome.ts properly acquires the platform via yield*. I want to trace where resolvedBaseEnv originates though, since it might default to process.env as a hidden dependency, so I'm going to check ClaudeHome.ts directly.

17. browse_code — apps/server/src/provider/Drivers/ClaudeHome.ts

💭 I'm noticing this same pattern I flagged earlier for CodexDriver: falling back to process.env directly instead of yielding HostProcessEnvironment, even though this function already yields HostProcessPlatform from the environment. The line itself is unchanged in the diff, but since the PR modified this function to source platform from the environment, the inconsistency of still defaulting to the module-level process.env got carried forward rather than fixed. Since the author already addressed the equivalent issue elsewhere but not here, flagging it seems warranted rather than duplicative — different file, same unresolved pattern. I want to check who calls makeClaudeEnvironment and whether the baseEnv parameter is actually used by any caller before deciding how to phrase the comment.

18. git_tools — makeClaudeEnvironment

💭 I'm noting that the fallback on line 23 predates this diff, so flagging it would mean calling out an untouched line—but it's still worth considering since the PR is actively reworking this function's environment handling, and callers omitting a value could hit that hidden dependency. Actually, checking further, that fallback resolves to process.env directly, which is live and matches what the test expects, so there's no real behavioral issue—I'll leave it unflagged as it seems like unrelated legacy code. I'm now scanning the rest of the diff for other concrete convention issues: the environment test spawns a real child process, which isn't ideal but isn't a service-pattern violation; the adapter's executable-path resolution deliberately captures construction-time context, which seems intentional; and I'm checking the maintenance capabilities typing on the managed server provider factory for anything worth flagging. Weighing whether to raise a second finding around ProviderRegistry's path-refresh logic. There, filesystem and path get pinned at construction while platform and environment context get resolved per-call, which means the platform gate could disagree with the environment used, and the captured host environment at construction might diverge from what's resolved at the call site, so PATH hydration could silently fail to apply in some scenarios. I'm deciding whether this is significant enough to report alongside my primary finding, given I already have one strong issue. Actually this seems defensible and actionable: fixPath depends on HostProcessPlatform/HostProcessEnvironment, and if drivers capture a different environment object reference at construction than what fixPath reads at call time, PATH hydration could silently write to the wrong environment while drivers read a stale one — a real correctness risk, not just style. That's worth flagging concretely. Now I need to pin down exact line numbers for my comments in the new file. In ProviderRegistry.ts, the added lines 232-242 include the fixPath call around line 237, which sits in the added hunk, so it's a valid target for an inline comment. But ProviderRegistry.test.ts line 1032 is unchanged, not part of the diff — I need to check whether GitHub even permits commenting there, since review comments typically require the line to appear in the diff. Since line 1032 falls outside any hunk (nearest hunks around 909 and 1178), an inline comment there likely won't be accepted by the API. I'm weighing whether to skip it, attach it awkwardly to a nearby changed line, or just fold that note into the overall review body text referencing the file and line instead of as an inline comment. Good, that test file's provider setup looks fine. Now I'm putting together the review: an inline comment on ProviderRegistry.ts around line 237 about pinning HostProcessPlatform/HostProcessEnvironment, plus a body note flagging the stale maintenanceCapabilities field in ProviderRegistry.test.ts at lines 1032/1055 since there's no good diff line to anchor it inline. Now let me draft the actual suggestion text for the ProviderRegistry.ts comment. I'm capturing the current 230-242 code showing how platform gets resolved from HostProcessPlatform and used to conditionally run the Windows path fix. The suggested fix adds a hostEnvironment binding pulled from HostProcessEnvironment right alongside the existing platform binding. Since this also requires providing both HostProcessPlatform and HostProcessEnvironment as services within the pipe, plus an import addition for HostProcessEnvironment, I'm noting this spans two related changes—the main hunk and the import update—so I'll present the unified diff for the core logic while calling out the necessary import addition separately. That confirms it's within the added range. Given the customer's instructions that this check defaults to failure when a clear convention violation exists, I'll conclude this should be marked as failure since I have real findings. For the test-file issue, I'll skip trying to post it inline since risking the whole review failing isn't worth it — I'll put both findings in the review body instead, starting with the provider-related issue.

19. modify_pr — ## Effect Service Conventions — 2 findings 1. Stale ServerProviderShape consumers left behind (apps/server/src/provider/Layers/ProviderRegistry.test.ts, lines 1032 and 1055) This PR renames ServerProviderShape.maintenanceCapabilities to getMaintenanceCapabilities: Effect<...>, and every other fake instance in this file was migrated — but the two instances in the instances array (satisfies ReadonlyArray<ProviderInstance> at line 1068) still set the removed field, so they no longer satisfy the new shape. diff snapshot: { - maintenanceCapabilities: makeManualOnlyProviderMaintenanceCapabilities({ - provider: codexDriver, - packageName: null, - }), + getMaintenanceCapabilities: Effect.succeed( + makeManualOnlyProviderMaintenanceCapabilities({ + provider: codexDriver, + packageName: null, + }), + ), getSnapshot: Effect.succeed(codexProvider), (and the same change for the openCodeDriver instance at line 1055). 2. refreshWindowsPath does not pin the host-process references it was built from — see the inline comment on apps/server/src/provider/Layers/ProviderRegistry.ts.


Agent Credits: 160 credits

Token usage: 32 uncached input · 986,145 cache-read input · 104,998 cache-write input · 14,631 output
Agent Credits may also include non-token charges from external tools such as web research.