Files
Vijay Janapa Reddi 4328ff2bdd fix(navbar+release-pill): three post-deploy regressions
1) release-pill.html: nested HTML comment broke every Quarto site that
   included it via include-after-body. The Pattern B documentation
   block contained a literal `<!-- in footer -->` inside the outer
   `<!-- ... -->` doctring; HTML disallows nested comments, so the
   inner `-->` terminated the outer comment early and the example
   markup that followed (`<span data-release-pill>` and
   `<script src="/release-pill.js">`) leaked into the rendered page —
   producing a 404 on every page that fetched the script. Replaced
   with a `// in footer:` pseudo-comment and added a NOTE warning.

2) shared/_navbar.scss: dim the SEAS shield in dark mode. The logo
   asset is transparent-bg, but the white "VE RI TAS" books area at
   the top of the crest read as a bright square against the dark
   navbar. `filter: brightness(0.85) contrast(1.05)` softens the
   crest without losing the crimson. Targets both `body.quarto-dark`
   (Quarto's class) and `[data-bs-theme="dark"]` (Bootstrap 5+).

3) EcosystemBar.tsx: mirror Quarto's brand-title abbreviation.
   StaffML was always rendering the full "Machine Learning Systems"
   string with CSS ellipsis, so narrow viewports ellipsis-truncated
   it mid-word — visually distinct from every Quarto site, which
   swap to a clean "ML Systems" via the
   `_mobile.scss @media (max-width: 1199px)` rule. Added an
   `nav-xl:hidden` / `nav-xl:inline` pair (with an `sr-only` full
   string for screen readers) so the abbreviation behaves
   identically to Quarto on the same screen widths.
2026-04-29 07:14:11 -04:00
..

Shared release infrastructure

Single source of truth for "what release is this?" across every publishable artifact in the MLSysBook monorepo. Mirrors and generalizes the StaffML pattern landed in feat/staffml-version. See docs/VERSIONING.md for contributor-facing usage; this file is for operators and downstream projects that need to know the contract.


What's here

File Purpose
release-pill.html Footer snippet — small "v0.1.0 · Apr 26" identity pill
release-card.html About-page snippet — fuller release-identity card with copyable hash
README.md This file

The Python helpers and JSON schema live at the repo root under scripts/version/ so they can be invoked from any workflow without relative-path gymnastics:

Path Purpose
scripts/version/release.py CLI: compute-id, compute-hash, emit-release, emit-manifest
scripts/version/schema.json JSON Schema for releases/<id>/release.json

The reusable GitHub Actions workflow lives where workflows live:

Path Purpose
.github/workflows/_release-publish.yml workflow_call — orchestrates bump + tag + release notes

Contract

Every project that adopts the pattern produces TWO build-time artifacts on every publish:

  1. releases/<project>-<release_id>/release.json — the canonical, commit-ready release artifact. Validates against scripts/version/schema.json. Contains release_id, release_hash (full hex digest over input bytes), git_sha, created_at, input_paths, and a metadata object with project-specific stats. Tier A also includes a files: [{path, hash}, ...] array (Merkle-ish per-file hashes) for partial verification.

  2. <deployable>/release-manifest.json — the build-time projection the deployable bundles. Strict subset: releaseId, releaseHash, schemaVersion, tier, project, buildDate, plus a metadata object. Static sites deploy this at the site root; the footer pill fetches it via <meta name="release-manifest" content="...">.

A project's site may extend (1) and (2) with project-specific keys (StaffML's vault-manifest.json adds questionCount, trackDistribution, etc.) — but those keys live in metadata, never at the top level.

Tiers

  • Tier A (citable): full Merkle-style file index in release.json. Use for academically-cited content (paper hashes, textbook releases, StaffML question bank, TinyTorch framework releases).
  • Tier B (lite): single SHA-256 over content directory; no per-file index. Use for rapidly-iterating content where citation isn't a primary concern (Kits, Labs, Instructors).

Each Quarto project does ~3 lines of config. Example for a project deployed at https://mlsysbook.ai/<project-base>/:

# _quarto.yml
project:
  resources:
    - "../shared/release/release-pill.html"

format:
  html:
    include-in-header:
      - text: |
          <meta name="release-manifest" content="/<project-base>/release-manifest.json">
    include-after-body:
      - file: "../shared/release/release-pill.html"

The publish workflow drops release-manifest.json at the site root (<deploy_path>/release-manifest.json) so the meta-tag URL resolves.

The pill is a React-free static snippet — works in any HTML. Set the meta tag once in your layout, then drop the snippet wherever you want the pill (typically the footer). See StaffML's Footer.tsx for an inline-React equivalent that bakes the manifest at build time instead of fetching at runtime — that approach is preferred for citation- critical content and is what StaffML uses.

Reusable workflow setup

Each project's <project>-publish-live.yml becomes a thin wrapper calling _release-publish.yml. See StaffML's workflow for a full example. The reusable workflow handles:

  • Validates confirm: PUBLISH safety gate
  • Computes new_release_id from release_type + previous tag
  • Calls the project's build with the computed release_id
  • Validates the manifest the build emitted (must agree with computed id)
  • Tags <project>-v<release_id>
  • Generates GitHub Release notes (AI-enhanced if ai_release_notes=yes)
  • Uploads the deployable artifact

The project-specific build commands are passed in via with:. The reusable workflow never assumes a particular build tool.

When NOT to use this

  • One-shot scripts or internal tools that don't get cited or deployed.
  • Documentation that lives inside another project's repo (use the outer project's release identity).
  • Anything that doesn't run through a publish workflow at all (Periodic-Table, currently — needs a publish workflow first).

Validating an existing release

# From repo root, validate a release.json against the schema:
python3 -c "
import json, jsonschema
schema = json.load(open('scripts/version/schema.json'))
release = json.load(open('releases/staffml-0.1.0/release.json'))
jsonschema.validate(release, schema)
print('OK')
"

(jsonschema package required; install via pip install jsonschema.)

See also

  • docs/VERSIONING.md — contributor-facing how-to
  • interviews/staffml/src/lib/stats.ts — StaffML's reference reader
  • .github/workflows/_release-publish.yml — reusable workflow source