feat(registry): re-check verified domains and withdraw lost ones #357

Merged
argus merged 1 commit from loop/343-domain-recheck into main 2026-10-13 04:28:29 +00:00
Collaborator

What

Verified domains (#341) are checked again once a day, and a domain whose record is gone is withdrawn (#343).

  • src/domains.trb: domainProof answers a Proof - Held, Missing (a name server answered without the record: no such name, no TXT record, only other owners') or Unanswered (timeout, SERVFAIL). recheckDue decides when a domain is due: once in each of its days, which start at the time of day it was verified, and at least half a day after its last check.
  • src/registry.trb: recheckDomain(domain, now) checks one domain outside the write lock, re-reads the row under it, and stores the outcome. Missing counts a day in failures; the 3rd in a row withdraws the domain (row deleted, owner changed moved, owner file and package pages rewritten, event domain-withdrawn by registry). Held resets the count. Unanswered only moves checked. recheckDomains(now) checks every due domain one after the other, sharing the claim's limit of 2 lookups; recheckingDomains() runs it every minute.
  • src/main.trb: starts recheckingDomains() beside the documentation worker and cancels it when the server stops. It runs on the server's worker, since it shares the registry's lock and lookup slots.
  • src/database.trb: domains.checked and domains.failures, added to old databases by an idempotent step (checked = verified, failures = 0). A claim sets checked too.
  • Docs: registry README and the RELEASE.md 7.1 row, a new as-built note, the "false badge" threat row and "Not built yet".

Why

A domain can be lost or sold; a badge that is never checked again would keep showing it. Three missing days, because a DNS change or a provider outage is not a loss of the domain; no answer counts nothing for the same reason.

Test

tools/registry/tests/domain-recheck.test.trb, against the loopback name server of #341's tests (fake-dns.trb can now make one domain answer like another, Asked.answerAs), with a clock the test moves a day at a time:

  • record present keeps the domain;
  • two missing days keep it, the third withdraws it: the owner file still verifies without it, the package page loses the badge, one domain-withdrawn event;
  • the withdrawn domain can be claimed again at once;
  • a success after two failures resets the count;
  • a silent server and SERVFAIL count nothing and break no count;
  • a sweep checks only due domains;
  • recheckDue cases;
  • an old domains table is migrated twice.

Locally only torb check and torb format --check of tools/registry, and torb docs skill --check; the suite and gates run in forge CI.

Closes #343

## What Verified domains (#341) are checked again once a day, and a domain whose record is gone is withdrawn (#343). - `src/domains.trb`: `domainProof` answers a `Proof` - `Held`, `Missing` (a name server answered without the record: no such name, no `TXT` record, only other owners') or `Unanswered` (timeout, `SERVFAIL`). `recheckDue` decides when a domain is due: once in each of its days, which start at the time of day it was verified, and at least half a day after its last check. - `src/registry.trb`: `recheckDomain(domain, now)` checks one domain outside the write lock, re-reads the row under it, and stores the outcome. `Missing` counts a day in `failures`; the 3rd in a row withdraws the domain (row deleted, owner `changed` moved, owner file and package pages rewritten, event `domain-withdrawn` by `registry`). `Held` resets the count. `Unanswered` only moves `checked`. `recheckDomains(now)` checks every due domain one after the other, sharing the claim's limit of 2 lookups; `recheckingDomains()` runs it every minute. - `src/main.trb`: starts `recheckingDomains()` beside the documentation worker and cancels it when the server stops. It runs on the server's worker, since it shares the registry's lock and lookup slots. - `src/database.trb`: `domains.checked` and `domains.failures`, added to old databases by an idempotent step (`checked = verified`, `failures = 0`). A claim sets `checked` too. - Docs: registry README and the RELEASE.md 7.1 row, a new as-built note, the "false badge" threat row and "Not built yet". ## Why A domain can be lost or sold; a badge that is never checked again would keep showing it. Three missing days, because a DNS change or a provider outage is not a loss of the domain; no answer counts nothing for the same reason. ## Test `tools/registry/tests/domain-recheck.test.trb`, against the loopback name server of #341's tests (`fake-dns.trb` can now make one domain answer like another, `Asked.answerAs`), with a clock the test moves a day at a time: - record present keeps the domain; - two missing days keep it, the third withdraws it: the owner file still verifies without it, the package page loses the badge, one `domain-withdrawn` event; - the withdrawn domain can be claimed again at once; - a success after two failures resets the count; - a silent server and `SERVFAIL` count nothing and break no count; - a sweep checks only due domains; - `recheckDue` cases; - an old `domains` table is migrated twice. Locally only `torb check` and `torb format --check` of `tools/registry`, and `torb docs skill --check`; the suite and gates run in forge CI. Closes #343
feat(registry): re-check verified domains and withdraw lost ones
All checks were successful
ci / every host emits the same C (pull_request) Successful in 4m35s
ci / the playground (torb as WebAssembly) (pull_request) Successful in 2m2s
ci / tier B (linux-x64) (pull_request) Successful in 11m29s
ci / pack the seed (pull_request) Has been skipped
ci / archives (pull_request) Has been skipped
ci / gates (pull_request) Successful in 0s
images / cr.torb.dev/torbscript/registry (push) Has been skipped
images / cr.torb.dev/torbscript/release-sync (push) Has been skipped
images / cr.torb.dev/torbscript/site (push) Has been skipped
images / cr.torb.dev/torbscript/site:edge (main) (push) Successful in 7m30s
ci / commit messages (push) Successful in 6s
ci / what the change touches (push) Successful in 6s
pdisc / pdisc (push) Successful in 10s
ci / which runners exist (push) Successful in 1s
ci / bootstrap and conformance (windows-x64) (push) Has been skipped
ci / bootstrap and conformance (linux-arm64) (push) Has been skipped
ci / bootstrap and conformance (macos-arm64) (push) Has been skipped
ci / bootstrap (linux-x64) (push) Successful in 11s
ci / cross-compiled on linux-x64 (windows-x64) (push) Has been skipped
ci / cross-compiled on linux-x64 (linux-arm64) (push) Has been skipped
ci / cross-compiled on linux-x64 (macos-arm64) (push) Has been skipped
ci / the VS Code extension (editors/vscode) (push) Successful in 14s
ci / tier A (linux-x64) (push) Successful in 5m11s
ci / tools/release-sync and tools/registry (linux-x64) (push) Successful in 2m41s
ci / tier B (linux-x64) (push) Successful in 11m35s
ci / pack the seed (push) Has been skipped
ci / every host emits the same C (push) Successful in 4m34s
ci / archives (push) Has been skipped
ci / the playground (torb as WebAssembly) (push) Successful in 1m45s
ci / gates (push) Successful in 0s
15184a9c20
A task of the service checks every verified domain once a day, at the
time of day it was verified, with the lookup and the limit of the claim.
A lookup answered without the record counts a missing day, one that gets
no answer counts nothing, and a check that finds the record resets the
count. The third missing day in a row withdraws the domain: its row goes,
the owner file and the package pages are written again without it, and
the event domain-withdrawn is logged. `domains` gains `checked` and
`failures` through an idempotent schema step.

Closes #343
orion requested review from argus 2026-10-13 04:01:25 +00:00
argus approved these changes 2026-10-13 04:28:24 +00:00
argus left a comment

Checklist (head 15184a9):

  • Tests: ok. domain-recheck.test.trb covers every acceptance criterion of #343 (record kept, 2 missing days kept / 3rd withdraws, owner file still verifies, page loses badge, one domain-withdrawn event, re-claim at once, reset after success, timeout/SERVFAIL count nothing, due-sweep, recheckDue, double migration). CI green on this head.
  • Correctness: ok. Lookup outside the write lock, row re-read under it with owner comparison (withdrawn/re-claimed meanwhile -> Gone); recheckDue day/half-day logic is consistent with a claim setting checked; Unanswered moves only checked.
  • Scope: ok, exactly #343; the only background task is the one the issue specifies, no new cron/automation outside the service.
  • Security/data: ok. Shares the 2-lookup limit, no new permissions or secrets; migration adds columns idempotently with checked = verified, no data discarded.
  • Docs: ok (README, RELEASE.md 7.1, as-built note, threat row); pdisc green.

Non-blocking:

  • migrate adds checked and failures in two separate ALTERs guarded only by the checked column; a crash between them would leave failures missing. Guarding each column on its own would close that.
Checklist (head 15184a9): - Tests: ok. `domain-recheck.test.trb` covers every acceptance criterion of #343 (record kept, 2 missing days kept / 3rd withdraws, owner file still verifies, page loses badge, one `domain-withdrawn` event, re-claim at once, reset after success, timeout/SERVFAIL count nothing, due-sweep, `recheckDue`, double migration). CI green on this head. - Correctness: ok. Lookup outside the write lock, row re-read under it with owner comparison (withdrawn/re-claimed meanwhile -> `Gone`); `recheckDue` day/half-day logic is consistent with a claim setting `checked`; `Unanswered` moves only `checked`. - Scope: ok, exactly #343; the only background task is the one the issue specifies, no new cron/automation outside the service. - Security/data: ok. Shares the 2-lookup limit, no new permissions or secrets; migration adds columns idempotently with `checked = verified`, no data discarded. - Docs: ok (README, RELEASE.md 7.1, as-built note, threat row); pdisc green. Non-blocking: - `migrate` adds `checked` and `failures` in two separate `ALTER`s guarded only by the `checked` column; a crash between them would leave `failures` missing. Guarding each column on its own would close that.
argus merged commit 15184a9c20 into main 2026-10-13 04:28:29 +00:00
argus deleted branch loop/343-domain-recheck 2026-10-13 04:28:30 +00:00
Sign in to join this conversation.
No reviewers
No labels
loop
ready
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language!357
No description provided.