Conversation
* fix(deploy): stamp build SHA into serverVersion to catch web/server drift (#1) Source-mode nodes (e.g. the RPi in #1) rebuild apps/web/dist only when someone explicitly runs the web build, separately from `git pull` restarting the server. Since serverVersion/APP_VERSION otherwise track package.json's semver (which doesn't bump per commit on this fork), a stale bundle can silently share a version string with a server that has moved on to a schema-incompatible commit — the existing client/server version-mismatch banner never fires, and the connection just dies with a generic SchemaError. - ServerBuildSha.resolveServerBuildSha resolves the server's own git HEAD SHA at runtime (via the existing ProcessRunner service) and ServerEnvironment suffixes it onto serverVersion when resolvable, falling back to the plain semver for packaged builds without a .git directory (desktop, HA add-on). - vite.config.ts stamps APP_VERSION with the checkout SHA the build ran from, unless an explicit APP_VERSION is provided (release builds). - platform.ts logs a warning (via the existing versionSkew comparison) as soon as the pre-flight environment descriptor is fetched over HTTP, before the WS RPC session is attempted — this is the earliest point a mismatch can be observed, since the WS handshake itself is what fails to decode when client/server drift. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(web): scope SHA-granularity version-mismatch checks to the primary connection The reviewer on #2 flagged a false-positive regression: stamping serverVersion with +git.<sha> made resolveVersionMismatch compare SHAs across every connected environment, not just the primary/local one. A packaged desktop build (no .git, plain semver) or any remote peer on a different commit now tripped the "version drift" banner even though both were perfectly healthy — exactly the multi-environment path the original issue's failure mode was reported on. resolveVersionMismatch/resolveServerConfigVersionMismatch now compare at release granularity by default (git build metadata stripped) and only opt into exact SHA comparison via `{ compareBuildMetadata: true }` for call sites that are provably the primary/same-origin connection: - ConnectionsSettings.tsx's primary banner (opts in) - ChatView.tsx's per-thread banner (opts in only when the active thread's environment is the primary one) - connection/platform.ts's pre-flight descriptor check (opts in — both its callers bootstrap a same-machine connection built from this client's own checkout) Saved/remote environment rows in ConnectionsSettings.tsx keep the new default (no option passed), matching pre-#1 semver-only behavior. Also addresses the review's two minor notes: dropped the redundant /i flag on the already-lowercased SHA regex (server and vite.config.ts), and gated vite.config.ts's git rev-parse spawn to `command === "build"` so dev/test invocations no longer spawn it on every run. --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
* fix(server): per-repo semaphore around git fetch + resolveRemoteTrackingCommit in worktree provisioning Concurrent worktree-provisioning dispatches for the same repo could race: a `git fetch` writing refs/remotes/* on one thread could interleave with `git rev-parse --verify refs/remotes/...` on another, failing with "fatal: Needed a single revision". Serialize fetch, resolveRemoteTrackingCommit, and worktree add per repo (keyed by gitCommonDir) so the same clone's git-prep never runs concurrently, while different repos keep provisioning in parallel. Fixes #3 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * test(server): assert cross-repo git-lock concurrency, not just per-repo max=1 Review on #5 flagged that the lock test only asserted maxActiveByRepo===1 per repo, which would also pass under a regressed single global lock - the "but not across repos" half of the test name was unverified. Track global concurrent guarded-subprocess count and assert it reaches 2, so a regression to one shared semaphore across repos fails the test. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Issue #9 wants a measured browser.state (ok/degraded/absent) in the /.well-known/t3/environment response instead of trusting declared config, since cc_runner's capability dispatch needs to detect drift. This test is red until BrowserCapabilityProbe lands.
cc_runner's capability-based dispatch (fzoll/cc_runner) demotes nodes whose declared config drifted from reality, so the public /.well-known/t3/environment descriptor now reports a measured capabilities.browser field instead of a config flag: - "ok": a Chromium binary was found (Playwright's downloaded browser cache is checked first, falling back to a system install) and it launched successfully. - "degraded": a binary was found but either it failed to launch, or only a system Chromium exists and the Playwright browser cache is missing/incomplete. - "absent": no Chromium binary could be found anywhere. The probe is lazy and cached for 6 hours (Effect.cachedWithTTL) so it never runs on every health-check request. Detection is filesystem/ process-based only (no playwright-core dependency added to apps/server); installation itself stays out of scope per the issue.
|
Opened against the wrong repo (upstream instead of the fork). Closing; correct PR opened against fzoll/t3code. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (14)
📝 WalkthroughWalkthroughThe PR adds browser capability detection, Git-based build metadata, version-skew handling, and per-repository Git operation locks. It updates server descriptors, web connection checks, build configuration, contracts, and related tests. ChangesEnvironment observability and version identity
Per-repository Git synchronization
Estimated code review effort: 4 (Complex) | ~45 minutes Change: Feature Sequence Diagram(s)sequenceDiagram
participant WebBuild
participant ServerEnvironment
participant ServerBuildSha
participant BrowserCapabilityProbe
participant WebClient
WebBuild->>ServerBuildSha: resolve git SHA during build
ServerEnvironment->>ServerBuildSha: resolveServerBuildSha()
ServerEnvironment->>BrowserCapabilityProbe: probe()
BrowserCapabilityProbe-->>ServerEnvironment: BrowserCapability
ServerEnvironment-->>WebClient: environment descriptor with serverVersion
WebClient->>WebClient: compare release and build metadata
Suggested reviewers: ✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Comment |
| "/Applications/Chromium.app/Contents/MacOS/Chromium", | ||
| ], | ||
| linux: [ | ||
| "/usr/bin/chromium", |
There was a problem hiding this comment.
🟡 Medium environment/BrowserCapabilityProbe.ts:31
On Ubuntu hosts using the Chromium Snap, the probe reports state: "absent" and incorrectly demotes the node when no Playwright cache or legacy /usr/bin/chromium wrapper exists. Add /snap/bin/chromium to the Linux system-binary candidates so the working browser is probed.
| "/usr/bin/chromium", | |
| "/snap/bin/chromium", | |
| "/usr/bin/chromium", |
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/environment/BrowserCapabilityProbe.ts around line 31:
On Ubuntu hosts using the Chromium Snap, the probe reports `state: "absent"` and incorrectly demotes the node when no Playwright cache or legacy `/usr/bin/chromium` wrapper exists. Add `/snap/bin/chromium` to the Linux system-binary candidates so the working browser is probed.
| path: Path.Path, | ||
| ): string { | ||
| const overridePath = env.PLAYWRIGHT_BROWSERS_PATH; | ||
| if (overridePath && overridePath !== "0") { |
There was a problem hiding this comment.
🟡 Medium environment/BrowserCapabilityProbe.ts:48
When PLAYWRIGHT_BROWSERS_PATH is set to "0" and the hermetic Chromium is the only browser available, this probe returns absent (or incorrectly degraded when a system Chromium exists), causing capability-based dispatch to demote the node. The condition at line 48 discards Playwright's hermetic-install marker and scans only the OS cache; resolve node_modules/playwright-core/.local-browsers for this mode as well.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/environment/BrowserCapabilityProbe.ts around line 48:
When `PLAYWRIGHT_BROWSERS_PATH` is set to `"0"` and the hermetic Chromium is the only browser available, this probe returns `absent` (or incorrectly `degraded` when a system Chromium exists), causing capability-based dispatch to demote the node. The condition at line 48 discards Playwright's hermetic-install marker and scans only the OS cache; resolve `node_modules/playwright-core/.local-browsers` for this mode as well.
There was a problem hiding this comment.
🟠 High
Status refreshes still mutate refs/remotes/* outside repoGitLocks, so a concurrent fetchRemoteForStatus can race with resolveRemoteTrackingCommit and reproduce the ref-read failure. Protect fetchRemoteForStatus with the same per-repository semaphore before running its fetch.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/vcs/GitVcsDriverCore.ts around line 991:
Status refreshes still mutate `refs/remotes/*` outside `repoGitLocks`, so a concurrent `fetchRemoteForStatus` can race with `resolveRemoteTrackingCommit` and reproduce the ref-read failure. Protect `fetchRemoteForStatus` with the same per-repository semaphore before running its `fetch`.
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR introduces a production browser-capability probe used for automated node demotion, changes version and Git concurrency behavior, and adds a static-analysis suppression directive. Unresolved detection gaps and a remaining Git ref-race risk further warrant human validation. Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
Summary
Adds a measured
capabilities.browserfield to the public/.well-known/t3/environmentdescriptor so cc_runner's capability-based dispatch can demote nodes whose declared config has drifted from reality, per #9.ok: a Chromium binary was found (Playwright's downloaded browser cache is checked first, falling back to a well-known system install path) and it launched successfully — reportsbinaryPath+version.degraded: a binary was found but either it failed to launch, or only a system Chromium exists while the Playwright browser cache is missing/incomplete — reportsbinaryPath+details.absent: no Chromium binary could be found anywhere.The probe (
apps/server/src/environment/BrowserCapabilityProbe.ts) is lazy and cached for 6 hours viaEffect.cachedWithTTL, so it never runs on every health-check poll.ExecutionEnvironmentCapabilities.browseris an additive optional field inpackages/contracts/src/environment.ts; existing web/desktop clients tolerate it.Detection is filesystem + process based only (directory scan of the Playwright cache, well-known system paths, then a
--versionspawn) — noplaywright-coredependency was added toapps/server. Installation/telepítés-kezelés and cc_runner's dispatch/demote logic stay out of scope per the issue.Decisions
apps/server, with mockedFileSystem/ProcessRunner(matches the issue's## Testnote). First commit (c2550a5c) addsBrowserCapabilityProbe.test.tsalone and is red (imports a module that doesn't exist yet); the second commit adds the implementation and wiring.degraded, since either way the automation stack that actually needs to drive the browser (Playwright) can't be trusted yet — matches the issue's example (RPi has both apt chromium and the ms-playwright cache →ok).Effect.cachedWithTTL(..., "6 hours")per server instance, as specified.Manually verified
scripts/agent-verify.shdoes not exist in this repo, so per instructions I ranpnpm lintand the relevant test suites directly.Pre-existing, unrelated flake found while running the full
pnpm testRunning
pnpm testat the repo root (which fans out to every workspace package in parallel) reproduces one failing test twice in a row:I confirmed this is not caused by this PR:
git diff main -- apps/mobile/src/features/diffs/nativeReviewDiffHighlighter.ts apps/mobile/src/features/diffs/nativeReviewDiffHighlighter.test.tsis empty — neither file is touched by this branch.apps/mobile's full test suite alone (cd apps/mobile && pnpm exec vp test run), twice, passes cleanly both times:520 passed (520).pnpm testruns 4+ workspace packages' Vitest processes fully in parallel in this sandbox and fails identically both times I tried, which points at CPU-contention-sensitive timing inside the shared Shiki/JS-regex highlighter singleton under heavy load (the failing assertion shows coarser, less-tokenized output consistent with a tokenizer time budget being hit), not a logic bug in the diff.I did not attempt a fix for it here since it's unrelated to #9's scope and I couldn't get a reliable, isolated repro to validate a fix against — flagging it explicitly rather than silently leaving it. Given the issue's own acceptance criteria (measured
ok/degraded/absentbrowser capability, lazy 6h-cached probe, unit test coverage) are fully met and verified above, I'm titling this "Fixes #9"; happy to split the mobile flake into a separate follow-up issue if preferred.Closes #9
Summary by CodeRabbit
New Features
Bug Fixes