0.167.27

Fixed

  • Кластер фиксов аудита 2026-06 (#204, #205 — P2). (1) #203 [A-015]: байтовая обрезка newText[:4000] soul_evolved в Dream резала многобайтовые UTF-8 руны (кириллица, эмодзи) — в БД и system prompt попадал инвалидный UTF-8. Теперь лимит soulEvolvedMaxRunes считается в рунах, обрезка — rune-safe через общий truncateRunes с маркером «…[обрезано]» (виден в UI и в следующем dream-цикле), hard limit синхронизирован с промптом («target max 1000 chars; hard limit 4000 chars»), no-op-детект newText == currentSoul перенесён после обрезки (сравнивает фактическое сохраняемое значение). (2) #204 [A-016]: лимит summary/reflection в skill_tool намеренно остаётся в БАЙТАХ — он согласован с PG CHECK chk_skill_runs_summary_size/reflection_size (миграция 089, octet_length), а rune-based Go-чек разошёлся бы с БД для кириллицы/эмодзи. Расхождение с JSON Schema устранено явно: description параметров и сообщение об ошибке называют единицу («4000/8000 UTF-8 bytes, multibyte characters count as 2-4 bytes each») — прежде schema maxLength (code points) и текст ошибки молча подразумевали разные единицы, и LLM с 4000 кириллическими символами получал непонятный reject на 8000 байтах. (3) #205 [A-017]: data race на поле logger в SkillReflectionJob — SetLogger писал голое поле без синхронизации, reflectSkill читал из другой горутины (на практике main.go зовёт SetLogger до Start, но контракт этого не гарантирует). Поле переведено на atomic.Pointer[llmlog.Logger] (Store/Load), nil-семантика сохранена. Тесты: rune-safe обрезка на 4500 рунах кириллицы+эмодзи (валидный UTF-8, лимит+маркер) и позитивная граница (500 рун сохраняются дословно); байтовый лимит на кириллице (2000 рун=4000 байт проходят, 2001 руна=4002 байта и 4001 руна reflection — reject с указанием единицы); конкурентные Store/Load логгера под -race. Попутно устранён пре-существующий data race в TestMaybeCompactAsync_EnabledGate/TestMaybeCompactAsync_TryLock (наблюдатели читали fakeProvider.callsAll без мьютекса; добавлен потокобезопасный callsSnapshot()) — go test -race ./internal/memory/... теперь чистый.