Егор Урванов

Где ставить проверку работы ИИ-агентаГраница агрегата и теорема Райса

Почему любой код агента нельзя проверить на любое правило, какие три способа делают проверку конечной, как граница агрегата из event storming становится постом проверки, как по проверяемости выбрать размер ограниченного контекста и почему первую рамку важно уметь дёшево сдвигать.

Проверку работы ИИ-агента ставят на границе агрегата: там, где входят команды, выходят события и записаны правила, которые всегда должны выполняться. Код внутри границы пишет агент. Причина в теореме Райса: проверить любую программу на любое смысловое правило невозможно, поэтому проверку сужают до рамки, где ответ конечен. Ниже: почему так, три способа сузить проверку и как выбрать размер контекста.

Это мои размышления. Статья — авторская попытка понять, где проводить границу при работе с ИИ-агентами и как резать систему на контексты; теорема Райса здесь только средство, которое помогает проверить уже проведённую границу. Утверждения с источником отмечены значком ↗ рядом с текстом: формулировки теорем, определения, цитаты. Всё остальное — мои выводы и гипотезы: выбор границы агрегата как места проверки, критерий размера контекста, сопоставление с CAP и с Гёделем. Их стоит читать как точку зрения, которую ещё предстоит проверить.

Коротко: что проверяет человек, а что делает агент

3граница контекста «Бронирование» — держит человек2граница агрегата «Бронь» — проверкакомандаЗабронироватьсобытиеБроньСоздана1внутри: код пишет агентправило: брони не пересекаютсячеловек проверяет границы, агент свободен внутри● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Три зоны работы с агентом: где он свободен, где стоит проверка и где решает человек.

Внутри агрегата работает агент. Он пишет обработчики команд, запросы к базе, хранение данных и тесты. Агент может переписать всё внутреннее устройство: разбить таблицу на две, поменять запросы, переделать обработку. Пока граница цела, человеку не нужно читать каждую строку.

На границе агрегата стоит проверка. Здесь записано, какие команды агрегат принимает, какие события отдаёт соседям и какие правила верны всегда. Эту границу проверяет машина. Модель на Quint — это запись правил системы на специальном языке, по которой программа перебирает все возможные порядки команд и ищет тот, где правило нарушится. Ограничения в базе данных — правила, которые база проверяет при каждой записи и не даёт сохранить запрещённое. Человек смотрит только правки самой границы.

Границу контекста держит человек. Какие агрегаты живут вместе и где меняется смысл слов, по коду не вычислить: это зависит от будущих изменений. Поэтому эту рамку ставит человек и сдвигает её по истории правок и планам, подробно об этом в разделе «Первая рамка».

Вывод
В этом примереАгрегат «Бронь переговорной»: команда «Забронировать», событие «БроньСоздана», правило «брони одной комнаты не пересекаются». Как это хранить и обрабатывать, решает агент.
В общем случаеЧеловек держит в руках короткий список вещей на границе, и этот список можно проверить машиной до конца. Всё, что внутри, меняется свободно, пока граница цела.
Что сделатьДля своего проекта выпишите один агрегат и на его границе три строки: команды, события, правила.

Почему нельзя проверить весь код агента: теорема Райса

Суть. Какой бы умной ни была проверка кода агента, найдётся код, на котором она ошибётся. Это доказал Генри Гордон Райс в 1951 году.

  • Что нельзя проверить: поведение программы, то есть что она делает при запуске. Например, «никогда не списывает деньги без заказа».
  • Условие теоремы: свойство есть у одних программ и нет у других. Если оно есть у всех или ни у одной, ответ известен заранее.
  • Подробно с доказательством: статья «Теорема Райса простыми словами».

Два вида вопросов о программе. Вопрос с ответом «да» или «нет» математики называют предикатом. Теорема запрещает точный ответ только на второй вид.

Как код написан
Что код сделает при запуске
Пример
есть ли в коде запись в таблицу платежей?
спишет ли программа деньги без заказа хоть раз?
Что просмотреть
текст кода: он конечный
все запуски со всеми данными: их бесконечно много, часть не заканчивается
Ответ
точный, поиском по коду
в общем случае невозможен

Практический приём: переписать код так, чтобы важное правило стало вопросом первого вида.

былостало?три входа к даннымза каждым не уследитьодин вход с замкомпроверить: нет ли других входоввход — модуль, который пишет в таблицу платежей; замок — ограничение в базе● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Похожее различие есть между императивным и декларативным подходами. Императивный код описывает шаги, и по ним в общем случае не понять результат. Простая декларативная запись, например ограничение в базе, сама говорит, каким должен быть результат, и база его соблюдает.

кодвопросчто нужно просмотретьответкак написано40 строкесть ли в коде записьв таблицу платежей?строки: 1, 2 … 40 — конецконечно: прочитать вседа или нетчто получитсятот же кодспишет ли деньги без заказахоть в одном запуске?вход 1вход 2вход 3вход 4… ∞запусков бесконечно, часть не кончается?не решаетсяесли у одних программ «да»,а у других «нет»● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, границаКак написано: прочитать конечный список строк. Что получится: перебрать все запуски, а их бесконечно

Код один и тот же. Вопрос о записи решается чтением конечного текста, вопрос о поведении требует перебрать все запуски.

Почему на вопрос о поведении нельзя ответить для любой программы, видно из одного построения. Возьмём любую программу PP и любые входные данные ww для неё; запись P(w)P(w) значит «программа PP, запущенная на данных ww». Соберём новую программу QQ: сначала она запускает P(w)P(w), а когда та закончится, делает шаг BB, который нарушает правило, например списывает деньги без заказа. Если P(w)P(w) никогда не заканчивается, до шага BB дело не доходит и правило не нарушено. Значит, проверка правила для QQ должна знать, закончится ли P(w)P(w). Схема ниже показывает это построение, формулы и вывод — сразу под ней.

Программа Q(x)P(w)любая программакончилась →B(x)нарушает правилосначала P, потом B?проверка правилаP(w) остановилась→ Q нарушаетP(w) крутится вечно→ Q чистаответ проверки = ответ «остановится ли P(w)»а этот вопрос не решается ни одной программой● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Доказательство в одну схему: проверка правила для QQ отвечала бы, остановится ли P(w)P(w).

Как это доказывают. Возьмём любую программу PP со входом ww и построим из неё новую программу QQ:
Q(x)  =  запусти P(w); когда она закончится, выполни B(x)Q(x) \;=\; \text{запусти } P(w)\text{; когда она закончится, выполни } B(x)

Шаг B(x)B(x) правило нарушает, а программа, которая работает вечно, его не нарушает. Значит, QQ доходит до нарушения только если P(w)P(w) когда-нибудь закончится:

Q нарушает правило  ⟺  P(w) останавливаетсяQ \text{ нарушает правило} \iff P(w) \text{ останавливается}

Если бы существовала проверка правила для любой программы, она, получив QQ, ответила бы и на вопрос, остановится ли P(w)P(w). А этот вопрос, проблема остановки, не решается никакой программой: это доказал Алан Тьюринг.

Вывод
В этом примереАгент принёс 2000 строк. Проверка «этот код никогда не создаст пересекающиеся брони» для произвольного кода в общем случае невозможна, сколько бы её ни улучшали.
В общем случаеОтсюда следует выбор: либо проверять не всё, либо проверять в рамке, где ответ конечен. Третьего пути нет, и это касается и программ-проверок, и ревью человеком.
Что сделатьДля правила, которое хотите проверять у агента, спросите: в какой рамке ответ будет точным? Если рамки нет, правило проверяется только на примерах.

Три способа сделать проверку конечной

Раз точной проверки для любой программы нет, проверку ограничивают так, чтобы она касалась не любой программы. Ограничить можно тремя способами: уменьшить мир, в котором проверяют, сузить язык, на котором пишут, или разрешить проверке честно отвечать «не знаю». На схеме все три способа рядом.

Сузить мирСузить языкРазрешить «не знаю»3 комнаты × 5 бронейперебраны все состоянияQuintодин путь записипроверить: нет ли обходадоказанонарушено?не уверенатретий ответ — человекувнутри рамки ответ точный● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Слева перебор маленького мира, в центре один путь записи в базу, справа три ответа проверки, где третий уходит человеку.

В таблице те же три способа подробнее: как работает каждый, какое условие теоремы он убирает и почему после этого ответ точный, и что при этом теряют. Как каждый способ выглядит для правила «брони одной комнаты не пересекаются», показано ниже, в подразделе «Как это выглядит на деле».

СпособЧто делают на практикеПочему ответ получается точнымЧто теряют
Малый мирпишут модель бронирования на Quint: 3 комнаты, до 5 броней, действия «забронировать» и «отменить». Программа перебирает все последовательности этих действий и после каждого шага проверяет правило «брони одной комнаты не пересекаются»вариантов конечное число, поэтому перебор доходит до конца и отвечает «правило держится» или показывает цепочку шагов, где оно сломалосьошибку, которая появляется только при 50 одновременных бронях, перебор с 5 бронями не увидит
Узкий языкправило записывают ограничением в базе PostgreSQL, а писать в таблицу броней разрешают только файлу booking/repository.ts. При каждой правке агента поиск проверяет, нет ли записи в таблицу броней в других файлахограничение — одна строка в схеме базы, база сама проверяет его при каждой записи; поиск по файлам всегда заканчивается и даёт точный ответагент не может писать бронь откуда удобно: даже массовый импорт броней придётся провести через тот же разрешённый файл
Ответ «не знаю»проверка правки агента выдаёт один из трёх ответов: «соблюдено», «нарушено», «не могу определить». Третий ответ ставит на правку метку «нужен человек»проверка не обязана решать трудные случаи, например запрос к базе, собранный из строк на лету: на них она честно говорит «не могу определить», а там, где ответила «соблюдено» или «нарушено», ответ точныйразработчик тратит время на правки с меткой «нужен человек»

Подробнее, с доказательством того, почему каждый способ снимает запрет, — в статье «Теорема Райса простыми словами».

Как это выглядит на деле: одно правило, три проверки

Возьмём правило «брони одной комнаты не пересекаются по времени» и агента, который пишет код бронирования. Ниже для каждого способа: что именно записывают, что запускают и что получают на выходе.

Сузить мир: модель на Quint. Правило и действия системы записывают коротким описанием, без настоящего кода. Состояние — снимок данных в какой-то момент: какие брони есть, у какой комнаты, с какого по какое время. Действия — «забронировать» и «отменить». Правило записывается одной строкой: для любых двух броней одной комнаты одна заканчивается раньше, чем начинается другая.

Правило в модели на Quint

val noOverlap = bookings.forall(a => bookings.forall(b =>
  a == b or a.room != b.room or a.end <= b.start or b.end <= a.start))

Дальше программа сама перебирает все последовательности действий для маленького мира: 3 комнаты, до 5 броней. Если правило где-то нарушается, она выдаёт цепочку шагов. Например: два клиента одновременно бронируют комнату 2 на 10:00–11:00, обе проверки «свободно ли» проходят раньше обеих записей, и в базе оказываются две брони на одно время. Эта цепочка и есть находка: ошибка в замысле видна до того, как агент написал код. Маленького мира хватает, потому что такие ошибки проявляются уже на двух-трёх бронях.

Сузить язык: правило в базе и один писатель. Правило переносят туда, где его держит не код агента, а сама база данных. В PostgreSQL это одно ограничение на таблицу броней: база откажется сохранить бронь, если её время пересекается с другой бронью той же комнаты.

Ограничение в PostgreSQL

CREATE EXTENSION IF NOT EXISTS btree_gist;
ALTER TABLE bookings ADD CONSTRAINT no_overlap
  EXCLUDE USING gist (room_id WITH =, tstzrange(starts_at, ends_at) WITH &&);

Вторая половина — один писатель: записывать в таблицу броней может только один модуль. Это проверяется поиском по тексту кода при каждой правке агента. Команда ниже ищет все файлы, где есть запись в таблицу броней, кроме разрешённого; пустой результат значит «обхода нет».

Проверка «один писатель» поиском по коду

grep -rl "INSERT INTO bookings" src | grep -v src/booking/repository.ts

Вопрос «может ли код агента создать пересекающиеся брони» превратился в два вопроса о тексте: есть ли ограничение в схеме базы и нет ли записи в обход. На оба ответ точный.

Разрешить «не знаю»: три вердикта на правку агента. Проверка правки агента собирается из предыдущих двух и выдаёт один из трёх ответов. «Доказано»: модель на Quint прошла, ограничение в базе на месте, поиск не нашёл записей в обход. «Нарушено»: поиск нашёл, что агент добавил запись в таблицу броней из модуля отчётов. «Не уверена»: агент собирает запрос к базе из строк на лету, и поиск по тексту не может понять, в какую таблицу он пишет. Тогда правка получает пометку «нужен человек», и её смотрит разработчик. Человек тратит время только на третий случай.

Каждый из трёх ответов точен только в своих пределах. Перебор доказывает, что правило держится в модели с 3 комнатами и 5 бронями, но не в боевой базе с тысячами броней. Поиск доказывает, что в коде нет записи в обход, но не то, что само ограничение в базе написано верно. Ответ «соблюдено» точен, но часть правок всё равно уходит человеку. Поэтому способы используют вместе: модель проверяет замысел до кода, ограничение и поиск проверяют сам код, а человек смотрит то, что осталось с меткой.

Есть и четвёртый вариант, который на практике встречается чаще всего: отвечать всегда, но иногда ошибаться. Так работают тесты на примерах и ревью кода другой моделью. Это тоже допустимый выбор, но осознанный: он годится там, где ошибка дешёвая, и не годится для денег и доступов. Похожую развилку знают по теореме CAP о распределённых системах: при разрыве связи сервер либо ждёт, либо отвечает по устаревшей копии. Общее у них одно — пока событие не произошло, нельзя понять, случится ли оно позже или не случится никогда, сколько бы ни ждать, — а причины разные; подробно в статье «Теорема Райса простыми словами».

Вывод
В этом примереПравило «брони не пересекаются»: модель на Quint перебрала все порядки команд для 3 комнат, ограничение в базе запрещает пересечение, а линтер — программа, которая проверяет текст кода по заданным правилам, — следит, что в таблицу броней пишет только один модуль.
В общем случаеОтвет «не уверена» — это честный результат проверки. Он показывает, где рамка кончилась и где ответственность снова на человеке, и тем самым задаёт, какой риск принят.
Что сделатьДля каждого правила отметьте, какой из трёх способов его держит. Правило без отметки проверяется только тестами на примерах.

Агрегат как пост проверки: что даёт event storming

Event storming — формат совместной работы, на котором команда раскладывает предметную область на события. После него у каждого агрегата есть четыре вещи: команды, которые его меняют, события, которые он отправляет, модели чтения, через которые на него смотрят, и инварианты — правила, которые верны в каждом состоянии.

Агрегат «Заказ»Кореньверсия 7ПозицииБизнес-правиласумма ≥ 0, оплаченный не меняетсяКомандыДобавить позициюОплатитьМодели отображениякарточка и список заказовСобытие«Заказ оплачен»Граница контекстаДоставкадругой контекст● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, границаКоманды меняют агрегат, правила внутри его защищают, модели отображения показывают, события уходят в другой контекст

Эти четыре вещи и есть граница, на которой удобно ставить проверку. Все изменения проходят через команды, всё, что видят соседи, уходит событиями, а правила записаны в одном месте. Это прямо второй способ из прошлого раздела: в таблицу агрегата пишет только он сам, поэтому правило не нарушит никакой другой код, и проверить нужно лишь одно: нет ли записи в эту таблицу из других мест.

внутри: код пишет агентагрегат «Бронь»командаЗабронироватьсобытиеБроньСозданаправило: брони комнаты не пересекаютсямодель чтениярасписание комнатыграница =пост проверки● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Пост проверки стоит на входе команд и выходе событий. Внутри границы агент свободен.

В таблице по строкам: что из четырёх частей агрегата лежит на границе и проверяется машиной и человеком, а что остаётся внутри и делается агентом без построчного ревью.

На границе (проверяется)
Внутри (делает агент)
Команды
какие есть и что принимают
как их обработать
События
какие уходят и с какими полями
когда и как их собрать
Инварианты
модель на Quint, ограничения в базе
код, который их не нарушает
Модели чтения
что показывают
как их строить быстро
Вывод
В этом примереАгент переписал хранение броней с одной таблицы на две. Граница не изменилась: те же команды, те же события, модель на Quint проходит, ограничение в базе держит. Ревью человека сводится к одному вопросу: тронута ли граница.
В общем случаеКогда граница записана, проверка изменения агента становится конечной: сравнить границу до и после. Код внутри можно смотреть выборочно.
Что сделатьЗаведите для агрегата файл с границей: команды, события, инварианты, модели чтения. Любая правка этого файла — повод для ревью человеком, правки внутри — нет.

Как выбрать размер ограниченного контекста: по проверяемости

Переход от предметной области к ограниченным контекстам — самое трудное место в DDD. Обычные признаки границы: одно слово начинает значить разное, меняется команда, правила перестают быть обязаны выполняться одновременно.

Критерий размера контекста. Контекст достаточно мал, если модель его правил на Quint перебирается до конца на малых числах и отвечает «правило держится» или показывает нарушение. Если перебор не заканчивается, контекст нужно разрезать. Критерий следует из теоремы Райса: точный ответ возможен только там, где вариантов конечное число и их можно перебрать все.

Как применить критерий к своему проекту. Берут часть системы, которую считают кандидатом в контекст, например «бронирование», и проверяют её за пять шагов.

  1. Выписать правила и действия. Правила — то, что должно быть верно всегда: «брони одной комнаты не пересекаются». Действия — команды, которые меняют данные: «забронировать», «отменить».
  2. Записать их моделью на Quint. Состояние — какие брони есть; действия — как они меняют состояние; правила — проверки после каждого шага. Это десятки строк, без настоящего кода.
  3. Выбрать малые числа. По 2–3 объекта каждого вида: 3 комнаты, 5 броней, 2 клиента. Обычно этого достаточно, чтобы встретились типичные неприятные сочетания: две брони одной комнаты, два клиента в одну минуту. Гарантии нет: ошибка, которой нужно больше объектов, пройдёт мимо.
  4. Запустить перебор с пределом времени, например 10 минут.
  5. Прочитать результат по таблице ниже. Перебор закончился без нарушений — размер подходит. Закончился и показал нарушение — размер подходит, но в правилах или действиях ошибка, её чинят. Не закончился за предел — состояний слишком много, кандидата режут.

Оценок нет. Числа здесь — ориентир, а не измеренные пороги. Сколько объектов достаточно, чтобы поймать ошибки в контексте, и какой предел времени считать признаком «слишком большой», никто для этого критерия не измерял. Подбирайте их по своему проекту и записывайте, при каких числах модель проверялась.

Запуск перебора для модели бронирования

quint verify booking.qnt --invariant=noOverlap --max-steps=10

Как резать, если перебор не закончился. Выписать для каждого правила, каких данных оно касается. Правила, у которых нет общих данных, разводят по разным частям: «брони не пересекаются» касается только броней, «счёт не оплачивается дважды» — только счетов. Между частями оставляют события, например «БроньСоздана». Потом каждую часть проверяют теми же пятью шагами.

Один большой контекстРазрезали по проверкеброньоплатауведомления?проверка: «не уверена»состояний слишком многоброньоплатасобытиекаждая модель: до концамежду ними только события● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Если модель контекста отвечает «не уверена», контекст режут, и между частями остаются только события.

Как пользоваться этим признаком: записать правила контекста моделью на Quint, задать маленькие числа и запустить перебор. Результат прогона попадает в одну из строк таблицы, а в последнем столбце сказано, что делать дальше.

ПризнакЧто значитЧто делать
Модель проходит на малых числахмодель проверена до конца, нарушений нетоставить
Модель не доходит до концасостояний слишком многоразрезать по правилам, которым не нужно выполняться вместе
Правило нельзя записать без внешнего мираграница проведена не тамвынести внешний мир за границу, говорить с ним событиями
Между частями только событиячасти не лезут в данные друг другау каждой части своя модель и свой агент
Вывод
В этом примереБронь, оплата и уведомления в одной модели: перебор не заканчивается за час. Бронь отдельно и оплата отдельно, связаны событием «БроньСоздана»: каждая модель проходит за секунды.
В общем случаеРазмер контекста перестаёт быть делом вкуса: если правила внутри нельзя проверить до конца, контекст великоват или правила записаны на слишком сильном языке. Подробнее про агента на каждый контекст — в статье сколько нужно ИИ-агентов.
Что сделатьЗапишите модель самого крупного контекста на Quint с маленькими числами. Если перебор не заканчивается, найдите правила, которым не нужно держаться одновременно, и проведите границу между ними.

Первая рамка: почему она ошибётся и как сделать её дешёвой

Открытый вопрос. Как устроен выбор рамки, пока до конца не ясно; раздел фиксирует предварительную гипотезу для будущих статей. Гипотеза: выбор рамки упирается в то же общее ядро, что теорема CAP и теорема Райса, — пока событие не произошло, нельзя понять, случится ли оно позже или не случится никогда, сколько бы ни ждать; здесь событие — правка, ради которой пришлось бы менять рамку: придёт ли она через месяц или не придёт вообще, заранее не узнать. Это ядро разобрано в разделе «Связь с теоремой CAP». Фактов и проверенных примеров в её пользу пока недостаточно, поэтому дальнейший текст следует читать как набросок, требующий проверки. Это направление дальнейшего исследования.

рамкаброникомнатысчетаправка 1: внутри рамкиправка 2: через границу — рамку сдвигать?какая придёт?

Рамку провели вокруг броней и комнат. Если дальше придёт правка про брони и комнаты, рамка подойдёт. Если придёт правка про брони и счета, она пересечёт границу, и рамку придётся сдвигать. Какая из них придёт, сейчас не узнать — это и есть открытый вопрос.

Что предстоит выяснить:

  • можно ли строго записать выбор рамки как задачу с нехваткой сведений, как это сделано для CAP, или сходство только словесное;
  • насколько история прошлых правок предсказывает будущие: измерений нет, есть только наблюдения по отдельным проектам;
  • какой длины цикл пересмотра рамки работает: две недели ниже взяты как пример, а не как проверенное число;
  • как связаны два вопроса: какого размера должна быть часть (здесь помогает теорема Райса) и где провести её границы (здесь нужны сведения о будущем).

Выбрать рамку мешает другой запрет, чем в теореме Райса. Проверке кода сведений хватает, весь код перед ней, но ответ из него нельзя вычислить. Рамке не хватает самих сведений. Хорошая рамка — та, внутри которой будут жить будущие изменения, а о будущем нет данных ни в коде, ни где-либо ещё. Это ровно положение сервера из теоремы CAP: он не знает, что происходит у соседа за оборванной связью, а здесь неизвестно, какие правки придут через месяц.

Поэтому и выходы те же, что в CAP. Ждать, пока будущее станет известно, нельзя: работа идёт сейчас. Остаётся ответить сейчас по тому, что есть, и быть готовым ошибиться. «То, что есть» — два приближения будущего: история прошлых правок, где видно, что обычно меняется вместе, и планы, которые знаете только вы. А третий выход из CAP — ограничить время — здесь превращается в короткие циклы agile: ставить рамку на две недели, смотреть, как в ней живут правки, и сдвигать. Раз рамка всё равно будет ошибаться, важно, чтобы её было дёшево сдвинуть.

Теорема Райса в этом разделе всё же участвует, но в другой роли. Она не помогает угадать будущее, зато даёт проверку уже выбранной рамки: если модель правил части перебирается на Quint до конца, часть достаточно мала, а если не перебирается — её стоит разрезать. Об этом признаке шла речь в разделе о размере контекста.

Откуда взять первые части

Знать части заранее не нужно: первую нарезку даёт то, что уже есть, а человеку остаётся дать частям имена и поправить спорные места.

Что естьПервая нарезкаПотом
История правоктаблицы, которые почти всегда меняются в одних коммитах, склеиваются в одну частьпроверить нарезку на эпиках из бэклога
Правила о данных, истории неттаблицы, которые упоминаются в одном правиле, кладутся в одну частьсверить с историей после первых десятков коммитов
Ничего, холодный стартодна часть на одно главное понятие: проект, репорт, эпик, доступсверить с историей после первых десятков коммитов и сдвинуть

Как работает склейка по правилам. Выписать правила о данных, например «в закрытом эпике нет открытого репорта», «токен видит только свои проекты». Если правило упоминает две таблицы, они в одной части. Получившиеся группы и есть первая нарезка.

часто меняются вместе → сдвинуть границуэпикирепортыв закрытом эпике нет открытого репортатокеныпроектытокен видит только свои проектыстатус репортаобщее ядро, один владелецдоскатолько через владельцатоже через него● модель, люди, системы, данные  ● агент и харнесс  ● риск, стоп, граница

Группы склеенных таблиц и есть первая нарезка. Таблица, нужная всем, становится общим ядром.

Где правило связывает почти всё, как статус репорта, который нужен и эпикам, и доске, эта таблица становится общим ядром с одним владельцем. Остальные части обращаются к ней только через него. Так в таблицу статусов пишет только ядро, и правило о статусах не может нарушить ни эпик, ни доска.

Вывод
В этом примереЭпики и репорты легли в одну часть, токены и проекты — в другую, статус репорта стал ядром. Через месяц история показала, что файлы проектов и эпиков правят в одних и тех же коммитах: проекты переехали к эпикам.
В общем случаеОшибка в рамке обходится дёшево: сдвинуть таблицу в другую часть — это правка одной строки, после которой проверки сами показывают, стало лучше или хуже. Раз угадать рамку заранее нельзя, её держат такой, чтобы её было легко двигать.
Что сделатьПопросите агента проверить нарезку по истории правок и по бэклогу.

При чём тут Гёдель: только аналогия

Связь теоремы Гёделя о неполноте с этой темой — моё предположение, источников, которые бы её проводили, я не нашёл. Повод для него: и у Гёделя, и у Райса доказательство держится на одном приёме, программе или формуле, которая говорит о самой себе. Но первая теорема Гёделя относится к формальным системам, в которых можно вести элементарную арифметику, и о границах предметной области ничего не говорит. Для довода о проверке агента точный результат — теорема Райса.

Как аналогия полезна вторая теорема: такая система не может доказать собственную непротиворечивость. В переводе на работу с агентом: агент не может сам себе подтвердить, что сделал правильно, нужен проверяющий за пределами его рамки. Это образ, математического вывода из него нет.

Частые вопросы

Где ставить проверку работы ИИ-агента?
На границе агрегата: на командах, событиях и правилах, которые всегда должны выполняться. Эту границу можно проверить машиной до конца, а код внутри неё пишет агент.
Что говорит теорема Райса простыми словами?
Нет программы, которая для любой программы точно скажет, есть ли у неё заданное свойство поведения. Поэтому проверку сужают: маленьким миром, узким языком или честным ответом «не знаю».
Как выбрать размер ограниченного контекста?
Кроме смены смысла слов и команд, есть проверяемый признак: модель правил контекста должна перебираться до конца на малых числах. Если не перебирается, контекст режут по правилам, которым не нужно выполняться вместе.
Как выбрать первую рамку без истории правок?
Таблицы, которые упоминаются в одном правиле о данных, кладут в одну часть, а если правил ещё нет, начинают с одной части на одно главное понятие. После первых десятков коммитов нарезку сверяют с историей и сдвигают.
Факты: на 6 ноября 2026, по Википедии (теоремы Райса и Гёделя) и eventstorming.com. Пример с бронью условный.
© 2026 Егор Урванов