feat(trace): WINDSURFAPI_LEAK_TRACE — structured reasoning/content boundary logs for catching live reasoning leaks (opt-in, default OFF) - #249
Conversation
|
评审:门控和脱敏我逐条驱动过,都成立。请补一条 —— 标记表认不出 我实跑过什么head
「门关时热路径只多一次 env 读 + 布尔比较」这句我特意攻过,它成立。 我原本怀疑的是调用点参数求值 —— 三个埋点的分层选得准:事件层拿原始通道、分类层拿决策、出口层拿 settle 后的尺寸比。要定位「是哪一层把 reasoning 放进 content 的」,这三个位置是最小充分集。 M1(请补)—
|
… boundary logs (default OFF) Gate WINDSURFAPI_LEAK_TRACE=1 enables LEAK_TRACE-prefixed structured log lines at the reasoning/content boundary to catch the live-only reasoning
…failure exits; measured log volume - THINK_MARKERS now includes '<think>'/'</think>' — the dialect dwgx#250 is named by and the dwgx#243 classifier is built on; the trace must recognize the dialect it is deployed to catch (pinned by a unit test + mutation) - connect settle probe: every loop exit logged, including error/abort where lastOkSr is null — an all-empty row read as 'traced, nothing found'. Now carries outcome: ok | client-abort | upstream-error (pinned by an error-exit fixture + mutation) - .env.example: measured volume — a 2000-token answer (one token per event) yields 2000 lines / ~215 KiB (~110 B per line); how to switch off
dd0f95e to
4f39142
Compare
中文 TL;DRM1: 我实跑过什么head
M1 —
|
中文 TL;DR
已知问题(见文末 issue):thinking 模型偶尔把 reasoning 写进 CONTENT 通道;只能在真实会话中偶发复现,受控探针复现不出来,所以下一层修复一直缺现场数据。本 PR 在 reasoning/content 边界加一套结构化日志:devin-connect-openai 事件层、messages 分类层、chat 出口层,记录通道、think-标记状态、有限文本采样、reqId/acct。由 WINDSURFAPI_LEAK_TRACE 门控,默认关闭;关闭时行为逐字不变、热路径零额外开销。本 PR 只做可观测性,不做修复;抓到现场后另开 PR 提修复。
Зачем
Протекание мыслей в контент — известная проблема, воспроизводится только живьём. Каждое поколение защиты строилось по полевой сигнатуре, а не по репродукции: #238 (rescue пустых ответов), #241 (точность rescue), #243 (перекладка ведущего
<think>-блока из content в thinking). Чтобы предложить фикс следующего слоя, нужен пойманный инцидент: какой канал, какие маркеры, какой префикс. Этот PR даёт удочку.Точки лога
src/devin-connect-openai.js— сырые события границы: канал (content/reasoning), наличие think-маркеров, ограниченный сэмпл текста,reqId/acct.src/handlers/messages.js— решения классификации/перекладки блоков.src/handlers/chat.js— что ушло в content на settle/finish, соотношение размеров reasoning и content.Модуль
src/leak-trace.js: гейт, маркеры (<think>/</think>— диалект, которым назван #250 и на котором построен классификатор #243 — плюс<thinking>и◁think▷Kimi K2), обрезка сэмплов через существующийlog-safety— в лог не пишутся ключи и полные ответы. Settle-запись несётoutcome(ok / client-abort / upstream-error): на ошибочных выходах остальные поля пусты по определению, и outcome говорит почему — вслепую пустая строка читалась бы как «трейс отработал, ничего не нашёл».Safety
WINDSURFAPI_LEAK_TRACE, default OFF. При выключенном гейте поведение побайтово неизменно, горячий путь не делает лишней работы кроме чтения флажка.0..env.exampleи README.Test plan
test/leak-trace.test.js: при включённом гейте — лог-строки с ожидаемыми полями на всех трёх точках (подмена логгера по прецедентуtest/retry-rescue-budget-split.test.js); при выключенном гейте на том же горячем пути — ни одной строки; таблица маркеров узнаёт<think>; settle на ошибочном выходе пишетoutcome, а не вслепую пустую строку.test/mutations/leak-trace.json(6 мутаций, все CAUGHT) + все spec репо: EXIT=0, anchor'ы ровно по разу.51846e0).