Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Roadmap

MOTIR-4219Implemented

(motir-core) The certificate status job — refresh pending customer domains from the platform, surface issued / expired / revoked / failed, and record the last check

Opened by Zhu Yue ·

A customer domain's certificate state changes on the platform, not in our database — this job is what carries the change back, so the settings pane shows the truth and never a stale "pending". Fly validates and issues asynchronously after the lifecycle requests a certificate, renews on its own, and a domain can stop resolving because a customer edited DNS nobody told us about. Nothing in the request path can observe any of that.

What ships

  • A job in the repository's OWN job enginelib/jobs/definitions/publicAddressCertificateRefresh.ts via defineJob (Inngest is retired here: tests/jobs/inngest-retired.test.ts asserts it), registered in lib/jobs/registry.ts, scheduled by lib/jobs/cron.ts on the cadence the ADR's Q5 sets (recommend every 5 minutes for pending_certificate / verifying, hourly for issued), with a catchUp posture consistent with lib/jobs/catchUp.ts.
  • Per run: listByStatusOlderThan for the statuses it owns, in bounded pages; for each row call the port's check(hostname) (the adapter) and map the answer onto the enum: issued when the platform reports the certificate issued; failed with the platform's reason when validation has failed or the required DNS is absent; expired / revoked when the platform says so on a previously-issued row; verifying rows re-run the _motir-verify TXT lookup the lifecycle owns and advance or fail. Every transition writes lastCheckedAt, and issuedAt on the first issued. The enum is total: a Record<PublicAddressStatus, …> decides what each value does on a check, including the values that do nothing (active, alias).
  • The platform call is a side effect outside any transaction (CLAUDE.md): read the platform, THEN one short write per row; a platform failure for one row marks nothing and moves on (logged, DLQ'd through lib/jobs/dlq.ts after the engine's retry budget), so one unreachable API call never wedges the sweep.
  • Not-configured is inert: with FLY_CERTS_TOKEN unset the job logs once and exits — a self-hosted build schedules it and it does nothing.
  • Tests: table-driven over every PublicAddressStatus × every port answer; the DLQ path for a platform failure; the bounded page size; the not-configured exit; the Record totality (a compile-time failure when the enum grows).

Boundary

No route, no UI, no certificate REQUEST (the lifecycle requests; this only reads), no rename or alias handling. The pane (next card) renders whatever status this job last wrote plus lastCheckedAt, which is why it is blocked_by this card.

Acceptance criteria

  • The job is defined with defineJob, registered, and scheduled; a test enumerates the registry and finds it, and inngest-retired.test.ts stays green.
  • For each PublicAddressStatus value, a table-driven test states the transition (or the no-op) for each port answer, and the mapping is a total Record.
  • A platform error on one hostname leaves that row unchanged, is retried by the engine, reaches the DLQ after the budget, and does not prevent the other rows in the same run from being checked.
  • lastCheckedAt is written on every checked row and issuedAt exactly once; a row that is issued and later reported expired by the platform becomes expired with the reason.
  • With FLY_CERTS_TOKEN unset the run exits without a repository read, asserted with a spy.
  • No file outside motir-core is touched.

Context refs

  • motir-core/lib/jobs/defineJob.ts · registry.ts · cron.ts · catchUp.ts · dlq.ts — the engine; tests/jobs/inngest-retired.test.ts
  • the adapterCertificateProvider.check; the storelistByStatusOlderThan, updateStatus
  • the decision — Q5 (Fly renews; we surface state)
  • motir-core/CLAUDE.md — side effects outside transactions

Discussion

No comments yet.

Adding to this discussion signs you in on app.motir.co and brings you back to this request.

Add a comment