Три ALLOW и 120 единиц вместо 100: как ERP обходит лимиты AI-агентов
Разбор инцидента в ERP показал, что три последовательных разрешения ALLOW могут привести к превышению общего лимита: вместо разрешённых 100 единиц товара система заказала 120. Проблема не в ошибке авторизации, а в архитектуре контроля, где локальная проверка каждого шага не гарантирует соблюдение совокупного ограничения.
В сообществе разработчиков продолжается цикл материалов о том, что происходит между решением человека и фактическим действием AI-агента в корпоративных системах. Очередной разбор посвящён сценарию, в котором workflow получил разрешение заказать не более 100 единиц товара COMP-17 у трёх поставщиков, сформировал три заказа по 40 единиц каждый, и все три запроса прошли через слой авторизации с результатом ALLOW. Однако независимое чтение ERP показало итоговый объём 120 единиц. Ни один отдельный заказ не превышал 100, ни один запрос не обошёл контроль, но совокупный результат вышел за границу, заданную человеком.
Для проверки гипотезы авторы собрали воспроизводимый стенд с тремя реализациями одного и того же ограничения. В стенде grant привязан к субъекту planner-1, ресурсу COMP-17, списку поставщиков SUP-A, SUP-B и SUP-C и общему пределу в 100 единиц. Планировщик намеренно сделан детерминированным, без использования LLM, чтобы отделить механизм авторизации от качества рассуждений модели. В последовательном режиме stateful-контроль корректно отклоняет третий заказ: первые два по 40 единиц проходят, третий запрос с накопленным потреблением 80 единиц получает DENY, и в ERP остаётся 80 единиц. Однако эта схема работает только при строгом последовательном поступлении запросов.
Уязвимый вариант хранит использованную величину, но разделяет чтение, решение, исполнение и обновление на отдельные этапы. При конкурентном запуске три обработчика успевают прочитать одно и то же нулевое значение, после чего стенд намеренно удерживает их на барьере и отпускает одновременно. Каждый из трёх запросов видит доступные 100 единиц, проверяет, что 40 меньше 100, получает ALLOW и создаёт заказ в Demo ERP. Итоговый объём достигает 120 единиц, при этом учёт полномочий также показывает 120, то есть потерянного обновления или повторного начисления за одну операцию здесь нет. Ошибка возникает раньше: система допускает действие к исполнению, не закрепив за ним часть общего лимита. Это классическая гонка check-then-act, которая не появилась из-за ИИ и возможна в любом обычном сервисе.
Авторы подчёркивают принципиальное различие между локальной допустимостью отдельного шага и допустимостью итогового совокупного результата. Простейшая проверка вида requested_quantity <= 100 отвечает на вопрос, не превышает ли 100 единиц конкретный заказ, тогда как исходное разрешение означало, останется ли сумма всех заказов в пределах 100. Решение ALLOW в такой архитектуре не является доказательством того, что действие укладывается в делегированный общий мандат: оно говорит лишь о том, что конкретная реализация контроля пропустила запрос. Без атомарного резервирования три локально корректных решения могут вместе превысить один общий мандат, и именно это произошло в разобранном сценарии.
Исправленный вариант переносит проверку и резервирование в единый защищённый переход состояния. Gateway до вызова ERP выполняет транзакцию с блокировкой записи grant_balance, проверяет ресурс, поставщика и остаток, создаёт запись RESERVED и списывает доступную величину, после чего фиксирует изменения и возвращает ALLOW. Ключевой момент: когда один запрос зарезервировал 40 единиц, эти 40 становятся недоступны остальным, даже если запись в ERP ещё не завершилась. В конкурентном прогоне два запроса получают ALLOW и доходят до COMMITTED, а третий получает DENY_CAPACITY, поскольку доступными остаются только 20 единиц. Какой именно поставщик окажется третьим, при конкуренции несущественно, важен инвариант: два заказа исполнены, один отклонён до обращения к ERP, итог в ERP равен 80 единицам. В проверенной реализации механизм построен на PostgreSQL.
Разобранный случай продолжает серию материалов о границах между человеческим разрешением и реальным действием AI-агента. В первом разборе речь шла о разрыве между одобренным действием и тем, что workflow фактически попытался выполнить в связке n8n, MCP и Bitrix24. Во втором рассматривалась ситуация, когда агенту запретили запись в CRM, но CRM всё равно изменилась, поскольку права модели и фактические возможности всей системы не совпадают. Новый сценарий добавляет к этому ещё один класс проблем: даже корректно работающий компонент авторизации не гарантирует соблюдения общего лимита, если допуск не связан атомарно с общим состоянием. Для российского рынка, где ERP и CRM всё чаще связываются с агентскими workflow через промежуточные шлюзы, это означает необходимость пересмотра типовых подходов к контролю квот и полномочий.
Практический вывод для команд, внедряющих агентов в корпоративные системы, сводится к тому, что контроль должен отвечать на вопрос о совокупном результате, а не только о допустимости отдельного шага. Альтернативы атомарному резервированию, такие как последовательная обработка или stateful-проверка без блокировок, сохраняют уязвимость при конкурентном исполнении, а принудительная сериализация запросов снижает пропускную способность. Открытым остаётся вопрос, как масштабировать резервирование на распределённые ERP-контуры и как поступать с частично исполненными заказами при отказе после резервирования. Пока же авторы фиксируют главное: локально корректные решения ALLOW не заменяют доказательства того, что действие укладывается в делегированный мандат.