File size: 9,051 Bytes
e2d5b71
 
 
 
 
 
 
 
 
 
 
ced8fd0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ff41d2c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
---
title: CodeReviewEnv
emoji: πŸ”
colorFrom: indigo
colorTo: blue
sdk: docker
app_port: 7860
pinned: false
tags:
  - openenv
---
# πŸ” CodeReviewEnv

> An OpenEnv-compliant benchmark environment where AI agents act as senior engineers reviewing pull requests β€” catching bugs, finding security holes, and fixing broken code.

---

## Overview & Motivation

Code review is one of the highest-leverage activities in software engineering, yet it is time-consuming, inconsistent, and cognitively demanding. A model that can reliably triage pull requests, identify security vulnerabilities, and produce corrected patches would meaningfully accelerate software delivery.

**CodeReviewEnv** simulates exactly this. Three tasks of increasing difficulty present agents with realistic pull requests containing planted defects. The agent must reason over code, report issues with structured annotations, submit a corrected patch, and deliver a final verdict β€” all within a bounded step budget.

---

## Environment Architecture

```
code-review-env/
β”œβ”€β”€ env.py               # Core OpenEnv environment (reset / step / state)
β”œβ”€β”€ server.py            # FastAPI HTTP server exposing the OpenEnv interface
β”œβ”€β”€ models.py            # Pydantic typed models: Action, Observation, Reward, State
β”œβ”€β”€ openenv.yaml         # OpenEnv metadata
β”œβ”€β”€ tasks/
β”‚   β”œβ”€β”€ task1_easy.py    # Bug hunt: simple Python utility
β”‚   β”œβ”€β”€ task2_medium.py  # Security audit: Flask auth endpoint
β”‚   └── task3_hard.py    # Correctness: distributed LRU cache
β”œβ”€β”€ graders/
β”‚   └── grader.py        # Deterministic keyword + AST graders
β”œβ”€β”€ agents/
β”‚   └── baseline_agent.py  # HF Inference API baseline (OpenAI-compatible)
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ requirements.txt
└── README.md
```

---

## Action Space

Each agent turn is a single `ReviewAction` JSON object:

| Field | Type | Description |
|---|---|---|
| `action_type` | `"review" \| "patch" \| "comment" \| "submit"` | What the agent is doing |
| `severity` | `"critical" \| "major" \| "minor" \| "info"` | Issue severity (for `review`) |
| `issue_type` | `"bug" \| "security" \| "performance" \| "logic" \| "style"` | Issue category |
| `line_number` | `int \| null` | Line the issue is on |
| `description` | `str` | Concise natural-language description of the issue |
| `patched_code` | `str \| null` | Full corrected code (for `patch` actions) |
| `comment` | `str \| null` | Free-form annotation |
| `verdict` | `"approve" \| "request_changes" \| "reject"` | Final verdict (for `submit`) |
| `confidence` | `float [0.0, 1.0]` | Agent's self-reported confidence |

---

## Observation Space

Each step returns an `Observation` containing:

| Field | Description |
|---|---|
| `task_id` | Identifier of the current task |
| `step` / `max_steps` | Current step and budget |
| `review_context` | Full PR: title, author, description, code files, linter output, test results |
| `previous_actions` | All actions taken so far this episode |
| `issues_found_so_far` | Structured list of issues reported |
| `score_so_far` | Running cumulative intermediate reward |
| `done` | Whether the episode has ended |

---

## Reward Function

Reward is **dense** β€” provided at every step, not only at the end.

### Intermediate (per-step)

| Signal | Value | Rationale |
|---|---|---|
| Step penalty | βˆ’0.01 | Encourages efficiency |
| Review with description | +0.05 | Rewards substantive annotations |
| Critical severity bonus | +0.03 | Rewards correct triage |
| Patch submitted | +0.10 | Rewards producing a fix |
| Repetition penalty | βˆ’0.05 | Penalises looping / copy-paste |

### Terminal (on `submit` or step exhaustion)

The programmatic grader runs and returns a score in **[0.0, 1.0]** based on which issues were correctly identified and how well the submitted patch addresses them. This final score overwrites the episode total.

---

## Tasks

### Task 1 β€” Easy: Bug Hunt (`task_1_easy_bug_hunt`)

**Max steps:** 8  
**File reviewed:** `utils.py` (Python, 30 lines)

A developer submits three utility functions. Three bugs are planted:

| # | Line | Bug | Severity |
|---|---|---|---|
| 1 | 3 | `=` (assignment) used instead of `==` (comparison) β€” causes `SyntaxError` | Critical |
| 2 | 6 | `range(1, len(numbers) + 1)` β€” off-by-one causes `IndexError` | Critical |
| 3 | 9 | Missing `return max_val` β€” function silently returns `None` | Major |

**Grading:** 30% per critical bug identified, 20% for minor, 20% for a syntactically valid patch with all three fixes applied.

---

### Task 2 β€” Medium: Security Audit (`task_2_medium_security`)

**Max steps:** 12  
**File reviewed:** `auth.py` (Flask, 55 lines)

A backend developer submits login and registration endpoints. Six security vulnerabilities are present:

| # | Line | Vulnerability | Severity |
|---|---|---|---|
| 1 | 23 | SQL injection in `login` query (f-string interpolation) | Critical |
| 2 | 44 | SQL injection in `register` INSERT | Critical |
| 3 | 39 | Plaintext password storage (no hashing) | Critical |
| 4 | β€” | No rate limiting on `/login` (brute-force possible) | Major |
| 5 | 30 | Sensitive data leakage: error distinguishes "wrong password" vs "user not found" | Major |
| 6 | 5 | Hardcoded `secret_key` in source | Major |

**Grading:** Weighted by severity. Patch checked for parameterized queries, password hashing, and environment variable use.

---

### Task 3 β€” Hard: Distributed Systems Correctness (`task_3_hard_perf_correctness`)

**Max steps:** 16  
**File reviewed:** `cache.py` (Python, 55 lines)

A senior engineer submits a Redis-backed LRU cache claimed to be production-ready. Six issues lurk:

| # | Issue | Type | Severity |
|---|---|---|---|
| 1 | Non-atomic `EXISTS` + `GET` creates a race condition | Concurrency | Critical |
| 2 | Local `dict` grows unboundedly β€” `capacity` parameter ignored | Performance | Critical |
| 3 | `get_many` calls `self.get()` in a loop (N+1 round trips) | Performance | Major |
| 4 | `dict` preserves insertion order, not access order β€” LRU eviction is wrong | Logic | Major |
| 5 | Shared `dict` modified without a `threading.Lock` | Concurrency | Critical |
| 6 | `pickle.loads` on bytes from Redis β€” arbitrary code execution | Security | Critical |

**Grading:** Equally weighted. Patch checked structurally for `threading.Lock`, `OrderedDict.move_to_end`, `mget`, and `json` instead of `pickle`.

---

## Baseline Performance

Evaluated with `Qwen/Qwen2.5-72B-Instruct` via Hugging Face Inference API:

| Task | Score |
|---|---|
| Task 1 β€” Easy | 0.72 |
| Task 2 β€” Medium | 0.55 |
| Task 3 β€” Hard | 0.38 |
| **Aggregate** | **0.55** |

---

## Setup & Usage

### 1. Local (Python)

```bash
git clone <repo>
cd code-review-env
pip install -r requirements.txt
python server.py
# Server running at http://localhost:7860
```

### 2. Docker

```bash
docker build -t code-review-env .
docker run -p 7860:7860 code-review-env
```

### 3. API Quickstart

```bash
# Reset to task 1
curl -X POST http://localhost:7860/reset \
  -H "Content-Type: application/json" \
  -d '{"task_id": "task_1_easy_bug_hunt"}'

# Take a step
curl -X POST http://localhost:7860/step \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "<session_id>",
    "action": {
      "action_type": "review",
      "severity": "critical",
      "issue_type": "bug",
      "line_number": 3,
      "description": "Assignment operator = used instead of comparison == on line 3"
    }
  }'
```

### 4. Run inference script

```bash
export HF_TOKEN=hf_your_token_here
export API_BASE_URL=https://router.huggingface.co/v1
export MODEL_NAME=Qwen/Qwen2.5-72B-Instruct
python inference.py
```

Expected stdout format:
```
[START] task=task_1_easy_bug_hunt env=code-review-env model=Qwen/Qwen2.5-72B-Instruct
[STEP] step=1 action=review:assignment operator = instead of == reward=0.07 done=false error=null
[STEP] step=2 action=review:off-by-one in range reward=0.07 done=false error=null
[STEP] step=3 action=patch:fixed code reward=0.10 done=false error=null
[STEP] step=4 action=submit:request_changes reward=1.00 done=true error=null
[END] success=true steps=4 score=1.000 rewards=0.07,0.07,0.10,1.00
```

### 5. OpenEnv validation

```bash
openenv validate .
```

---

## HTTP API Reference

| Method | Endpoint | Description |
|---|---|---|
| `GET` | `/` | Environment info |
| `GET` | `/tasks` | List all tasks |
| `POST` | `/reset` | Start a new episode |
| `POST` | `/step` | Take an action |
| `GET` | `/state/{session_id}` | Inspect full environment state |
| `DELETE` | `/session/{session_id}` | Clean up session |

---

## Hugging Face Spaces Deployment

The `Dockerfile` targets port `7860` and runs as a non-root user β€” compatible with HF Spaces Docker SDK out of the box. Tag the Space with `openenv`.

```yaml
# README header for HF Spaces
---
title: CodeReviewEnv
emoji: πŸ”
colorFrom: indigo
colorTo: blue
sdk: docker
pinned: false
tags:
  - openenv
---
```
"# CodeReviewEnv"