Per review §2:
- web/db.py: new _tx() context manager wraps multi-statement writers in
BEGIN IMMEDIATE … COMMIT/ROLLBACK (our connections run in autocommit
mode, so plain `with _lock:` doesn't give atomicity). partnership_accept
(UPDATE + DELETE) and cleanup_retention (3 deletes/updates) now use it.
- Fire-and-forget tasks: add module-level _bg_tasks sets in web/app.py and
web/enrichment.py. A _spawn() helper holds a strong ref until the task
finishes so the GC can't drop it mid-flight (CPython's event loop only
weakly references pending tasks).
- apply/main.py: require_api_key uses hmac.compare_digest, matching web's
check. Also imports now use explicit names instead of `from settings *`.
- apply/language.py: replace `from settings import *` + `from paths import *`
with explicit imports — this is the pattern that caused the LANGUAGE
NameError earlier.
- alert/utils.py: pickle-based hash_any_object → deterministic JSON+sha256.
Cheaper, portable across Python versions, no pickle attack surface.
- web/notifications.py: /fehler links repointed to /bewerbungen (the
former page doesn't exist).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>