# =============================================================================
# Shared Lychee ignore patterns (Tier 2 / Tier 3 link checking)
# =============================================================================
# Patterns are anchored regexes per Lychee's --exclude-file format.
# Anything matching a pattern below is silently skipped.
#
# Per-site overrides:
#   If a subsite needs to skip URLs that don't apply to other sites, create
#   <site>/.lycheeignore and pass `lycheeignore_path: <site>/.lycheeignore`
#   to infra-link-check.yml. The book site keeps its existing canonical file
#   at book/config/linting/.lycheeignore (do not duplicate those patterns
#   here — that file remains authoritative for book content).
# =============================================================================

# --- Localhost / private network (per-site authors often paste these) ---
^https?://localhost(:\d+)?(/.*)?$
^https?://127\.0\.0\.1(:\d+)?(/.*)?$
^https?://192\.168\.\d+\.\d+(:\d+)?(/.*)?$
^https?://10\.\d+\.\d+\.\d+(:\d+)?(/.*)?$

# --- Slide decks behind Google auth (return 200 to logged-in users only) ---
^https://docs\.google\.com/presentation/

# --- Known transient 404s (re-add once content is restored) ---
^https://www\.reuters\.com/?$

# --- Live preview targets that only exist post-deploy ---
# (Avoid Lychee chasing the very URL we're about to publish to.)
^https://harvard-edge\.github\.io/cs249r_book_dev/
^https://mlsysbook\.ai/

# --- SPA routes that use # for client-side routing (not document anchors) ---
# Lychee treats anything after # as a fragment to verify, but for these
# single-page-apps the # is part of the URL semantics. Skip fragment check.
^https://star-history\.com/#

# --- Unrendered JS template literals (false positives) ---
# When Lychee parses a .qmd that contains JavaScript using template literals
# like `https://github.com/${m.github}`, the template literal is URL-encoded
# in the AST as `$%7B…%7D` and reported as a broken URL. The literal is
# substituted at runtime with the actual value, so it is never a real URL.
# Pattern matches any `${ANY.ANY}` template literal residue.
^https?://[^/]+/[^?#\s]*\$%7B[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*%7D

# --- GitHub avatar URLs (lychee unreliably HEADs them) ---
# `https://github.com/<user>.png(?size=N)?` returns 200 in browsers but lychee
# regularly returns 4xx/timeout against them due to GitHub's HEAD throttling
# for unauthenticated avatar requests. Manually verified: every avatar URL
# flagged by the link-rot tracker is reachable in a browser.
^https://github\.com/[A-Za-z0-9][A-Za-z0-9-]*\.png(\?size=\d+)?$

# =============================================================================
# Anti-bot false positives — sites that block HEAD/GET from non-browser agents
# =============================================================================
# Each entry below was manually verified live in a browser but flagged by
# Lychee due to bot-detection or aggressive HTTP HEAD response codes
# (999, 403, 503, transient 5xx). These are NOT broken — they're guaranteed
# false positives that produce permanent tracker noise.

# LinkedIn — always returns 999 to non-browser clients (anti-scraping).
^https?://(www\.)?linkedin\.com/

# X / Twitter — Cloudflare bot challenge for unauthenticated requests.
^https?://(www\.)?(twitter|x)\.com/

# Harvard SEAS faculty/people pages — university CDN blocks bots.
^https?://[a-z0-9.-]+\.harvard\.edu/people/

# Edge AI Foundation — verified live; intermittent 5xx to lychee.
^https?://(www\.)?edgeaifoundation\.org/

# discuss.tinymlx.org — Discourse forum; 403 to bot HEAD requests.
^https?://discuss\.tinymlx\.org/

# edX certification pages — slow/throttled responses to lychee, real in browser.
^https?://(www\.)?edx\.org/(professional-certificate|course)/

# mpstewart.net — personal site that 302-redirects in ways lychee mishandles.
^https?://(www\.)?mpstewart\.net/

# Personal blog domains commonly cited in slides that block bot HEAD requests.
^https?://[a-z0-9.-]+\.medium\.com/
^https?://towardsdatascience\.com/

# Forbes/Reuters/WSJ — paywall/anti-bot frequently flagged by lychee.
^https?://(www\.)?forbes\.com/
^https?://(www\.)?wsj\.com/
^https?://(www\.)?reuters\.com/

# StackOverflow / SE-network — Cloudflare bot challenge on raw URLs.
^https?://(www\.)?stackoverflow\.com/
^https?://[a-z]+\.stackexchange\.com/

# YouTube channels (URL form `/c/` or `/channel/` or `/@handle`) — sometimes
# return 4xx to HEAD even for live channels.
^https?://(www\.)?youtube\.com/(c|channel|@)/

# =============================================================================
# Round 2 — additional false positives surfaced by 2026-04-26 workflow run
# =============================================================================

# tinyMLx/courseware/raw — every URL we reference here was validated against
# the upstream Contents API; the 6 genuinely-broken targets were repaired in
# PR #1553. The remaining 319 references all return 200 to a browser, but
# Lychee's HEAD requests against github.com/.../raw/master/... are
# inconsistent (rate-limited / 4xx). Suppress wholesale.
^https?://github\.com/tinyMLx/courseware/raw/master/edX/

# GitHub Issues "/new" pages — always live (it's a form submission target),
# but Lychee gets confused by the parameterized template= variants.
^https?://github\.com/[^/]+/[^/]+/issues/new

# GitHub Releases asset downloads — Cloudflare's HEAD response for these
# asset URLs is unreliable, but GET works for end users in browser.
^https?://github\.com/[^/]+/[^/]+/releases/download/

# Personal blog: Laurence Moroney (Google Brain TensorFlow lead).
^https?://(www\.)?laurencemoroney\.com/
