Why:
- Any test using the client/api_client fixtures runs the app's real lifespan,
which calls the production configure_logging() -- setting
cache_logger_on_first_use=True (ADR-0011). That permanently monkeypatches
the .bind method on whichever module-level
logger = structlog.get_logger(__name__) instance is used first.
structlog.reset_defaults() only resets *global* config, not that
per-instance mutation, so once triggered, structlog.testing.capture_logs()
silently stops intercepting events in every test that runs afterward in the
same pytest process -- order-dependent flakiness with no useful failure
message (assertions just see an empty list).
Changes:
- Added two autouse fixtures: one no-ops configure_logging for tests that
spin up the app via LifespanManager (they test HTTP behavior, not logging
output, so they don't need the real thing), one resets structlog defaults
after every test as defense in depth.
Impact:
- Test-only; makes capture_logs()-based assertions reliable regardless of
test execution order.
Why:
- Plan 001 Phase 4 needs batched, concurrency-bounded embedding wired into
the inline upload path, with process-wide capacity/timeout/chunk-limit
guards (ADR-0017).
- The BM25 analyzer and dense-model config are ported from the `emet`
evaluation lab, which benchmarked them against the real Farsi corpus
(bm25-fa-norm-stop; nomic-embed-text-v2-moe at 768-dim; text-embedding-3-large
at native 3072-dim), closing open items in ADR-0001/ADR-0005.
Changes:
- New: embedding ports, orchestration (embed_chunks), request-bounds
helpers, and dense/sparse adapters (analyzers.py, bm25.py,
openai_compatible.py).
- upload.py now parses/chunks/embeds inline behind INGESTION_MAX_CONCURRENCY
(503), INGESTION_TIMEOUT_SECONDS (504), and the chunk-count ceiling (413);
every failure path still writes a terminal job row.
- Lifespan builds and warms both dense embedders at startup (fail-soft) and
creates the sparse embedder and concurrency semaphore.
- httpx moves from dev to main dependencies (adapters use it directly).
Impact:
- Qdrant point upserts are still Phase 5 -- chunks_indexed stays 0.
- New EMBEDDING_* env vars documented in .env.example; safe defaults.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>