Repository navigation
Description
Area
packages/client-runtime (affects apps/mobile and apps/web)
What happens
Tasks a thread delegated to a linked environment (delegate_task with target.environmentId) sit under their parent while the parent is fresh. Once the parent is settled and falls out of the newest-settled window of its server's shell snapshot, every one of those tasks pops back into the thread list as a standalone top-level row. No new activity happens on the parent or the tasks; it is triggered by other threads settling on the parent's server.
On the iPhone app this looked like a batch of day-old finished tasks ("Done") suddenly appearing at the top of the list.
Cause
delegatedUnderParentAtom (packages/client-runtime/src/state/threadShell.ts) keeps a delegated task under its parent only when the parent is in the client's thread index:
get(environmentThreadIndexAtom(parent.environmentId)).get(parent.threadId)?.archivedAt === nullWhen the parent is missing from the index this is undefined === null, so the task is treated as an orphan and listed on its own.
The parent goes missing because omitOlderSettledShells (apps/server/src/orchestration-v2/ShellStream.ts) keeps only the NEWEST_SETTLED_KEPT = 25 newest settled top-level threads in opted-in snapshots. Older ones are kept only while "pinned, snoozed, live, or above a kept subagent or side chat". A parent of a remote delegate is none of those: its child lives in another environment's snapshot, so the server that trims the parent never sees it.
Steps to reproduce
- Link environment B to environment A.
- In a thread P on A, run
delegate_taskwithtarget.environmentId = B; let it finish. Don't settle the task on B. - Settle P. The task stays nested under P. Correct.
- Settle 25 more top-level threads on A (or let auto-settle do it).
- P leaves A's snapshot (counted under
olderSettled), and the task on B now appears as its own row in the list on mobile and desktop.
Observed
Server 0.1.7-nightly.20261104.4151 on all environments; iOS app build 202. Parent settled 2026-11-03T14:37Z; the 25th newer settled thread on its server landed 2026-11-04T15:35Z, and four tasks on the linked environment appeared as top-level rows from then on. Their own event streams show no events between finishing on 11-03 and being auto-settled later.
Expected
A delegated task stays out of the list while its parent exists and is not archived, whether or not the parent is currently in the trimmed snapshot.
Possible fixes
- Client: treat "parent not in index" as "parent unknown" rather than "orphan" when the parent's environment reports
olderSettledthreads (e.g. treat only an explicitarchivedAt !== nullor a deleted parent as orphaning), or fetch the parent's shell on demand. - Server: hard to fix server-side alone, since the parent's server cannot see the remote child. Recording remote children on the parent (it already records a remote task child) and keeping such parents in the snapshot like local subagent parents would also work.
- Separately, a "Hide tasks delegated from other environments" list option would give users a way out of every variant of this.
Related
- [Bug]: Archiving a thread lists the tasks it delegated to linked environments as separate sidebar threads #30265: same orphaning path, triggered by archiving the parent.
- iPhone app lists cross-machine delegated tasks as top-level threads; desktop nests them under their parent #26854: the original mobile/desktop nesting fix (feat(server): delegate_task to a linked environment #16719) that added
delegatedUnderParentAtom.
Activity
juliusmarminge commentedon Nov 4, 2026
Duplicate of https://git.cafe/pingdotgg/t3code/issues/30320, which reports the same thing: a task delegated to a linked environment is listed as a top-level thread once its settled parent falls below the newest 25 settled threads on the parent's server.
Checked on main at 9e85538.
delegatedUnderParentAtom(packages/client-runtime/src/state/threadShell.ts) still needs the parent in the client's thread index, andomitOlderSettledShells(apps/server/src/orchestration-v2/ShellStream.ts) has no rule that keeps the parent of a remote task. Open PR https://git.cafe/pingdotgg/t3code/pulls/30266 covers the archived-parent case (https://git.cafe/pingdotgg/t3code/issues/30265) but not this one.Closing in favour of https://git.cafe/pingdotgg/t3code/issues/30320. The extra detail here (iOS, the four tasks, the server-side fix idea) is useful context for that fix.