Fix fabricated API URLs and an upscaled image found in self-review

Three defects in the preceding two commits.

llms.txt generated 47 API URLs for pages that do not exist, from two
wrong assumptions about how Mintlify slugs OpenAPI operations:

- Tags were slugged with underscores collapsed to hyphens. Mintlify uses
  the tag verbatim apart from case and whitespace, and the LangSmith spec
  carries both `annotation-queues` and `annotation_queues` as distinct
  tags rendering to different directories. Collapsing them produced URLs
  for pages that were never generated.
- Operations marked `x-hidden` were emitted. Mintlify renders no page for
  them, which is why every fleet-* endpoint 404'd.

Two smaller slug mismatches: apostrophes were turned into separators
rather than dropped ("user's" gave user-s, not users), and operations
sharing a summary were skipped rather than given the numeric suffix
Mintlify assigns.

Derived API URLs now match the production sitemap exactly: 599 derived,
599 present, 0 fabricated, down from 47 wrong. Re-sampled 45 at random
against production, all 200, and separately confirmed 0 malformed
entries, 0 empty titles, and 0 duplicate URLs across all 2,038 lines.

Separately, vertex-ai-image-example.jpg had been upscaled from its native
602x800 to 770x1024, because `sips -Z` enlarges images smaller than the
target as well as shrinking larger ones. Regenerated at native size: no
invented detail, and smaller on disk (97,695 vs 123,886 bytes).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lauren Hirata Singh
2026-08-13 16:12:43 -07:00
parent 057f646549
commit 4cfe5f5bb6
3 changed files with 103 additions and 7 deletions
+33 -7
View File
@@ -1129,8 +1129,26 @@ class DocumentationBuilder:
@staticmethod
def _slugify(value: str) -> str:
"""Lowercase, hyphenate, and strip a string for use in a URL path."""
return re.sub(r"-+", "-", re.sub(r"[^a-z0-9]+", "-", value.lower())).strip("-")
"""Lowercase, hyphenate, and strip a string for use in a URL path.
Apostrophes are dropped rather than turned into separators, matching
Mintlify: "Get the authenticated user's provider user ID" slugs to
``...-users-provider-user-id``, not ``...-user-s-...``.
"""
cleaned = re.sub(r"[']", "", value.lower())
return re.sub(r"-+", "-", re.sub(r"[^a-z0-9]+", "-", cleaned)).strip("-")
@staticmethod
def _tag_slug(value: str) -> str:
"""Slug an OpenAPI tag the way Mintlify does, preserving underscores.
Mintlify lowercases the tag and replaces whitespace, but otherwise uses
it verbatim. Underscores must survive: the LangSmith spec carries both
``annotation-queues`` and ``annotation_queues`` as distinct tags that
render to different directories, so normalising them together would
point at pages that do not exist.
"""
return re.sub(r"[^a-z0-9_-]+", "-", value.lower()).strip("-")
def _read_frontmatter(self, path: Path) -> dict:
"""Return the YAML frontmatter of an MDX file, or an empty dict."""
@@ -1214,17 +1232,25 @@ class DocumentationBuilder:
for operation in item.values():
if not isinstance(operation, dict) or "responses" not in operation:
continue
# Mintlify renders no page for hidden operations.
if operation.get("x-hidden"):
continue
summary = operation.get("summary") or operation.get("operationId")
if not summary:
continue
tags = operation.get("tags") or ["default"]
slug = (
f"{self._slugify(str(tags[0]))}/{self._slugify(str(summary))}"
f"{self._tag_slug(str(tags[0]))}/{self._slugify(str(summary))}"
)
if slug in seen:
continue
seen.add(slug)
entries.append((label, f"{base}/{slug}", str(summary)))
# Two operations can share a summary. Mintlify keeps both
# and disambiguates with a numeric suffix, so mirror that
# rather than dropping the second page.
unique, duplicate_index = slug, 0
while unique in seen:
duplicate_index += 1
unique = f"{slug}-{duplicate_index}"
seen.add(unique)
entries.append((label, f"{base}/{unique}", str(summary)))
return entries
def _generate_llms_txt(self) -> None:
Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

After

Width:  |  Height:  |  Size: 95 KiB

+70
View File
@@ -5,6 +5,7 @@ covering all methods and edge cases including file extension handling,
directory structure preservation, and error conditions.
"""
import json
from pathlib import Path
import pytest
@@ -704,3 +705,72 @@ def test_build_all_writes_llms_txt() -> None:
# noindex pages and snippets are not real pages, so they stay out.
assert "hidden.md" not in llms_txt
assert "snippets/shared.md" not in llms_txt
def test_tag_slug_preserves_underscores() -> None:
"""Test that OpenAPI tag slugs keep underscores but normalize case and spaces.
The LangSmith spec carries both `annotation-queues` and `annotation_queues`
as distinct tags that Mintlify renders to different directories, so
collapsing them together would generate URLs for pages that do not exist.
"""
slug = DocumentationBuilder._tag_slug
assert slug("annotation_queues") == "annotation_queues"
assert slug("annotation-queues") == "annotation-queues"
assert slug("SCIM Tokens") == "scim-tokens"
assert slug("A2A") == "a2a"
def test_slugify_drops_apostrophes() -> None:
"""Test that apostrophes are removed rather than turned into separators."""
slug = DocumentationBuilder._slugify
assert slug("Get the authenticated user's provider user ID") == (
"get-the-authenticated-users-provider-user-id"
)
assert slug("Get company info") == "get-company-info"
def test_openapi_entries_skip_hidden_and_number_duplicates() -> None:
"""Test that hidden operations are omitted and duplicate slugs get suffixes.
Mintlify renders no page for `x-hidden` operations, and disambiguates two
operations sharing a summary with a numeric suffix instead of dropping one.
"""
spec = {
"paths": {
"/a": {"get": {"tags": ["orgs"], "summary": "Get info", "responses": {}}},
"/b": {"get": {"tags": ["orgs"], "summary": "Get info", "responses": {}}},
"/c": {
"get": {
"tags": ["fleet orgs"],
"summary": "Hidden op",
"responses": {},
"x-hidden": True,
}
},
}
}
docs_json = {
"navigation": {
"pages": [
{
"group": "REST API",
"openapi": {
"source": "langsmith/spec.json",
"directory": "langsmith/api",
},
}
]
}
}
files: list[File] = [
{"path": "docs.json", "content": json.dumps(docs_json)},
{"path": "langsmith/spec.json", "content": json.dumps(spec)},
{"path": "langsmith/page.mdx", "content": "---\ntitle: Page\n---\n\nBody.\n"},
]
with file_system(files) as fs:
builder = DocumentationBuilder(fs.src_dir, fs.build_dir)
builder.build_all()
slugs = [slug for _, slug, _ in builder._openapi_entries()]
assert slugs == ["langsmith/api/orgs/get-info", "langsmith/api/orgs/get-info-1"]