Found by the Chapter 2 exploration harness (epic #403) during the #399 acceptance runs — the explorer hit it through the real UI, and the e2e_oracles logscan caught the traceback independently in the same session.
Repro (function-mode stack):make e2e-up with the deterministic seam (SAPLING_MODEL_MODE=function SAPLING_FUNCTION_HANDLERS=agents.function_handlers_e2e), sign in as rich-user-active, resume the seeded tutor session ("Understanding Recursion"), and let the UI issue POST /api/graph/rich-user-active/concept-description → 500.
Root cause:agents/function_handlers_e2e.py registers six tasks (chat_tutor, quiz, classifier, summary, concepts, course_summary) but not concept_describe. agents/_providers.py::_dispatch raises LookupError("SAPLING_MODEL_MODE=function but no handler is registered for task 'concept_describe'..."); routes/graph.py's handler catches (AgentRunError, httpx.HTTPError, ValidationError) — not LookupError — so it escapes to the global handler as a 500.
Fix options: register a fixed concept_describe handler in function_handlers_e2e.py (mind the quiz_context precedent — post-response BackgroundTask handlers are deliberately left unregistered to fail fast rather than race the truncate; concept_describe is request-path, so registering it is safe), or catch LookupError in the route with a graceful degradation. The runbook (docs/e2e-exploration.md §7) uses this bug as its worked promotion example — a Chapter 1 journey asserting the concept-description path in function mode would be the promotion.
🤖 Generated with Claude Code
Found by the Chapter 2 exploration harness (epic #403) during the #399 acceptance runs — the explorer hit it through the real UI, and the
e2e_oracleslogscan caught the traceback independently in the same session.Repro (function-mode stack):
make e2e-upwith the deterministic seam (SAPLING_MODEL_MODE=function SAPLING_FUNCTION_HANDLERS=agents.function_handlers_e2e), sign in asrich-user-active, resume the seeded tutor session ("Understanding Recursion"), and let the UI issuePOST /api/graph/rich-user-active/concept-description→ 500.Root cause:
agents/function_handlers_e2e.pyregisters six tasks (chat_tutor,quiz,classifier,summary,concepts,course_summary) but notconcept_describe.agents/_providers.py::_dispatchraisesLookupError("SAPLING_MODEL_MODE=function but no handler is registered for task 'concept_describe'...");routes/graph.py's handler catches(AgentRunError, httpx.HTTPError, ValidationError)— notLookupError— so it escapes to the global handler as a 500.Fix options: register a fixed
concept_describehandler infunction_handlers_e2e.py(mind thequiz_contextprecedent — post-responseBackgroundTaskhandlers are deliberately left unregistered to fail fast rather than race the truncate;concept_describeis request-path, so registering it is safe), or catchLookupErrorin the route with a graceful degradation. The runbook (docs/e2e-exploration.md§7) uses this bug as its worked promotion example — a Chapter 1 journey asserting the concept-description path in function mode would be the promotion.🤖 Generated with Claude Code