Composition Rewrite ADR
- 1. Статус и назначение документа
- 2. Контекст
- 3. Проблема, которую нужно было решить
- 4. Рассмотренные варианты
- 5. Принятое решение
- 6. Детализация принятого решения
- 6.1. Rewrite работает на уровне блоков, а не на уровне итогового текста
- 6.2. Preview является обязательным отдельным артефактом
- 6.3. Patch-модель сознательно ограничена частичными изменениями
- 6.4. Apply публикует новые версии блоков, а затем новую версию композиции
- 6.5. Placeholder preservation контролируется engine, а не только prompt policy
- 6.6. Повторные ссылки на один и тот же блок не должны порождать лишние patch entries
- 7. Последствия решения
- 8. Риски и меры снижения
- 9. Что сознательно не покрывается
- 10. Связанные документы
1. Статус и назначение документа
Статус: принят и описывает текущий patch-oriented workflow.
Назначение: зафиксировать, почему переписывание композиции оформлено как preview/apply процесс с patch-моделью по блокам, а не как прямое переписывание композиции целиком.
2. Контекст
В TextFoundry композиция состоит из структуры фрагментов, а ключевой
переиспользуемой единицей смысла остаётся блок. Пользователь нередко хочет:
-
доработать композицию по новой инструкции;
-
улучшить тексты блоков;
-
сохранить общую структуру и состав композиции;
-
не пересобирать композицию вручную целиком.
При этом система должна удерживать важные ограничения:
-
не менять состав блоков без явного authoring;
-
не ломать placeholders;
-
не превращать rewrite в скрытый redesign композиции;
-
давать пользователю inspectable preview до публикации.
3. Проблема, которую нужно было решить
Нужно было добавить AI-assisted rewrite существующей композиции так, чтобы он:
-
обновлял содержание блоков, а не структуру композиции;
-
был совместим с block versioning;
-
позволял человеку просмотреть proposed changes;
-
не превращался в непрозрачный one-shot overwrite.
Прямая перезапись композиции здесь опасна, потому что теряется понимание:
-
какие именно блоки изменились;
-
какие поля были затронуты;
-
не сломаны ли placeholders;
-
опубликована ли новая версия осознанно.
4. Рассмотренные варианты
Вариант A. Переписать композицию целиком как готовый текст
Идея: отдать модели весь render или композицию и получить новый финальный текст.
Плюсы:
-
проще с точки зрения одной операции;
-
пользователю легко объяснить "переписать всё".
Минусы:
-
теряется связь с block structure;
-
блоки перестают быть главной единицей сопровождения;
-
невозможно аккуратно выпустить новые версии только нужных блоков;
-
высок риск unintended redesign.
Вердикт:
-
отклонено.
Вариант B. Разрешить модели напрямую мутировать композицию без preview
Идея: LLM предлагает изменения, а система сразу применяет их к хранилищу.
Плюсы:
-
минимум шагов в UX;
-
быстрая автоматизация.
Минусы:
-
нет inspectable review stage;
-
сложнее локализовать ошибку;
-
выше риск повредить production-ценные блоки;
-
пользователь фактически теряет контроль над публикацией.
Вердикт:
-
отклонено.
Вариант C. Patch-oriented preview и отдельный apply
Идея:
модель возвращает не новую композицию целиком, а набор BlockRewritePatch,
которые пользователь сначала просматривает, а потом отдельно применяет.
Плюсы:
-
видно, какие блоки реально затронуты;
-
проще удерживать структуру композиции;
-
engine может валидировать placeholders и дубликаты patch entries;
-
apply можно трактовать как обычный controlled versioning workflow.
Минусы:
-
больше шагов;
-
preview UI сложнее простого textarea;
-
модель должна быть дисциплинирована и возвращать частичный patch, а не новый design всей композиции.
Вердикт:
-
выбранный вариант.
5. Принятое решение
Принято решение оформлять composition rewrite как двухфазный процесс:
-
PreviewCompositionBlockRewrite(…) -
ApplyCompositionBlockRewrite(…)
Ключевые правила:
-
переписываются только блоки, уже присутствующие в композиции;
-
composition structure, block ids и порядок блоков не меняются;
-
preview обязателен перед apply;
-
apply публикует новые версии затронутых блоков и новую версию композиции;
-
placeholders должны сохраняться.
6. Детализация принятого решения
6.1. Rewrite работает на уровне блоков, а не на уровне итогового текста
Причина:
в TextFoundry composition - это структура из block refs и других фрагментов,
а не просто строка.
Поэтому в контекст rewrite передаются:
-
block_id; -
type; -
language; -
description; -
defaults; -
tags; -
templ.
Такое решение удерживает rewrite внутри модели "улучшить существующие блоки", а не "сгенерировать новую композицию как попало".
6.2. Preview является обязательным отдельным артефактом
Причина: между предложением модели и записью в storage должен существовать inspectable буфер принятия решения.
CompositionBlockRewritePreview хранит:
-
исходную композицию и версию;
-
список patch entries;
-
рациональ каждого patch.
Это даёт:
-
понятную review stage;
-
возможность показать before/after summary;
-
отделение AI suggestion от фактической mutation.
6.3. Patch-модель сознательно ограничена частичными изменениями
Причина: чем богаче patch format, тем выше риск дать модели возможность менять слишком много.
Поэтому patch разрешает изменять только:
-
description; -
templ; -
defaults; -
tags; -
rationale.
Он не даёт:
-
добавлять новые блоки;
-
удалять блоки;
-
менять
block_id; -
менять
type; -
менять структуру композиции.
Это главный safety boundary всей функции.
6.4. Apply публикует новые версии блоков, а затем новую версию композиции
Причина: rewrite не должен обходить обычный lifecycle сущностей.
При применении engine:
-
валидирует patch set;
-
загружает исходные блоки из композиции;
-
собирает обновлённые block drafts;
-
проверяет placeholders;
-
вызывает
UpdateBlock(…); -
затем публикует новую версию композиции с обновлёнными ссылками.
Это позволяет сохранить версионирование и воспроизводимость истории.
6.5. Placeholder preservation контролируется engine, а не только prompt policy
Причина: если положиться только на текстовую инструкцию модели, rewrite может случайно сломать runtime contract блока.
Поэтому перед UpdateBlock(…) engine сравнивает множества placeholders
исходного и переписанного шаблонов. Любое нарушение приводит к ошибке.
Это фиксирует правило: rewrite допустим только пока он не ломает executable semantics шаблона.
6.6. Повторные ссылки на один и тот же блок не должны порождать лишние patch entries
Причина: композиция может ссылаться на один и тот же блок более одного раза.
В preview context engine собирает уникальные block ids и не передаёт один и тот же блок модели несколько раз. Это уменьшает шум и риск конфликтов.
7. Последствия решения
Положительные:
-
mutation остаётся inspectable;
-
блоки сохраняют роль главной единицы сопровождения;
-
структура композиции защищена от случайного redesign;
-
apply интегрируется в существующий versioning workflow.
Компромиссы:
-
пользователю нужно сначала делать preview, а потом apply;
-
preview показывает summary patches, а не полный rich diff;
-
часть desired changes пользователь всё равно может предпочесть сделать вручную в редакторе.
Отрицательные:
-
некоторые сценарии "перепридумать композицию" intentionally не покрываются;
-
если instruction слишком общая, preview может быть малополезным;
-
apply затрагивает несколько сущностей и требует более аккуратной обработки ошибок.
8. Риски и меры снижения
Риск: модель попробует изменить структуру композиции через содержательные rewrite
Снижение:
-
patch format не поддерживает structural changes;
-
prompt constraints требуют сохранять composition structure.
9. Что сознательно не покрывается
Данный ADR не фиксирует:
-
structural rewrite композиции;
-
массовое добавление и удаление блоков через AI;
-
автоматический merge разных preview между собой;
-
полноценный визуальный diff на уровне редактора композиции.