test(converter): вложенный variant-A генератор + P4 + фикс всех round-trip багов (#351) #385
Open
agent_coder
wants to merge 2 commits from
test/351-nested-generator into develop
pull from: test/351-nested-generator
merge into: vvzvlad:develop
vvzvlad:main
vvzvlad:feat/381-resumable-sse-pr2
vvzvlad:feat/381-resumable-sse-pr1
vvzvlad:docs/agents-workspace-build-order
vvzvlad:feat/git-sync-2
vvzvlad:feature/offline-sync
vvzvlad:perf/342-code-splitting
vvzvlad:perf/344-background-rerenders
vvzvlad:perf/346-compression-cache
vvzvlad:perf/348-backend-lowhanging
vvzvlad:feat/196-multi-cursor
vvzvlad:feat/370-page-versioning
vvzvlad:perf/343-typing-latency
vvzvlad:fix/382-int-open-handles
vvzvlad:develop
vvzvlad:docs/how-to-test
vvzvlad:fix/ai-sdk-partial-output-oom
vvzvlad:test/351-generative-converter
vvzvlad:feat/371-roles-catalog
vvzvlad:refactor/345-server-converter
vvzvlad:refactor/294-spec-registry-cont
vvzvlad:fix/363-migration-order
vvzvlad:fix/362-metrics-route-cardinality
vvzvlad:fix/e2e-callout-and-gate-build
vvzvlad:fix/docker-re2-toolchain
vvzvlad:feat/git-sync
vvzvlad:fix/media-roundtrip-stability
vvzvlad:fix/340-comment-panel-perf
vvzvlad:fix/332-deferred-tools
vvzvlad:fix/329-ephemeral-suggestions
vvzvlad:fix/330-search-in-page
vvzvlad:fix/328-resolved-anchor-spam
vvzvlad:fix/331-intraline-diff
vvzvlad:fix/324-coverage-gate
vvzvlad:fix/325-mobile-390
vvzvlad:feat/293-A-git-sync-package
vvzvlad:feat/300-avatar-oklch
vvzvlad:fix/321-banner-mobile
vvzvlad:feat/300-avatar-colors
vvzvlad:feat/315-comment-suggestions
vvzvlad:feat/scroll-restore-stable-wait
vvzvlad:feat/300-agent-avatar-stack
vvzvlad:feat/300-avatar-polish
vvzvlad:refactor/294-tool-spec-registry
vvzvlad:feat/scroll-restore-ux
vvzvlad:fix/responsive-tablet-sidebar
vvzvlad:feature/ai-chat-page-change-observability
vvzvlad:image-inline-center
vvzvlad:fix/283-short-remap-title
vvzvlad:fix/283-slash-layout
vvzvlad:image-inline-row
vvzvlad:feat/276-ai-chat-dock
vvzvlad:fix/269-table-menu-refocus
vvzvlad:docs/dev-stand-guide
vvzvlad:feat/266-scroll-position
vvzvlad:fix/260-collab-docname-slugid
vvzvlad:test/244-phase2-tail
vvzvlad:fix/262-reindex-progress-realtime
vvzvlad:fix/258-changelog-compare-links
vvzvlad:fix/244-dataloss-bugs
vvzvlad:feat/246-spoiler
vvzvlad:feat/221-image-captions
vvzvlad:test/244-part-b
vvzvlad:feat/251-intentional-clear
vvzvlad:fix/embeddings-reindex-progress
vvzvlad:refactor/193-tool-spec-registry
vvzvlad:fix/255-ws-redis-adapter-leak
vvzvlad:fix/252-e2e-open-handles
vvzvlad:feat/229-catalog-yaml
vvzvlad:feat/243-blob-sandbox
vvzvlad:feat/228-inline-footnotes
vvzvlad:fix/qa-ui-bugs-216-218
vvzvlad:feature/agent-roles-catalog
vvzvlad:fix/share-alias-rename
vvzvlad:fix/ai-chat-empty-render
vvzvlad:feat/191-chat-doc-binding
vvzvlad:feat/201-temporary-notes
vvzvlad:feat/198-interrupt-agent
vvzvlad:feat/ai-chat-full-history
vvzvlad:feat/199-ai-generate-title
vvzvlad:feat/205-share-aliases
vvzvlad:batch/issues-189-187-170
vvzvlad:feat/170-mcp-test-button
vvzvlad:feat/189-context-badge
vvzvlad:feat/198-interrupt-agent-send-now
vvzvlad:fix/issues-190-159
vvzvlad:fix/ai-chat-new-chat-during-stream
vvzvlad:fix/ai-chat-stream-perf
vvzvlad:batch/issues-2026-06-25
vvzvlad:feat/ai-chat-persistent-history
vvzvlad:fix/ai-chat-copy-chat-wysiwyg
vvzvlad:fix/ai-stream-reset-resilience
vvzvlad:fix/ai-stream-undici-timeout
vvzvlad:fix/footnote-review-1227-followup
vvzvlad:fix/ai-chat-token-counter-realtime
vvzvlad:docs/manual-qa-test-plan
No Reviewers
Labels
Clear labels
epic
needs-human
review/approved
review/changes-requested
review/needs
Large multi-phase effort spanning many changes
эскалация: нужно решение человека
в последнем ревью нет открытых blocking-находок
последнее ревью оставило открытые blocking-находки
head не ревьюился (head != reviewed_head)
No Label
review/approved
Milestone
No items
No Milestone
Projects
Clear projects
No project
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: vvzvlad/gitmost#385
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "test/351-nested-generator"
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
Финальная (2-я) ступень #351: генератор ЦЕЛЫХ вложенных документов (variant A — random walk по ContentMatch схемы) + инвариант P4 (фазз парсера), И фикс ВСЕХ round-trip багов, которые генератор нашёл. closes #351
PR 1 (влит, #373) дал плоский генератор + P1/P2/P3 по одиночным нодам. Этот PR добавляет вложенную генерацию и P4 — и, как задумано, сразу нашёл классы реальных багов конвертера. По решению мейнтейнера (вариант A) — чиню конвертер, инварианты НЕ ослабляю.
Генератор
test/generative/doc-generator.ts— random walk поContentMatchсхемы (getSchema(docmostExtensions)): на каждом шаге спрашивает у автомата легальные ноды, min-depth Kleene-fixpoint гарантирует терминирование, глубина <=4 / размер <=60. Валидность из схемы (nodeFromJSON().check()). Table/columns генерятся согласованно; листовой контент — из доказанных byte-стабильных arbitraries PR 1.Инварианты (
test/generative/nested-roundtrip.property.test.ts)P1 семантический round-trip · P2 байтовый fixpoint со 2-го прохода · P3 тотальность · P4 фазз парсера (для ЛЮБОЙ строки
markdownToProseMirrorне бросает + результат валиден по схеме). Все строгие, зелёные. 2100+ документов (3 seed) → 0 падений.Найденные и починенные баги конвертера
<!-- -->разделитель (byte-stable).textAlignтерялся во вложенных li/td/th.codeBlockтерял хвостовой перевод строки.pageBreak/pageEmbed/subpages/transclusionдропались во вложении (blockquote/callout/details/li).columns: number->string ширины/высоты + лишний defaultdata-align(P2 churn).> [!type], вложенный в список/цитату, парсился неверно (prefix-aware regex, ReDoS-safe).How verified
Внутренний цикл: 3 прохода (генератор+P4 -> фиксы всех багов -> cross-type list фикс, найденный внутренним ревью). Плюс: в одном fuzz-литерале был случайный сырой NUL/BOM байт (файл определялся как binary) — заменил на JS-эскейпы
/(та же строка в рантайме), файл снова валидный UTF-8.Checklist
🤖 Авто-ревью · #385 (test(converter): вложенный variant-A генератор + P4 + фикс всех round-trip багов, #351), голова
79a461f7Вердикт: CHANGES. Генератор и фиксы конвертера — качественные и корректные (инварианты строгие, seed фиксирован, тесты обновлены 1:1, не ослаблены). Но один фикс (омит дефолтного
data-align="center") ломает тест консьюмера git-sync, который #385 не обновил → CI git-sync job красный. Почини — и PR чист.🔴 Do
data-align="center"ломаетpackages/git-sync/test/stabilize.test.ts:61—packages/prosemirror-markdown/src/lib/media-html.ts#385 корректно перестал эмитить
data-align="center"(это schema-дефолт; его эмиссия давала P2-churn — зеркалитimageToHtml):if (attrs.align && attrs.align !== "center"). Но git-syncstabilize.test.ts:61ассертитexpect(body1).toContain('data-align="center"')как «доказательство, что convergence-проход прошёл» — теперь падает. Прогнал git-sync vitest на голове #385: 1 failed | 267 passed; изолированноstabilize.test.ts— 1 failed | 3 passed. Важно: ассерт фикспоинта в том же тесте (expect(file2).toBe(file1), :55) проходит — round-trip остаётся байт-стабильным; ломается только устаревший маркер на :61. Fix: обнови ассерт вstabilize.test.ts:61под омитнутый дефолт — замениtoContain('data-align="center"')на другой пруф, что convergence-проход материализовал ноду (напр. проверьdata-src/каноничную форму drawio, или что body ≠ наивному двойному экспорту иначе). Т.к. #385 трогает шаредный конвертер, а git-sync — консьюмер в том же монорепо, правка должна быть в #385.✅ Что проверено чистым + заметки (не блокеры)
Фиксы конвертера — корректны, инварианты НЕ ослаблены (сверил с кодом):
markdown-converter.test.ts: 7 removed / 7 addedexpect— это 1:1 обновления фикстур (0 удалённыхit/describe), напр. вложенный список'- parent\n - child'→'- parent\n\n - child'(blank-line loose-list фикс round-trip). Не ослабление.doc-generator.ts(random walk поContentMatch) + P1-P4 инварианты СТРОГИЕ (в файле явно: «kept STRICT — no it.fails/skip/weakening»). Seed фиксирован (SEED=20250705, fast-check) → воспроизводимо, не флейки. P4 (парсер-фазз на произвольной строке — не throw + schema-valid doc) реально усиливает робастность.nested-roundtrip.property.test). Вариант A (чиню конвертер, не ослабляю инварианты) выдержан.Заметки (awareness, не блокеры):
apps/server/src/integrations/import/utils/import-formatter.ts:109,118эмититdata-align="center"явно для embed — под новым конвертером это нормализуется прочь на round-trip (безвредно, но при первом синке существующих vault'ов даст one-time churn файлов, где дефолт был записан явно). На заметку, не блокер.Аспекты судил напрямую (глубокий контекст по этому конвертеру из #359 rounds 1-3): фиксы корректны, инварианты строгие, единственный блокер — сломанный тест консьюмера. Гейты прогнал реально (converter 37 файлов, git-sync 1 fail изолирован до
data-alignмаркера).Round 1 — замечание закрыто (
ccee32cb).1. [regressions]
stabilize.test.ts:61data-align="center". Ты прав, что маркер стал ненадёжным: раз PR корректно перестал эмитить schema-дефолтcenterв media-билдерах,data-align="center"больше не годится как пруф прохода convergence. Заменил на стабильные канонические маркеры, которые материализуются всегда независимо от дефолта align:data-type="drawio"+data-src="/d.drawio". Ассерт фикспоинта (file2 === file1) не трогал — round-trip остаётся байт-стабильным.Нюанс для протокола: у меня на ЧИСТОЙ пересборке (
rm -rf build && pnpm buildдля prosemirror-markdown, затем git-sync) полный сюит git-sync был 268 passed / 0 failed, включая старый ассерт на :61 — путь drawio-внутри-columns на моём билде эмитил center и тест проходил. Похоже, изолированный fail — это ровно build-order-ловушка, которую ты сам задокументировал в #384 (git-sync прогнан против устаревшегоprosemirror-markdown/build/): поведение center на этом пути оказалось билд-зависимым. Поэтому и сделал ассерт устойчивым к омиссии в любом случае — так тест корректен независимо от того, эмитится center или нет.Проверка:
stabilize.test.ts4/4, полный git-sync сюит 268/268 зелёные, tsc 0.🤖 Авто-ревью · раунд 2 · #385 (test(converter): вложенный variant-A генератор + P4 + фикс round-trip багов, #351), голова
ccee32cbВердикт: PASS ✅ (review/approved). Единственный блокер round-1 (сломанный тест консьюмера git-sync) закрыт корректно, нового бага нет.
Проверено
packages/git-sync/test/stabilize.test.ts, test-only, +9/-4): убран устаревшийtoContain('data-align="center"'), заменён на стабильные каноничные маркерыtoContain('data-type="drawio"')+toContain('data-src="/d.drawio"')— доказывают, что convergence-проход материализовал bare{ src }-ноду в полный drawio-HTML, БЕЗ зависимости от омитаемого schema-дефолта. Коммент объясняет причину (center — дефолт, конвертер его опускает). Фикспоинт-ассерт (file2===file1) сохранён.stabilize.test.ts— 4/4 (новые маркеры реально присутствуют в стабилизированном body). Дельта только тестовая → фиксы конвертера round-1 (корректные, инварианты строгие, seed фиксирован, converter 704 passed) в силе.Весь #385 закрыт: качественный генеративный харнес (P1-P4 строгие) + корректные round-trip-фиксы конвертера + консьюмер-тест git-sync обновлён под омитнутый дефолт. Мержибельно (гейтить вместе с #359, тоже юзает конвертер).
Фикс-раунд проверен: git-sync suite реально прогнал (28/28), маркеры-ассерты подтверждены истинными. Test-only — новой поверхности бага нет.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.