ADR-050: Definition/Instance Duality and Two-Tier Instance LayeringΒΆ
| Attribute | Value |
|---|---|
| Status | Proposed |
| Date | 2026-06-12 |
| Deciders | Architecture Team |
| Extends | ADR-036 (Resource Management Abstraction Layer) |
| Related ADRs | ADR-045, ADR-046, ADR-047, ADR-051 |
1. ContextΒΆ
ADR-036 layered the instance state (ResourceState β TimedResourceState β concrete) and
ADR-047 gave us one reconcile loop. But the platform also has a large definition side β the
legacy .NET Track Manager, Session Manager, and Pod Manager all express a
definition β instance duality (SessionType β Session, PodDefinition β Pod,
Track β β¦ β Form). Today LCM models only a few of these (SessionDefinition, PodDefinition)
ad hoc, with no shared base, and treats every runtime resource as timed β even automation
outputs (Job, Report) that have no schedule of their own.
We need (a) one definition base mirroring the one instance base, and (b) a clean split between timed and untimed instances.
2. DecisionΒΆ
2.1 Two parallel familiesΒΆ
Generalise onto two bases in lcm_core:
ResourceDefinitionβ type metadata:type_key,version,provisioning_source, optionalauthorization_policy_id, a lifecycle template, child requirements/selectors, adefinition_status, and (for synced content) async_status. Definitions are the catalogue; they do not reconcile against infrastructure.ResourceInstanceβ a running thing:status+desired_status,state_history, an instantiatedlifecycle,owner_id, children. Its behaviour is to reconcile towarddesired_status.
classDiagram
class ResourceDefinition {
+str type_key
+str version
+str provisioning_source
+str~None authorization_policy_id
+dict lifecycle_template
+list child_requirements
+str definition_status
+str~None sync_status
}
class ResourceInstance {
+str id
+str resource_type
+str definition_ref
+str status
+str~None desired_status
+str owner_id
+list state_history
+reconcile()
}
class TimedResource {
+dict timeslot
+dict lifecycle
}
ResourceDefinition ..> ResourceInstance : instantiates
ResourceInstance <|-- TimedResource
ResourceInstance <|.. Job : untimed
ResourceInstance <|.. Report : untimed
TimedResource <|.. Session
TimedResource <|.. SessionPart
TimedResource <|.. PodInstance
TimedResource <|.. Host
2.2 Two-tier instance layeringΒΆ
ResourceInstance (L1) carries lifecycle + reconciliation but no Timeslot. TimedResource
(L2) adds the Timeslot (and TimedResourceState of ADR-036). The split decides where each
resource sits:
| Tier | Class | Instances |
|---|---|---|
| L1 (untimed) | ResourceInstance (holds ResourceState) |
Job, Report β inherit their parent part's window. |
| L2 (timed) | TimedResource (holds TimedResourceState) |
Session, SessionPart, PodInstance, Host/Worker. |
2.3 Catalogue β runtime mapΒΆ
| Definition | β Instance | Tier | Source |
|---|---|---|---|
SessionDefinition |
Session |
Timed | seed |
PartDefinition |
SessionPart |
Timed | seed |
PodDefinition |
PodInstance |
Timed | seed / content_package |
HostDefinition |
Host / Worker |
Timed | seed |
Form (+ taxonomy) |
delivered by SessionPart β no instance |
β | content_package |
JobDefinition |
Job |
Untimed | content_package |
ReportDefinition |
Report |
Untimed | content_package |
config (DeliveryEnvironment, LabLocation, HostingSiteLocation, AuthorizationPolicy) |
no instance | β | seed |
Device / DeviceDefinition are deferred (out of scope this round).
3. ConsequencesΒΆ
Positive β one definition base + one instance base; a single mental model (definition instantiates instance); untimed automation no longer forced into a timeslot; aligns the reconcile loop (ADR-047) with both timed and untimed instances.
Negative / trade-offs β two base classes to maintain; the L1/L2 split must be enforced so untimed instances are not accidentally scheduled.
Persistence β both bases are state-based Neuroglia aggregates (MotorRepository +
state_version); see ADR-051.
4. RelatedΒΆ
- resource-model.md β instance side.
- definition-catalog-model.md β definition side.