Skip to content

Commit 9f5fc73

Browse files
sjarmakclaude
andcommitted
feat: eliminate clone+backup+truncate from sg_only Dockerfiles (v2 clone-at-verify)
Replace the /repo_full/ backup pattern with clone-at-verify: build-requiring Dockerfile.sg_only files now embed a JSON clone manifest instead of cloning, backing up to /repo_full/, and truncating. The verifier wrapper reads the manifest and clones mirrors with --depth 1 at verification time. Key changes: - scripts/sgonly_verifier_wrapper.sh: clone from manifest, legacy /repo_full/ fallback - scripts/generate_sgonly_dockerfiles.py: CCB_REPO_BASE_MAP, extract_clone_layout(), generate_build_requiring() v2 with SWE-bench/code-review/multi-repo variants - 190 Dockerfile.sg_only regenerated (128 build-requiring, 62 write-only) - 128 verifier wrappers updated with v2 clone-at-verify logic This eliminates ~100MB-2GB /repo_full/ backup per image and ~60% build time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 43261e9 commit 9f5fc73

File tree

315 files changed

+23727
-5657
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

315 files changed

+23727
-5657
lines changed
Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
# bustub-hyperloglog-impl-001 — sg_only_env variant
2-
# Source files truncated so agent must use Sourcegraph MCP for code access.
3-
# Verifier wrapper restores full repo before running tests.
2+
# No local repo clone — agent uses Sourcegraph MCP exclusively for code access.
43

5-
# TAC Task Wrapper: sde-implement-hyperloglog
6-
FROM ghcr.io/theagentcompany/sde-implement-hyperloglog-image:1.0.0
4+
FROM ubuntu:22.04
75

86
ENV SOURCEGRAPH_REPO_NAME=sg-benchmarks/bustub--d5f79431
97

10-
# Create logs directory for Harbor compatibility
11-
RUN mkdir -p /logs /workspace
8+
ENV DEBIAN_FRONTEND=noninteractive
9+
10+
RUN apt-get update && apt-get install -y --no-install-recommends \
11+
git \
12+
ca-certificates \
13+
python3 \
14+
curl \
15+
&& rm -rf /var/lib/apt/lists/*
1216

13-
# Set working directory
1417
WORKDIR /workspace
1518

16-
# Environment variables
17-
ENV TAC_SERVER_HOSTNAME=localhost
18-
ENV DECRYPTION_KEY="theagentcompany is all you need"
19+
# Empty git repo so agent can commit work
20+
RUN git init && \
21+
git config user.email "agent@example.com" && \
22+
git config user.name "Agent"
23+
24+
RUN mkdir -p /logs/agent /logs/verifier
1925

26+
# Mark sg_only mode so verifiers can skip local-path checks
27+
RUN touch /tmp/.sg_only_mode
2028

21-
# --- sg_only_env: back up full repo, then truncate source ---
22-
RUN cp -a /workspace /repo_full
23-
RUN find /workspace -type f \( -name "*.py" -o -name "*.pyx" -o -name "*.pyi" -o -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -o -name "*.mjs" -o -name "*.cjs" -o -name "*.mts" -o -name "*.cts" -o -name "*.go" -o -name "*.java" -o -name "*.kt" -o -name "*.scala" -o -name "*.groovy" -o -name "*.clj" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" -o -name "*.cxx" -o -name "*.h" -o -name "*.hh" -o -name "*.hpp" -o -name "*.hxx" -o -name "*.rs" -o -name "*.rb" -o -name "*.cs" -o -name "*.fs" -o -name "*.swift" -o -name "*.m" -o -name "*.mm" -o -name "*.vue" -o -name "*.svelte" -o -name "*.sh" -o -name "*.bash" -o -name "*.zsh" -o -name "*.lua" -o -name "*.proto" -o -name "*.thrift" -o -name "*.avsc" -o -name "*.fbs" -o -name "*.yaml" -o -name "*.yml" -o -name "*.toml" -o -name "*.json" -o -name "*.xml" -o -name "*.ini" -o -name "*.cfg" -o -name "*.md" -o -name "*.rst" -o -name "*.txt" -o -name "*.adoc" -o -name "*.cmake" -o -name "*.bzl" -o -name "*.bazel" -o -name "*.sql" -o -name "*.erl" -o -name "*.ex" -o -name "*.exs" -o -name "*.php" -o -name "*.pl" -o -name "*.pm" -o -name "*.r" -o -name "*.R" \) ! -path "*/.git/*" ! -path "*/node_modules/*" ! -path "*/__pycache__/*" ! -path "*/vendor/*" -exec truncate -s 0 {} \;
24-
# Recommit truncated state so git history cannot recover full files.
25-
# Without this, `git show HEAD:<file>` or `git checkout HEAD -- <file>`
26-
# would bypass truncation by reading from the pre-truncation commit.
27-
RUN cd /workspace && git config user.email "agent@example.com" && git config user.name "Agent" && git add -A && git commit -m "sg_only truncation" --allow-empty --quiet
28-
RUN touch /tmp/.sg_only_mode && echo '/workspace' > /tmp/.sg_only_workdir
29-
CMD ["bash"]
29+
ENTRYPOINT []
Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,42 @@
1-
# camel-fix-protocol-feat-001 — sg_only_env variant
2-
# Source files truncated so agent must use Sourcegraph MCP for code access.
3-
# Verifier wrapper restores full repo before running tests.
1+
# camel-fix-protocol-feat-001 — sg_only_env variant (v2: clone-at-verify)
2+
# Empty workspace — agent uses Sourcegraph MCP for code access.
3+
# Verifier clones mirror at verification time via clone manifest.
44

5-
FROM ccb-repo-camel-1006f047
5+
FROM eclipse-temurin:17-jdk
66

77
ENV SOURCEGRAPH_REPO_NAME=sg-benchmarks/camel--1006f047
88

9-
# --- sg_only_env: back up full repo, then truncate source ---
10-
RUN cp -a /workspace /repo_full
11-
RUN find /workspace -type f \( \
12-
-name "*.java" -o -name "*.xml" -o -name "*.yaml" -o -name "*.yml" \
13-
-o -name "*.json" -o -name "*.properties" -o -name "*.sh" -o -name "*.md" \
14-
-o -name "*.txt" -o -name "*.toml" -o -name "*.gradle" -o -name "*.kt" \
15-
-o -name "*.scala" -o -name "*.groovy" -o -name "*.py" \
16-
\) ! -path "*/.git/*" -exec truncate -s 0 {} \;
17-
# Recommit truncated state so git history cannot recover full files.
18-
RUN cd /workspace && git add -A && git commit -m "sg_only truncation" --allow-empty --quiet
19-
RUN touch /tmp/.sg_only_mode && echo '/workspace' > /tmp/.sg_only_workdir
9+
ENV DEBIAN_FRONTEND=noninteractive
10+
11+
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
git \
13+
curl \
14+
python3 \
15+
python3-pip \
16+
ca-certificates \
17+
&& rm -rf /var/lib/apt/lists/*
2018

2119
WORKDIR /workspace
20+
21+
# Empty git repo so agent can commit work
22+
RUN git init && \
23+
git config user.email "agent@example.com" && \
24+
git config user.name "Agent"
25+
26+
RUN mkdir -p /logs/agent /logs/verifier
27+
28+
# Clone manifest for verifier (clone-at-verify strategy)
29+
RUN echo '{
30+
"workdir": "/workspace",
31+
"repos": [
32+
{
33+
"mirror": "sg-benchmarks/camel--1006f047",
34+
"target_dir": "."
35+
}
36+
]
37+
}' > /tmp/.sg_only_clone_manifest.json
38+
39+
# Mark sg_only mode
40+
RUN touch /tmp/.sg_only_mode
41+
2242
ENTRYPOINT []
Lines changed: 150 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
11
#!/bin/bash
2-
# SG-only verifier wrapper: restore truncated source files from backup
2+
# SG-only verifier wrapper: restore full repo + overlay agent changes
33
#
44
# Source this at the TOP of test.sh for build-requiring tasks that use
5-
# sg_only_env mode. It detects /tmp/.sg_only_mode and restores truncated
6-
# (0-byte) source files from /repo_full/ while preserving agent changes.
5+
# sg_only_env mode. It detects /tmp/.sg_only_mode and:
76
#
8-
# Key insight: the sg_only Dockerfile truncates source files to 0 bytes.
9-
# Agent-written files are non-zero. So restoring only 0-byte files from
10-
# /repo_full/ recovers the full codebase without touching agent work.
11-
# This avoids the expensive delete+copy cycle on large repos (e.g. 9GB
12-
# ProtonMail monorepo with 135K node_modules entries).
7+
# PRIMARY PATH (clone manifest):
8+
# 1. Reads clone manifest from /tmp/.sg_only_clone_manifest.json
9+
# 2. Backs up agent-written files (non-empty, non-git, non-test)
10+
# 3. Clones each mirror repo with --depth 1
11+
# 4. Re-runs inject_defects.sh if specified in manifest
12+
# 5. Overlays agent changes on top
13+
#
14+
# LEGACY FALLBACK (pre-v2 images):
15+
# If manifest is missing but /repo_full/ exists, restores from /repo_full/
16+
# as before. This ensures unregenerated images still work during rollout.
1317
#
1418
# For non-sg_only runs, this script is a no-op.
1519
#
1620
# Usage in test.sh:
1721
# #!/bin/bash
18-
# [ -f /tmp/.sg_only_mode ] && [ -f /tests/sgonly_verifier_wrapper.sh ] && source /tests/sgonly_verifier_wrapper.sh
22+
# # Source the sg_only wrapper (no-op if not in sg_only mode)
23+
# if [ -f /tests/sgonly_verifier_wrapper.sh ]; then
24+
# source /tests/sgonly_verifier_wrapper.sh
25+
# fi
1926
# # ... rest of test.sh as normal ...
2027

2128
if [ ! -f /tmp/.sg_only_mode ]; then
@@ -25,6 +32,130 @@ fi
2532

2633
echo "[sg_only_verifier] Detected sg_only mode, restoring full repo..."
2734

35+
# ---------------------------------------------------------------------------
36+
# Helper: back up agent-written files from a directory
37+
# ---------------------------------------------------------------------------
38+
backup_agent_files() {
39+
local srcdir="$1"
40+
if [ ! -d "$srcdir" ]; then
41+
return
42+
fi
43+
cd "$srcdir"
44+
mkdir -p /tmp/agent_work
45+
find . -type f -size +0 \
46+
! -path './.git/*' \
47+
! -path './tests/*' \
48+
! -path './.claude/*' \
49+
-print0 | while IFS= read -r -d '' f; do
50+
mkdir -p "/tmp/agent_work/$(dirname "$f")"
51+
cp "$f" "/tmp/agent_work/$f"
52+
done
53+
echo "[sg_only_verifier] Backed up agent-written files from $srcdir"
54+
}
55+
56+
# ---------------------------------------------------------------------------
57+
# Helper: overlay agent-written files back onto a directory
58+
# ---------------------------------------------------------------------------
59+
overlay_agent_files() {
60+
local targetdir="$1"
61+
if [ ! -d /tmp/agent_work ]; then
62+
return
63+
fi
64+
cd /tmp/agent_work
65+
find . -type f -print0 | while IFS= read -r -d '' f; do
66+
local target="${targetdir}/${f#./}"
67+
mkdir -p "$(dirname "$target")"
68+
cp "$f" "$target"
69+
done
70+
echo "[sg_only_verifier] Overlaid agent changes onto $targetdir"
71+
}
72+
73+
# ---------------------------------------------------------------------------
74+
# PRIMARY PATH: clone manifest
75+
# ---------------------------------------------------------------------------
76+
MANIFEST="/tmp/.sg_only_clone_manifest.json"
77+
78+
if [ -f "$MANIFEST" ]; then
79+
echo "[sg_only_verifier] Found clone manifest, using clone-at-verify strategy"
80+
81+
# Parse manifest with python3 (always available in our images)
82+
WORKDIR=$(python3 -c "import json; m=json.load(open('$MANIFEST')); print(m.get('workdir', '/workspace'))")
83+
echo "[sg_only_verifier] Working directory: $WORKDIR"
84+
85+
# 1. Back up agent-written files
86+
backup_agent_files "$WORKDIR"
87+
88+
# 2. Clone each mirror repo
89+
REPO_COUNT=$(python3 -c "import json; m=json.load(open('$MANIFEST')); print(len(m.get('repos', [])))")
90+
for i in $(seq 0 $((REPO_COUNT - 1))); do
91+
MIRROR=$(python3 -c "import json; m=json.load(open('$MANIFEST')); print(m['repos'][$i]['mirror'])")
92+
TARGET_DIR=$(python3 -c "import json; m=json.load(open('$MANIFEST')); print(m['repos'][$i].get('target_dir', '.'))")
93+
CLONE_URL="https://github.com/${MIRROR}.git"
94+
95+
if [ "$TARGET_DIR" = "." ]; then
96+
CLONE_TARGET="$WORKDIR"
97+
else
98+
CLONE_TARGET="${WORKDIR}/${TARGET_DIR}"
99+
fi
100+
101+
echo "[sg_only_verifier] Cloning $MIRROR -> $CLONE_TARGET"
102+
103+
# Remove existing directory contents (truncated files) but preserve .git
104+
# for target_dir="." we need to be careful with the working directory
105+
if [ "$TARGET_DIR" = "." ]; then
106+
# For root workspace: remove everything except .git, then clone into temp and move
107+
TMPCLONE=$(mktemp -d)
108+
if git clone --depth 1 "$CLONE_URL" "$TMPCLONE" 2>/dev/null; then
109+
# Remove old files (except .git and tests)
110+
find "$CLONE_TARGET" -mindepth 1 -maxdepth 1 \
111+
! -name '.git' ! -name 'tests' ! -name '.claude' \
112+
-exec rm -rf {} + 2>/dev/null || true
113+
# Copy cloned files (except .git)
114+
cd "$TMPCLONE"
115+
find . -mindepth 1 -maxdepth 1 ! -name '.git' -exec cp -a {} "$CLONE_TARGET/" \;
116+
cd /
117+
rm -rf "$TMPCLONE"
118+
echo "[sg_only_verifier] Restored $MIRROR to $CLONE_TARGET"
119+
else
120+
echo "[sg_only_verifier] WARNING: Failed to clone $CLONE_URL"
121+
rm -rf "$TMPCLONE"
122+
fi
123+
else
124+
# For subdirectory: remove and re-clone
125+
rm -rf "$CLONE_TARGET"
126+
if git clone --depth 1 "$CLONE_URL" "$CLONE_TARGET" 2>/dev/null; then
127+
echo "[sg_only_verifier] Restored $MIRROR to $CLONE_TARGET"
128+
else
129+
echo "[sg_only_verifier] WARNING: Failed to clone $CLONE_URL"
130+
fi
131+
fi
132+
done
133+
134+
# 3. Re-run inject_defects if specified
135+
INJECT_SCRIPT=$(python3 -c "import json; m=json.load(open('$MANIFEST')); print(m.get('inject_defects', ''))")
136+
if [ -n "$INJECT_SCRIPT" ] && [ -f "$INJECT_SCRIPT" ]; then
137+
echo "[sg_only_verifier] Running defect injection: $INJECT_SCRIPT"
138+
cd "$WORKDIR"
139+
chmod +x "$INJECT_SCRIPT"
140+
bash "$INJECT_SCRIPT"
141+
echo "[sg_only_verifier] Defect injection complete"
142+
fi
143+
144+
# 4. Overlay agent changes
145+
overlay_agent_files "$WORKDIR"
146+
147+
# Return to working directory
148+
cd "$WORKDIR"
149+
echo "[sg_only_verifier] Clone-at-verify restore complete, proceeding with tests"
150+
151+
return 0 2>/dev/null || exit 0
152+
fi
153+
154+
# ---------------------------------------------------------------------------
155+
# LEGACY FALLBACK: /repo_full/ restore (for pre-v2 images)
156+
# ---------------------------------------------------------------------------
157+
echo "[sg_only_verifier] No clone manifest found, trying legacy /repo_full/ restore..."
158+
28159
# Read the working directory
29160
WORKDIR="$(cat /tmp/.sg_only_workdir 2>/dev/null || echo '/app')"
30161
echo "[sg_only_verifier] Working directory: $WORKDIR"
@@ -34,18 +165,16 @@ if [ ! -d /repo_full ]; then
34165
return 0 2>/dev/null || exit 0
35166
fi
36167

37-
# Restore truncated files: find 0-byte files and bulk-copy originals from
38-
# backup using tar pipe (orders of magnitude faster than individual cp on
39-
# repos with 100K+ truncated files like ProtonMail's node_modules).
40-
# Agent-written files are non-zero and will not be touched.
41-
cd "$WORKDIR"
42-
find . -type f -size 0 \
43-
! -path './.git/*' ! -path './tests/*' ! -path './.claude/*' \
44-
! -path './node_modules/*' ! -path './__pycache__/*' ! -path './vendor/*' \
45-
-print0 | (cd /repo_full && tar --null -T - -cf - 2>/dev/null) \
46-
| tar xf - -C "$WORKDIR/" 2>/dev/null
47-
echo "[sg_only_verifier] Restored truncated files from /repo_full/"
168+
# 1. Find files the agent wrote (non-empty, non-git, non-test files)
169+
backup_agent_files "$WORKDIR"
170+
171+
# 2. Restore full repo from backup
172+
rsync -a --delete /repo_full/ "$WORKDIR/"
173+
echo "[sg_only_verifier] Restored full repo from /repo_full/"
174+
175+
# 3. Overlay agent's changes
176+
overlay_agent_files "$WORKDIR"
48177

49178
# Return to working directory
50179
cd "$WORKDIR"
51-
echo "[sg_only_verifier] Restore complete, proceeding with tests"
180+
echo "[sg_only_verifier] Legacy restore complete, proceeding with tests"
Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
1-
# cgen-deps-install-001 — sg_only_env variant
2-
# Source files truncated so agent must use Sourcegraph MCP for code access.
3-
# Verifier wrapper restores full repo before running tests.
1+
# cgen-deps-install-001 — sg_only_env variant (v2: clone-at-verify)
2+
# Empty workspace — agent uses Sourcegraph MCP for code access.
3+
# Verifier clones mirror(s) at verification time via clone manifest.
44

55
FROM ubuntu:22.04
66

77
ENV SOURCEGRAPH_REPO_NAME=sg-benchmarks/cgen--dibench
88

99
ENV DEBIAN_FRONTEND=noninteractive
1010

11-
RUN apt-get update -qq && apt-get install -y -qq --no-install-recommends \
12-
python3 python3-pip git curl ca-certificates \
11+
RUN apt-get update && apt-get install -y --no-install-recommends \
12+
git \
13+
ca-certificates \
14+
python3 \
15+
curl \
1316
&& rm -rf /var/lib/apt/lists/*
1417

15-
# Python already installed above
16-
# Copy repo
17-
COPY repo /app/repo
18-
1918
WORKDIR /app/repo
2019

21-
# --- sg_only_env: back up full repo, then truncate source ---
22-
RUN cp -a /app/repo /repo_full
23-
RUN find /app/repo -type f \( -name "*.py" -o -name "*.pyx" -o -name "*.pyi" -o -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -o -name "*.mjs" -o -name "*.cjs" -o -name "*.mts" -o -name "*.cts" -o -name "*.go" -o -name "*.java" -o -name "*.kt" -o -name "*.scala" -o -name "*.groovy" -o -name "*.clj" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" -o -name "*.cxx" -o -name "*.h" -o -name "*.hh" -o -name "*.hpp" -o -name "*.hxx" -o -name "*.rs" -o -name "*.rb" -o -name "*.cs" -o -name "*.fs" -o -name "*.swift" -o -name "*.m" -o -name "*.mm" -o -name "*.vue" -o -name "*.svelte" -o -name "*.sh" -o -name "*.bash" -o -name "*.zsh" -o -name "*.lua" -o -name "*.proto" -o -name "*.thrift" -o -name "*.avsc" -o -name "*.fbs" -o -name "*.yaml" -o -name "*.yml" -o -name "*.toml" -o -name "*.json" -o -name "*.xml" -o -name "*.ini" -o -name "*.cfg" -o -name "*.md" -o -name "*.rst" -o -name "*.txt" -o -name "*.adoc" -o -name "*.cmake" -o -name "*.bzl" -o -name "*.bazel" -o -name "*.sql" -o -name "*.erl" -o -name "*.ex" -o -name "*.exs" -o -name "*.php" -o -name "*.pl" -o -name "*.pm" -o -name "*.r" -o -name "*.R" \) ! -path "*/.git/*" ! -path "*/node_modules/*" ! -path "*/__pycache__/*" ! -path "*/vendor/*" -exec truncate -s 0 {} \;
24-
# Recommit truncated state so git history cannot recover full files.
25-
# Without this, `git show HEAD:<file>` or `git checkout HEAD -- <file>`
26-
# would bypass truncation by reading from the pre-truncation commit.
27-
RUN cd /app/repo && git config user.email "agent@example.com" && git config user.name "Agent" && git add -A && git commit -m "sg_only truncation" --allow-empty --quiet
28-
RUN touch /tmp/.sg_only_mode && echo '/app/repo' > /tmp/.sg_only_workdir
29-
30-
WORKDIR /app/repo
20+
# Empty git repo so agent can commit work
21+
RUN git init && \
22+
git config user.email "agent@example.com" && \
23+
git config user.name "Agent"
24+
25+
RUN mkdir -p /logs/agent /logs/verifier
26+
27+
# Clone manifest for verifier (clone-at-verify strategy)
28+
RUN echo '{
29+
"workdir": "/app/repo",
30+
"repos": [
31+
{
32+
"mirror": "sg-benchmarks/cgen--dibench",
33+
"target_dir": "."
34+
}
35+
]
36+
}' > /tmp/.sg_only_clone_manifest.json
37+
38+
# Mark sg_only mode
39+
RUN touch /tmp/.sg_only_mode
3140

3241
ENTRYPOINT []

0 commit comments

Comments
 (0)