Skip to content

fix(server): normalize cache keys and add consistency test for stable…

MacroscopeApp / Macroscope - Effect Service Conventions failed Jul 30, 2026 in 1m 46s

Effect Service Conventions: 1 issue found

  • apps/server/src/vcs/GitVcsDriverCore.test.ts (new test, lines 156-173): the added case asserts only that two consecutive statusDetailsLocal calls on a fresh repo agree, which holds with or without the new caches. The changed backend behavior (5-minute defaultBranch / hasOriginRemote caching plus the invalidateStatusStaticCaches hook in withListRefsInvalidation) is therefore still untested, contrary to the change-discipline rule that behavior changes require focused tests.

Resolved since the previous run: both new caches now key on normalizeRepositoryPathsCacheKey(cwd), matching the module's other path-keyed caches, so Cache.get in readStatusDetailsLocal and invalidateStatusStaticCaches cannot diverge on differently spelled paths.

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 examined: apps/server/src/vcs/GitVcsDriverCore.ts, apps/server/src/vcs/GitVcsDriverCore.test.ts.

Convention checks with no findings:

  • Imports remain subpath namespace imports (import * as Cache from "effect/Cache", Duration, Effect) and the local service module is used as GitVcsDriver.GitVcsDriver / GitVcsDriver.layer.
  • No new service definition, tag, make, or layer was introduced; the change is internal to makeGitVcsDriverCore.
  • No new Layer.succeed implementation, ManagedRuntime.make, runPromise/runPromiseExit, or service-instance parameter was added; dependencies are still acquired from the Effect environment.
  • Error handling is unchanged: the removed inline symbolic-ref call is replaced by the existing resolveDefaultBranchName/originRemoteExists helpers, and failures are still absorbed with Effect.orElseSucceed, matching the prior defaultRefResult.exitCode fallback semantics. No new error classes, discriminators, or catchIf/catchTag usage.
  • No files moved or re-export shims added.

Suggested coverage for the flagged gap: populate the caches with a statusDetailsLocal call, add origin via driver.ensureRemote (which is wrapped in withListRefsInvalidation), and assert the next statusDetailsLocal observes hasOriginRemote: true; optionally add a raw driver.execute(["remote", "add", ...]) variant that only becomes visible after TestClock.adjust("5 minutes") to pin the TTL.


🔍 Agent activity — 1 tool call

💭 Looking at the code changes to see if the previous issues have been resolved—it looks like normalizeRepositoryPathsCacheKey is now being used for cache keys and there's a new test in place, so both concerns appear to be addressed. The prior issues seem resolved with normalized keys and a new test, though I'm noticing that initRepoWithListRefsInvalidation doesn't clear the status static caches. This could mean if statusDetails gets called before the repo is initialized, the defaultBranchCache might hold onto a null value for five minutes. I'm wondering if this actually violates the Effect service conventions the check is looking for, but since a test was added to cover the backend behavior change, that should satisfy the requirements. Looking at the test more carefully though—it only verifies that repeated calls return consistent results, not that invalidation actually works. The earlier feedback asked for a case showing that a mutating operation wrapped in withListRefsInvalidation makes the next statusDetails call see the new state. The test covers the caching part but not the invalidation part, so it's a partial fix. I could re-flag this, but the code did change in response to what I noted, so it's a judgment call whether to push back on the incomplete coverage. There's also the underlying issue that the initRepo path invalidates the repository caches and listRefs, but not the status static caches—so a stale hasOriginRemote=false or defaultBranch=null could linger for five minutes after initialization or adding a remote. I need to check whether initRepo actually adds an origin remote, and whether withListRefsInvalidation wraps the relevant mutating operations like ensureRemote or addRemote. I'm checking whether the new approach using resolveDefaultBranchName(cwd, "origin") produces the same result as the previous method that read from symbolic-ref refs/remotes/origin/HEAD. Let me look at what resolveDefaultBranchName actually does to verify they're equivalent. Looking at the conventions being used here — Cache.makeWith, Cache.invalidate, and Effect.gen all align with the module's style, and the imports should be consistent with import * as Cache from "effect/Cache". But there's a correctness issue I'm noticing: initRepoWithListRefsInvalidation isn't invalidating the new status caches, which means stale cached values from a previous initRepo call could persist for the default branch and origin status. Though actually, for non-repo paths, statusDetails returns early before touching the caches, so they only get populated for real repositories. The real question is whether this violates the conventions being checked — the listed conventions cover imports, service definition, dependency acquisition, errors, and layout, but caching correctness isn't explicitly listed except for the requirement that behavior changes need focused tests. A test was added, but it only verifies consistency across calls rather than actually testing the invalidation behavior itself. The prior feedback flagged two issues: cache key normalization (which was fixed) and missing tests for the behavior change (a test was added but doesn't exercise cache invalidation). Since the code did change in response to the original comment, I can re-flag that the test doesn't actually validate the caching mechanism. Let me look at the imports and test file to make sure I'm not missing anything. Looking at the Effect service conventions, the code follows proper namespace imports and uses the Cache module correctly without affecting error handling. However, there's a test coverage gap: the new test doesn't actually validate the caching and invalidation behavior since two consecutive statusDetailsLocal calls in a fresh repo would return identical results regardless of whether caching is implemented. The real risk is that backend behavior changes—like adding a git remote add operation—could break things without focused tests catching it. The real issue is that the added test doesn't actually exercise cache staleness or invalidation behavior—it passes regardless of whether the caching logic exists. That's a concrete violation of the change discipline convention: when backend behavior changes (like the 5-minute caching of default branch and origin existence), the tests should verify that behavior fails without the change. I should flag this with a specific suggestion to use TestClock or test the invalidation path, and also note the initRepo gap where cache invalidation isn't called. I'm weighing whether this test gap is significant enough to fail the check. The new test doesn't actually verify the behavior that changed, which is a genuine gap in coverage for a required convention. I'm leaning toward setting this as a failure since it's a substantive finding, though I'm being cautious about whether the severity justifies it. Now I need to write the review comment targeting the new test in GitVcsDriverCore.test.ts. The test just asserts that two calls return the same value, but that assertion would pass regardless of whether the caching or invalidation logic is working. I should suggest a more targeted test that actually exercises the new behavior—something that verifies the cache invalidation hook fires when adding a remote and that subsequent calls reflect the updated state.

1. modify_pr — One finding: the new backend caching behavior (5-minute defaultBranch / hasOriginRemote caches plus the withListRefsInvalidation hook) is still not covered by a test that would fail without the change. Cache-key normalization from the previous review is resolved.


Agent Credits: 89 credits