# fix\(muse\): list background children under their turn item's native id · PR \#23856 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/23856)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

State: open

Source repository: Unavailable fork

Source branch: fix/muse-roster-task-ids

Target branch: main

Head commit: 7c9904fa81ba3e4120cc55b438f7c82730d60471

[Discussion and reviews](https://git.cafe/pingdotgg/t3code/pull/23856)

[Commits](https://git.cafe/pingdotgg/t3code/pull/23856/commits?format=markdown)

[Files changed](https://git.cafe/pingdotgg/t3code/pull/23856/diffs?format=markdown)

## Description

---

Fixes #23844. Follow-up to #23828.

Muse put running children on the provider-thread background roster under `itemId`, but their subagent turn items carry `childSessionId || subagentId ?? itemId`. Readers pair roster entries with turn items by that id:
- `derivePendingBackgroundWork` dedupes the two.
- Restart recovery skips roster tasks it already cancelled as turn items.
- #23828 drops the running follow-up turn's own children from the banner.

With different ids, the same child could show up twice. Real transcripts (`subagent_v2/muse_transcript.ndjson`) have three distinct ids per child, and `childSessionId` only appears in revision 2, so the turn item's id changes while the child runs.

## Summary

```diff
 publishItem(subagent | workflow)
   observedChildren keyed by itemId            # stable key for routing and cleanup, unchanged
-  if wasRunning !== running
+  if wasRunning !== running || (running && not listed under backgroundTaskId(item))
     syncBackground()

 syncBackground
-  taskId: itemId
+  taskId: backgroundTaskId(item)

+backgroundTaskId(item)
+  subagent: childSessionId || (subagentId ?? itemId)   # what the turn item's nativeItemRef already used
+  workflow: itemId                                     # its turn item uses itemId
```

The extra resync condition relists a running child when its id moves. A running child with an unchanged id is already listed, so it adds no extra `provider_thread.updated` emits.

## Evidence

New test in `packages/provider-muse/src/server/adapter.test.ts`. It takes one child through four revisions and checks the roster ids against the turn item's native id:

```text
rev  ids on item                      turn item nativeId   roster (before)   roster (after)
1    itemId only                      sub-1                [sub-1]           [sub-1]
2    + subagentId                     subagent-1           [sub-1]  ✗        [subagent-1]
3    + childSessionId                 child-session-1      [sub-1]  ✗        [child-session-1]
4    completed                        child-session-1      []                []
```

- **Before:** fails on `main`, because the roster stays `sub-1`.
- **After:** passes. Muse adapter 37/37, `MuseReplayFixtures.integration.test.ts` 8/8, `orchestrationV2PendingBackgroundWork` 16/16. GPT-6.1-Sol (Codex) reviewed it and reported no findings.

## Merge Danger

**Door:** two-way

Only the roster's `taskId` strings change. Nothing persisted depends on the old ids beyond the live roster, which Muse rewrites on its next sync.

**Blast Radius:** Muse-only

The Muse adapter is the only file changed. The roster still clears on completion, failure, cancellation, and session release.

---

Made with Claude Opus 5.5 (Claude Code in T3 Code). Review by GPT-6.1-Sol (Codex).

