Skip to content

Add per-tool documentation versioning (Latest/Stable/Previous versions) - #14

Merged
bcastets-robotiq merged 6 commits into
mainfrom
Documentation-version
Sep 28, 2026
Merged

bcastets-robotiq merged 6 commits into
mainfrom
Documentation-version

Conversation

@bcastets-robotiq

@bcastets-robotiq bcastets-robotiq commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Each Robotiq-maintained, submodule-synced tool (Tactile Sensor C++/Python, Adaptive grippers C++, Isaac Sim) gets its own Stable / Development (main) / Previous versions switcher, each backed by its own Docusaurus plugin-content-docs instance with content under versioned-tools/ instead of docs/. Stable owns the tool's root URL; Development lives at /next, banner-tagged unreleased and excluded from search (noIndex).
  • The full site navigation tree stays visible on every versioned tool's pages (scripts/site-nav-tree.mjs), using plain encodeURI()-escaped links rather than Docusaurus's pathname:// scheme, which silently opens links in a new tab instead of navigating. Every already-cut version's frozen sidebar snapshot is kept in sync with that tree automatically via scripts/regenerate-versioned-sidebars.mjs, wired into npm run generate.
  • New docs/api-stability.mdx: only a tagged release (Stable) is a compatibility commitment; Development (main) is experimental. Linked from the version banner, docs/intro.mdx, a "Use a released version" admonition on every Development wrapper page, and a short notice injected into every generated API reference page.
  • scripts/sync-external-docs.js cleans up a tool's pre-destRoot legacy output on every sync, so an existing local checkout doesn't end up serving duplicate routes.
  • Adds a node:test unit harness (npm run test:unit, wired into CI before Build) covering the tag-parsing logic, the stale-file pruning logic, the YouTube-embed remark plugin (both .md and .mdx compilation), and a drift guard for the versioned-sidebar snapshots.
  • docs/contribute/ is updated throughout, including a new versioning.mdx walkthrough of the whole mechanism, gotchas, and the manual version-cutting procedure.

Follow-ups (not in this PR, flagged in review)

  • scripts/cut-version.js to automate the manual checkout/sync/version/restore/restore cutting procedure (currently documented, but manual) — would also be the natural place to automate the main→tag source-link rewrite and derive each tool's Stable label from metadata instead of hand-typing it in docusaurus.config.js.
  • Whether Development's own generated API reference should be publicly indexed at all, vs. kept to a preview/internal deploy (noIndex currently covers the main practical risk either way) — open question, not resolved.

Test plan

  • Clean rebuild (npm run build) succeeds with no new broken links/anchors, no duplicate routes
  • npm test and npm run test:unit (33 tests) pass
  • Verified all 3 versions render correctly for every versioned tool, Stable at the root URL and Development at /next
  • Verified the version dropdown appears only on its own tool's pages
  • Verified the full site nav tree renders identically on every versioned page and the main site
  • Verified no sidebar links carry target="_blank" (only genuine external links do)
  • Verified docs/intro.mdx's site-wide tables still list all relocated tools
  • Verified doxygen2docusaurus's generated cross-reference links resolve correctly under /next
  • Verified the experimental notice/admonition renders on Development pages only, never on Stable

🤖 Generated with Claude Code

Each Robotiq-maintained, submodule-synced tool (Tactile Sensor C++/Python,
Adaptive grippers C++, Isaac Sim) now gets its own independent
Latest/Stable/Previous-versions switcher, backed by its own Docusaurus
plugin-content-docs instance with content under versioned-tools/ instead
of docs/. A shared nav-tree module (scripts/site-nav-tree.mjs) keeps the
full site sidebar visible on every versioned page instead of swapping in
an isolated one, using plain encodeURI()-escaped links rather than
Docusaurus's pathname:// scheme (which silently opens links in a new tab).
The version dropdown is scoped to its own tool via a swizzled navbar item,
and the default version banner is shortened to one line.

Also fixes CI's "generated content is committed" check to cover
versioned-tools/ (generate-tools-table.js rewrites wrapper pages there
too) and adds the matching versioned-tools/**/*.md gitignore rule so
synced content isn't accidentally tracked.

docs/contribute/ is updated throughout to document the new architecture,
including a new versioning.mdx walkthrough and a fix for a pre-existing
stale reference to a deleted script.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@mbegin-robotiq mbegin-robotiq left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed the code changes, not the synced or generated doc content, and reproduced #3 and #4 with real npm run build runs. Each inline comment includes a suggested fix and the unit tests I'd add.

Test setup proposal: right now the repo only has the post-build smoke test (npm test runs scripts/check-build.js). All the tests proposed here can use Node's built-in node:test with no new dependency. For example, add "test:unit": "node --test test/" and a npm run test:unit step in ci.yml before the build, since none of them need a build or network access. Some logic needs to move out of the CLI entry points so it can be imported: parseLsRemote from listTags, and pruneStale plus the legacy cleanup from the top-level job loop in sync-external-docs.js.

Unrelated to this PR: every build, including a clean one, warns about a broken anchor. 04-robust-example-walkthrough.md:69 links to 01-environment-setup.md#serial-port-notes, but that heading is ## Serial port settings. The fix belongs in the robotiq/grippers repo.

Comment thread scripts/list-submodule-tags.js Outdated
Comment thread scripts/site-nav-tree.mjs
Comment thread src/remark/youtubeEmbed.mjs Outdated
Comment thread scripts/sync-external-docs.js

@mbegin-robotiq mbegin-robotiq left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving so this can move forward, but the 4 inline comments from my previous review need to be resolved before merging (annotated-tag SHA, frozen site nav in versioned sidebars, YouTube embed breaking .mdx, stale synced files causing duplicate routes).

bcastets-robotiq and others added 2 commits September 25, 2026 14:31
The plugin emitted a raw mdast 'html' node unconditionally. Docusaurus
runs rehype-raw for plain Markdown but not for MDX, so an .mdx page
using the thumbnail-link pattern would fail the build with "Cannot
handle unknown node `raw`" — flagged in review on #11, never actually
fixed before that PR was approved and merged.

Now branches on the file's own extension (available on the vfile
passed to the transformer): .md keeps emitting the raw html node, .mdx
emits an equivalent mdxJsxFlowElement tree instead. Verified against a
throwaway .md and .mdx page using the same pattern — both now render
the identical <div class="video-wrapper"><iframe ...></iframe></div>
output, where before the .mdx one failed to build at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Addresses every inline comment from review, each reproduced before
fixing:

- scripts/list-submodule-tags.js: an annotated tag's SHA was the tag
  object's own SHA, not the commit it points at (git ls-remote emits
  both; the `^{}` peeled line was being dropped instead of preferred).
  A Stable pin or Previous-versions link built from this pointed at
  the wrong object. Parsing logic extracted into a pure `parseLsRemote`
  for testing.

- src/remark/youtubeEmbed.mjs: emitted a raw mdast `html` node
  unconditionally, which Docusaurus can't turn into HTML on an `.mdx`
  page (no rehype-raw there) — would fail any `.mdx` page hitting the
  thumbnail-link pattern with "Cannot handle unknown node `raw`". Now
  emits an `mdxJsxFlowElement` unconditionally instead, which compiles
  correctly for both `.md` (via rehype-raw's own passThrough list) and
  `.mdx` — one node shape, no format branching needed, and no manual
  HTML-escaping either.

- scripts/site-nav-tree.mjs: `buildInstanceSidebar`'s full output gets
  frozen into every cut version's `*_versioned_sidebars/*.json`
  snapshot, so a later change to the shared site nav tree (renamed
  label, moved page, new product) never reached an already-cut
  version. Added `extractActiveItem`/`regenerateInstanceSidebar` plus
  scripts/regenerate-versioned-sidebars.mjs, wired into `npm run
  generate`, so every snapshot is kept in sync automatically and
  ci.yml's existing drift check now covers these files too.

- scripts/sync-external-docs.js: a job that gained `destRoot` (moved
  its output from docs/ to versioned-tools/) left its OLD output under
  docs/drivers/ untouched on a checkout that had already synced
  against an older commit — reproduced as 49 duplicate-route warnings
  on a real build. Added cleanupLegacyDestRoot, run for every destRoot
  job (including the doxygen2docusaurus one), which prunes that legacy
  location on every sync going forward.

Also adds a `node:test`-based unit test harness (`npm run test:unit`,
wired into ci.yml before Build) covering all four fixes plus a
drift-guard regression test for the versioned-sidebar staleness issue.
pruneStale/cleanupLegacyDestRoot moved into scripts/lib/prune.js so
they're importable/testable without running the full sync pipeline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@bcastets-robotiq

Copy link
Copy Markdown
Collaborator Author

All 4 inline findings fixed in 260a153, replied to each individually with what changed and how I verified it. Summary:

  • scripts/list-submodule-tags.js — annotated-tag SHA bug fixed, confirmed against the real robotiq/grippers repo.
  • src/remark/youtubeEmbed.mjs — switched to your suggested unconditional mdxJsxFlowElement, confirmed both .md and .mdx compile and render identically now.
  • scripts/site-nav-tree.mjs — went with your option 2 (regenerate on every npm run generate, CI drift check catches it), with an extraction-based approach so a version's own real content shape is never guessed at.
  • scripts/sync-external-docs.js — legacy destRoot cleanup added, confirmed the exact 49-duplicate-routes repro is gone.

Test setup: adopted as proposed — npm run test:unit (node --test over glob patterns; a bare test/ directory argument turned out to reliably fail on this Windows/Git-Bash setup with a confusing "Cannot find module" error, so I used explicit globs instead, which work the same on both platforms), wired into ci.yml before Build. parseLsRemote and pruneStale/pruneLegacyFolder/cleanupLegacyDestRoot (the latter three now in scripts/lib/prune.js) are exported and covered — 33 tests total across 4 files, including a real @mdx-js/mdx + rehype-raw compile test for the YouTube plugin and a drift guard for the versioned-sidebar snapshots.

Broken anchor — agreed this is out of scope here; the fix belongs in robotiq/grippers (04-robust-example-walkthrough.md's #serial-port-notes link needs to match the actual heading, ## Serial port settings). Left onBrokenAnchors: 'warn' as-is per the existing comment in docusaurus.config.js tracking this.

@ebarnett3 ebarnett3 left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: changes requested (posted as a comment). The versioning mechanism looks solid. The blocking items are inline: the site currently defaults to main, and it needs to steer users to released versions and mark main's API as experimental.

Out of scope for this PR (SDK repos): mark main-only APIs with \since vX.Y / \experimental Doxygen tags (or an experimental namespace), and keep a CHANGELOG "Unreleased" section.

Comment thread docusaurus.config.js Outdated
Comment thread src/theme/DocVersionBanner/index.jsx Outdated
Comment thread versioned-tools/Tactile Sensor/Libraries/Python/index.mdx Outdated
Comment thread tactile-cpp_versioned_docs/version-stable/_readme.md Outdated
Comment thread adaptive-grippers-cpp_versioned_docs/version-stable/_readme.md Outdated
Comment thread docs/contribute/versioning.mdx Outdated
Comment thread versioned-tools/Tactile Sensor/Libraries/Python/index.mdx Outdated
Comment thread docusaurus.config.js
Comment thread docusaurus.config.js Outdated
Comment thread docs/contribute/versioning.mdx
bcastets-robotiq and others added 2 commits September 28, 2026 09:08
Pulls in PR #11 (merged) and two Dependabot submodule bumps
(2f85_cpp, isaacsim_assets) that landed on main since this branch
diverged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

# Conflicts:
#	docs/contribute/how-it-works.mdx
#	src/remark/youtubeEmbed.mjs
Blocking items from review:

- The instance root URL (a bare tool link, search result, or first
  visit) served Development (main) content, not a release — swapped
  the per-tool `versions` config so Stable owns the root path ('') and
  Development moves to '/next', banner-tagged 'unreleased' and marked
  noIndex so it's excluded from search/sitemap. Renamed "Latest" to
  "Development (main)" throughout (Docusaurus's own convention reserves
  "latest" for the newest *release*).
  - Required a follow-on fix: doxygen2docusaurus bakes every internal
    cross-reference as an absolute URL using the plugin's bare
    routeBasePath, with no idea Docusaurus versioning exists. Moving
    Development off the instance root broke every one of those links
    (every API page 404ing on itself) until `currentVersionPath` was
    added to thread that tool's `versions.current.path` through to the
    doxygen2docusaurus job.
- Added docs/api-stability.mdx (only a tagged release is a
  compatibility commitment; main is experimental; the vMAJOR.MINOR.PATCH
  scheme), linked from the version banner, docs/intro.mdx, and a new
  "Use a released version" admonition on Development's own wrapper
  pages. Every doxygen2docusaurus-generated API page also gets a short
  experimental notice injected right after its frontmatter — "where
  users copy code from" per the review.
- Rewrote the version banner to state the actual policy instead of just
  "unreleased".

Other findings fixed:

- Stable snapshots' README/source links pointed at `/tree/main/` and
  `/blob/main/` instead of the tag they're supposed to represent (the
  file at main can already differ from what shipped). Rewrote all 3
  found. Documented the gap: no automation for this yet, has to be
  checked by hand on every cut (see versioning.mdx).
- Wrong img alt text ("2F-85 gripper" on the C++/Python logos, copy-
  pasted boilerplate) across all 6 wrapper/snapshot pages, plus real
  typos ("developped", "the the", "Are below are") in the Tactile
  Sensor wrapper pages.
- Dropped draft/documentation-versioning.md and its summary (.md + .pdf)
  — folded the still-relevant "why this design" rationale into
  versioning.mdx instead of linking out to a design-exploration doc not
  meant to live in this repo. Updated ~15 code-comment references
  across the codebase to point at versioning.mdx instead.
- Reworded 3 passages in versioning.mdx that read as session narrative
  ("the user rejected it on sight", "this exact mistake has happened
  twice already") into neutral rules with rationale.

Not done in this pass (flagged as improvements/discussion, not
blocking, and each is its own real scope):
- A `scripts/cut-version.js` to automate the manual checkout/sync/
  version/restore sequence, and deriving the Stable label from
  metadata written at cut time instead of hand-typing it. The manual
  process is now documented accurately (including the main→tag
  rewrite step this pass added), but still fragile — worth a follow-up.
- Whether Development's own API reference should be publicly indexed
  at all vs. kept to a preview/internal deploy — noIndex now keeps it
  out of search either way; left the publish-or-not question open per
  the review's own "for discussion" framing.

Also merges main (PR #11, two Dependabot bumps) — this branch had
fallen behind.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@bcastets-robotiq

Copy link
Copy Markdown
Collaborator Author

Replied to each of the 12 inline comments individually (fixed in 7e3f1dc). Summary:

Blocking, all fixed:

  • Root URL now serves Stable, not Development (main) — swapped the per-tool versions config (stable: path: '', current: path: 'next'), renamed "Latest" → "Development (main)" site-wide. Required a follow-on fix to sync-external-docs.js (currentVersionPath) since doxygen2docusaurus's absolute cross-reference links needed the new /next segment.
  • New docs/api-stability.mdx policy page, linked from a reworded version banner, docs/intro.mdx, and a new "Use a released version" admonition on every Development wrapper page.
  • Every generated API page now gets a short experimental notice injected right after its frontmatter (injectExperimentalNotice in sync-external-docs.js), not just the section landing page.

Also fixed:

  • 3 Stable snapshots linking to /tree/main///blob/main/ source instead of their own tag, and the Adaptive grippers C++ Stable "GitHub Repository" button pointing at the default branch instead of v1.0.0.
  • Wrong alt="2F-85 gripper" on the C++/Python logos (6 places) and real typos in the Tactile Sensor wrapper pages.
  • Dropped draft/documentation-versioning* (2 .md + the .pdf) — folded the still-relevant design rationale into versioning.mdx.
  • Reworded 3 session-narrative passages in versioning.mdx into neutral rules + rationale.

Deferred, explained in the relevant thread each:

  • A scripts/cut-version.js to automate the manual cut procedure, and deriving the Stable label from metadata instead of hand-typing it — both real, and the right fix is the same piece of tooling, which is its own scope beyond this PR. The manual procedure is now documented accurately (including the main→tag rewrite step), so it's at least correct as a reference until that lands.
  • Whether Development's own API reference should be publicly indexed at all — noIndex already addresses the main practical risk either way; explained the reasoning in the thread, open to revisiting.

Merged main into this branch first (cb869b1) since it had fallen behind — PR #11 merged and two Dependabot bumps landed while this was open.

test:unit failed on CI (ubuntu-latest, Node 20) with "Could not find
'.../test/**/*.test.js'" — node --test's own glob-matching for
positional args, which the local dev environment's Node 24 supports,
isn't available on Node 20. A bare directory argument (node --test
test/, closer to the reviewer's original suggestion) isn't safe either:
it reproducibly fails locally (Windows, Node 24) with an unrelated
"Cannot find module" error, untested on Linux/Node 20.

Replaced both with scripts/run-unit-tests.js: discovers test/*.test.{js,mjs}
via a plain fs.readdirSync and passes the file list to node:test's
programmatic run() API. No CLI glob or directory-argument ambiguity,
works identically regardless of OS or Node version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@bcastets-robotiq

Copy link
Copy Markdown
Collaborator Author

Correction to the test-setup note in my earlier comment: the explicit glob strings ("test/**/*.test.js") I said I'd used instead of a bare test/ directory argument actually broke CI (7e3f1dc) — Node 20 (what CI runs) doesn't support glob patterns as node --test positional args the way Node 24 (my local environment) does; it failed with Could not find '.../test/**/*.test.js', taking the string as a literal path. Fixed in 7846b8b with a small scripts/run-unit-tests.js instead: discovers test/*.test.{js,mjs} with a plain fs.readdirSync and hands the file list to node:test's programmatic run() API, sidestepping both the glob-support gap and the bare-directory-argument issue I originally reported (which does still reproduce locally, separately from the CI failure — untested whether that one is Windows-specific or a Node 24 regression, moot now either way). CI is green.

@bcastets-robotiq
bcastets-robotiq merged commit 72a95a5 into main Sep 28, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants