Repository navigation
fix(server): a fork no longer inherits the source thread's pin, auto-settle and delegation state - #28378
Conversation
…settle and delegation state A fork was built by spreading the source thread, so it copied the source's pin, sidebar order key, auto-settle opt-out, last snooze wake and linked delegation. A fork of a pinned thread landed in Pinned, never auto-settled if the source opted out, and a fork of a delegated thread showed a false "Subagent of" row and refused side chats. The fork plan now resets pinnedAt, pinOrderKey, activeOrderKey, autoSettleDisabledAt and lastSnoozeWakeAt next to the existing snooze resets, and drops delegatedFrom. linkOrigin still carries over, as derived work keeps its origin, and so does historyOrigin, which the fork's inherited history rows need. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Needs Human Approval Macroscope's review found this PR requires human approval — New forks stop inheriting pin, ordering, auto-settle opt-out and delegation state, without changing their source threads. Human confirmation is needed for the new defaults, particularly automatic settlement of forks whose source disabled it. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Reset and verify fork state apps/server/src/orchestration-v2/ThreadForkService.ts, apps/server/src/orchestration-v2/ThreadForkService.test.ts |
The fork omits delegatedFrom and initializes selected state fields to null. The test verifies those resets and confirms that origin metadata remains preserved. |
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Possibly related PRs
- pingdotgg/t3code#24343: This PR also changes which source-thread state a fork inherits.
Suggested labels: bugfix, size:XS
Suggested reviewers: t3dotgg
Merge Risk: 
Minimal · up to 4c3ff
-
The fork-state reset is ready to merge; no actionable current-head risk was established.
Pre-merge checks: 
4
-
Full details: Title check
-
Explanation
The title names the main change: a fork no longer inherits the source thread's pin, auto-settle and delegation state. The changeset resets pinnedAt, pinOrderKey, activeOrderKey, autoSettleDisabledAt and lastSnoozeWakeAt in ThreadForkService.plan and drops delegatedFrom, matching the title. The title is long (96 characters) and uses the conventional commit prefix, but it stays specific and accurate.
Full details: Description check
-
Explanation
The description follows the repository template. It has Problem, Change, Scope and approval, and Verification sections. The Problem and Change sections explain the bug and the fix in detail. The Scope section explains why no prior issue is needed under the small-fix exemption. The Verification section lists focused test commands with results and gives before/after screenshots for web, Android and iOS. It also states what was not checked. The template's optional agent-model note is present at the end. The description is thorough and meets the template's requirements.
-
Finishing Touches
-
Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Usage-based review receipt
- Mode: Continue automatically
- Reviewed files: 2
- Charged: $0.50
- View usage details
Note
This review was completed with usage-based billing: files reviewed beyond your plan's included limits are billed at $0.25/file. View usage-based billing.
|
Note Written by Verified in a real dev environmentverified unchanged head
short runtime transcript, read from the dev databases after the ui actions: before, main: after, pr head, with the same prompt and source settings: fork interaction and real codex continuation, with startup frames trimmed; shown as an animated gif for github; mp4 playback and seeking also checked: blacksmith: both fork test files passed, 15/15. Not verifiedreal cross-environment delegation and its fork/side-chat behavior, since this run used one environment and one dev server; non-null manual active ordering; imported |



Problem
Forking a pinned thread gives you a second pinned thread. The fork plan copies the source thread and resets a list of fields, but the list misses the pin, the sidebar order key, the auto-settle opt-out, the last snooze wake and the linked-environment delegation. So a fork:
pinnedAt,pinOrderKey), or in the source's dragged slot in Active (activeOrderKey) instead of at the top like any new thread;autoSettleDisabledAt, checked inThreadSettlementService);lastSnoozeWakeAt, thoughsnoozedAtandsnoozedUntilare already reset;delegatedFrom). Web and mobile show a "Subagent of …" row for it, the client groups it under that remote thread, and the fork can't start a side chat.Change
ThreadForkService.planresetspinnedAt,pinOrderKey,activeOrderKey,autoSettleDisabledAtandlastSnoozeWakeAtnext to the existing snooze resets, and leavesdelegatedFromoff the fork (destructured out, sinceexactOptionalPropertyTypesrules outundefined). Subagent children already start with the pin pair and auto-settle opt-out cleared (#26035 added the last of those).linkOriginandhistoryOriginstill carry over: the contract says derived work keeps its link origin, and a fork's inherited v1 history rows needhistoryOrigin.activeOrderKeygoes slightly past the pin itself. It is the manual order in the Active section, andthread.settlealready clears it together with the pin pair.Scope and approval
No issue or discussion: this is a very small, focused fix for an obvious bug, which CONTRIBUTING allows without one. Five reset fields and one dropped field in one function, plus test assertions. It adds no new behavior or setting; a fork already starts unsnoozed, unsettled and unarchived, and now also starts unpinned and undelegated.
Verification
ThreadForkService.test.ts: the existing fork-reset case now gives the source all five reset fields plusdelegatedFrom,historyOriginandlinkOrigin, and asserts the fork clears the five, dropsdelegatedFromand keeps both origins. It failed on main (first failure:lastSnoozeWakeAt) and passes with the fix.vp test run apps/server/src/orchestration-v2/ThreadForkService.test.ts apps/server/src/orchestration-v2/ThreadFork.execution.test.ts: 15/15 pass.vp run check:changed 15fe2832727893cbdd2214383f9f971474849695: format, lint, knip, typecheck (3 packages) and tests pass.A fork of a pinned thread. Web, before (main): the fork shows a pin like its source:
After, the source stays pinned and the fork is not:
Android. Before (main), source and fork both show a pin:
After, only the source shows a pin:
iOS. Before (main), source and fork both show a pin:
After, only the source shows a pin:
A fork of a delegated thread. The source's parent is "R" and its link origin is "L". Web, before (main): the fork's conversation opens with a "Subagent of R" divider:
After, the divider is gone:
Web, the fork's Lineage panel before (main), listing the source's remote parent:
After, it lists only its local source:
iOS (iPad). Before (main), the fork's header reads "P · Dev · Subagent of R":
After, it reads "P · Dev · From L":
Android. Before (main), "P · Dev · Subagent of R":
After, "P · Dev · From L":
In every client the source thread still shows "Subagent of R" after the change.
Not checked:
linkOriginanddelegatedFromto a synthetic thread's projection in an isolated dev database, not through two linked environments.Prior PRs
None found. No open or closed PR or upstream branch changes this reset list. Nearby, not the same:
delegatedFromon a launch. A fork of a genuinely delegated thread still inherits it there; this PR covers that path.Generated with Claude Opus 5.5 and GPT-6.1 Terra in T3 Code Nightly