Repository navigation
Effect Service Conventions: 1 issue found
1 finding
apps/server/src/orchestration/Services/ThreadSettlementReactor.ts(andapps/server/src/orchestration/Layers/ThreadSettlementReactor.ts): the newThreadSettlementReactorservice is defined in the legacyServices/+Layers/split with a standaloneThreadSettlementReactorShapeinterface and aThreadSettlementReactorLivelayer export. Canonical layout is a single module (apps/server/src/orchestration/ThreadSettlementReactor.ts) with the interface inlined in theContext.Servicedeclaration, references viaThreadSettlementReactor["Service"], and exportedmake/layer.
An inline review comment with the concrete fix and the consumer files to update 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.
Checked and clean
- Dependency acquisition:
makeinLayers/ThreadSettlementReactor.tsacquires every dependency (OrchestrationEngineService,ProjectionSnapshotQuery,ServerSettingsService,GitManager,PullRequestService,Crypto.Crypto) from the Effect environment; no service instances are passed as constructor parameters and no dependencies are hidden in module globals. - Runtime boundaries: no
ManagedRuntime.make,runPromise, orrunPromiseExitintroduced in server service code.Layer.succeed/Layer.mockappear only in test harnesses (OrchestrationReactor.test.ts,OrchestrationEngineHarness.integration.ts,ThreadSettlementReactor.test.ts), which are legitimate test seams. - Imports: Effect modules are imported as namespaces from their subpaths (
effect/Effect,effect/Layer,effect/Stream,effect/Crypto,effect/DateTime,effect/Schedule,effect/Cause);@t3tools/contractsuses named imports, which the conventions allow. - Errors:
GitManager.branchPullRequestfails with the existingGitManagerErrorcarryingoperation/cwd/detailand a message derived from those attributes; nodetailcopied from a cause, no new redundant discriminators or error-factory helpers. Sweep failures are logged withCause.prettywhile interrupts are re-raised. - Tests: server behavior changes are covered by focused tests (
ThreadSettlementReactor.test.ts,ThreadSettlementPolicy.test.ts,decider.settled.test.ts,ProviderCommandReactor.test.ts,GitManager.test.ts) using test layers rather than mocking core logic. - Client-side changes (
apps/web,apps/mobile,packages/client-runtime) are React/state code with no Effect service definitions; nothing to flag under this check.
🔍 Agent activity — 8 tool calls
💭 I'm looking at the new ThreadSettlementReactor service and layer files, checking whether they follow the existing Services/Layers split pattern already used by ThreadDeletionReactor, CheckpointReactor, and ProviderCommandReactor rather than the combined domain file convention. I notice a standalone
ThreadSettlementReactorShapeinterface, which conflicts with the guideline to define the service interface inline in theContext.Servicedeclaration and reference it asFoo["Service"]instead. I also want to verify whether the layer export nameThreadSettlementReactorLivematches existing conventions or should instead be the canonicallayerexport.
1. browse_code — apps/server/src/orchestration/Services/ThreadDeletionReactor.ts
2. browse_code — apps/server/src/orchestration/**/*.ts
💭 I notice the repo's existing pattern splits Services/Layers with a
Shapeinterface, but the check instructions call for a newer single-file convention with inline interfaces and alayerexport, taking priority over older code when they conflict. Since ThreadSettlementReactor is new code introduced in this PR, I'm weighing whether to apply the new canonical convention here rather than mimicking the older local style. Since every sibling reactor follows the same pattern, flagging this one file alone feels inconsistent with the codebase's actual conventions. Let me set that aside for now and check other angles instead — dependency acquisition, error handling, Layer.succeed usage, ManagedRuntime, and runPromise — by examining the new Layer file in full.
3. browse_code — apps/server/src/orchestration/Layers/ThreadSettlementReactor.ts
4. browse_code — apps/server/src/orchestration/Layers/ThreadDeletionReactor.ts
💭 Since the new reactor exactly copies the existing ThreadDeletionReactor pattern in the same directory, flagging it feels borderline given the "no unrelated cleanup" rule—but since the conventions doc is authoritative and this is new code in the PR, a reasonable reviewer might note it without necessarily failing the check. Now I'm scanning the rest of the diff for other issues: no misuse of Layer.succeed, ManagedRuntime, or runPromise here, and the mobile-side EnvironmentAutoSettleSwitch component looks fine using atoms normally. Checking GitManager.branchPullRequest's error construction, the
detailfield describes a genuine validation failure rather than just copying a cause message, so that seems acceptable—I want to verify against the GitManagerError class definition and how other operations format their errors to confirm this is the standard pattern. I also notice a spot usingEffect.diewith a plain untyped Error for a "linked pull request not found" case—using a defect for an invariant violation is reasonable, though it does lose some context that a typed error would preserve. Following up on that die call, I realize catchCause would still catch it and log a warning rather than crashing the sweep, but I'm second-guessing whether dying is the right call at all since a linked PR's project could legitimately be missing—that's more a behavioral question than a convention violation. Then I move through other files: PullRequestError types look fine, ThreadSettlementPolicy.ts is just pure helpers, and the new service still follows the expected split of Services/Layers with a Shape interface and a "...Live" layer export instead of a generic "layer" or "make" export, consistent with its siblings. Server wiring in server.ts looks fine, test harnesses using Layer.succeed as a legitimate seam are fine, and imports throughout use proper namespaced Effect subpaths, including the test file's use of @effect/vitest. I confirm the testing imports and the Crypto module usage both correctly pull dependencies from the environment rather than instantiating directly, and dependency acquisition overall looks environment-driven and correct. I glance at the mobile SettingsRouteScreen but it's not an Effect service so it's out of scope, and now I want to check whether the repo has a documented convention doc—like an internals guide or AGENTS.md—that explicitly endorses the Services/Layers split, since if it's documented as canonical then flagging it would be wrong.
5. git_tools — Services/|Layers/
6. git_tools — Context.Service
💭 I'm noting that while newer modules are single-file, the orchestration folder still uses the legacy Services/Layers split, so a new service built in that older pattern could be a plausible violation worth flagging against the migration guidance. This looks like a feature PR introducing ThreadSettlementReactor as a new service following the legacy split pattern, which conflicts with the canonical convention. I'm weighing whether to flag it with a suggestion to collapse it into a single domain file with an inline interface and layer export, since the resulting import updates across OrchestrationReactor, server.ts, tests, and the harness would be mechanical rather than disruptive. I also want to double-check ServerSettingsService's interface methods and how ExecutionEnvironmentCapabilities is used, though those seem unrelated to the convention question. Other candidate issues I want to check: the new GitManagerError construction in branchPullRequest to see if its detail field matches existing usage patterns; an untyped Effect.die with a bare Error message that loses domain context like thread or project id, though it's a defect rather than a typed service error so it's a marginal case; whether ThreadSettlementReactor's make function should be exported given the sibling ThreadDeletionReactor also keeps it private; and reviewing GitManagerError's definition to confirm the new error message and cause handling align with conventions.
7. git_tools — class GitManagerError|GitManagerServiceError|Schema.TaggedErrorClass
💭 The GitManager error handling looks consistent with existing conventions, so that's fine. I'm now weighing whether the new ThreadSettlementReactor service, split across Services and Layers with a standalone Shape interface and a Live export instead of the usual layer/make pattern, actually counts as a clear convention violation worth flagging, and whether it falls within scope given the instructions about pull requests that create, move, or refactor code. Given the conventions explicitly prohibit standalone Shape interfaces and require the canonical single-module layout with make/layer, I've decided this qualifies. I'll draft a single inline comment on the new file recommending it be consolidated into the orchestration directory, with the interface inlined into the Context.Service declaration and proper make/layer exports, and I'm leaning toward failing the check since this is a precise, well-founded violation rather than unrelated cleanup. I'm now double-checking whether flagging this is correct given the instruction to defer to conventions even when existing code differs — since the file is essentially copied boilerplate from another reactor, a reviewer following the stated rules would catch this, so I feel confident it's the intended finding. I'm also examining a second potential issue: how PullRequestService is imported, checking whether it should follow the namespace-import pattern the conventions describe for service boundaries versus the named-import style already used throughout the codebase. I decide the namespace rule only applies when accessing make/layer members through aliased imports, not plain tag imports like this one, so I won't flag it since sibling files follow the same pattern. I note a minor point about the tag string identifier potentially needing to change if the module moves, and confirm the effect type signature looks fine. I also verify that the Layers file references the shape via a standalone type rather than through the service's Service property, which is exactly the pattern the convention wants replaced. I'm settling on posting a single review comment on the new Services file, targeting the interface lines, and starting to draft the suggested wording for that comment.
8. modify_pr — Reviewed the new ThreadSettlementReactor service and its consumers against the Effect service conventions. One finding: the new service is defined in the legacy Services/ + Layers/ split with a standalone Shape interface and a *Live layer export. Everything else (dependency acquisition from the environment, namespaced effect/* subpath imports, Layer.succeed/Layer.mock only in test harnesses, no ManagedRuntime/runPromise in service code, error construction in GitManager.branchPullRequest) matches the conventions.
Agent Credits: 145 credits
Token usage: 12 uncached input · 531,562 cache-read input · 146,199 cache-write input · 7,830 output
Agent Credits may also include non-token charges from external tools such as web research.