CRUDBench LocalMaxxing v2
Official shard evalTerminal-Bench 2.1 style CRUD API repair tasks, published through the Pro-gated terminal workflow.
Category: software-engineeringEval type: Shard evalQuestions: 2Shards: 2Runs: 2
Dry-run first:
lmx eval shard crudbench-localmaxxing-v2 --base-url http://localhost:8000 --questions 2 --dry-runThen submit with a real model and hardware profile:
lmx eval shard crudbench-localmaxxing-v2 --base-url http://localhost:8000 --questions 2 --model <hfId> --hardware hardware.json --submitScores are pooled by unique question_id; the leaderboard is ranked by Wilson 95% lower bound.
Leaderboard
Qwen/Qwen3.8-27B · 2 runs · 2/2 shards · harness-scoped
100.0%
95% CI 34.2–100.0%
2/2 correct · 100.0% coverage
Stability— historical rerun transparency
Leaderboard rank uses the canonical latest approved answer per question_id. These metrics include historical submissions too, so reruns and changed answers are visible but do not drive rank.
2 historical runs · 2 unique questions
Canonical
100.0%
Row avg
100.0%
Run avg
100.0%
Repeated
0
Changed
0
Runs— sample traces per run
by Lottolabs · shard 2 · 8/28/2026, 1:31:10 PM · cmtczpjii000qlm0156j2fcpo100.0%1/1 correct · 1 correct traces · 0 incorrect traces
by Lottolabs · shard 2 · 8/28/2026, 1:31:10 PM · cmtczpjii000qlm0156j2fcpo
100.0%
Correct samples
sample 1 · product-crud-paginationpass · 100.0% · 65003ms · 4cfcef20a8c7
Question
Finish the product API in `/app/server.py` without adding third-party dependencies.
Required behavior:
- `GET /products?limit=N&offset=N` returns `{items, total, limit, offset}`. Defaults are `limit=20`, `offset=0`; limit must be 1–100 and offset must be non-negative. Invalid values return `400`.
- `PATCH /products/{id}` accepts `name` and/or `price`. Reject an empty update, blank names, and non-positive prices with `400`. Preserve unspecified fields and return `404` for unknown products.
- `DELETE /products/{id}` returns `204` for an existing product and `404` otherwise.
Keep the existing `POST /products` contract and JSON content types working.Rendered prompt
You control a persistent Linux shell session inside a container. State persists across replies: your working directory, environment variables, and background jobs carry over from one command block to the next. Each reply MUST contain exactly one ```bash fenced block containing one or more non-interactive shell commands, which are executed in that same shell; stdout/stderr and exit code are returned. Prefer batching related inspection/edit/test commands instead of spending one model turn per tiny command. When the task is complete, reply with the single token TASK_COMPLETE and no code block. If you need Python/Ruby/Node/etc., run it from bash with a heredoc (for example: python3 <<'PY' ... PY). Avoid dumping huge files; inspect with head/tail/grep/scripts. Bound password crackers and deliberately long-running commands yourself with timeout, but do not prematurely cap package installs, builds, or tests unless they are clearly stuck. Never run foreground servers; start them in the background and verify them.
Agent trace
Turn 1
Assistant
{
"analysis": "The terminal is at a fresh prompt. I need to inspect the existing /app/server.py to understand the current state before making changes.",
"plan": "First, read the contents of /app/server.py to understand the existing code structure, then implement the required endpoints.",
"commands": [
{
"keystrokes": "cat /app/server.py\n",
"duration": 0.5
}
]
}Command
$ cat /app/server.py
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlparse
products = {}
next_id = 1
class Handler(BaseHTTPRequestHandler):
def log_message(self, *_): pass
def send_json(self, status, value):
body = json.dumps(value).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def read_json(self):
try:
value = json.loads(self.rfile.read(int(self.headers.get("Content-Length", "0"))) or b"{}")
return value if isinstance(value, dict) else None
except Exception: return None
def product_id(self):
path = urlparse(self.path).path.strip("/").split("/")
return int(path[1]) if len(path) == 2 and path[0] == "products" and path[1].isdigit() else None
def do_POST(self):
global next_id
if urlparse(self.path).path != "/products": return self.send_json(404, {"error": "not found"})
value = self.read_json()
if not value or not isinstance(value.get("name"), str) or not value["name"].strip() or not isinstance(value.get("price"), (int, float)) or value["price"] <= 0:
return self.send_json(400, {"error": "valid name and price are required"})
product = {"id": next_id, "name": value["name"], "price": value["price"]}
products[next_id] = product; next_id += 1
self.send_json(201, product)
def do_GET(self):
self.send_json(501, {"error": "not implemented"})
def do_PATCH(self):
self.send_json(501, {"error": "not implemented"})
def do_DELETE(self):
self.send_json(501, {"error": "not implemented"})
ThreadingHTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
[exit=0]Turn 2
Assistant
{
"analysis": "I can see the existing server.py with a working POST /products endpoint and stub implementations for GET, PATCH, and DELETE. I need to implement all three endpoints with the specified validation rules.",
"plan": "I'll write the complete server.py with all required endpoints implemented: GET /products with
…[29880 characters truncated — full trace in blob]…
led = 0
def check(desc, actual, expected):
global passed, failed
if actual == expected:
passed += 1
print(f" PASS: {desc}")
else:
failed += 1
print(f" FAIL: {desc} -> got {actual}, expected {expected}")
print("=== POST ===")
s, b = req("POST", "/products", {"name": "A", "price": 1.0})
check("POST valid", (s, b["id"]), (201, 1))
s, b = req("POST", "/products", {"name": "B", "price": 2.0})
check("POST valid 2", (s, b["id"]), (201, 2))
s, b = req("POST", "/products", {"name": "C", "price": 3.0})
check("POST valid 3", (s, b["id"]), (201, 3))
s, b = req("POST", "/products", {"name": "", "price": 1.0})
check("POST blank name", s, 400)
s, b = req("POST", "/products", {"name": "X", "price": -1})
check("POST neg price", s, 400)
print("\n=== GET ===")
s, b = req("GET", "/products")
check("GET default limit", b["limit"], 20)
check("GET default offset", b["offset"], 0)
check("GET total", b["total"], 3)
check("GET items count", len(b["items"]), 3)
s, b = req("GET", "/products?limit=2&offset=1")
check("GET limit=2 offset=1 items", len(b["items"]), 2)
check("GET limit=2 offset=1 first id", b["items"][0]["id"], 2)
check("GET limit=2 offset=1 total", b["total"], 3)
s, b = req("GET", "/products?limit=1&offset=0")
check("GET limit=1 offset=0", len(b["items"]), 1)
s, b = req("GET", "/products?limit=0")
check("GET limit=0 -> 400", s, 400)
s, b = req("GET", "/products?limit=101")
check("GET limit=101 -> 400", s, 400)
s, b = req("GET", "/products?offset=-1")
check("GET offset=-1 -> 400", s, 400)
s, b = req("GET", "/products?limit=abc")
check("GET limit=abc -> 400", s, 400)
s, b = req("GET", "/products?offset=abc")
check("GET offset=abc -> 400", s, 400)
s, b = req("GET", "/products?limit=100")
check("GET limit=100 -> 200", s, 200)
s, b = req("GET", "/products?limit=1")
check("GET limit=1 -> 200", s, 200)
print("\n=== PATCH ===")
s, b = req("PATCH", "/products/1", {"name": "A2"})
check("PATCH name only", (s, b["name"], b["price"]), (200, "A2", 1.0))
s, b = req("PATCH", "/products/1", {"price": 9.9})
check("PATCH price only", (s, b["name"], b["price"]), (200, "A2", 9.9))
s, b = req("PATCH", "/products/2", {"name": "B2", "price": 8.8})
check("PATCH both", (s, b["name"], b["price"]), (200, "B2", 8.8))
s, b = req("PATCH", "/products/1", {})
check("PATCH empty -> 400", s, 400)
s, b = req("PATCH", "/products/1", {"name": " "})
check("PATCH blank name -> 400", s, 400)
s, b = req("PATCH", "/products/1", {"price": 0})
check("PATCH zero price -> 400", s, 400)
s, b = req("PATCH", "/products/1", {"price": -5})
check("PATCH neg price -> 400", s, 400)
s, b = req("PATCH", "/products/999", {"name": "X"})
check("PATCH unknown -> 404", s, 404)
print("\n=== DELETE ===")
s, b = req("DELETE", "/products/3")
check("DELETE existing -> 204", (s, b), (204, None))
s, b = req("DELETE", "/products/3")
check("DELETE again -> 404", s, 404)
s, b = req("DELETE", "/products/999")
check("DELETE unknown -> 404", s, 404)
print("\n=== FINAL STATE ===")
s, b = req("GET", "/products")
check("Final total", b["total"], 2)
check("Final items", [(i["id"], i["name"], i["price"]) for i in b["items"]], [(1, "A2", 9.9), (2, "B2", 8.8)])
print(f"\n{'='*40}")
print(f"Results: {passed} passed, {failed} failed")
TESTEOF
=== POST ===
PASS: POST valid
PASS: POST valid 2
PASS: POST valid 3
PASS: POST blank name
PASS: POST neg price
=== GET ===
PASS: GET default limit
PASS: GET default offset
PASS: GET total
PASS: GET items count
PASS: GET limit=2 offset=1 items
PASS: GET limit=2 offset=1 first id
PASS: GET limit=2 offset=1 total
PASS: GET limit=1 offset=0
PASS: GET limit=0 -> 400
PASS: GET limit=101 -> 400
PASS: GET offset=-1 -> 400
PASS: GET limit=abc -> 400
PASS: GET offset=abc -> 400
PASS: GET limit=100 -> 200
PASS: GET limit=1 -> 200
=== PATCH ===
PASS: PATCH name only
PASS: PATCH price only
PASS: PATCH both
PASS: PATCH empty -> 400
PASS: PATCH blank name -> 400
PASS: PATCH zero price -> 400
PASS: PATCH neg price -> 400
PASS: PATCH unknown -> 404
=== DELETE ===
PASS: DELETE existing -> 204
PASS: DELETE again -> 404
PASS: DELETE unknown -> 404
=== FINAL STATE ===
PASS: Final total
PASS: Final items
========================================
Results: 33 passed, 0 failed
[exit=0]Turn 7
Assistant
{
"analysis": "All 33 tests passed with 0 failures. Every required behavior is verified:\n- GET /products with default limit=20, offset=0, returns {items, total, limit, offset}\n- GET with limit/offset validation (400 for limit<1, limit>100, offset<0, non-numeric values)\n- PATCH /products/{id} with name-only, price-only, both, empty body (400), blank name (400), non-positive price (400), unknown id (404)\n- DELETE /products/{id} returns 204 for existing, 404 for unknown\n- POST /products contract preserved (201 for valid, 400 for invalid)\n- JSON content types working throughout",
"plan": "Clean up the background server process and mark the task as complete.",
"commands": [
{
"keystrokes": "kill %1 2>/dev/null; echo 'Server stopped'\n",
"duration": 0.5
}
],
"task_complete": true
}Command
$ kill %1 2>/dev/null; echo 'Server stopped' Server stopped [exit=0]
Note
Model marked task complete after command batch.
Verifier
[verifier exit=0] reward: 1
by Lottolabs · shard 1 · 8/28/2026, 1:29:56 PM · cmtcznyxp000klm01qqafs0cf100.0%1/1 correct · 1 correct traces · 0 incorrect traces
by Lottolabs · shard 1 · 8/28/2026, 1:29:56 PM · cmtcznyxp000klm01qqafs0cf
100.0%
Correct samples
sample 1 · user-crud-apipass · 100.0% · 36721ms · f26524426201
Question
Complete the JSON user API in `/app/server.py`.
The existing `POST /users` and `GET /users` behavior must keep working. Implement:
- `GET /users/{id}`: return the user or `404`.
- `PUT /users/{id}`: accept a JSON object, update `name` and/or `email`, reject an empty update or empty string values with `400`, preserve unspecified fields, and return the updated user. Return `404` for an unknown ID.
- `DELETE /users/{id}`: delete an existing user and return HTTP `204` with an empty body. Return `404` for an unknown ID.
All JSON responses must set `Content-Type: application/json`. Do not change the port or introduce third-party dependencies.Rendered prompt
You control a persistent Linux shell session inside a container. State persists across replies: your working directory, environment variables, and background jobs carry over from one command block to the next. Each reply MUST contain exactly one ```bash fenced block containing one or more non-interactive shell commands, which are executed in that same shell; stdout/stderr and exit code are returned. Prefer batching related inspection/edit/test commands instead of spending one model turn per tiny command. When the task is complete, reply with the single token TASK_COMPLETE and no code block. If you need Python/Ruby/Node/etc., run it from bash with a heredoc (for example: python3 <<'PY' ... PY). Avoid dumping huge files; inspect with head/tail/grep/scripts. Bound password crackers and deliberately long-running commands yourself with timeout, but do not prematurely cap package installs, builds, or tests unless they are clearly stuck. Never run foreground servers; start them in the background and verify them.
Agent trace
Turn 1
Assistant
{
"analysis": "I need to inspect the current state of /app/server.py to understand the existing implementation before making changes.",
"plan": "First, read the existing server.py file to understand the current structure, then implement the required endpoints.",
"commands": [
{
"keystrokes": "cat /app/server.py\n",
"duration": 0.5
}
]
}Command
$ cat /app/server.py
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
users = {}
next_id = 1
class Handler(BaseHTTPRequestHandler):
def log_message(self, *_):
pass
def send_json(self, status, value):
body = json.dumps(value).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def read_json(self):
try:
size = int(self.headers.get("Content-Length", "0"))
value = json.loads(self.rfile.read(size) or b"{}")
return value if isinstance(value, dict) else None
except (ValueError, json.JSONDecodeError):
return None
def user_id(self):
parts = self.path.strip("/").split("/")
if len(parts) != 2 or parts[0] != "users" or not parts[1].isdigit():
return None
return int(parts[1])
def do_GET(self):
if self.path == "/users":
return self.send_json(200, list(users.values()))
user_id = self.user_id()
if user_id is None or user_id not in users:
return self.send_json(404, {"error": "not found"})
self.send_json(200, users[user_id])
def do_POST(self):
global next_id
if self.path != "/users":
return self.send_json(404, {"error": "not found"})
value = self.read_json()
if not value or not value.get("name") or not value.get("email"):
return self.send_json(400, {"error": "name and email are required"})
user = {"id": next_id, "name": value["name"], "email": value["email"]}
users[next_id] = user
next_id += 1
self.send_json(201, user)
def do_PUT(self):
self.send_json(501, {"error": "not implemented"})
def do_DELETE(self):
self.send_json(501, {"error": "not implemented"})
ThreadingHTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
[exit=0]Turn 2
Assistant
{
"analysis": "The existing server.py has GET /users, GET /users/{id}, and POST /users implemented. PUT and DELETE are stubs returning 501. I need to implement PUT /users/{id} and DELETE
…[17181 characters truncated — full trace in blob]…
ers/2 (204)\ns, b, h = req(\"DELETE\", \"/users/2\")\nprint(f\"DELETE /users/2: {s} body='{b}' CT={h.get('Content-Type')}\")\n\n# GET /users/2 after delete (404)\ns, b, h = req(\"GET\", \"/users/2\")\nprint(f\"GET /users/2 after del: {s} {b} CT={h.get('Content-Type')}\")\n\n# DELETE /users/999 (404)\ns, b, h = req(\"DELETE\", \"/users/999\")\nprint(f\"DELETE /users/999: {s} {b} CT={h.get('Content-Type')}\")\n\n# GET /users/1 to verify preserved fields\ns, b, h = req(\"GET\", \"/users/1\")\nprint(f\"GET /users/1 final: {s} {b} CT={h.get('Content-Type')}\")\n\nprint(\"\\nAll tests done.\")\nPYEOF\n",
"duration": 2.0
}
]
}Command
$ python3 << 'PYEOF'
import urllib.request, json
def req(method, path, data=None):
url = f"http://localhost:8080{path}"
body = json.dumps(data).encode() if data is not None else None
r = urllib.request.Request(url, data=body, method=method)
if body:
r.add_header("Content-Type", "application/json")
try:
resp = urllib.request.urlopen(r)
return resp.status, resp.read().decode(), dict(resp.headers)
except urllib.error.HTTPError as e:
return e.code, e.read().decode(), dict(e.headers)POST user 1
s, b, h = req("POST", "/users", {"name": "Alice", "email": "[email protected]"})
print(f"POST /users: {s} {b} CT={h.get('Content-Type')}")POST user 2
s, b, h = req("POST", "/users", {"name": "Bob", "email": "[email protected]"})
print(f"POST /users: {s} {b} CT={h.get('Content-Type')}")GET /users
s, b, h = req("GET", "/users")
print(f"GET /users: {s} {b} CT={h.get('Content-Type')}")GET /users/1
s, b, h = req("GET", "/users/1")
print(f"GET /users/1: {s} {b} CT={h.get('Content-Type')}")GET /users/999 (404)
s, b, h = req("GET", "/users/999")
print(f"GET /users/999: {s} {b} CT={h.get('Content-Type')}")PUT /users/1 update name only
s, b, h = req("PUT", "/users/1", {"name": "Alice Updated"})
print(f"PUT /users/1 name: {s} {b} CT={h.get('Content-Type')}")PUT /users/1 update email only
s, b, h = req("PUT", "/users/1", {"email": "[email protected]"})
print(f"PUT /users/1 email: {s} {b} CT={h.get('Content-Type')}")PUT /users/1 empty update (400)
s, b, h = req("PUT", "/users/1", {})
print(f"PUT /users/1 empty: {s} {b} CT={h.get('Content-Type')}")PUT /users/1 empty string name (400)
s, b, h = req("PUT", "/users/1", {"name": ""})
print(f"PUT /users/1 empty name: {s} {b} CT={h.get('Content-Type')}")PUT /users/999 (404)
s, b, h = req("PUT", "/users/999", {"name": "X"})
print(f"PUT /users/999: {s} {b} CT={h.get('Content-Type')}")DELETE /users/2 (204)
s, b, h = req("DELETE", "/users/2")
print(f"DELETE /users/2: {s} body='{b}' CT={h.get('Content-Type')}")GET /users/2 after delete (404)
s, b, h = req("GET", "/users/2")
print(f"GET /users/2 after del: {s} {b} CT={h.get('Content-Type')}")DELETE /users/999 (404)
s, b, h = req("DELETE", "/users/999")
print(f"DELETE /users/999: {s} {b} CT={h.get('Content-Type')}")GET /users/1 to verify preserved fields
s, b, h = req("GET", "/users/1")
print(f"GET /users/1 final: {s} {b} CT={h.get('Content-Type')}")
print("\nAll tests done.")
PYEOF
POST /users: 201 {"id": 1, "name": "Alice", "email": "[email protected]"} CT=application/json
POST /users: 201 {"id": 2, "name": "Bob", "email": "[email protected]"} CT=application/json
GET /users: 200 [{"id": 1, "name": "Alice", "email": "[email protected]"}, {"id": 2, "name": "Bob", "email": "[email protected]"}] CT=application/json
GET /users/1: 200 {"id": 1, "name": "Alice", "email": "[email protected]"} CT=application/json
GET /users/999: 404 {"error": "not found"} CT=application/json
PUT /users/1 name: 200 {"id": 1, "name": "Alice Updated", "email": "[email protected]"} CT=application/json
PUT /users/1 email: 200 {"id": 1, "name": "Alice Updated", "email": "[email protected]"} CT=application/json
PUT /users/1 empty: 400 {"error": "empty update"} CT=application/json
PUT /users/1 empty name: 400 {"error": "name must be a non-empty string"} CT=application/json
PUT /users/999: 404 {"error": "not found"} CT=application/json
DELETE /users/2: 204 body='' CT=None
GET /users/2 after del: 404 {"error": "not found"} CT=application/json
DELETE /users/999: 404 {"error": "not found"} CT=application/json
GET /users/1 final: 200 {"id": 1, "name": "Alice Updated", "email": "[email protected]"} CT=application/json
All tests done.
[exit=0]Turn 5
Assistant
{
"analysis": "All tests pass perfectly:\n- POST /users: 201 with correct JSON and Content-Type: application/json ✓\n- GET /users: 200 with list of users ✓\n- GET /users/1: 200 with user object ✓\n- GET /users/999: 404 ✓\n- PUT /users/1 (name only): 200, email preserved ✓\n- PUT /users/1 (email only): 200, name preserved ✓\n- PUT /users/1 (empty {}): 400 ✓\n- PUT /users/1 (empty string name): 400 ✓\n- PUT /users/999: 404 ✓\n- DELETE /users/2: 204 with empty body ✓\n- GET /users/2 after delete: 404 ✓\n- DELETE /users/999: 404 ✓\n- GET /users/1 final: both fields updated correctly ✓\n\nAll JSON responses have Content-Type: application/json. Port 8080 unchanged. No third-party dependencies used.",
"plan": "The task is complete. All endpoints are implemented and verified working correctly.",
"commands": [],
"task_complete": true
}Note
Model marked task complete.
Verifier
[verifier exit=0] reward: 1
