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-saphyr into strongly typed structs with deny_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 immutable ActiveState).
  • Activation is ArcSwap::store of 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 check and 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).