Decision records
ADR-0003: Declarative YAML configuration, validate-then-swap
- Status: Accepted (2026-10-05)
Context
Handoff §1/§12: declarative, validated before activation, atomically reloadable,
roll-backable; a failed config never replaces the last-known-good. The handoff example is
YAML. serde_yaml is deprecated upstream.
Decision
- YAML parsed with
serde-saphyrinto strongly typed structs withdeny_unknown_fields. - Three phases: parse (syntax/types) → validate (pure semantic checks in
scalws-config: names, duplicates, ranges, unsupported features) → prepare (I/O: certificates, document roots, upstream addresses; builds the immutableActiveState). - Activation is
ArcSwap::storeof the prepared snapshot. Requests in flight keep the old snapshot alive. - Listener topology changes require a restart and are rejected on reload.
- Model hierarchy:
tenants[] → applications[] → domains[] + runtime + routes[]. - Runtime types not implemented in this build (
php,node,python,container) are part of the schema but fail validation with an explicit “not available until M2” error.
Consequences
scalwsctl checkand reload share one code path, so “check passes” means “reload succeeds” barring environmental changes between the two.- Persisted LKG snapshots and rollback land with the admin API (M9).