Files
gpu-services/nanoclaude/tests
Hyungi Ahn 86c076fcf9 fix(nanoclaude): prevent classifier router JSON leak in fallback path
When the classifier (gemma4:e4b) timed out or returned unparseable
output, the worker's "direct" branch re-called backend_registry.classifier
with the original user message. The classifier still had CLASSIFIER_PROMPT
attached, so it dutifully emitted router JSON like
{"action": "route", "response": "추론 모델에게 전달할게요!", ...}
which was streamed verbatim to Synology Chat as the bot's answer.
The reasoning model (Gemma 26B on Mac mini) was never actually invoked.

Changes:
- New services/classifier_io.py with parse_classification (returns explicit
  classification_failed instead of silently morphing to direct) and
  looks_like_router_json (defense-in-depth guard on any user-facing output).
- New BackendRegistry.chat_fallback adapter — same physical model as the
  classifier but with CHAT_FALLBACK_PROMPT (no JSON, no routing meta).
  This is what the worker now uses for failed-classification recovery.
- worker.py direct branch split into two:
    * elif action=="direct" and response_text and not router_json → push as-is
    * else → _fetch_fallback_text via chat_fallback (never the classifier),
      with leak guard suppressing router-shaped output.
- Belt-and-suspenders leak check on the final concatenated answer before
  _send_callback fires.
- Static safe message ("분류기가 응답을 제대로 만들지 못했어요...") when the
  fallback path produces nothing usable.

Tests:
- 28 unit tests in tests/test_classifier_io.py covering parser failure
  modes and the leak guard (incl. verbatim production payload).
- Integration tests in tests/test_worker_fallback.py asserting
  backend_registry.classifier is NOT called by the fallback path,
  chat_fallback IS called, router JSON output is suppressed, and the
  chat_fallback adapter system_prompt != CLASSIFIER_PROMPT.

Out of scope: long-input pre-routing optimization, EXAONE_* env rename,
full model routing redesign.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 08:33:54 +09:00
..