Repository navigation
fix(#59): classify mixed relay-XML content as user text - #67
Merged
Merged
Conversation
A user prompt starting with a <teammate-message> wrapper plus real text (a trailing question, quoted XML) was swallowed as a teammate relay and the user's words were dropped from display. Relay detection now requires the whole content to be complete relay blocks: TEAMMATE_BLOCK_RE moves to the canonical core and is shared with teammateMessageParser, so classification and card rendering cannot drift. isTeammateRelayLine applies the whole-content rule across text blocks; the subagent display path only routes pure relays to teammate cards, mixed content keeps its text as subagent input. Pure relays, transcript-turn semantics and the hook canon (#55) are unchanged; malformed wrappers (unclosed, old-style id='x' — unconfirmed in real transcripts) stay visible as user text instead of vanishing. Co-Authored-By: Claude Code <noreply@anthropic.com>
axisrow
commented
Oct 8, 2026
axisrow
left a comment
Owner
Author
There was a problem hiding this comment.
Пост-ревью PR #67 — fix(#59): mixed relay-XML → user text. Вердикт: approved
PR уже смержен, поэтому это пост-ревью: правок не требуется, заметки ниже — кандидаты в фоллоу-ап, если когда-нибудь понадобятся.
Проверено по диффу против origin/main:
- Ядро (turn-accounting.mjs): relay теперь = только полные
<teammate-message teammate_id="...">...</teammate-message>блоки (плюс whitespace). isTeammateRelayLine склеивает text-блоки через\nи применяет правило к контенту целиком; смешанный контент → isUserChunkLine = true → UserChunk, слова пользователя сохраняются. Ядро zero-imports — бандл в renderer безопасен. - Все потребители консистентны: MessageClassifier (категория user → UserChunk), hook isRealUserLine (импортирует ядро напрямую), isTranscriptTurnLine (turnCount в jsonl.ts), groupTransformer (display summary), displayItemBuilder (гейт карточек). Второго расходящегося механизма на вопрос «relay или нет» не появилось.
- Regex один: TEAMMATE_BLOCK_RE перенесён в ядро, teammateMessageParser переиспользует. Оба потребителя клонируют regex (
new RegExp(source, flags)), утечки lastIndex у global-regex нет. - Первый call site карточек (displayItemBuilder.ts:274) остался без гейта — проверил достижимость: для mixed недостижим. classifyMessages отправляет mixed в категорию user, и он не попадает в AIChunk.responses; в responses попадают только чистые relay-и (категория ai) и meta-строки, которые сайт скипает. Гейт там был бы no-op. Второй site (subagent-путь) загейчен корректно и рендерит mixed как subagent_input.
- eslint allowImportNames: все 14 имён deep-импорта из turnAccounting.ts покрыты; stripTeammateBlocks напрямую никто не импортирует — несоответствия нет. d.mts-сигнатуры (
inputSideTokens(u?),readConfig(raw?)) согласованы с новыми вызовами тестов без аргументов. - Тесты и fixture: смена fixture на канонический teammate_id корректна; новый тест пинает, что unclosed и old-style (id= без teammate_id) обёртки — user text. prettier на test/ не распространяется, так что длинная строка в relay-тесте — только косметика.
Наблюдения вне находок: (1) malformed обёртки в старых логах теперь открывают hook-turn — осознанная семантика #59, покрыта тестом; (2) гейт в displayItemBuilder не покрыт тестом — displayItemBuilder.test.ts вообще не тестирует teammate-карточки, можно добросить в фоллоу-апе; (3) SubagentResolver.ts:165 держит свой regex для summary-атрибута — это извлечение атрибута из файлов сабагентов, не relay-предикат, дрейфа нет.
This was referenced Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Суть
Релей определяется только тогда, когда весь контент состоит из полных блоков
<teammate-message teammate_id="...">…</teammate-message>. Промпт, начинающийся с обёртки, но содержащий пользовательский текст (вопрос после релея, цитата), остаётся user-сообщением — текст сохраняется в отображении.Fixes #59
Что изменено
scripts/turn-accounting.mjs— канон:TEAMMATE_BLOCK_RE(тот же regex, что у парсера карточек) +stripTeammateBlocks;isTeammateText= «весь текст — только полные релей-блоки»;isTeammateRelayLineприменяет whole-content правило и по массиву текст-блоков (раньше один релей-блок делал всю строку релеем).src/shared/utils/teammateMessageParser.ts— импортирует regex из канона вместо собственной копии: классификация и рендер карточек не могут разъехаться.src/renderer/utils/displayItemBuilder.ts— сабагентский путь кладёт в карточки только чистые релеи; смешанное содержимое идёт вsubagent_inputс полным текстом (раньше текст вне обёртки выбрасывался).scripts/turn-accounting.d.mts,eslint.config.js— декларации и allowlist импорта нового экспорта.Поведение
обёртка + вопрос) — user-сообщение, transcript-turn остаётся одним ходом.id='x', не подтверждён в реальных транскриптах) — user-текст, не невидимый релей.Тесты
turnAccounting.relay.test.ts: репро из issue (строка и массив), чистый релей, некорректные обёртки.id='x', mixed-массив, незакрытая обёртка в хук-тесте); фикстура парити-теста переведена на реальную форму релея — золотые числа не изменились.pnpm typecheck— чисто;pnpm test— 950/950; eslint на изменённых файлах — чисто (заодно сняты 3 существовавших lint-ошибки вturnBudgetHookScript.test.ts).🤖 Generated with Claude Code