Comments 2
Сильная часть решения - переход от флага approved к связанному объекту действия. Но Action Envelope устраняет расхождение источников только в том случае, если после согласования его нельзя незаметно изменить. В n8n следующий Code или Edit Fields node способен пересобрать те же поля уже с другими значениями. Я бы сохранял при approval каноническое представление объекта и его digest, а непосредственно перед write заново вычислял digest и сравнивал его с одобренным. В envelope также полезны expires_at, nonce и версия целевого объекта. Остается еще узкое окно между pre-read и update_task: если задача изменится именно в этот момент, обычная проверка не спасет. Поддерживает ли ваш контур условную запись по версии или ETag, либо это окно закрывается блокировкой на стороне workflow?
Да, согласен — это отдельная граница контроля.
В примере Action Envelope должен быть связан не просто с approved=true, а с каноническим представлением конкретного action; непосредственно перед invocation эффективный payload нужно повторно канонизировать и сверять его digest с одобренным. Это закрывает незаметную мутацию внутри workflow после approval.
Но внешний race между последним read и tasks.task.update остаётся другим классом проблемы — TOCTOU. В текущем эксперименте я не считаю его атомарно закрытым: у используемого Bitrix24 update API я не опираюсь на документированный conditional write / If-Match. Поэтому fresh pre-read + post-write verification уменьшают и обнаруживают часть расхождений, но не эквивалентны compare-and-swap.
Для target system с ETag/version precondition я бы привязывал approval envelope ещё и к версии объекта и делал conditional write. Если такой примитив недоступен, это уже явное остаточное ограничение контура, которое нужно либо закрывать блокировкой на стороне target/workflow, либо учитывать в readiness decision.
Спасибо — это хороший следующий слой для разбора.
Нажали Approve на одно действие, а workflow попытался выполнить другое: разбор n8n + MCP + Bitrix24