ADR 0011 — Require pinned ACES SDL validation for scenario packs¶
Status: Accepted
Date: 2026-07-11
Extends: ADR 0009
Context¶
Every scenario pack requires an sdl/ start state, but aces-pack-validate
does not currently parse those files. Pack-local sdl/validate_*.py scripts are
optional authoring checks and cannot establish ACES conformance. The pack-owned
flags/placement.yaml contract also says that each host resolves to an SDL
start-state node, but the validator does not enforce that join.
ACES publishes the aces-sdl package as the authority for SDL structural and
semantic validation. Its public parse_sdl_file() API returns the validated
Scenario, including the resolved nodes mapping and non-fatal advisories. The
current published line is 0.20.0, declares Python >=3.11, and the ACES SDL
contracts remain draft. Making ACES optional would leave the package’s required
content unchecked in ordinary installations and would not satisfy the
fail-closed pack contract.
Decision¶
aces-sdl is a mandatory, exactly pinned runtime dependency while the upstream
SDL contracts are draft. The initial pin was aces-sdl==0.19.1; issue 95
advances it to aces-sdl==0.20.0 after compatibility tests against this
package’s validator and template.
The package’s Python requirement follows the pinned ACES requirement, currently
Python >=3.11. A compatible version range may replace the exact pin only after
ACES publishes a stability and compatibility guarantee that justifies it.
aces-pack-validate remains the single catalog-validation entry point. It
parses every direct sdl/*.sdl.yaml document through ACES
parse_sdl_file() with full semantic validation. A pack with no such document,
or with any document ACES rejects, fails. The local JSON-Schema subset validator
continues to serve only pack-owned schemas; it must not validate SDL, consume a
copied SDL schema, or become a second SDL parser. Pack-local validator scripts
remain additive checks, not ACES-conformance authorities.
The returned ACES Scenario objects are retained for pack-to-SDL checks rather
than reloading SDL as generic YAML. A flags/placement.yaml.flags[].host
reference resolves when its exact identifier is present in Scenario.nodes in
at least one validated SDL document in the pack. This union rule supports a
pack’s full and reduced start-state variants without inventing a local notion of
which variant is canonical. A future profile-specific placement contract must
make its target SDL variant explicit; it must not change this rule by filename
guessing.
Only structured references declared by the canonical pack contract are checked.
The current such reference is flags[].host. The validator must not infer SDL
references from prose, from arbitrary keys ending in host or entity, or from
downstream catalog vocabulary. A future pack-owned structured reference is
added explicitly and resolves against the already parsed upstream Scenario
section that owns its target concept.
ACES owns SDL error classification. The integration consumes the public
SDLError hierarchy and preserves ACES errors as fatal and advisories as
non-fatal; it does not create a parallel exception hierarchy or promote an ACES
advisory to failure. Diagnostics join the existing failures aggregation and
CLI exit-status convention. They identify the pack and file and remain bounded;
they must not dump a parsed scenario, raw SDL, flag values, credentials, or
other source payloads into CI output.
Consequences¶
This deliberately expands the runtime dependency and SBOM surface. Existing Dependabot updates, CI
pip-audit, and release CycloneDX generation remain the supply-chain controls for ACES and its transitive dependencies.SDL root files must pass the same real-path containment discipline as other pack reads. ACES itself remains responsible for local-import containment, lock/trust validation, digest/signature checks, network bounds, and OCI bundle extraction safety; this repository does not implement a second module resolver.
ACES OCI imports can perform allowlisted network reads and populate
sdl/.aces/module-cache. No document content or credentials are passed in process arguments, and this package adds no persistence of its own. Catalog CI must treat ACES trust-policy changes as security-sensitive input and run untrusted contributions without repository secrets.The SDL path adds one stdout section to the existing CLI, with bounded per-file diagnostics, a final aggregate failure count, and exit status
1on any failure. There is no database, service, controller, or pack-side state in this validation path beyond the ACES-owned import cache described above.ACES API drift, Python-floor changes, or materially different import side effects are reviewed when advancing the exact dependency pin rather than being accepted implicitly by a resolver.