feat(scenarios): implement execution engine contracts

This commit is contained in:
2026-08-21 16:15:40 +03:00
parent adbea9db18
commit ffa4d6a85b
117 changed files with 9156 additions and 530 deletions

View File

@@ -3,8 +3,11 @@
# @BRIEF The main entry point for the FastAPI application.
# @LAYER API
# @RELATION DEPENDS_ON -> [Api.Init.ApiRoutesModule]
# @RELATION CALLS -> [Dependencies.AppDependencies.LiveExecutionComposition]
# @INVARIANT All WebSocket connections must be properly cleaned up on disconnect.
# @INVARIANT All WebSocket connections must be authenticated via JWT or API key token (see [SEC:C-3]).
# @INVARIANT Startup initializes a fail-closed 044 LiveExecutionCompositionRoot; runtime providers
# must be registered server-side and never inferred from HTTP/run metadata.
# @PRE Python environment and dependencies installed; configuration database available.
# @POST FastAPI app instance is created, middleware configured, and routes registered.
# @SIDE_EFFECT Starts background scheduler and binds network ports for HTTP/WS traffic.
@@ -86,19 +89,47 @@ from .core.logger import belief_scope, logger
from .core.utils.network import NetworkError
from .dependencies import (
get_async_job_runner,
get_config_manager,
get_current_user,
get_live_execution_composition_root,
get_scheduler_service,
get_task_manager,
)
from .models.auth import Role, User
# #region App.AppModule.LiveExecutionCompositionBootstrap [C:4] [TYPE Function] [SEMANTICS scenario,execution,composition,startup]
# @BRIEF Register trusted deployment live bindings before the scheduler can dispatch queued ScenarioRuns.
# @RELATION CALLS -> [ScenarioExecution.LiveCompositionRoot.Bootstrap]
# @POST Default dispatcher sees exact configured 037 providers or typed unavailable bindings; HTTP/run
# metadata never creates a live client.
# @INVARIANT Browser and Screenshot providers are separately registered server-side; their absence does
# not prevent startup and remains typed unavailable.
# @REJECTED Deferring Superset provider creation to a queued run was rejected — that would derive
# execution authority from a persisted/request identifier instead of deployment config.
def initialize_live_execution_composition() -> int:
from .services.dashboard_testing.execution.live_composition import (
bootstrap_live_execution_composition,
)
return bootstrap_live_execution_composition(
get_live_execution_composition_root(),
config_manager=get_config_manager(),
run_async=get_async_job_runner().run,
)
# #endregion App.AppModule.LiveExecutionCompositionBootstrap
# #region App.AppModule.Lifespan [C:3] [TYPE Function]
# @ingroup Module
# @BRIEF Async context manager for FastAPI startup/shutdown lifecycle.
# @RELATION CALLS -> [Core.Database.InitDb]
# @RELATION CALLS -> [Dependencies.AppDependencies]
# @RELATION CALLS -> [App.AppModule.LiveExecutionCompositionBootstrap]
# @POST On startup: admin exists, scheduler started. On shutdown: scheduler stopped.
# @INVARIANT The trusted live-composition bootstrap runs after AsyncJobRunner initialization and
# before scheduler startup; queued dispatch therefore cannot observe an unbootstrapped
# default root during normal application startup.
# @RATIONALE Alembic migrations removed from lifespan — they now run exclusively
# in docker/backend.entrypoint.sh (wait_for_db → alembic upgrade head).
# Running migrations in both places added ~5s startup overhead and masked
@@ -193,6 +224,9 @@ async def lifespan(app: FastAPI):
logger.reason("Initializing AsyncJobRunner")
get_async_job_runner() # Initialize singleton with running event loop BEFORE scheduler starts
logger.reason("Bootstrapping fail-closed ScenarioRun live composition root")
live_bindings = initialize_live_execution_composition()
logger.reason("ScenarioRun live composition bootstrap complete", payload={"bindings": live_bindings})
logger.reason("Starting scheduler")
scheduler = get_scheduler_service()
scheduler.start()