Repository navigation
Upstream give-back backlog (hold until V2 merges upstream) #276
Description
Activity
More upstream candidates from the #262 live pass (evidence). Re-check them against upstream before offering:
- A server restart cancels the running turn silently. The cancelled turn has no marker, and it shows the wrong duration ("Worked for 479ms" for about 24 s of work). While only a held queued run remains, the sidebar says "Working".
- "New thread on " opens a draft on the worktree's temporary branch name (
t3code/<id>), not the chosen branch. - A repo with no remote shows "From origin/master" as the base branch.
Give-back candidate (Jackson, 2026-09-25): on environment-wide settings pages (upstream's Providers, and J5's Personas and Skills catalog), the new settings scope line still says "Applying settings for " when a project is selected, even though those settings can't be scoped to a project (only keys in
PROJECT_SCOPED_SERVER_SETTING_KEYScan). Suggest that upstream hide or disable the project picker, or reword the line, on pages whose settings are environment-wide.Added: Dead agent-device daemon reused by the device hub (#364, PR #369).
LocalDeviceHost.ensureAgentReadyreturns the cached agent-device endpoint without a health check, so after the daemon exits everydevice_openhands out a dead--config. The fix probes/healthbefore reuse and restarts the daemon. Still present onupstream/main.🤖 Generated with Claude Code
Give-back candidate: A hung
simctlbreaks device listing, behind a generic error. Seen 2026-10-04 on Jackson's Mac, after CoreSimulatorService had been up for about 2 days and stopped answering. Everysimctlcall hung, includingsimctl help. Restarting the service fixed it.What the person saw:
- The panel showed only "Device list failed: Could not communicate with device support. Try refreshing devices." The real cause,
simctlnot answering, never reached the person. - The iOS device list kept emptying and refilling. On refreshes where
simctlfailed instead of hanging, the hub returnedsimulators: []witherrors.refreshinDeviceService.tsreplaced the host's devices with that empty list, then the next good call brought them back. - Stuck
simctl list devices --jsonprocesses piled up, one every refresh. We counted 15, some orphaned (ppid 1) by earlier hub runs.
Where it belongs:
- expo-device-hub (expo/expo-device-hub):
execSimctlcallsexecFile("xcrun", ["simctl", ...])with no timeout, so a wedged CoreSimulator holds/api/devicesopen indefinitely. This is still the case in 0.12.0, the version upstream pins as ofupstream/maina1d9d72aef. Suggest a timeout that kills the child, and an error sayingsimctldid not respond. - T3 Code (
apps/server/src/device/DeviceService.tsand therequest_failedtext inpackages/contracts/src/device.ts, unchanged onupstream/maina1d9d72aef):hubJsonmaps a timeout, a bad status and a decode failure all to the samerequest_failedmessage. Telling a timeout apart ("The device hub did not answer within 15 s") would have pointed straight at the simulator service.- When the hub's list comes back empty and carries
errors, consider keeping the host's last known devices, with the error as detail, instead of showing none.
J5 carries no fix for this. The person-side fix is
killall -9 com.apple.CoreSimulator.CoreSimulatorService(with Simulator.app quit). Re-check against upstream and expo-device-hub before offering.Posted by an AI agent on Jackson's behalf.
- The panel showed only "Device list failed: Could not communicate with device support. Try refreshing devices." The real cause,
Candidate: the welcome wizard forgets the folder selection when you jump back to a stage by name
Not posted upstream. Recorded here for the give-back pass.
- What happens: in the import step, change which folders are selected (for example "Select none", then tick one). Click the Providers stage in the header, then Continue. The selection is back to the defaults and the one you ticked is unticked.
- Who hits it: only someone who jumps between stages by clicking a stage name. Going straight through the wizard never triggers it, and there is no Back button between those two stages.
- Likely cause, not confirmed against upstream's source: the selected paths are local state inside the import step, which unmounts when the stage changes.
- Why this is upstream's: J5's wizard is upstream's
components/onboarding/WelcomeWizard.tsxsince refactor(web): onboarding goes back to upstream's three stages #457, apart from branding and the "Providers" wording (FORK.md case 39). J5's older wizard kept the selection in its own import session, which refactor(web): onboarding goes back to upstream's three stages #457 removed. - Evidence: a tester reproduced it on 2026-10-04 on refactor(web): onboarding goes back to upstream's three stages #457's head against its base, with paired screenshots.
- Not checked: whether upstream
mainstill behaves this way, and whether upstream already tracks it.
Candidate: revoking a client does not close the sockets it already has open
Not posted upstream. Recorded here for the give-back pass. Found in review of #506.
- What happens: revoke a client in Settings → Connections while it has a WebSocket open. Its next HTTP request gets a 401, but the open socket stays up and keeps serving every method its scopes allowed, until the socket closes for another reason.
- Why: the socket's scopes are fixed at upgrade.
apps/server/src/ws.tsauthenticates once in the/wsroute and builds the RPC server withRpcAuthorization.layer(session.scopes)(line 3202 in J5's copy), and nothing re-checks the session per request.SessionStore.revoke(apps/server/src/auth/SessionStore.ts, lines 995-1013 in J5's copy) marks the row revoked, drops the session from the connected-sessions map and publishesclientRemoved. The only subscriber turns that into an entry on the access stream for the Connections list; none closes a socket. Expiry is the same: it is checked when a ticket is verified, not afterwards. - How it was checked: read from the code, then reproduced on an isolated dev server with an empty home (the Move J5's client-facing actions onto WebSocket methods #506 branch, not a live install). A second session opened a socket, an admin session revoked it through
POST /api/auth/clients/revoke(200,revoked: true), the revoked token then got 401 onPOST /api/auth/websocket-ticket, and three seconds later the socket was still open and answeredj5.crews.stop,j5.peers.addressesandj5.peers.issueCredentialas before. Not reproduced on unmodified upstream, and not with an upstream method, though the path is the same for those. - Who hits it: anyone who revokes a client expecting it to stop at once, most likely for a lost device or a leaked pairing link. A client that is closed, or reconnects, is refused.
- Why J5 cares: since Move J5's client-facing actions onto WebSocket methods #506, J5's client actions are socket methods and take this behavior (FORK.md case 64). Before, each was an HTTP request and re-authenticated. The sharpest case is
j5.peers.issueCredential, which mints a long-lived peer credential under a new session id that revoking the client does not touch. - Smallest fix to offer: close a session's sockets when it is revoked (and when it expires), for example by having the
/wsroute end its scope on aclientRemovedchange for itssession.sessionId.
Candidate: a server's name cannot be set, so two servers on one machine report the same name
Not posted upstream. Recorded here for the give-back pass.
- What happens:
resolveServerEnvironmentLabelnames a server after its machine (friendly name, hostname, cwd base name) with no override, so two servers on one host show the same label in Connections and at/.well-known/t3/environment. - J5's fix: Two servers on one machine report the same name #545, PR feat(server): a server's name can be set, so two on one machine can be told apart #548 (register D32, FORK.md case 66): an environment variable,
J5CODE_SERVER_NAME, read before the host lookups. Upstream could take it as aT3CODE_variable or aserveflag.
Posted by an AI agent on Jackson's behalf.
- What happens:
Candidate:
node --watch src/bin.tsrestarts the dev server when another pnpm worktree installs (not posted upstream): on Linux a bare--watchwatches about 1,200 loaded files undernode_modules/.pnpmthat pnpm hardlinks from its shared store, so a second worktree's install or removal changes their link count and restarts the server; J5 narrowed it to--watch-path=src --watch-path=../../packagesin #550 (issue #544, FORK.md case 66), measured there, and upstreammainwas not checked for an existing fix or issue.
Fixes and improvements J5 carries that belong upstream. We hold them while V2 (pingdotgg#2829) is still under heavy construction, then offer them once it settles and merges. Check this list at every upstream advance and remove items upstream fixes on its own.
ProjectionStore.getLimitRecoveryCandidatesinterpolatesautoResume/snoozebooleans (refactor(server): share scheduling for tasks and limit recovery pingdotgg/t3code#12795). Node 24'snode:sqliterejects them, so usage-limit recovery scans fail at runtime and upstream's ownProjectionStoretest fails. J5 binds 1/0 as a temporary patch (chore(upstream): advance to V2 67a2be0 with release archives and migration bridge #262).t3-codeMCP server to Codex, Claude, OpenCode, Pi and ACP sessions, but pre-approves its tools only on Claude (mcp__t3-code__*). Elsewhere a T3 tool call (e.g.spawn_agent,schedule_task) raises the provider's native MCP prompt. The per-adapter mechanics, and the traps, are in the reviews on closed fork PRs feat(server): OpenCode Captains propose a Crew without a native prompt #302 (OpenCode's<server>_<tool>permission rules), feat(server): Pi Captains propose a Crew without a native prompt #303 (Pi's injected extension) and feat(server): ACP Captains propose a Crew without a native prompt #304 (ACP carries no trustworthy server identity; the Antigravity metadata bypass). Related: a forked OpenCode session (Session.fork) loses T3's whole permission ruleset. From the State the Captain decision per provider adapter #233 ruling, 2026-09-26.t3command stays on the old version after an in-app update. The installer's~/.local/bin/t3links to one version's executable, and onlyt3 updaterepoints it (repointLauncherinapps/server/src/cli/update.tshas a single caller). A server self-update through the service launcher never touches the link, sot3, and any agent calling it, keeps running the previous version. Confirmed on upstream main on 2026-10-02 (e0db2a5e58). J5's fix (The j5 command stays on the old version after an in-app update #398, PR fix(cli): j5 follows the server after an in-app update #415) has the service's server repoint the installer's default link at itself afterlauncher.prepareTrial, reusingrepointLauncherunchanged; upstream could take it as is witht3forj5.SERVICE_LAUNCHER_PROTOCOLbump and a manual step on every machine. Proposed: after a self-update commits, the server rewrites the unit to name its own version, so the new launcher takes over at the next restart. This is a design change to offer, not a bug fix; not built yet. Tracked in Keep the service's supervisor current after an update from the app #444.