Do not link to undocumented helpers from @noRd blocks

devtools::document() reported six links it could not resolve, all of them
pointing from one @noRd block to another: a function marked @noRd has no
topic to link to. They are plain code spans now. Links to
queryStringToLabel() stay as they are: that one is exported and does have
a topic.

Nothing catches this by itself, which is why it went unnoticed for a
week. The links never reach a manual page - no Rd file changes when they
go - so R CMD check is silent and comparing the generated files finds
nothing either. And roxygen2 reports them as messages rather than
warnings, so they scroll past. A workflow of its own now documents the
package and looks for that message, failing when it appears. Verified
both ways: it passes as things stand and fails once a link is put back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Change-Id: Ifb5795ba2058c2f5a3b8d660a1d61f127ad82599
diff --git a/.github/workflows/document.yaml b/.github/workflows/document.yaml
new file mode 100644
index 0000000..6c5bddc
--- /dev/null
+++ b/.github/workflows/document.yaml
@@ -0,0 +1,63 @@
+# Rebuilds the documentation and fails on links roxygen2 cannot resolve.
+#
+# Those arise from linking to a function marked @noRd, which has no topic to
+# link to. They never reach a manual page, so R CMD check says nothing and a
+# comparison of the generated files finds nothing either - the only trace is a
+# message while documenting, which is easy to miss.
+on:
+  push:
+    branches: [main, master]
+    paths:
+      - 'R/**'
+      - 'man/**'
+      - 'NAMESPACE'
+      - 'DESCRIPTION'
+      - '.github/workflows/document.yaml'
+  pull_request:
+    branches: [main, master]
+
+name: document
+
+jobs:
+  document:
+    runs-on: ubuntu-latest
+
+    env:
+      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
+
+    steps:
+      - uses: actions/checkout@v3
+
+      - uses: r-lib/actions/setup-r@v2
+        with:
+          use-public-rspm: true
+
+      - uses: r-lib/actions/setup-r-dependencies@v2
+        with:
+          extra-packages: any::roxygen2
+
+      - name: Document, and refuse links that do not resolve
+        shell: Rscript {0}
+        run: |
+          messages <- character()
+          withCallingHandlers(
+            roxygen2::roxygenise(),
+            message = function(m) {
+              messages <<- c(messages, conditionMessage(m))
+              invokeRestart("muffleMessage")
+            }
+          )
+          cat(messages, sep = "")
+
+          # reported as a message rather than a warning, so it has to be looked for
+          unresolved <- grep("Could not resolve link", messages, value = TRUE)
+          if (length(unresolved) > 0) {
+            stop(
+              sprintf(
+                "roxygen2 could not resolve %d link%s. A function marked @noRd has no topic to link to; write it as `code` instead.",
+                length(unresolved),
+                if (length(unresolved) == 1) "" else "s"
+              ),
+              call. = FALSE
+            )
+          }