Skip to content

[Bug]: Delegated tasks on a linked environment reappear as top-level threads once their settled parent leaves the newest-25 settled window #31008

Closed

Description

@zucram

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 === null

When 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

  1. Link environment B to environment A.
  2. In a thread P on A, run delegate_task with target.environmentId = B; let it finish. Don't settle the task on B.
  3. Settle P. The task stays nested under P. Correct.
  4. Settle 25 more top-level threads on A (or let auto-settle do it).
  5. 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 olderSettled threads (e.g. treat only an explicit archivedAt !== null or 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

Activity

  1. juliusmarminge commented on Nov 4, 2026

    @juliusmarminge
    Member

    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, and omitOlderSettledShells (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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions