# 08 — AI Feature-Flag Integration (Part 8) How the AI layer plugs into the flag system while staying **completely separable** from core email logic. Extends the blueprint AI strategy ([../06](../06-ai-strategy.md)); the gate math lives in [04](04-settings-and-flags.md). ## Principle: AI is a guest, never a host Core email (sync, search-lexical, cleanup, settings, admin) **never references an AI type**. It calls domain services; those *optionally* consult AI through a single gate + facade. Remove AI entirely and nothing in the core path breaks. ``` Core feature code │ (never touches Ollama/IAiProvider directly) ▼ IAiGate.IsAiFeatureEnabled("summaries", user) ──► false ─► non-AI path / hide │ true ▼ IInboxAi facade (Application) ──► model router ──► IAiProvider / IEmbeddingProvider (Null | Ollama | future) ``` ## Toggle behaviour (flag-driven) - Before *any* AI call, code asks `IAiGate` (which folds in `ai.enabled` + `ai.` + provider capability + user opt-in — the AND-chain from [04](04-settings-and-flags.md)). - **Admin `ai.enabled` = off** ⇒ gate returns false everywhere ⇒ AI UI hidden, AI code paths skipped. Flip on ⇒ features reappear (hot-reloaded flag cache) with **no redeploy**. - Per-feature flags allow shipping AI features **dark** and enabling gradually (rollout). ## Fallback when AI is disabled (per feature) | AI feature | Fallback with AI off | |------------|----------------------| | Semantic / NL search | Lexical + structured + fuzzy search (still excellent) | | Thread summary | Hidden; show first snippet + metadata | | Reply suggestions | Hidden; normal compose | | Follow-up detection | Heuristic-only (sent + question + no reply in N days) | | Categorisation | `HeuristicClassifier` rules only | | Ask-your-inbox | Feature hidden | | Dedup | Exact-hash only (no near-dup) | Every fallback is **first-class**, not a broken/greyed feature — this satisfies "AI must never be required for core functionality." ## Ollama integration layer (local models) - `OllamaProvider` (`IAiProvider`) + `OllamaEmbeddingProvider` (`IEmbeddingProvider`) talk to a local Ollama (own container, optional Compose `ai` profile). - **Model router** maps logical task → model via config (`Ai:Models:{Chat,Embed,Vision}`); swapping a model is a config change, not code. - **VRAM guard** (RTX 3080 / 10 GB): embeddings hot, 7B warm, vision on-demand ([../06](../06-ai-strategy.md)). - **Health surfaced to admin** ([05](05-admin-system.md)): reachable? models loaded? VRAM? latency? If Ollama is down, capability = false ⇒ gate falls back gracefully (no user errors). ## Safe abstraction (`IAIProvider`) — separation guarantees 1. **Interface boundary:** only Infrastructure implements providers; Application depends on `IInboxAi`/`IAiGate` abstractions. 2. **Null objects:** `NullAiProvider`/`NullEmbeddingProvider` return "unavailable" so the DI graph is always valid, AI on or off. 3. **Analyzer pipeline:** AI enrichers (`IEmailAnalyzer`) declare required capabilities and are **skipped** when unavailable — adding/removing AI features never touches core sync/search. 4. **Bounded:** every AI call has timeout + `CancellationToken` + Polly fallback to the Null path; AI can never hang or crash the core. 5. **Provider-swap:** adding a future AI provider = one class + config + (optionally) a flag — no feature-code changes. ## Precedence recap (single source of truth) The effective availability chain and admin master-switch semantics are defined once in [04 — Settings & Feature Flags](04-settings-and-flags.md#ai-gating-precedence-the-key-requirement); this document is the *architecture* of how features consume that decision.