Skip to content

Claude Sonnet 5.5 (effort default (no --effort flag) · thinking on) on Fix a lock-ordering deadlock, a lost-update race and torn snapshots in a threaded bank ledger

AClaude Sonnet 5.5default · thinking on · Claude Code 2.1.299 (headless -p) · cloud · 2026-10-17 · by @bobsiopener

Trust 80%Fully autonomoussuccess · first try
Estimated cost
$0.05
Wall time
12s
Human step-ins
0
Outcome
Pass

Compare with other models on this task →

Summary

Exact prompt

# Task: fix the concurrency bugs in bank.py `bank.py` is called from many worker threads at once. In production the worker pool sometimes hangs forever, money occasionally appears or disappears (the bank total drifts), balances have gone negative, and auditors say `total()`/`snapshot()` sometimes report a state that never existed. Fix `bank.py` so that, under heavy concurrent use: - `transfer` can never deadlock, never loses or creates money, never makes a balance negative, and raises `InsufficientFunds` (leaving everything unchanged) when the source lacks funds; - `total()` and `snapshot()` return a consistent point-in-time view even while transfers are running; - every successful transfer is in `log` exactly once, failed ones not at all. Keep the public API (class names, method names/signatures, `bal` and `log` attributes). Do not make it single-threaded by removing threading support from callers; a global lock is acceptable only if it keeps throughput reasonable (the grader runs 8 threads x 20,000 transfers in under 30 s). Standard library only. No network.

Three distinct bugs: check-then-act outside the lock (lost updates/negatives), opposite lock order (deadlock), unlocked snapshot/total (torn reads). Fixing one exposes the others; the stress test forces frequent thread switches. Original benchmark task written for usecaserank.com (not based on a specific public post). Headless, offline run on a reproducible fixture. Each run's notes say how its cost was measured (estimates are marked).

Success criteria: 1. no_deadlock: each of 3 stress runs (8 threads x 20,000 random transfers plus a concurrent auditor) finishes within 30 s. 2. final_total_ok: total money is conserved in every run. 3. no_negative: no balance is ever negative (final state and every audited snapshot). 4. log_exact: log has exactly one entry per successful transfer. 5. snapshots_consistent: every snapshot()/total() taken during the run sums to the true total. 6. nsf_raises_unchanged: an overdraft raises InsufficientFunds and changes neither balances nor log.

Setup notes: Use Case Scout batch 5 case e03-bank-deadlock-race (offline fixture). Prepared with batch5/prepare.sh; hidden key/tests kept outside the agent's work dir. Prompt = TASK.md verbatim. Scored with the scout's scorer: `python score.py WORKDIR KEYDIR`. Tools: Read/Write/Edit/Glob/Grep/Bash, web disabled. Single run, no retries. 1-min load average at scoring: 0.35. Claude Code's own reported cost for claude-sonnet-5.5: $0.045672. Score: 6/6 checks. Cost is an ESTIMATE: measured tokens x pricing.json list price (Claude Pro subscription, nothing billed); input_tokens include cache reads and writes. Single run.

Estimated cost List-price estimate; not actually billed.

Metrics

Estimated cost
$0.05
Wall time
12s
Human step-ins
0
Turns
3
Model usage
ModelInput tokOutput tokCost
AClaude Sonnet 5.5anthropic/claude-sonnet-5.5effort default (no --effort flag) · thinking on56,5161,267$0.05

Reproduce this run

  1. Use the use case prompt on the use case page.
  2. Same setup: Claude Sonnet 5.5 (anthropic/claude-sonnet-5.5, effort default (no --effort flag) · thinking on) via Claude Code 2.1.299 (headless -p), cloud.
  3. It counts as a success only if it meets every success criterion: 1. no_deadlock: each of 3 stress runs (8 threads x 20,000 random transfers plus a concurrent auditor) finishes within 30 s. 2. final_total_ok: total money is conserved in every run. 3. no_negative: no balance is ever negative (final state and every audited snapshot). 4. log_exact: log has exactly one entry per successful transfer. 5. snapshots_consistent: every snapshot()/total() taken during the run sums to the true total. 6. nsf_raises_unchanged: an overdraft raises InsufficientFunds and changes neither balances nor log.
  4. Log model, tokens, wall time, human step-ins and the evidence log, then submit it as a reproduction. A different model? Submit a head-to-head rerun.

How runs are scored: Methodology.

Was this useful?

⇄ Rerun on another model

Automated checks

Trust 80% comes from these checks (how Trust % works).

Evidence log
[
 {
  "duration_api_ms": 10923,
  "stop_reason": "end_turn",
  "session_id": "[REDACTED]",
  "total_cost_usd": 0.045672000000000004,
  "usage": {
   "input_tokens": 6,
   "cache_creation_input_tokens": 7010,
   "cache_read_input_tokens": 49500,
   "output_tokens": 1267,
   "output_tokens_details": {
    "thinking_tokens": 68
   },
   "server_tool_use": {
    "web_search_requests": 0,
    "web_fetch_requests": 0
   },
   "service_tier": "standard",
   "cache_creation": {
    "ephemeral_1h_input_tokens": 7010,
    "ephemeral_5m_input_tokens": 0
   },
   "inference_geo": "global",
   "iterations": [
    {
     "input_tokens": 2,
     "output_tokens": 434,
     "cache_read_input_tokens": 18753,
     "cache_creation_input_tokens": 796,
     "cache_creation": {
      "ephemeral_5m_input_tokens": 0,
      "ephemeral_1h_input_tokens": 796
     },
     "type": "message"
    }
   ],
   "speed": "standard",
   "fallback_credit": null
  },
  "modelUsage": {
   "claude-sonnet-5-5": {
    "inputTokens": 6,
    "outputTokens": 1267,
    "cacheReadInputTokens": 49500,
    "cacheCreationInputTokens": 7010,
    "webSearchRequests": 0,
    "costUSD": 0.045672000000000004,
    "contextWindow": 1000000,
    "maxOutputTokens": 128000,
    "thinkingTokens": 68,
    "canonicalModel": "claude-sonnet-5-5",
    "provider": "firstParty",
    "costBasis": "list"
   }
  },
  "permission_denials": [],
  "terminal_reason": "completed",
  "fast_mode_state": "off",
  "fast_mode_disabled_reason": "sdk_opt_in_required",
  "subagent_stats": {
   "spawned": 0,
   "requested": {
    "background": 0,
    "foreground": 0,
    "unset": 0
   },
   "started_in_background": 0,
   "max_depth": 0,
   "spawned_by_subagents": 0,
   "completed": 0,
   "failed": 0,
   "killed": {
    "parent": 0,
    "user": 0,
    "system": 0
   },
   "refused": {
    "depth_limit": 0,
    "concurrency_limit": 0,
    "budget": 0
   },
   "by_type": {}
  },
  "safety_stops": 0,
  "is_error": false,
  "num_turns": 3,
  "subtype": "success",
  "api_error_status": null,
  "result": "I fixed `bank.py` by replacing the per-account locks with a single lock that guards every operation. A quick stress run of 8 threads \u00d7 20,000 random transfers finished in about 0.2 s. The total stayed at 10,000 and no balance went negative. I didn't run any test against the `log` or against `total()`/`snapshot()` during transfers.\n\n- **Deadlock:** the old code took the source and destination locks in whatever order the caller gave, so two opposite transfers could wait on each other forever. With one lock there is no ordering to get wrong.\n- **Lost or created money and negative balances:** the old code read the balance before taking any lock, then wrote back a stale value. The balance check, both updates and the log append now happen together under the lock.\n- **Failed transfers:** `InsufficientFunds` is raised before anything is changed or logged. An unknown account name still raises `KeyError`, also before any change.\n- **`total()` and `snapshot()`:** both take the same lock, so they only ever see the state between transfers.\n- **Log:** each successful transfer is appended exactly once, inside the same locked section as the balance change.\n\nThe public API is unchanged. The `locks` dict attribute is gone, replaced by a private `_lock`. I assumed nothing outside `bank.py` reads `locks`, and I didn't check.",
  "ttft_ms": 1695,
  "type": "result",
  "duration_ms": 11437,
  "uuid": "[REDACTED]",
  "ttft_stream_ms": 1053,
  "time_to_request_ms": 205,
  "first_content_frame_ms": 1053,
  "queued_turn_count": 0,
  "result_index": 0
 }
]

Get new runs and ranking changes weekly