File size: 5,240 Bytes
3bfeaae
 
 
 
 
9a7cbe0
3bfeaae
 
 
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
 
464ced6
3bfeaae
 
 
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464ced6
3bfeaae
 
 
 
464ced6
 
 
3bfeaae
 
 
 
9a7cbe0
 
5274271
 
 
464ced6
5274271
 
9a7cbe0
 
 
 
 
 
 
464ced6
9a7cbe0
464ced6
9a7cbe0
464ced6
9a7cbe0
464ced6
9a7cbe0
 
 
464ced6
9a7cbe0
 
 
 
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
"""Task catalog for the Codebug debugging benchmark."""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Dict, List


@dataclass(frozen=True)
class DebugTask:
    """Immutable task bundle used by the environment and grader."""

    task_id: str
    difficulty: str
    instruction: str
    grader_id: str
    source: str
    entrypoint_call: str
    hidden_test_source: str
    expected_bug_lines: List[int]
    patch_budget_lines: int
    max_steps: int


TASKS: List[DebugTask] = [
    DebugTask(
        task_id="easy_off_by_one",
        difficulty="easy",
        instruction=(
            "Fix the logic bug so aggregate_range returns the inclusive sum from 1 to n."
        ),
        grader_id="grade_easy_off_by_one",
        source="""def aggregate_range(n: int) -> int:
    total = 0
    for value in range(1, n):
        total += value
    return total


def render_report(n: int) -> str:
    return f"sum={aggregate_range(n)}"
""",
        entrypoint_call="render_report(5)",
        hidden_test_source="""from target import aggregate_range, render_report


def test_aggregate_range_small():
    assert aggregate_range(1) == 1
    assert aggregate_range(5) == 15


def test_render_report():
    assert render_report(4) == "sum=10"
""",
        expected_bug_lines=[3],
        patch_budget_lines=2,
        max_steps=8,
    ),
    DebugTask(
        task_id="medium_mutable_default",
        difficulty="medium",
        instruction=(
            "Fix the state-leak bug so collect_tags does not reuse data across calls."
        ),
        grader_id="grade_medium_mutable_default",
        source="""from typing import List, Optional


def collect_tags(tag: str, bucket: List[str] = []) -> List[str]:
    bucket.append(tag)
    return bucket


def build_ticket(title: str, tag: Optional[str] = None) -> dict:
    tags = collect_tags(tag or "general")
    return {"title": title, "tags": tags}
""",
        entrypoint_call="(build_ticket('first', 'bug'), build_ticket('second', 'ops'))",
        hidden_test_source="""from target import build_ticket, collect_tags


def test_collect_tags_isolated():
    assert collect_tags("bug") == ["bug"]
    assert collect_tags("ops") == ["ops"]


def test_build_ticket_isolated():
    first = build_ticket("first", "bug")
    second = build_ticket("second", "ops")
    assert first["tags"] == ["bug"]
    assert second["tags"] == ["ops"]
""",
        expected_bug_lines=[4],
        patch_budget_lines=4,
        max_steps=10,
    ),
    DebugTask(
        task_id="hard_cross_function_corruption",
        difficulty="hard",
        instruction=(
            "Fix the source of the corrupted user record so build_profile returns the "
            "primary email address without crashing."
        ),
        grader_id="grade_hard_cross_function_corruption",
        source="""def normalize_user(payload: dict) -> dict:
    return {
        "name": payload["name"].strip().title(),
        "contact": {"mail": payload["email"].strip().lower()},
    }


def enrich_user(user: dict) -> dict:
    user["contact"]["primary"] = user["contact"]["email"]
    return user


def build_profile(payload: dict) -> str:
    normalized = normalize_user(payload)
    enriched = enrich_user(normalized)
    return f"{enriched['name']} <{enriched['contact']['primary']}>"
""",
        entrypoint_call="build_profile({'name': '  ada lovelace ', 'email': ' ADA@EXAMPLE.COM '})",
        hidden_test_source="""from target import build_profile, enrich_user, normalize_user


def test_normalize_user_schema():
    user = normalize_user({"name": " Ada ", "email": " ADA@EXAMPLE.COM "})
    assert user["contact"]["email"] == "ada@example.com"


def test_build_profile():
    profile = build_profile({"name": " Ada ", "email": " ADA@EXAMPLE.COM "})
    assert profile == "Ada <ada@example.com>"


def test_enrich_user():
    user = {"name": "Ada", "contact": {"email": "ada@example.com"}}
    enriched = enrich_user(user)
    assert enriched["contact"]["primary"] == "ada@example.com"
""",
        expected_bug_lines=[4, 9],
        patch_budget_lines=4,
        max_steps=12,
    ),
]


TASK_BY_ID: Dict[str, DebugTask] = {task.task_id: task for task in TASKS}


def get_task(index: int) -> DebugTask:
    """Return a task using deterministic round-robin selection."""

    return TASKS[index % len(TASKS)]


def get_task_by_id(task_id: str) -> DebugTask:
    """Return a task by public identifier."""

    return TASK_BY_ID[task_id]


def task_catalog() -> List[Dict[str, Any]]:
    """Return public task metadata for validators and UIs."""

    return [
        {
            "task_id": task.task_id,
            "difficulty": task.difficulty,
            "description": task.instruction,
            "instruction": task.instruction,
            "grader_id": task.grader_id,
            "patch_budget_lines": task.patch_budget_lines,
            "max_steps": task.max_steps,
            "grader": {
                "grader_id": task.grader_id,
                "type": "hidden_pytest",
                "scoring_range": [0.0, 1.0],
                "pass_metric": "pass_rate",
                "enabled": True,
            },
        }
        for task in TASKS
    ]