@@ -538,6 +538,7 @@ class BatchRun:
538538 stall_action : str = "blocker"
539539 concurrency : ConcurrencyConfig = field (default_factory = ConcurrencyConfig )
540540 isolate : bool = True
541+ isolation : str = "none"
541542
542543
543544def start_batch (
@@ -554,6 +555,7 @@ def start_batch(
554555 stall_action : str = "blocker" ,
555556 concurrency_by_status : Optional [dict [str , int ]] = None ,
556557 isolate : bool = True ,
558+ isolation : str = "none" ,
557559) -> BatchRun :
558560 """Start a batch execution of multiple tasks.
559561
@@ -609,6 +611,7 @@ def start_batch(
609611 stall_action = stall_action ,
610612 concurrency = concurrency ,
611613 isolate = isolate ,
614+ isolation = isolation ,
612615 )
613616
614617 # Save to database
@@ -1014,8 +1017,17 @@ def _execute_serial_resume(
10141017 if on_event :
10151018 on_event ("batch_task_started" , {"task_id" : task_id , "position" : i + 1 , "is_retry" : True })
10161019
1017- # Execute task via subprocess
1018- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1020+ # Execute task via subprocess (with isolation context)
1021+ from codeframe .core .sandbox .context import IsolationLevel , create_execution_context
1022+ exec_ctx = create_execution_context (task_id , IsolationLevel (batch .isolation ), workspace .repo_path )
1023+ try :
1024+ result_status = _execute_task_subprocess (
1025+ workspace , task_id , batch .id , engine = batch .engine ,
1026+ stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action ,
1027+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1028+ )
1029+ finally :
1030+ exec_ctx .cleanup ()
10191031
10201032 # Record result (overwrites previous result)
10211033 batch .results [task_id ] = result_status
@@ -1182,8 +1194,17 @@ def _execute_retries(
11821194 print (f"\n [Retry { retry_num } , { i + 1 } /{ len (failed_tasks )} ] { task_id } : { task_title } " )
11831195 print (f" Previous: { previous_status } " )
11841196
1185- # Execute task
1186- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1197+ # Execute task (with isolation context)
1198+ from codeframe .core .sandbox .context import IsolationLevel , create_execution_context
1199+ exec_ctx = create_execution_context (task_id , IsolationLevel (batch .isolation ), workspace .repo_path )
1200+ try :
1201+ result_status = _execute_task_subprocess (
1202+ workspace , task_id , batch .id , engine = batch .engine ,
1203+ stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action ,
1204+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1205+ )
1206+ finally :
1207+ exec_ctx .cleanup ()
11871208
11881209 # Update result
11891210 batch .results [task_id ] = result_status
@@ -1402,16 +1423,29 @@ def _execute_serial(
14021423 if on_event :
14031424 on_event ("batch_task_started" , {"task_id" : task_id , "position" : i + 1 })
14041425
1405- # Execute task via subprocess
1406- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1426+ # Execute task via subprocess (with isolation context)
1427+ from codeframe .core .sandbox .context import IsolationLevel , create_execution_context
1428+ exec_ctx = create_execution_context (task_id , IsolationLevel (batch .isolation ), workspace .repo_path )
1429+ try :
1430+ result_status = _execute_task_subprocess (
1431+ workspace , task_id , batch .id , engine = batch .engine ,
1432+ stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action ,
1433+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1434+ )
14071435
1408- # If task is BLOCKED, try supervisor resolution
1409- if result_status == RunStatus .BLOCKED .value :
1410- supervisor = get_supervisor (workspace )
1411- if supervisor .try_resolve_blocked_task (task_id ):
1412- # Supervisor resolved the blocker - retry the task
1413- print (" [Supervisor] Retrying task after auto-resolution..." )
1414- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1436+ # If task is BLOCKED, try supervisor resolution
1437+ if result_status == RunStatus .BLOCKED .value :
1438+ supervisor = get_supervisor (workspace )
1439+ if supervisor .try_resolve_blocked_task (task_id ):
1440+ # Supervisor resolved the blocker - retry the task
1441+ print (" [Supervisor] Retrying task after auto-resolution..." )
1442+ result_status = _execute_task_subprocess (
1443+ workspace , task_id , batch .id , engine = batch .engine ,
1444+ stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action ,
1445+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1446+ )
1447+ finally :
1448+ exec_ctx .cleanup ()
14151449
14161450 # Record result
14171451 batch .results [task_id ] = result_status
@@ -1803,16 +1837,37 @@ def _execute_single_task(
18031837 if on_event :
18041838 on_event ("batch_task_started" , {"task_id" : task_id , "position" : position })
18051839
1806- # Execute task via subprocess
1807- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1840+ # Create execution context (handles isolation level; NONE is a no-op)
1841+ from codeframe .core .sandbox .context import IsolationLevel , create_execution_context
1842+ exec_ctx = create_execution_context (
1843+ task_id , IsolationLevel (batch .isolation ), workspace .repo_path
1844+ )
1845+
1846+ try :
1847+ # Execute task via subprocess
1848+ result_status = _execute_task_subprocess (
1849+ workspace , task_id , batch .id ,
1850+ engine = batch .engine ,
1851+ stall_timeout_s = batch .stall_timeout_s ,
1852+ stall_action = batch .stall_action ,
1853+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1854+ )
18081855
1809- # If task is BLOCKED, try supervisor resolution
1810- if result_status == RunStatus .BLOCKED .value :
1811- supervisor = get_supervisor (workspace )
1812- if supervisor .try_resolve_blocked_task (task_id ):
1813- # Supervisor resolved the blocker - retry the task
1814- print (" [Supervisor] Retrying task after auto-resolution..." )
1815- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1856+ # If task is BLOCKED, try supervisor resolution
1857+ if result_status == RunStatus .BLOCKED .value :
1858+ supervisor = get_supervisor (workspace )
1859+ if supervisor .try_resolve_blocked_task (task_id ):
1860+ # Supervisor resolved the blocker - retry the task
1861+ print (" [Supervisor] Retrying task after auto-resolution..." )
1862+ result_status = _execute_task_subprocess (
1863+ workspace , task_id , batch .id ,
1864+ engine = batch .engine ,
1865+ stall_timeout_s = batch .stall_timeout_s ,
1866+ stall_action = batch .stall_action ,
1867+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1868+ )
1869+ finally :
1870+ exec_ctx .cleanup ()
18161871
18171872 # Record result
18181873 batch .results [task_id ] = result_status
@@ -1902,8 +1957,23 @@ def execute_task(task_id: str) -> tuple[str, str]:
19021957 if on_event :
19031958 on_event ("batch_task_started" , {"task_id" : task_id , "parallel" : True })
19041959
1905- # Execute via subprocess
1906- result_status = _execute_task_subprocess (workspace , task_id , batch .id , engine = batch .engine , stall_timeout_s = batch .stall_timeout_s , stall_action = batch .stall_action )
1960+ # Create execution context for this task
1961+ from codeframe .core .sandbox .context import IsolationLevel , create_execution_context
1962+ exec_ctx = create_execution_context (
1963+ task_id , IsolationLevel (batch .isolation ), workspace .repo_path
1964+ )
1965+
1966+ try :
1967+ # Execute via subprocess
1968+ result_status = _execute_task_subprocess (
1969+ workspace , task_id , batch .id ,
1970+ engine = batch .engine ,
1971+ stall_timeout_s = batch .stall_timeout_s ,
1972+ stall_action = batch .stall_action ,
1973+ worktree_path = exec_ctx .workspace_path if exec_ctx .workspace_path != workspace .repo_path else None ,
1974+ )
1975+ finally :
1976+ exec_ctx .cleanup ()
19071977
19081978 # Record result (thread-safe due to GIL for simple dict operations)
19091979 batch .results [task_id ] = result_status
@@ -2062,12 +2132,21 @@ def _save_batch(workspace: Workspace, batch: BatchRun) -> None:
20622132 conn = get_db_connection (workspace )
20632133 try :
20642134 cursor = conn .cursor ()
2135+ # Ensure isolation column exists (migration for existing databases)
2136+ try :
2137+ cursor .execute (
2138+ "ALTER TABLE batch_runs ADD COLUMN isolation TEXT DEFAULT 'none'"
2139+ )
2140+ conn .commit ()
2141+ except Exception :
2142+ pass # Column already exists
2143+
20652144 cursor .execute (
20662145 """
20672146 INSERT OR REPLACE INTO batch_runs
20682147 (id, workspace_id, task_ids, status, strategy, max_parallel, on_failure,
2069- started_at, completed_at, results, engine)
2070- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
2148+ started_at, completed_at, results, engine, isolation )
2149+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )
20712150 """ ,
20722151 (
20732152 batch .id ,
@@ -2081,6 +2160,7 @@ def _save_batch(workspace: Workspace, batch: BatchRun) -> None:
20812160 completed_at ,
20822161 results_json ,
20832162 batch .engine ,
2163+ batch .isolation ,
20842164 ),
20852165 )
20862166 conn .commit ()
@@ -2102,4 +2182,5 @@ def _row_to_batch(row: tuple) -> BatchRun:
21022182 completed_at = datetime .fromisoformat (row [8 ]) if row [8 ] else None ,
21032183 results = json .loads (row [9 ]) if row [9 ] else {},
21042184 engine = row [10 ] if len (row ) > 10 and row [10 ] else "plan" ,
2185+ isolation = row [11 ] if len (row ) > 11 and row [11 ] else "none" ,
21052186 )
0 commit comments