@@ -192,8 +192,9 @@ impl ExecutionEngine {
192192 respond_emitter : Option < & dyn RespondEmitter > ,
193193 with_trace : bool ,
194194 ) -> EngineExecutionReport {
195- self . execute_graph_with_execution_id_report_async (
195+ self . execute_graph_with_project_id_report_async (
196196 execution_id,
197+ flow. project_id ,
197198 flow. starting_node_id ,
198199 flow. node_functions ,
199200 flow. input_value ,
@@ -373,6 +374,30 @@ impl ExecutionEngine {
373374 remote : Option < & dyn RemoteRuntime > ,
374375 respond_emitter : Option < & dyn RespondEmitter > ,
375376 with_trace : bool ,
377+ ) -> EngineExecutionReport {
378+ self . execute_graph_with_project_id_report_async (
379+ execution_id,
380+ 0 ,
381+ start_node_id,
382+ node_functions,
383+ flow_input,
384+ remote,
385+ respond_emitter,
386+ with_trace,
387+ )
388+ . await
389+ }
390+
391+ async fn execute_graph_with_project_id_report_async (
392+ & self ,
393+ execution_id : ExecutionId ,
394+ project_id : i64 ,
395+ start_node_id : i64 ,
396+ node_functions : Vec < NodeFunction > ,
397+ flow_input : Option < Value > ,
398+ remote : Option < & dyn RemoteRuntime > ,
399+ respond_emitter : Option < & dyn RespondEmitter > ,
400+ with_trace : bool ,
376401 ) -> EngineExecutionReport {
377402 if let Some ( emitter) = respond_emitter {
378403 emitter. emit ( execution_id, EmitType :: StartingExec , null_value ( ) ) ;
@@ -383,7 +408,7 @@ impl ExecutionEngine {
383408 None => ValueStore :: default ( ) ,
384409 } ;
385410
386- let compiled = match compile_flow ( start_node_id, node_functions) {
411+ let compiled = match compile_flow ( project_id , start_node_id, node_functions) {
387412 Ok ( plan) => plan,
388413 Err ( err) => {
389414 let runtime_error = err. as_runtime_error ( ) ;
@@ -628,6 +653,7 @@ mod tests {
628653 struct StubRemoteRuntime {
629654 result : NodeExecutionResult ,
630655 target_services : Option < Arc < Mutex < Vec < String > > > > ,
656+ project_ids : Option < Arc < Mutex < Vec < i64 > > > > ,
631657 }
632658
633659 #[ async_trait]
@@ -643,6 +669,12 @@ mod tests {
643669 . expect ( "target service recorder should not be poisoned" )
644670 . push ( execution. target_service ) ;
645671 }
672+ if let Some ( project_ids) = & self . project_ids {
673+ project_ids
674+ . lock ( )
675+ . expect ( "project id recorder should not be poisoned" )
676+ . push ( execution. request . project_id ) ;
677+ }
646678
647679 Ok ( self . result . clone ( ) )
648680 }
@@ -1240,6 +1272,7 @@ mod tests {
12401272 result : None ,
12411273 } ,
12421274 target_services : None ,
1275+ project_ids : None ,
12431276 } ;
12441277 let mut remote_node = node (
12451278 1 ,
@@ -1285,6 +1318,7 @@ mod tests {
12851318 result : Some ( node_execution_result:: Result :: Success ( string_value ( "ok" ) ) ) ,
12861319 } ,
12871320 target_services : Some ( Arc :: clone ( & target_services) ) ,
1321+ project_ids : None ,
12881322 } ;
12891323 let mut remote_node = node (
12901324 1 ,
@@ -1306,6 +1340,47 @@ mod tests {
13061340 ) ;
13071341 }
13081342
1343+ #[ test]
1344+ fn remote_execution_uses_flow_project_id ( ) {
1345+ let engine = ExecutionEngine :: new ( ) ;
1346+ let project_ids = Arc :: new ( Mutex :: new ( Vec :: new ( ) ) ) ;
1347+ let remote = StubRemoteRuntime {
1348+ result : NodeExecutionResult {
1349+ started_at : 1 ,
1350+ finished_at : 2 ,
1351+ parameter_results : Vec :: new ( ) ,
1352+ id : Some ( node_execution_result:: Id :: NodeId ( 99 ) ) ,
1353+ result : Some ( node_execution_result:: Result :: Success ( string_value ( "ok" ) ) ) ,
1354+ } ,
1355+ target_services : None ,
1356+ project_ids : Some ( Arc :: clone ( & project_ids) ) ,
1357+ } ;
1358+ let mut remote_node = node (
1359+ 1 ,
1360+ "remote::project" ,
1361+ vec ! [ literal_param( 100 , "payload" , int_value( 20 ) ) ] ,
1362+ None ,
1363+ ) ;
1364+ remote_node. definition_source = Some ( "action.example" . to_string ( ) ) ;
1365+ let flow = ExecutionFlow {
1366+ flow_id : 10 ,
1367+ project_id : 42 ,
1368+ starting_node_id : 1 ,
1369+ node_functions : vec ! [ remote_node] ,
1370+ input_value : None ,
1371+ } ;
1372+
1373+ let report = engine. execute_flow_report ( flow, Some ( & remote) , None , false ) ;
1374+
1375+ assert_eq ! ( report. exit_reason, ExitReason :: Success ) ;
1376+ assert_eq ! (
1377+ * project_ids
1378+ . lock( )
1379+ . expect( "project id recorder should not be poisoned" ) ,
1380+ vec![ 42 ]
1381+ ) ;
1382+ }
1383+
13091384 #[ test]
13101385 fn remote_execution_rejects_empty_action_definition_source ( ) {
13111386 let engine = ExecutionEngine :: new ( ) ;
0 commit comments