Skip to content

fix(server): skip subprocess poll tick when process snapshot is unusable

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

Effect Service Conventions: 1 issue found

  • apps/server/src/terminal/Manager.ts (lines 620-630): snapshotFailure manufactures a synthetic Error solely to populate cause and encodes the snapshot verdict (code, timedOut, stdoutTruncated) inside that string instead of as structural attributes on TerminalSubprocessCheckError. Model the context as fields on the error class and derive message from them; cause should carry only the real spawn failure. With structural fields in place the helper is a bare error construction and can be inlined at the two failure boundaries.

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/terminal/Manager.ts and apps/server/src/terminal/Manager.test.ts.

Checked and found compliant:

  • Namespace subpath imports for Effect modules; import { ChildProcessSpawner } from "effect/unstable/process" in the test matches the established repo-wide pattern for that package subpath.
  • TerminalSubprocessCheckError remains a Schema.TaggedErrorClass with a message derived from its attributes; the command discriminator has multiple values, so it is not a redundant singleton, and removing terminalPid is consistent with the snapshot now being process-table wide rather than per terminal.
  • Dependency acquisition: posixProcessTableSnapshot, windowsProcessTableSnapshot, and resolvePosixPsCommand acquire ProcessRunner.ProcessRunner / FileSystem.FileSystem from the environment and expose those requirements in their types; no ManagedRuntime.make, runPromise, runPromiseExit, or new Layer.succeed implementations were introduced. options.subprocessInspector remains a test seam.
  • Effect.catch in pollSubprocessActivity intentionally handles the whole error channel, so catchTags is not required; logged annotations stay bounded and do not copy command output.
  • The new tests cover a real behavior change (shared snapshot, non-authoritative failed snapshot), so they are not tests added solely for a mechanical refactor.

🔍 Agent activity — 1 tool call

💭 Looking at the changed file, I'm evaluating whether the error class conventions are being followed. The TerminalSubprocessCheckError removes the terminalPid field and derives the message from command alone, which acts as a discriminator between powershell and ps. The snapshotFailure helper seems to be building an error object, though the thought cuts off before I can fully assess whether it violates the guideline about not creating helpers that just wrap error construction.… Looking at whether snapshotFailure violates conventions — it's a helper that constructs an error with a formatted message and encodes structural data like exit codes and timeouts into the message string rather than as proper attributes. This runs counter to the principle of not creating helpers that just wrap error construction, and also conflicts with the guidance against manufacturing errors solely to populate a cause field. The fix is straightforward: add exitCode, timedOut, and truncated as actual fields on TerminalSubprocessCheckError instead of embedding them in a fabricated error message. On the imports side, the test file pulls ChildProcessSpawner as a named import from "effect/unstable/process", but the convention expects subpath imports to come in as namespaces — so it should be import * as UnstableProcess from "effect/unstable/process" and then reference it as UnstableProcess.ChildProcessSpawner.… The test imports look standard across the codebase, so that's fine. The real issue is how snapshotFailure is creating an Error object just to use as a cause, which violates the principle of not manufacturing errors for that purpose. Instead, I should be capturing the actual domain context—like the operation or stage—in a normalized, serializable way.… So Effect.catch properly handles the entire channel, which is acceptable. The error being logged is the actual error object, and its cause is a synthetic Error with exit code information—following the convention of keeping direct error attributes safe without copying raw wire data or command arguments. The only real issue I'm seeing is that snapshotFailure creates a fabricated Error cause with an unstructured message, and I'm weighing whether that's a clear enough convention violation to warrant failing the check. The convention explicitly forbids manufacturing an Error just to populate cause, and says to capture context as structural attributes instead. Yeah, I think I should flag this with an inline comment. The fix would involve adding fields to the error class and removing the fabricated cause—that's a multi-hunk change across the same file, so I'll describe it rather than provide a diff. I'm also considering whether the helper function itself should be removed since it only wraps the error construction, but it's used twice and builds the message, so that's worth thinking through once the class gets proper fields. Now I need to figure out the diff line numbers in…

1. modify_pr — One convention finding on the new snapshot failure path in apps/server/src/terminal/Manager.ts: the snapshot failure is modeled by fabricating an Error whose message carries the structural context, instead of putting that context on TerminalSubprocessCheckError as attributes.


Agent Credits: 66 credits