Replace the git-tag-based snapshot model with frozen-directory
snapshots. Each released spec version is its own subtree under
./versions/vX.Y.Z/ — a literal copy of ./src/ taken at release time.
Why: tagging the whole repo conflated *spec content* with *site
infrastructure* (book.toml, theme, picker JS, workflow, build
scripts). Improving any of those required cherry-picking the change
back to every old tag. With directory snapshots, content is frozen
but every deploy renders every version with TODAY's infrastructure
— site fixes propagate everywhere for free.
Changes:
- scripts/build-site.sh now iterates ./versions/v* directories
instead of `git tag --list 'v*'`. Each per-version build sets
MDBOOK_BOOK__SRC to the snapshot dir and MDBOOK_OUTPUT__HTML__SITE_URL
to /meshcore-spec/<version>/. The root book.toml, theme, and
picker JS apply uniformly.
- justfile gains `cut-version vX.Y.Z` — validates the name, refuses
to overwrite, runs `cp -R src versions/<version>`, prints next-
step hints. Cutting a release is now `just cut-version v0.1.0`,
then a commit; optionally tag the commit for provenance, but
tags no longer drive CI.
- .github/workflows/mdbook.yml drops the `tags: ['v*']` trigger
and `fetch-depth: 0` (no longer iterating git history). Triggers
on push to main and PRs.
- src/00-overview.md: "Spec Versions" section rewritten to describe
the directory-snapshot model and the deliberate content-vs-
infrastructure split.
Smoke-tested locally: `just build-site` with no versions/ produces
`_site/{latest/, versions.json=["latest"], index.html}`.
`just cut-version v0.0.1` + rebuild produces both `latest/` and
`v0.0.1/`, versions.json=`["latest","v0.0.1"]`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three intertwined changes — split conceptually but landed together
because they share the same workflow rewrite:
1. MULTI-VERSION SITE. The published site now keeps every prior spec
version alongside the rolling latest build (docs.rs / readthedocs
pattern):
- .github/workflows/mdbook.yml builds latest from current HEAD and
each v* tag in a git worktree, placing each into _site/<ver>/.
Each per-version build gets MDBOOK_OUTPUT__HTML__SITE_URL set to
/meshcore-spec/<ver>/ so the sitemap/canonical links resolve
correctly per version.
- Workflow emits _site/versions.json (newest first) and a root
index.html that redirects to /latest/.
- theme/version-picker.js is a small client-side dropdown that
fetches /<base>/versions.json and lets the reader switch to the
same chapter in any other version. Slots into mdbook's menu bar
(.right-buttons); falls back to a fixed top-right widget if the
menu isn't found.
- theme/version-picker.css styles it to fit the navy theme.
- book.toml wires the picker files via additional-js /
additional-css; site-url defaults to /meshcore-spec/latest/ for
the main build (CI overrides per tag).
- Old tags built without these files render without a picker, which
is fine — users won't typically need to navigate AWAY from an
older version. v0.1.0 onward will all carry the picker.
Spec versions use independent semver and do NOT mirror MeshCore
firmware versions; each spec release records the upstream commit
hash it was validated against in CHANGELOG.md.
2. MISE-PINNED TOOLS. mise.toml pins cargo:mdbook so local dev and
CI use the same version. The workflow installs everything via
jdx/mise-action instead of peaceiris/actions-mdbook, making
mise.toml the single source of truth for tool versions.
3. JUSTFILE. justfile gives short names (build / serve / clean /
validate / setup) for the common tasks. Recipes run under
`mise exec -- sh -c …` so they always pick up the mise-pinned
tools (sh is intentional, keeping recipes POSIX-compatible).
Documentation: README's spec link now mentions the versioning model;
src/00-overview.md gets a "Spec Versions" subsection explaining the
URL layout and version-picker.
Verified locally: `just build` produces a clean book/ with the
version-picker JS/CSS injected (hashed filenames, slotted into
theme/). JS parses clean under `node --check`.
Note for first-time deploy: GitHub Pages source must be set to
"GitHub Actions" in repo settings (one-time, manual). After that,
push to main builds + deploys latest, and pushing a v* tag adds
the snapshot to the site.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The book's first page previously claimed the spec was "the
authoritative definition of the wire format" derived from the
firmware. That misrepresents the project's stance. Replace the
existing "Status" block with a more honest "Status and Provenance"
block that mirrors the README disclosure:
- This is an unofficial, independent project — NOT part of the
upstream MeshCore project, not affiliated, not endorsed.
- Primarily AI-authored (Claude / Opus 4.x) under Stephen Waits's
direction, with human proofreading and editing.
- The upstream MeshCore C++ firmware is the source of truth;
this spec is downstream. CHANGELOG records the upstream commit
hash per pass.
- DongLoRa observations refine the spec but never override
upstream.
- The corpus is a useful signal but not a substitute for
cross-checking against upstream firmware.
Visible to anyone landing on https://swaits.github.io/meshcore-spec/
or reading the rendered overview chapter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Set up the protocol spec as an mdBook and add a GitHub Actions
workflow that builds it on every push/PR and deploys to GitHub
Pages on main. The repo is now both a machine-readable corpus and
a browsable, searchable site.
Structure changes (one-time, mechanical):
- Rename the spec source directory from `spec/` to `src/` to match
mdBook's default convention. All 21 chapter files move; their
internal relative cross-links are unchanged.
- Add `src/SUMMARY.md` as the mdBook table of contents, grouping
chapters under Wire Format, Payloads, Cryptography & Identity,
and Routing & Higher-Layer Protocols.
- Add `book.toml` at repo root: title, author, search enabled,
fold enabled, edit-on-GitHub links, navy theme.
- Add `.github/workflows/mdbook.yml`: build on push + PR, deploy
on push to main only (configure-pages + upload-pages-artifact +
deploy-pages from actions/).
- Add `/book/` to .gitignore.
Reference updates so the old path is fully retired:
- Every `spec_ref` in `corpus/**/*.json` rewritten from `spec/` to
`src/` (54 files).
- Schema description text and example path in
`corpus/schema/test-vector.schema.json`.
- `README.md`: prominent link to the published site near the top;
"What's Here" updated for the new layout.
- `CONTRIBUTING.md`: spec-editing instructions point at `src/`
and note the SUMMARY.md requirement.
- `CLAUDE.md`: directory-layout notes updated.
CHANGELOG.md historical entries intentionally keep their `spec/`
paths since those record what the paths were at the time of those
commits.
After this lands, the user needs to enable GitHub Pages in repo
settings with source = "GitHub Actions" (one-time, manual). The
workflow will then publish to https://swaits.github.io/meshcore-spec/
on every push to main.
Verified locally: `mdbook build` produces a clean book/ tree with
all 21 chapters rendered and the SUMMARY-driven sidebar populated.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>