0.167.17

Fixed

  • Адресация замечаний ocr review по батчу компакции (#282/#284/#285/#286). (1) TruncateToolResult: стоимость маркера \n[... truncated ...]\n вычитается из бюджета — результат больше не превышает maxTokens на ~5 токенов; документирован +0.5-запас хвоста. (2) archiveToConversation (memory): битый JSON tool_calls больше не выбрасывает tool-вызовы из handoff молча — slog.Warn + рендер сырого блоба <raw>…</raw>; добавлен общий кап входа сводки compactConversationRunes=250k рун с маркером обрезки (сотни tool-результатов × 2000 рун раздули бы вход за контекст модели сводки — clamp DynamicSummaryMaxTokens ограничивает только выход); ошибка GetRecentMessages при поиске userID теперь логируется (раньше — невидимая деградация до shared-scope консолидации). (3) Дедупликация набора диалоговых ролей: канонический store.IsDialogRole/dialogRoles + пин-тест TestDialogRoleFilterSync, сверяющий SQL-константы dialogRoleFilter (SQLite) и pgDialogRoleFilter (PostgreSQL) с каноном — список в memory и SQL больше не может разъехаться молча. (4) Хрупкий хардкод фолбэка бюджета: memory.FallbackHistoryBudgetTokens экспортирован и зажат пин-тестом TestAutocompactFallbackBudgetMatches против agent.ComputeBudget(DefaultContextMaxTokens).History. (5) tokens.isCJKRune дополнен Unicode-блоками (Extensions C–H, Compatibility Ideographs, CJK Strokes, Enclosed CJK, Bopomofo); package-doc уточняет калибровку ±20% (латиница/CJK) и консервативный вес кириллицы 0.4; doc TruncateByTokens фиксирует контракт maxTokens <= 0 → "". (6) marshalArgsNoEscape (compressor) документирован как best-effort + debug-лог при ошибке кодирования; фолбэк emergencyCompact помечен best-effort (инвариант последнего user не гарантируется). JSDoc CompactionConfig в types.ts переписан без внутреннего противоречия (union всех схем, включая legacy-only поля). Ложные срабатывания ревью (guard maxTokens<=0 в TruncateByTokens существует; тест зелёный) — отклонены с обоснованием. Принятые LOW без правки: O(N) rune-подсчёт Count (осознанный трейд-офф точности; вызовы линейны по истории), rune-аллокация в compressTruncate (только путь summarization), float-накопление в Count (погрешность ~1e-10 на 400k рун), renderArchiveMessage покрыт опосредованно тестами archiveToConversation. Тесты: TestArchiveToConversation_MalformedToolCalls_RendersRaw, _TotalRunesCap, TestDialogRoleFilterSync, TestIsDialogRole, TestAutocompactFallbackBudgetMatches; полный go test ./... зелёный, golangci-lint — 0 issues, npm run check — 0 ошибок.