Repository navigation
admin: a domain verified by hand is not an alert until a check has passed - #49
Merged
Merged
Conversation
added 12 commits
September 26, 2026 00:49
… the last check's result
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A domain added with
clickmonk domain add --verifiedhas no TXT record by design, so its DNS check fails every five minutes and it used to count as needing attention for ever. This records when a domain's check last passed, and a verified domain that has never passed one is shown as verified by hand rather than as a problem.The rule
A verified domain that has never passed a DNS check is not an alert. Once a check has passed, a later failure is an alert again, because then something changed: a record removed, a nameserver moved. An unverified domain waiting for its record is still an alert, as before. The rule is one SQL condition (
ALERT_CONDITION), and bothGET /api/alertsand the status route's count use it.Only a
verifiedresult counts as a pass. A resolver error or a missing record never sets the time. If either did, one resolver outage would put every domain verified by hand back in the alert list.The API says so rather than leaving the interface to work it out. Domain objects gain
passedAt(when a check last passed, ornull) andhandVerified(verified with no passing check). The domain card reads "Verified by hand, no TXT record", then the last check's own result and time in muted text. It still shows the record to publish, and it no longer says the record proved anything.Storage
Postgres 010 adds
domain_dns_checks.passed_at timestamptz NULLand backfills it from rows whose last check wasverified.SCHEMA_VERSIONis 10. The column goes on the check table, not ondomains, for the reason the table exists: a write todomainsfiresconfig_changedand makes the redirect reload its configuration, and the check runs every five minutes. The redirect's snapshot load never reads this table, so the migration's lock cannot hold it up. The worker and the on-demand check decide "passed" once, in one upsert (COALESCE(EXCLUDED.passed_at, domain_dns_checks.passed_at)), so a failing check keeps the earlier time.The backfill cannot tell two cases apart. It only knows the last stored result, so a domain verified by DNS whose last stored check happened to fail looks exactly like one verified by hand. After this migration it would stop alerting until its next passing check. No release has been tagged, so no install is upgrading into this.
Closes #47
Verification
The gate ran in CI's order:
pnpm lint,pnpm lint:sh,pnpm typecheck,pnpm build, thenpnpm test, which ran 1,558 service tests and 562 interface tests. The interface suite passed five runs in a row. The stack suites passed 86 tests, including the browser suite, whose screenshot shows the hand-verified domain left out of "1 domain needs attention". The durability suite passed.Every guard was mutated individually and caught by exactly its own test: the pass-only stamp, the
COALESCEon update, thed.verifiedclause in the alert condition, the backfill, the API fields on every route that returns a domain, and the card's order.