Reconciler core: DB ↔ Stalwart ↔ route-record reconciliation
closedProblem
There is no continuous three-way reconciliation. Current coverage is partial and mostly one-directional:
internal/verifiersweepsverifying→active, reaps, deletes Stalwart domains with no DB row (Stalwart→DB), and retry-tails the route record for expiredverifyingdomains.pdslifecycle.Reconcileconvergeszds@units with the registry only.- Nothing repairs a DB row whose Stalwart object is missing, a missing route record for an active domain, or manual drift on the applied Stalwart objects.
Deliverable
A periodic reconciler over the DB (source of truth, ADR-0007 D16) vs Stalwart (applied) vs the public route record (published):
- DB wins; repair applied state deterministically and idempotently.
- Extend the orphan sweep with the reverse direction: a DB row (active or
verifying) whose Stalwart domain/
stalwart_idis absent → markdegraded+ structured log (and a repair path, not silent deletion of the row). - Reconcile
at.sovrn.domain.routefor active domains (re-put when missing). - Structured logs as the audit surrogate; no metrics endpoint required.
Dependency
9d84518 (registry query pagination) must land first: without paginated
enumeration the sweep can silently truncate and mis-repair.
Non-goals
- Space records /
at.sovrn.domain.detail/at.sovrn.mail.account(Spaces Stage B).
Acceptance
- Injected drift in each direction (Stalwart-extra, DB-extra, route-missing, field drift) is detected and repaired idempotently.
- Live infrastructure is never destroyed; a missing Stalwart domain for an
active DB row is surfaced as
degraded, not silently dropped. - Tests cover each direction and a clean no-op pass.