Skip to content

fix: preserve fragments in root spec links - #759

Merged
amithanda merged 5 commits into
mainfrom
fix/vertical-doc-fragments
Aug 22, 2026
Merged

fix: preserve fragments in root spec links#759
amithanda merged 5 commits into
mainfrom
fix/vertical-doc-fragments

Conversation

@igrigorik

Copy link
Copy Markdown
Contributor

Follow-up to #723, which moved the specification overview from overview.md to overview/index.md as part of the vertical documentation hierarchy. Root documentation links were rewritten to the versioned specification but for links containing fragments, the rewriter checked for index.md before separating the fragment, so links such as:

/latest/specification/overview/index.md#protocol-version

were left pointing at the generated Markdown source instead of the rendered page:

/latest/specification/overview/#protocol-version

The existing link checker did not catch this because the generated .md file exists and latest/specification paths are otherwise ignored during partial builds.

Changes

  • Separate fragments before normalizing index.md and restore them on the canonical rendered URL.
  • Reject internal links to raw .md files before applying .linkignore patterns.
  • Continue allowing external Markdown links, such as GitHub source files.

Checklist

  • Documentation: Updates to README, or documentations regarding schema or capabilities.
  • I have followed the Contributing Guide
  • I have updated the documentation (if applicable).
  • My changes pass all local linting and formatting checks.

Root-site rewriting left fragments attached to index.md paths, causing links
to serve raw Markdown instead of rendered specification pages.

Normalize the path before restoring its fragment, and reject internal raw
Markdown targets even when version paths are otherwise ignored.
@igrigorik igrigorik added this to the 2026-08-24 milestone Aug 21, 2026
@igrigorik igrigorik self-assigned this Aug 21, 2026
@igrigorik igrigorik added the TC review Ready for TC review label Aug 21, 2026
Comment thread scripts/check_links.py Outdated
@igrigorik
igrigorik requested a review from amithanda August 21, 2026 19:56
@amithanda
amithanda merged commit 9ed9049 into main Aug 22, 2026
18 checks passed
@amithanda
amithanda deleted the fix/vertical-doc-fragments branch August 22, 2026 03:07
Ectsang added a commit to Ectsang/ucp that referenced this pull request Aug 26, 2026
check_links.py decides whether a link is external by matching its scheme
against ("http", "https") plus a four-entry skip list. Anything else falls
through and its path is resolved against the local build, so an off-site
link is reported as a broken internal one:

  //example.com/x          -> "Not Found"   (protocol-relative)
  ftp://example.com/x      -> "Not Found"   (scheme we do not resolve)
  vscode:extension/x       -> "Not Found"   (scheme carrying no host)

Classify by what the URL carries instead: a host, or a scheme we do not
resolve, means off-site. A relative path containing a colon still parses
with no scheme and no host, so it keeps being resolved.

Two adjacent gaps in the same block:

- The raw-Markdown guard added in Universal-Commerce-Protocol#759 compares a case-sensitive suffix,
  so a link to page.MD is accepted while page.md is rejected.
- The path is percent-decoded but the fragment is not, so target/#re%61l
  reports "Anchor not found" against an id of "real".

Also drops the reassignment of `link` after the site-prefix strip. That
value is never read again -- the last read is the startswith() test above
it -- so the removal is behavior-neutral. Called out here rather than left
silent, since it is not required by the fix.

Adds scripts/test_check_links.py, the first tests for this script, on the
same harness as test_validate_examples.py. 30 tests covering off-site
classification, resolution, the raw-Markdown guard, exit codes, .linkignore
precedence and DOCS_MODE=spec. Six fail on unpatched main.

Wires those tests in the same two places the validator tests run, so they
execute rather than sit unused:

- .github/workflows/docs.yml: a "Run link checker unit tests" step beside
  the existing validator step.
- .pre-commit-config.yaml: a check-links-tests hook mirroring
  validate-examples-tests.

No behavior change on the current docs. Built the site locally and diffed
findings between this and main: 0 findings either way, in both DOCS_MODE
values. `pre-commit run --all-files` passes.
Ectsang added a commit to Ectsang/ucp that referenced this pull request Aug 26, 2026
check_links.py decides whether a link is external by matching its scheme
against ("http", "https") plus a short skip list. Anything else falls
through and its path is resolved against the local build, so an off-site
link is reported as a broken internal one:

  //example.com/x          -> "Not Found"   (protocol-relative)
  ftp://example.com/x      -> "Not Found"   (scheme we do not resolve)
  vscode:extension/x       -> "Not Found"   (scheme carrying no host)

Classify by what the URL carries instead: a host, or a scheme we do not
resolve, means off-site. A relative path containing a colon still parses
with no scheme and no host, so it keeps being resolved.

Two adjacent gaps in the same block:

- The raw-Markdown guard added in Universal-Commerce-Protocol#759 compares a case-sensitive suffix,
  so a link to page.MD is accepted while page.md is rejected.
- The path is percent-decoded but the fragment is not, so target/#re%61l
  reports "Anchor not found" against an id of "real".

Also drops the reassignment of `link` after the site-prefix strip. That
value is never read again -- the last read is the startswith() test above
it -- so the removal is behavior-neutral. Called out here rather than left
silent, since it is not required by the fix.

Adds scripts/test_check_links.py, the first tests for this script, on the
same harness as test_validate_examples.py, plus a check-links-tests hook
in .pre-commit-config.yaml mirroring validate-examples-tests.

No CI step is added. Editing .github/workflows/docs.yml makes zizmor scan
it, which surfaces pre-existing unpinned-uses findings unrelated to this
change. Left for a maintainer to decide on separately.

No behavior change on the current docs. Built the site locally and diffed
findings between this and main: 0 findings either way, in both DOCS_MODE
values. `pre-commit run --all-files` passes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

TC review Ready for TC review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants