@@ -71,10 +71,12 @@ func (s *exactProgressTaskStore) Update(context.Context, *storage.Task) error {
7171
7272type fakeControlEngine struct {
7373 engine.Engine
74- stopCount int
75- cutoverCount int
76- cutoverResult * engine.ControlResult
77- cutoverErr error
74+ stopCount int
75+ cutoverCount int
76+ progressResult * engine.ProgressResult
77+ progressErr error
78+ cutoverResult * engine.ControlResult
79+ cutoverErr error
7880}
7981
8082func (e * fakeControlEngine ) Name () string { return "fake" }
@@ -88,6 +90,9 @@ func (e *fakeControlEngine) Apply(context.Context, *engine.ApplyRequest) (*engin
8890}
8991
9092func (e * fakeControlEngine ) Progress (context.Context , * engine.ProgressRequest ) (* engine.ProgressResult , error ) {
93+ if e .progressResult != nil || e .progressErr != nil {
94+ return e .progressResult , e .progressErr
95+ }
9196 return & engine.ProgressResult {State : engine .StateRunning }, nil
9297}
9398
@@ -126,6 +131,7 @@ type exactProgressStorage struct {
126131 tasks storage.TaskStore
127132 logs storage.ApplyLogStore
128133 controlRequests storage.ControlRequestStore
134+ vitessApplyData storage.VitessApplyDataStore
129135}
130136
131137func (s * exactProgressStorage ) Applies () storage.ApplyStore { return s .applies }
@@ -139,6 +145,30 @@ func (s *exactProgressStorage) ApplyLogs() storage.ApplyLogStore {
139145func (s * exactProgressStorage ) ControlRequests () storage.ControlRequestStore {
140146 return s .controlRequests
141147}
148+ func (s * exactProgressStorage ) VitessApplyData () storage.VitessApplyDataStore {
149+ return s .vitessApplyData
150+ }
151+
152+ type exactProgressVitessApplyDataStore struct {
153+ storage.VitessApplyDataStore
154+ data * storage.VitessApplyData
155+ saveData * storage.VitessApplyData
156+ err error
157+ }
158+
159+ func (s * exactProgressVitessApplyDataStore ) GetByApplyID (context.Context , int64 ) (* storage.VitessApplyData , error ) {
160+ return s .data , s .err
161+ }
162+
163+ func (s * exactProgressVitessApplyDataStore ) Save (_ context.Context , data * storage.VitessApplyData ) error {
164+ if s .err != nil {
165+ return s .err
166+ }
167+ clone := * data
168+ s .saveData = & clone
169+ s .data = data
170+ return nil
171+ }
142172
143173func TestApplyCancelHandleDoesNotCancelNewerOwner (t * testing.T ) {
144174 client := & LocalClient {}
@@ -291,6 +321,67 @@ func TestLocalClient_ProgressByApplyIDReturnsNotFoundForMissingApplyData(t *test
291321 }
292322}
293323
324+ func TestLocalClient_ProgressPersistsRecoveredVitessMigrationContext (t * testing.T ) {
325+ apply := & storage.Apply {
326+ ID : 42 ,
327+ ApplyIdentifier : "apply-vitess-recovered-context" ,
328+ Database : "testdb" ,
329+ DatabaseType : storage .DatabaseTypeVitess ,
330+ Environment : "staging" ,
331+ State : state .Apply .Running ,
332+ Engine : storage .EnginePlanetScale ,
333+ }
334+ task := & storage.Task {
335+ ID : 43 ,
336+ ApplyID : apply .ID ,
337+ TaskIdentifier : "task-vitess-recovered-context" ,
338+ Database : "testdb" ,
339+ DatabaseType : storage .DatabaseTypeVitess ,
340+ Namespace : "testdb" ,
341+ TableName : "users" ,
342+ State : state .Task .Running ,
343+ }
344+ vitessData := & storage.VitessApplyData {
345+ ApplyID : apply .ID ,
346+ BranchName : "schemabot-apply" ,
347+ DeployRequestID : 123 ,
348+ ExistingMigrationCtxs : map [string ]storage.VitessMigrationContextTimestamps {
349+ "preexisting" : {RequestedTimestamp : "2026-01-01 00:00:00" },
350+ },
351+ }
352+ vitessStore := & exactProgressVitessApplyDataStore {data : vitessData }
353+ client := & LocalClient {
354+ config : LocalConfig {
355+ Database : "testdb" ,
356+ Type : storage .DatabaseTypeVitess ,
357+ },
358+ storage : & exactProgressStorage {
359+ applies : & exactProgressApplyStore {apply : apply },
360+ tasks : & exactProgressTaskStore {tasks : []* storage.Task {task }},
361+ vitessApplyData : vitessStore ,
362+ },
363+ planetscaleEngine : & fakeControlEngine {progressResult : & engine.ProgressResult {
364+ State : engine .StateRunning ,
365+ ResumeState : & engine.ResumeState {
366+ MigrationContext : "recovered-context" ,
367+ },
368+ }},
369+ logger : slog .Default (),
370+ }
371+
372+ _ , err := client .Progress (t .Context (), & ternv1.ProgressRequest {
373+ ApplyId : apply .ApplyIdentifier ,
374+ Environment : apply .Environment ,
375+ })
376+ require .NoError (t , err )
377+ require .NotNil (t , vitessStore .saveData )
378+ assert .Equal (t , "recovered-context" , vitessStore .saveData .MigrationContext )
379+ assert .Equal (t , apply .ID , vitessStore .saveData .ApplyID )
380+ assert .Equal (t , "schemabot-apply" , vitessStore .saveData .BranchName )
381+ assert .Equal (t , uint64 (123 ), vitessStore .saveData .DeployRequestID )
382+ assert .Contains (t , vitessStore .saveData .ExistingMigrationCtxs , "preexisting" )
383+ }
384+
294385func TestLocalClient_ProcessPendingStopControlRequest (t * testing.T ) {
295386 apply := & storage.Apply {
296387 ID : 123 ,
0 commit comments