Skip to content
Beskid Platform specification

Beskid

Jump to a Beskid service

Beskid

Jump to a Beskid service

Native dependency injection - Contracts and edge cases

Platform spec article

Native dependency injection - Contracts and edge cases

Spec standingStandard

Owner
Piotr Mikstacki
Submitter
Piotr Mikstacki
  • Compile-time resolution — All bindings must be resolved before lowering; no runtime service locator in v0.2.
  • Fail-closed — Graph errors must block codegen for the host target; partial containers are forbidden.
  • Launched host wins — For the same binding key, the topmost (launched) host registry overrides parent host and corelib base entries.
  • Plural vs singular inject — Multiple registrations for one contract require T[] inject; singular inject T must resolve to exactly one.
  • Field inject only — Constructor parameter inject is forbidden.
  • One app per run — Exactly one launch per process; manifest app target is the single application host entry.
  • Lib hosts without launchLib targets may define host; launch must be rejected.
  • Fiber-local scope stack — Active named scopes are tracked per fiber (Execution).
  • Mod isolationMod projects must not define app host blocks.
  • Backend parity — JIT and AOT must share the same binding plan.
RuleEnforcement
Global single must not depend on named-scope services without withCompile error
startup only uses global bindingsCompile error if a named scope is required
Named-scope service used outside a satisfying withE1706
Service graph cycle (including field inject edges)E1703
Singular inject with multiple registrations at resolution levelE1705 (use T[])
Plural inject T[] with zero registrationsE1704
Child scope with without parent on stackE1707
Override changes lifetime kindCompile error
RuleDetail
Multiple host definitions per projectAllowed
launch Host per runExactly one host type
app targetSingle executable application target naming the entry that **launch**es the app host
Dual launch in one programForbidden
FormValid when
Unqualified injectDefault walk inner → global
global::Always targets merged global registry of launched host
parent::Active named scope stack depth ≥ 1

Invalid qualifiers or unreachable parents → compile error.

Reserved for composition in Diagnostic code registry. Register codes in compiler/crates/beskid_analysis/src/analysis/diagnostic_kinds.rs when implemented.

CodeCondition
E1701Executable app target missing or no launch reachable from entry
E1702More than one launch in the entry program (single-run violation)
E1703Service dependency cycle
E1704Unregistered contract/type at inject site (including empty T[])
E1705Singular inject matches multiple registrations (use T[])
E1706Scoped service used outside active with
E1707Child scope activated without parent
E1708with argument mismatch vs scope parameters
E1709launch target is not a host type
E1710host on Mod project
E1711launch in Lib target
E1712Constructor inject (field-only rule)
E1713Host override lifetime kind mismatch
E1714Invalid scope qualifier (global:: / parent::)
  • init / dispose on unwind — If init completed, dispose runs for that activation when the with block exits abnormally; activations that never finished init do not run dispose.
  • Repeated with HttpScope — Independent activations; separate scoped instance sets.
  • Same contract in parent and child scope — Unqualified singular inject resolves in innermost scope first; use global:: to pull parent/global registration explicitly.
  • Multiple Storage at globalinject Storage[] in startup receives all; singular inject StorageE1705.
  • Library host only — App host : LibHost merges registries; only app project **launch**es.