"""Runtime configuration warnings for Phase 1/2 feature alignment.""" from __future__ import annotations from app.config import settings from app.redis_client import job_queue_enabled, redis_configured from app.retrieval.semantic_cache import is_semantic_cache_active def collect_optimization_warnings() -> list[str]: """Return human-readable misconfiguration / feature-gap warnings.""" warnings: list[str] = [] backend = (settings.vectorstore_backend or "faiss").strip().lower() if settings.enable_async_pipeline and backend != "qdrant": warnings.append( "ENABLE_ASYNC_PIPELINE=true but VECTORSTORE_BACKEND is not qdrant; " "hybrid retrieval and semantic cache require Qdrant." ) if settings.semantic_cache_enabled and not is_semantic_cache_active(): warnings.append( "SEMANTIC_CACHE_ENABLED=true but semantic cache is inactive " "(requires VECTORSTORE_BACKEND=qdrant)." ) if settings.enable_hybrid_retrieval and backend != "qdrant": warnings.append( "ENABLE_HYBRID_RETRIEVAL=true has no effect unless VECTORSTORE_BACKEND=qdrant." ) if ( settings.enable_speculative_executor and settings.enable_async_pipeline and settings.notes_only_generation and not settings.agentic_inspector_when_notes_only ): warnings.append( "ENABLE_SPECULATIVE_EXECUTOR=true but notes_only_generation=true forces the " "standard pipeline on POST /generate (inspector/speculation skipped). " "Set AGENTIC_INSPECTOR_WHEN_NOTES_ONLY=true or NOTES_ONLY_GENERATION=false." ) if settings.enable_prompt_caching and not settings.enable_async_pipeline: warnings.append( "ENABLE_PROMPT_CACHING=true requires ENABLE_ASYNC_PIPELINE=true." ) if settings.enable_temporal_workflow and "sqlite" in (settings.database_url or "").lower(): if not settings.allow_sqlite_parallel_sections: warnings.append( "Temporal + SQLite: parallel section activities are disabled by default; " "use PostgreSQL for parallel Temporal sections." ) if backend == "qdrant": from pathlib import Path faiss_dir = Path(settings.faiss_index_path) try: if faiss_dir.is_dir() and any(faiss_dir.iterdir()): warnings.append( "FAISS index data still present on disk; re-ingest into Qdrant " "(scripts/reingest_qdrant.py) if you migrated backends." ) except OSError: pass if settings.enable_job_queue and not redis_configured(): warnings.append( "ENABLE_JOB_QUEUE=true requires REDIS_URL; " "generation will fall back to in-process tasks until Redis is configured." ) if settings.enable_rag_upload_sanitisation and not (settings.openai_api_key or "").strip(): warnings.append( "ENABLE_RAG_UPLOAD_SANITISATION=true but OPENAI_API_KEY is unset; " "uploads are indexed using regex-only redaction (weaker than the LLM sanitiser)." ) return warnings def collect_optimization_hints() -> list[str]: """Non-blocking operational hints (not misconfigurations).""" hints: list[str] = [] if job_queue_enabled(): hints.append( "Job queue enabled: ensure `python jobs_worker.py` is running " "(or `docker compose --profile redis --profile jobs up`)." ) if redis_configured() and not settings.enable_job_queue: hints.append( "REDIS_URL is set: distributed rate limits are active across API replicas." ) return hints