π Technical Design 021 β Application Entry Point and Bootstrap Orchestration¶
| Field | Value |
|---|---|
| ID | TD-021 |
| Title | Application Entry Point and Bootstrap Orchestration |
| Status | Completed |
| Owner | Contributors |
| Audience | Contributors, maintainers, DI system users |
| Created | 2025-10-11 |
| Last Updated | 2025-10-12 |
| Completion | 2025-10-12 |
| Reviewers | TBD |
| Approvers | TBD |
| Tracking | Phase 7 of DI Roadmap |
| Related | TD-013 (Module Scanning), TD-020 (Bootstrap Runtime), TD-012 (Enhanced Annotations) |
π§ 1. Summary¶
This design introduces application-level orchestration for DI container bootstrap, providing a standardized entry point pattern for configuring and launching applications with automatic service discovery. Building on TD-013's scanning infrastructure and TD-020's bootstrap runtime, this design adds the @application decorator, an ApplicationRuntime coordinator, and an ApplicationBase contract that promotes constructor injection and a single run() lifecycle method.
At a glance:
@applicationdecorator marks application entry points with declarative scanning configurationApplicationRuntime.launch("module:Class")bootstraps the container, resolves the application, and invokesrun()ApplicationBasedefines the lifecycle contract (run(self) -> None) for DI-managed applications- Integration with TD-013
BootstrapPlanBuilderand TD-020BootstrapRuntimefor automatic service discovery and bootstrap execution - Observability currently relies on container/bootstrap metrics, with room to extend runtime-specific signals later
π 2. Context and Problem Statement¶
With TD-013 providing module scanning and TD-020 externalizing bootstrap orchestration, the DI framework has the building blocks for automatic service discovery. However, there's no standardized way to configure and launch applications. Users must manually compose scanning, plan building, and bootstrap steps.
Phase 1-5 provides registration, bootstrapping, injection, annotations, and scanning, but application setup remains manual:
# Must manually compose scanning and bootstrap
scanner = DiPackageScanner(reflection)
plan_builder = BootstrapPlanBuilder()
# Manual scanning
plan = plan_builder.scan_packages(["myapp.services", "myapp.repositories"])
# Manual bootstrap
runtime = BootstrapRuntime()
container = DiContainer()
runtime.bootstrap(container, plan)
# Manual lifecycle
app = MyApplication()
app.run(container)
Key limitations:
- No Standardized Entry Point - No declarative way to mark application classes with configuration
- Manual Orchestration Required - Developers must manually wire scanning, planning, and bootstrap
- Container Exposure - Applications must accept the container to obtain dependencies, increasing coupling
- Limited Observability - Bootstrap and runtime metrics are scattershot across ad-hoc orchestration
2.1 Goals¶
- Declarative Entry Point -
@applicationdecorator for marking application classes with scanning configuration - Automatic Orchestration -
ApplicationRuntimecoordinates the complete bootstrap workflow via module path resolution - Lifecycle Simplicity - Standard
run()method executed on a DI-managedApplicationBasesubclass (no container exposure) - Integration with TD-013 - Leverage
BootstrapPlanBuilderscanning methods for service discovery - Integration with TD-020 - Use
BootstrapRuntimefor all bootstrap coordination - Zero-Boilerplate Startup - Single function call launches fully configured application using
"module:Class"path strings - Embedded Observability - Capture bootstrap, resolution, and runtime metrics without additional user code
2.2 Non-Goals (Out of Scope)¶
- Configuration file format or external configuration loading (future TD)
- Profile-based configuration selection (e.g., dev/staging/prod profiles)
- Application server integration (web frameworks, ASGI/WSGI servers)
- Hot-reload or development mode features
- Multi-container or distributed application patterns
2.3 Assumptions and Constraints¶
- TD-013
BootstrapPlanBuilderwith scanning methods is available - TD-020
BootstrapRuntimeandBootstrapPlanare implemented - TD-012 annotation processing infrastructure is available
- Applications have a single entry point class marked with
@application - Scanning happens once at application startup (not runtime discovery)
- Container lifecycle is owned by
ApplicationRuntime, not the application class
π§© 3. Design Overview¶
The application entry point system provides standardized orchestration for DI container bootstrap, enabling "convention over configuration" application setup. The design introduces a declarative @application decorator, the ApplicationRuntime coordinator, and an ApplicationBase contract that relies on constructor injection and a single run() lifecycle method.
3.1 Key Components¶
| Component | Purpose |
|---|---|
@application | Decorator marking application classes with scanning configuration and bootstrap options |
ApplicationRuntime | Coordinator that resolves "module:Class" paths, orchestrates bootstrap, and executes the application |
ApplicationBase | Minimal lifecycle contract (run(self) -> None) implemented by container-managed applications |
ApplicationConfiguration | Metadata captured by the decorator and consumed by the runtime |
3.2 Architecture¶
graph TB
subgraph Definition
DEC["@application"] --> CFG[ApplicationConfiguration]
DEC --> APP[ApplicationBase]
end
subgraph Runtime
RT["ApplicationRuntime.launch()"] --> RES[Module Resolver]
RES --> APP
RT --> CFG
RT --> BPB[BootstrapPlanBuilder]
RT --> BR[BootstrapRuntime]
end
subgraph Execution
BR --> CON[DiContainer]
CON --> INST[Resolved Application]
INST --> RUN["run()"]
end
classDef node fill:none,stroke:#1976D2,stroke-width:2px,color:#1976D2
classDef exec fill:none,stroke:#1976D2,stroke-width:2px,color:#1976D2
class DEC,CFG,APP,RT,RES,BPB,BR,CON node
class INST,RUN exec 3.3 Observability¶
- Existing
ContainerMetricsandBootstrapMetrics(TD-020) already capture the critical timings exercised by the runtime. - Application-specific telemetry is deferred; future work may layer module/class identifiers if gaps remain.
- Failures propagate module path and class context to enable logging/alerting without exposing the container.
3.4 Interface Impact (Before β After)¶
| Area | Before (Manual) | After (Application Entry Point) |
|---|---|---|
| Application Setup | Manual scanning + plan building + bootstrap | ApplicationRuntime.launch("myapp.entry:App") |
| Dependency Access | .run(container) accepts container directly | Constructor/autowired injection on ApplicationBase subclass |
| Lifecycle Control | Custom bootstrap workflows | Standard run() lifecycle method |
| Observability | Ad-hoc logging | Reuse ContainerMetrics/BootstrapMetrics; future runtime signals optional |
3.5 Removal/Deprecation Policy¶
- Alpha stage: No deprecation period for new features
- Migration strategy: Manual bootstrap workflows remain supported; new entry point pattern is additive
- Test updates: All new tests covering application startup will use the runtime-based entry point pattern
- Documentation: User guides will demonstrate both manual and runtime entry point approaches
π 4. Implementation Details¶
4.1 Application Contract¶
from dataclasses import dataclass
from typing import Callable, Sequence, TypeVar
from loryth.common.annotations import Annotation
from loryth.common.annotations import AnnotationContext
ApplicationT = TypeVar("ApplicationT", bound="ApplicationBase")
@dataclass(frozen=True)
class ApplicationConfiguration:
"""Configuration captured by @application decorator.
:param scan_packages: Import paths to scan for annotated services.
:type scan_packages: Sequence[str]
:param exclude_packages: Packages to exclude during scanning.
:type exclude_packages: Sequence[str]
:param validate_dependencies: Whether dependency graphs are validated.
:type validate_dependencies: bool
:param eager_prepare: Whether singletons are eagerly prepared.
:type eager_prepare: bool
"""
scan_packages: Sequence[str]
exclude_packages: Sequence[str] = ()
validate_dependencies: bool = True
eager_prepare: bool = True
class ApplicationError(Exception):
"""Raised when application orchestration fails."""
class ApplicationAnnotation(Annotation):
"""Annotation storing application configuration metadata."""
def __init__(self, config: ApplicationConfiguration) -> None:
"""Initialize the application annotation.
:param config: Application configuration extracted from the decorator.
:type config: ApplicationConfiguration
"""
super().__init__(name="application")
self.config = config
class ApplicationBase:
"""Base class for DI-managed application entry points."""
def run(self) -> None:
"""Start the application.
Dependencies are provided via injection.
:raises NotImplementedError: If a subclass does not implement the method.
"""
raise NotImplementedError
def application(
*,
scan_packages: Sequence[str],
exclude_packages: Sequence[str] = (),
validate_dependencies: bool = True,
eager_prepare: bool = True,
) -> Callable[[type[ApplicationT]], type[ApplicationT]]:
"""Decorator capturing application configuration metadata.
:param scan_packages: Packages to include during discovery.
:type scan_packages: Sequence[str]
:param exclude_packages: Packages removed from discovery.
:type exclude_packages: Sequence[str]
:param validate_dependencies: Toggle for dependency validation.
:type validate_dependencies: bool
:param eager_prepare: Toggle for eager singleton preparation.
:type eager_prepare: bool
:return: Decorated application class.
:rtype: type[ApplicationT]
"""
def decorator(cls: type[ApplicationT]) -> type[ApplicationT]:
"""Attach application configuration metadata to the decorated class.
:param cls: Application class being decorated.
:type cls: type[ApplicationT]
:return: Annotated application class.
:rtype: type[ApplicationT]
"""
config = ApplicationConfiguration(
scan_packages=scan_packages,
exclude_packages=exclude_packages,
validate_dependencies=validate_dependencies,
eager_prepare=eager_prepare,
)
AnnotationContext.annotate(cls, ApplicationAnnotation(config))
return cls
return decorator
ApplicationBaseprovides a minimal interface: applications overriderun()and rely on constructor or autowired injection (the container itself is never passed).ApplicationConfigurationholds decorator metadata; we continue to assume a single decorated class per module and resolve it by convention.- The
@applicationdecorator reusesloryth.common.annotations(same infrastructure as@service) to attach metadata viaApplicationAnnotation.
4.2 Runtime Orchestration¶
from importlib import import_module
from loryth.common.annotations import find_annotation
from loryth.common.di.bootstrap import BootstrapPlanBuilder, BootstrapRuntime
from loryth.common.di.container import Container
class ApplicationRuntime:
"""Coordinates bootstrap runtime and application execution."""
def __init__(self, bootstrap_runtime: BootstrapRuntime | None = None) -> None:
"""Create an application runtime coordinator.
:param bootstrap_runtime: Optional runtime used to execute bootstrap stages.
:type bootstrap_runtime: BootstrapRuntime | None
"""
self._bootstrap_runtime = bootstrap_runtime or BootstrapRuntime()
@classmethod
def launch(cls, path: str, *, bootstrap_runtime: BootstrapRuntime | None = None) -> None:
"""Convenience helper that creates a runtime and executes the application.
:param path: Dotted module path in ``module:Class`` format.
:type path: str
:param bootstrap_runtime: Optional runtime used for bootstrap orchestration.
:type bootstrap_runtime: BootstrapRuntime | None
:raises ApplicationError: If the application cannot be resolved or started.
"""
runtime = cls(bootstrap_runtime=bootstrap_runtime)
runtime.run(path)
def run(self, path: str) -> None:
"""Bootstrap, resolve, and execute an application entry point.
:param path: Dotted module path in ``module:Class`` format.
:type path: str
:raises ApplicationError: If resolution or execution fails.
"""
application_type = self._resolve_application(path)
config = self._read_configuration(application_type)
container = self._bootstrap_container(config)
application = container.resolve(application_type)
application.run()
def _resolve_application(self, path: str) -> type[ApplicationBase]:
"""Load the application class from a module path.
:param path: Dotted module path in ``module:Class`` format.
:type path: str
:raises ApplicationError: If the module or class cannot be located.
:return: Application class that inherits from ``ApplicationBase``.
:rtype: type[ApplicationBase]
"""
try:
module_path, class_name = path.split(":")
module = import_module(module_path)
application = getattr(module, class_name)
except (ValueError, AttributeError, ModuleNotFoundError) as exc:
raise ApplicationError(f"Cannot resolve application entry point '{path}': {exc}") from exc
if not issubclass(application, ApplicationBase):
raise ApplicationError(f"Application '{path}' must inherit from ApplicationBase")
return application
def _read_configuration(self, application_type: type[ApplicationBase]) -> ApplicationConfiguration:
"""Read configuration metadata attached by @application.
:param application_type: Application class being resolved.
:type application_type: type[ApplicationBase]
:raises ApplicationError: If the application annotation is missing.
:return: Configuration declared via the ``@application`` decorator.
:rtype: ApplicationConfiguration
"""
annotation = find_annotation(application_type, ApplicationAnnotation)
if annotation is None:
raise ApplicationError(
f"Application '{application_type.__module__}:{application_type.__name__}' is missing @application metadata",
)
return annotation.config
def _bootstrap_container(self, config: ApplicationConfiguration) -> Container:
"""Execute bootstrap plan based on decorator metadata.
:param config: Application configuration extracted from annotations.
:type config: ApplicationConfiguration
:return: Container prepared with all discovered services.
:rtype: Container
"""
plan_builder = BootstrapPlanBuilder.create()
plan = plan_builder.scan_packages(
config.scan_packages,
exclude=config.exclude_packages,
).build()
container = Container()
self._bootstrap_runtime.bootstrap(
container,
plan,
validate_dependencies=config.validate_dependencies,
eager_prepare=config.eager_prepare,
)
return container
ApplicationRuntime.launch("test.service.app:Application")resolves the class, reads decorator metadata via annotations, bootstraps the container, and executesrun().- Advanced scenarios can still instantiate
ApplicationRuntimedirectly to supply custom bootstrap runtimes or instrumentation. - Package scanning remains declarative through
@application; runtime does not keep an explicit reference to the container once execution starts. - Long-running behavior (e.g., schedulers, HTTP servers) is delegated to injected services; threading/async orchestration will arrive in a future TD.
4.3 Lifecycle Flow¶
@application(scan_packages=["orders.services"])
class OrderApplication(ApplicationBase):
"""Launch order-processing services."""
def __init__(
self,
http_server: HttpServer,
scheduler: JobScheduler,
consumer: MessageConsumer,
) -> None:
"""Store injected services required by the application.
:param http_server: HTTP server responsible for serving APIs.
:type http_server: HttpServer
:param scheduler: Scheduler that manages background jobs.
:type scheduler: JobScheduler
:param consumer: Message consumer handling inbound events.
:type consumer: MessageConsumer
"""
self._http_server = http_server
self._scheduler = scheduler
self._consumer = consumer
def run(self) -> None:
"""Start all long-running services."""
self._consumer.start() # RabbitMQ consumer owns its thread
self._scheduler.start() # Scheduler manages its own worker pool
self._http_server.start() # Web server blocks the main thread
@applicationpersists metadata for runtime consumption.ApplicationRuntime.launch()bootstraps and resolvesOrderApplication.- Dependencies arrive through constructor injection;
run()coordinates service startup without container access.
4.4 Error Handling¶
class SafeApplication(ApplicationBase):
"""Fails fast when startup prerequisites are missing."""
def __init__(self, health_check: StartupHealthCheck) -> None:
"""Store the injected health check dependency.
:param health_check: Service that validates environment readiness.
:type health_check: StartupHealthCheck
"""
self._health_check = health_check
def run(self) -> None:
"""Verify readiness and emit clear diagnostics.
:raises ApplicationError: If the application fails to start.
"""
if not self._health_check.is_ready():
raise ApplicationError("Startup health check failed")
try:
self._start_components()
except Exception as exc: # noqa: BLE001 - surfaced via ApplicationError
raise ApplicationError(f"Application startup failed: {exc}") from exc
def _start_components(self) -> None:
"""Private helper invoked during run().
:raises ApplicationError: If a component fails during startup.
"""
...
- Decorator or module resolution failures raise
ApplicationErrorbefore bootstrapping begins. - Exceptions from
BootstrapRuntimepropagate with application context for debugging. - Applications can raise
ApplicationErrordirectly to surface startup issues with clear messaging.
4.5 Observability¶
ApplicationRuntimeleans onContainerMetricsandBootstrapMetrics; no new counters are introduced in this phase.- Additional runtime-specific measurements (e.g., resolution or
run()duration) are deferred until concrete needs surface.
βοΈ 5. Semantics¶
5.1 Parameter Ordering Conventions¶
@applicationparameters followscan_packagesβadditional_configpatternrun()is parameterless; dependencies are delivered by DI construction- Error messages include application class name for context
5.2 Error Handling Strategies¶
- Failures during scanning or bootstrap are fatal and terminate startup
- Exceptions escaping
run()are wrapped with module path and application class context - All errors include the application class name for debugging
5.3 Threading Behavior¶
- Application bootstrap is synchronous and single-threaded
- Lifecycle methods should handle their own threading requirements
- Container is thread-safe after bootstrap completion
5.4 Observability Considerations¶
ApplicationRuntimeemits bootstrap, resolution, and run timings to the shared metrics pipeline- Metric payloads include module path and application class name for correlation
- Error events capture phase information to aid alert routing
π§ͺ 6. Examples¶
6.1 Constructor and Autowired Injection¶
from typing import Protocol
from loryth.common.di.application import ApplicationBase, ApplicationRuntime, application
from loryth.common.di.injection import autowired
class InventoryApi(Protocol):
"""Protocol for the inventory HTTP API."""
def start(self) -> None: ...
class LoggerProtocol(Protocol):
"""Protocol for structured logging."""
def info(self, message: str) -> None: ...
@application(scan_packages=["myapp.services"])
class InventoryApplication(ApplicationBase):
"""Launches the inventory API with injected dependencies."""
def __init__(self, api: InventoryApi) -> None:
self._api = api
self._logger: Annotated[LoggerProtocol, Autowired("inventory")]
def run(self) -> None:
"""Start the API service."""
self._logger.info("Starting inventory service")
self._api.start()
if __name__ == "__main__":
ApplicationRuntime.launch("myapp.entry:InventoryApplication")
- Constructor injection provides the primary API dependency.
- Autowired property resolves a qualified logger without exposing the container.
- The runtime loads the class from its module path and invokes
run().
6.2 Coordinating Long-Running Services¶
from loryth.common.di.application import ApplicationBase, ApplicationRuntime, application
@application(scan_packages=["payments.services"])
class PaymentApplication(ApplicationBase):
"""Coordinates background services that manage their own threads."""
def __init__(
self,
consumer: PaymentConsumer,
scheduler: ReconciliationScheduler,
api: PaymentsApi,
) -> None:
self._consumer = consumer
self._scheduler = scheduler
self._api = api
def run(self) -> None:
"""Launch long-running components."""
self._consumer.start() # RabbitMQ consumer owns its thread
self._scheduler.start() # Scheduler manages its worker pool
self._api.serve_forever() # Blocking HTTP server call
if __name__ == "__main__":
ApplicationRuntime.launch("payments.app:PaymentApplication")
- Each injected dependency owns its concurrency model.
run()simply coordinates startup order, aligning with the designβs βapplication spins up servicesβ guidance.
6.3 CLI-Oriented Application¶
import argparse
from loryth.common.di.application import ApplicationBase, ApplicationRuntime, application
@application(scan_packages=["reports.services"])
class ReportCli(ApplicationBase):
"""Generates reports from the command line."""
def __init__(self, generator: ReportGenerator) -> None:
self._generator = generator
def run(self) -> None:
"""Parse CLI arguments and execute the command."""
parser = argparse.ArgumentParser()
parser.add_argument("--output", required=True)
options = parser.parse_args()
self._generator.generate(output_path=options.output)
if __name__ == "__main__":
ApplicationRuntime.launch("reports.cli:ReportCli")
- CLI applications still return
None; exit codes remain the responsibility of the entry script. - Dependencies (e.g.,
ReportGenerator) are injected, enabling focused unit tests ofrun().
π§ͺ 7. Test Matrix¶
7.1 Unit Coverage¶
tests/unit/di/application/
βββ test_application_decorator.py # @application metadata capture
βββ test_application_runtime.py # launch() error handling and flow control
βββ test_application_configuration.py # Validation of ApplicationConfiguration defaults
Unit Test Focus: - Decorator metadata storage and validation (including missing config failures) - Module-path resolution and error propagation within ApplicationRuntime - Container bootstrap delegation (mocks/stubs for TD-013 and TD-020 components) - Static launch helper delegating to instance runtime
7.2 Integration Coverage¶
tests/integration/di/
βββ test_application_launch.py # End-to-end launch via runtime helper
βββ test_application_injection.py # Constructor + autowired injection flows
βββ test_runtime_container_bridge.py # Coordination with bootstrap/container components
Integration Test Focus: - Complete application startup via "module:Class" paths - Interaction between runtime, BootstrapPlanBuilder, and BootstrapRuntime - Validation that container/bootstrap metrics remain available for instrumentation - Compatibility with long-running services (simulated asynchronous components)
7.3 Regression Coverage¶
tests/regression/di/
βββ test_manual_bootstrap_compat.py # Manual bootstrap remains functional
βββ test_entrypoint_migration.py # Migration from manual to runtime entry points
Regression Test Focus: - Ensuring manual bootstrap paths remain untouched - Validating migration guides and mixed usage scenarios - Guarding against breaking changes in decorator metadata format - Sustaining compatibility with TD-013 scanning behavior
Testing Notes: - Unit tests isolate runtime components via fakes for plan builders and bootstrap runtime. - Integration tests rely on full implementations to verify discovery and injection. - Regression tests blend manual and runtime flows to confirm interoperability.
β 8. Acceptance Criteria¶
Note: Use this checklist to verify conformance when reviewing PRs.
-
@applicationdecorator persistsApplicationConfigurationmetadata on the class -
ApplicationRuntime.launch(path: str)resolves the decorated class and executesrun() - Applications inherit from
ApplicationBaseand expose onlyrun(self) -> None - Runtime integrates with TD-013 scanning and TD-020 bootstrap execution
- Validation errors (missing metadata, bad module path) raise
ApplicationError - Annotation metadata is attached/retrieved via
loryth.common.annotationsutilities - Comprehensive test coverage (unit, integration, regression) exercises constructor + autowired injection
- Migration and user documentation demonstrate
"module:Class"launch semantics - Manual bootstrap workflows remain supported and tested
π 9. Rollout and Migration¶
9.1 Implementation Phases¶
Phase 1: Core Contracts - Define ApplicationBase, ApplicationConfiguration, ApplicationError, and ApplicationAnnotation - Implement @application decorator using AnnotationContext for metadata storage - Validate annotated classes inherit from ApplicationBase - Outcome: Application contract and decorator established
Phase 2: Runtime Orchestration - Implement ApplicationRuntime.run() instance workflow with module resolution, configuration lookup, and bootstrap integration - Provide class-level ApplicationRuntime.launch() helper that instantiates the runtime - Harden error propagation for resolution and annotation failures - Outcome: Runtime orchestrates container bootstrap and application execution
Phase 3: Integration & Hardening - Wire runtime with TD-013 scanning and TD-020 bootstrap metrics - Confirm compatibility with existing container/bootstrap observability - Deliver documentation updates and example entry scripts - Outcome: Runtime ready for adoption with clear guidance
β οΈ 10. Risks and Mitigations¶
| Risk | Mitigation |
|---|---|
| Performance impact from additional abstraction layers | Profile startup time; optimize critical paths; maintain O(1) container operations |
| Migration complexity for existing users | Provide comprehensive migration guide with before/after examples; maintain backward compatibility |
| Integration issues with TD-013/TD-020 | Extensive integration testing; phased rollout; fallback to manual patterns |
| Learning curve for new application pattern | Clear documentation with progressive examples; starter templates |
| Error diagnosis complexity in orchestration | Comprehensive error wrapping with application context; detailed logging |
π 11. Progress¶
Legend: β³ Pending Β· π§ In Progress Β· β Completed
Phase 1 β Core Contracts - [x] ApplicationBase, ApplicationConfiguration, and ApplicationError - [x] ApplicationAnnotation leveraging AnnotationContext - [x] @application decorator validation for inheritance and configuration
Phase 2 β Runtime Orchestration - [x] Module-path resolution and container bootstrap coordination - [x] Class-level ApplicationRuntime.launch() helper - [x] Error propagation for annotation/lookup failures
Phase 3 β Integration & Documentation - [x] TD-013/TD-020 wiring confirmed with runtime workflow - [x] Guidance and examples refreshed across docs - [x] Test matrix (unit/integration/regression) implemented
π 12. Changelog¶
- 2025-10-12 β Restructured to highlight
ApplicationRuntime, runtime observability, and simplified lifecycle - 2025-10-11 β Initial draft created with summary and context sections
π 13. Glossary¶
| Term | Definition |
|---|---|
| ApplicationBase | Abstract base class implemented by application entry points exposing run() |
| ApplicationConfiguration | Decorator metadata describing scanning scope and bootstrap options |
| ApplicationError | Exception hierarchy raised for runtime orchestration failures |
| ApplicationRuntime | Coordinator that resolves module paths, bootstraps the container, and executes applications |
| ApplicationDecorator | The @application decorator that attaches configuration metadata to classes |
| Entry Point | Module path string ("module:Class") identifying the application to launch |
| Bootstrap Plan | Immutable specification of registration steps (TD-013) |
| Bootstrap Runtime | External orchestrator executing bootstrap plans (TD-020) |
| Runtime Observability | Future enhancements layering application identifiers atop existing container/bootstrap metrics |