Skip to content

Commit d2aa66f

Browse files
committed
docs(sphinx): redirect the pdoc-era URLs and fix the stub's anchor rewriting
The site publishes into one mutable directory: each release's build replaces sdk-docs/python/ wholesale, so a retired layout's pages are deleted rather than kept. sdk-docs' own history is therefore the record of every URL the site has served. Across 63 Python builds it has served 342; 145 resolve today. 197 are dead. 14 are viewcode listings, which redirects cannot cover because they are not Sphinx documents. The other 183 are content pages, and 180 of them come from the pdoc generation (v3.0-v7.0), which named a page after each module path. Two commits did most of the damage, both by adding __all__ to a package __init__: pdoc filters submodules through it, so v5.4.0 deleted the nine pinecone/grpc/* pages and v7.0.0 took the tree from 84 pages to 2. v4 never published docs at all -- the workflow had no caller then -- so its URLs are v3.2.2's, and rebuilding v4.0.0 confirms an identical page set. Targets are not guesses. A page goes to the page its documented symbol lives on today, checked against an index of every anchor in the current build; failing that, to the page for a subject the docs still cover; failing that, to index.html, which is honest about there being no counterpart rather than stranding the reader somewhere plausible-looking. 97 of the 183 land there. The stub template needed three fixes for any of this to work: Its anchor remap was gated on the target starting with the literal "reference/", which is only true for a stub at the docs root. Every entry added here is nested, so the remap would have silently done nothing for all of them. The stub now reads the "../" prefix off its own target and reuses it. The remap mapped renamed classes, but 10.0's change was moving control-plane verbs onto sub-resources, which renames the member too. rest.html's where it does not exist; it is Indexes.create now. One member map covers the sync, asyncio and gRPC clients, which split identically. grpc.html#pineconegrpc forwarded into reference/grpc.html, which stopped documenting PineconeGRPC when it merged into Pinecone -- a redirect landing on a page about something else. That and 20 further section anchors, verified present in the v8 build and mapped to ids verified present in this one, are now in the sections table. check_redirect_anchors.py guards the tables: every page they name must exist, every fragment must be an id on the page it is paired with. This failure mode is invisible otherwise, since the browser loads the page and just does not scroll. It validates the entries present; it cannot know an anchor is missing one it ought to have. published-urls.txt grows by the 183 new stubs via --update, per #655.
1 parent 6547b78 commit d2aa66f

6 files changed

Lines changed: 762 additions & 8 deletions

File tree

‎.github/workflows/on-push.yml‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,9 @@ jobs:
342342
# and deterministic; docs/published-urls.txt is the committed inventory.
343343
- name: Check published docs URLs still resolve
344344
run: uv run --no-sync python scripts/check_docs_urls.py
345+
346+
# A stub that rewrites a fragment to somewhere that no longer exists
347+
# fails silently: the page loads and simply does not scroll. Nothing
348+
# else in the build notices.
349+
- name: Check redirect anchor targets still exist
350+
run: uv run --no-sync python scripts/check_redirect_anchors.py

‎docs/_templates/redirect.html‎

Lines changed: 93 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@
99
(function () {
1010
var target = "${to_uri}";
1111
var hash = window.location.hash;
12+
// A stub sits at whatever depth its old URL had, so its target carries a
13+
// matching "../" prefix. Any page substituted below has to carry the same
14+
// one. Stubs that forward somewhere other than reference/ never rewrite a
15+
// fragment, because only the reference pages carry autodoc anchors.
16+
var into = target.match(/^((?:\.\.\/)*)reference\//);
17+
var prefix = into ? into[1] : "";
1218
// Classes that were renamed or moved to a different page in 10.0. Each row is
1319
// the old autodoc id, the reference/ page the class now lives on, and its new
1420
// id. A hash is either the class id itself or that id followed by ".<member>",
@@ -27,29 +33,108 @@
2733
["pinecone.admin.resources.OrganizationResource", "admin.html", "pinecone.admin.organizations.Organizations"],
2834
["pinecone.admin.resources.ProjectResource", "admin.html", "pinecone.admin.projects.Projects"]
2935
];
30-
// Section anchors the old landing page linked to, which now map to a whole page.
36+
// 10.0 moved the control-plane verbs off the client classes onto sub-resource
37+
// objects, so a rename of the owning class is not enough to place them: the
38+
// member name changed too. The split is identical for the sync, asyncio and
39+
// gRPC clients, so one map serves all three and only the module and the class
40+
// prefix differ. Verbs absent here stayed on the client and need no rewrite.
41+
var verbs = {
42+
"create_index": ["indexes", "create"],
43+
"delete_index": ["indexes", "delete"],
44+
"describe_index": ["indexes", "describe"],
45+
"list_indexes": ["indexes", "list"],
46+
"configure_index": ["indexes", "configure"],
47+
"has_index": ["indexes", "exists"],
48+
"create_index_for_model": ["indexes", "create_for_model"],
49+
"create_backup": ["indexes", "create_backup"],
50+
"describe_backup": ["indexes", "describe_backup"],
51+
"list_backups": ["indexes", "list_backups"],
52+
"delete_backup": ["backups", "delete"],
53+
"create_collection": ["collections", "create"],
54+
"delete_collection": ["collections", "delete"],
55+
"describe_collection": ["collections", "describe"],
56+
"list_collections": ["collections", "list"],
57+
"describe_restore_job": ["restore_jobs", "describe"],
58+
"list_restore_jobs": ["restore_jobs", "list"]
59+
};
60+
var resources = {
61+
"indexes": "Indexes",
62+
"collections": "Collections",
63+
"backups": "Backups",
64+
"restore_jobs": "RestoreJobs"
65+
};
66+
// Old client class, the page it now lives on, its module, and the prefix its
67+
// sub-resource class names take.
68+
var clients = [
69+
["pinecone.Pinecone", "pinecone.html", "pinecone.client", ""],
70+
["pinecone.PineconeAsyncio", "async-pinecone.html", "pinecone.async_client", "Async"],
71+
["pinecone.grpc.PineconeGRPC", "pinecone.html", "pinecone.client", ""]
72+
];
73+
// Section anchors, which autodoc ids cannot cover: a heading that was renamed,
74+
// or one whose content became a page of its own. A value may carry its own
75+
// fragment; without one the reader lands at the top of the named page.
3176
var sections = {
77+
"rest.html#db-control-plane": "pinecone.html",
3278
"rest.html#db-data-plane": "sync-index.html",
79+
"rest.html#vectors": "sync-index.html",
80+
"rest.html#records": "sync-index.html",
81+
"rest.html#namespaces": "sync-index.html",
82+
"rest.html#bulk-import": "sync-index.html",
83+
"rest.html#restore-jobs": "pinecone.html#restorejobs",
84+
"asyncio.html#db-control-plane": "async-pinecone.html",
3385
"asyncio.html#db-data-plane": "async-index.html",
34-
"grpc.html#db-data-plane": "grpc.html"
86+
"asyncio.html#vectors": "async-index.html",
87+
"asyncio.html#records": "async-index.html",
88+
"asyncio.html#namespaces": "async-index.html",
89+
"asyncio.html#bulk-import": "async-index.html",
90+
"asyncio.html#pineconeasyncio": "async-pinecone.html#asyncpinecone",
91+
"asyncio.html#indexes": "async-pinecone.html#asyncindexes",
92+
"asyncio.html#collections": "async-pinecone.html#asynccollections",
93+
"asyncio.html#backups": "async-pinecone.html#asyncbackups",
94+
"asyncio.html#inference": "async-pinecone.html#asyncinference",
95+
"asyncio.html#restore-jobs": "async-pinecone.html#asyncrestorejobs",
96+
// 10.0 folded PineconeGRPC into Pinecone, so the gRPC page documents only
97+
// the index and future classes. Its control-plane anchors belong elsewhere.
98+
"grpc.html#pineconegrpc": "pinecone.html",
99+
"grpc.html#db-control-plane": "pinecone.html",
100+
"grpc.html#indexes": "pinecone.html",
101+
"grpc.html#collections": "pinecone.html",
102+
"grpc.html#backups": "pinecone.html",
103+
"grpc.html#restore-jobs": "pinecone.html#restorejobs",
104+
"grpc.html#db-data-plane": "grpc.html",
105+
"grpc.html#vectors": "grpc.html",
106+
"grpc.html#namespaces": "grpc.html",
107+
"admin.html#admin-api": "admin.html#admin"
35108
};
36109
var page = window.location.pathname.split("/").pop();
37-
var dir = "reference/";
38110
var moved = sections[page + hash];
39111
if (target.indexOf("#") !== -1) {
40112
// The target names its own section; the old fragment has nothing to add.
41113
hash = "";
42114
} else if (moved) {
43-
target = dir + moved;
115+
target = prefix + "reference/" + moved;
44116
hash = "";
45-
} else if (hash && target.indexOf(dir) === 0) {
117+
} else if (hash && into) {
46118
var id = hash.substring(1);
47-
for (var i = 0; i < classes.length; i++) {
119+
var done = false;
120+
// A relocated member is more specific than its class's rename, so it wins.
121+
for (var c = 0; c < clients.length && !done; c++) {
122+
if (id.indexOf(clients[c][0] + ".") === 0) {
123+
var verb = verbs[id.substring(clients[c][0].length + 1)];
124+
if (verb) {
125+
target = prefix + "reference/" + clients[c][1];
126+
hash = "#" + clients[c][2] + "." + verb[0] + "." +
127+
clients[c][3] + resources[verb[0]] + "." + verb[1];
128+
done = true;
129+
}
130+
}
131+
}
132+
for (var i = 0; i < classes.length && !done; i++) {
48133
var oldId = classes[i][0];
49134
if (id === oldId || id.indexOf(oldId + ".") === 0) {
50-
target = dir + classes[i][1];
135+
target = prefix + "reference/" + classes[i][1];
51136
hash = "#" + classes[i][2] + id.substring(oldId.length);
52-
break;
137+
done = true;
53138
}
54139
}
55140
}

0 commit comments

Comments
 (0)