Skip to content

fix: discover project skills from workspace

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 4, 2026 in 2m 21s

Effect Service Conventions: 1 issue found

1 finding

  • apps/server/src/provider/Drivers/CodexDriver.ts:221 — the new skill-discovery fallback logs error: String(error), copying arbitrary error text (including the spawned codex app-server command from CodexAppServerSpawnError) into the log payload. Log a normalized tag (errorTag/causeErrorTag from @t3tools/shared/observability, as the other provider layers do) and keep the real error only as cause.

An inline review comment with a suggested fix has been posted.

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.

Reviewed in-scope changes:

  • apps/server/src/provider/Drivers/CodexDriver.ts — new listSkills closure. Namespace subpath imports (import * as Duration from "effect/Duration") are correct; Effect.provideService(ChildProcessSpawner...) re-provides a dependency already acquired from the environment inside the same constructor (a legitimate R = never narrowing, not fake injection); the whole error channel is intentionally handled, so Effect.catch is appropriate. Only the log annotation is flagged.
  • apps/server/src/provider/Layers/CodexProvider.ts — extraction of openCodexAppServerProbe plus the new listCodexProviderSkills keeps Effect.fn naming, reuses buildCodexInitializeParams() (removing a duplicated literal), and leaves scope acquisition to callers. No error-modelling changes introduced.
  • apps/server/src/provider/Layers/ProviderRegistry.ts, Services/ProviderRegistry.ts, ProviderDriver.ts — additive listSkills method/optional instance hook. The pre-existing Services/Layers split and ProviderRegistryShape interface are legacy and out of scope for this PR.
  • apps/server/src/ws.ts, apps/server/src/auth/RpcAuthorization.ts, packages/contracts/src/{rpc,server}.ts, packages/client-runtime/src/state/server.ts — new RPC method, scope entry, and schemas follow existing patterns; failures stay in the Effect channel (Effect.orElseSucceed), with no ManagedRuntime.make, runPromise, or Layer.succeed hidden-runtime usage.
  • apps/web/src/state/queries.ts, apps/web/src/components/chat/ChatComposer.tsx, ChatView.tsx — React query/UI wiring at the framework boundary; no Effect service construction.
  • Tests (ProviderRegistry.test.ts, server.test.ts, providerMaintenanceRunner.test.ts, testUtils/providerRegistryMock.ts) — focused backend behavior coverage for the new routing, using test layers rather than mocking business logic.

🔍 Agent activity — 1 tool call

💭 I'm looking at the diff to identify Effect service convention violations, starting with the CodexDriver file which uses Effect.catch to handle errors and Effect.timeout with error catching, which appears acceptable for intentional error channel handling. I'm also checking the broader usage patterns of Effect.catch against the guidelines to see where it's being applied appropriately. The ProviderRegistry file has a pre-existing ProviderRegistryShape interface that the PR modifies, but since this is legacy code and the instructions say not to flag unrelated repository-wide cleanup, I'm not flagging it. However, I'm noticing that listSkills returns an Effect with no error channel, yet it calls instanceRegistry.getInstance which could fail — that might be a type mismatch worth investigating. The ws.ts file is using Effect.orElseSucceed to swallow errors and return Option.none(), which seems to violate the convention about keeping failures typed in the Effect layer rather than bypassing it. Let me look at the actual implementation files to verify whether CodexDriver properly provides service instances and whether ProviderRegistry.listSkills is correctly typed for its error handling. I'm looking at a logging issue in CodexDriver where an error is being stringified directly into a log annotation. The problem is that this could expose sensitive information like command arguments or stderr output, which violates the logging safety guidelines that require sanitized error handling. However, stringifying errors into log annotations is pretty standard practice, so this feels like a weak finding. The Effect.catch is properly scoped to the channel, and the pre-existing detail: cause.message on line 143 isn't part of the diff anyway. Moving through the other files now — ws.ts looks fine, and in ProviderRegistry.ts, the instanceRegistry.getInstance call would cause a type error if it had an error channel since the return type specifies no error, so that's presumably safe. I'm checking for any catchIf, catchTag, Layer.succeed, ManagedRuntime, or runPromise patterns in the changed code, but none appear in the diff. Now I need to look at the imports in apps/web/src/state/queries.ts. Checking the ChatComposer and contracts imports to make sure they're following conventions properly, and the CodexProvider's consolidated imports from "effect" look fine. I'm noticing the new listCodexProviderSkills and openCodexAppServerProbe functions might have resource lifecycle issues since Layer.build needs a scope to work correctly. Looking at the error handling with Effect.catch((error) => ... String(error)) — this could be problematic under the logging guidelines. The error object could be a CodexAppServerSpawnError with command strings and spawn stderr in its message, or a TimeoutError, or a JSON-RPC error containing wire payloads. Converting that to a string and putting it in a log annotation looks like it's capturing arbitrary defect text, which the rules explicitly prohibit. This feels like a genuine violation worth flagging. Let me check if other parts of the codebase do error: String(error) in similar logging calls to see if this is a pattern. I'm noticing that the code uses String(error) to convert the error directly into the log payload, which goes against the repo's convention of using normalized error tags or passing the cause through proper channels. This looks like it could violate the check's rule about not copying arbitrary defect text into parallel log payloads—the check specifically wants normalized categories exposed instead. Since this is a new line in the CodexDriver.ts diff and falls under the "Errors and predicates" section, it's worth flagging. I've checked ChatComposer and it doesn't have Effect service concerns since it's React. The ws.ts handler uses Effect.orElseSucceed to swallow failures intentionally, which aligns with the convention of keeping failures typed in Effect when callers need fallback behavior. The listSkills field on the registry shape is optional as expected. Now I'm looking at whether Effect.catch is being used appropriately—the rule says to use Effect.catchTags for statically known tagged failures, and Effect.catch is only appropriate when the entire error channel needs handling. In CodexDriver, the entire error channel (spawn errors, timeouts, jsonrpc errors) is being handled, so that's fine. The main issue I found is the error: String(error) pattern—since Effect.catch provides a typed error union where all errors have a _tag property, I should suggest replacing it with errorTag: error._tag to preserve the error type information instead of stringifying it. The safer approach would be using Effect.catchCause with causeErrorTag, which is the dominant pattern in the repo, but that requires additional imports and changes the structure. I'll describe the issue without proposing a strict diff. I should also look at the errorTag helper function in the shared observability module. I can use errorTag() from the observability utilities to normalize the error, which is cleaner than manual handling. Since CodexDriver doesn't currently import from that package, I'll need to add the import statement. Let me check if there are any other issues in the diff I should address. Looking through the rest of the changes, the interface naming conventions are acceptable—ProviderRegistryListSkillsInput is fine for an input type, and the optional listSkills field on the driver instance is reasonable. The contract definitions look good too. The tests are in place for the new behavior, which satisfies the testing requirement. So the only real finding is the log annotation issue, which is a modest but clear violation of the rules. Given the instructions that this check defaults to failure when there are findings, I'll mark it as failure and post an inline comment on line 221 of CodexDriver.ts about the String(error) pattern not matching the repo's convention of using errorTag or causeErrorTag.

1. modify_pr — One finding on error-log hygiene in the new Codex skill-discovery fallback. Everything else (subpath namespace imports, Effect.fn service methods, whole-channel Effect.catch, contract schemas, added focused tests) matches the conventions.


Agent Credits: 84 credits