Spaces:
Sleeping
fix(orchestrator): KI-012 critical — transition to free-form after fact-find
Browse filesP002 transcript revealed: after fact-find completed at turn 11, the bot
returned the SAME readback summary ("Got it — here's what I've understood:
…") to all 19 subsequent free-form policy questions. User asked about
claim settlement, room rent caps, comparisons — bot just echoed the
profile readback every time.
Root cause: on fact-find completion, the code only cleared
`session.awaiting_question_id` but did NOT set
`session.free_form_session = True`. Next turn classifier still routed
through the fact-find branch, `next_question()` returned None, code
hit the "complete" path again, emitted readback summary again. Loop.
Fix is one line: set `session.free_form_session = True` + flush. Now
subsequent turns skip the fact-find branch entirely and go through
retrieval + brain as intended.
Effect on the audit data: every persona's post-fact-find ~20 turns
will now go through real RAG + brain instead of silently looping the
readback. The 100-persona audit data will finally surface real
policy-Q&A behaviour at scale.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@@ -242,9 +242,15 @@ async def handle_turn(
|
|
| 242 |
else:
|
| 243 |
brain_tag = "needs_finder::fact_find_continue" if in_fact_find_continuation else "needs_finder::fact_find_start"
|
| 244 |
else:
|
| 245 |
-
# Fact-find complete — produce a profile readback + invite next step
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
from backend.needs_finder import readback_summary
|
| 247 |
session.set_awaiting(None)
|
|
|
|
|
|
|
| 248 |
summary = readback_summary(session.profile)
|
| 249 |
reply = (
|
| 250 |
f"Got it — here's what I've understood: {summary}. Want me to suggest 2-3 policies that fit your profile, "
|
|
|
|
| 242 |
else:
|
| 243 |
brain_tag = "needs_finder::fact_find_continue" if in_fact_find_continuation else "needs_finder::fact_find_start"
|
| 244 |
else:
|
| 245 |
+
# Fact-find complete — produce a profile readback + invite next step.
|
| 246 |
+
# CRITICAL (KI-012): flip free_form_session=True so subsequent turns
|
| 247 |
+
# don't re-enter the fact-find branch and repeat the readback. Before
|
| 248 |
+
# this, every post-fact-find turn returned the same readback summary
|
| 249 |
+
# because next_question() kept returning None.
|
| 250 |
from backend.needs_finder import readback_summary
|
| 251 |
session.set_awaiting(None)
|
| 252 |
+
session.free_form_session = True
|
| 253 |
+
session._flush()
|
| 254 |
summary = readback_summary(session.profile)
|
| 255 |
reply = (
|
| 256 |
f"Got it — here's what I've understood: {summary}. Want me to suggest 2-3 policies that fit your profile, "
|
|
@@ -209,3 +209,48 @@ empirical signal for whether a fix is actually working in production.
|
|
| 209 |
The standing ratio target: **for every 1 user-facing bug a reviewer
|
| 210 |
catches, we should close 5 internal issues from this log before the next
|
| 211 |
review.**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
The standing ratio target: **for every 1 user-facing bug a reviewer
|
| 210 |
catches, we should close 5 internal issues from this log before the next
|
| 211 |
review.**
|
| 212 |
+
|
| 213 |
+
### KI-011 — Fact-find re-ask infinite loop under load — **FIXED in `171f2a4`**
|
| 214 |
+
|
| 215 |
+
**Severity:** P0
|
| 216 |
+
**Source:** `backend/orchestrator.py` fact-find branch + `backend/fact_find_normalizer.py` LLM-only path
|
| 217 |
+
**Discovered:** First persona of the 100-persona audit (P002, verbose style)
|
| 218 |
+
|
| 219 |
+
When NIM rate-limited the Llama-3.3-70B normalizer under audit
|
| 220 |
+
concurrency, the LLM call raised, the orchestrator marked the answer
|
| 221 |
+
ambiguous, kept `awaiting_question_id` set, and re-asked the same
|
| 222 |
+
question on the next turn. User moved on with answers to OTHER
|
| 223 |
+
questions. Normalizer rejected them. Bot re-asked again. Infinite loop.
|
| 224 |
+
|
| 225 |
+
**Fix:** Keyword fast-path in `fact_find_normalizer.py` (hand-curated
|
| 226 |
+
substring matchers for 9 metros, 15 tier1 cities, dependents
|
| 227 |
+
combinations, income/budget bands, primary goals, common health
|
| 228 |
+
conditions) bypasses the LLM for ~80% of answers. Re-ask cap in
|
| 229 |
+
`orchestrator.py` gives up after 2 failed normalizations on the same
|
| 230 |
+
question and marks it asked. Production audit on persona P002
|
| 231 |
+
post-fix: 30/30 turns completed in 85s with 0 refusals (vs. infinite
|
| 232 |
+
loop before).
|
| 233 |
+
|
| 234 |
+
### KI-012 — Bot stuck in fact_find_complete readback loop — **FIXED in next commit**
|
| 235 |
+
|
| 236 |
+
**Severity:** P0
|
| 237 |
+
**Source:** `backend/orchestrator.py` fact-find-complete branch
|
| 238 |
+
**Discovered:** Reviewing audit transcript of P002 post-KI-011-fix
|
| 239 |
+
|
| 240 |
+
After fact-find completes, the orchestrator only calls
|
| 241 |
+
`session.set_awaiting(None)` — it does NOT flip
|
| 242 |
+
`session.free_form_session = True`. On every subsequent turn, the
|
| 243 |
+
classifier still routes through the fact-find branch (because
|
| 244 |
+
`free_form_session` is false), `next_question()` returns None (all
|
| 245 |
+
fields captured), and the code path emits the readback summary AGAIN
|
| 246 |
+
instead of going to retrieval + brain.
|
| 247 |
+
|
| 248 |
+
**Effect:** P002 used 19 of 30 turns repeating the same readback
|
| 249 |
+
"Got it — here's what I've understood: …" instead of answering the
|
| 250 |
+
user's real policy questions. Every persona that completes fact-find
|
| 251 |
+
hits this.
|
| 252 |
+
|
| 253 |
+
**Fix:** When fact-find completes, set
|
| 254 |
+
`session.free_form_session = True` and flush to disk. Subsequent turns
|
| 255 |
+
skip the fact-find branch entirely and go through retrieval + brain
|
| 256 |
+
as intended.
|