Replay, fork, compare
Что это
Replay позволяет переиграть прошлый прогон с закреплёнными входами для отладки, не повторяя побочные эффекты (send/publish/pay) и не наследуя устаревшие одобрения. Подсистема включена по умолчанию (replay_enabled=true в config/platform.yaml). Она планирует, стейджит и аудирует, но не исполняет: запуск материализованной записи отложен на плоскость рантайм-адаптера, а она выключена по умолчанию (runtime_execution_enabled=false). Всё хранится в изолированном ops/platform.sqlite; канонические данные не пишутся (docs/12-platform-capabilities.md, ops/decisions/ADR-022-replay-fork-compare.md).
Когда использовать
- Нужно переиграть зафиксированный прогон с теми же входами для разбора поведения.
- Требуется fork: изменить ограниченный набор полей и увидеть, что поменялось.
- Нужно честно сравнить два прогона по токенам, стоимости, задержке, вызовам инструментов и eval-результатам.
Как это безопасно
ExecutionRecord неизменяемы и привязаны к хэшу; повторная запись с другими байтами — ошибка целостности, а не обновление. Результаты побочных эффектов хранятся отдельными неизменяемыми записями; план replay может подставить только проверенные записанные результаты, а каждый исходный побочный эффект без записи попадает в список blocked. Одобрения никогда не переносятся: план несёт производные плейсхолдеры по позициям, поэтому исходные approval_id не могут попасть в план, а стейджинг помечает план approval_required, если исходный прогон держал одобрения (src/raytsystem/replay/service.py).
Fork ограничен разрешённым набором полей — runtime_id, model, хэши инструкций и навыков, toolset_sha256, бюджеты (token_budget/cost_budget), graph_snapshot_id — пересечённым с контрактом; изменённая запись перевалидируется. Различия фиксируются по каждому полю с исходным и новым значением. Целостность плана проверяется при каждом использовании: хэш плана, производный ID, ожидаемый blocked-набор, плейсхолдеры одобрений и привязки записанных результатов должны совпасть, иначе план отклоняется как попытка обойти побочные эффекты или свежие одобрения.
Пошагово
- Постройте план replay поверх зафиксированного прогона:
uv run raytsystem replay plan .... - Или форкните с ограниченными изменениями:
uv run raytsystem replay fork .... - Сравните два прогона:
uv run raytsystem replay compare .... - Посмотрите существующие планы:
uv run raytsystem replay list --json.
Ожидаемый результат
RunComparison заполняется по каждому измерению с явным происхождением: токены/стоимость/задержка — из трейсов (с откатом на бюджеты, где записано), изменения вызовов инструментов и сбоев — из спанов трейса, изменения файлов — из расширений записи, изменения eval-счётов/assertions/артефактов — из связанных eval-результатов. Недоступные измерения перечисляются в unavailable_dimensions; test_changes всегда явно недоступно, так как observation-уровневые результаты тестов не персистятся.
Ограничения и безопасность
- Replay никогда не пере-отправляет, не пере-публикует и не пере-оплачивает: эффекты берутся из записанных доказательств или блокируются.
- Материализация возможна только из неизменяемого
ready-плана без blocked-эффектов и без ожидающих одобрений. - Любая точка входа fail-closed: при
replay_enabled=falseвызовы падают с ошибкой подсистемы.
Связанные страницы
Источники истины
docs/12-platform-capabilities.mdsrc/raytsystem/replay/service.pyconfig/platform.yamlops/decisions/ADR-022-replay-fork-compare.md