Этот документ описывает execution semantics и operational nuances v8-runner без дублирования
полного каталога команд. За точным пользовательским surface обращайтесь к
CAPABILITIES.md, за YAML-контрактом к CONFIGURATION.md.
- Модель выполнения
- source-set и change detection
- Пайплайн push
- status
- Проверка и тесты
- Файловые сценарии и публикация
- Shared EDT
- workPath, lock и interruption policy
- MCP runtime semantics
v8-runner разделяет public surface и execution model:
- CLI и MCP являются разными публичными поверхностями.
- Use case слой остаётся transport-neutral orchestration boundary.
- Platform DSL и process execution остаются ниже use case слоя.
- Text output и machine-readable envelope проектируются отдельно от доменного результата.
Это позволяет держать один orchestration model для CLI и MCP, не смешивая clap, Presenter и
MCP DTO в одном слое.
source-set — минимальная единица оркестрации.
- Для
format=DESIGNERиспользуется один runtime contextdesigner-<sourceSetName>. - Для
format=EDTиспользуются два context-а:edt-<sourceSetName>для решения, нужен ли export;designer-<sourceSetName>для решения, что именно загружать в ИБ.
- Хеши конфигураций и расширений лежат в
workPath/infobases/<база>/hashes/<набор>.redb, хеши исходников расширений-инструментов — вhashes/tools/<имя>.redbтой же базы.<база>— имя объявленной базы; база, названная строкой соединения, помнится под ключом@<хеш>из нормализованного адреса без учётных данных. Адрес базы, исходный каталог и назначение набора проверяются вместе со снимком. Чужая память дляpush— отсутствие памяти, и у--fullтоже: отказno_memoryназывает её чужой; новую память создают полныйpull(pull <SET> --force) или перезаписьpush --force. - Кеш экспорта EDT и внешних артефактов остаётся общим в
workPath/hash-storages/. Журнал поколений —workPath/infobases/<база>/generation.json, запись на набор с привязкой памяти набора, именем инструмента, которым получен токен (designer,ibcmd,agent), и операцией; загрузка без применения (push --no-applyили отказ применения) добавляетapplied: false, аapplyпереносит запись на поколение после себя и снимает признак;resetпосле отката делает то же ответом инструмента записи, если база не ушла от записи, а перед откатом заменяет свою хеш-память набора пустой, и следующийpushзагружает набор заново. Прежний раннер поля не знает и читает такую запись как обычную запись отправки; егоpullперепишет запись безapplied: false, и непринятое после этого помнит толькоstatus --deep.pushспрашивает поколение до загрузки и после неё,pull— до выгрузки и после неё; изменившееся во время выгрузки поколение ответ называет, а в журнал ложится поколение до выгрузки, и следующийpushоткажет. Выгрузка по изменившемуся, перед которой поколение совпало с записью того же инструмента, не запускается (up_to_date). Без памяти о базеpush(и--full, и превью, иtest) отказываетno_memory, базу, ушедшую вперёд, —non_fast_forward; толькоpush --forceперезаписывает базу без этих проверок. Токен сравнивается только с токеном того же инструмента: запись другой пары, другого инструмента, запись без имени инструмента или неразборчивая запись не даёт пропустить выгрузку. - Копия файла версий набора лежит в
workPath/infobases/<база>/dump-info/<набор>/: подменённыйConfigDumpInfo.xmlв каталоге набора перед выгрузкой по изменившемуся, перед выборкойibcmd(--object, идёт как--sync) и перед загрузкой Конфигуратором или агентом заменяется ею, после удачной команды она перенимает файл платформы. Исключения: выборочная выгрузка Конфигуратора,pushчерезibcmdиpushчерез агента, получившего копию каталога (SFTP, общий каталог без ссылки), копию не меняют — файл в каталоге они не переписывают или их запись остаётся на стороне агента; сбой копию тоже не меняет. - Generated Designer output для EDT flow живёт под памятью базы
workPath/infobases/<база>/designer/<sourceSetName>; внешние обработки и отчёты — подworkPath/designer/<sourceSetName>. - Файл версий и версия формата в нём читаются до запуска платформы. Нет файла или в его корне
нет версии формата — выгрузка по изменившемуся становится полной поверх каталога, а снимок
EDT заменяется целиком; ответ и превью называют
FULLи причину. Лишнего такая выгрузка не удаляет и хеш-память не пишет (выравниваетpull <SET> --force). - Любая выгрузка без
--forceдо запуска платформы спрашивает сторожа замены (use_cases::destruction_guard) о каталоге набора: поверх каталога — по изменившемуся, выборкой, полной без файла версий —overwrite, замена и проект EDT —replace(замена ещё раз перед публикацией). Незакоммиченное в каталоге набора и каталог вне системы контроля версий с файлами — отказ до платформы; пустой каталог терять нечего. С--forceсторож отвечает перечнем уничтоженного: публикация отдаёт его вdata.lossesи в сообщение. Превью спрашивает того же сторожа и ничего не пишет:git statusидёт сGIT_OPTIONAL_LOCKS=0.ibcmd config exportбез--syncв непустой каталог отказывает, поэтому полная выгрузкаibcmdидёт в промежуточный каталог и ложится поверх каталога набора. Версия формата сверяется по таблице замеров «платформа → версия формата» (8.3.27 — 2.20, 8.5.4 — 2.22). - Прежняя общая память (
hash-storages/designer-*.redb,hash-storages/tool-*.redb,designer/<набор>формата EDT,agent/generation/) не переносится и не удаляется: первыйpushпосле обновления грузит всё дерево.
Change detection выполняется on-demand во время build/export/load decision и не требует
background watcher. push <SET> ограничивает анализ, export/load decision и
runtime snapshot commit только указанным source-set.
Для DESIGNER:
- Анализ изменений по выбранным
source-set. - Выбор partial/full path по изменённым файлам. Сегодня удаление, правка
Configuration.xml, изменённый каталог и список частичной загрузки больше 20 файлов (с XML-описаниями, добавленными к изменённым модулям) дают full; порог не настраивается (ключpush.partialLoadThresholdотвергается), а эти переходы снимаются — #379. - Загрузка через выбранный backend.
- Commit runtime snapshot только после успешного шага.
Для EDT:
- Анализ выбранных EDT source-set.
- Export затронутых EDT source-set в generated Designer representation.
- Повторный анализ generated Designer files.
- Load/apply generated files через
DESIGNERилиIBCMD.
Пайплайн намеренно не является атомарным across many source-set: поздний failure не откатывает
уже успешные ранние шаги.
status ничего не меняет — пишет только журналы платформы и сессии агента — и делит знание на два уровня по цене:
- без ключа — только память под
workPath/infobases/<база>: по набору — помнит ли копия базу (то же определение памяти, по которомуpushотказываетno_memory), запись журнала поколений и число файлов, изменившихся с последнего чтения каталога (анализ изменений без записи). Платформа не запускается и может отсутствовать;--allповторяет это для каждой базы местного слоя; --deep— команда чтения базы под её замком: поколение спрашивает тот же исполнитель, что выбрал быpush, и сверка с записью идёт по тому же правилу, что сверка перед загрузкой, — поэтому приmoved_aheadpush, который грузит этот набор без--force, откажетnon_fast_forward. Читает поколение тот же читатель, что уpushиpull(generation_reader), сверка —exchange_guard::predict. Состав расширений читает исполнительextensionsбез снимков ради префиксов; копии-владельцы берутся из метки рядом с файловой базой. Чего платформа не ответила, ответ называетnullс причиной.
test и check проектируются как часть того же локального цикла, а не как отдельная
эксплуатационная подсистема.
testсначала делаетpush, затем запускает YaXUnit или Vanessa Automation; с--no-pushсборки нет, и тесты идут в уже подготовленной базе.check designer-*работает только дляDESIGNERsource format.check edtиспользует EDTvalidateи привязан кformat=EDT.- Таймауты и interruption metadata должны проходить через общий command-level contract, а не жить как ad hoc special case конкретной команды.
Важно различать три разных класса файловых операций:
Это reverse sync из ИБ обратно в файловые исходники.
- Для
DESIGNERможет быть full, incremental или partial. - Для
IBCMDobject-scoped partial деградирует в incremental. - Полный
pullв форматеDESIGNERсначала считает хеши staging, затем публикует дерево и записывает эти хеши. Это общий путь Конфигуратора,ibcmdи агента. Отказ до публикации оставляет память прежней; после публикации ошибки хеширования или записи памяти становятся предупреждением с предложением повторить полныйpull. Правка опубликованного дерева остаётся изменением. - Цель полной выгрузки не может содержать
workPath: замена удалила бы состояние команды. - Для
format=EDTиспользует internal Designer snapshot, затем EDT import. pull --all(dump_config::execute_all) читает список расширений базы выбранным исполнителемpull, обходит пакеты в порядкеSourceSetInventory::configuration_packagesтем же сценариемpull <SET>и для расширения без набора выгружает его полностью вsrc/ext/<Name>(отbasePath), а затем дописывает набор вv8project.yaml(config_init::declare_source_sets, текстом, с повторным чтением). До первой выгрузки проект с объявляемыми наборами проходитconfig::validate::validate_with_declared_source_sets— те же проверки, что при загрузке, без требования каталога, которого ещё нет. Расширение-инструментtools.client_mcp.extensionне объявляется. Объявление идёт после выгрузки: отказ посреди обхода не оставляет в проекте набора без содержимого, а сбой между выгрузкой и объявлением оставляет каталог без записи — его сторож охраняет советомForceWayOut::Undeclared(безpull <SET> --force).downloadбез набора (infobase_export::execute_configuration_export_all) выбирает исполнителя выгрузки один раз, читает им состав базы тем же читателем, чтоpull --all(installed_extensions::read_installed_extensions), сопоставляет наборыSourceSetInventory::installed_packages(со сторожем #218) и выгружает найденные пакеты сценариемdownload <SET>вsource_inventory::package_in_directory.makeбез набора (artifacts::execute_all) обходитSourceSetInventory::ordered_source_setsсценариемmake <SET>. Каталог вместо файла проверяетSourceSetInventory::packages_directoryи отдаёт разрешённый путь; до работыSourceSetInventory::check_package_targetsотказывает, если пакет ложится на каталог набора илиworkPath(совпадает, внутри, вокруг), если имена пакетов совпадают без регистра или называют устройство Windows. Накопление ответов, остановку и закрытие ответа у всех трёх обходов ведётset_walk. Проект без пакетов (source-set: []) уdownloadидёт прежним путём одной выгрузки.
Это repo-aware файловая конвертация между XML платформы, проектом EDT и пакетом .cf/.cfe.
- Не использует базу проекта: загрузчик её не выбирает (
load_config_without_infobase), а--infobaseотвергаетcli::global_flags. - Не является alias для
pull. - Наборы берёт из
v8project.yaml; файл пакета — значение с расширением.cf/.cfeна месте набора (ConvertScopeRequest::from_arguments). - Направление решает
convert_sources::resolve_directionиз--to, формата и вида входа. EDT ↔ XML исполняет1cedtcli; направления с пакетом —convert_sources::package: выбор исполнителя по строкеconvertматрицы (provider_selection::select, квитанция вdata.provider), затемThrowawayInfobaseподworkPath/temp/throwaway-infobases/— тот же владелец, что уmake:build_package(config import --out) иexport_package(config export --file). Исходники EDT сперва переводит в XMLThrowawayInfobase::xml_from_edtв каталог временной базы. Пакет публикуется заменой файла, XML — заменой каталога со сторожем незафиксированной работы; цель перепроверяется после работы исполнителя.
Это materialization сценарии поверх готовых артефактов или publish targets.
uploadработает с готовыми.cf/.cfe.make/artifactsсобирают final.cf,.cfe,.epf,.erfиз исходников и публикуют их. База проекта не участвует: пакет собирается во временной базе раннера (use_cases::throwaway_infobase::ThrowawayInfobase) подworkPath/temp/throwaway-infobases/—ibcmd(infobase createсо своим--data, затемconfig import --out) или Конфигуратор (CREATEINFOBASE,/LoadConfigFromFilesбез файла версий,/DumpCfg; расширение — поверх основной конфигурации). Исходники EDT сперва переводит в XMLthrowaway_infobase::edt_sources_to_xml— единственный перевод уmake,convertиinfobase create(временная база зовёт его черезThrowawayInfobase::xml_from_edt): шаг сборкиbuild_project::execute_edt_export_stepв рабочей областиworkPath/edt-workspace, общей сессией EDT команды, если она её держит, — тогда действует предел команды сессии (tools.edt_cli.command_timeout_ms); одноразовым процессом уmakeиinfobase createшаг без предела, как уpush, уconvert— с пределом EDT команды. Других вызывающих шага, кроме сборкиpush, нет — это держит проверкаthe_edt_export_step_has_one_converter_besides_push. База служит прогону, своя у каждого исполнителя (artifacts::MakeSession):make <SET>— своя, обход без набора — общая на все наборы; внешние обработки Конфигуратор собирает поверх основной конфигурации в своей базе; после прогона она убирается, а брошенную описаниеTempDirKind::ThrowawayInfobaseвыдаёт уборке как свою. Замка базы и метки владельца уmakeнет.- Full replacement target publication идёт через staged publication model.
Сценарий — use_cases::init_project; вид цели решает путь. Файловая база: память
собираемого набора снимается до сборки (exchange_guard::AssembledMemory; у проекта EDT —
исходники EDT до перевода, а основной набор переводит в XML каталога, куда его переводит
push, единственный перевод throwaway_infobase::edt_sources_to_xml после импорта рабочей
области), затем ibcmd infobase create --import --apply --force или Конфигуратор (CREATEINFOBASE,
/LoadConfigFromFiles без файла версий, /UpdateDBCfg); после удачи
exchange_guard::remember_created_base пишет собранному набору его дерево, остальным —
пустую память. Сборка Конфигуратором, остановленная после создания, оставляет пустую память.
База в кластере: строку CREATEINFOBASE собирает V8Connection::create_cluster_infobase_arg
из Srvr/Ref подключения и реквизитов dbms/cluster, всегда с CrSQLDB=Y и
SchJobDn=Y (база создаётся с запретом регламентных заданий); /Out не ставится, а вывод
платформы в отказе проходит mask_text с паролями СУБД и кластера. DBPwd и SPwd
маскирует platform::secrets, DBUID и SUsr прячутся в показе отказа. Все процессы
создания — критическая фаза; отсрочку отмены называет collecting_deferrals.
С --from путь другой — init_project/copy.rs: конфигурация источника
(copy::source_config) — та же, что у команды, с его секцией из местного слоя. Замок
источника берёт граница — transport::hold_source_base из адаптера CLI, вслед за замками
своей базы, до конца команды; проверки владельца у источника нет. Снимок и загрузка образа
идут исполнителями infobase dump и infobase restore — infobase_export:: run_snapshot_provider и run_restore_provider с Конфигуратором, образ проверяет
validate_platform_artifact; у кластера перед загрузкой базу создаёт ClusterCreation —
тот же, что у infobase create, с тем же предупреждением о CrSQLDB=Y. После удачи
exchange_guard::remember_copied_base стирает прежнюю память под именем базы и пишет
copied-from.json: источник, образ, время. memory_of считает признак
памятью набора, build_project превращает первую отправку в полную, Standing не предлагает
выгрузку; признак снимает удачная отправка (forget_copied_base) и remember_created_base.
tools.edt_cli.interactive_mode включает shared interactive EDT execution model.
falseозначает one-shot1cedtcli.trueозначает shared actor/manager и одну interactive session для поддержанных EDT-сценариев.- Для CLI shared EDT стартует лениво при первом EDT-вызове.
tools.edt_cli.auto-startотносится только к long-lived host process, сейчас это MCP server.
Shared EDT нужен не ради отдельного public режима, а ради повторного использования одного execution model для CLI и MCP.
Проверку проекта EDT — check для формата EDT и check_syntax_edt — выполняет один
исполнитель для CLI и MCP. В shared-режиме у команды сессии нет кода выхода, и исход
читается по её выводу и журналу --file: stderr даёт tool_failed, замечания журнала —
issues_found, stdout без замечаний — tool_failed, а exit_code в ответе — 101 или -1. Предел
command_timeout_ms действует на каждый проект отдельно.
workPath является корнем runtime state.
- Логи, temp files, generated outputs и persisted snapshots не должны расползаться по каталогу primary config.
- Public CLI/MCP команды, работающие с runtime state под
workPath, должны брать workspace lock. - Workspace lock сериализует доступ к конкретному runtime root, но не заменяет admission limits и не делает multi-step orchestration fully atomic.
- Файловую базу команда держит своим замком рядом с каталогом базы, взятым после workspace lock:
две рабочие копии с разными
workPathодновременно с одной базой не работают, вторая получаетinfobase_busy. - Под замком базы граница проверяет метку владельца рядом с каталогом базы: команда записи на
базе другой рабочей копии идёт с предупреждением шага
infobase ownerи метку не меняет; команда записи на базе из местного слоя без другого живого владельца записывает свою копию в метку. Проверка одна — вuse_cases/transport.rs, за замком базы, для CLI и MCP; превью читает метку без замка. Запись другой копии владелец замечает своей следующей отправкой по поколению (non_fast_forward).
Interruption policy:
- timeout/cancellation являются общим CLI/MCP contract;
- terminal cancellation и deferred interruption должны различаться;
- отмена — род
interruptionу любой команды, и решает это сама ошибка, а не сигнал: отказ, пришедший при ожидающей отмене, остаётся отказом; - в формах с итогом исполнения
test,upload,make,download,infobase dumpиinfobase restoreостановку отменой пишет один владелец (record_cancellation): статусcancelled, ошибкаcancelledи запись о прерывании с одним текстом; - critical publish/apply phases не hard-kill by default; запись в базу, и
/RestoreIBтоже, дорабатывает до конца.
MCP deliberately narrower than CLI.
- Опубликованы только 8 tool-операций.
CallToolResult/isErrorостаются MCP-native protocol behavior.- Business failure payload uses the shared command envelope.
- HTTP session capacity и execution admission являются разными guardrails.
- Shared EDT under MCP reuses the same execution model instead of inventing a separate MCP-only runtime path.