Skip to content

refactor(client): one VCS status refresh owner per checkout - #24975

Merged
juliusmarminge merged 4 commits into
mainfrom
effect/split-F-vcs-revalidation
Oct 25, 2026
Merged

juliusmarminge merged 4 commits into
mainfrom
effect/split-F-vcs-revalidation

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

Problem

Mobile refreshed the selected thread's git status from a useEffect keyed on five primitives copied out of the selection, plus a useEffectEvent to avoid stale closures. Each consumer of useSelectedThreadGitActions ran its own copy, so two sheets showing the same checkout each fired a refresh.

Change

  • packages/client-runtime: new createVcsStatusRevalidationAtomFamily. It makes one atom per environment and cwd that refreshes while mounted, but only through the connected atom it is given: once when that atom is true on mount, once per reconnect, and on an optional debounced wake signal. Every subscriber to the same checkout shares it, and the wake subscription and timer end with the last subscriber.
  • Mobile: useSelectedThreadGitActions mounts the atom with useAtomMount. A new environmentConnectedAtom family supplies the connection flag, and setPendingConnectionError still reports refresh failures.
  • Removed the .test.tsx render-loop harness that tested the old effect. The new family test covers the behavior instead.

Behavior change: opening a git sheet no longer refreshes on its own

Before, every useSelectedThreadGitActions mount fired a quiet refresh, so opening the Git overview, branches, commit, confirm, or review sheet triggered one. Those sheets are native-stack screens above ThreadRouteScreen, which stays mounted and holds the same (environment, cwd) atom. The atom is already live, so opening a sheet adds a subscriber and does not refresh again. This is fine. The route already refreshed on selection and on every reconnect. The sheets read the live subscribeVcsStatus stream, not a one-time snapshot. Every git mutation refreshes afterward, and the overview sheet keeps pull-to-refresh and its Refresh button. A sheet opened without the route underneath (a deep link) mounts the atom itself and refreshes as before.

What this improves

  • Sync removed: the selection-driven refresh effect, which mirrored primitives into deps and needed useEffectEvent.
  • Duplicate refreshes removed: consumers showing the same checkout now share one refresh per selection or reconnect (refreshes once per connection, shared by every subscriber, and again on reconnect).
  • Tests in vcsStatusRevalidation.test.ts: waiting for the connection before the first refresh, debounced wake with teardown, and the idle target.

Effects

apps/mobile/src/state/use-selected-thread-git-actions.ts: 1 -> 0. Other touched files: 0 -> 0.

Effect report

From scripts/effect-report.ts --compare github/main (harness in #24980).

package effects syncEffects noDeps chained renderRefWrites
apps/web/src 620 52 20 24 0
apps/mobile/src 398 → 397 (-1) 59 6 26 7
packages/client-runtime/src 0 0 0 0 0
total 1018 → 1017 (-1) 111 26 50 7
changed file effects syncEffects noDeps chained renderRefWrites
apps/mobile/src/state/use-selected-thread-git-actions.ts 1 → 0 (-1) 0 0 0 0

Render scenarios: Mobile has no scenario harness yet; this change is mobile-only.

Verification

  • vp test run packages/client-runtime/src/state/vcsStatusRevalidation.test.ts apps/mobile/src/state/use-selected-thread-git-actions.test.ts: 15 passed
  • vp run check:changed: format, lint, knip, and typecheck (34 packages) pass. Tests: 2701/2702. The one failure was PullRequestCodeTab.browser.test.tsx ("Cannot verify that chromium request interception is active after 5s"), an environment flake in a file this PR does not touch. It passes on rerun.

Model: Claude Opus 5.5, Claude Code harness.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 25, 2026
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Thread transfer impact

⚠️ The latest CI run did not produce a thread transfer result for ca1e467.

This comment will update automatically after the next completed run.

@juliusmarminge
juliusmarminge force-pushed the effect/split-F-vcs-revalidation branch from 15db051 to 582db9c Compare October 25, 2026 20:49
@juliusmarminge
juliusmarminge marked this pull request as ready for review October 25, 2026 21:09
@macroscopeapp

macroscopeapp Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This refactor changes mobile VCS refresh ownership and timing by introducing a shared connection-aware atom, alongside new lifecycle tests. It also adds an @effect-diagnostics globalTimers:off suppression, which requires human review under the configured policy.

Notes:

  • All code in this push has already been reviewed. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

@juliusmarminge
juliusmarminge force-pushed the effect/split-F-vcs-revalidation branch from 582db9c to ca1e467 Compare October 25, 2026 21:17
@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

Run configuration
Commits

Reviewing files that changed from the base of the PR and between ca1e467 and da58a63.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 582db9c and ca1e467.

Files selected for processing: 1
  • scripts/effect-budget.json
Files with no reviewable changes: 1
  • scripts/effect-budget.json

Limit details: You’ve used all 10 included reviews currently available.

Walkthrough

The client runtime adds a shared VCS status revalidation atom family. Mobile uses it to refresh status for the selected thread’s environment and working directory, with refresh errors reflected in pending connection state.

Changes: Mobile VCS status refresh

Layer / File(s) Summary
Shared VCS status revalidation
packages/client-runtime/src/state/vcsStatusRevalidation.ts, packages/client-runtime/src/state/vcsStatusRevalidation.test.ts, packages/client-runtime/src/state/vcs.ts
The new atom family shares refreshes by environment and working directory. It supports connection-triggered and wake-triggered refreshes, wake debouncing, and cleanup when subscribers unmount. Tests cover these behaviors, and vcs.ts re-exports the implementation.
Selected-thread refresh integration
apps/mobile/src/state/use-remote-environment-registry.ts, apps/mobile/src/state/use-selected-thread-git-actions.ts, apps/mobile/src/state/use-selected-thread-git-actions.test.ts, apps/mobile/src/state/use-selected-thread-git-actions.test.tsx, scripts/effect-budget.json
Mobile adds an environment connection atom and mounts shared revalidation for a selected thread with a project and working directory. Refresh failures use a shared message helper. The test mocks change, the previous hook test is removed, and the effect-budget entry for the hook is deleted.

Priority: Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Sequence Diagram(s)

sequenceDiagram
  participant Hook as useSelectedThreadGitActions
  participant Mount as useAtomMount
  participant Revalidation as selectedThreadStatusRevalidation
  participant Connection as environmentConnectedAtom
  participant Refresh as vcsEnvironment.refreshStatus
  participant ErrorState as setPendingConnectionError
  Hook->>Mount: Mount revalidation for selected environment and cwd
  Mount->>Revalidation: Subscribe to selected-thread status atom
  Revalidation->>Connection: Read connection state
  Connection-->>Revalidation: Connected state
  Revalidation->>Refresh: Refresh status when connected or woken
  Refresh-->>Revalidation: Return refresh result
  Revalidation->>ErrorState: Clear or set pending connection error
Loading

Possibly related issues

  • pingdotgg/t3code#20254 — The shared refresh owner may address overlapping refresh work, but this change does not address slow Git commands or event-loop stalls.

Possibly related PRs

Suggested reviewers: macroscopeapp

Merge Risk: Minimal · up to ca1e4

No issue with the selected change is established; it is mergeable after normal checks.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning The description thoroughly covers the problem, change, behavior, and verification. It omits the required Scope and approval section, including issue or maintainer approval details or an exemption rati… Add a Scope and approval section. Link the triaged issue or maintainer approval, or explain why this focused fix qualifies for an exemption.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: one VCS status refresh owner per checkout.
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.
Full details: Description check

Explanation

The description thoroughly covers the problem, change, behavior, and verification. It omits the required Scope and approval section, including issue or maintainer approval details or an exemption rationale.

Resolution

Add a Scope and approval section. Link the triaged issue or maintainer approval, or explain why this focused fix qualifies for an exemption.

Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

juliusmarminge and others added 4 commits October 25, 2026 15:21
Problem: mobile refreshed the selected thread's git status from a
useEffect keyed on five primitives mirrored from the selection, with a
useEffectEvent to dodge the stale-closure trap. Every consumer of
useSelectedThreadGitActions ran its own copy, so two sheets showing the
same checkout each fired a refresh.

Fix: add createVcsStatusRevalidationAtomFamily to client-runtime. It
yields one atom per environment and cwd that refreshes while mounted:
on mount once connected, once per reconnect, and optionally on a
debounced wake signal. Subscribers to the same checkout share it, and
the wake subscription and timer end with the last subscriber. Mobile
mounts it with useAtomMount, reading the connection flag from a new
environmentConnectedAtom family.

Effects: removes the selection-refresh useEffect (and its
useEffectEvent) from use-selected-thread-git-actions. None added.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The doc comment said the atom refreshes on mount. It refreshes only
when a `connected` atom is passed and reads true: on mount and once per
reconnect. Without it, only the debounced wake signal refreshes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juliusmarminge
juliusmarminge force-pushed the effect/split-F-vcs-revalidation branch from ca1e467 to da58a63 Compare October 25, 2026 22:21
@juliusmarminge
juliusmarminge merged commit 604ecb6 into main Oct 25, 2026
31 checks passed
@juliusmarminge
juliusmarminge deleted the effect/split-F-vcs-revalidation branch October 25, 2026 22:27
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Oct 26, 2026
## What's Changed
* fix(server): attachments are no longer silently dropped from prompts by @maria-rcks in pingdotgg/t3code#21356
* fix(mobile): images picked with choose files reach the agent as images by @maria-rcks in pingdotgg/t3code#21352
* feat(web): attach svg files to messages by @maria-rcks in pingdotgg/t3code#21355
* feat(server): send pdf attachments to claude and antigravity as documents by @maria-rcks in pingdotgg/t3code#21358
* feat(mobile): play audio inline and open shared files in the viewer by @maria-rcks in pingdotgg/t3code#21353
* feat(web): play audio inline and open any file the agent shares in the viewer by @maria-rcks in pingdotgg/t3code#21363
* perf(pull-requests): faster pull request timeline, code tab, summary and search by @maria-rcks in pingdotgg/t3code#22697
* perf(mobile): bound streaming markdown cache and pending work by @juliusmarminge in pingdotgg/t3code#24263
* fix(web): question options show a radio and an aligned shortcut key by @maria-rcks in pingdotgg/t3code#23255
* fix(server): notify parents after delegated background runs by @juliusmarminge in pingdotgg/t3code#23542
* fix(server): running delegates tell agents to end the turn by @t3dotgg in pingdotgg/t3code#24887
* perf(ci): cache server tests individually across shards by @juliusmarminge in pingdotgg/t3code#24966
* feat(mobile): one cached native-client install command for agents and machines by @juliusmarminge in pingdotgg/t3code#24965
* perf(source-control): pull request previews read only the pull request by @maria-rcks in pingdotgg/t3code#22583
* feat(infra): native client cache panels on the task cache dashboard by @juliusmarminge in pingdotgg/t3code#24994
* feat(web): UI design overhaul, with the new look behind a Beta toggle by @t3dotgg in pingdotgg/t3code#24865
* test(server): tests no longer depend on the host machine by @t3dotgg in pingdotgg/t3code#25001
* perf: opening a thread loads 85% less data by @t3dotgg in pingdotgg/t3code#24899
* fix(server): orchestrator records command count and duration again by @yordis in pingdotgg/t3code#23966
* fix(observability): every app reports its own environment and release channel by @yordis in pingdotgg/t3code#24340
* chore(lint): React effects can't grow past each file's budget by @juliusmarminge in pingdotgg/t3code#24964
* fix(observability): every exported resource names its service instance by @yordis in pingdotgg/t3code#23973
* fix(install): stable installs no longer fail behind a page of nightlies by @t3dotgg in pingdotgg/t3code#22907
* fix(server): Grok refresh no longer restores removed models from cache by @t3dotgg in pingdotgg/t3code#22849
* fix(server): resume fallback keeps the latest turn when an older handoff is pending by @t3dotgg in pingdotgg/t3code#22902
* fix(client-runtime): "Codex (hub)" badges read CH instead of C( by @t3dotgg in pingdotgg/t3code#22918
* fix(mobile): retain requested PR environment while connecting by @juliusmarminge in pingdotgg/t3code#24262
* fix(web): usage-limit banner reset time follows the Time format setting by @t3dotgg in pingdotgg/t3code#22915
* fix(web): terminal drag selection scrolls faster the farther past the edge by @t3dotgg in pingdotgg/t3code#22872
* fix(observability): resources add OTel semconv runtime and browser keys by @yordis in pingdotgg/t3code#23972
* chore(lint): main passes lint again with effects merged after the budget by @t3dotgg in pingdotgg/t3code#25055
* fix(server): ended roots no longer leave provider turns running by @t3dotgg in pingdotgg/t3code#22846
* feat(mobile): open threads and devices in a resizable iOS inspector by @juliusmarminge in pingdotgg/t3code#24985
* chore(web): measure renders before/after with render scenarios by @juliusmarminge in pingdotgg/t3code#24980
* fix(web): asset URLs re-mint per revision and before expiry without effects by @juliusmarminge in pingdotgg/t3code#24970
* fix(web): queued-message edits survive navigation and settle once by @juliusmarminge in pingdotgg/t3code#24972
* refactor(mobile): thread visits are tracked outside React by @juliusmarminge in pingdotgg/t3code#24973
* refactor(client): cloud account transitions run in one service by @juliusmarminge in pingdotgg/t3code#24974
* refactor(client): one VCS status refresh owner per checkout by @juliusmarminge in pingdotgg/t3code#24975
* refactor(web): document appearance and title are applied from app start by @juliusmarminge in pingdotgg/t3code#25004
* refactor(web): app shell shortcuts register once through one command dispatcher by @juliusmarminge in pingdotgg/t3code#25016
* refactor(web): shared intersection and document-activity stores by @juliusmarminge in pingdotgg/t3code#25020
* refactor(web): the theme store and diff worker pool stop syncing the theme through effects by @juliusmarminge in pingdotgg/t3code#25007
* fix(server): keep history discovery off the writer and pace compaction by @JustYannicc in pingdotgg/t3code#20877
* perf(mobile): compact persisted thread snapshots by @juliusmarminge in pingdotgg/t3code#24265


**Full Changelog**: pingdotgg/t3code@v0.1.3-nightly.20261025.3682...v0.1.3-nightly.20261025.3692

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.1.3-nightly.20261025.3692
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). 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.

1 participant