Skip to content

docs(spec): liveness-ledger follow-through — colorVariant flips live, Field.widget note corrected (#7069) #1333

docs(spec): liveness-ledger follow-through — colorVariant flips live, Field.widget note corrected (#7069)

docs(spec): liveness-ledger follow-through — colorVariant flips live, Field.widget note corrected (#7069) #1333

Workflow file for this run

name: Check Links
# Repo-internal link gate (#6028).
#
# `pull_request` was commented out in a59dc59e (2026-01-28) as a rider on an
# unrelated commit, with no rationale recorded; the gate then sat dormant for
# six months while `lychee.toml` and `fail: true` kept it looking alive.
# Maintainer ruling 2026-08-07: restore the trigger, check REPO-INTERNAL links
# only, and land it advisory-first (NOT in the required set) until it has shown
# a stable green streak.
#
# ⛔ No `merge_group` trigger on purpose: this is an advisory lane, and an
# advisory gate does not get to consume merge-queue capacity. If it is ever
# promoted into the required set, `merge_group` MUST be added in the same
# change or the queue stalls on a required check that never reports (#6121).
on:
workflow_dispatch:
pull_request:
branches:
- main
jobs:
link-checker:
name: Check Documentation Links
runs-on: ubuntu-latest
# Least privilege: the job only reads the tree and runs lychee offline.
# There is no issue-filing step, and `--offline` makes zero network
# requests, so neither `issues: write` nor a GITHUB_TOKEN is needed.
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v7
# ADR cross-link gate (#6592). `docs/adr/` is deliberately NOT added to the
# lychee globs below -- see the ⛔ note there for why -- so the decision
# registry gets its own resolver, in the same advisory lane.
#
# Deliberately `node` and not `pnpm`: the script has zero dependencies, so
# this lane needs no setup-node / corepack / `pnpm install`, and the whole
# advisory job stays a checkout plus two checks. It is also why an author
# can run it locally in any container (`pnpm check:adr-links` when a
# workspace install exists, `node scripts/check-adr-links.mjs` when it does
# not) -- which lychee, installed by the action at CI time, cannot offer.
- name: Check ADR cross-links
run: node scripts/check-adr-links.mjs --self-test && node scripts/check-adr-links.mjs
- name: Check links with lychee
uses: lycheeverse/lychee-action@v2
with:
# `--offline` is the internal-only mechanism, and it lives HERE rather
# than in lychee.toml on purpose: the equivalent `offline = true`
# config key is silently ignored by older lychee (measured: ignored on
# 0.19.1, honoured on the 0.24.2 this action pins). A determinism
# guarantee must not depend on which lychee the action happens to
# install, so it is asserted at the invocation site.
#
# Offline means only `file://` targets are resolved -- every http(s)
# link is reported EXCLUDED, never requested. That is what makes this
# gate deterministic and free of external-network flake.
#
# --root-dir is what makes ROOT-RELATIVE links checkable. Most internal
# links in content/** are site routes (`/docs/permissions`), and lychee
# hard-errors on those unless it is told which directory `/` means.
# The Fumadocs content root is `content/`, so `/docs/x` resolves to
# content/docs/x -- and --fallback-extensions supplies the .mdx/.md
# suffix that a site route omits. Without this pair the gate cannot go
# green at all: 1286 root-relative links fail as "Cannot resolve
# root-relative link ... provide a root dir".
#
# ⛔ Do NOT add `docs/adr/**/*.md` here. It looks like the one-line fix
# for #6592 and it is not: measured on the pinned lychee 0.24.2, that
# glob reports 8 broken links today, every one a pre-existing ADR →
# source-tree link whose target moved out of this repo. This job would
# be red on every PR from the moment it merged, which is how an
# advisory lane becomes a lane nobody reads (#6028 landed it
# advisory-first specifically to earn a green streak). `docs/adr/` is
# checked by the `Check ADR cross-links` step above instead, which can
# freeze those 8 on a shrink-only baseline and fail on a NEW one --
# something neither `exclude` nor `.lycheeignore` can express, because
# neither ever tells you an entry stopped being needed.
# `ARCHITECTURE.md` joined this glob in #6867: unlike `docs/adr/**`, it
# carried no pre-existing rot once its 10 dead links + 2 stale path
# references were fixed in the same PR, so -- unlike the ADR directory
# above -- it needs no KNOWN_DEAD_TARGETS-style baseline to land clean.
args: >-
--offline
--root-dir ${{ github.workspace }}/content
--fallback-extensions mdx,md
--config lychee.toml
'content/**/*.md'
'content/**/*.mdx'
'README.md'
'ARCHITECTURE.md'
# Fail the job if broken links are found
fail: true