Fix broken cross-package Haddock links on hosted docs site
Fixes #601. Cross-package hrefs emitted by cabal haddock-project are
relative paths (e.g. href="../cardano-ledger-api-1.2.3-hash/Foo.html")
that don't resolve on the published site — we only host cardano-api's
own output, not its dependencies, so every cross-package reference
404s by default.
Add scripts/fix-haddock-links.sh and wire it into the github-page
workflow between haddock-project and the artifact upload. The script
replaces each cross-package href with either an absolute URL on the
upstream doc site or a tooltip-annotated unclickable <span>, so the
published site has zero clickable 404s.
Pipeline
Phase 1 Scan filesystem, symlink versioned directories, fetch the
CHaP index, grep HTML for cross-package link targets.
Phase 2 For each discovered target, probe candidate doc-site URLs
and rewrite links (or mark unclickable if unresolvable).
Phase 2b Rewrite local re-export pages to point at the defining
upstream package, using Haddock's "Source" cabal-store link
as ground truth for which package the type lives in.
Phase 3 HEAD-validate rewritten URLs; rescue dead ones by probing
doc-site subdirs (api/, protocols/, framework/) and parent
modules with #t: fragment reconstruction. What can't be
rescued becomes an annotated <span>.
Doc-site resolution for CHaP packages — two lookups, first hit wins:
1. Name-suffix heuristic under *.cardano.intersectmbo.org — strip
trailing '-token' segments of the package name and HEAD-probe
each candidate's doc-index.html. Covers cardano-ledger-*,
plutus-*, ouroboros-*, etc.
2. Fixed fallback against a small IOG_DOC_BASES list — covers
packages whose subdomain isn't a suffix of the package name
(e.g. cardano-base at base.cardano.intersectmbo.org).
Non-CHaP packages (bootlibs like base, bytestring, time) are NOT
linked. Haddock's per-module URL structure doesn't line up cleanly
with Hackage's (src/ source views, -inplace version suffixes) so
Hackage rewrites mostly produce 404s, and readers of cardano-api docs
rarely click into bootlib internals. Rendered as unclickable spans,
no outbound link, no validation noise.
Dead-link CI policy
Actionable (FAILS CI): a CHaP package the probe couldn't resolve to
any doc site. Usually a gap in IOG_DOC_BASES — fix by adding the
package's upstream doc base URL or, if genuinely unpublished, adding
the package to KNOWN_UNDOCUMENTED.
Unfixable (does NOT fail CI, logged for visibility): module-level
404s on otherwise-valid upstream sites where upstream only publishes
umbrella exposed-modules; packages with no published Haddocks
anywhere; absolute Hackage URLs that lack a package version. All
outside this repo to fix.
Escape hatch FIX_HADDOCK_LINKS_ALLOW_DEAD=1 exits 0 even with
actionable entries; under GitHub Actions, actionable entries emit
::warning:: annotations.
Rolling tracking issue
Post-merge workflow failures on master open or comment on a single
rolling issue, tagging the PR opener so the breakage lands on
someone's board instead of going unnoticed. The Deploy step skips on
failure, so the published site stays at its last good revision until
the issue is resolved.
Includes a Herald changelog fragment under .changes/.