Introduce 13 LaTeX-typeset algorithm blocks across 8 chapters (Adam update,
gradient checkpointing, FlashAttention, backpropagation, mini-batch SGD,
reverse-mode AD, PTQ calibration, tiled GEMM, ring all-reduce, 1F1B pipeline,
continuous-batching scheduler, speculative decoding, power-of-two routing),
each integrated into existing prose with a motivating lead-in and a
systems-consequence follow-up.
Extension (book/quarto/_extensions/mlsysbook-ext/pseudocode):
- Vendored under the owned mlsysbook-ext/ namespace (moved from leovan/,
version -mlsysbook-custom) and wired into the html, pdf, and epub filters.
- MIT Press cross-ref casing: @algo- -> 'algorithm N' mid-sentence,
@Algo- -> 'Algorithm N' at sentence start.
- Right-aligned italic triangle comments (CLRS column convention).
- Static EPUB renderer (upstream supports only HTML via pseudocode.js and PDF
via algpseudocodex; EPUB previously emitted raw \begin{algorithm}).
- Uses the algo- prefix: native @alg- collides with Quarto's algorithm theorem
environment and FATALs the build.
Ref tooling (book/cli/commands): teach validate.py, bib.py, and info.py the
algo-/Algo- crossref prefix (LABEL_REF_PATTERN, EXCLUDED_CITATION_PREFIXES,
Algorithm label-def patterns, and a chunk-option label harvest that runs inside
the pseudocode fence) so check refs and check labels resolve @algo-/@Algo-
instead of misreading them as missing citations.
Verified rendering in HTML, PDF, and EPUB; check refs and check labels pass
book-wide.
Vendor leovan/quarto-pseudocode into _extensions, patched for the book:
@algo-/@Algo- references render lowercase/capitalized per MIT Press style,
and algorithm comments default to a triangle marker in italics. Register
the filter in the shared HTML and PDF filter chains. Algorithm block
conversions in chapter prose follow in separate commits.
Add shared/config/footer-common.yml (mirrors navbar-common.yml) and point
slides, labs, kits, and instructors at it via metadata-files, replacing their
drifted inline footers. The release pill now lives in the footer right slot
(not dangling below the page) as a fixed muted-gray chip, pinned so it looks
identical regardless of each site's theme accent. mlsysim and the book keep
their own footers (dual license / build stamp) but carry the same pill span.
release-pill.html is now assets-only and populates every data-release-pill
span from each site's own release-manifest.
Replace pointers to the private project rules/docs tree (relative .claude/rules
and .claude/docs paths) in code comments and docstrings with neutral phrasing
("the project prose style guide", etc.). Load-bearing runtime paths that the
tooling reads or writes are left intact.
Every subsite's announcement bar Line 1 carried a 'Start reading →' / 'Start building →' / 'Get started →' link that pointed at the very subsite the reader was already on. Clicking it was a no-op self-navigation.
Strip the CTA from Line 1 across all 8 sites that have the regression:
- announcement-vol1.yml drop 'Start reading →'
- announcement-vol2.yml drop 'Start reading →'
- tinytorch drop 'Start building →'
- mlsysim drop 'Get started →'
- kits drop 'Get started →'
- labs drop 'Preview →'
- slides drop 'Browse decks →'
- instructors drop 'Start here →'
Line 1 keeps the bold identity statement, which is what readers came for. The other lines (Vol I / II links, sibling row, newsletter CTA) keep their navigations since they DO lead somewhere new.
announcement-book.yml is unchanged — its Line 1 already points at the ecosystem root (https://mlsysbook.ai/), not at /book/ where the reader is.
Adds the third member of the announcement-* family (vol1, vol2, and now book) so the legacy /book/ landing page's banner content lives under version control like the others, in the same shape and house style.
/book/ has no live Quarto build (preserved as a frozen gh-pages artifact by site-publish-live.yml), so the YAML does not drive a build directly. The header comment documents the manual sync requirement: edits to this file should be mirrored to book/index.html on gh-pages with the equivalent rendered HTML, and the data-announcement-id should be bumped so dismissals of previous banners reset.
The actual gh-pages HTML edit ships in a separate commit on the gh-pages branch.
For the public launch, every site's "Alongside the book" (or "Build
with your students") row now lists StaffML alongside TinyTorch, Hardware
Kits, MLSys·im, and Labs. Two coupled changes:
• StaffML appended with verb "practice" — pairs cleanly with the
existing verbs (build / deploy / model / explore / practice).
• MLSys·im verb changed from "simulate" to "model" to match the
project's own self-description ("first-principles analytical
modeling for ML training and inference; model the physics before
you build"). MLSys·im is analytical, not Monte-Carlo simulation;
the new verb is more honest and the audience reads it cleanly.
Also restores tinytorch/quarto/config/announcement.yml to the canonical
4-line ecosystem template. That file had been silently rewritten to a
release-only banner ("🎉 v0.1.11 released — ...") by the
tinytorch-publish-live workflow, dropping the ecosystem cross-links
entirely. Restoration here; workflow fix is a separate commit.
Per-site row state after this commit (each site omits itself):
site, vol1, vol2: TinyTorch · Kits · MLSys·im · Labs · StaffML
instructors: TinyTorch · Kits · Slides · StaffML
kits: TinyTorch · MLSys·im · Labs · StaffML
labs: TinyTorch · Kits · MLSys·im · StaffML
mlsysim: TinyTorch · Kits · Labs · StaffML
tinytorch: Kits · MLSys·im · Labs · StaffML
slides: (teacher-focused row, unchanged)
The staffml site itself has its own Next.js ecosystem navbar
(EcosystemBar.tsx) which is out of scope for this Quarto-only sweep
and audited separately.
The genai/ folder advertised an implementation detail (AI-driven) and
held only one tool. The siblings under book/tools/scripts/ are all
named by purpose (audit/, glossary/, mit_press/, publish/, ...) — this
brings the quiz pipeline into line with that convention.
Changes:
- git mv book/tools/scripts/genai/quiz_refresh -> book/tools/scripts/quizzes
- empty genai/ parent directory removed
- 4 path-string references rewritten (filters.yml comment, three
internal docstrings/CLI examples in README/generate_quizzes/
build_audit_context)
- 2 BUILD.md + DEVELOPMENT.md tree-listing entries updated to point at
the new path
- README.md title and tagline updated (no longer "Quiz Refresh — runner";
the "quiz-refresh pattern" label is replaced with "spec-plus-runner
pattern" since the directory name now self-documents)
- generate_quizzes.py: meta["generated_by"] now writes
"quizzes/generate_quizzes.py" (was "quiz-refresh/generate_quizzes.py");
--skip-existing matcher loosened from "quiz-refresh" substring to
"generate_quizzes" so it accepts both old and new descriptors
- 33 chapter quiz JSONs and 30 _audit/*_audit.json files: the
generated_by metadata string updated to match new descriptor
- extract_anchors.py docstring: "quiz-refresh pipeline" -> "quizzes pipeline"
Verified post-rename:
- All scripts parse (ast.parse on all three .py files passes)
- validate_quiz_json.py works on sample chapters from each volume
- --skip-existing dry-run matches the new descriptor correctly
- git grep finds no remaining "genai/" or "quiz_refresh" references;
the one remaining "quiz-refresh" reference is an intentional
backwards-compat note in the --skip-existing comment block
The chapter quiz corpus and the spec at .claude/rules/quiz-generation.md
are unchanged in content — this is purely a directory + descriptor rename.
Wave 1 + 2 of the quiz refresh landed 1867 questions across 33
chapters on feat/quiz-refresh. With all JSONs in place and the
validator green across every chapter, re-enable the HTML-side
injection so readers actually see the quizzes at end of each ##
section + the "Self-Check Answers" roll-up at the end of each
chapter.
Two bug fixes this commit also picks up:
1. Remove the module-level self-guard that used
``quarto.doc.is_format("html")`` to short-circuit non-HTML
loads. ``is_format`` returns false at filter-load time (before
format detection has completed), so the guard was returning
an empty filter table for HTML builds too — silently disabling
all quiz injection. Cross-format protection is already provided
at the config layer: ``shared/html/filters.yml`` is the only
per-format filters.yml that lists this filter; pdf/ and epub/
lists do not. Verified by rendering vol1/training and observing
the filter's "📝 [Quiz Filter]" log emit.
2. Fix playwright_verify.py selectors to match the actual rendered
DOM: Quarto emits ``<h2 data-anchor-id="...">`` (the id lives
on the enclosing <section>), and the self-check-answers block
is ``<section id="self-check-answers">`` not ``<h2 id=...>``.
End-to-end render check:
$ quarto render contents/vol1/training/training.qmd
→ 📝 Document has quizzes - processing
→ ✅ 8 quiz sections injected
$ playwright_verify.py training.html
→ Q=8 A=8 self-check-answers=yes errors=0 warnings=0
Filter is now live for HTML builds; PDF and EPUB remain clean
(they never loaded the filter, and the filter's config-layer gating
is unchanged).
Every site's announcement bar now follows one template:
Line 1 — identity + primary CTA (what is THIS site)
Line 2 — the book (or, on book sites, the other volume)
Line 3 — "Alongside the book:" sibling row (3 most-relevant verbs)
Line 4 — newsletter
The book is the anchor of the curriculum; every other site is a verb
applied to it — TinyTorch (build), Hardware Kits (deploy), MLSys·im
(simulate), Labs (explore), Slides + Instructors (teach). Making that
shape visible in every bar turns nine independent sites into chapters
of one curriculum.
Removed stale copy: "Happy New Year!" on kits + labs, "coming in 2026"
on labs (we are in 2026; replaced with "Coming Summer 2026"), TinyTorch
v0.1.10 single-line release notice (belonged in a release changelog,
not the always-visible nav bar).
Normalized outbound links: /book -> /vol1/ and /vol2/, consistent
trailing-slash hygiene on every URL. Newsletter link points to
https://mlsysbook.ai/newsletter/ (the actual Quarto page) instead of
#subscribe (which only resolves on the landing page).
The landing site (mlsysbook.ai) uses a 5-line variant that covers all
four learner verbs + the teacher-tools row; every other site uses the
4-line form.
StaffML is a Next.js app, not a Quarto site, so its banner is out of
scope for this PR and will ship as a separate React component change.
Inline quiz callouts and the SocratiQ widget are disabled in both HTML
builds while the book goes through a major content refresh. The existing
*_quizzes.json files are stale against the current prose and will be
regenerated on a parallel branch before the filter is re-enabled.
- Comment out inject_quizzes.lua in shared/html/filters.yml
- Add a quarto.doc.is_format("html") self-guard inside the filter so
it is a no-op if accidentally loaded under pdf/epub/latex
- Comment out the SocratiQ TOC entry and bundle.js <script> include
in _quarto-html-vol{1,2}.yml
JSON files, YAML quiz: entries, custom-numbered-blocks, and the
socratiq.qmd landing page are left in place so re-enabling is a
four-line revert.
* fix(dev-mirror): compute prefix from dev-side depth in rewrite-dev-urls.sh
The previous implementation hard-coded PREFIX="../" for any non-root
subsite, which silently mis-rewrote every absolute mlsysbook.ai link on
the dev preview for nested subsites (vol1, vol2 — they live at
/book/vol1/ and /book/vol2/ on dev). The most visible symptom was the
navbar title-href landing one level too shallow: clicking the navbar
title from inside Vol I went to /book/ instead of the unified landing
page at the dev root.
Fix: derive PREFIX from the number of path segments in the calling
subsite's dev-side path (book/vol1 → 2 hops → '../../') and use the
mlsysbook.ai key (not the dev-path) for self-link detection. Add an
explicit error if the caller passes a subsite name that is not in the
SUBSITES map, instead of silently producing wrong rewrites.
Sample rewrites with the fix:
vol1 page https://mlsysbook.ai/ → ../../
vol1 page https://mlsysbook.ai/vol2/ → ../../book/vol2/
vol1 page https://mlsysbook.ai/kits/ → ../../kits/
kits page https://mlsysbook.ai/ → ../
kits page https://mlsysbook.ai/vol1/ → ../book/vol1/
Live builds are unaffected — they use the original absolute URLs.
* feat(book): per-volume announcement bars (Crimson / ETH-Blue)
Split the shared book announcement bar into two volume-scoped files so
each volume gets audience-appropriate copy AND inherits the right brand
tint. Vol I keeps the Harvard-Crimson tint (its theme accent) and the
Foundations-flavored content; Vol II picks up the ETH-Blue tint (its
theme accent) and Scale-flavored content that leads with the new
volume launch and the cross-ecosystem build path.
Files:
- announcement-vol1.yml — new, Vol I copy, no hard-coded color (uses
`type: primary` so .announcement / .alert-primary get $accent =
$brand-crimson via theme-harvard.scss)
- announcement-vol2.yml — new, Vol II copy, same pattern but theme
feeds $accent = $brand-eth-blue via theme-eth.scss
- announcement.yml — emptied to a no-op with a deprecation note;
keep for one release cycle to avoid breaking any external metadata
reference, then delete
The CSS that translates `type: primary` into the per-theme tint already
lived in book/quarto/assets/styles/_base-styles.scss (`.announcement {
background: linear-gradient(... lighten($accent, 52%) ...) }`). No
SCSS changes needed — the previous behavior of a single shared bar
just hid that the tint was already theme-driven.
Resolves the "Vol II announcement should be ETH-themed" QA note.
* feat(theme): cross-site dark-mode persistence + FOUC guard
Make dark-mode preference flow seamlessly across every subsite under
mlsysbook.ai (Quarto-built and Next.js alike) and eliminate the
theme-flash that dark-mode readers see on first paint.
Quarto subsites (book / labs / kits / slides / instructors / mlsysim /
tinytorch / unified site):
- shared/config/site-head.html now inlines a tiny pre-paint script
that reads `quarto-color-scheme` from localStorage (or falls back
to OS preference) and applies `data-bs-theme`,
`data-quarto-color-scheme`, and `style.color-scheme` on <html>
BEFORE any other script runs. Eliminates the visible flash that
was happening because Quarto's own toggle script runs late.
- Listens for `storage` events so a toggle in tab A propagates to
tab B without a refresh.
- Inlined deliberately: the script is tiny, must be synchronous in
<head> to avoid the flash, and inlining sidesteps per-subsite
asset path differences. Canonical externalized source kept at
shared/scripts/theme-persist.js for documentation/testability —
if you change one, mirror to the other.
StaffML (Next.js):
- public/theme-bootstrap.js now reads the Quarto-side key as a
fallback when StaffML has no local preference, so a user toggling
dark mode on the book lands here in dark mode on first visit.
- components/ThemeProvider.tsx mirrors writes back to
`quarto-color-scheme`, so navigating onward to any Quarto subsite
inherits StaffML's choice. Both subsystems retain their own keys
as primary so each app's behavior is unchanged in isolation.
The `quarto-color-scheme` key is the bridge contract — keep it stable
across all theme code paths.
* test(audit): Playwright site-audit script (sidebar / darkmode / assets)
Single Playwright-driven QA script that the release-prep plan needs in
three flavors. Implemented as one CLI with three subcommands so the
shared boilerplate (browser launch, URL list, output dirs, screenshot
naming) lives in one place and the per-site source-of-truth list does
too.
Subcommands:
sidebar Assert every Quarto subsite exposes a populated, visible
#quarto-sidebar / .sidebar-navigation. Skips sites that
intentionally have no sidebar (landing, slides, StaffML).
Catches the regression where Vol I/II builds dropped the
sidebar after a config refactor.
darkmode Force dark-mode via localStorage + data attributes, scroll
top→bottom in 800px chunks (so lazy content renders), and
screenshot full-page into _audit/darkmode/<site>.png for
eyeball review. Surfaces "half-themed" widgets that CSS
linters can't find (announcement bar, footer tiles, code
blocks, etc.).
assets Listen for failed network requests + 4xx/5xx responses on
every site URL. Catches the broken <img> embeds reported
during dev-mirror review (TinyTorch big-picture PDF
viewer, Vol II cover) before they hit production.
Targets dev / live / local with --target. Use --only <substring> to
narrow scope. JSON report written to _audit/<cmd>.json for CI ingest.
Exits non-zero on issues so it can become a blocking CI check once the
baseline is clean.
Requires `npm i -D playwright && npx playwright install chromium`.
* feat(footer): build-time "last updated" stamp
Add a small build-time stamp to the page footer ("Last updated YYYY-MM-DD
· <site> · <commit>") so readers can see at a glance that the site is
fresh. Quarto's per-page `date-modified` already exists for chapter
pages, but it doesn't capture site-level rebuilds (theme tweaks,
navbar changes, deploy reruns).
Pieces:
- shared/scripts/inject-build-stamp.sh: wraps a token-replace over a
build directory. Search-and-replace on `<!-- MLSB_BUILD_STAMP -->`
means sites that haven't adopted the token are unaffected — opt-in
rollout per subsite.
- book/quarto/config/shared/html/footer-common.yml: token added next
to the existing copyright line in the shared book footer.
- shared/config/footer-site.yml: token added next to the copyright
in the unified-site footer.
- shared/config/site-head.html: minimal CSS for `.mlsb-build-stamp`
(small, neutral, dark-mode aware).
- .github/workflows/kits-publish-live.yml: representative wiring —
runs the stamp step after build and before deploy. Other publish-
live workflows can adopt the step the same way as they roll
through release-prep validation.
* feat(navbar): expose paper.pdf for TinyTorch / MLSys·im / StaffML
Each of these subsites already builds a companion paper.tex in CI and
ships the PDF alongside the HTML site. Surface those papers in the
navbar dropdowns where readers actually look for them:
Build menu:
- TinyTorch → site
- TinyTorch Paper (file-pdf icon, opens in new tab)
→ /tinytorch/assets/downloads/TinyTorch-Paper.pdf
- MLSys·im → site
- MLSys·im Paper (file-pdf icon, opens in new tab)
→ /mlsysim/mlsysim-paper.pdf
Prepare menu (after a separator):
- StaffML Paper (file-pdf icon, opens in new tab)
→ /staffml/downloads/StaffML-Paper.pdf
Paper URLs are intentionally kept in lockstep with the build steps in
tinytorch-publish-live (assets/downloads/), mlsysim-publish-live
(site root), and staffml-publish-live (out/downloads/). If a build
path moves, both the workflow and this navbar entry need to move
together — there is no single source.
* feat(404): per-site 404 pages for slides / instructors / unified site
The book, kits, labs, mlsysim, and tinytorch subsites already have
flavored 404.qmd pages that route lost readers to the right
neighborhood. Add the missing three so every subsite under
mlsysbook.ai has a coherent recovery experience instead of falling
back to GitHub Pages' default white-page 404.
- slides/404.qmd — slide-deck flavored copy, pointers back to
the deck index, the volumes, and the hub.
- instructors/404.qmd — instructor-flavored copy, pointers to the
course map, slides, and both volumes.
- site/404.qmd — landing-page flavored copy, the most
ecosystem-wide nav (links to every subsite)
because this is the most common 404 source
for inbound links from the legacy single-
volume mlsysbook.ai.
StaffML already has its own React not-found.tsx so no work needed.
TinyTorch's legacy Sphinx 404.md is preserved for now (still wired on
the Sphinx site that hasn't migrated yet).
* ci(precommit): block subsite-mirror drift on shared assets
Add a pre-commit hook that runs `shared/scripts/sync-mirrors.sh --check`
on every commit. The hook fails if any of the per-subsite real-file
mirrors (subscribe-modal.js, theme SCSS partials, logo) has drifted
from its canonical source in `shared/`.
Why a guard, not just a sync: Quarto's resource-copy step preserves
symlinks instead of dereferencing them, so we have to keep real
copies. Without the guard, "I'll edit the canonical and forget to
re-sync" silently re-introduces the duplicate-divergence bug we just
spent effort fixing. `always_run: true` because a mirror can drift via
deletion of the canonical, not just by editing the canonical itself.
To re-sync after a deliberate change:
bash shared/scripts/sync-mirrors.sh
* refactor(audit): duplicate-file finder + clean up obvious leftover
Add shared/scripts/find-duplicates.py as a periodic duplication
auditor. It SHA-1 hashes every source-y file across the ecosystem
roots, groups identical contents, subtracts the intentional groups
declared in shared/scripts/sync-mirrors.sh, and reports the rest as
unintended duplicates. JSON report written to .audit/duplicates.json
for CI ingest later; --strict makes it exit non-zero.
Defaults err on the side of being useful out of the box:
- Skips symlinks (those are deliberate aliases, not duplicates).
- Skips small files (<256B) — LICENSE stubs, .gitkeep, etc.
- Skips _site / _build / node_modules / .next / out / .git.
- Source-y suffix list (.js, .ts, .scss, .css, .html, .yml, .py, .sh).
Binary assets (images, PDFs) are NOT scanned because their dup
story is different (logos, icons are intentionally repeated).
Initial-cleanup pass:
- Delete tinytorch/scripts/cleanup_repo_history.sh — byte-identical
leftover; the canonical version lives at
tinytorch/tools/maintenance/cleanup_history.sh and is the one
referenced by tinytorch/tools/maintenance/README.md.
After this commit the only remaining unintended duplicate is
runHistoryProvider.ts in three vscode-ext packages (kits / labs /
tinytorch). Promoting that into a shared vscode-ext package is real
refactor work — out of scope for release-prep, captured for later.
Add .audit/ and _audit/ (the latter from the Playwright site-audit
script) to .gitignore.
* docs(release-prep): handoff notes covering all five PR groupings
Add a single document at the worktree root that walks through what
this branch contains, why each piece is there, the recommended PR
split (PR-1 safety-net, PR-2 visual polish, PR-3 scripts/audits/
cleanup, PR-4 TinyTorch prep, PR-5 cutover skeletons), what was
intentionally LEFT OUT (and why), and what verification was done
locally vs. what still needs the dev mirror to exercise.
Treat this as the cover memo for the staged-rollout foundation
work; once the five PRs are individually merged into dev, this file
will outlive the branch but the per-PR sections still document why
each piece exists for anyone debugging months from now.
Architecture:
- Merge landing, about, community, newsletter into one site/ project
- Move navbar-common.yml to shared/config/ (used by 12 configs)
- Create shared/config/footer-site.yml for centralized footer
- Create shared/scripts/subscribe-modal.js as canonical copy
- Single _quarto.yml replaces 4 independent configs
- One site_libs/ copy replaces four
Features gained:
- Google Analytics on ALL hub pages (was only on book volumes)
- Subscribe modal on landing page (was missing)
- Centralized footer with consistent links
Workflows updated:
- site-preview-dev.yml: matrix strategy → single build job
- site-publish-live.yml: loop over subsites → single build + deploy
- sync-newsletter.yml: builds from unified site project
- publish-all-live.yml: removed stale subsite input
- rewrite-dev-urls.sh: added --shallow flag for unified builds
All 12 navbar-common.yml references updated:
book vol1/vol2, site (unified), slides, instructors, interviews,
kits, labs, mlsysim
- Remove content-visible wrapper from community index.qmd so Quarto
generates TOC entries for the four ## sections
- Add ul.collapse override in _toc.scss to ensure TOC list is visible
- Add explicit .quarto-dark overrides in community.css for opening text,
card headings, and body text visibility
- Scope dark mode blockquote rule to blockquote:not([class]) to avoid
overriding custom spotlight quotes
- Add .content p/li dark mode color rule in _site-dark.scss
- Replace MIT Press SVG placeholder with proper PNG logo
- Update community index.qmd to reference mit-press.png
- Fix Global Network navbar link to /community/ (remove #outreach anchor)
- Update landing _quarto.yml to use shared style-site.scss and site-head.html
Add "Our Story" section telling the 2020-2026 arc from Harvard classroom
to global curriculum. Replace Press with visual Milestones timeline.
Reorganize Team into People grouped by contribution area (Curriculum,
Hardware & Labs, Global Outreach, edX). Remove thin Adopters section
(community page owns that story). Update navbar: add Our Story and
Milestones, move Discussions to GitHub dropdown, add MIT Press logo
to community partners.
Restructure community page from information architecture to story arc:
opening statement, global network map, community voices, outreach cards,
events, and partner logos. Add real TinyML4D map image and all partner/
sponsor logos from tinyml.seas.harvard.edu and book acknowledgements.
Update navbar dropdown to include Global Network, Events, and Partners.
Fix contributor count to 95+ (deduplicated across API and all-contributors).
- Bump navbar collapse-below from lg (992px) to xl (1200px) since
5 left dropdowns + 4 right items need more horizontal space
- Remove redundant collapse-below/background/pinned/collapse overrides
from vol1 and vol2 configs (now inherited from shared navbar)
- Add mobile breakpoints for Beamer frame, blueprint schematic, and
flashcard stack (text scaling, grid stacking, reduced spacing)
Single source of truth for the navigation bar in navbar-common.yml.
New 5-dropdown structure: Read | Build | Teach | Community | About.
- Add generate-navbar.py script to merge shared + site-local dropdowns
- Add _navbar-local.yml for slides, instructors, mlsysim (site-specific menus)
- Generate _navbar-generated.yml for all 6 subsites (committed, no CI changes needed)
- Strip hardcoded navbars from all _quarto.yml configs (landing, vol1, vol2, slides,
instructors, mlsysim, kits, labs, newsletter)
- Add community/ and about/ paths to rewrite-dev-urls.sh for dev preview
To update navbar: edit navbar-common.yml, run generate-navbar.py --all, commit.
- Add config/shared/html/footer-common.yml with common page-footer elements
(copyright/license left, GitHub/star right, background, border)
- Reduce _quarto-html-vol1.yml and _quarto-html-vol2.yml page-footer to
volume-specific center link only; shared elements imported via metadata-files
- Update announcement bar: lead with two-volume launch, keep four-line format
Moves common diagram and PDF title/build settings into shared metadata layers, simplifies per-volume configs to keep only volume-specific values, and carries related chapter figure text/asset updates needed in the current working set.
Unifies Quarto metadata into shared base/format/volume fragments while carrying through chapter path, asset, and tooling updates to keep the repository consistent and easier to maintain.