Two simultaneous folder-creation requests from the same user will both read the same ROOT JSON, both modify it locally, and both write it back — the second write wipes the first. The same hazard exists for FAISS appends.
Current state:
No locks, no CAS, no versioning.
Proposed implementation:
- Introduce a per-user asyncio/
threading.Lock registry keyed by username (WeakValueDictionary), wrapping every read-modify-write of ROOT, SHARE_MANAGER, and the FAISS index.
- For the ResilientDB backend: add an optional
version field in the stored JSON and a CAS check on write; refuse and retry on mismatch.
- Document the invariant in
docs/architecture.md: "a user's tree mutations are serialized."
- Add a regression test using
ThreadPoolExecutor that fires 20 concurrent /create-folder requests for 20 distinct names and asserts all 20 appear.
Files likely affected:
backend/locks.py (new)
app.py (wrap mutating routes)
backend/rag_utils.py (serialize FAISS updates)
tests/test_concurrency.py (new)
Acceptance criteria:
- Race test passes 10× in a row.
- Single-user serial throughput regresses by < 5 %.
- Under the CAS backend, two instances of the app serving the same user produce consistent state.
Two simultaneous folder-creation requests from the same user will both read the same ROOT JSON, both modify it locally, and both write it back — the second write wipes the first. The same hazard exists for FAISS appends.
Current state:
No locks, no CAS, no versioning.
Proposed implementation:
threading.Lockregistry keyed by username (WeakValueDictionary), wrapping every read-modify-write of ROOT, SHARE_MANAGER, and the FAISS index.versionfield in the stored JSON and a CAS check on write; refuse and retry on mismatch.docs/architecture.md: "a user's tree mutations are serialized."ThreadPoolExecutorthat fires 20 concurrent/create-folderrequests for 20 distinct names and asserts all 20 appear.Files likely affected:
backend/locks.py(new)app.py(wrap mutating routes)backend/rag_utils.py(serialize FAISS updates)tests/test_concurrency.py(new)Acceptance criteria: