Skip to content

fix(desktop): harden interrupted update recovery

MacroscopeApp / Macroscope - Effect Service Conventions failed Aug 23, 2026 in 1m 51s

Effect Service Conventions: 1 issue found

  • apps/desktop/src/window/DesktopTray.ts: DesktopTrayConfigurationError declares a single-value stage: Schema.Literal("setup") discriminator (mirrored in its log annotation) that duplicates the distinction already carried by the error tag. Drop the redundant singleton field and keep cause.

Previously flagged items on this PR (unstructured tray/updater warning payloads) are now resolved: both sites construct a tagged error and log errorTag/action.

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.

Files reviewed in scope: apps/desktop/src/window/DesktopTray.ts (new), apps/desktop/src/window/DesktopWindow.ts, apps/desktop/src/app/DesktopLifecycle.ts, apps/desktop/src/app/DesktopApp.ts, apps/desktop/src/updates/DesktopUpdates.ts, apps/desktop/src/main.ts, plus the touched test harnesses.

Checked and found conforming:

  • Namespace subpath imports (effect/Effect, effect/Layer, ...) and local service namespace imports (DesktopTray.DesktopTray, DesktopTray.layer).
  • Canonical module order: errors, Context.Service tag with inline interface, make, layer; single canonical module per service.
  • Dependencies acquired via yield* Foo.Foo in DesktopTray.make; no service-instance parameters in production code (service objects appear only in test layers).
  • Effect.runPromiseWith(context) is confined to the Electron tray/menu native-callback boundary, matching the existing DesktopApplicationMenu.ts adapter; it is not consumed by another Effect service.
  • Effect.catchTags usage in DesktopUpdates.ts unchanged and correct; new recovery paths log errorTag/action with only bounded, safe annotations and preserve the real cause.
  • Direct electron namespace usage inside DesktopTray.ts follows the existing precedent in DesktopWindow.ts, so it was not flagged.
  • New tests accompany real behavior changes (tray background mode, close-to-hide, install recovery), which the change-discipline rules require rather than prohibit.

🔍 Agent activity — 6 tool calls

💭 I'm checking whether the two issues flagged in the prior review at commit ad85aa1 were resolved in the new head commit f03da70. Looking at DesktopTray.ts, the logTrayWarning function now includes errorTag/action, which seems to address one issue, and I'm checking DesktopUpdates.ts to see how recoverInstallAction constructs its error object. Now I'm scanning for new violations. First I'm considering whether DesktopTray.ts using Effect.runPromiseWith inside a service constructor crosses a runtime boundary improperly, but since tray click handlers are native Electron callbacks, that likely counts as an allowed application-framework boundary — I want to check if DesktopApplicationMenu.ts follows the same pattern. Second, I'm flagging that DesktopTrayConfigurationError uses a single-value literal for its stage field, which looks redundant given the error already has a specific tag, so that's a likely finding worth reporting. Meanwhile DesktopTrayActionError's fields look fine since it combines a string with a cause rather than duplicating a single-value discriminator. I want to grep the repo for similar single-literal stage patterns elsewhere to see if this is an established convention I'd be flagging inconsistently, and also double check that the catchCause handling on configure, which downgrades failures to a warning, is appropriate before moving on to compare against DesktopApplicationMenu.ts.

1. browse_code — apps/desktop/src/window/DesktopTray.ts

2. browse_code — apps/desktop/src/window/DesktopApplicationMenu.ts

💭 The tray module largely mirrors DesktopApplicationMenu with prior comments addressed. I'm flagging one remaining issue: DesktopTrayConfigurationError has a stage: Schema.Literal("setup") field that's redundant since it's a single-value literal duplicating what the error tag already conveys, and its message isn't derived from actual attributes—violating the convention against double-encoding the same distinction in both a specific tag and a singleton phase field. I want to verify whether this pattern exists elsewhere in the repo before treating it as a clear violation. Checking DesktopUpdates.ts, I see similar "stage" values used as log annotations rather than as fields on an error object, which is a different (acceptable) pattern, and the existing DesktopUpdateUnexpectedActionError looks fine as legacy code. Also worth checking DesktopTray's use of runPromiseWith — that mirrors a sibling pattern as an allowed native callback boundary, and DesktopWindow's new synchronous mutators are contained within the service's own closure with documentation explaining why they're synchronous, so no hidden mutable state concern there. Now I'm searching for other instances of single-value stage literals like Schema.Literal("setup") to confirm whether this is truly a new violation.

3. git_tools — stage: Schema.Literal(

💭 This looks like a new occurrence introduced in this PR, so I should flag it. Let me also check the current code around recoverInstallAction in DesktopUpdates.ts to see if there are other convention issues, like how errors are constructed and logged there.

4. browse_code — apps/desktop/src/updates/DesktopUpdates.ts

💭 I'm checking for circular dependency risk between DesktopUpdates and DesktopWindow, but it looks like DesktopWindow doesn't import DesktopUpdates, so that's fine. I'm also noting that DesktopTray's test mocks Electron directly and instantiates Tray within the service rather than through a wrapper, which I want to check against how the repo typically structures Electron abstractions.

5. git_tools — from "electron"

💭 DesktopWindow.ts already imports electron directly, so that precedent means I won't flag this pattern elsewhere. The real issue is the redundant "setup" literal discriminator in DesktopTrayConfigurationError alongside the log annotation duplicating error.stage—that's a genuine convention violation worth weighing whether it rises to a failing issue. I want to check if that stage field existed at the earlier commit or is newly introduced, though it likely doesn't change my decision either way. I'll draft an inline suggestion targeting the field definition and separately note the redundant log annotation needs removal too, since a single inline suggestion can't span both non-contiguous locations cleanly.

6. modify_pr — One finding on the new tray service: DesktopTrayConfigurationError carries a single-value stage literal that duplicates the information already in the error tag. Everything else (namespace imports, Context.Service + inline interface, make/layer ordering, dependency acquisition via yield*, and the native-callback runPromiseWith boundary mirroring DesktopApplicationMenu.ts) matches the conventions.


Agent Credits: 59 credits