Skip to content

feat(cli): audit markdown cross-references, including the ones that fail silently - #698

Merged
thevuong merged 1 commit into
mainfrom
feat/cli-audit-links
Aug 7, 2026
Merged

feat(cli): audit markdown cross-references, including the ones that fail silently#698
thevuong merged 1 commit into
mainfrom
feat/cli-audit-links

Conversation

@thevuong

@thevuong thevuong commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Six dead links had accumulated across this repo's documentation before anyone
looked. The class that motivated this is worse, because it is invisible: an
anchor into another document. A wrong #fragment does not 404 — the browser
scrolls to the top, so the link looks like it worked. A stale SPEC §4.8 degrades
the same way, which is how one survived here pointing at a section that never
existed.

codefast audit links reports three shapes:

Breakage Why it needs a machine
relative path does not exist visible, but only if someone clicks
in-document anchor with no heading / <a id> silent scroll
cross-document anchor the target does not offer silent scroll, and no single file is wrong

External URLs are skipped as somebody else's to verify. So are links inside fenced
code — those are examples, and checking them would fail the audit on documentation
that is doing its job.

It defaults to the repo root rather than a configured target: a scan scoped to
one package cannot see the cross-package references, which are exactly the ones
most likely to rot. It runs in the packages gate, so a link that rots is a red
build rather than a discovery months later.

Verification

pnpm --filter @codefast/cli test:unit && pnpm --filter @codefast/cli check-types
pnpm cli:audit:links
  • 55 unit tests pass (12 new), check-types clean, lint --deny-warnings and format:check clean.
  • On this repo: ✓ 233 repo-local link(s) across 152 document(s) all resolve.
  • pnpm cli:mirror leaves no diff, so the CI exports check stays green.

Seeded before trusted

A clean result from a checker nobody has made fail is worth nothing, so all three
breakage shapes were seeded into a real file in this repo:

SEED-AUDIT.md
  3: ./no-such-file.md → path does not exist
  4: #not-a-heading-here → anchor not found in this document
  5: packages/di/SPEC.md#no-such-anchor → anchor not found in SPEC.md

✖ 3 broken link(s)   (exit 1)

The three valid controls sitting beside them in the same file — a good
cross-document anchor, a good local anchor, and an external URL — stayed
unflagged, along with a link inside a fenced block.

One assertion I got wrong on the first run is worth noting: I expected linkCount: 3
for a document with three links, one of them external. The count is repo-local
references, so 2 was correct — but the presenter said "N link(s) all resolve", which
overclaims. It now says "repo-local link(s)".

Design

The extraction is pure and lives in domain/markdown-links.ts, so the rules are
testable with no filesystem; existence checks and the per-document anchor cache sit
in run-links.ts. That follows the boundary ARCHITECTURE.md already states for
this package.

Checklist

  • Changeset added — minor, never major while on 0.x
  • Tests under tests/unit/** mirroring the src/ path (audit/domain/, audit/)
  • No hand-written @since tags — new exports carry none; codefast tag stamps them at release
  • Comments state the why in three lines or fewer, no numbers, no history
  • package.json#exports@codefast/cli is false in the mirror config, and pnpm cli:mirror confirms no diff
  • New public API audited against the naming rubric: audit links mirrors audit rtl, and the result/prelude types follow the existing Rtl* shapes

…ail silently

Six dead links had accumulated across this repo's documentation before anyone
looked, and the class that motivated this was invisible: an anchor into another
document. A wrong `#fragment` does not 404 — the browser scrolls to the top, so
the link looks like it worked. A stale section number degrades the same way.

`codefast audit links` reports three shapes: a relative path that does not
exist, an in-document anchor with no matching heading or `<a id>`, and a
cross-document anchor the target does not offer. External URLs are skipped as
somebody else's to verify; so are links inside fenced code, which are examples
rather than references — checking those would fail the audit on documentation
doing its job.

It defaults to the repo root rather than a configured target: a scan scoped to
one package cannot see cross-package references, which are the ones most likely
to rot. It gates CI, so a link that rots is a red build.

The extraction is pure and lives in `domain/`, so the rules are testable without
a filesystem; existence checks and the per-document anchor cache sit in the run
layer. All three breakage shapes were seeded against the real repo before the
green result was trusted, and the three valid controls beside them — a good
cross-document anchor, a good local one, an external URL — stayed unflagged.
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
codefast-tanstack-start Ready Ready Preview Aug 7, 2026 3:01pm
codefastlabs Building Building Preview Aug 7, 2026 3:01pm

@thevuong
thevuong enabled auto-merge August 7, 2026 15:01
@thevuong
thevuong merged commit cce37d8 into main Aug 7, 2026
9 checks passed
@thevuong
thevuong deleted the feat/cli-audit-links branch August 7, 2026 15:03
@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 63.35878% with 48 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/cli/src/audit/command.ts 0.00% 16 Missing ⚠️
packages/cli/src/audit/prepare.ts 0.00% 12 Missing ⚠️
packages/cli/src/audit/output.ts 0.00% 10 Missing ⚠️
packages/cli/src/audit/domain/markdown-links.ts 89.65% 2 Missing and 1 partial ⚠️
packages/cli/src/audit/run-links.ts 93.87% 2 Missing and 1 partial ⚠️
packages/cli/src/core/workspace/markdown-walk.ts 76.92% 1 Missing and 2 partials ⚠️
packages/cli/src/audit/cli-schema.ts 0.00% 1 Missing ⚠️
Files with missing lines Coverage Δ
packages/cli/src/core/config/schema.ts 90.90% <100.00%> (+0.90%) ⬆️
packages/cli/src/audit/cli-schema.ts 0.00% <0.00%> (ø)
packages/cli/src/audit/domain/markdown-links.ts 89.65% <89.65%> (ø)
packages/cli/src/audit/run-links.ts 93.87% <93.87%> (ø)
packages/cli/src/core/workspace/markdown-walk.ts 76.92% <76.92%> (ø)
packages/cli/src/audit/output.ts 0.00% <0.00%> (ø)
packages/cli/src/audit/prepare.ts 0.00% <0.00%> (ø)
packages/cli/src/audit/command.ts 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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