# Unified Search Architecture

Unified Search is the cross-domain query and answer subsystem of Advisory AI. It lets operators and users who are unfamiliar with Stella Ops terminology find relevant results across every plane of the release control plane — findings, VEX, policy, graph, timeline, scanner, platform knowledge, and operational memory — through a single deterministic ranking and synthesis pipeline.

Audience: engineers building against the unified-search API and operators tuning its ranking and federation behavior. For the parent service see architecture.md; for operator configuration and examples see unified-search-operations.md and knowledge-search.md.

Goals

Four-Layer Architecture

flowchart LR
  Q[Layer 1: Query Understanding]
  R[Layer 2: Federated Retrieval]
  F[Layer 3: Fusion and Entity Cards]
  S[Layer 4: Synthesis]

  Q --> R --> F --> S

Layer 1: Query Understanding

Layer 2: Federated Retrieval

Findings coverage

FindingsSearchAdapter reads the served-generation headers on every page of GET /api/findings/v1/security/findings: X-StellaOps-Match-State, X-StellaOps-Match-Incomplete-Versions, X-StellaOps-Source-State, X-StellaOps-Source-As-Of, and X-StellaOps-Corpus-Digest. The meaning of these headers is defined by the Findings API contract. An incomplete match means evaluable matches are present while unevaluated applicability remains unknown; missing findings and zero counts do not prove absence.

All chunks from one fetch carry the conservative combination of every page in their existing metadata: matchState, matchIncompleteVersions, sourceState, sourceAsOf, corpusDigest, and findingsTruncated. Any incomplete page makes match coverage incomplete; any stale page makes source freshness stale. Missing or invalid header values remain unknown. The incomplete-version count is the maximum tenant-wide count seen, not a sum across pages, and becomes unknown if a page omits it. The oldest source activation time is retained only when every page supplies it; a digest is retained only when all pages agree. Different generations cannot support a current-snapshot claim. Reaching the page cap is marked as a partial result set independently of match coverage. Snapshots have unknown served-generation coverage.

The indexer persists this metadata alongside each chunk and refreshes it even when only coverage changes. Search cards, facets, previews, and snippets retain the state; card merging combines Findings coverage even when a different domain supplies the primary card. Partial, stale, and unknown coverage produces an explicit Findings coverage: notice in snippets, deterministic summaries, LLM prompt context, and returned generated summaries. Grounded chat carries the notice into its evidence pack and reapplies it after model response validation. This makes coverage disclosure independent of model wording. Existing indexed rows without the metadata are treated as unknown until the next refresh.

Layer 3: Fusion and Entity Cards

Layer 4: Synthesis

Telemetry and gap surfacing

Data Flow

sequenceDiagram
  participant UI as Web UI / API Client
  participant API as UnifiedSearchEndpoints
  participant PLAN as QueryUnderstanding
  participant IDX as KnowledgeSearchStore
  participant FED as FederatedDispatcher
  participant FUS as WeightedRrfFusion
  participant CARDS as EntityCardAssembler
  participant SYN as SearchSynthesisService
  participant ANA as SearchAnalyticsService

  UI->>API: POST /v1/search/query
  API->>PLAN: Build QueryPlan
  PLAN-->>API: intent + entities + domain weights
  API->>IDX: SearchFtsAsync + LoadVectorCandidatesAsync
  API->>FED: DispatchAsync (optional)
  IDX-->>API: lexical + vector rows
  FED-->>API: federated rows + diagnostics
  API->>FUS: Fuse rankings
  FUS-->>API: ranked rows
  API->>CARDS: Assemble entity cards
  CARDS-->>API: entity cards
  API->>ANA: Record query/click/zero_result
  API-->>UI: UnifiedSearchResponse

  UI->>API: POST /v1/search/synthesize
  API->>SYN: ExecuteAsync
  SYN-->>UI: SSE deterministic-first + optional LLM chunks

Contracts and API Surface

POST /v1/search/query response notes:

POST /v1/search/suggestions/evaluate response notes:

OpenAPI contract presence is validated by integration test:

Determinism Rules

Configuration

Primary section: AdvisoryAI:UnifiedSearch

Detailed operator config and examples: