Skip to content

feat: prepare saved documentation editions from pinned releases - #379

Draft
brendanclement wants to merge 15 commits into
mainfrom
brendan/release-records-and-editions-r2
Draft

brendanclement wants to merge 15 commits into
mainfrom
brendan/release-records-and-editions-r2

Conversation

@brendanclement

@brendanclement brendanclement commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

This adds the foundation for versioned docs: a command to save documentation from a release’s exact sources, a record of what built it, and CI checks that keep older editions intact while allowing reviewed corrections. It doesn’t change the live site yet.

Next steps

  • Build the versioned site. Combine those saved editions into one Mintlify site, add product and version selectors, keep links within the selected edition, and explain its sources on an “About this version” page.
  • Review and publish. Put the combined site on staging for human review, then promote that same checked build to production after approval.
  • Automate release preparation. Detect eligible OSS releases and qualified Enterprise releases, then open PRs containing their documentation editions.

Why save each edition in this repository?
Authors continue writing documentation alongside the product code. When we prepare a release’s docs, we save a copy here so Mintlify can serve multiple versions together, and later source changes won’t alter older guides.

The tradeoff is that documentation exists in two places: the source guides for future releases, and saved editions for published releases. We only edit a saved edition when correcting that version’s documentation. For example, fixing an incorrect example. That correction goes through a reviewed PR and is recorded without changing the edition’s original source history. A correction to the source guides won’t automatically update older editions. We deliberately choose which versions need it, rather than rebuilding old docs with content that might describe newer functionality.

The edition builder needs to assemble a site exactly as `make assemble`
does. `assemble_site` runs the stages in order, and `main` now calls it,
so a stage added later reaches both.
`scripts/edition.py prepare` builds one release's edition with the
assembler and saves it under `editions/<product>/<version>/`, with a
release record in `releases/` naming the release and the commit of every
root. Each root is read from Git at its commit, only from its docs folder.

An Enterprise release must be qualified, and its shared pages come from
the LanceDB commit it bundles. An OSS edition names its Enterprise source
explicitly. A saved edition is never replaced: preparing the same release
again changes nothing, even after a correction, and different inputs stop.
A failed preparation saves nothing. `check` pairs records with editions
and requires changed editions to list their corrections.
VERSIONING.md carries the approved design: decisions, components,
records, corrections, planned reader and publication behavior, and the
open questions. The README explains how to prepare and correct an edition,
with a sample record.
A record that lost its docs source, carried a malformed commit or dropped
an Enterprise release's qualification or bundled LanceDB still loaded,
because only a few nested keys were read. Records are now checked against
what `prepare` writes: every release and source field, product-specific
fields, commit and checksum formats, and agreement between each source and
the release field that selected it. Each problem names its record and
field. The check is offline and does not require a tag for a bundled
LanceDB commit.
@brendanclement
brendanclement force-pushed the brendan/release-records-and-editions-r2 branch from 0d6083e to 3ec217e Compare October 20, 2026 19:10
Once a record listed any correction, `check` accepted every later change
to its edition, including an unrelated deleted page. Each correction now
records the checksum of the edition it accepts, and the edition must match
the latest one, or the prepared checksum when there is none. `check`
prints the checksum to record, and the README's correction steps use it.
Preparing a saved release again still keeps the edition and its
corrections.
@brendanclement
brendanclement force-pushed the brendan/release-records-and-editions-r2 branch from 3ec217e to 62675cc Compare October 20, 2026 19:13
`check` compared each edition only with the record beside it, so an
edition rewritten together with its prepared checksum, an earlier
correction edited or removed, or an edition deleted with its record all
passed. `check --base COMMIT` also compares the editions and records on
that commit: each must remain, every record field but `corrections` must
be unchanged, and existing corrections must stay as they were, with new
ones only after them. Records are compared as parsed values, so
formatting does not matter, and new editions are checked as before.

The Assemble workflow's test job runs it offline, without credentials:
a pull request against the base commit its event names, and a push
against the commit the branch pointed at before it, each fetched by
hash. A manual run checks every edition against its record only.
The record named this checkout's HEAD as the source of the docs-owned
pages, assemble.yaml and the assembler. On a pull request's branch that
commit gets a new hash when the branch is squash merged, and a second
edition prepared after the first was committed named the unmerged
edition commit.

`docs/` and assemble.yaml are now read from Git at origin/main, or at an
earlier commit of main named with `--docs`, and that is the commit the
record names. Preparation stops when the commit is not on origin/main,
or when this checkout's scripts/, the assembler that runs, are not that
commit's. Preparing a saved release again is still a no-op that keeps
its corrections.
A short hash of the right commit was reported as a different bundled
LanceDB; `--bundled-lancedb` now asks for the full hash.

Tests now cover guards that had none: a lightweight qualification tag, a
root in assemble.yaml without recorded provenance, Git control files in
an edition and a folder in editions/ that is not a product's. Two test
docstrings describe their cases rather than where the cases came from.
Product pages come from the release commits, and the docs-owned pages,
dataset cards and REST specification from the commit of main that
preparation read; both are fixed when the edition is prepared. The README
gives the updated preparation and correction commands, lists the rules
`check` enforces, including the base comparison the pull request check
runs, and marks the sample record as illustrative. A recreated
qualification tag is described as new evidence rather than a duplicate,
and naming an OSS edition's Enterprise source as pinning, not approving,
it.
Preparation trusted origin/main without knowing where it came from. In
the usual fork layout, origin is the contributor's fork, so a docs-owned
change only on the fork's main reached the edition and its record named
the commit as lancedb/docs.

Preparation now requires origin to be lancedb/docs over HTTPS or SSH,
with URL rewriting applied as fetching applies it, and stops with how to
fix it before fetching or saving anything. It then fetches main from
origin itself and checks the docs input commit against what that fetch
brought, not against a remote-tracking branch fetched earlier. The
ancestry and matching-scripts checks are unchanged, and `check` stays
offline.

Tests stand in for lancedb/docs with a local bare repository that they
accept as its URL; one test checks the real URL forms alone.
The check protects saved editions only if it must pass before a pull
request merges, which is a repository rule set up separately. The check
on a push to main reports a violation in that push but cannot undo it,
and a later push does not find it, because its base already includes the
change. The README, VERSIONING.md and the module docstring now say so.
Preparation fetched lancedb/docs main into refs/remotes/origin/main but
then resolved the shorthand origin/main, which was also the default for
--docs. A local branch or tag named origin/main wins that lookup, so its
unmerged commit passed the ancestry check and went into the edition.

The fetched main is now resolved as refs/remotes/origin/main, and
without --docs preparation uses the commit that fetch returned. A commit
named with --docs is still checked against it.
The CI step fetches its comparison commit with the job's GitHub token;
`edition.py check` itself is offline and needs no Enterprise repository
credentials. Alongside requiring the check before merging, changes to the
checker and its workflow need enforced review, such as required
code-owner review of scripts/, the Makefile and .github/workflows/.

This branch has not been deployed

No deployments
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.

1 participant