Scout Training — Phase 1 Complete

All 71 knowledge base articles have been tagged with training questions. Scout's search accuracy is measurably better. Next up: making her smarter.

✓ 71 / 71 articles verified live
Checking live KB…

Phase 2: How to Make Scout Smarter

Phase 1 improved what Scout can find. Phase 2 improves what she can understand, remember, and learn from. These are ordered by impact-per-effort — start at the top.

✓ SHIPPED 2026-05-16

1. Gap detection from real conversations

Scout already captures every conversation where it couldn't confidently answer (can_answer = false) or where the user thumbs-downed the response (feedback = 'not_helpful'). The admin sidebar's Content Gaps panel surfaces both signals as ranked lists with date, user, and full question/answer text. CSV export available at /api/admin/export-gaps for offline analysis.

Shipped: Admin panel + /insights endpoint (topUnansweredTopics) + CSV export, all live. Real signal will accumulate once Scout is in front of customer traffic.

✓ SHIPPED 2026-05-16

2. Query expansion with a Plansight glossary

Before a user's question hits UserGuiding search, Scout now rewrites acronyms and aliases: BP → BenefitPoint, RFP → Request for Proposal, MR → Market Response, Brite → Brite Benefits, etc. Bi-directional — typing the full term also adds the acronym to the search context. One-way corrections also handle voice-dictation typos (plan site → Plansight) and customer synonyms (print / PDF / output → presentation).

Shipped: 106 bi-directional pairs + 7 one-way corrections in api/lib/glossary.js. Wired into api/routes/chat.js (live-search path). Sanity-check at /api/glossary/test?q=....

SUPERSEDED 2026-05-16

3. LLM re-ranking of KB search results

The original plan (re-rank UG keyword results before sending to Claude) was written before the KB Bundle path existed. Now that Scout's primary retrieval path is the cached bundle — where Claude does its own relevance ranking implicitly when reading the markdown — explicit re-ranking on the live-search fallback would add complexity without a real production impact (the fallback path runs <1% of traffic).

Why superseded: bundle path made the original design moot. Revisit only if the live-search fallback becomes a meaningful share of traffic, or if you want to add explicit re-ranking inside the bundle path (a different feature).

✓ SHIPPED 2026-05-16

4. Conversation memory for follow-ups

Scout now tracks the last 3 user/assistant pairs across a chat session, so questions like "what about for admins?" or "and for canceled ones?" are interpreted against the prior turns. The fix is three-layered: the system prompt nudges Claude to use conversational context, the message array is capped server-side at 6 messages so token cost stays bounded, and KB-search queries for follow-up questions get stitched with the previous user turn so UserGuiding's keyword search still returns relevant articles (without that, follow-ups returned garbage and Claude had to fall back to working memory).

Shipped: isLikelyFollowUp() + history cap in api/routes/chat.js; FOLLOWUP_NUDGE appended to the resolved system prompt in api/lib/claude.js.

✓ SHIPPED 2026-05-16

5. Confidence-gated responses + HubSpot

When Scout's answer trips the no-answer heuristic (can_answer = false), the widget surfaces a "Can't find what you need? Get help" nudge that forks into two paths: "I want to learn how to do something" (resource request) or "Something isn't working right" (support ticket). Tickets flow through POST /api/ticket into HubSpot's Support Tickets pipeline (836359507), landing in the New (Unassigned) stage with all 7 Scout custom properties populated (submitter, brokerage, page URL, chat transcript). Slack notification fires in parallel.

Shipped: Engineering was already largely built (escalation UI, ticket route, HubSpot lib, custom property wiring). Today's session added the missing routing config: HUBSPOT_PIPELINE_ID, HUBSPOT_STAGE_ID, HUBSPOT_PORTAL_ID in Vercel production env. End-to-end smoke test confirmed ticket creation, correct pipeline/stage routing, and property population. Optional polish for later: populate brokerage_hubspot_map to auto-associate tickets to Company records in HubSpot CRM.

DEFERRED 2026-05-16

6. Semantic search layer (embeddings)

Original plan: add an embedding index alongside UG keyword search to catch paraphrased questions ("invite someone" matching "add a team member"). Deferred because Scout's KB Bundle path already provides semantic-like retrieval via Claude reading the whole bundle. Building semantic search now would add a new embedding-model vendor (Voyage, OpenAI, or self-hosted) to the compliance footprint during the active Vercel+Neon BAA push, for dormant code that wouldn't change user-facing behavior today.

Trigger to revisit: when gap detection (#1) shows a persistent pattern of paraphrase misses in real customer traffic (the question's meaning is clearly in the KB but Scout didn't find it). Corpus size is not the trigger — a healthy KB stays focused, not large. Signal will dictate vendor choice + scope at that point.

✓ SHIPPED 2026-05-16

7. Video timestamp deep-linking

When Scout's answer cites a Wistia video, the embed now jumps to the exact second the relevant content was discussed instead of always playing from the start. Transcripts are now formatted as [Ns] segment text so Claude can identify the precise moment, citation syntax extended to <videos>hashedId@83</videos>, and the widget's iframe URL appends &wtime=N. The video card label also shows "Watch from 1:23" instead of generic "Watch this video" when a timestamp was picked.

Shipped: SRT timestamps preserved in api/lib/wistia.js; citation grammar extended in api/lib/claude.js; startSeconds threaded through api/routes/chat.js; iframe + card label updated in widget/chatbot.js. Note: requires a KB Bundle rebuild (admin → Library → Rebuild) to pick up the new timestamp-formatted transcripts in cached content.

✓ SHIPPED 2026-05-16

8. Automated feedback → training loop

Every chat where can_answer = false or feedback = 'not_helpful' already auto-captures into the conversations table (shipped as Phase 2 #1). What was missing was the action loop: a way to mark a gap addressed once you've fixed it (wrote the article, updated the glossary, etc.). The Content Gaps admin tab now has a Mark addressed button on every row, an Open / Addressed / All filter at the top, and Reopen for misclicks. The audit trail records who addressed each gap and when.

Shipped: migration 020_gap_addressed.js adds gap_addressed_at + gap_addressed_by columns; POST /api/admin/gaps/:id/address and /reopen endpoints; ?gaps=open|addressed|all filter parameter on /insights and /stats; UI filter toggle + per-row action buttons in widget/admin.html. Defaults to showing only open gaps so the list stays focused as your KB matures.