fix(cache): allow nested and recursive cached calls
Calling a cached resource loader from another cached loader currently deadlocks: the outer call holds the global non-reentrant lock and the inner call tries to acquire it again on the same thread. Recursive cached functions also hang.
Use a reentrant lock so these calls complete while retaining the existing synchronization and single-computation behavior for concurrent callers. The regression exercises nested loaders, cache hits and recursive Fibonacci in a subprocess with a timeout, so a recurrence cannot hang the test runner. It times out on unchanged code and passes with the fix.
Validation: 54 cache, chat-context and user-session tests passed on Python 3.13, including the existing concurrent cache test. Ruff lint/format checks and git diff --check passed. One existing third-party Pydantic deprecation warning remains.
Prepared with assistance from OpenAI Codex; the diff was reviewed and the checks above were run locally.
Summary by cubic
Fixes a deadlock when a cached resource loader calls another cached loader or when a cached function recurses: the outer call held the global non-reentrant lock, so the inner call hung on the same thread. The cache now uses a reentrant lock, so these calls complete while concurrent callers still share a single computation.
Adds a regression test that runs nested loaders, cache hits, and recursive Fibonacci in a subprocess with a timeout, so a deadlock cannot hang the test runner.