Contributor note: this file is the internal module and boundary map. For the user-facing operational guide, see
docs/DEEP_DIVE.md.
v8-runner is a Rust CLI for orchestrating local 1C platform operations. The current codebase is organized into eight main layers:
Architecture decisions live in spec/decisions, and agent-facing invariants are summarized in spec/architecture/invariants.md. Практический checklist для изменений MCP surface, public command boundary и config contract вынесен в spec/architecture/change-checklist.md.
cliparses arguments, maps them into transport-neutral requests, and owns command-level text/json rendering.configloads and validates YAML configuration.domaindefines structured result types for commands plus shared execution step structs.use_casesowns transport-neutral requests,ExecutionContext, structured failures, and business orchestration.mcpnow contains both the MCP-facing service boundary and the stdio/HTTP transport adapters: it maps raw tool inputs into use-case requests, returns MCP-specific DTOs plus structured business/internal failures, and publishes the live MCP tool servers.platformcontains process execution, utility discovery, connection argument building, and low-level 1C adapters.outputcontains CLI presentation primitives such asPresenterandEnvelope.change_detection,parsers, andsupportprovide shared subsystems and utilities.
The platform layer is intentionally split so responsibilities do not bleed into use cases:
platform::processdefinesProcessRunner,ProcessExecutor,ProcessRequest,ProcessResult, andSpawnResult.platform::locatorresolves concrete executables (1cv8,1cv8c,ibcmd,1cedtcli) and caches results perLocatorinstance. Platform component discovery by version mask is governed by ADR-0004.platform::connectionbuilds reusable V8 connection/auth arguments frominfobase.connection.platform::utilitiesis the current facade used by use cases. It owns the statefulLocatorand exposes the standard execution path.platform::designeris the low-level batch DSL for1cv8 DESIGNER, returningPlatformCommandResultso/Outlogs stay separate from runner-captured stdio.platform::ibcmdis the low-level DSL foribcmd, returningPlatformCommandResultwith stdout/stderr diagnostics (no/Outlog).platform::interactivenow contains the low-levelInteractiveProcessExecutorfor1cedtcli: it starts one child in its own process group, waits for the1C:EDT>prompt on stdout or stderr, executes prompt-delimited commands, applies the shared interruption policy for timeout/cancellation, and supports graceful shutdown with forced-kill escalation.platform::edt_sessionтеперь содержит общий shared EDT actor/manager для CLI и MCP: host owner явно задаёт queue capacity, shutdown timeout, startup timeout, workspace и prewarm policy; actor держит одну lazy interactive session, снимает queued cancellation/timeout из внутренней FIFO, использует absolute deadline от enqueue-time, сохраняет baseline reset/probe, restart/shutdown drain и typed lifecycle errors.mcp::edt_syntaxтеперь остаётся только MCP-specific boundary над общим actor: он рендерит interactivevalidate, читает--filelogs, сохраняетissues_found, когда parseable issues приходят вместе с interactivestdout, и маппит ошибки actor назад в существующий syntax-result/use-case boundary.mcp::telemetrynow owns MCP runtime telemetry state and stable tracing contracts for semaphore admission wait, shared EDT queue depth, EDT startup failures, strict session restarts, and restart/shutdown drain stats.
This boundary keeps interactive EDT execution isolated from the locator API and the standard execution path without reopening a separate execution model.
The CLI/runtime boundary is now split explicitly:
app.rsowns bootstrap concerns only: config loading, logging setup, log cleanup, and top-level error envelopes for pre-command failures.app.rsnow also branches early formcp serve stdioandmcp serve http, because those paths must bypass CLI presenters and run with MCP-specific bootstrap/logging behavior.cli::executeconvertsclapargs into transport-neutral request structs and renders command success/failure output.cli::executealso owns the CLI workspace lock boundary for commands that useworkPath; nested flows call explicit unlocked internals only while the outer command owns the lock.- CLI-only maintenance commands like
convertlive on the same adapter boundary and do not imply a matching MCP tool. use_cases::{request,context,result}define the transport-neutral contract that both CLI and future MCP adapters can consume.use_cases/*.rsno longer depend onclap,Presenter, orEnvelope.- Новые public CLI/MCP команды с runtime state под
workPathдолжны сохранять этот boundary и проходить checklist изspec/architecture/change-checklist.md.
This keeps current CLI behavior intact while reserving a stable internal API for MCP stdio/HTTP adapters. Workspace ownership is governed by ADR-0011.
CLI and MCP commands must share the same timeout/cancellation semantics.
The target contract is that every public command has a deadline, cancellation is routed through a transport-neutral execution context, and a cancelled/timed-out operation is reported only after the underlying operation reaches a terminal state.
Mutating DB operations must mark critical phases where hard kill is not allowed by default.
Cancellation representation фиксируется на command boundary: фактическая terminal cancellation использует ExecutionStatus::Cancelled, а cancellation/shutdown/timeout внутри successful critical phase возвращается как Succeeded с warning, без per-step cancellation state machine.
This policy is governed by ADR-0014.
Runner-like and pipeline-like commands should be assembled in the use-case layer as transport-neutral pipelines of validation, target resolution, workspace preparation, platform execution, output parsing, publication, cleanup, and diagnostics blocks.
Those blocks exchange typed context/input/output, leave step entries for skipped/degraded/failure behavior, and report domain execution through ExecutionOutcome<T>.
This result grammar is governed by ADR-0016.
v8project.yaml, loaded into AppConfig and accepted by config::validate, is the main project configuration contract.
source-set.name is a stable identity for runtime state, generated directories, diagnostics, and source-set selection.
The supported source-set[].type contract and validation boundary are governed by ADR-0017.
config init must autodetect source-set types only from marker content: Designer CONFIGURATION / EXTENSION come from Configuration.xml, ordinary EDT CONFIGURATION / EXTENSION come from .project natures plus DT-INF/PROJECT.PMF (EXTENSION also requires Base-Project) and src/Configuration/Configuration.mdo, while EDT external .epf/.erf sources are discovered only through homogeneous aggregate roots of valid child projects classified by canonical src/root.xml, never through recursive descriptor scans, per-artifact fallback, or phantom source-set generation.
The typed config model now splits MCP knobs into active HTTP/session settings and shared execution guardrails:
mcp.httpdefines the live HTTP listener and session behavior (bind_address,path,stateful_sessions,max_sessions,idle_ttl_secs).mcp.executiondefines shared admission/shutdown limits (max_concurrent_calls,shutdown_grace_period_secs) reused by both stdio and HTTP.tools.edt_clinow also carriesstartup_timeout_msandcommand_timeout_ms; the shared MCP EDT actor reuses these knobs for startup and bounded syntax execution.tools.client_mcp.wait_ready_timeout_msis the per-readiness wait budget for client MCP launch probing; when unset it falls back to the globalexecution_timeout, and the effective wait remains capped by the command deadline.
This keeps the config surface stable while allowing both MCP transports to share the same execution/session infrastructure.
Новые public config fields, source-set types и infobase subtrees должны обновлять typed model, validation, config init, примеры и архитектурную документацию синхронно по checklist из spec/architecture/change-checklist.md.
The MCP adapter no longer needs to talk to cli::execute or to reuse domain serialization directly.
mcp::requestdefines raw tool-facing request DTOs.mcp::service::McpServicemaps those requests intouse_cases::request::*and attaches per-call MCP transport metadata.mcp::responsedefines MCP-specific response DTOs, including nested step/test/issue structs that are decoupled from domain serialization details.mcp::errorsplits failures intoMcpBusinessFailure<T>for structured tool responses andMcpInternalErrorfor adapter/runtime misuse that must not be surfaced as business payloads.mcp::tool_resultdefines the structured transport payload returned by MCP tools for success vs business failure outcomes.mcp::server::McpToolServeris the shared rmcp handler used by both transports. It exposes tools-only capabilities, maps incomingcamelCaseparams into MCP DTOs, gates every tool call through a global semaphore, calls the synchronousMcpServiceviatokio::task::spawn_blockingfor non-EDT tools, and routes livecheck_syntax_edtthroughmcp::edt_syntaxplus the sharedEdtSessionManager.mcp::portowns the MCP workspace lock boundary before dispatching requests into transport-neutral use cases; the global MCP semaphore remains an admission limit, not a replacement for per-workPathownership.- Изменение MCP tool surface должно оставаться явным архитектурным событием: список опубликованных tools синхронизируется между
src/mcp/server.rs,ADR-0005, invariants и checklist-документом. - MCP execution admission and HTTP session capacity are separate guardrails governed by ADR-0013.
- MCP runtime telemetry is intentionally implemented as structured
tracingevents rather than a separate metrics backend: semaphore acquisition emitsmcp_execution_semaphore_wait, while the shared EDT actor emitsmcp_edt_queue_depth,mcp_edt_startup_failure,mcp_edt_session_restart, andmcp_edt_shutdown_drain. - The stdio adapter still reserves
stdoutfor MCP frames and enforces an absolute deadline for bounded EDT syntax calls: queue wait plus actor-side baseline/reset plus the interactivevalidatecommand all consume the sametools.edt_cli.command_timeout_msbudget. - The HTTP adapter is built on
axum+rmcp::transport::StreamableHttpService. A thin wrapper around the rmcp service enforces transport-level overload semantics for newinitializerequests (503whenmax_sessionsis exhausted), translates stateful non-initializePOSTs withoutMcp-Session-Idinto deterministic400, and eagerly releases tracked capacity afterDELETE. - HTTP session capacity is tracked via atomic reservation (
reserve -> delegate initialize -> confirm/release) plus lazy pruning of expired rmcp sessions, somax_sessionsremains correct across explicit close, TTL expiry, and failed initializes. - Queued MCP cancellation/timeout still return early as transport-level admission errors. Detached one-shot work retains the server-side permit until completion, while live
check_syntax_edtretains both the server-side permit and the shared actor's internal admission slot until the in-flight interactive command reaches terminal state and the server can return a structured tool result. - MCP normalization is finalized in the service layer: dump-mode defaulting, launch alias mapping,
allExtensionstri-state inference, and MCP-only pre-validation for syntax flag dependencies all live there instead of leaking into transport-neutral use cases. - Общий shared actor применяет deterministic baseline contract перед каждой interactive EDT-командой:
cd <scenario EDT workspace>, затемcd, который обязан вернуть тот же workspace path. Дляinitэто обычноworkPath/edt-workspace, дляconvert—workPath/convert/edt-workspace. Exhaustion request budget в этой pre-dispatch phase остаётсяQueuedTimeout; reset/probe faults форсят session restart и queue drain.
Important staging note:
- Shared EDT actor теперь живёт в
platformи используется всеми поддержанными interactive EDT сценариями: CLIinit, EDT export вbuild, CLIsyntax edtи live MCPcheck_syntax_edt. tools.edt_cli.auto_start=trueостаётся eager prewarm только для long-lived host process вроде MCP server; short-lived CLI commands всегда стартуют shared EDT lazy и держат session только в рамках current command lifetime.spec/archive/MCP_IMPLEMENTATION_PLAN_2026-03-21.mdremains the canonical staged MCP rollout history/reference for the closed Stage 1-5 MCP rollout; it is not the active backlog for follow-up EDT work.
build and dump use cases dispatch by builder:
builder=DESIGNERuses the existingDesignerDsl.builder=IBCMDusesIbcmdDslwithconfig import/applyfor build andconfig exportfor dump; for EDT build the EDT export step still produces Designer-format files first, and for EDT dump the reverse path first updates an internal Designer snapshot before EDT import/publication.- Builder backends are expected to stay interchangeable for implemented builder scenarios. Functionality added for the Designer builder should also be available through the IBCMD builder, or the gap must be documented explicitly. Future Designer agent mode should be added behind the same use-case contract.
- Server infobase support is a target contract for all tools; file-only behavior must be documented as a current gap rather than treated as the permanent architecture.
Constraints to keep in mind:
- Граница поддержки
IBCMDкак ограниченного backend формально закреплена в ADR-0001. - Для реализованных builder-сценариев
IBCMDуже поддерживает file и server infobase connections; server path требует полныйinfobase.dbmscontract. Оставшиеся file-only или unsupported сценарии считаются явными gaps, а не нормой архитектуры. builder=DESIGNERsupports object-level partial dump via/DumpConfigToFiles -partial -listFile.builder=IBCMDdoes not support object-scoped partial dump directly;PARTIALdegrades to incremental export for the resolved target and returns a warning while preserving the requested mode in the result payload.convertis intentionally not a builder-dispatch scenario: it is a CLI-only repo-aware EDT-CLI conversion flow over configuredsource-setthat stays independent from infobase/builder semantics;--outputselects a target root only, not arbitrary source/target pairs.
Full replacement outputs are published through a staging/backup contract governed by ADR-0015. Full dump writes to a sibling staging directory before replacing the resolved target directory. Package artifacts write to a sibling staging file before replacing the output file, and external EPF/ERF publication stages the whole output directory before replacing it. Incremental and partial dump modes remain direct non-atomic update modes.
Use cases now return transport-neutral payloads or structured failures.
cli::executeconverts successful command payloads intoEnvelope<T>for JSON mode.cli::executepreserves command-specific text formatting for build, test, dump, convert, syntax, and launch.- Failure payload emission is also decided at the adapter boundary, which keeps
launch --json-messagefailure semantics unchanged while allowing other commands to keep structured JSON failures. mcp::servicereturns MCP-specific DTOs and never reuses CLIEnvelopeor presenter logic.- Runner-like command payloads use
ExecutionOutcome<T>as their domain source of truth for status, diagnostics, structured errors, metrics, artifacts, and typed parsed payload; compatibility fields are computed by CLI/MCP adapters when a presentation contract still needs them.
workPath is the root for runtime artifacts:
workPath/logs/platform/stores platform log files.workPath/edt-workspace/stores the shared EDT workspace used byinit.workPath/convert/edt-workspace/stores the dedicated EDT workspace used byconvert.workPath/convert/out/<sourceSetName>/<designer|edt>/stores default generated convert outputs;convert --output <dir>publishes the same converted source-set content under a caller-provided root using source-set path mirror layout.workPath/temp/partial-lists/stores partial load and partial dump list files.workPath/temp/yaxunit/stores temporary YaXUnit config files.workPath/hash-storages/remains reserved for change detection state.workPath/designer/<sourceSetName>/is used by the EDT export/build flow as the generated Designer-format output area for a source-set.
The source-set and workPath state boundary is formalized in ADR-0002: DESIGNER format uses one designer-<sourceSetName> change-detection context, while EDT format uses both edt-<sourceSetName> for export decisions and designer-<sourceSetName> for load decisions.
Exclusive command ownership of workPath is governed by ADR-0011.
On-demand change detection and conservative file-level partial load rules are governed by ADR-0012.