From 3747ed02e382421a187d33b352b2a99703b2fc24 Mon Sep 17 00:00:00 2001 From: sotashimozono Date: Sat, 5 Sep 2026 09:07:33 +0000 Subject: [PATCH] docs: placeholder URLs that cannot resolve, instead of ones that 404 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #20. Measured: https://github.com/org/Pkg.jl/issues/12 404 resolves, and fails https://github.com/org/MyPackage.jl/issues/12 404 https://example.invalid/issues/12 000 does not resolve, by design The first two reach GitHub and come back 404, so a reviewer running a link checker sees two dead links — which is the finding that opened the review of another package in this organisation. `example.invalid` is reserved by RFC 2606 and cannot resolve, which is what a placeholder should look like. The package's own tests already used it; six sites in `docs/src` and `src` did not. The lint that keeps it that way does not use the network — a check that asks for a response would be a flake generator across three runners. The property is the host: a URL inside a fenced julia block must be under a reserved example domain or on a host this organisation owns. Verified by restoring one of the old URLs and watching it fail, naming the file and the URL. Suite: 1022 passed. Co-Authored-By: Claude Opus 5 --- docs/src/declaring.md | 2 +- docs/src/releases.md | 4 ++-- src/lifecycle.jl | 2 +- src/query.jl | 2 +- src/release.jl | 2 +- test/test_readme.jl | 45 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 6 deletions(-) diff --git a/docs/src/declaring.md b/docs/src/declaring.md index b1bd796..d8a77c6 100644 --- a/docs/src/declaring.md +++ b/docs/src/declaring.md @@ -51,7 +51,7 @@ Archeion.ingest — experimental ```julia @experimental("export format is a guess until someone consumes it", since = v"0.4.0", - tracking = "https://github.com/org/Pkg.jl/issues/12", + tracking = "https://example.invalid/issues/12", registry_entry(x) = x) ``` diff --git a/docs/src/releases.md b/docs/src/releases.md index 3a9742f..d5d770a 100644 --- a/docs/src/releases.md +++ b/docs/src/releases.md @@ -22,7 +22,7 @@ stable = ["adapt", "measure"] [experimental.render_report] reason = "reads Test's internal result tree" -tracking = "https://github.com/org/MyPackage.jl/issues/12" +tracking = "https://example.invalid/issues/12" ``` On the next release, compare: @@ -96,7 +96,7 @@ A mark that can only ever be added is a decoration. `until=` is what makes it a @experimental( "no reference value yet", since = v"0.1.0", - tracking = "https://github.com/org/Pkg.jl/issues/12", + tracking = "https://example.invalid/issues/12", until = () -> isfile(joinpath(@__DIR__, "..", "test", "refs", "energy.toml")), energy(β) = 2β, ) diff --git a/src/lifecycle.jl b/src/lifecycle.jl index e05d0d4..ea33e88 100644 --- a/src/lifecycle.jl +++ b/src/lifecycle.jl @@ -17,7 +17,7 @@ Not "is this marked" but "may this stop being marked", answered by the thing tha @experimental( "no reference value yet", since = v"0.1.0", - tracking = "https://github.com/org/Pkg.jl/issues/12", + tracking = "https://example.invalid/issues/12", until = () -> isfile(joinpath(@__DIR__, "..", "test", "refs", "energy.toml")), energy(β) = 2β, ) diff --git a/src/query.jl b/src/query.jl index 3ce4332..907b15f 100644 --- a/src/query.jl +++ b/src/query.jl @@ -260,7 +260,7 @@ same way. mark_method!( which(fetch_value, Tuple{Heisenberg,Energy}), "numerically delicate; no reference value"; - tracking = "https://github.com/org/Pkg.jl/issues/12", + tracking = "https://example.invalid/issues/12", ) ``` diff --git a/src/release.jl b/src/release.jl index ae2a3b9..8f41b94 100644 --- a/src/release.jl +++ b/src/release.jl @@ -28,7 +28,7 @@ stable_methods = ["adapt(::Model, ::Grid)", "measure(::Model)"] [experimental.render_report] reason = "reads Test's internal result tree" -tracking = "https://github.com/org/MyPackage.jl/issues/12" +tracking = "https://example.invalid/issues/12" [experimental_methods."fetch_value(::Heisenberg, ::Energy)"] reason = "numerically delicate; no reference value" diff --git a/test/test_readme.jl b/test/test_readme.jl index a5cfd5e..a7dbde4 100644 --- a/test/test_readme.jl +++ b/test/test_readme.jl @@ -219,3 +219,48 @@ end # turning it back into an inert ```julia fence is caught here. @test occursin("```@example", read(joinpath(_DOCS, "index.md"), String)) end + +# ── URLs inside examples ───────────────────────────────────────────────────────────────────── +# +# A placeholder URL must not look like a real address that fails. `github.com/org/Pkg.jl/issues/12` +# resolved to GitHub and returned **404**, so a reviewer running a link checker saw a dead link — +# which is the finding that opened the review of another package in this organisation. +# `example.invalid` cannot resolve at all (RFC 2606 reserves it), which is what a placeholder +# should look like. Checked without the network: the property is the host, not the response. + +const _RESERVED_HOSTS = ["example.com", "example.net", "example.org", "example.invalid"] +const _OWN_HOSTS = ["github.com/QAtlasHub/", "qatlashub.github.io/"] + +"Every URL inside a fenced julia block, across the README and `docs/src`." +function example_urls() + out = Tuple{String,String}[] + files = vcat([joinpath(@__DIR__, "..", "README.md")], sort(readdir(_DOCS; join=true))) + for f in files + endswith(f, ".md") || continue + for m in eachmatch(r"`{3,}julia\r?\n(.*?)`{3,}"s, read(f, String)) + for u in eachmatch(r"https?://[^\s\"')]+", m.captures[1]) + push!(out, (basename(f), u.match)) + end + end + end + return out +end + +@testset "a URL in an example is a reserved placeholder or a host we own" begin + urls = example_urls() + @test !isempty(urls) # non-vacuity: the scan finds URLs at all + bad = [ + "$f: $u" for (f, u) in urls if + !any(h -> occursin(h, u), _RESERVED_HOSTS) && !any(h -> occursin(h, u), _OWN_HOSTS) + ] + @test bad == String[] +end + +@testset "…and the check can see one" begin + # Control: `github.com/org/…` is the shape that shipped, and it must not be accepted. + u = "https://github.com/org/Pkg.jl/issues/12" + @test !any(h -> occursin(h, u), _RESERVED_HOSTS) + @test !any(h -> occursin(h, u), _OWN_HOSTS) + # …while the replacement is. + @test any(h -> occursin(h, "https://example.invalid/issues/12"), _RESERVED_HOSTS) +end