Repository navigation
fix(server): a turn that adds a Git remote shows "Add to another machine" right away - #29947
juliusmarminge wants to merge 3 commits into
Conversation
A project whose enrichment cached "no repository" keeps a null repositoryIdentity after a turn adds a Git remote, until the one-minute caches expire. This test reproduces #29929: it fails on main because the post-turn finalization refresh never re-resolves the project's identity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a turn ran `git remote add` or `gh repo create --push` in a project with no repository identity, both the enrichment cache and the resolver's negative cache kept reporting "no repository" for up to a minute, hiding "Add to another machine" and the "Run on" menu. Post-turn finalization now re-resolves the identity past both caches for the thread's project when it has none yet, alongside the existing workspace and VCS refresh. Projects that already have an identity pay only an in-memory peek. A failure is logged and does not affect the turn. Fixes #29929 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for missing identities The gate now reads through the enrichment cache instead of peeking it, so a known identity past its 1-minute TTL no longer forces a resolver refresh. The refresh runs in a per-project FiberMap so forge probes cannot delay the next queued turn, and a forced resolve that still finds no remote publishes nothing. The thread shell is read after the workspace and VCS refreshes again, so its failure cannot interrupt them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Projects that gain their first Git remote during a turn now publish their repository identity promptly, making existing machine options available without waiting for cache expiry. The refresh runs in the background and avoids forced lookups for known identities or notifications for unchanged misses. You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
Problem
When an agent's turn gives a project its first Git remote (
git remote add,gh repo create --push), the composer's "Run on" menu and its "Add to another machine" item stay hidden for up to a minute. The server keeps serving the project's cachedrepositoryIdentity: nulluntil two 1-minute caches expire: theProjectEnrichmentServiceidentity cache and theRepositoryIdentityResolvernegative cache.Reproduced on main at 61c3794 with a dev server on a fresh database. A Claude (Sonnet 5.5) thread ran
git remote add origin https://github.com/t3-triage/agent-29929.gitand finished at 04:29:06Z.GET /api/orchestration/shellstill returnedrepositoryIdentity: nullfor that project and showed the GitHub identity only 55 s after the turn ended. The same happens with a plain shellgit remote add: 53 s.Change
RunFinalizationObserver.refreshstarts a background refresh of the thread's project identity, keyed by project. A newer turn's refresh replaces a running one, the same way the pull-request lookup there already runs. The next turn never waits for it, and forge discovery for self-hosted remotes can take seconds.readRepositoryIdentity). A project that already has an identity stops there and spawns no forced git lookup.ProjectEnrichmentService.refreshRepositoryIdentity. That re-resolves past the resolver's negative cache and, when it finds an identity, replaces the cached enrichment entry and publishes the change to shell subscribers.Clients need no change: web, desktop and mobile already apply enrichment changes from the shell stream.
Scope and approval
Fixes #29929
Triaged via the automated issue flow.
Verification
vp test run apps/server/src/orchestration-v2/RunFinalizationService.test.ts: 10/10 pass. Three new tests:resolves the identity of a project whose remote was added during the turn: real temp git repo, cachednull, remote added, turn finalized, then the identity is published. On main it never publishes. In its first form, which awaited the refresh inline, it failed withthe project's repository identity is still null after the turn added a remote. Since the refresh moved to the background, all three new tests fail on main by hitting the test timeout rather than an assertion, because the event they await never arrives.keeps a known identity's resolver caches when a turn outlasts the enrichment TTL: a project with a known identity, a turn after 61 s, and the resolver never receivesrefresh: true.returns from the post-turn refresh while the identity resolver is still running: finalization returns while a gated resolver is pending, and the identity is published once it is released.RunFinalizationQueue,DelegatedCompletionDelivery,runtimeLayerandProjectEnrichmentServicetests pass.RepositoryIdentityResolvertests pass 11/11 withGIT_CONFIG_GLOBAL=/dev/null; the test VM's globalurl.insteadOfrewrite breaks 2 of them on main too.vp run check:changedpasses: format, lint, knip, typecheck (3 packages), tests (6 files).Runtime transcript, same driver and agent prompt on fresh dev databases. The driver polls the shell snapshot every 2 s after the turn ends:
originsetNot checked:
repositoryIdentityshown above.Model and harness: Claude Opus 5.5 (lead, red test, implementation, review B) and GPT-6.1 Sol (review A), run through T3 Code with the Claude Code and Codex harnesses.
🤖 Generated with Claude Code