24 KiB
Execution Broker — текущий локальный контур
Проверено: 2026-10-14. Репозиторий: /Users/admin/Developer/execution-broker.
Состояние приёмки
main и origin/main Broker остаются на 437cbf8. Локальный кандидат 0.1.0-rc.26 зафиксирован в codex/production-readiness на b64a1ba83c82475b08276ea3fb6a54c99d4a1509. Смежные исправления Balda — отдельная ветка codex/production-readiness на 223b85ad213f77edebd452147d0058588813fe6c, checkout /private/tmp/execution-broker-balda-production. Кандидат не развёрнут и не опубликован; новых PR нет. Указанная Balda 223b85ad — отклонённый прототип; актуальный HEAD 49ce205d находится в отдельной ветке codex/ingress-outbox-v2, см. пересмотр после ревью ниже.
Действующий Broker — execution-broker:production-a3594c3, gateway — execution-broker-gateway:quality-437cbf8, Prism — execution-prism-adapter:session-fix-20261004. Сверка обнаружила drift: broker.json и worker.json выбирают разные immutable images для linux-smoke и linux-opencode-deepseek; три coding-профиля worker.json по-прежнему содержат Docker socket/group. В исходниках rc.26 этот доступ запрещён, а несовпадение image pin отклоняется до выделения worker с освобождением недоставленного credential. До применения кандидата старый работающий контур этих защит не получает. macOS bootstrap-пакеты и dynamic build contexts также требуют согласованного обновления Runner/Callee/config/workflow pins. Проверки из предыдущей приёмки ниже относятся к прежним развёрнутым версиям.
Локальная приёмка rc.26 — 2026-10-14
По решению владельца GitHub Actions заменены локальным прогоном. Все запущенные финальные проверки прошли: полный Broker make check build на macOS ARM64 и Linux ARM64 (Colima), race-тесты Callee на обеих ОС, Balda go test -race ./..., golangci-lint и architecture check, проверка плагина на закреплённой версии Balda, source/binary govulncheck и gitleaks всей истории. Для Broker, Callee и Balda — 0 вызываемых уязвимостей; недостижимые findings остаются отдельно видны в полных отчётах. Исправлены Go 1.26.8 → 1.26.9 и x/net 0.58 → 0.60 у Balda/Callee. Gitleaks исключает только точный fingerprint ложного срабатывания на старый Mattermost post ID.
Проверены реальные Docker/Callee Human pause → restart → resume → 5 артефактов → cleanup, embedded Beads и signed host-plan с rollback. Отдельно Linux ARM64 архив установлен без Go и source checkout: 4 сервисных образа, MCP, перезапуск Broker, 5 артефактов, succeeded и cleanup=done. Чистая установка закреплённых Claude/OpenCode/Node и ACP initialize прошла на macOS/Linux ARM64 без provider inference. Все четыре release-архива выполнили проверки версий, vault import/revoke, MCP, отказа без авторизации и SQLite backup; AMD64 на обеих ОС проверен через эмуляцию, не на native AMD64. Пять архивов rc.26 и SHA256SUMS лежат в dist/.
Полный отчёт и логи: /Users/admin/Developer/execution-broker/state/production-readiness-20261014/local-checks.json. Прежнее закрытие локальной задачи Balda balda-7w4 пересмотрено после ревью: она переоткрывалась и закрыта заново после исправлений и новых проверок; подробности ниже. Обе ветки и коммиты сохранены локально, checkout чистые; автоматическая проверка запретила push исходников и истории без явного разрешения владельца.
Границы Broker и оставшаяся работа
Предыдущий список смешивал Broker с локальными агентскими сценариями. Полный iPad sign/upload/install/unlock/launch, конфигурация search/Obsidian MCP, PR-workflows, миграция Hermes и решения об общем доступе к vault принадлежат Balda/локальному агенту или конкретному проекту. Включение их в условия готовности релиза Broker было ошибкой. Никакая новая политика прав Obsidian этим прогоном не реализована и не применялась. UI red/green и запись для конкретного приложения — его workflow; Broker отвечает за используемые им общие механизмы worker/guest execution и артефактов.
В актуальном docs/work-plan.md остаются собственные задачи Broker: согласованное развёртывание принятых бинарников/образов/bootstrap/plugin, универсальная подготовка стеков Linux/macOS, immutable tooling/Git caches, run-to-run artifact inputs и retention holds. Настраиваемый remote-action API — отдельное будущее расширение; обычный локальный агент может работать по SSH без него. Native AMD64 и off-host/Keychain disaster recovery остаются отдельными неподтверждёнными границами заявляемой поддержки. Физический iPad не является release gate Broker.
Пересмотр патчей Balda после ревью — 2026-10-14
Старая codex/production-readiness / 223b85ad — отклонённый прототип. Текущая codex/ingress-outbox-v2 в /private/tmp/execution-broker-balda-upstream содержит три локальных коммита поверх upstream 875d78eefd846ea2d54db37260409f412ed9c42f: 8615d512 (outbox), 1fd3e101 (continuation и README), 49ce205d (marketplace symlink paths). go.mod/go.sum не менялись, рабочее дерево чистое. Push, PR и deploy не выполнялись.
Локальная запись означает accepted независимо от NATS; publisher повторяет исходный envelope. Terminal receipts/expired tombstones удаляются через семь дней, pending не удаляются GC. NATS budgets включаются явно через balda.nats.bounded_streams: true; обычное обновление прежних caps не меняет. Policy принадлежит jobs/commandoutbox, state/bus wiring — commandoutboxfx; архитектурный enforcement обновлён.
После дополнительного ревью исправлена потеря continuation: повтор исходного provider message восстанавливает её из сохранённой answered-записи с тем же question-based ID/dedupe key; новое inbound ID и изменённый текст retry не заменяют ответ и не создают обычный turn. Проверены переполнение, ошибка AppKV, uncertain write и сбой до enqueue с закрытием/повторным открытием SQLite. README теперь документирует bounded_streams, default, env override и безопасное включение.
Финальный go test -race ./... прошёл в штатном macOS TMPDIR, без TMPDIR=/private/tmp workaround. Причина исходных plugin/catalog failures устранена: discovery вычисляет relative path относительно canonical root, тесты сравнивают canonical paths. Отдельный symlink-root regression до исправления падал, после него проходит. Lint (0 issues), architecture, govulncheck (0 reachable vulnerabilities), build и обе tagged race integration suites SQLite/PostgreSQL прошли. Первый полный прогон дополнительно поймал MCP shutdown timeout; baseline и три отдельных повтора прошли, затем прошёл и полный финальный прогон. Этот первый сбой сохранён в отчёте, причина нагрузки не объявляется доказанной.
Отчёт и все логи: /Users/admin/Developer/execution-broker/state/production-readiness-20261014/review-followup.json. Beads balda-7w4 закрыта после финальных проверок в явно локальной временной базе; это не shared task и не подтверждение независимого PR review. CLI: /private/tmp/execution-broker-native-tools/bd, в PATH не установлен; проектная база без issue_prefix не переинициализировалась.
История приёмки действующих версий
Проверка продолжения: run-0175c98134e42a9d912dcc2626264bcd получил точный план из одобрения human-1 запуска run-3a21ab05f78f688abc923d0946728233 (SHA256 994b9c5492136ff1710ace38aef33767658585fd597f553d74f85a3122f287dc). Реальная macOS VM начала с implementer, без specify/design/breakdown и нового Human. Claude ответил Authentication required; конкретная ошибка доставлена в Mattermost. Код не создан и не опубликован.
Native CLI обнулил оба токена и expiresAt в private cache, из-за чего прежний checkpoint застрял. Восстановление распознаёт этот явный результат с привязкой к аккаунту/организации: сохраняет предыдущий зашифрованный cache, отмечает необходимость входа и разрешает cleanup остановленного worker. Реальный cleanup=done подтверждён; issuer не revoked, owner освобождён, reauthentication_required=true. Владелец вошёл по ссылке из Mattermost; issuer подтвердил credentials_saved 2026-10-14 08:20:37 UTC, и run-3fcbd9a52b55e9c750671ea4357b705a автоматически продолжился с прежним утверждённым планом. Реализация, тесты и ревью прошли, но quality gate отклонил verifier: ACP склеил поясняющий текст с финальным JSON. Конкретная ошибка доставлена в Mattermost (g4nbxpzff78s8e5jjwgwxoxcjo). Исправление 437cbf8 допускает текст перед первым JSON, сохраняет исходный отчёт и по-прежнему отвергает несколько объектов, trailing content, failed и невыполненные проверки. Реальный отчёт воспроизведён исправленным шлюзом успешно.
Итоговый run-a1b236aaff2e3d877049cf790262ac37 той же Story завершился succeeded, cleanup=done 2026-10-14 около 08:36 UTC. Он начал сразу с implementer, без нового планового Human. На Darwin 27.0.0 / Go 1.26.9 ARM64 прошли gofmt, go vet, go test -count=1 ./..., сборка и smoke (--version, --help, greet, отсутствие имени и неизвестная команда с ожидаемым exit=2), ревью без findings, quality.json passed=true. SHA256 всех артефактов проверены. execution_publish_artifacts опубликовал b5a238cd478ae89923cdbb4908c4f26fd7ddabfc в /Users/admin/Developer/go-cli-claude-test, checkout чистый. Через Prism закрыты Task eb-9840de48c9a2090fdb1b6a4f, затем Story eb-bae3eaa3bfcaeb17678c1bc7; обе операции вернули completed=true, а read-only Beads подтвердил status=closed. Broker → Balda → исходный Mattermost-тред доставил итог: коммит опубликован, Task и Story закрыты. Это проверенный coding flow; первоначальный повтор потерянной MM-команды запускал оператор через штатный Broker retry, поэтому восстановление conversational ingress после NATS outage отдельно не объявляется проверенным. Эфемерные login URL в документации не хранить.
Молчание по команде владельца подтверждено: 2026-10-14 06:24:56 UTC Mattermost принял post, NATS вернул 503 insufficient resources, после трёх попыток ingress прекратил dispatch без ответа. История BALDA_EVENTS заняла около 1.9 ГБ при account max_store=2gb. Локальный max_store повышен до 16gb, история сохранена, Balda перезапущен. Новая ошибка запуска после этого доставлена. Повышение max_store было только восстановлением ёмкости. В локальной ветке Balda 223b85ad теперь реализованы durable ingress outbox на AppKV, сохранение исходного envelope до публикации, повтор после рестарта, dedupe receipts, FIFO внутри сессии и ограниченные retry/retention. Для NATS добавлены отдельные бюджеты streams с резервом для Commands и отказом при попытке установить лимит ниже уже хранимых данных. После исчерпания входных retries Mattermost получает безопасный ответ в исходной теме со стабильным pending_post_id. SQLite restart, переполнение настоящего NATS и доставка через HTTP-fixture проверены. В работающий Balda эти исходники в этом прогоне не устанавливались; реальный conversational outage/recovery в Mattermost заново не запускался.
Конфигурация и перезапуск
- Действующий Compose-файл:
/Users/admin/Developer/execution-broker/state/deploy/compose.production.json(приватный, не коммитить). Это полный снимок действующей конфигурации вместо цепочки временных override. - Broker config:
state/deploy/broker.json; worker config:state/deploy/worker.json; bootstrap assets:state/deploy/assets. - Контейнеры Broker/gateway/Prism:
execution-broker-broker-1,execution-broker-worker-1,execution-broker-prism-1. Balda:balda-mm-mac. - Применение выбранного образа:
docker-compose -f state/deploy/compose.production.json -p execution-broker up -d --no-deps brokerиз каталога репозитория. Изменение Git само по себе ничего не разворачивает. - Перед изменением активной конфигурации сохранять образ, config и согласованный Broker backup; не прерывать чужие задачи.
Одобрения
Для явно запрошенного повторного запуска использовать execution_retry: исходный run_id, chat/topic и новый idempotency_key. Broker выводит точный прежний scope и сохраняет одобрённый текст, вместо пересказа задачи моделью. Тот же Story/task/repository revision/worker/image/agent не требует нового одобрения плана. Изменение scope или позднейшие замечания владельца требуют нового решения. Сохранённый план — приватный admission snapshot; публичный status его не раскрывает. Native sign-in и ACP permissions остаются отдельными механизмами.
telegram_approvals.enabled=true и выбранная исходная сессия: запрос только в @balda_approval_bot; при выключенном Telegram — в исходном канале Balda. Результат, причина сбоя и очистка приходят в исходный Mattermost-тред. Original execution_respond сохранён для восстановления. После истечения срока самого Telegram-запроса кнопка «Обновить запрос» создаёт свежие кнопки для того же ожидающего Human в том же run и VM, пока не истёк исходный deadline запуска; она не одобряет задачу и не продлевает run. Токены находятся только в приватных secret-файлах.
Бот отправляет одно читаемое сообщение с кнопками. Длинный план явно помечен как preview; полный файл отправляется только по кнопке «Полный план». Просмотр не одобряет задачу. Reply на сообщение с кнопками передаёт замечания к плану: до трёх доработок в том же run с повторным одобрением. Обычное сообщение или Reply на вложение не считается ответом. Для ACP permission нужно выбрать предложенный вариант, для остановки — «Отменить задачу».
Это одобрения Broker workflows и worker ACP. Прямые ACP-запросы хостовых агентов Balda и operator grants для существующих папок/managed hosts — отдельные механизмы. Контекстный субагент для autoapproval остаётся плановой работой.
VM и доработка
VM принадлежит run. Терминальный исход завершает её после сбора артефактов; открытая Story сама по себе VM не удерживает. Claude/OpenCode теперь выполняют до трёх циклов implementation → verification → review в одном checkout и VM, с передачей проверок и findings в доработку. Исчерпанный цикл блокирует публикацию финальным quality gate. Инфраструктурный сбой, отмена и исходный deadline остаются терминальными.
Тестом на двух независимых соединениях воспроизведён SQLite database is locked / SQLITE_BUSY_SNAPSHOT (517). Запись теперь резервирует writer до чтения через BEGIN IMMEDIATE. Это доказанный дефект, но он не объявляется установленной причиной четвёртого запуска: его исходная ошибка не записана.
Автоматическое окружение и качество
Новые Broker-managed проекты не требуют ручного allowlist в каждой VM: Broker выводит guest config для своей Git namespace, а run-bound Git capability ограничивает доступ конкретным проектом. Digest пакета и версии workflow проверяются до запуска.
Go 1.26.9 Darwin ARM64 автоматически загружается Broker, проверяется по SHA256, кешируется и устанавливается только в disposable VM. Golden image и пользовательский Mac не меняются. SDK wrapper задаёт правильный GOROOT и доступные права каталогов.
Detached HEAD — штатный checkout закреплённой ревизии; локальные коммиты сохраняются в commits.bundle. Одобрение — факт workflow journal, переданный subsequent roles, а не файл в репозитории. Кандидат rc.26 усиливает quality gate: каждый verifier command повторно исполняется в disposable reviewed checkout, фактические exit/output сохраняются в private quality.json; изменение HEAD, tracked source или index блокирует публикацию. Любая проверка должна сама завершиться с exit=0; expected_exit_code != 0 отвергается. Отрицательный CLI-сценарий оформляется shell assertion, которая проверяет ненулевой код и сообщение приложения, а сама возвращает 0. Эта новая защита пока относится к кандидату, а исторические live-прогоны выше выполнены прежним Callee.
execution_diagnostics проверяет checksum артефактов и извлекает bounded причину Callee или Runner из callee.log, даже без quality.json, для failed, expired и canceled. Реальный expired run проверен через MCP после развёртывания fd29974. Отдельным тестом воспроизведён прежний отказ журнала для длинного Human: теперь вопрос до 256 КиБ сохраняется целиком, Human event ограничен 512 КиБ, остальные события — 32 КиБ. Конкретная ошибка обработки события сохраняется в редактированном логе Runner. Ошибки cleanup записываются отдельно в cleanup_error и не заменяют исходную причину исполнения. Cleanup, завершившийся во время отложенной доставки terminal, получает отдельное уведомление; более поздний receipt не скрывает его.
Подробные контракты: docs/telegram-approvals.md, docs/operations.md, docs/protocol.md, docs/testing.md. Будущие host permissions, SSH command catalog, iPad и прочие миграционные задачи — отдельные планы в docs/work-plan.md; они не объявлены реализованными этой приёмкой.