ProofedMesh/services/attest-reconciler
CTO 2e44147a71
All checks were successful
validate / JSON Schema (ajv) (push) Successful in 19s
validate / Go (vet + test) (push) Successful in 19s
validate / Rego (opa fmt + opa test) (push) Successful in 14s
services: add attest-reconciler Go service (periodic worker re-signs per_diem_rates rows without rate_change_attestation_ref via Signer+TLog, 11/11 go tests pass, go vet clean)
- services/attest-reconciler/ as its own go.mod (admin-api internal/ is not importable; shared code gets extracted when a 3rd consumer appears).
- Scheduler accepts "@every <dur>" or a bare Go duration; context-cancellation stops the loop cleanly.
- Store client defines PendingRateStore + Postgres skeleton for SELECT ... WHERE rate_change_attestation_ref IS NULL.
- Orchestrator + HTTPSigner + tlog.HTTPSubmitter mirror admin-api byte-for-byte so the TLog idempotency key collides on resubmits (kein Doppelsignieren).
- Prometheus text-format /metrics endpoint, dependency-free: attest_reconciler_dirty_rows_total, _reconciliation_attempts_total, _reconciliation_failures_total, _idempotent_noop_total.
- Tests with fake store + fake signer + fake submitter cover: happy path, already-attested rows are NOT re-signed, TLog idempotency across ticks, TLog-down failure path, pre-cancelled ctx.
- Top-level README reflects the new service; CI auto-discovers services/*/go.mod so no workflow change needed.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-25 18:06:36 +00:00
..
cmd/attest-reconciler services: add attest-reconciler Go service (periodic worker re-signs per_diem_rates rows without rate_change_attestation_ref via Signer+TLog, 11/11 go tests pass, go vet clean) 2026-10-25 18:06:36 +00:00
internal services: add attest-reconciler Go service (periodic worker re-signs per_diem_rates rows without rate_change_attestation_ref via Signer+TLog, 11/11 go tests pass, go vet clean) 2026-10-25 18:06:36 +00:00
go.mod services: add attest-reconciler Go service (periodic worker re-signs per_diem_rates rows without rate_change_attestation_ref via Signer+TLog, 11/11 go tests pass, go vet clean) 2026-10-25 18:06:36 +00:00
README.md services: add attest-reconciler Go service (periodic worker re-signs per_diem_rates rows without rate_change_attestation_ref via Signer+TLog, 11/11 go tests pass, go vet clean) 2026-10-25 18:06:36 +00:00

attest-reconciler

Periodic worker that re-signs per_diem_rates rows missing a rate_change_attestation_ref. Mirrors admin-api's Signer + TLog orchestrator (ADR-0005). Leans on the Transparency Log's idempotency guarantee so re-runs land on the same log_index and never produce a second entry.

Layout

  • cmd/attest-reconciler/ — entry point; wires store, orchestrator, metrics, and scheduler, handles SIGINT/SIGTERM.
  • internal/reconcile/ — RunOnce (per-tick work) and Scheduler (parses @every <dur> or a bare Go duration and drives RunOnce).
  • internal/attest/ — Statement, Envelope, Orchestrator, HTTPSigner. Byte parity with admin-api/internal/attest; split out until a 3rd consumer justifies a shared module (see parent issue note).
  • internal/tlog/ — HTTPSubmitter for POST /api/v1/log/entries.
  • internal/store/ — PendingRateStore interface + Postgres skeleton.
  • internal/metrics/ — dependency-free Prometheus text-format exporter for attest_reconciler_dirty_rows_total, attest_reconciler_reconciliation_attempts_total, attest_reconciler_reconciliation_failures_total, attest_reconciler_idempotent_noop_total.

Running

attest-reconciler \
  -spec="@every 1m" \
  -signer-url="https://trust.basicstack.de" \
  -tlog-url="https://tlog.basicstack.de" \
  -bearer="$POCKET_ID_TOKEN" \
  -metrics-addr=":9090"

Production replaces -bearer with the client_credentials TokenSource built in DEV-602.

Tests

go test ./...

Covers:

  • Pending rows get signed, logged, and attached (happy path).
  • Rows that already have an attestation ref are not re-signed (TestReconciler_SkipsAlreadyAttestedRows).
  • Re-signing the same row yields the same TLog entry (TestReconciler_TLogIdempotencyOnReRun) — proves "kein Doppelsignieren".
  • TLog failures bump the failure counter and leave the row pending.
  • Pre-cancelled context aborts the per-row loop.
  • ParseSpec accepts @every and bare durations, rejects crontab lines.
  • Metrics exposition format matches # HELP + # TYPE headers.