flowchart TD
  A["User clicks tour card in Onboarding Panel"] --> B["panel.dispatch start-tour"]
  B --> C["TourEngine.handle start-tour"]
  C --> D{"sandbox.detectConflict"}
  D -- "none" --> E["start 200ms timer"]
  D -- "exists-clean" --> F["reuse existing sandbox"]
  D -- "exists-modified" --> G["post tour-confirm-reset-sandbox"]
  G --> H["await inbound confirmation"]
  H --> E
  E --> I["scaffold.scaffold workspacePath"]
  E --> J["timer fires, post tour-preparing-sandbox"]
  I --> K["scaffold resolves, cancel timer"]
  F --> K
  K --> L["progress.load folderUri, tourId"]
  L --> M["client.listTours, pick TourDto"]
  M --> N["render first step or resume step"]
  N --> O["post tour-step"]
  O --> P{"step.kind"}
  P -- "read" --> Q["panel shows Next button"]
  P -- "action" --> R["client.watchStep tourId, stepId"]
  Q --> S["inbound tour-next-step"]
  R --> T["server fires onStepCompleted"]
  S --> U["progress.save with new step pointer"]
  T --> U
  U --> V{"more steps?"}
  V -- "yes" --> N
  V -- "no" --> W["progress.save finished=true"]
  W --> X["completed.markCompleted tourId"]
  X --> Y{"tour has final_handoff step"}
  Y -- "yes" --> Z["post tour-final-handoff-prompt"]
  Y -- "no" --> AA["post tour-finished"]
  Z --> AB["inbound tour-final-handoff-confirmed"]
  AB --> AC["commands.execute turbine.datasources.newDatasource"]
  AC --> AD["END"]
  AA --> AD
sequenceDiagram
  actor User
  participant Panel as OnboardingViewProvider
  participant Engine as TourEngine
  participant Client as TurbineClient
  participant Scaffold as SandboxScaffold

  User->>Panel: click tour card
  Panel->>Engine: handle start-tour tourId folderUri
  Engine->>Scaffold: detectConflict workspacePath
  Scaffold-->>Engine: none
  Engine->>Engine: schedule 200ms hint timer
  Engine->>Scaffold: scaffold workspacePath
  Note right of Engine: race between scaffold and 200ms
  Engine->>Panel: post tour-preparing-sandbox after 200ms
  Panel->>User: render Preparing sandbox hint
  Scaffold-->>Engine: SandboxPath
  Engine->>Engine: cancel hint timer
  Engine->>Client: listTours
  Client-->>Engine: ListToursResult
  Engine->>Engine: progress load folderUri tourId
  Engine->>Panel: post tour-step index 0
  Panel->>User: render step 0
  User->>Panel: click Next or trigger predicate
  Panel->>Engine: handle tour-next-step
  Engine->>Client: watchStep when action step
  Client-->>Engine: onStepCompleted notification
  Engine->>Engine: progress save record
  Engine->>Panel: post tour-step index 1
  Note over Engine,Panel: loop until all steps done
  Engine->>Engine: completed markCompleted tourId
  Engine->>Panel: post tour-final-handoff-prompt
  User->>Panel: confirm
  Panel->>Engine: handle tour-final-handoff-confirmed
  Engine->>Panel: commands execute turbine.datasources.newDatasource
classDiagram
  class TourEngine {
    +handle(message) Promise~void~
    +resume(folderUri, tourId) Promise~void~
    +dispose() void
  }
  class TurbineClient {
    <<existing>>
    +listTours() Promise~ListToursResult~
    +watchStep(params) Promise~void~
    +unwatchStep() Promise~void~
    +runStep(params) Promise~RunStepResultDto~
    +onStepCompleted(handler) Disposable
  }
  class SandboxScaffold {
    <<existing>>
    +exists(workspacePath) Promise~boolean~
    +scaffold(workspacePath) Promise~SandboxPath~
    +reset(workspacePath) Promise~void~
    +detectConflict(workspacePath) Promise~ConflictKind~
  }
  class TourPanelChannel {
    <<Interface>>
    +post(message) void
  }
  class TourProgressStore {
    <<Interface>>
    +load(folderUri, tourId) Promise~TourProgressRecord~
    +save(record) Promise~void~
  }
  class CompletedToursStore {
    <<Interface>>
    +list() readonly_string_array
    +markCompleted(tourId) Promise~void~
  }
  class TourCommandSink {
    <<Interface>>
    +execute(command, args) Promise~unknown~
  }
  class OnboardingViewProvider {
    <<existing>>
    +resolveWebviewView(view) void
    +show() Promise~void~
    +postToWebview(message) void
  }
  class LspTourProgressStore {
    +load(folderUri, tourId) Promise~TourProgressRecord~
    +save(record) Promise~void~
  }
  TourEngine --> TurbineClient : uses
  TourEngine --> SandboxScaffold : uses
  TourEngine --> TourPanelChannel : posts
  TourEngine --> TourProgressStore : persists
  TourEngine --> CompletedToursStore : marks
  TourEngine --> TourCommandSink : final-handoff
  OnboardingViewProvider --> TourEngine : routes start-tour
  OnboardingViewProvider ..|> TourPanelChannel : implements via postToWebview
  LspTourProgressStore ..|> TourProgressStore : implements
  LspTourProgressStore --> TurbineClient : sendRequest