This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 3e5c153767f1db0b339db42c97c69e9ba5f92c33
Author: Stephen Mallette <[email protected]>
AuthorDate: Thu Jul 30 11:01:03 2026 -0400

    Point each Markdown docs page at its own version's llms.txt
    
    Pages carried a hardcoded site-root /llms.txt, so a 3.7 page sent agents to
    whichever version published last. MarkdownSplitter now takes --version and
    emits the absolute versioned URL, matching the HTML footer. Stops
    publish-docs.sh from writing a copy of the index to the site root.
    
    Assisted-by: Claude Code:claude-opus-5
---
 bin/process-docs.sh                                | 12 ++---
 bin/publish-docs.sh                                | 11 -----
 .../tinkerpop/tinkeradoc/MarkdownSplitter.java     | 51 ++++++++++++++++++----
 .../tinkerpop/tinkeradoc/MarkdownSplitterTest.java | 22 ++++++++++
 4 files changed, 72 insertions(+), 24 deletions(-)

diff --git a/bin/process-docs.sh b/bin/process-docs.sh
index efeea29986..aa0468bf7f 100755
--- a/bin/process-docs.sh
+++ b/bin/process-docs.sh
@@ -97,6 +97,11 @@ port_open() {
   fi
 }
 
+# Resolve version from pom.xml. Needed by both the dry-run and full-build 
paths (the Markdown split
+# stamps it into each page's llms.txt pointer), so it is resolved before 
either runs.
+TP_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout 
2>/dev/null || \
+  grep -A1 '<artifactId>tinkerpop</artifactId>' pom.xml | grep -o 
'version>[^<]*' | grep -o '>.*' | cut -d '>' -f2 | head -n1)
+
 # ---------------------------------------------------------------------------
 # Markdown split (agentdocsspec.com)
 # ---------------------------------------------------------------------------
@@ -119,7 +124,8 @@ split_markdown() {
   [ -z "${books}" ] && return 0
   echo "Splitting Markdown books into agent-sized pages (summary-driven)..."
   # shellcheck disable=SC2086
-  java -cp "${ext_classes}" org.apache.tinkerpop.tinkeradoc.MarkdownSplitter 
--strict ${books}
+  java -cp "${ext_classes}" org.apache.tinkerpop.tinkeradoc.MarkdownSplitter \
+    --strict --version "${TP_VERSION}" ${books}
 
   # Generate the llms.txt discovery index over the split pages 
(agentdocsspec.com).
   echo "Generating llms.txt discovery index..."
@@ -147,10 +153,6 @@ fi
 # Full build mode
 # ---------------------------------------------------------------------------
 
-# Resolve version from pom.xml
-TP_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout 
2>/dev/null || \
-  grep -A1 '<artifactId>tinkerpop</artifactId>' pom.xml | grep -o 
'version>[^<]*' | grep -o '>.*' | cut -d '>' -f2 | head -n1)
-
 # 1. Validate console distribution
 CONSOLE_DIR=$(ls -d 
gremlin-console/target/apache-tinkerpop-gremlin-console-*-standalone 
2>/dev/null | head -n1)
 if [ -z "${CONSOLE_DIR}" ] || [ ! -d "${CONSOLE_DIR}" ]; then
diff --git a/bin/publish-docs.sh b/bin/publish-docs.sh
index 06639ce989..316ebb76e9 100755
--- a/bin/publish-docs.sh
+++ b/bin/publish-docs.sh
@@ -124,17 +124,6 @@ do
   fi
 done
 
-# Generate the site-root /llms.txt (agentdocsspec.com discovery index) with 
ABSOLUTE links into the
-# versioned docs tree, matching the per-page "> ... see [llms.txt](/llms.txt)" 
pointer. Absolute
-# URLs are required for the spec's link-resolution checks. This index lives at 
the site root; the
-# per-version llms.txt (also absolute now) is published alongside the pages 
via the loop above.
-if [ -d "../docs/markdown" ] && [ -d "${PUBLISH_EXT_CLASSES}" ]; then
-  echo "Generating site-root llms.txt..."
-  java -cp "${PUBLISH_EXT_CLASSES}" 
org.apache.tinkerpop.tinkeradoc.LlmsTxtGenerator \
-    --prefix "${SITE_DOCS_URL}/${VERSION}/" --out llms.txt ../docs/markdown
-  ${SVN_CMD} add --force llms.txt 2>/dev/null || true
-fi
-
 pushd "docs/${VERSION}/"; cat ../../../publish-docs.docs | awk '/^A/ {print 
$2}' | grep -v '.graffle$' | xargs --no-run-if-empty svn add --parents; popd
 pushd "javadocs/${VERSION}/"; cat ../../../publish-docs.javadocs | awk '/^A/ 
{print $2}' | xargs --no-run-if-empty svn add --parents; popd
 pushd "jsdocs/${VERSION}/"; cat ../../../publish-docs.jsdocs | awk '/^A/ 
{print $2}' | xargs --no-run-if-empty svn add --parents; popd
diff --git 
a/docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitter.java
 
b/docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitter.java
index 6eabea91d0..70e284dd37 100644
--- 
a/docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitter.java
+++ 
b/docs/tinkeradoc-extension/src/main/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitter.java
@@ -71,13 +71,28 @@ class MarkdownSplitter {
     private static final Logger LOG = 
Logger.getLogger(MarkdownSplitter.class.getName());
 
     private final int budget;
+    private final String llmsPointer;
 
     MarkdownSplitter() {
         this(DEFAULT_BUDGET);
     }
 
     MarkdownSplitter(final int budget) {
+        this(budget, null);
+    }
+
+    /**
+     * @param version the TinkerPop version these pages are published under, 
used to build the
+     *                per-page index pointer. When {@code null} the pointer 
falls back to the
+     *                site-root {@code /llms.txt}, which is not 
version-correct.
+     */
+    MarkdownSplitter(final int budget, final String version) {
         this.budget = budget;
+        this.llmsPointer = llmsPointer(version);
+        if (version == null || version.isEmpty()) {
+            LOG.warning("No version supplied; pages will point at the 
site-root /llms.txt rather "
+                    + "than this version's index. Pass --version to make the 
pointer version-correct.");
+        }
     }
 
     /**
@@ -124,19 +139,23 @@ class MarkdownSplitter {
     }
 
     /**
-     * CLI entry point: {@code MarkdownSplitter [--budget N] [--strict] 
<book.md> [<book.md> ...]}.
+     * CLI entry point:
+     * {@code MarkdownSplitter [--budget N] [--strict] [--version x.y.z] 
<book.md> [<book.md> ...]}.
      * Each named rendered book file is split in place (summary-driven) into 
pages in its own
      * directory. Pages over the byte budget that are not flagged {@code 
allow-oversize} are reported;
      * with {@code --strict} the process exits non-zero when any such 
violation exists, so the docs
-     * build can gate on it.
+     * build can gate on it. {@code --version} sets the version the per-page 
index pointer resolves to.
      */
     public static void main(final String[] args) throws IOException {
         int budget = DEFAULT_BUDGET;
         boolean strict = false;
+        String version = null;
         final List<String> files = new ArrayList<>();
         for (int i = 0; i < args.length; i++) {
             if ("--budget".equals(args[i]) && i + 1 < args.length) {
                 budget = Integer.parseInt(args[++i]);
+            } else if ("--version".equals(args[i]) && i + 1 < args.length) {
+                version = args[++i];
             } else if ("--strict".equals(args[i])) {
                 strict = true;
             } else {
@@ -144,10 +163,11 @@ class MarkdownSplitter {
             }
         }
         if (files.isEmpty()) {
-            System.err.println("usage: MarkdownSplitter [--budget N] 
[--strict] <book.md> [<book.md> ...]");
+            System.err.println("usage: MarkdownSplitter [--budget N] 
[--strict] [--version x.y.z] "
+                    + "<book.md> [<book.md> ...]");
             System.exit(2);
         }
-        final MarkdownSplitter splitter = new MarkdownSplitter(budget);
+        final MarkdownSplitter splitter = new MarkdownSplitter(budget, 
version);
         final List<String> violations = new ArrayList<>();
         for (final String f : files) {
             final Path p = Path.of(f);
@@ -250,7 +270,7 @@ class MarkdownSplitter {
             final StringBuilder body = new StringBuilder();
             renderPage(plan.owner, body, plan == index, nodeToFile);
             final String rewritten = rewriteLinks(body.toString(), 
plan.fileName, anchorToFile);
-            pages.add(new Page(plan.fileName, LLMS_POINTER + rewritten, 
isAllowOversize(plan.owner)));
+            pages.add(new Page(plan.fileName, llmsPointer + rewritten, 
isAllowOversize(plan.owner)));
         }
         return pages;
     }
@@ -380,12 +400,27 @@ class MarkdownSplitter {
         return null;
     }
 
+    /** Canonical base for the versioned documentation tree. */
+    private static final String DOCS_BASE_URL = 
"https://tinkerpop.apache.org/docs";;
+
     /**
      * The agent-facing directive prepended to every page (agentdocsspec.com 
{@code
-     * llms-txt-directive-md} check): a top-of-page blockquote pointing at the 
site-root index.
+     * llms-txt-directive-md} check): a top-of-page blockquote pointing at 
this version's index.
+     * <p>
+     * The URL is absolute and version-qualified so a page always points at 
the index describing that
+     * same version, mirroring the HTML backend's directive in {@code 
docs/src/docinfo-footer.html}.
+     * A site-root {@code /llms.txt} would instead resolve to whichever 
version published last.
+     * <p>
+     * The version cannot be substituted from the {@code x.y.z} placeholder 
the way the rest of the
+     * Markdown is: {@link MarkdownConverter} does that substitution while 
rendering, and the splitter
+     * runs afterwards as a separate pass over the already-rendered book.
      */
-    static final String LLMS_POINTER =
-            "> For the complete documentation index, see 
[llms.txt](/llms.txt)\n\n";
+    static String llmsPointer(final String version) {
+        final String url = version == null || version.isEmpty()
+                ? "/llms.txt"
+                : DOCS_BASE_URL + "/" + version + "/llms.txt";
+        return "> For the complete documentation index, see [llms.txt](" + url 
+ ")\n\n";
+    }
 
     // ---- parsing -----------------------------------------------------------
 
diff --git 
a/docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitterTest.java
 
b/docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitterTest.java
index f6587e3d1a..9b389413a7 100644
--- 
a/docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitterTest.java
+++ 
b/docs/tinkeradoc-extension/src/test/java/org/apache/tinkerpop/tinkeradoc/MarkdownSplitterTest.java
@@ -224,4 +224,26 @@ public class MarkdownSplitterTest {
         assertThat(body, containsString("```properties"));
         assertThat(body, containsString("After the block."));
     }
+
+    @Test
+    public void everyPagePointsAtItsOwnVersionsIndex() {
+        final String md = "preamble\n\n" + heading("io", 1, "IO Reference") + 
"\nintro\n\n"
+                + summarized("graphson", 1, "GraphSON", "The GraphSON 
format.") + "\nbody\n";
+        final List<MarkdownSplitter.Page> pages = new 
MarkdownSplitter(MarkdownSplitter.DEFAULT_BUDGET, "3.7.7")
+                .split(md, "index.md");
+        // Both the index page and the split-off page carry the directive, and 
it names 3.7.7 rather
+        // than resolving to whichever version published to the site root last.
+        for (final MarkdownSplitter.Page p : pages) {
+            assertThat(p.getContent(), containsString(
+                    "> For the complete documentation index, see "
+                            + 
"[llms.txt](https://tinkerpop.apache.org/docs/3.7.7/llms.txt)"));
+            assertThat(p.getContent(), 
not(containsString("[llms.txt](/llms.txt)")));
+        }
+    }
+
+    @Test
+    public void pointerFallsBackToSiteRootWithoutAVersion() {
+        assertThat(MarkdownSplitter.llmsPointer(null), 
containsString("[llms.txt](/llms.txt)"));
+        assertThat(MarkdownSplitter.llmsPointer(""), 
containsString("[llms.txt](/llms.txt)"));
+    }
 }

Reply via email to