Skip to content

[BUG] History restore can desync the active profile during a task switch #48

Open

Description

@simurg79

Problem (one or two sentences)

Restoring a history task can apply its saved model profile globally after a different task has become current. The active profile can then disagree with the current task's saved profile, making the selected model misleading.

Context (who is affected and when)

Affects users who switch to or create another task while a history restore awaits profile loading or activation. An uncontended restore must still activate the restored task's profile normally.

Reproduction steps

Source-based interleaving to reproduce; not executed as part of this report:

  1. Have history task A saved with profile A and another task B with profile B.
  2. Begin restoring A; pause its asynchronous profile activation before the global writes complete.
  3. Switch to or create B so B becomes current with its own profile.
  4. Release A's delayed activation and wait for both operations to settle.
  5. Compare the final global profile name and provider settings, the UI's active profile, and the current task's saved profile.

Expected result

After any sequence of restores and task switches, the active profile shown in the UI matches the current task's profile. Final global profile name and provider settings must not retain a stale restore's profile.

Actual result

A delayed restore can write profile A globally after B becomes current. Task-local identity guards do not protect those earlier writes. The inspected fork also lacks the checkout's task-local guards, so effects can extend beyond stale global state.

App Version

Installed version not supplied. Inspected fork main: b32c5cf (package version 3.53.6). Local checkout HEAD: 22cb84b8bfd0b626308424037d96b0003cdbb379. Source-verified race report, not a runtime reproduction on that release.

Relevant logs or errors (optional)

No runtime logs were collected. Verified source locations and scope follow.

Inspected checkout: history restoration and global writes

Equivalent locations verified in this fork

The fork revision above lacks the checkout's history transition queue, unlocked helpers, and expected-current-task option. Task-local guards should not be described as already present in this fork.

Fix constraints and possible directions

Simply skipping global activation is insufficient: a successful uncontended restore must still show its own profile. Routing all task creation through the history-task queue changes ordering for every caller.
Possible directions, not a prescribed implementation:

  • Roll back or re-apply the appropriate global profile when the current task changes during restore.
  • Make profile activation and the current-task check atomic within the existing history-task queue, accounting for task changes outside that queue. That queue is present in the inspected checkout, not this fork revision.
  • Derive the UI's active profile from the current task instead of global state; also address remaining global-state consumers.

Regression coverage

Add a deterministic test interleaving history restore with a task switch. Release delayed activation, await settlement, and check final global profile name and provider settings against the current task's profile. Also check posted UI profile and that the newly current task's saved profile is not overwritten.
Keep an uncontended-restore test proving successful profile activation. Existing checkout identity-guard tests in ClineProvider.sticky-profile.spec.ts assert task-local writes, not the final global profile after this interleaving.

Activity

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

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions