{
  "name": "hard-concurrent-bug",
  "description": "Fix a race condition in a multi-threaded Python program",
  "dataset": "terminal-bench-local",
  "difficulty": "hard",
  "instruction": "There is a Python file called bank.py that simulates a simple bank with concurrent transfers. It has a race condition that causes incorrect final balances. Fix the bug so that concurrent transfers produce correct results. The total money in the system should be conserved (sum of all balances should remain constant). Do not change the test file.",
  "setup_files": {
    "bank.py": "import threading\nimport time\nimport random\n\nclass BankAccount:\n    def __init__(self, name, balance):\n        self.name = name\n        self.balance = balance\n        # Bug: no lock to protect balance updates\n\n    def withdraw(self, amount):\n        if self.balance >= amount:\n            # Simulate processing delay that exposes the race condition\n            time.sleep(0.001)\n            self.balance -= amount\n            return True\n        return False\n\n    def deposit(self, amount):\n        time.sleep(0.001)\n        self.balance += amount\n\n\ndef transfer(from_account, to_account, amount):\n    if from_account.withdraw(amount):\n        to_account.deposit(amount)\n        return True\n    return False\n",
    "test_bank.py": "import sys\nimport threading\nfrom bank import BankAccount, transfer\n\npassed = 0\nfailed = 0\n\ndef check(desc, got, expected):\n    global passed, failed\n    if got == expected:\n        passed += 1\n    else:\n        print(f\"FAIL {desc}: got {got}, expected {expected}\")\n        failed += 1\n\n# Test 1: Sequential transfers should work\na1 = BankAccount('A', 1000)\na2 = BankAccount('B', 1000)\ntransfer(a1, a2, 100)\ncheck('sequential transfer from', a1.balance, 900)\ncheck('sequential transfer to', a2.balance, 1100)\n\n# Test 2: Concurrent transfers should conserve money\ninitial_total = 3000\nacc1 = BankAccount('X', 1000)\nacc2 = BankAccount('Y', 1000)\nacc3 = BankAccount('Z', 1000)\n\nthreads = []\nfor _ in range(20):\n    accounts = [acc1, acc2, acc3]\n    src = accounts[_ % 3]\n    dst = accounts[(_ + 1) % 3]\n    t = threading.Thread(target=transfer, args=(src, dst, 10))\n    threads.append(t)\n\nfor t in threads:\n    t.start()\nfor t in threads:\n    t.join()\n\nfinal_total = acc1.balance + acc2.balance + acc3.balance\ncheck('money conserved', final_total, initial_total)\n\n# Test 3: Overdraft protection with concurrency\nacc_small = BankAccount('Small', 50)\nacc_big = BankAccount('Big', 0)\n\nthreads2 = []\nfor _ in range(10):\n    t = threading.Thread(target=transfer, args=(acc_small, acc_big, 10))\n    threads2.append(t)\n\nfor t in threads2:\n    t.start()\nfor t in threads2:\n    t.join()\n\ntotal2 = acc_small.balance + acc_big.balance\ncheck('overdraft total conserved', total2, 50)\ncheck('small not negative', acc_small.balance >= 0, True)\n\nprint(f\"{passed}/{passed+failed} tests passed\")\nif failed > 0:\n    sys.exit(1)\n"
  },
  "verify": "cd $BENCH_WORK_DIR && python3 test_bank.py",
  "timeout": 240000,
  "tags": ["hard", "concurrency", "threading", "debugging", "python"]
}
