…#78)
Forward on one thread then .backward() on another raised 'Trying to backward
through the graph a second time': the eager tape was thread_local, so the
backward thread found none. Each thread still records into its own tape, now
an Arc<Mutex> also listed in a process-wide TAPES table; _eager_backward asks
its own tape first and otherwise takes the tape (try_lock, never blocking
under the GIL) that holds the output. Independent trainers never touch each
other's tapes. Door path unchanged; recording pays one uncontended lock per
op (not measured).
test_threadstate: two cross-thread tests red on the old shim with the
misnamed error, green now; a concurrent-trainers guard green on both.
Closes #78. Based on #77 (feat/thread-state), so merge #77 first.
Defect fixed
.backward()on another now gives upstream's gradient. Before, it raised the misnamed "backward through the graph a second time".try_lock, never blocking).Test added
tests/api/test_threadstate.py+3:Gate (worktree, local)
build.pyself-test suites that need.caches/;test_anedecode, whereMLComputePlanreturned "internal failure". Rerun alone twice: 10 ok both times. This is the CoreML drift recorded in AGENTS.md §13.3.Not done