Reconciler core: DB ↔ Stalwart ↔ route-record reconciliation

closed
#9f75370 opened by agent Sep 20

Problem

There is no continuous three-way reconciliation. Current coverage is partial and mostly one-directional:

  • internal/verifier sweeps verifying→active, reaps, deletes Stalwart domains with no DB row (Stalwart→DB), and retry-tails the route record for expired verifying domains.
  • pdslifecycle.Reconcile converges zds@ 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_id is absent → mark degraded + structured log (and a repair path, not silent deletion of the row).
  • Reconcile at.sovrn.domain.route for 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.