Partially. BrassCoders catches two structural patterns that indicate missing synchronization: calls to threading.Thread without a paired threading.Lock, and global mutable state modified inside async def functions. Both leave a deterministic marker in the source that the scanner can match.
The threading.Thread case is the cleaner catch. Spin up threads over functions that read and write shared state, and the scanner sees the thread call and checks for an associated lock. No lock: flagged. The async function plus global mutation pattern works the same way — the AST shows a global variable being written inside an async def, a structural sign of a potential race.
What BrassCoders cannot catch: the asyncio race that happens when two coroutines share a variable across an await point but no threading call is present. Python's asyncio event loop is single-threaded and cooperatively scheduled — any await expression is a potential handoff to another coroutine, and shared state written before and after that handoff can end up stale. But if the code contains no threading.Thread call and the variable isn't at module scope, there's no marker to match. Two coroutines reading and writing the same variable across an await looks structurally identical to two coroutines doing so safely.
The gap gets filled in two ways. An AI assistant — Claude Code, Cursor, or similar — reading the YAML output can trace which variables are actually shared across await points and flag missing asyncio.Lock usage. That kind of reasoning needs full function-body context, which deterministic rules can't supply. asyncio-specific linters can catch some of the same patterns, though at the cost of more false positives than BrassCoders targets.
One practical distinction worth making: when the shared state is auth data or a session store, the correctness bug becomes a security bug. A stale counter is a metrics error. A stale session token map that briefly exposes one user's state to another is a real vulnerability.
The full mechanics — how asyncio's cooperative scheduling creates race windows and what fixes them — are in Race Conditions in AI-Generated Concurrent Python.
Top comments (0)