Skip to content

Pin domain registration to the audit and print it in the client report - #56

Merged
ThinkingSpade merged 3 commits into
mainfrom
feat/audit-domain-expiry
Aug 20, 2026
Merged

ThinkingSpade merged 3 commits into
mainfrom
feat/audit-domain-expiry

Conversation

@ThinkingSpade

Copy link
Copy Markdown
Owner

The "proper" version of audit domain expiry: stored on the run, so it reaches the client report PDF.

Migration is already applied to prod

drizzle/0040_plain_saracen.sql — ALTER TABLE audits ADD domain_expiration_json text.

Applied to prod D1 before this code exists, per the deploy trap where Workers Builds ships on a push to main and never runs db:migrate:prod. Verified: the column is present on remote, and migrations list --remote reports nothing pending. Additive and nullable, so the currently-running build ignores it — this is safe to sit ahead of the merge indefinitely.

Also mirrored into the hand-written Postgres schema, which the parity test enforces.

It is a click, not part of the crawl

Resolving bills 5 APIVerve credits. An audit's consent covers crawling — firing a third-party lookup the user never asked for, on every audit, is exactly the auto-spend pattern this codebase keeps getting bitten by. So the results page shows a card with an explicit "Check domain registration" and the cost stated up front.

Once stored, re-opening the audit renders it with no request at all.

Absolute dates only, recomputed on read

The row stores { domain, expirationDate, createdDate, lastUpdatedDate } and nothing derived. Day counts are computed against the reader's clock, so a report opened three months after the audit states what is true then rather than what was true on audit day. There is a test that advances the clock 30 days over one stored row and asserts the sentence changes from "40 days" to "10 days".

The report sentence

Three registers, because a client reads it — expired and near-expiry prompt an action, everything else is context:

  • "The domain registration has EXPIRED… needs renewing immediately to avoid losing it."
  • "The domain is 10 years old and expires in 12 days — renew it now."
  • "The domain is 10 years old, with 551 days left on its registration."

It prints nothing when the lookup was never run or the stored value cannot be trusted. A deliverable should stay silent rather than guess about something the reader may act on.

Verification

  • pnpm ci:check clean; pnpm test green — 307 files, 3098 tests.
  • 6 new tests on the report sentence: never-run, unparseable, healthy, critical, expired, and the clock-advance case.
  • Schema parity test passes (185 assertions).
  • Migration applied and verified on local and prod D1.

Not verified

The rendered card and the printed report line are not browser-verified — proving them end to end needs a completed audit plus a real 5-credit lookup.

🤖 Generated with Claude Code

Adds a nullable domain_expiration_json column to audits (migration 0040,
ALREADY APPLIED to prod D1 ahead of this code -- additive and nullable, so the
running build ignores it).

Populated by an explicit click, NOT during the crawl. Resolving bills 5 APIVerve
credits, and an audit's consent covers crawling; running a third-party lookup
the user never asked for on every audit is exactly the auto-spend this codebase
keeps getting bitten by.

Only the ABSOLUTE dates are stored. Every day count is recomputed against the
reader's clock, which is what lets a report opened three months later say what
is true then rather than what was true on audit day -- there is a test that
advances the clock thirty days over one stored row and asserts the sentence
changes from 40 days to 10.

The report sentence has three registers, because a client reads it: expired and
near-expiry prompt an action, everything else is context. It prints nothing at
all when the lookup was never run or the stored value cannot be trusted -- a
deliverable should stay silent rather than guess about something the reader may
act on.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 20, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
✅ Deployment successful!
View logs
flyrocketseo b0d047e Aug 20 2026, 02:58 PM

Runs against the offline backlinks seed, whose referring domains are synthetic
(source-01.com ...). Looking those up would burn about 145 APIVerve credits to
learn nothing, so the spec deliberately stops short of clicking: it proves the
wiring, the billable-count arithmetic and that the cost is quoted BEFORE any
click, and asserts zero metered requests fire from opening the menu. The fetch
itself is already covered by the live spec and by unit tests.

Needs no API key and no guard, so it runs on every CI run.
Proves the property that makes storing absolute dates worthwhile: a stored
registration renders with ZERO metered requests, and the day counts and status
are derived against the current clock rather than read back from the row.

Seeded directly into local D1 rather than produced by a real crawl -- no audit
run, no credits. Guarded behind AUDIT_EXPIRY_SEEDED=1 because CI has no such
row; verified that it skips without the flag and passes with it.
@ThinkingSpade
ThinkingSpade merged commit f1f1deb into main Aug 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant