ADR-048: APTL Image-Free, Placement-Based Realization Envelope¶
Status¶
accepted
Date¶
2026-07-20
Last Updated¶
2026-07-20
Context¶
ADR-035 adopted RAES SDL and wired APTL in as a conformant RAES backend.
ADR-046 established dynamic realization: APTL compiles an authored RAES SDL into
a typed RuntimeModel, plans an ExecutionPlan, interprets it into
AptlRealization and DeploymentRealizationSpec, and applies it through the
deployment backend. ADR-046's Image Realization Addendum (issue #574) then
defined a node's realized identity as an image: a node source is either
pulled (a pullable image reference) or built (from captured source.build
provenance).
Issue #581 exposes why that image model is the wrong foundation for APTL's
realization envelope. The whole point of APTL being a RAES-conformant backend
is to demonstrate that an arbitrary conformant RAES SDL dynamically composes
into a meaningfully realistic range within a backend's realization envelope. A
pre-baked appliance image (for example wazuh/wazuh-manager:4.x or
docker.elastic.co/...) already contains the node's software, services,
content, accounts, and configuration. When a node is realized by pulling or
building such an image, the SDL is not driving the realization; the image is.
The range's meaningful detail lives outside the SDL, in a hand-curated image
specific to one scenario. That proves nothing about RAES's ability to compose
ranges. It re-encodes the previously hand-built Docker lab in RAES clothing.
RAES already models the surface needed to do this properly. A compiled
ProvisioningPlan carries not only nodes and networks but placements:
feature-binding, content-placement, and account-placement. A node's
runtime (RuntimeConfiguration) is a deep declarative desired-state contract:
packages, software_components, filesystem_inventory, local_identity,
identity_authorities, service_manager_units, and typed service families such
as security_monitoring_managers (Wazuh) and network_detection_engines
(Suricata). Source is backend-agnostic. So RAES can express an operating
system plus everything running on it; the backend, not an appliance image, is
responsible for materializing that state.
The RAES reference backend (raes_reference_backend, RUN-314) realizes plans
over an in-process or OCI driver. It is an emulation backend: its driver stands
up a container from an image_ref and records placements for provenance without
installing software. It proves the plan-interpretation and provenance shape, not
real materialization.
APTL is a single-user, local, Docker-based cyber range. That is a load-bearing property, not an implementation detail. APTL and Shifter (full cloud VMs) are the two distinct real conformant backends alongside the RAES libvirt reference; backend diversity is the research value of RAES conformance. APTL must therefore remain Docker-based and must not migrate to libvirt or VMs, since doing so would collapse the set of distinct conformant backends.
Decision¶
APTL realizes a node's meaningful state from the compiled RAES
ProvisioningPlan and RuntimeConfiguration, not from a pre-baked appliance
image. This supersedes ADR-046's Image Realization Addendum as APTL's
node-realization model.
-
Placements and declared runtime state are the realization mechanism. A node's software (
packages,software_components,feature-binding), data and configuration (content-placement,filesystem_inventory), and identities (account-placement,local_identity) are realized by the backend applying the declared RAES desired state onto a node, at the granularity the currentdocker-compose.ymlexpresses or better. The SDL and its compiled plan are the sole authority for what a node contains. -
A generic base substrate is permitted; an appliance image is not. A node still runs on some container base. A generic operating-system base image (the substrate a container needs to exist) is allowed. What is forbidden is an appliance image that encodes the node's scenario-meaningful software, services, content, accounts, or configuration outside the SDL. The test is: would this node realize into the same meaningful range if the image were replaced by a generic base of the same OS family? If not, the range detail is being smuggled in through the image and the realization is invalid.
-
APTL stays Docker-based and local. No migration to libvirt or VM targets. APTL's realization envelope is designed for its own affordances, a single-user local Docker range, not as a copy of the reference backend. This ADR sets the foundation for APTL's entire RAES realization envelope, optimized for security, maintainability, extensibility, and reliability, not for the minimum needed to boot one scenario.
-
Expressivity gaps are surfaced upstream, never worked around. When the RAES contract cannot express a fact a realistic node needs, the fix is a RAES issue against the contract (repo
Brad-Edwards/aces), not an APTL-local schema, a scenario-name branch, an appliance image, or a silent backend injection. Where the RAES realization posture legitimately admits backend-supplied detail, that detail is authored as an open realization scope (AuthorRealizationPosture.OPEN), not smuggled in under a closed-world default. Surfacing expressivity gaps is an intended output of this work. -
docker-compose.ymlis not an authoring or topology authority. Any retained Compose file is derived reference output only. It is never a topology, recovery, packaging, validation, or parity input. Realization, lifecycle, and parity all key on the admitted execution identity and the typed realization, per ADR-046. -
Parity is bidirectional. Static and live gates prove the realized range equals the admitted graph: both missing and unexpected runtime objects (containers, networks, volumes, mounts, ports, dependencies, placements) fail. A healthy subset is not parity.
The canonical authority chain remains ADR-046's: catalog/SDL, RAES
parse/compile/plan, interpret_provisioning_plan, AptlRealization,
DeploymentRealizationSpec, deployment backend, observation. This ADR changes
what a node's realized content comes from (declared desired state onto a base,
not an appliance image), not the pipeline that carries it.
Generic materializer contract (the invariant)¶
APTL's provisioner is a scenario-agnostic materializer. It contains no
per-product, per-node, or per-scenario branch. There is no wazuh, ad, misp,
shuffle, or techvault special case anywhere. It realizes any conformant node
purely from that node's declared desired state, and this invariant is what proves
RAES can compose an arbitrary conformant SDL. If APTL needs a product-specific
code path to stand a node up, the design has failed the bar.
Concretely, for every node the materializer:
- Base substrate. Starts a generic base-OS container image derived solely
from the node's
osandos_versionthrough a small, fixed, scenario-independent base-image map. There is no per-node image and no appliance image. - Software. Installs the node's declared
runtime.packagesandsoftware_components(package-manager provenance) via the declared package manager. Software identity comes from the SDL, not a baked image. - Filesystem and config. Places the declared
content(file, directory, or dataset) andruntime.filesystem_inventoryentries, using APTL's existing containment, symlink-rejection, and atomic-write discipline. - Identity. Creates the declared
runtime.local_identity(users, groups, sudo) and realizesaccounts, including domain-bound accounts through the existing directory provider. - Services. Installs, enables, and starts the declared
service_manager_unitsand the units implied by the typed runtime service families, through one generic service-unit mechanism, never a product-named startup path. - Runtime wiring. Applies declared networks, mounts, published ports, environment (reference names and classification only), Linux capabilities, and container settings.
- Verify. Observes the realized node and asserts it satisfies the declared runtime desired-state contract by read-after-write. A fact APTL cannot observe and verify is not claimed as realized.
APTL's backend manifest is expanded to honestly declare exactly the realization
kinds the materializer both materializes and verifies (packages,
software_components, service units and families, filesystem_inventory,
local_identity), drawn from RAES's published controlled vocabularies. A
declared node fact that APTL cannot express, materialize, and verify generically
is either a RAES contract gap (file a RAES issue) or a blocking admission
diagnostic, never a product-specific workaround and never a silent drop.
Capability-specific knowledge (which packages, which config, which service units
make a working Wazuh) lives entirely in the SDL.
Consequences¶
Positive¶
- APTL becomes a genuine demonstration that arbitrary conformant RAES SDLs realize into meaningful ranges, the actual research claim, rather than a re-skin of a hand-built Compose lab.
- The realization envelope generalizes beyond TechVault: any node describable by RAES features, content, and accounts realizes without a bespoke image.
- Expressivity gaps in RAES are surfaced as concrete upstream issues, improving the contract for every conformant backend.
Negative / costs¶
- Substantially more realization work than pulling images: features, content, and accounts must be provisioned onto a base substrate. TechVault is large; a full local range may need 20GB+ of memory. This is accepted.
- The TechVault SDL must declare node features, content, and accounts at docker-compose granularity or better. Nodes that previously leaned on an appliance image must express that capability declaratively.
- This is a large change delivered as one branch, many commits, one PR.
- The image-based node realization from ADR-046's Image Realization Addendum and its supporting code is superseded and removed from the operational path.
Risks¶
- Some node capabilities may exceed the current RAES expressivity, or exceed what a single generic base-OS container can host. Mitigation: file RAES contract issues and, where legitimate, author open realization scopes; never fall back to an appliance image. A node that cannot yet be realized image-free fails admission loudly rather than silently regressing to an image.
Supersession¶
Superseded in part by ADR-051 (2026-07-28). Decision point 2 above, that a generic base substrate is the only permitted container image and that no per-component image may supply a node's software, no longer holds. A node may be realized from a pinned upstream artifact or a digest-bound per-component materialization when the authored RAES
Source.artifact_requirementsays so, because under SEM-218 the authored posture binds the backend and APTL does not get to substitute a generic materialization for an exact declaration. Everything else in this ADR remains in force: placement-driven realization, fail-closed readback, the no-scenario-branch materializer invariant, Docker-local single-user scope, bidirectional parity,docker-compose.ymlas derived reference only, and the prohibition on a whole-range appliance image. ADR-051 additionally requires the complete runtime contract for every node, including image-backed ones, so an image may own component software but never TechVault's topology, credentials, accounts, seeded content, or peer wiring.
This ADR supersedes ADR-046's Image Realization Addendum (issue #574): a node's realized software, content, accounts, and configuration is no longer sourced from a pulled or built appliance image. ADR-046 otherwise remains authoritative for the dynamic realization pipeline, network realization, generated-model and lifecycle contract, and parity model. ADR-046's addendum is annotated to point here.