Spaces:
Runtime error
Runtime error
File size: 22,630 Bytes
b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d b3f5a94 72fa63d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 | # Vantage β Master Plan
> **Agentic Market Intelligence.** The single source of truth (SSOT) for this project.
> *"What is the market asking for that our research library hasn't covered yet?"*
>
> This document is the master reference. Every architectural, scoping, and sequencing
> decision lives here. Update it as the project evolves; do not let code drift from it.
## Table of Contents
1. [Product & Problem](#1-product--problem)
2. [The Five Capabilities](#2-the-five-capabilities)
3. [GapScore Methodology](#3-gapscore-methodology)
4. [Scope](#4-scope)
5. [Key Trade-offs](#5-key-trade-offs)
6. [Tools & Stack](#6-tools--stack)
7. [Architecture & Patterns](#7-architecture--patterns)
8. [Folder Structure](#8-folder-structure)
9. [Data Model](#9-data-model)
10. [The Agent](#10-the-agent)
11. [Edge Cases](#11-edge-cases)
12. [Build Phases (organic, local-first)](#12-build-phases-organic-local-first)
13. [Guiding Principles](#13-guiding-principles)
14. [Local Dev Workflow](#14-local-dev-workflow)
15. [Reproducibility & Delivery](#15-reproducibility--delivery)
16. [Evaluation Methodology](#16-evaluation-methodology)
17. [Observability](#17-observability)
18. [Demo Script](#18-demo-script)
19. [Effort Summary](#19-effort-summary)
---
## 1. Product & Problem
Research organizations (the case study is framed around a Gartner-like firm) maintain a large
internal library of analyst content. The market, meanwhile, moves constantly β new topics surge
in search and news every week. The strategic question for research leadership is:
> **Where is market demand outrunning our coverage?**
**Vantage** answers this by connecting **external market demand** to **internal library
coverage** through a shared topic vocabulary. For any topic it knows two things at once:
- **Momentum** β how hot the topic is in the outside world (search/news signal).
- **Coverage** β how well the internal library addresses it (retrieval density).
The gap between them β the **GapScore** β drives a ranked commissioning list and a
conversational research assistant. Every answer is grounded in cited sources, and every agent
decision is fully auditable.
**Simulated internal library:** we use the public **HuffPost News Category Dataset**
(~200k pre-labeled articles) as a stand-in for the proprietary research corpus. Its built-in
category labels give us topic ground truth for free.
---
## 2. The Five Capabilities
Mapped directly to the case-study brief:
1. **Detect emerging topics** β from public search/news signals (Google Trends via pytrends).
2. **Answer client questions** β RAG over the library returning **cited** sources.
3. **Identify gaps** β compare topic momentum vs. internal coverage (the core metric).
4. **Knowledge Graph** β model documents, topics, entities, and their relationships.
5. **Agentic orchestration** β an agent that plans, retrieves, analyzes, and synthesizes
across all of the above.
---
## 3. GapScore Methodology
The core metric. **Borrowed, not invented** β adapted from SEO keyword opportunity scoring
(Ahrefs/SEMrush content-gap methodology), generalized to research topics.
```
GapScore(topic) = Momentum_percentile(topic) Γ (1 β Coverage_percentile(topic))
```
**Why this formula is defensible:**
- Both inputs are **percentile ranks** across all tracked topics β same ordinal scale β
multiplication/comparison is dimensionally valid (avoids the trap of subtracting two
differently-scaled raw numbers).
- Output is bounded **[0, 1]**, never negative.
- The **product** (not difference) means *both* conditions must hold to flag a gap: a topic
nobody wants AND that we cover well is correctly scored near 0.
**Inputs defined:**
- **Momentum_percentile** β percentile rank of the topic's search-interest z-score
(rolling baseline) across all tracked topics. Source: pytrends, cached.
- **Coverage_percentile** β percentile rank of the topic's *retrieval density* (count of
library chunks above a similarity threshold, normalized) across all tracked topics.
**The 2Γ2 decision matrix** (how results are presented to a business audience):
```
HIGH COVERAGE
β
Over-Served β Well-Covered β
(deprioritize)β (maintain)
βββββββββββββββββΌββββββββββββββββ MOMENTUM β
Ignore β π΄ PRIORITY GAP
(low demand) β (commission now)
β
LOW COVERAGE
```
**Worked example:** topic "Generative AI Enterprise" β momentum_pctile 0.96, coverage_pctile
0.12 β GapScore = 0.96 Γ (1 β 0.12) = **0.84** β π΄ Priority Gap.
**Union seeding (solves cold start + blind spot):** topics are seeded from the **union** of
(a) internal topics (HuffPost categories / extracted keywords) and (b) external trending terms
(pytrends top-N). Internal seeding solves the cold-start problem (no external taxonomy needed);
external seeding patches the blind spot where we have **zero** coverage of a surging topic (such
topics would never appear if we only looked inward).
---
## 4. Scope
**In scope**
- HuffPost dataset as the *simulated internal library* (~200k pre-labeled articles).
- Hybrid RAG (dense + sparse) β cross-encoder rerank β cited answers.
- **Union-seeded** gap analysis (internal βͺ external) β cold start + zero-coverage blind spot.
- Knowledge Graph in managed Neo4j; entities via spaCy NER; IPTC-style topic hierarchy.
- LangGraph agent (4 tools) with multi-turn memory + multi-hop reasoning.
- React/TS dashboard; evaluation harness; Langfuse observability; one-command Docker delivery.
**Out of scope (with reason)**
- **BERTopic** β HuffPost categories already label topics; nothing to discover.
- **GDELT / Guardian / NYT / SEC / SPARQL** β size/complexity/auth; documented as production paths.
- **Self-hosted DBs** β managed free tiers (Qdrant Cloud, Neo4j AuraDB) instead.
- **XGBoost/learning-to-rank reranker** β needs labeled data; pre-trained cross-encoder wins zero-shot.
- **Auth, multi-tenancy, streaming ingestion** β V2 items, mentioned in write-up.
---
## 5. Key Trade-offs
| Decision | Chosen | Why | Trade-off accepted |
|---|---|---|---|
| External signal | pytrends (cached) | Free, fast, offline-safe | Lower fidelity than GDELT |
| Reranker | Pre-trained cross-encoder | No training data needed | Not domain-tuned |
| Topic seeding | Union (internal βͺ external) | Catches thin *and* zero coverage | Slightly more compute |
| Architecture | 3-service modular monorepo | CQRS + SSOT, KISS | Not "pure" microservices |
| Databases | Managed free tiers | Zero ops, zero cost | Free-tier capacity limits |
| Gap compute | Scheduled/offline, API reads | Never blocks user queries | Gaps eventually-consistent |
| Topic modeling | HuffPost category labels | Labels already exist | Coarser than learned topics |
| Delivery | Pre-built GHCR images | One-command boot for reviewer | CI build pipeline upfront cost |
---
## 6. Tools & Stack
| Layer | Tool | Role |
|---|---|---|
| Frontend | React + Vite + TS + Tailwind + shadcn/ui + react-force-graph | Dashboard UI |
| API | FastAPI | Read side / BFF + agent host |
| Agent | LangGraph | Router, 4 tools, ReAct, memory |
| Domain | `vantage_core` (shared pkg) | SSOT logic: gapscore, retrieval, topics |
| Vectors | **Qdrant Cloud (free)** | Hybrid dense + sparse search (~1M vectors) |
| Embeddings | all-MiniLM-L6-v2 | Chunk + query vectors (384-dim) |
| Rerank | cross-encoder/ms-marco-MiniLM-L-6-v2 | Precision boost (top-50 β top-5) |
| Graph | **Neo4j AuraDB (free)** | Topics/entities/gap scores (~200k nodes) |
| NER | spaCy `en_core_web_sm` | Entity extraction (ORG/PERSON/GPE) |
| Signal | pytrends | Momentum (cached, TTL 6h) |
| LLM | OpenAI `gpt-4o-mini` | Routing + cited generation |
| Eval | RAGAS + NDCG@5 | Faithfulness, context recall, relevance |
| Observability | Langfuse Cloud | Trace every call/decision |
| Delivery | Docker + GHCR + one compose | `docker compose up` |
---
## 7. Architecture & Patterns
**Three services + two managed databases.** Local-first during development (plain scripts +
`start.sh`/`stop.sh`); containerized only at the final phase.
- **`apps/web`** β React/TS UI (chat, gap radar, graph). Thin; types generated from OpenAPI.
- **`apps/api`** β FastAPI **read side** (BFF). Hosts the LangGraph agent + 4 tools. Reads only.
- **`apps/worker`** β **write side**. Ingestion, KG build, signal refresh, gap computation.
- **`packages/vantage_core`** β **SSOT domain**: ports & adapters, models, gapscore, retrieval.
- **`contracts/openapi.yaml`** β API-first contract β generates the TS client (type SSOT).
- **Managed:** Qdrant Cloud (vectors), Neo4j AuraDB (graph).
**Patterns in play (and what each means here):**
- **SSOT** β Qdrant owns chunks/vectors; Neo4j owns topics/entities/gap scores; `signals.json`
owns external momentum; `vantage_core.models` owns schemas; `openapi.yaml` owns API types.
- **CQRS-lite** β `worker` writes (ingest, compute gaps); `api` reads. Gap math never blocks queries.
- **Hexagonal (ports & adapters)** β domain depends on interfaces; Qdrant/Neo4j/OpenAI/pytrends
are swappable adapters (e.g. pytrends β GDELT later).
- **Repository** β `VectorRepo`, `GraphRepo`, `SignalSource` abstract all I/O; domain is unit-testable.
- **Twelve-Factor** β config in `.env`, stateless services, disposable containers, dev/prod parity.
- **Cache-aside + TTL** β `signals.json` cached; recompute on miss/expiry.
- **Idempotent batch** β worker uses upserts; re-running ingestion is safe.
- **Graceful degradation** β every external dependency has a fallback/health-check.
---
## 8. Folder Structure
```
vantage/
βββ docs/MASTER_PLAN.md # this file β the master reference
βββ README.md # quickstart + architecture diagram (P13)
βββ .env.example # canonical list of every env var
βββ start.sh / stop.sh # local run (P9βP10): boot/stop api + web
βββ Makefile # convenience targets (ingest/seed/eval/...)
βββ docker-compose.yml # references GHCR images (P13)
βββ .github/workflows/ci.yml # build+push images to GHCR (P13)
βββ contracts/
β βββ openapi.yaml # API-first contract β TS client (SSOT for types)
βββ packages/
β βββ vantage_core/ # SSOT domain logic (imported by api + worker)
β βββ domain/{gapscore,retrieval,topics}.py
β βββ adapters/{vector_qdrant,graph_neo4j,signals_pytrends,llm_openai}.py
β βββ ports.py # VectorRepo, GraphRepo, SignalSource interfaces
β βββ models.py # pydantic domain models (SSOT schemas)
β βββ config.py # settings from .env
βββ apps/
β βββ api/ # FastAPI read side + LangGraph agent
β β βββ vantage_api/{main.py,routers/,agent/{graph,state,tools/}}
β βββ worker/ # write side jobs
β β βββ vantage_worker/{ingest_documents,build_graph,compute_signals,compute_gaps}.py
β βββ web/ # React + TS dashboard
β βββ src/{features/{chat,gap-radar,graph}/,lib/api/,App.tsx}
βββ scripts/ # one-shot dev scripts (local-first)
β βββ healthcheck.py download_data.sh ingest.py search.py
β βββ ask.py refresh_signals.py compute_gaps.py build_graph.py agent_cli.py
βββ eval/{golden_dataset.json,run_eval.py,report.md}
```
---
## 9. Data Model
**Qdrant (vectors)** β one point per chunk:
- `id`, `dense_vector` (384-dim), `sparse_vector` (BM25)
- payload: `doc_id`, `title`, `category`, `date`, `source`, `chunk_text`
**Neo4j (graph)** β nodes and edges:
- Nodes: `(:Document {id,title,category,date})`, `(:Topic {name,iptc_code,coverage_pctile,
momentum_pctile,gap_score,quadrant})`, `(:Entity {name,type})`
- Edges: `(Document)-[:MENTIONS]->(Topic)`, `(Document)-[:CONTAINS]->(Entity)`,
`(Entity)-[:RELATED_TO]->(Topic)`, `(Topic)-[:BROADER]->(Topic)`
**`signals.json`** β `{fetched_at, topics:[{keyword,z_score,momentum_pctile}]}`.
**`gap_log.jsonl`** β async query-level log: `{query,topic,retrieval_score,momentum_pctile,gap_score,ts}`.
---
## 10. The Agent
**LangGraph, ReAct pattern.** State carries conversation memory and gap log:
```python
class AgentState(TypedDict):
messages: Annotated[list, add_messages] # multi-turn memory
current_context: str # e.g. "APAC", "healthcare"
last_topics: list[str] # topics from previous turn
gap_log: list[dict] # running query-level gap signals
```
**Four tools:**
- **RAG Tool** β Qdrant hybrid β cross-encoder β cited answer.
- **Signal Tool** β reads `signals.json` β ranked momentum.
- **Gap Tool** β Neo4j Cypher β GapScore table + quadrant.
- **Graph Tool** β Neo4j Cypher β entity/topic/relationship traversal.
**Router** classifies intent and selects tool(s). **Multi-hop** chains tools within one query
(e.g. Gap β Graph β RAG). **Multi-turn memory** resolves references like "which of thoseβ¦".
**Async side-effect:** after each RAG answer with low retrieval score, write to `gap_log.jsonl`.
---
## 11. Edge Cases
Representative set (full list maintained alongside tests):
- **Zero relevant docs** β answer "no internal coverage" + log gap; never hallucinate.
- **LLM omits/forges citations** β post-validate against retrieved chunk IDs; retry/drop.
- **Topic trending, zero coverage** β union seeding catches it; coverage_pctile 0 β max gap.
- **pytrends 429 / flat series** β fall back to cache; guard z-score divide-by-zero.
- **Garbage / variant entities** β type whitelist + min-frequency + alias normalization.
- **AuraDB node limit** β cap ingested docs; documented.
- **Wrong/missing env var** β fail fast with explicit message (health-check).
- **Worker hasn't run** β API returns "gap data not yet computed" empty-state.
- **OpenAI/Langfuse down** β backoff / fire-and-forget; never crash the demo.
- **Multi-hop latency (10β20s)** β FE progress indicator / per-tool status.
---
## 12. Build Phases (organic, local-first)
**Principle:** vertical slices β each phase delivers *one* runnable, testable component. Infra
(Docker/GHCR) comes last. Managed DBs are remote endpoints we connect to from local scripts.
### Phase 1 β π Bootstrap & Connectivity *(π’ 2h)*
- **Contains:** repo folders, `requirements`, venv, `config.py`, `.env.example`; provision
Qdrant Cloud + Neo4j AuraDB; `scripts/healthcheck.py`.
- **Test:** `python scripts/healthcheck.py` β `Qdrant OK Β· Neo4j OK Β· OpenAI OK`.
- **Deliverable:** green health check. *(No Docker, no GHCR.)*
### Phase 2 β π Data Ingestion *(π‘ 3β4h)*
- **Builds on:** P1. **Contains:** `download_data.sh`, `models` (Document/Chunk), loader,
chunker, embedder, Qdrant adapter (upsert), `scripts/ingest.py`.
- **Test:** ingest 2k sample docs β `scripts/peek.py` shows counts + a sample chunk.
- **Deliverable:** populated Qdrant collection.
### Phase 3 β π Retrieval (hybrid + rerank) *(π‘ 3β4h)*
- **Builds on:** P2. **Contains:** hybrid dense+sparse search, cross-encoder rerank,
`scripts/search.py` (CLI).
- **Test:** 5 manual queries return on-topic chunks; rerank order sensible.
- **Deliverable:** `retrieval` module + search CLI.
### Phase 4 β π¬ RAG Answers (cited) *(π‘ 3β4h)*
- **Builds on:** P3. **Contains:** prompt template, OpenAI adapter, citation formatter +
validation, `scripts/ask.py`.
- **Test:** ask 5 questions β real citations; "no coverage" path triggers correctly.
- **Deliverable:** working RAG via CLI.
### Phase 5 β π External Signals *(π’ 2β3h)*
- **Builds on:** P1. **Contains:** pytrends adapter, z-scoreβpercentile, cache-aside TTL β
`signals.json`, `scripts/refresh_signals.py`.
- **Test:** run β `signals.json` populated; rate-limit falls back to cache.
- **Deliverable:** momentum data.
### Phase 6 β π― Coverage + GapScore *(π‘ 3β4h)*
- **Builds on:** P2, P5. **Contains:** coverage via Qdrant density, **union seeding** +
normalization, `gapscore.py`, `scripts/compute_gaps.py`.
- **Test:** gap table prints; zero-coverage topic β max gap; **unit tests** on `gapscore`.
- **Deliverable:** `gap_scores.csv`.
### Phase 7 β πΈοΈ Knowledge Graph *(π‘ 3β4h)*
- **Builds on:** P2, P6. **Contains:** spaCy NER + entity filtering/normalization, Neo4j
adapter (Doc/Topic/Entity upserts + edges), write gap scores onto Topic nodes,
`scripts/build_graph.py`.
- **Test:** Cypher in Neo4j Browser returns top gap topics + linked entities.
- **Deliverable:** populated graph.
### Phase 8 β π€ Agent (CLI) *(π΄ 4β5h)*
- **Builds on:** P4, P5, P6, P7. **Contains:** LangGraph state (memory), router, 4 tools,
ReAct multi-hop, `scripts/agent_cli.py`.
- **Test:** all 5 demo queries β correct routing + multi-hop + memory.
- **Deliverable:** working agent, terminal-only.
### Phase 9 β π API *(π‘ 3β4h)*
- **Builds on:** P8. **Contains:** FastAPI routers (chat/gaps/graph), session-keyed memory,
emit `openapi.yaml`, `start.sh`/`stop.sh` (local uvicorn).
- **Test:** `curl` each endpoint; `openapi.yaml` generated.
- **Deliverable:** API running locally via `start.sh`.
### Phase 10 β π¨ Frontend *(π΄ 6β8h)*
- **Builds on:** P9. **Contains:** React/Vite/TS + Tailwind + shadcn, 3 features
(chat/gap-radar/graph), generated TS client; `start.sh` boots **api + web**, `stop.sh` stops both.
- **Test:** click through 3 tabs; all 5 queries work in the UI.
- **Deliverable:** full local app via `start.sh`.
### Phase 11 β π Evaluation *(π’ 2β3h)*
- **Builds on:** P4. **Contains:** golden set (10 hand + 40 Opus), RAGAS + NDCG@5 β `eval/report.md`.
- **Test:** `python eval/run_eval.py` prints metrics.
- **Deliverable:** metrics report for README.
### Phase 12 β π Observability *(π’ 2h)*
- **Builds on:** P8. **Contains:** Langfuse wiring across LLM/tool/agent calls (fire-and-forget).
- **Test:** traces appear; app works if Langfuse is down.
- **Deliverable:** traced runs.
### Phase 13 β π¦ Containerize + GHCR + One-Command *(π‘ 3β4h, the very end)*
- **Builds on:** all. **Contains:** 3 Dockerfiles, `docker-compose.yml` (GHCR images),
healthchecks + `depends_on`, GitHub Action build/push, README + architecture diagram.
- **Test:** clean machine β `docker compose up` β everything boots.
- **Deliverable:** submission-ready reproducible repo.
---
## 13. Guiding Principles
| Principle | How it's honored |
|---|---|
| One thing at a time | Each phase = a single capability, nothing bundled |
| Always runnable | Every phase ends with a script/CLI you can execute |
| Local-first | Plain scripts; `start.sh`/`stop.sh` at P9βP10; Docker/GHCR last (P13) |
| Builds upward | Search β RAG β Signals β Gap β Graph β Agent β API β UI |
| Testable atoms | Each phase has a concrete pass/fail test |
| De-risked | Hardest integration (agent, P8) sits on already-proven tools |
| SSOT everywhere | Domain in `vantage_core`; types in `openapi.yaml`; no duplicated logic |
---
## 14. Local Dev Workflow
- **Dependencies:** Python 3.11 venv per service; `pip install -e packages/vantage_core`.
- **Config:** copy `.env.example` β `.env`; fill Qdrant/Neo4j/OpenAI/Langfuse creds.
- **One-shot scripts (P2βP8):** `ingest.py`, `search.py`, `ask.py`, `refresh_signals.py`,
`compute_gaps.py`, `build_graph.py`, `agent_cli.py` β run individual capabilities.
- **Long-running services (P9βP10):** `./start.sh` boots api (uvicorn) + web (vite);
`./stop.sh` stops both. No Docker required during development.
- **Seeding:** `make seed` (or `scripts/seed_all.sh`) populates the managed DBs end-to-end,
idempotently β runnable by reviewer if they bring their own free-tier creds.
---
## 15. Reproducibility & Delivery
- **Images:** built and pushed to **GHCR** (`ghcr.io/<user>/vantage-{api,worker,web}`) by a
GitHub Action on merge to main.
- **One command:** reviewer clones, drops in provided `.env` (demo creds), runs
`docker compose up` β Docker pulls pre-built images β full stack boots. DBs are pre-seeded.
- **Rule:** always read `docker-compose.yml` and `.env.example` before answering infra
questions; never guess env var names or ports.
---
## 16. Evaluation Methodology
- **Golden set:** 50 Q&A β **10 hand-labeled** (human ground truth, breaks LLM-circularity)
+ 40 generated by Claude Opus over sampled articles.
- **Metrics:** RAGAS (faithfulness, context recall, answer relevance) + **NDCG@5** for retrieval.
- **Output:** `eval/report.md` table, surfaced in the README.
- **Honesty:** LLM-as-judge limitations stated explicitly; the 10 human-labeled anchor credibility.
---
## 17. Observability
- **Langfuse Cloud** traces every LLM call, tool call, and agent handoff.
- Logged per query: query β extracted topic β momentum β retrieval score β answer β gap flag.
- **Fire-and-forget:** tracing never blocks or breaks a user response.
---
## 18. Demo Script
Five rehearsed queries, in order β each builds on the last and together they exercise every
capability in the brief:
1. **RAG only** β *"What are the challenges of AI in healthcare?"* β cited answer.
2. **Signal only** β *"What technology topics are surging right now?"* β ranked momentum.
3. **Gap only** β *"What should we commission next quarter?"* β GapScore table + 2Γ2.
4. **Multi-hop** (GapβGraphβRAG) β *"Which companies sit in our biggest AI gaps?"* β synthesis.
5. **Multi-turn memory** β follow-up *"Which of those are we thin on?"* β memory-scoped gaps.
---
## 19. Effort Summary
| Phase | Theme | Effort |
|---|---|---|
| 1 | Bootstrap & Connectivity | π’ 2h |
| 2 | Data Ingestion | π‘ 3β4h |
| 3 | Retrieval (hybrid + rerank) | π‘ 3β4h |
| 4 | RAG Answers (cited) | π‘ 3β4h |
| 5 | External Signals | π’ 2β3h |
| 6 | Coverage + GapScore | π‘ 3β4h |
| 7 | Knowledge Graph | π‘ 3β4h |
| 8 | Agent (CLI) | π΄ 4β5h |
| 9 | API | π‘ 3β4h |
| 10 | Frontend | π΄ 6β8h |
| 11 | Evaluation | π’ 2β3h |
| 12 | Observability | π’ 2h |
| 13 | Containerize + GHCR | π‘ 3β4h |
| **Total** | | **β 42β53h** |
Build order is strictly sequential P1 β P13. Fits comfortably within the 2β3 day budget.
|