@@ -349,8 +349,13 @@ _drain_pool() {
349349# Launch a task PAIR: baseline + full simultaneously for the same task.
350350# Follows _common.sh's run_paired_configs pattern: both configs run in parallel
351351# per task so timing is comparable and resource utilization is maximized.
352- # Dockerfile swap (for artifact mode) is handled once at the task level and
353- # restored by a background watcher after BOTH configs complete — no race condition.
352+ #
353+ # Key design: baseline uses the ORIGINAL Dockerfile (full local repos).
354+ # MCP uses a TEMP COPY of the task dir with Dockerfile.sg_only swapped in
355+ # so the agent has NO local source code and must use Sourcegraph MCP tools.
356+ # The verifier's tests/ dir (uploaded by Harbor at runtime) still works
357+ # because oracle_checks.py scores answer.json content, not compiled code.
358+ #
354359# Args: bm task_id task_path bl_jobs_dir full_jobs_dir
355360_launch_task_pair () {
356361 local bm=" $1 " task_id=" $2 " task_path=" $3 " bl_jobs_dir=" $4 " full_jobs_dir=" $5 "
@@ -361,22 +366,10 @@ _launch_task_pair() {
361366 return
362367 fi
363368
364- # Swap Dockerfile once for both configs (artifact mode only).
365- # Idempotent: skip backup if .run_bak already exists (safe on re-run after kill).
366- local _df=" ${abs_path} /environment/Dockerfile"
367- local _df_artifact=" ${abs_path} /environment/Dockerfile.artifact_only"
368- local _df_swapped=false
369- if [[ " $FULL_CONFIG " == * -artifact ]] && [ -f " $_df_artifact " ]; then
370- if [ ! -f " ${_df} .run_bak" ]; then
371- cp " $_df " " ${_df} .run_bak"
372- fi
373- cp " $_df_artifact " " $_df "
374- _df_swapped=true
375- fi
376-
377369 local pair_pids=()
370+ local _mcp_temp_dir=" "
378371
379- # Launch baseline config
372+ # Launch baseline config — uses original Dockerfile (full local repos)
380373 if [ " $RUN_BASELINE " = true ]; then
381374 _wait_for_slot
382375 local _bl_home
@@ -400,15 +393,30 @@ _launch_task_pair() {
400393 sleep 2
401394 fi
402395
403- # Launch full/MCP config
396+ # Launch full/MCP config — uses Dockerfile.sg_only (no local source code)
404397 if [ " $RUN_FULL " = true ]; then
398+ local _mcp_task_path=" $abs_path "
399+ local _df_sgonly=" ${abs_path} /environment/Dockerfile.sg_only"
400+
401+ # Create temp copy with Dockerfile.sg_only swapped in.
402+ # This ensures baseline sees the original Dockerfile while MCP sees sg_only.
403+ if [ -f " $_df_sgonly " ]; then
404+ _mcp_temp_dir=$( mktemp -d " /tmp/mcp_${task_id} _XXXXXX" )
405+ cp -a " ${abs_path} /." " ${_mcp_temp_dir} /"
406+ cp " ${_mcp_temp_dir} /environment/Dockerfile.sg_only" " ${_mcp_temp_dir} /environment/Dockerfile"
407+ _mcp_task_path=" $_mcp_temp_dir "
408+ echo " [sg_only] Using empty-workspace Dockerfile for MCP config: $task_id "
409+ else
410+ echo " WARNING: No Dockerfile.sg_only for $task_id — MCP will have local source access"
411+ fi
412+
405413 _wait_for_slot
406414 local _full_home
407415 _full_home=$( _next_account)
408416 (
409417 export HOME=" $_full_home "
410418 BASELINE_MCP_TYPE=$FULL_MCP_TYPE harbor run \
411- --path " $abs_path " \
419+ --path " $_mcp_task_path " \
412420 --agent-import-path " $AGENT_PATH " \
413421 --model " $MODEL " \
414422 --jobs-dir " $full_jobs_dir " \
@@ -423,14 +431,14 @@ _launch_task_pair() {
423431 sleep 2
424432 fi
425433
426- # Background watcher: restore Dockerfile after BOTH pair configs complete .
434+ # Background watcher: clean up temp dir after MCP config completes .
427435 # Not counted in _PIDS (it's cleanup, not a work slot).
428- if [ " $_df_swapped " = true ] && [ " ${# pair_pids[@]} " -gt 0 ]; then
436+ if [ -n " $_mcp_temp_dir " ] && [ " ${# pair_pids[@]} " -gt 0 ]; then
429437 (
430438 for p in " ${pair_pids[@]} " ; do
431439 wait " $p " 2> /dev/null || true
432440 done
433- [ -f " ${_df} .run_bak " ] && mv " ${_df} .run_bak " " $_df "
441+ rm -rf " $_mcp_temp_dir " 2> /dev/null || true
434442 ) &
435443 fi
436444}
0 commit comments