// Package store contains the pending-rows reader. The reconciler never writes // to per_diem_rates directly; it hands the attestation ref back through // AttachAttestation, which goes through the same immutability-safe update // path admin-api uses. package store import ( "context" "errors" "basicstack.de/proofedmesh/services/attest-reconciler/internal/attest" ) // ErrNotFound is returned by AttachAttestation when the rate_id is gone. var ErrNotFound = errors.New("per_diem_rate: not found") // PendingRateStore is implemented by the Postgres reader in prod and by a // fake in tests. ListPending returns every row where // rate_change_attestation_ref IS NULL — these are what the reconciler re-signs. // // Kind is reconstructed from (valid_to, now): a rate with a valid_to that was // present at creation time is a "create" (valid_to-at-creation stays with the // row), a rate whose valid_to was set later via Retire is a "retire". Because // the Transparency Log is idempotent on (envelope, content_hash), a wrong // Kind guess cannot produce a duplicate log entry — it would just land under // a different content_hash the first time and converge from then on. type PendingRateStore interface { ListPending(ctx context.Context, limit int) ([]PendingRow, error) AttachAttestation(ctx context.Context, rateID string, attestationRef string) error } // PendingRow is the minimal projection of per_diem_rates needed to rebuild a // RateChangeEvent. The reconciler intentionally does NOT read the admin // principal fields — it attests under its own service identity (see // PerformedBy in the main command) because the original admin session is long // gone by the time a row is picked up. type PendingRow struct { Rate attest.Rate Kind attest.ChangeKind }