Files
brain-of-reese/.agent/user_stories/honest-deflection.md
T
ducoterra 022da8e2bc feat: scaffold Brain of Reese — FastAPI RAG chat over Postgres 17 + pgvector
Foundation (phase 01, verified):
- FastAPI app: /api/health, /api/suggestions, /api/chat (placeholder),
  static frontend served locally (no CDN)
- Postgres 17 + pgvector via db/Containerfile + compose.yaml
  (podman compose up -d db), Alembic initial migration (documents,
  chunks with vector(768), query_log)
- LLM client targeting https://aipi.reeseapps.com/v1 (turbo/embed);
  scripts/llm_probe.py verified models + 768-dim embeddings live
- Conditional debugpy: imported only when DEBUGPY=1 (attach on demand,
  :5678); logging config for clean single-line logs
- Frontend shell: mobile-first chat + Sources pages, tokens, a11y baselines
- Tests: 24 unit+integration (99% coverage on app/), ruff + pyright clean,
  Playwright smoke E2E (3 tests) against a deterministic mock LLM
- Planning: .agent/PLAN.md (architecture + LOCKED decisions), AGENTS.md,
  6 user stories, 7 phase files (one story / one phase / one Playwright
  suite each)
2026-08-21 13:42:21 -04:00

58 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Story: Honest Deflection
**Phase:** `04_story_honest_deflection.md` · **E2E:** `tests/e2e/test_honest_deflection.py`
## Narrative
As **a user**, when I ask something Brain genuinely has no notes about, I
want it to **admit it plainly** and still be helpful — so I never walk away
with a confident-sounding hallucination.
- **Given** the knowledge base is about homelab/infra topics
- **When** I ask "How do I bake sourdough bread?"
- **Then** retrieval's best similarity is below `BOR_RELEVANCE_THRESHOLD`,
Brain switches to deflection mode, opens with a variant of
**"I haven't done anything like that"**, stays chippy, and offers 2–3
alternative questions about things it *does* know (from the weak hits).
## Acceptance criteria
1. Gate: `max(1 − cosine_distance) < BOR_RELEVANCE_THRESHOLD` ⇒
`<relevance>LOW</relevance>` + `DEFLECT_MODE` system prompt (weak-hit
**titles only**, no full docs).
2. The LLM is still called (voice stays chippy); the prompt forces the
honesty phrasing + alternative suggestions (PLAN §6).
3. `done` event carries `deflected: true` and `suggestions[]` (2–3 strings).
4. `query_log` row has `deflected=true` + the weak `top_score`.
5. UI: the deflected bubble is visually distinct (amber border/background),
and "Maybe try:" chips render below it; clicking a chip asks that
question (delegated to the suggestion-chips story for chip behavior;
here only rendering).
6. Threshold is env-tunable; lowering it to ~0 makes every question an
"answer" (documented in README troubleshooting).
7. Unit tests cover the gate boundary (score == threshold → answer mode;
just below → deflect) using a fake retriever — no LLM needed.
## UI Visualization & Structure
- Deflected brain bubble: `background: var(--accent-bg) #fff7e8`,
`border: 1px solid var(--accent-line) #f59e0b`, text stays `var(--ink)`
(or accent-ink for emphasis ≥4.5:1) — clearly "different" from a normal
answer without being alarm-red (it's honesty, not an error).
- Below the bubble: `Maybe try:` label (visually hidden for SR, `aria-label`
on the chip group) + 2–3 `.suggestion-chip` pills (same chip component as
onboarding: ≥44px height, brand-soft bg, brand-ink text).
- Bubble may include the model's alternative list in text too; chips are the
one-click affordance.
- Contrast audit: `#92400e` on `#fff7e8` ≈ 8.7:1 ✓; chip text on chip bg ≥6:1 ✓.
## Playwright Mapping Rule
**Test Scenario → `tests/e2e/test_honest_deflection.py`** (mock LLM, seeded KB):
1. `test_off_topic_question_deflects_honestly` — ask "How do I bake
sourdough bread?"; assert the answer bubble is `.is-deflected`, its text
matches /haven't done anything like that/i, and ≥2 "Maybe try:" chips
render below it.
2. `test_deflection_suggestions_are_clickable` — click the first deflection
chip; assert the input is populated/focus behavior per chip contract and a
new user bubble is created.
3. `test_threshold_gate_unit_boundary` is a **unit** test (not Playwright):
retriever returns score 0.30 → HIGH; 0.2999 → LOW (mocked components).