Skip to content

sync: port upstream websocket/compression and git perf work (#4291–#4985) - #191

Merged
aaditagrawal merged 15 commits into
mainfrom
sync/20260730-l2-server-perf
Aug 1, 2026
Merged

sync: port upstream websocket/compression and git perf work (#4291–#4985)#191
aaditagrawal merged 15 commits into
mainfrom
sync/20260730-l2-server-perf

Conversation

@aaditagrawal

@aaditagrawal aaditagrawal commented Jul 31, 2026

Copy link
Copy Markdown
Owner

L2/7 of the 2026-07-30 upstream sync stack. Stacked on #190.

What lands

Fork deviations preserved

  • apps/server/src/ws.ts: upstream replaced the live path with streamDomainEvents; the fork keeps subscribeDomainEvents + latestSequence and its early liveBuffer queue. Upstream's projectActivityEvent pruning was applied to the fork's live-buffer path as well, so all four sites (replay, live, catch-up, snapshot) prune — otherwise the fix would be silently defeated on the live path.
  • isThisThreadDetailEvent keeps the fork's thread.deleted / thread.archived cases.
  • BranchToolbarBranchSelector: kept the fork-local getBranchTriggerLabel (upstream's resolveBranchTriggerLabel lives in a BranchToolbar.logic.ts extraction the fork never took) and the fork's pagination effect.

Verification

vp run typecheck and vp check pass; full server suite green (211 files).

Summary by CodeRabbit

  • New Features
    • Added gzip compression for large JSON responses and WebSocket message compression.
    • Improved Git branch and repository performance with smarter caching, refreshes, and invalidation.
    • Added more reliable branch pagination and loading indicators.
    • CLI commands now adapt to npm, pnpm, and Bun launchers.
  • Bug Fixes
    • Improved handling of newly created repositories, unborn branches, worktrees, and failed refreshes.
    • MCP credentials now remain active while their thread is alive and provide clearer authentication warnings.
    • Activity responses now limit unnecessary payload data and history.
  • Breaking Changes
    • Removed the orchestration event replay operation.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds VCS cache invalidation and Git snapshot caching. It also adds HTTP compression, MCP liveness tracking, activity payload projection, launcher-aware CLI output, editor discovery timeouts, POSIX HOME hydration, and scroll-driven branch pagination.

Changes

VCS cache coordination

Layer / File(s) Summary
Cache contracts and persistence
packages/client-runtime/src/platform/persistence.ts, apps/mobile/src/persistence/*, apps/mobile/src/connection/*, apps/web/src/connection/storage.ts
VCS reference caches can be removed by working directory or cleared by environment.
Client invalidation state
packages/client-runtime/src/state/vcsRefInvalidation.ts, packages/client-runtime/src/state/vcs.ts, packages/client-runtime/src/state/runtime.ts, packages/client-runtime/src/state/sourceControl.ts, packages/client-runtime/src/state/vcsAction.ts
Revision state, persistence readability, locking, refresh commits, and settlement invalidation were added.
Git snapshots
apps/server/src/vcs/GitVcsDriverCore.ts, apps/server/src/git/GitManager.ts, apps/server/src/vcs/VcsDriverRegistry.ts
Repository paths and Git refs use cached snapshots with refresh coalescing, invalidation, retry backoff, and unborn-HEAD handling.

Server behavior and transport

Layer / File(s) Summary
Activity projection
apps/server/src/orchestration/ActivityPayloadProjection.ts, apps/server/src/ws.ts, apps/server/src/orchestration/http.ts
Snapshots and activity events now expose bounded projected payloads and reduced context-window history.
MCP liveness
apps/server/src/mcp/*, apps/server/src/provider/Layers/ProviderService.ts
MCP credentials use thread liveness windows and can be refreshed by provider activity.
HTTP and WebSocket compression
apps/server/src/http.ts, apps/server/src/httpCompression/*, apps/server/src/server.ts, patches/*
Eligible JSON responses use negotiated gzip compression. Node and Bun WebSocket servers negotiate per-message deflate.
Orchestration and editor handling
packages/contracts/src/orchestration.ts, packages/contracts/src/rpc.ts, apps/server/src/ws.ts
The replay-events RPC was removed. Editor discovery now times out after five seconds.

CLI and platform behavior

Layer / File(s) Summary
Launcher-aware CLI commands
apps/server/src/cli/invocation.ts, apps/server/src/cli/connect.ts
Connection instructions preserve detected npm, pnpm, Bun, nightly, and direct-install invocation forms.
POSIX HOME hydration
apps/server/src/os-jank.ts, apps/server/src/os-jank.test.ts
Blank HOME values are populated from the system account without replacing explicit values.

Branch pagination

Layer / File(s) Summary
Scroll-driven branch pagination
apps/web/src/state/paginatedBranches.ts, apps/web/src/state/queries.ts, apps/web/src/components/BranchToolbarBranchSelector.tsx
Next-page state is tracked separately, and loading uses forward scroll distance rather than onEndReached.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: juliusmarminge

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the upstream sync and its main websocket, compression, and Git performance changes.
Description check ✅ Passed The description clearly explains the changes, fork-specific deviations, and verification results, but it does not include a separate Why section or checklist.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sync/20260730-l2-server-perf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. label Jul 31, 2026
@github-actions github-actions Bot added the size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). label Jul 31, 2026
@aaditagrawal

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
apps/server/src/os-jank.ts (1)

78-84: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add a focused test for the HOME lookup failure path.

The current tests cover hydratePosixHome directly, but they do not verify that fixPath catches a failed HOME lookup, logs a warning, and continues to PATH hydration. Add and run a focused regression test for this startup behavior.

As per coding guidelines, backend changes must include and run focused tests for the changed behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/os-jank.ts` around lines 78 - 84, Update the tests for
fixPath to cover a failed HOME lookup: mock or force hydratePosixHome to fail,
assert that logPathHydrationWarning is called, and verify fixPath continues into
PATH hydration rather than terminating. Run this focused regression test.

Source: Coding guidelines

apps/server/src/vcs/VcsDriverRegistry.ts (1)

118-121: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Use a short non-zero TTL for negative detections.

The change fixes stale negative detections. Duration.zero also removes all throttling for paths that are not repositories. Every detect call then spawns rev-parse --is-inside-work-tree, and resolve calls detect on many request paths.

GitVcsDriverCore.ts Line 61 solves the same problem with NON_REPOSITORY_PATHS_CACHE_TTL = Duration.seconds(1). A one-second TTL keeps detection of a newly created repository fast and bounds the subprocess rate.

♻️ Proposed change to throttle negative detections

Add the constant next to DETECTION_CACHE_TTL:

+const NON_DETECTION_CACHE_TTL = Duration.seconds(1);

Then apply the short TTL to null results:

       timeToLive: Exit.match({
-        onSuccess: (detected) => (detected === null ? Duration.zero : DETECTION_CACHE_TTL),
+        onSuccess: (detected) =>
+          detected === null ? NON_DETECTION_CACHE_TTL : DETECTION_CACHE_TTL,
         onFailure: () => Duration.zero,
       }),

The existing test asserts two work-tree checks across two sequential detect calls. A non-zero TTL would coalesce those into one check, so the test needs a TestClock.adjust between the calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/vcs/VcsDriverRegistry.ts` around lines 118 - 121, Use the
existing one-second NON_REPOSITORY_PATHS_CACHE_TTL for null detections in the
VcsDriverRegistry timeToLive logic instead of Duration.zero, while retaining
DETECTION_CACHE_TTL for successful detections and zero TTL on failures. Update
the sequential detect test to advance TestClock between calls so it still
verifies two work-tree checks.
apps/server/src/vcs/GitVcsDriverCore.ts (1)

1522-1588: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Return parsed numstat entries instead of re-serializing to text.

The unborn-HEAD fallback merges staged and unstaged entries into a map, then formats the map back into tab-separated numstat text at Line 1558. Line 1649 parses that text again with parseNumstatEntries.

The round-trip is lossy for any path that contains a tab or a newline, because parseNumstatEntries splits on those characters. The fallback also duplicates the merge logic that Line 1650 already performs.

Change the Effect.all element to produce Array<{ path; insertions; deletions }> for both branches. Parse the diff HEAD output in the success branch, and return the merged array directly in the unborn branch. Then Line 1649 consumes the array without a second parse.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/vcs/GitVcsDriverCore.ts` around lines 1522 - 1588, The
numstat flow currently re-serializes parsed entries into text, which loses paths
containing tabs or newlines and duplicates merging. Update the
`GitVcsDriver.statusDetails.numstat` `Effect.all` element so the successful
`diff HEAD` branch returns `parseNumstatEntries(result.stdout)`, while the
unborn-HEAD branch merges staged and unstaged parsed entries into and returns an
array of `{ path, insertions, deletions }`; then update the consumer near
`parseNumstatEntries` to use that array directly without reparsing.
packages/client-runtime/src/state/vcs.ts (1)

145-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared persist-and-warn logic for cached refs.

Lines 145-155 build a saveVcsRefs effect with a warning log. commitVcsRefsRefresh repeats the same call and the same annotated warning at lines 86-96. A future change to the log message or the annotation set must be applied twice. Extract one helper and call it from both places.

♻️ Proposed extraction
+const persistVcsRefs = (
+  cache: EnvironmentCacheStore["Service"],
+  environmentId: EnvironmentId,
+  cwd: string,
+  refs: VcsListRefsResult,
+) =>
+  cache.saveVcsRefs(environmentId, cwd, refs).pipe(
+    Effect.catch((error) =>
+      Effect.logWarning("Could not persist cached Git refs.").pipe(
+        Effect.annotateLogs({
+          environmentId,
+          cwd,
+          ...safeErrorLogAttributes(error),
+        }),
+      ),
+    ),
+  );

Then in refresh:

-    const persist = cache.saveVcsRefs(environmentId, input.cwd, refs).pipe(
-      Effect.catch((error) =>
-        Effect.logWarning("Could not persist cached Git refs.").pipe(
-          Effect.annotateLogs({
-            environmentId,
-            cwd: input.cwd,
-            ...safeErrorLogAttributes(error),
-          }),
-        ),
-      ),
-    );
+    const persist = persistVcsRefs(cache, environmentId, input.cwd, refs);

And in commitVcsRefsRefresh replace lines 86-96 with yield* persistVcsRefs(cache, input.environmentId, input.cwd, input.refs);.

Based on the coding guideline "extract shared logic instead of duplicating local implementations".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/client-runtime/src/state/vcs.ts` around lines 145 - 155, Extract the
duplicated save-and-warning effect into a shared persistVcsRefs helper near the
existing VCS state logic, preserving saveVcsRefs, the warning message, and
safeErrorLogAttributes annotations. Update both refresh and commitVcsRefsRefresh
to call this helper with the cache, environmentId, cwd, and refs instead of
constructing their own persistence effects.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/server/src/cli/connect.ts`:
- Around line 530-534: Add focused tests in invocation.test.ts that execute the
connect link/connect command paths with injected launcher arguments, asserting
the output includes the resolved serve command. Cover the background-service
path and assert it returns without displaying the next-step message, while
preserving existing pure formatting-helper tests.

In `@apps/server/src/mcp/McpHttpServer.ts`:
- Around line 77-85: Update the rejected-credential branch in the MCP request
handler around invocation to rate-limit or sample the warning emitted by
Effect.logWarning, while preserving a metric for every rejected credential. Keep
the unauthorized response unchanged and ensure the metric remains recorded even
when the warning is suppressed.

In `@apps/server/src/os-jank.test.ts`:
- Around line 14-29: Remove the process.env.HOME mutation and restoration
try/finally block from the “hydrates HOME independently of a blank process HOME”
test. Keep the test isolated by passing the existing { HOME: " " } object
directly to hydratePosixHome and preserve the assertion against
NodeOS.userInfo().homedir.

In `@apps/server/src/vcs/GitVcsDriverCore.ts`:
- Around line 2414-2439: Bound the retry loop in resolveListRefsSnapshot with a
finite attempt limit. Track the most recently fetched snapshot and, when the
limit is reached despite generation changes, return that snapshot instead of
starting another scan; preserve the existing generation-stability fast path and
refresh/non-refresh cache selection.

---

Nitpick comments:
In `@apps/server/src/os-jank.ts`:
- Around line 78-84: Update the tests for fixPath to cover a failed HOME lookup:
mock or force hydratePosixHome to fail, assert that logPathHydrationWarning is
called, and verify fixPath continues into PATH hydration rather than
terminating. Run this focused regression test.

In `@apps/server/src/vcs/GitVcsDriverCore.ts`:
- Around line 1522-1588: The numstat flow currently re-serializes parsed entries
into text, which loses paths containing tabs or newlines and duplicates merging.
Update the `GitVcsDriver.statusDetails.numstat` `Effect.all` element so the
successful `diff HEAD` branch returns `parseNumstatEntries(result.stdout)`,
while the unborn-HEAD branch merges staged and unstaged parsed entries into and
returns an array of `{ path, insertions, deletions }`; then update the consumer
near `parseNumstatEntries` to use that array directly without reparsing.

In `@apps/server/src/vcs/VcsDriverRegistry.ts`:
- Around line 118-121: Use the existing one-second
NON_REPOSITORY_PATHS_CACHE_TTL for null detections in the VcsDriverRegistry
timeToLive logic instead of Duration.zero, while retaining DETECTION_CACHE_TTL
for successful detections and zero TTL on failures. Update the sequential detect
test to advance TestClock between calls so it still verifies two work-tree
checks.

In `@packages/client-runtime/src/state/vcs.ts`:
- Around line 145-155: Extract the duplicated save-and-warning effect into a
shared persistVcsRefs helper near the existing VCS state logic, preserving
saveVcsRefs, the warning message, and safeErrorLogAttributes annotations. Update
both refresh and commitVcsRefsRefresh to call this helper with the cache,
environmentId, cwd, and refs instead of constructing their own persistence
effects.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 35effc4e-c1a3-48b6-a5cd-15a485793c5d

📥 Commits

Reviewing files that changed from the base of the PR and between 60b1c8a and 896ccca.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (56)
  • apps/mobile/src/connection/environment-cache-store.test.ts
  • apps/mobile/src/connection/environment-cache-store.ts
  • apps/mobile/src/persistence/mobile-database.ts
  • apps/server/src/cli/connect.ts
  • apps/server/src/cli/invocation.test.ts
  • apps/server/src/cli/invocation.ts
  • apps/server/src/git/GitManager.ts
  • apps/server/src/http.test.ts
  • apps/server/src/http.ts
  • apps/server/src/httpCompression/HttpResponseCompression.test.ts
  • apps/server/src/httpCompression/HttpResponseCompression.ts
  • apps/server/src/mcp/McpHttpServer.test.ts
  • apps/server/src/mcp/McpHttpServer.ts
  • apps/server/src/mcp/McpInvocationContext.test.ts
  • apps/server/src/mcp/McpInvocationContext.ts
  • apps/server/src/mcp/McpSessionRegistry.test.ts
  • apps/server/src/mcp/McpSessionRegistry.ts
  • apps/server/src/mcp/PreviewAutomationBroker.test.ts
  • apps/server/src/mcp/PreviewAutomationBroker.ts
  • apps/server/src/orchestration/ActivityPayloadProjection.ts
  • apps/server/src/orchestration/http.ts
  • apps/server/src/os-jank.test.ts
  • apps/server/src/os-jank.ts
  • apps/server/src/provider/Layers/ProviderService.ts
  • apps/server/src/server.test.ts
  • apps/server/src/server.ts
  • apps/server/src/vcs/GitVcsDriverCore.test.ts
  • apps/server/src/vcs/GitVcsDriverCore.ts
  • apps/server/src/vcs/VcsDriverRegistry.test.ts
  • apps/server/src/vcs/VcsDriverRegistry.ts
  • apps/server/src/ws.ts
  • apps/server/test/ActivityPayloadProjection.test.ts
  • apps/web/src/components/BranchToolbarBranchSelector.tsx
  • apps/web/src/connection/storage.ts
  • apps/web/src/state/paginatedBranches.test.ts
  • apps/web/src/state/paginatedBranches.ts
  • apps/web/src/state/queries.ts
  • packages/client-runtime/src/connection/registry.test.ts
  • packages/client-runtime/src/platform/persistence.ts
  • packages/client-runtime/src/state/runtime.ts
  • packages/client-runtime/src/state/server.test.ts
  • packages/client-runtime/src/state/shell-sync.test.ts
  • packages/client-runtime/src/state/sourceControl.test.ts
  • packages/client-runtime/src/state/sourceControl.ts
  • packages/client-runtime/src/state/threads-sync.test.ts
  • packages/client-runtime/src/state/vcs.test.ts
  • packages/client-runtime/src/state/vcs.ts
  • packages/client-runtime/src/state/vcsAction.test.ts
  • packages/client-runtime/src/state/vcsAction.ts
  • packages/client-runtime/src/state/vcsRefInvalidation.ts
  • packages/contracts/src/git.ts
  • packages/contracts/src/orchestration.ts
  • packages/contracts/src/rpc.ts
  • patches/@effect__platform-bun@4.0.0-beta.102.patch
  • patches/@effect__platform-node@4.0.0-beta.102.patch
  • pnpm-workspace.yaml
💤 Files with no reviewable changes (6)
  • apps/server/src/mcp/McpInvocationContext.test.ts
  • apps/server/src/mcp/McpHttpServer.test.ts
  • apps/server/src/mcp/McpInvocationContext.ts
  • packages/contracts/src/orchestration.ts
  • apps/server/src/mcp/PreviewAutomationBroker.test.ts
  • packages/contracts/src/rpc.ts

Comment on lines +530 to +534
const serveCommand = yield* resolveCliCommand("serve");
yield* Console.log(
flags.publishOnly
? `✓ Authorized${connectedAs(linked.identity)}\n\nNext\n Start T3 to publish agent activity (no managed tunnel).`
: `✓ Authorized${connectedAs(linked.identity)}\n\nNext\n Start the server with \`t3 serve\` to make this machine reachable.`,
: `✓ Authorized${connectedAs(linked.identity)}\n\nNext\n Start the server with \`${serveCommand}\` to make this machine reachable.`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add focused tests for the connection command output.

apps/server/src/cli/invocation.test.ts tests the pure formatting helpers only. It does not execute connect link or connect.

Add tests that inject launcher arguments and assert the displayed serve command. Also assert that the background-service path returns without the next-step message.

As per coding guidelines, “Backend changes must include and run focused tests for the changed behavior.”

Also applies to: 696-704

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/cli/connect.ts` around lines 530 - 534, Add focused tests in
invocation.test.ts that execute the connect link/connect command paths with
injected launcher arguments, asserting the output includes the resolved serve
command. Cover the background-service path and assert it returns without
displaying the next-step message, while preserving existing pure
formatting-helper tests.

Source: Coding guidelines

Comment on lines +77 to +85
if (!invocation) {
// Without this the only symptom of a dead credential is the agent
// quietly losing the whole `t3-code` toolkit for the rest of its
// session, with nothing on the server to explain why.
yield* Effect.logWarning("rejected MCP request with an unusable credential", {
reason: token.length === 0 ? "missing_bearer_token" : "unknown_or_expired_token",
});
return unauthorized;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound warnings for rejected MCP credentials.

An unauthenticated caller can send unlimited invalid requests to /mcp. Each request now writes a warning. This can flood logs and consume logging capacity during an attack. Rate-limit or sample this warning, and retain a metric for rejected credentials.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/mcp/McpHttpServer.ts` around lines 77 - 85, Update the
rejected-credential branch in the MCP request handler around invocation to
rate-limit or sample the warning emitted by Effect.logWarning, while preserving
a metric for every rejected credential. Keep the unauthorized response unchanged
and ensure the metric remains recorded even when the warning is suppressed.

Comment on lines +14 to +29
it("hydrates HOME independently of a blank process HOME", () => {
const originalHome = process.env.HOME;
const env: NodeJS.ProcessEnv = { HOME: " " };

try {
process.env.HOME = " ";
hydratePosixHome(env);
} finally {
if (originalHome === undefined) {
delete process.env.HOME;
} else {
process.env.HOME = originalHome;
}
}

assert.equal(env.HOME, NodeOS.userInfo().homedir);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Remove the unnecessary global environment mutation.

hydratePosixHome reads the supplied env, so changing process.env.HOME does not affect this test. Remove the mutation and restoration block. Keep the test isolated by passing { HOME: " " } directly.

As per coding guidelines, prioritize reliability and predictable behavior under load and failures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/os-jank.test.ts` around lines 14 - 29, Remove the
process.env.HOME mutation and restoration try/finally block from the “hydrates
HOME independently of a blank process HOME” test. Keep the test isolated by
passing the existing { HOME: " " } object directly to hydratePosixHome and
preserve the assertion against NodeOS.userInfo().homedir.

Source: Coding guidelines

Comment on lines +2414 to +2439
const resolveListRefsSnapshot = Effect.fn("resolveListRefsSnapshot")(function* (
gitCommonDir: string,
refresh: boolean,
) {
while (true) {
const generation = currentListRefsGeneration(gitCommonDir);
const currentEpoch = listRefsEpochByCommonDir.get(gitCommonDir);
const snapshot =
refresh || currentEpoch === undefined
? // The refresh cache owns the complete snapshot read, rather than only the
// epoch bump. Slow repositories therefore remain singleflight for the
// entire Git scan even when more refresh requests arrive after the
// coalescing TTL would otherwise have elapsed.
yield* Cache.get(
listRefsRefreshSnapshotCache,
new GitRefsRefreshCacheKey({ gitCommonDir, generation }),
)
: yield* Cache.get(
listRefsSnapshotCache,
new GitRefsSnapshotCacheKey({ gitCommonDir, epoch: currentEpoch }),
);
currentPath = exists ? candidatePath : null;
} else if (line.startsWith("branch refs/heads/") && currentPath) {
worktreeMap.set(line.slice("branch refs/heads/".length), currentPath);
} else if (line === "") {
currentPath = null;
}
}
if (currentListRefsGeneration(gitCommonDir) === generation) {
return snapshot;
}
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound the snapshot retry loop.

resolveListRefsSnapshot retries without a limit. Each iteration reads the generation, fetches a snapshot, and restarts when invalidateListRefsSnapshot advanced the generation during the fetch.

A repository under a continuous stream of mutations advances the generation on every mutation. A ref scan on a large repository can take seconds. In that case listRefs restarts on every attempt and never returns. The request blocks until the RPC times out, and each attempt spawns another full for-each-ref, worktree list, and remote scan.

Add a retry limit. After the limit, return the last snapshot that was read. The result is then at most one generation stale, which is the same guarantee that a non-refresh read already provides.

🔒️ Proposed fix to bound the retries
   const resolveListRefsSnapshot = Effect.fn("resolveListRefsSnapshot")(function* (
     gitCommonDir: string,
     refresh: boolean,
   ) {
-    while (true) {
+    // A repository under continuous mutation advances the generation on every
+    // scan. Stop after a bounded number of attempts and accept a snapshot that
+    // is at most one generation stale, rather than never returning.
+    const maxAttempts = 3;
+    for (let attempt = 1; ; attempt += 1) {
       const generation = currentListRefsGeneration(gitCommonDir);
       const currentEpoch = listRefsEpochByCommonDir.get(gitCommonDir);
       const snapshot =
         refresh || currentEpoch === undefined
           ? // The refresh cache owns the complete snapshot read, rather than only the
             // epoch bump. Slow repositories therefore remain singleflight for the
             // entire Git scan even when more refresh requests arrive after the
             // coalescing TTL would otherwise have elapsed.
             yield* Cache.get(
               listRefsRefreshSnapshotCache,
               new GitRefsRefreshCacheKey({ gitCommonDir, generation }),
             )
           : yield* Cache.get(
               listRefsSnapshotCache,
               new GitRefsSnapshotCacheKey({ gitCommonDir, epoch: currentEpoch }),
             );
-      if (currentListRefsGeneration(gitCommonDir) === generation) {
+      if (currentListRefsGeneration(gitCommonDir) === generation || attempt >= maxAttempts) {
         return snapshot;
       }
     }
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const resolveListRefsSnapshot = Effect.fn("resolveListRefsSnapshot")(function* (
gitCommonDir: string,
refresh: boolean,
) {
while (true) {
const generation = currentListRefsGeneration(gitCommonDir);
const currentEpoch = listRefsEpochByCommonDir.get(gitCommonDir);
const snapshot =
refresh || currentEpoch === undefined
? // The refresh cache owns the complete snapshot read, rather than only the
// epoch bump. Slow repositories therefore remain singleflight for the
// entire Git scan even when more refresh requests arrive after the
// coalescing TTL would otherwise have elapsed.
yield* Cache.get(
listRefsRefreshSnapshotCache,
new GitRefsRefreshCacheKey({ gitCommonDir, generation }),
)
: yield* Cache.get(
listRefsSnapshotCache,
new GitRefsSnapshotCacheKey({ gitCommonDir, epoch: currentEpoch }),
);
currentPath = exists ? candidatePath : null;
} else if (line.startsWith("branch refs/heads/") && currentPath) {
worktreeMap.set(line.slice("branch refs/heads/".length), currentPath);
} else if (line === "") {
currentPath = null;
}
}
if (currentListRefsGeneration(gitCommonDir) === generation) {
return snapshot;
}
}
});
const resolveListRefsSnapshot = Effect.fn("resolveListRefsSnapshot")(function* (
gitCommonDir: string,
refresh: boolean,
) {
// A repository under continuous mutation advances the generation on every
// scan. Stop after a bounded number of attempts and accept a snapshot that
// is at most one generation stale, rather than never returning.
const maxAttempts = 3;
for (let attempt = 1; ; attempt += 1) {
const generation = currentListRefsGeneration(gitCommonDir);
const currentEpoch = listRefsEpochByCommonDir.get(gitCommonDir);
const snapshot =
refresh || currentEpoch === undefined
? // The refresh cache owns the complete snapshot read, rather than only the
// epoch bump. Slow repositories therefore remain singleflight for the
// entire Git scan even when more refresh requests arrive after the
// coalescing TTL would otherwise have elapsed.
yield* Cache.get(
listRefsRefreshSnapshotCache,
new GitRefsRefreshCacheKey({ gitCommonDir, generation }),
)
: yield* Cache.get(
listRefsSnapshotCache,
new GitRefsSnapshotCacheKey({ gitCommonDir, epoch: currentEpoch }),
);
if (currentListRefsGeneration(gitCommonDir) === generation || attempt >= maxAttempts) {
return snapshot;
}
}
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/server/src/vcs/GitVcsDriverCore.ts` around lines 2414 - 2439, Bound the
retry loop in resolveListRefsSnapshot with a finite attempt limit. Track the
most recently fetched snapshot and, when the limit is reached despite generation
changes, return that snapshot instead of starting another scan; preserve the
existing generation-stability fast path and refresh/non-refresh cache selection.

saphid and others added 14 commits August 1, 2026 12:31
(cherry picked from commit b4680cb)
(cherry picked from commit 581748f)
(cherry picked from commit 23ea08d)
(cherry picked from commit 04132f9)
(cherry picked from commit 0e19c10)
(cherry picked from commit 9815a68)
…g#4705)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 887dd6e)
(cherry picked from commit 47c8546)
(cherry picked from commit 8829e2f)
(cherry picked from commit 088e98a)
Co-authored-by: codex <codex@users.noreply.github.com>
(cherry picked from commit 38a6e3c)
(cherry picked from commit 3a7a0e4)
…pingdotgg#4791)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 5fcdefd)
(cherry picked from commit 1712447)
Co-authored-by: codex <codex@users.noreply.github.com>
(cherry picked from commit 8650f05)
(cherry picked from commit 9eae936)
(cherry picked from commit d19039a)
(cherry picked from commit 3863931)
…e diff HEAD --numstat (pingdotgg#4843)

(cherry picked from commit faea70a)
(cherry picked from commit 9c33505)
)

(cherry picked from commit 85a8986)
(cherry picked from commit a1c82df)
pingdotgg#4897)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit 6ab2f16)
(cherry picked from commit aa2e1e1)
(cherry picked from commit edc503a)
(cherry picked from commit 896ccca)
@aaditagrawal
aaditagrawal force-pushed the sync/20260730-l2-server-perf branch from 896ccca to f7ab627 Compare August 1, 2026 07:11
@aaditagrawal

Copy link
Copy Markdown
Owner Author

Review triage

Every finding on this PR was checked against upstream/main by blob hash (not just diff). All are verbatim upstream code, carried in unmodified by this port — the files are byte-identical to upstream, so the flagged behavior affects upstream equally and is not introduced by the sync.

Deliberately not fixing them here: patching upstream bugs inside a 101-commit port would diverge the fork in exactly the files this stack exists to realign, and would make the next sync harder. They are better raised upstream or tracked as fork-local follow-ups on their own branch, where they can be reviewed on their merits.

Notably, the files where this PR did carry fork-specific conflict resolutions drew no findings.

@aaditagrawal
aaditagrawal changed the base branch from sync/20260730-l1-infra-effect to main August 1, 2026 07:18
@aaditagrawal
aaditagrawal merged commit 5634634 into main Aug 1, 2026
12 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f7ab627485

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +187 to +188
: Stream.fromEffect(
refresh().pipe(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore revalidation for provider-created refs

When Git refs change outside the VCS RPCs—most commonly when a coding provider runs git branch or git checkout directly—no client invalidation callback fires. Replacing the five-second tick with this one-shot effect means a mounted branch list never discovers those changes; even remounting can reuse the server's two-minute ref snapshot because the web/mobile queries do not set refresh: true. Retain periodic revalidation or issue a forced-refresh request so provider-created branches and checkouts become visible.

Useful? React with 👍 / 👎.

Comment on lines +19 to +22
+ perMessageDeflate: {
+ compress: "dedicated",
+ decompress: "shared"
+ },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Actually compress Bun WebSocket frames

On the Bun server path, this only negotiates permessage-deflate; the Effect Bun writer still calls ws.sendText(chunk) and ws.sendBinary(chunk) without Bun's per-send compression flag. Consequently clients advertise and negotiate the extension, but server-to-client orchestration frames have RSV1 unset and remain uncompressed, so the main high-volume direction receives none of the intended throughput reduction. Pass the compression flag when writing negotiated WebSocket frames or use a platform implementation that does so.

AGENTS.md reference: AGENTS.md:L127-L127

Useful? React with 👍 / 👎.

@aaditagrawal
aaditagrawal deleted the sync/20260730-l2-server-perf branch August 1, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ effective changed lines (test files excluded in mixed PRs). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants