Relyra.Metadata.AutoRefresh (relyra v1.1.0)

Copy Markdown View Source

Phase 21 scheduled-refresh wrapper per D-05. Does NOT re-implement Relyra.Metadata.Refresh.refresh/2 — wraps it from outside, inserting the asymmetric-strictness checks D-15..D-21 BEFORE any deep parse.

Linear pipeline (every stage is a refusal point):

  1. Strict Req profile fetch (D-20)
  2. Pre-parse the metadata-root signature envelope (Pitfall 4 — verify BEFORE parse-deeply) and route through Signature.verify_metadata_root/4 against the operator-pinned trust anchor (D-16 + D-17)
  3. Parser.parse/2 (the existing hardened parser — only NOW)
  4. CorpusGate.check/2 post-parse pre-apply (D-21)
  5. DriftDetector.diff/2 (D-18)
  6. Import.build_candidate/1
  7. MetadataApply.apply_revision/4 with trigger: :scheduled_refresh (Plan 04 transactional D-28 path)

Any refusal short-circuits to MetadataApply.record_attempt/3 with the appropriate typed auto_suspended_reason so the LOCKED enum from Plan 01 is honored. Five refusal classes route to typed reasons:

Refusalauto_suspended_reason
TrustAnchor.check/2:trust_anchor_mismatch
Signature.verify_metadata_root:signature_invalid
CorpusGate.check/2:corpus_violation
DriftDetector entity_id_drift:entity_id_drift
DriftDetector new_signing_cert:new_signing_cert
(5 transient default):transient_failures_exceeded

D-39: every emit + every record_attempt call carries the batch's correlation_id from opts[:audit][:correlation_id].

Summary

Functions

refresh(source, opts)

@spec refresh(
  map(),
  keyword()
) :: {:ok, struct()} | {:error, Relyra.Error.t()}