fix(web): show running servers on thread rows#24606

draft3
main
fix/issue-15238
opened18d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 18d ago

Problem

A Claude thread can start a background dev server that returns HTTP 200 while its sidebar row shows no server indicator. The default sidebar does not render the existing server button, and discovery only associates listeners with T3 terminals.

Change

Attribute listeners to their thread through registered Claude and ACP provider process ancestry. Keep terminal ownership separate and preserve the rule that every listener sharing a port must be owned before probing it. Reuse the existing server button in the default card and slim rows and the legacy sidebar.

Scope and approval

Fixes https://github.com/pingdotgg/t3code/issues/15238

GitCafe: #15238. Triaged bug via the automated issue flow.

Verification

  • Reproduced on main with a real Claude background python3 -m http.server 5173: HTTP 200 and an active chat task, with no sidebar server indicator.
  • Repeated on the fix: Open localhost:5173 appeared. Stopping the task removed the listener and the globe on the next discovery refresh.
  • The attribution test failed on main. Final vp test run apps/server/src/preview/PortScanner.test.ts: 15/15 passed, including lsof and Linux /proc shared-port collisions in both orders and unregistering.
  • Scoped provider, port-state and lifecycle checks passed; server, web, contracts and ACP typechecks passed. Changed-file lint and whitespace checks passed.
  • Two independent reviews found no blocking code defects on the final head.
  • The ACP process-tree suite has an environment failure in its exact-argv test: its fixed /usr/bin:/bin PATH cannot find this VM’s Node executable. The focused ACP lifecycle check and package typecheck passed.

Evidence: capture report, artifact manifest and fixture trace, fixture matrix. Scripts and fixture data are uploaded with the captures, not committed.

Before is 3cc31ed27c8956b36cee35a50509fb7c6869592b; after is 7c0a3cea4591c78c825de359226cc0c0467cdee2. D shows card and slim rows; L shows the legacy sidebar.

Recordings and narrated steps are indexed in the capture report:

Rendering: product Browser panel, no device emulation; CSS 1440×1000 captures are scaled to 1280×889, CSS 390×1000 captures are 780×2000 at DPR 2. Both themes use matched synthetic data. Agent slim fixtures are snoozed because settling stops their servers.

What else changed in the captures: some terminal indicator colors differ; five same-revision desktop pairs retain small edge or toggle halo differences. These prevent a claim of exact visual equivalence. The capture report lists every comparison and pixel count.

Pending evidence gates: strict stabilization for five desktop compositions, narrow keyboard activation, baseline Browser-list comparison, and the proof repairs below. Reduced-motion emulation is unavailable in this Browser tool; stills pause animations and recordings retain live motion. Permission-denied and real ACP-provider flows were not exercised. Some recording endpoints show a connecting Browser state; supplemental loaded-page stills are linked in the report.

Proof audit: INSUFFICIENT — row audit and repair list. All 96 uploaded hashes matched; an independent head legacy-dark rebuild matched exactly (0/1,137,920 pixels changed). Remaining repairs: five unstable still compositions, three terminal-color comparison pairs, narrow keyboard activation, a readable baseline legacy390 endpoint, baseline Browser-list/discovery and globally empty-state proof, real ACP attribution/unregister, and retained lifecycle removal receipts. The head list recording needs relabeling. Permission-denied remains unverified. The requested nonzero diff-count fixture is unavailable because that renderer returns null on both revisions. This PR remains draft pending those repairs and CI/bot review.

Attribution covers POSIX Claude and spawned ACP provider descendants. Shared Codex processes, OpenCode/Pi, Windows descendants and fully detached processes remain outside this attribution path. Native mobile rendering is unchanged. Real ACP-provider, Electron and remote/tunnel interaction were not exercised.

Models: Claude Opus 5.5 via the Claude Agent harness; GPT-6.1-Sol via the Codex harness for lead, review and evidence.

Checks

22 successful · 4 skipped
All checks passed
7c0a3ce

Added 3 commits

  • fix(server): never probe a port an agent server shares with an unrelated listener7c0a3ce
  • fix(server): attribute agent-started background servers to their threada327d35
  • test(server): agent-started background servers are attributed to their threadefe9ec8
Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiB✅
ClaudeLive turn messages220 (0.0%)8✅

Baseline: c4fa462 · PR result: 7c0a3ce · Source CI: success

Scenario and decoded snapshot size

10 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.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.