@@ -79,10 +79,10 @@ function planItem(overrides: Record<string, unknown> = {}) {
7979 }
8080}
8181
82- /** The source loader, answering for `wf-src` only, as the real one answers for sync sources only. */
82+ /** The source loader, answering for `wf-src` in the child only, as the real one answers for sync sources only. */
8383function sourceIs ( sourceState : WorkflowState | null ) {
84- mocks . loadSourceDeployedWorkflow . mockImplementation ( async ( _workspaceId : string , id : string ) =>
85- id === 'wf-src' && sourceState
84+ mocks . loadSourceDeployedWorkflow . mockImplementation ( async ( workspaceId : string , id : string ) =>
85+ workspaceId === 'child' && id === 'wf-src' && sourceState
8686 ? { summary : { id, name : 'Support Agent' } , state : sourceState }
8787 : null
8888 )
@@ -118,13 +118,27 @@ describe('getWorkspaceSyncWorkflowDiff', () => {
118118 allowPersonalApiKeys : false ,
119119 } ) )
120120 workspaceForkingLineageMockFns . mockResolveForkEdge . mockResolvedValue ( edge )
121- mocks . loadForkBlockMap . mockResolvedValue ( {
122- parentToChild : new Map ( ) ,
123- childToParent : new Map ( [ [ 'b1' , { targetBlockId : 'mapped-b1' , targetWorkflowId : 'wf-tgt' } ] ] ) ,
124- } )
121+ /* Pairs come back only for a read scoped to the target workflow, so a mapped id proves the scope. */
122+ mocks . loadForkBlockMap . mockImplementation (
123+ async ( _db : unknown , child : string , scope ?: { side : string ; workflowId : string } ) => ( {
124+ parentToChild : new Map ( ) ,
125+ childToParent :
126+ child === 'child' && scope ?. side === 'parent' && scope . workflowId === 'wf-tgt'
127+ ? new Map ( [ [ 'b1' , { targetBlockId : 'mapped-b1' , targetWorkflowId : 'wf-tgt' } ] ] )
128+ : new Map ( ) ,
129+ } )
130+ )
125131 sourceIs ( state ( { b1 : { } , b2 : { } } , [ { id : 'e' , source : 'b1' , target : 'b2' } ] ) )
126- mocks . resolveForkPlanItem . mockResolvedValue ( planItem ( ) )
127- mocks . loadTargetDraftState . mockResolvedValue ( state ( { 'mapped-b1' : { } } ) )
132+ /* The item only resolves for the child-to-parent orientation both directions use here. */
133+ mocks . resolveForkPlanItem . mockImplementation (
134+ async ( params : { sourceWorkspaceId : string ; targetWorkspaceId : string } ) =>
135+ params . sourceWorkspaceId === 'child' && params . targetWorkspaceId === 'parent'
136+ ? planItem ( )
137+ : null
138+ )
139+ mocks . loadTargetDraftState . mockImplementation ( async ( id : string , workspaceId : string ) =>
140+ id === 'wf-tgt' && workspaceId === 'parent' ? state ( { 'mapped-b1' : { } } ) : null
141+ )
128142 } )
129143
130144 it ( 're-keys the source through the block map and derives ids for unmapped blocks' , async ( ) => {
@@ -143,11 +157,6 @@ describe('getWorkspaceSyncWorkflowDiff', () => {
143157 afterLabel : 'Support Agent (deployed)' ,
144158 } )
145159 expect ( result . before ) . toEqual ( state ( { 'mapped-b1' : { } } ) )
146- expect ( mocks . loadTargetDraftState ) . toHaveBeenCalledWith ( 'wf-tgt' , 'parent' )
147- expect ( mocks . loadForkBlockMap ) . toHaveBeenCalledWith ( expect . anything ( ) , 'child' , {
148- side : 'parent' ,
149- workflowId : 'wf-tgt' ,
150- } )
151160 } )
152161
153162 it ( 're-keys source variables and their assignments to the target ids by unique name' , async ( ) => {
@@ -196,8 +205,6 @@ describe('getWorkspaceSyncWorkflowDiff', () => {
196205 expect ( result . before ) . toBeNull ( )
197206 expect ( result . targetWorkflowId ) . toBeNull ( )
198207 expect ( result . beforeLabel ) . toBe ( 'Support Agent (current)' )
199- expect ( mocks . loadTargetDraftState ) . not . toHaveBeenCalled ( )
200- expect ( mocks . loadForkBlockMap ) . not . toHaveBeenCalled ( )
201208 } )
202209
203210 it ( 'fails instead of guessing when a replaced target cannot be loaded' , async ( ) => {
@@ -210,35 +217,29 @@ describe('getWorkspaceSyncWorkflowDiff', () => {
210217 await expect ( run ( { sourceWorkflowId : 'foreign' } ) ) . rejects . toMatchObject ( {
211218 code : 'not_found' ,
212219 } )
213- expect ( mocks . resolveForkPlanItem ) . not . toHaveBeenCalled ( )
214- expect ( mocks . loadTargetDraftState ) . not . toHaveBeenCalled ( )
215220 } )
216221
217222 it ( 'rejects a source whose target is excluded from sync, as the promote skips it' , async ( ) => {
218223 mocks . resolveForkPlanItem . mockResolvedValue ( null )
219224
220225 await expect ( run ( ) ) . rejects . toMatchObject ( { code : 'not_found' } )
221- expect ( mocks . loadTargetDraftState ) . not . toHaveBeenCalled ( )
222226 } )
223227
224228 it ( 'refuses two admin workspaces that are not a direct fork edge' , async ( ) => {
225229 workspaceForkingLineageMockFns . mockResolveForkEdge . mockResolvedValue ( null )
226230
227231 await expect ( run ( ) ) . rejects . toMatchObject ( { code : 'validation' } )
228- expect ( mocks . loadSourceDeployedWorkflow ) . not . toHaveBeenCalled ( )
229232 } )
230233
231234 it ( 'reads the other side as the source on a pull and pairs through the child block map' , async ( ) => {
232- await run ( { workspaceId : 'parent' , otherWorkspaceId : 'child' , direction : 'pull' } )
233-
234- expect ( mocks . loadSourceDeployedWorkflow ) . toHaveBeenCalledWith ( 'child' , 'wf-src' )
235- expect ( mocks . resolveForkPlanItem ) . toHaveBeenCalledWith (
236- expect . objectContaining ( { sourceWorkspaceId : 'child' , targetWorkspaceId : 'parent' } )
237- )
238- expect ( mocks . loadForkBlockMap ) . toHaveBeenCalledWith ( expect . anything ( ) , 'child' , {
239- side : 'parent' ,
240- workflowId : 'wf-tgt' ,
235+ const result = await run ( {
236+ workspaceId : 'parent' ,
237+ otherWorkspaceId : 'child' ,
238+ direction : 'pull' ,
241239 } )
240+
241+ expect ( result . targetWorkflowId ) . toBe ( 'wf-tgt' )
242+ expect ( Object . keys ( result . after . blocks ) ) . toContain ( 'mapped-b1' )
242243 } )
243244
244245 it ( 'refuses when the caller is not an admin on the other side' , async ( ) => {
@@ -251,6 +252,5 @@ describe('getWorkspaceSyncWorkflowDiff', () => {
251252 )
252253
253254 await expect ( run ( ) ) . rejects . toMatchObject ( { code : 'forbidden' } )
254- expect ( mocks . loadSourceDeployedWorkflow ) . not . toHaveBeenCalled ( )
255255 } )
256256} )
0 commit comments