Catch IPv6 breaking after a deploy

A few lines in your pipeline. It fails when your site's IPv6 grade drops below what you set, prints why, and retries — instead of failing — when something couldn't be checked.

url="https://aaaa.bot/check/example.com?min=C"
for i in 1 2 3 4; do
  rm -f aaaa.txt
  code=$(curl -sS -o aaaa.txt -w '%{http_code}' "$url") || code=000
  cat aaaa.txt 2>/dev/null || true; echo
  case "$code" in
    200) exit 0 ;;                       # meets the minimum
    422) exit 1 ;;                       # confirmed below the minimum
    *)   sleep 30 ;;                     # 503 couldn't check, 429 busy, network error: try again
  esac
done
echo "IPv6 check inconclusive after 4 tries — not failing the build."

Quick version, if you don't mind a rare false alarm when a check can't complete: curl -sS --fail-with-body --retry 3 --retry-delay 30 "https://aaaa.bot/check/example.com?min=C"

What it answers

200PASS example.com: grade A (minimum C) — …
422FAIL example.com: grade D (minimum C) — … plus the first fix
503UNKNOWN … — we couldn't complete the check. The script above retries, then lets the build pass rather than blame you for our gap.

min is the lowest grade you accept: C (the default) means "the website answers over IPv6", B allows one gap, A means website, mail and DNS all on IPv6. How grades work. Every answer links to a saved evidence record.

GitHub Actions

Save as .github/workflows/ipv6.yml and change the domain:

name: IPv6
on:
  deployment_status:        # after each deploy (Vercel, Netlify and others report these)
  schedule:
    - cron: "17 6 * * 1"     # and every Monday
  workflow_dispatch:
jobs:
  ipv6:
    if: github.event_name != 'deployment_status' || github.event.deployment_status.state == 'success'
    runs-on: ubuntu-latest
    steps:
      - name: Check IPv6
        run: |
          url="https://aaaa.bot/check/example.com?min=C"
          for i in 1 2 3 4; do
            rm -f aaaa.txt
            code=$(curl -sS -o aaaa.txt -w '%{http_code}' "$url") || code=000
            cat aaaa.txt 2>/dev/null || true; echo
            case "$code" in
              200) exit 0 ;;                       # meets the minimum
              422) exit 1 ;;                       # confirmed below the minimum
              *)   sleep 30 ;;                     # 503 couldn't check, 429 busy, network error: try again
            esac
          done
          echo "IPv6 check inconclusive after 4 tries — not failing the build."

Checks run from aaaa.bot's server, not from your runner, so they work on any CI — GitLab, CircleCI, a cron job. The limit is 30 domain checks a minute per IP; the script retries the rare 429.

JSON

curl -s -H "accept: application/json" "https://aaaa.bot/check/example.com?min=B"
{"pass":true,"grade":"A","min":"B","status":200,"receiptId":"…","text":"PASS …"}