feat(client): intraline diff в блоке предложения-правки (#331) #336
Reference in New Issue
Block a user
Delete Branch "fix/331-intraline-diff"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Intraline diff в блоке предложения-правки (#315): вместо «вся старая строка красным зачёркнута / вся новая зелёным» подсвечиваются только ИЗМЕНЁННЫЕ фрагменты внутри строки (git-style). Правка одной буквы (
заведем→заведём) теперь видна сразу.closes #331.Чисто клиентское, только рендер — БД/бэкенд/MCP/IComment/мутации/Apply/Badge не тронуты.
Как
computeSuggestionDiff(old, new) => { old: Segment[], new: Segment[] }(Segment = {text, changed}) вsuggestion.ts. Гибрид word+char:diffWordsWithSpace— словный каркас, затемdiffCharsвнутри смежной пары removed+added (замена слова), так что подсвечиваются только различающиеся буквы, а не слово целиком; одиночная вставка/удаление — целиком changed; equal — common с обеих сторон. Конкатенация каждой стороны воспроизводит вход (lossless).useMemoпо[selection, suggestedText].comment-list-item.tsx: посегментный рендер<span>вместо двух цельных<Text>; changed-сегменты получают.suggestionChanged(усиленный currentColor-тинт + bold, БЕЗ text-decoration — line-through старого блока сохраняется на изменённых буквах; вся старая строка всё ещё читается как removed).diff@8.0.3(jsdiff, уже в корневом package.json) добавлен вapps/client/package.json(+ lockfile, аддитивно).How verified
tsc --noEmit— чисто.vitest run— 892 passed | 1 expected-fail (97 файлов).suggestion.test.ts:заведем→заведём(ровное/ёchanged), замена слова (общеемиростаётся common, без побуквенного шума), вставка/удаление слова, идентичные строки. Ассерты по сегментам (текст + флаги), non-vacuous.Ограничение честно: визуального тулинга в репо нет — пиксельный вид тинта/жирности на изменённых токенах и на узком (390px) comment-панели нужен человеческий проход. Логика diff и рендер-компиляция проверены (юнит + tsc + полный suite).
Checklist
🤖 Generated with Claude Code
Ревью — #336 (intraline diff в блоке предложения-правки, #331), round 1, head
f13105333, base developf5d19f97Вердикт: CHANGES — фича чистая, корректная и хорошо покрыта; правка одна и микроскопическая: комментарий к CSS-правилу
.suggestionChangedописывает подчёркивание, которого в правиле нет (и сам себе противоречит двумя строками ниже). Почини F1 — и PASS.Объективка запущена мной (head
f13105333, client):tsc --noEmit→ 0; vitest наsuggestion+comment-list-item→ 20 passed (2 файла). Зелёная. (Кодер: полный client-suite 892 passed.)Веер 7 аспектов (security/stability/test-coverage/conventions/simplification/regressions/coherence):
computeSuggestionDiffпроверен эмпирически на реальномdiff@8.0.3: 200k+ рандом-кейсов lossless, 0 потерь, ни одного throw (пустые строки, whole-line replace, whitespace, unicodeё/decomposed, emoji, смежные замены);useMemo-deps корректны, рендер без raw-HTML.dangerouslySetInnerHTMLнет;diff@8.0.3— аддитивный пин уже-корневого jsdiff; секретов нет.заведем→заведёмассертит, что changed ТОЛЬКОе/ё(не всё слово) — падал бы на whole-line-baseline; замена слова / вставка / удаление / identical покрыты;comment-list-item.test.tsxадаптирован (getByText→textContent.toContainиз-за разбивки на span'ы), существующие ассерты не ослаблены.diffWordsWithSpaceкрасит слово целиком, только-diffCharsместами хуже на whitespace-кейсах), dep уместен, мёртвого кода нет.Segment[]producer↔consumer совпадает; line-through старой строки сохраняется (правило намеренно без text-decoration); CSS-класс новый, коллизий нет; scope-claim верен (толькоapps/client, backend/MCP/мутации не тронуты).Do — почини, потом ставь
review/needs.suggestionChangedобещает подчёркивание, которого в правиле нет — поправь описание —apps/client/src/features/comment/components/comment.module.css:56-60.Блок-комментарий (:58) говорит «adds a stronger tint plus an underline so the eye lands on the changed letters». Но само правило
.suggestionChanged(:61-69) подчёркивания НЕ добавляет — толькоbackground(color-mix тинт) +font-weight:700, и внутренний комментарий (:64-65) прямо пишет «Notext-decorationhere on purpose». Итог: заголовочный комментарий противоречит и коду, и соседнему комментарию — вводит в заблуждение (будущий редактор решит, что подчёркивание потеряли, и «вернёт» его). Внесено этим PR.Fix: убери «plus an underline» из :58 (стиль различает changed-фрагмент тинтом + жирностью, без подчёркивания — чтобы наследованный line-through старого блока сохранялся), либо приведи текст в соответствие с фактическим правилом.
⛔ DROP — кодеру НЕ делать · калибровочный лог (для оператора)
[below-threshold]suggestion/high[regressions] при пустомcomment.selectionно заданномsuggestedTextвся новая строка становится lone-insertion → целиком changed (жирная/тинт), а не просто зелёная. Косметика, читается как «всё новое», автор вправе принять — не дефект.[speculative]low/high[simplification] вisReplacementPairветка(part.added && next.removed)(added-before-removed) не исполняется — jsdiff всегда эмитит removed-before-added (0/300k). Order-agnostic graceful degradation, остаётся lossless; удаление — не явный выигрыш, автор вправе оставить.F1: fixed — поправил заголовочный комментарий к
.suggestionChanged(comment.module.css): было «adds ... an underline», стало «adds a stronger tint plus bold weight». Правило действительно даёт только color-mix тинт + font-weight:700, без text-decoration (что и подтверждает внутренний комментарий). Только текст комментария, поведение/тесты не тронуты. review/needs.Ре-ревью — #336 (intraline diff в блоке предложения-правки, #331), round 2, head
94f60cf0, base developВердикт: PASS — F1 закрыт, готово к мержу. Delta r1→r2 = ровно одна строка (комментарий CSS), scope-creep нет; остальной PR байт-идентичен полностью отвеерянному round-1 состоянию (все 7 аспектов там LGTM).
F1 fixed (сверено по коду): заголовочный комментарий
.suggestionChanged(comment.module.css:56-60) теперь «adds a stronger tint plus bold weight» — соответствует правилу (color-mix тинт +font-weight:700, без text-decoration) и больше не противоречит внутреннему комментарию «Notext-decorationhere on purpose». Ложное упоминание подчёркивания убрано.Объективка перезапущена мной (head
94f60cf0): clienttsc --noEmit→ 0; vitestsuggestion+comment-list-item→ 20 passed. Зелёная. (Изменение — только текст комментария, поведение/тесты не тронуты.)