# Flowchart: hybrid-search-orchestration ## Sources Consulted - `src/services/worker/search/SearchOrchestrator.ts:1-290` - `src/services/worker/search/strategies/ChromaSearchStrategy.ts:1-120` - `src/services/worker/search/strategies/SQLiteSearchStrategy.ts:1-120` - `src/services/worker/search/strategies/HybridSearchStrategy.ts:1-240` - `src/services/worker/search/ResultFormatter.ts:1-200` - `src/services/worker/search/TimelineBuilder.ts:1-220` - `src/services/worker/SearchManager.ts:1-600` - `src/services/worker/http/routes/SearchRoutes.ts:1-150` ## Happy Path Description `/api/search` → `SearchRoutes` → `SearchManager.search()` (thin facade) → `SearchOrchestrator` chooses among three strategies: **Path 1 (Filter-only):** No query text → `SQLiteSearchStrategy` does metadata-only filter via SessionSearch (date range, project, concept/type/file). **Path 2 (Semantic):** Query text + ChromaSync available → `ChromaSearchStrategy.queryChroma` → filter by recency (90-day default or custom) → categorize by doc type → hydrate from SQLite. If Chroma fails mid-query, orchestrator falls back to filter-only SQLite (drops the query term). **Path 3 (Hybrid):** `findByConcept|Type|File` specialty methods → `HybridSearchStrategy` two-phase: (1) SQLite metadata filter → all matching IDs; (2) Chroma semantic ranking → re-rank; (3) intersect + hydrate → return metadata-matched IDs in Chroma rank order. `ResultFormatter` renders markdown tables grouped by date/file. `TimelineBuilder` handles chronological grouping with anchor-based depth filtering. ## Mermaid Flowchart ```mermaid flowchart TD A["GET /api/search
SearchRoutes.ts:22"] --> B["SearchManager.search
SearchManager.ts:161"] B --> C["SearchOrchestrator.search
SearchOrchestrator.ts:71"] C --> D{Decision
SearchOrchestrator.ts:81} D -->|no query| E["SQLiteStrategy.search
SQLiteSearchStrategy.ts:38"] D -->|query + Chroma| F["ChromaStrategy.search
ChromaSearchStrategy.ts:42"] D -->|no Chroma| G["Return empty
SearchOrchestrator.ts:115"] E --> E1["SessionSearch.searchObservations/Sessions/Prompts"] E1 --> E4["StrategySearchResult
SearchOrchestrator.ts:98"] F --> F1["ChromaSync.queryChroma
ChromaSearchStrategy.ts:104"] F1 --> F3["filterByRecency 90d
SearchOrchestrator.ts:119"] F3 --> F4["categorizeByDocType
SearchOrchestrator.ts:120"] F4 --> F5["hydrate from SQLite"] F5 --> F6["StrategySearchResult usedChroma=true"] F --> F7[/Error?/] F7 -->|yes| F8["SQLiteStrategy fallback
SearchOrchestrator.ts:102"] F8 --> E4_Fallback["fellBack=true
SearchOrchestrator.ts:107"] E4 --> H["SearchManager formats
SearchManager.ts:320-444"] E4_Fallback --> H F6 --> H G --> H H --> Hfmt{format?} Hfmt -->|json| H1["Raw JSON"] Hfmt -->|markdown| H2["ResultFormatter.formatSearchResults
ResultFormatter.ts:25"] H2 --> H3["combineResults
ResultFormatter.ts:115"] H3 --> H4["groupByDate
ResultFormatter.ts:49"] H4 --> H5["groupByFile
ResultFormatter.ts:61"] H5 --> H9["Markdown tables"] J["findByConcept/Type/File
SearchOrchestrator.ts:126-180"] --> K["HybridStrategy
HybridSearchStrategy.ts:26"] K --> K1["Phase 1: SessionSearch metadata filter
HybridSearchStrategy.ts:74/112/152"] K1 --> K2["Phase 2: ChromaSync.queryChroma
HybridSearchStrategy.ts:180/208"] K2 --> K3["Phase 3: intersectWithRanking
HybridSearchStrategy.ts:228"] K3 --> K4["hydrate SQLite
HybridSearchStrategy.ts:188"] K4 --> K5["StrategySearchResult usedChroma=true"] L["TimelineBuilder.buildTimeline
TimelineBuilder.ts:46"] --> L1["Unify obs/sessions/prompts"] L1 --> L2["filterByDepth
TimelineBuilder.ts:73"] L2 --> L3["formatTimeline
TimelineBuilder.ts:124"] ``` ## Side Effects - Chroma unavailability → fallback to filter-only SQLite (drops query text). - Default 90-day recency filter unless `dateRange` is explicit. - HybridStrategy errors → metadata-only results with `fellBack=true`. - SearchManager normalizes comma-separated URL params → arrays. ## External Feature Dependencies **Calls into:** ChromaSync, SessionSearch (SQLite FTS5), SessionStore (hydration), ModeManager (type icons), timeline-formatting helpers. **Called by:** Search routes, mem-search skill, CorpusBuilder (via SearchOrchestrator). ## Important Clarification: SearchManager vs SearchOrchestrator - **SearchOrchestrator** is the canonical strategy coordinator introduced in Jan 2026 monolith refactor. - **SearchManager** is a **thin facade** delegating to SearchOrchestrator, plus HTTP/display wrapping. - **NOT duplicates.** But SearchManager retains legacy private methods (`queryChroma`, `searchChromaForTimeline` marked `@deprecated`) — candidates for cleanup. ## Confidence + Gaps **High:** Three paths + fallback chains; SearchManager is thin facade; TimelineBuilder is standalone formatter. **Gaps:** Pagination enforcement across strategies; CorpusBuilder's exact call into SearchOrchestrator; deprecated SearchManager methods still present.