Skip to content

fix(chat): refresh read-only teammate thread metadata so preview finds the repo - #5171

Merged
pedrofrxncx merged 1 commit into
mainfrom
fix/read-only-thread-preview-stale-repo
Jul 24, 2026
Merged

fix(chat): refresh read-only teammate thread metadata so preview finds the repo#5171
pedrofrxncx merged 1 commit into
mainfrom
fix/read-only-thread-preview-stale-repo

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

Opening someone else's thread showed "No source to preview / Connect GitHub" even though the thread had clearly loaded a repo and opened a PR — as the user put it, "it opened directly on the Super Agent, and the Super Agent has no github."

Root cause

load_repo correctly persists githubRepo (and sandboxMap) on the thread row's metadata. But a read-only viewer's panel row can predate that write:

  • The live data-open-preview stream chunk that patches githubRepo/sandboxMap onto the client row reaches only the user who ran the tool.
  • The decopilot.thread.status SSE carries no metadata (thread-status-events.ts), so handleWatchEvent never refreshes it.
  • useEnsureTask prefers a cached localHit and fetchThread short-circuits on it, so the viewer's activeTask stays a pre-repo snapshot.

Result: preview-tab reads activeTask.metadata.githubRepo (absent) → empty state; and the owner-keyed sandbox lookup (from the read-only preview fix) finds no sandboxMap entry → no preview.

Fix

On opening a read-only teammate thread, force one fresh COLLECTION_THREADS_GET and merge it into the store via a new ThreadManagerStore.refreshThreadMetadata(id)update-only (guards on the row already being loaded), so it can never insert a teammate's thread into the scoped panel list. activeTask then carries the current githubRepo + sandboxMap, fixing both the preview gate and the owner-sandbox preview.

  • New hook useRefreshViewedThreadMetadata, gated to others' threads (created_by !== me). No-op for your own thread (kept current by the live stream).
  • Fires once per (org, thread) (staleTime: Infinity).

Testing

  • tsc --noEmit clean (apps/web).
  • No useEffect (uses useQuery); query key is a KEYS constant.

Notes / follow-ups

  • Ceiling (marked ponytail:): a teammate's thread that binds a repo while you're already watching it won't refresh until reload — add a finite staleTime/refetch if that matters.
  • Secondary gap (not fixed here): for a repo-on-agent thread (repo on activeTask.virtual_mcp_id's agent metadata, opened read-only without ?virtualmcpid=), the preview resolves the URL's Super Agent and never the thread's own agent. Follow-up: resolve useVirtualMCP(activeTask.virtual_mcp_id) in the clonable-source check.

🤖 Generated with Claude Code


Summary by cubic

Fixes missing repo preview when opening a teammate’s thread by force-refreshing thread metadata so githubRepo and sandboxMap are up to date. Prevents the “No source to preview / Connect GitHub” state and restores the owner’s sandbox preview.

  • Bug Fixes
    • Added ThreadManagerStore.refreshThreadMetadata(id) to fetch and merge fresh metadata via COLLECTION_THREADS_GET (update-only).
    • Introduced useRefreshViewedThreadMetadata to trigger a one-time refresh for read-only teammate threads; no-op for your own.
    • Wired the hook into agent-shell-layout and added a KEYS.viewedThreadMetadataRefresh query key.

Written for commit 5c178c2. Summary will update on new commits.

Review in cubic

…s the repo

Opening someone else's thread showed "No source to preview / Connect GitHub"
even when the thread had loaded a repo and opened a PR — the preview opened as
if on the bare Super Agent.

Root cause: load_repo persists githubRepo (and sandboxMap) on the THREAD row,
but a read-only viewer's panel row can predate that write. The live
data-open-preview stream chunk that patches githubRepo/sandboxMap onto the
client row only reaches the user who ran the tool, and the thread-status SSE
carries no metadata — so the viewer's activeTask stays a pre-repo snapshot.
preview-tab then reads activeTask.metadata.githubRepo (absent) and shows the
empty state, and the owner-keyed sandbox lookup finds no sandboxMap entry.

Fix: on opening a read-only teammate thread, force one fresh
COLLECTION_THREADS_GET and merge it into the store (update-only, so it can't
pollute the scoped panel list). activeTask then carries current githubRepo +
sandboxMap, fixing both the preview gate and the owner-sandbox preview. No-op
for your own thread (kept current by the live stream).
@pedrofrxncx
pedrofrxncx enabled auto-merge (squash) July 24, 2026 13:58
@pedrofrxncx
pedrofrxncx merged commit 585c766 into main Jul 24, 2026
14 checks passed
@pedrofrxncx
pedrofrxncx deleted the fix/read-only-thread-preview-stale-repo branch July 24, 2026 14:00
decocms Bot pushed a commit that referenced this pull request Jul 24, 2026
PR: #5171 fix(chat): refresh read-only teammate thread metadata so preview finds the repo
Bump type: patch

- decocms (apps/api/package.json): 4.122.4 -> 4.122.5

Deploy-Scope: web
pedrofrxncx pushed a commit that referenced this pull request Jul 27, 2026
#5240)

Reverts #5112 (share agent sandboxes by branch), #5116 (always share
agent sandboxes) and #5132 (use shared staging branch), restoring the
pre-#5112 behaviour: hosted agent sandboxes are per-user again, and a
new GitHub-backed thread gets a generated branch instead of `staging`.

Reconstructed against current paths rather than reverted: #5120 split
apps/mesh into apps/api + apps/web and hoisted branch-name.ts,
runtime-defaults.ts and thread/schema.ts into packages/shared, and #5174
deleted vm-events.ts outright, so none of the three commits reverse-apply.

Core change: SandboxId goes back to a flat `{ userId, projectRef }` and
sandboxIdKey back to `userId:projectRef`, so every hosted claim handle
changes. Live shared claims must be drained BEFORE this deploys.

Also reverted, because they only exist inside the shared model:
- #5225 withoutLegacyAgentSandboxEntries — left in place it would strip
  the sandboxMap entries the reverted server writes back, leaving
  shouldAutoStart permanently true (silent, compiles fine)
- #5219 resolveSharedThreadVm and the shared-scope branch
- #5183 stale-provisioning reset (lived inside the deleted storage)

Deliberately preserved:
- migrations 137/138 and their index.ts entries — Kysely's
  #ensureNoMissingMigrations runs unconditionally, so deleting an applied
  migration crash-loops every pod. The tables are dropped by a follow-up
  forward migration after the drain, not by this commit.
- #5114/#5118 withClaimGitLock, #5126 org-context guard, #5143 analytics
  gate, #5171 owner-keyed thread graft, #5195/#5207/#5210/#5221 client
  auto-retry, the daemon status-code train and the settings-validation train
- #5112's org-fs least-privilege narrowing and the start dedup key fix
- #5116's squashed queue-tray pluralization (en + pt-br)
- the remote-branch-name validations #5132 deleted, since this restores
  the dynamic origin/HEAD lookup that made them load-bearing

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Pedro França <pedrofrxncx@deco.cx>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant