jekyll-theme-zer0 1.27.0 → 1.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +386 -4
  3. data/_data/consumers.yml +147 -0
  4. data/_data/features.yml +77 -5
  5. data/_data/i18n/fr.yml +98 -0
  6. data/_data/i18n/manifest.yml +1502 -0
  7. data/_data/navigation/docs.yml +2 -0
  8. data/_data/navigation/main.yml +6 -0
  9. data/_data/series.yml +19 -0
  10. data/_data/theme-manifest.yml +348 -266
  11. data/_includes/README.md +21 -2
  12. data/_includes/analytics/google-tag-manager-body.html +11 -2
  13. data/_includes/analytics/google-tag-manager-head.html +16 -6
  14. data/_includes/analytics/posthog.html +33 -4
  15. data/_includes/components/abc-letter.html +43 -0
  16. data/_includes/components/book-card.html +42 -0
  17. data/_includes/components/book-nav.html +80 -0
  18. data/_includes/components/book-plate.html +31 -0
  19. data/_includes/components/book-toc.html +47 -0
  20. data/_includes/components/bookshelf.html +68 -0
  21. data/_includes/components/card-grid.html +60 -0
  22. data/_includes/components/data-card.html +95 -0
  23. data/_includes/components/halfmoon.html +5 -1
  24. data/_includes/components/page-feedback.html +65 -2
  25. data/_includes/components/theme-controls-bar.html +10 -2
  26. data/_includes/components/theme-customizer.html +8 -2
  27. data/_includes/content/seo.html +9 -3
  28. data/_includes/core/color-mode-init.html +13 -4
  29. data/_includes/core/favicon.html +46 -0
  30. data/_includes/core/head.html +9 -0
  31. data/_includes/custom/body-end.html +18 -0
  32. data/_includes/custom/body-start.html +17 -0
  33. data/_includes/custom/footer.html +18 -0
  34. data/_includes/custom/head.html +18 -0
  35. data/_includes/navigation/local-graph.html +28 -2
  36. data/_includes/navigation/nav-tree.html +3 -3
  37. data/_includes/navigation/sidebar-config.html +21 -0
  38. data/_includes/navigation/sidebar-nav.html +4 -0
  39. data/_includes/navigation/sidebar-pagetree.html +150 -0
  40. data/_includes/navigation/unified-drawer.html +8 -2
  41. data/_includes/obsidian/full-graph.html +165 -136
  42. data/_layouts/404.html +260 -0
  43. data/_layouts/README.md +2 -0
  44. data/_layouts/book-abc.html +106 -0
  45. data/_layouts/book-story.html +91 -0
  46. data/_layouts/book.html +113 -0
  47. data/_layouts/collection.html +17 -5
  48. data/_layouts/home.html +5 -2
  49. data/_layouts/landing.html +9 -0
  50. data/_layouts/news.html +155 -31
  51. data/_layouts/root.html +16 -2
  52. data/_layouts/section.html +57 -15
  53. data/_sass/components/_book.scss +423 -0
  54. data/_sass/core/_navbar.scss +13 -0
  55. data/_sass/core/_obsidian.scss +286 -6
  56. data/_sass/theme/_backgrounds.scss +21 -8
  57. data/assets/css/main.scss +1 -0
  58. data/assets/js/auto-hide-nav.js +5 -1
  59. data/assets/js/halfmoon.js +26 -0
  60. data/assets/js/obsidian-graph.js +702 -264
  61. data/assets/js/obsidian-local-graph.js +161 -54
  62. data/assets/js/search-modal.js +4 -1
  63. data/scripts/bin/manifest +31 -4
  64. data/scripts/bin/validate +5 -1
  65. data/scripts/install/README.md +47 -6
  66. data/scripts/install/ai/client.sh +302 -93
  67. data/scripts/install/ai/prompts/spec.schema.json +1 -1
  68. data/scripts/install/ai/wizard.sh +10 -5
  69. data/scripts/install/apply.sh +7 -3
  70. data/scripts/install/cli.sh +54 -4
  71. data/scripts/install/config.sh +167 -0
  72. data/scripts/install/doctor.sh +38 -0
  73. data/scripts/install/plan.sh +10 -0
  74. data/scripts/install/spec.sh +15 -7
  75. data/scripts/install/template.sh +4 -0
  76. data/scripts/propagate.rb +277 -0
  77. data/scripts/translate.rb +90 -0
  78. metadata +27 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3cb4259aa073fce4885f3d87ae9e4d7227b6580eba6599c270b0a98660ba52a8
4
- data.tar.gz: 1606cb3f5fe102133fccf84ba7e7f11d3338695b41c1f546f15a4c775b956834
3
+ metadata.gz: 8b72b3e6bf60fc9df7f31ecd56d157770fede085973db6d2153980c3004bc0fc
4
+ data.tar.gz: 369c0158b06d41d52c3f737d9a88a44e2cb9265653db55bf376e0651a502980b
5
5
  SHA512:
6
- metadata.gz: 20b1f33db10f4dde3b0ee980cd481405fc166c765f3ba9c2d740a448aeed77f8aa08f017570d33c8329330009499b4629243e6ea35da3fd635ee87025eae541d
7
- data.tar.gz: e7a0a830ea658d6a798ac53001535e849853f177be6e295524289d1e8a41ccb734964ee7d9ce7e85c6811e9409c27c6e922a0c631a26ea63c971a83c4769cfd3
6
+ metadata.gz: 0d89cbf414b78be0b73fd22f8102dfacf8e38f10c561b2cc50fb4b492b8840d15e38f3b83243a589cd32f7fe7d72e4eb009a8dba44f09634e5e6611195971566
7
+ data.tar.gz: cbcbec935073100919c21c9f3f542124a291529a93212706b8c7e82773a4361d7b272cc60ec966f077213c6c7ae23d36a60ad129c08bfd33506d382172109a88
data/CHANGELOG.md CHANGED
@@ -5,6 +5,388 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ Two kinds of section appear below. `## [X.Y.Z]` headings are generated by
9
+ release-please from Conventional Commits and are the authoritative record of
10
+ what shipped in each release. `## Detailed notes — vX.Y.Z` headings are
11
+ hand-written prose covering the same releases in more depth; they sit below
12
+ their version because release-please inserts each new release at the top of the
13
+ file. Only `## [Unreleased]` describes work that has not shipped yet.
14
+
15
+ ## [1.28.0](https://github.com/bamr87/zer0-mistakes/compare/v1.27.0...v1.28.0) (2026-08-09)
16
+
17
+
18
+ ### Features
19
+
20
+ * **books:** children's picture-book collection with immersive layouts and components ([#328](https://github.com/bamr87/zer0-mistakes/issues/328)) ([e059d1a](https://github.com/bamr87/zer0-mistakes/commit/e059d1afdc95073c5ce5bf9d1516b362979ad402))
21
+ * **ci:** deploy the site via Actions so examples reach the live domain ([#353](https://github.com/bamr87/zer0-mistakes/issues/353)) ([959243c](https://github.com/bamr87/zer0-mistakes/commit/959243c0e8e504fe5d8dba44b89016b413bc88da))
22
+ * **docs:** theme-canary reporting contract for downstream theme-scouts (FF-0019) ([#358](https://github.com/bamr87/zer0-mistakes/issues/358)) ([c1c1b30](https://github.com/bamr87/zer0-mistakes/commit/c1c1b309c5504b014602982fc96ec80c3f8f70de))
23
+ * **examples:** add serialized reading-blog example site ([#339](https://github.com/bamr87/zer0-mistakes/issues/339)) ([aca0b53](https://github.com/bamr87/zer0-mistakes/commit/aca0b53b88067bda80fb299f9d5148ccb185d618))
24
+ * **includes:** config-driven favicon, GTM gating, og:image fallback fix, sidebar nav aliases ([#327](https://github.com/bamr87/zer0-mistakes/issues/327)) ([fe8aacc](https://github.com/bamr87/zer0-mistakes/commit/fe8aacc234003f9f170fcb3b8b29c60ac18ed94b))
25
+ * **install:** Claude Code OAuth + multi-provider AI + config-file layer ([#330](https://github.com/bamr87/zer0-mistakes/issues/330)) ([fde414c](https://github.com/bamr87/zer0-mistakes/commit/fde414cce5286f90de1ad02ca6ca40d634be5611))
26
+ * **layouts:** book-abc board-book layout + ABC art-style skins ([#336](https://github.com/bamr87/zer0-mistakes/issues/336)) ([d88038e](https://github.com/bamr87/zer0-mistakes/commit/d88038e806e0d1a492e5d12b4e10e55fd240d692))
27
+ * **navigation:** nav: pages sidebar mode — auto-build the tree from page URLs ([#333](https://github.com/bamr87/zer0-mistakes/issues/333)) ([c0c627d](https://github.com/bamr87/zer0-mistakes/commit/c0c627d5f50051e8f5eb4f0d6681244acaaa8d85))
28
+ * **obsidian:** revamp graph frontend with Obsidian-style controls ([#366](https://github.com/bamr87/zer0-mistakes/issues/366)) ([7143d9c](https://github.com/bamr87/zer0-mistakes/commit/7143d9cd137408ad82981c9f9835204bab3a3db5))
29
+ * **theme:** consumer-adoption hardening — mobile overlay fixes, zero-data resilience, extension hooks ([#338](https://github.com/bamr87/zer0-mistakes/issues/338)) ([84bcce1](https://github.com/bamr87/zer0-mistakes/commit/84bcce15e66b0bc312f513cef4a9dd11f972a049))
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * **books:** pin abc-demo permalink so its cover lands at /books/abc-demo/ ([#345](https://github.com/bamr87/zer0-mistakes/issues/345)) ([943f463](https://github.com/bamr87/zer0-mistakes/commit/943f463c73081e7cc3d914c28a2ec2eea3d1b5ae))
35
+ * **ci:** give the Dependabot label job an explicit GH_REPO ([#370](https://github.com/bamr87/zer0-mistakes/issues/370)) ([808b20e](https://github.com/bamr87/zer0-mistakes/commit/808b20ebbdcd5b0bc139b90947297cec6d226787))
36
+ * **ci:** prefer CLAUDE_CODE_OAUTH_TOKEN over ANTHROPIC_API_KEY in all AI workflows ([#334](https://github.com/bamr87/zer0-mistakes/issues/334)) ([043848e](https://github.com/bamr87/zer0-mistakes/commit/043848eb84222240efc121e8112ddc12ab959a64))
37
+ * **ci:** unbreak the production Pages build, frozen since 2026-08-05 ([#356](https://github.com/bamr87/zer0-mistakes/issues/356)) ([05465cf](https://github.com/bamr87/zer0-mistakes/commit/05465cfd5480a6bdfb0d164d56a892f2825ec1cf))
38
+ * **i18n:** exclude admin config page from translation to unbreak Pages deploy ([#349](https://github.com/bamr87/zer0-mistakes/issues/349)) ([3f4890c](https://github.com/bamr87/zer0-mistakes/commit/3f4890cee3dd59b7f1cbc6ec235a863017b075fb))
39
+ * **i18n:** normalise generated prose so translation runs keep CI green ([#342](https://github.com/bamr87/zer0-mistakes/issues/342)) ([70a7234](https://github.com/bamr87/zer0-mistakes/commit/70a723425b8cc6a77e1b845b212a8a7d127a7779))
40
+ * **navigation:** mark only the current page active in the sidebar nav-tree ([#331](https://github.com/bamr87/zer0-mistakes/issues/331)) ([3f1b723](https://github.com/bamr87/zer0-mistakes/commit/3f1b723169258993d4530dd5817740e62734ccd4))
41
+ * **sass:** restore mobile navigation in the example, collapsed to a 60px sliver ([#363](https://github.com/bamr87/zer0-mistakes/issues/363)) ([8c7d87a](https://github.com/bamr87/zer0-mistakes/commit/8c7d87af4fd476f06c16ce58ca4d4cd0e2c4169d))
42
+
43
+ ## [Unreleased]
44
+
45
+ ### Added
46
+
47
+ - **Obsidian graph frontend revamp** — the graph views now mirror the Obsidian
48
+ desktop experience. The full graph page gains a floating **Graph settings**
49
+ card (Filters / Display / Forces): search with `tag:`/`path:` operators,
50
+ per-collection toggles generated from the wiki-index (count badge + color
51
+ swatch, doubling as the legend), show-orphans and show-unresolved switches,
52
+ node-size / link-thickness / label-fade sliders, repel-force and
53
+ link-distance sliders with animated re-layout, plus a zoom / fit / fullscreen
54
+ button stack, an Obsidian-style hover preview card, live dark-mode restyling,
55
+ and localStorage persistence. The local graph panel gains a depth selector
56
+ (1–3) and outgoing/incoming direction switches that re-render the subgraph in
57
+ place. Same vendored cytoscape.js, unchanged `wiki-index.json` contract
58
+ (evidence:
59
+ [`test/visual/evidence/obsidian-graph-revamp/`](test/visual/evidence/obsidian-graph-revamp/README.md);
60
+ regression: `test/visual/features/obsidian-graph.spec.js`).
61
+
62
+ - **Theme-canary reporting contract** (`docs/systems/theme-canary-contract.md`) —
63
+ the canonical upstream bug-intake protocol for downstream theme-scout agents
64
+ (it-journey, lifehacker.dev): required `theme-canary` + `from-<consumer>`
65
+ labels, a deterministic 12-hex dedupe key + hidden body marker, the mandated
66
+ open-AND-closed pre-filing search, a 5-issues-per-consumer-per-run cap, and a
67
+ required evidence format that records the theme version/commit observed (so
68
+ fixed-in-release triage is mechanical). Ships with the matching
69
+ `theme-canary.yml` issue form.
70
+
71
+ ### Fixed
72
+
73
+ - **Mobile navigation opened as an unusable 60px sliver in the Swerve of Shore
74
+ example.** Its skin set `backdrop-filter` on `.navbar` for a frosted sticky
75
+ header, which — per the CSS spec, alongside `transform`/`filter`/`perspective`
76
+ — makes that element the containing block for its `position: fixed`
77
+ descendants. The theme's main-nav panel (`#bdNavbar`, an `.offcanvas-lg`) is
78
+ one, so it sized itself against the 60px navbar instead of the viewport:
79
+ tapping the hamburger dimmed the page and showed a bare title bar with **0 of
80
+ 14 navigation links** reachable. The effect now lives on a `.navbar::before`
81
+ pseudo-element — visually identical, not an ancestor — restoring the
82
+ full-height panel with **14 of 14** links (evidence:
83
+ [`test/visual/evidence/mobile-nav-containing-block/`](test/visual/evidence/mobile-nav-containing-block/README.md)
84
+ — panel 60px → 780px at 390 and 768). A new smoke-tier spec
85
+ (`test/visual/features/mobile-nav-containing-block.spec.js`) guards the
86
+ invariant on the theme and names the offending ancestor when it fails.
87
+
88
+ - **The example's home and blog pages overflowed and ran edge-to-edge on
89
+ phones.** Their feed grid used Bootstrap's `.row` gutters without a container
90
+ to absorb the −12px margins, making the page 13px wider than the screen, and
91
+ neither section carried an inline padding, so 15 of 30 text blocks sat flush
92
+ against the bezel. Now `gx-0 gy-4` plus a 0.75rem mobile gutter matching the
93
+ theme's own 12px inset — zero horizontal overflow at 320–768, banner still
94
+ full-bleed.
95
+
96
+ - **GitHub Pages production deploy no longer fails at all — the site had been
97
+ frozen since 2026-08-05.** Three independent faults, each of which aborted the
98
+ whole production `jekyll build`, so nothing published after #346:
99
+ 1. `_layouts/collection.html` sorted `site[page.collection]` without checking
100
+ it resolved. A page can select this layout in front matter while living
101
+ outside any collection, making that lookup `nil`; Liquid's `sort` then
102
+ raises `Cannot sort a null object.` and kills the *entire* build, not just
103
+ the page. It now falls back to an empty list.
104
+ 2. `scripts/translate.rb` copied `layout: collection` into the flat `fr/**`
105
+ tree, which is exactly the misconfiguration above — `fr/docs/index.md` was
106
+ the page that took the site down. Collection-only layouts are now dropped
107
+ from generated translations so the `path: fr` default (`layout: default`)
108
+ applies, and the affected page is regenerated.
109
+ 3. `CHANGELOG.md` is a published page (`/CHANGELOG/`), so its prose is parsed
110
+ as Liquid. Two entries quoted Liquid tags without a `raw` guard; one of
111
+ them genuinely executed `include_relative` on `_config.yml`, which in turn
112
+ tripped over a literal `mermaid` tag written inside a config comment.
113
+ Both entries are now guarded and the config comment no longer spells the
114
+ tag out.
115
+
116
+ - **Production builds are now verified before merge.** `.github/workflows/pages.yml`
117
+ builds (never deploys) on pull requests. No other job ran `jekyll build`
118
+ against the production config, which is why all three faults above reached
119
+ `main` with CI green.
120
+
121
+ - **GitHub Pages production deploy no longer fails on the translated config
122
+ page.** The admin config utility `pages/_about/settings/config.md` embeds a
123
+ raw `_config.yml` dump via {% raw %}`{% include_relative _config.yml %}`{% endraw %}, but the
124
+ translation pipeline copied the page into `fr/about/settings/` without its
125
+ sibling data file, so the production `github-pages` build died with
126
+ `Could not locate the included file '_config.yml'`. The page is now excluded
127
+ from translation (`translation.exclude` in `_config.yml`) — it has no
128
+ prose to translate anyway — and the stale `fr/about/settings/config.md` plus
129
+ its `_data/i18n/manifest.yml` entry are removed.
130
+ - **Translation runs no longer break the `oneline` check.** `scripts/translate.rb`
131
+ writes whatever the provider returns, and a provider is free to soft-wrap a
132
+ translated paragraph across several lines — no prompt instruction reliably
133
+ prevents it. Wrapped prose then landed in `fr/**`, turned
134
+ `markdown-oneline.yml` red on the translation PR, and stayed red on `main`
135
+ after it merged. Two of the currently committed translations were in exactly
136
+ that state.
137
+ - `translate.rb` now normalises every page it writes through
138
+ `tools/unwrap-prose.py` — the same tool CI runs, so the rule has one source
139
+ of truth instead of a reimplementation that could drift. Best-effort: a
140
+ missing `python3` warns rather than failing an otherwise good run.
141
+ - `.github/workflows/translate.yml` runs the same tool as a guaranteed
142
+ backstop immediately before committing, then `--check`s its own work so a
143
+ silent failure cannot just move the breakage to the PR's CI run.
144
+ - The tool is resolved relative to `translate.rb` rather than `--root`;
145
+ `--root` points at the content tree being translated, so the previous
146
+ lookup missed the tool whenever the two differed.
147
+ - Unwrapped the two affected files, so `oneline` passes on `main` again.
148
+ - Regression test in `test/test_i18n.sh` backed by a new `stub-wrap`
149
+ provider that soft-wraps at 40 columns. Asserting "output is unwrapped"
150
+ against the plain stub would have passed whether or not normalisation ran.
151
+
152
+ ### Added
153
+
154
+ - **`examples/` — self-contained demo sites built on the theme.** New top-level
155
+ directory (excluded from the theme's own site build and from the gem) for
156
+ complete Jekyll sites that show the theme configured for a particular kind of
157
+ site. Each has its own `_config.yml`, `Gemfile`, and content, and builds
158
+ against the local theme sources via `_config_dev.yml`.
159
+ - `examples/swerve-of-shore/` — **Swerve of Shore**, a serialized literary
160
+ reading blog rebuilt from
161
+ [swerveofshore.com](https://www.swerveofshore.com/) with the site owner's
162
+ permission. 52 pages, 0 broken internal links. Exercises a `series` output
163
+ collection with nested per-section paths, a data-driven taxonomy
164
+ (`_data/episodes.yml`) that generates the sidebar rail, the episode
165
+ schedule with live entry counts, and a section page for every node — so a
166
+ nav target resolves even where nothing is written yet. Also covers article
167
+ hero images (`show_hero`), entries ordered by number rather than date, the
168
+ shared `post-card` component in a single-column feed, and a full editorial
169
+ light-mode restyle done entirely through `assets/css/user-overrides.css` —
170
+ no theme files touched. The site's identity, taxonomy, entry titles/dates,
171
+ and featured images are reproduced, along with a short quoted excerpt per
172
+ entry (the opening the original publishes in its own RSS feed), attributed
173
+ and linked back. The essays themselves are not reproduced.
174
+ - `examples/README.md` — how to run one and the conventions for adding
175
+ another.
176
+ - **Theme propagation system — releases now reach the sites built on them.**
177
+ Releasing ended at RubyGems; nothing told the five downstream consumers a new
178
+ version existed, so all three pinned sites were still on v1.26.0 when v1.27.0
179
+ shipped and the two unpinned ones had been silently tracking `main`.
180
+ - `_data/consumers.yml` — registry of every consumer, its consumption mode
181
+ (`remote_theme_pinned` / `remote_theme_floating` / `gem` / `path`), and every
182
+ file that holds a version pin.
183
+ - `scripts/propagate.rb` — reports pin drift across the registry
184
+ (`--format text|json|github`, `--strict`) or dispatches a `theme-release`
185
+ event to each consumer (`--dispatch`).
186
+ - `.github/workflows/propagate-theme.yml` — dispatches on release publish;
187
+ weekly drift report. Never pushes to a consumer: each one opens its own PR so
188
+ its own CI gates the bump.
189
+ - `templates/consumer/` — the consumer's half of the contract:
190
+ `bump-theme-pins.sh` (rewrites `remote_theme`, `theme_repo`, and Gemfile gem
191
+ constraints in one pass; `--check`, `--dry-run`, `--latest`, `--pin`),
192
+ `theme-bump.yml` (dispatch + weekly schedule + manual), and a
193
+ `.theme-overrides.yml` starter. The schedule matters most for gem-mode
194
+ consumers, which have no `remote_theme` and so pick up nothing automatically.
195
+ - `docs/systems/theme-propagation.md` — how the whole flow fits together.
196
+ - **`./scripts/bin/manifest --check`** — verifies the committed theme manifest
197
+ matches the working tree, ignoring `generated_at`. `--dry-run` now emits only
198
+ YAML on stdout (progress logs moved to stderr) so its output can be diffed
199
+ directly.
200
+ - **Consumer extension hooks (`_includes/custom/`).** Four empty stubs the
201
+ chrome now includes at fixed points — `custom/head.html` (end of `<head>`),
202
+ `custom/body-start.html` (right after `<body>`, e.g. GTM noscript),
203
+ `custom/footer.html` (after the theme footer), `custom/body-end.html` (last
204
+ thing before `</body>`). A consumer site shadows just the stub to inject
205
+ JSON-LD, fonts, verification tags, or scripts — no more forking
206
+ `core/head.html`/`root.html` and drifting from the theme. Documented in
207
+ `_includes/README.md`.
208
+ - **`components/card-grid.html` + `components/data-card.html`.** A generic,
209
+ data-driven card grid (title/url/icon/badge/meta-pills/buttons schema) for
210
+ org hub dashboards, fleet registries, service grids, and link boards —
211
+ the markup consumer sites have been hand-rolling per page. Includes an
212
+ optional empty-state message.
213
+ - **`_layouts/404.html` — the 404 page as a theme layout.** The full 404
214
+ experience (including the unconfigured-site setup guide) now lives in the
215
+ theme; a consumer's `/404.html` shrinks from a 224-line vendored copy to a
216
+ 4-line front-matter stub (`layout: "404"`). Setup mode is branded with
217
+ `site.title` instead of a hardcoded theme welcome, and the stub page's body
218
+ renders below the standard content for site-specific additions.
219
+ - **`color_mode_lock` config.** Pin the site to one color mode: visitor
220
+ preference and OS scheme are ignored, the light/dark/auto switcher is
221
+ removed, and `core/color-mode-init.html` + `halfmoon.js` enforce the lock
222
+ pre-paint. Replaces consumer JS workarounds that re-asserted a mode on every
223
+ `matchMedia` change.
224
+ - **PostHog privacy options** (`posthog.privacy.*`): `respect_gpc` (honor the
225
+ Global Privacy Control signal alongside DNT, default on), `require_consent`
226
+ (start opted out with memory-only persistence until the visitor accepts the
227
+ cookie-consent "analytics" category), and `geoip_disable` (no IP→location
228
+ resolution). Upstreams the deltas consumer sites were maintaining in a
229
+ full fork of `analytics/posthog.html`.
230
+ - **`news:` config surface for the news/section layouts.** `category_base`
231
+ (e.g. `/categories/` instead of the hardcoded `/news/`), `index_url`,
232
+ `hero: false`, `archives_url`, and a `newsletter` block (endpoint-or-mailto,
233
+ or hidden entirely — the old markup shipped a form that submitted nowhere).
234
+
235
+ ### Changed
236
+
237
+ - **The news/section layouts work with zero `_data`.** Section navigation
238
+ falls back from `_data/navigation/posts.yml` to `site.categories`; the hero
239
+ falls back to the newest post when nothing is marked `breaking`/`featured`;
240
+ tags links render only when a tags page exists (honoring `site.tags_page`);
241
+ archive month links render only when an archives page exists. A data-less
242
+ consumer now gets a fully working magazine homepage instead of empty chrome
243
+ and 404 links.
244
+ - **Zero-`_data` resilience across components.** The skin quick-select and
245
+ theme customizer fall back to the compiled skin registry when
246
+ `_data/theme_skins.yml` is absent; the page-feedback widget falls back to a
247
+ generic four-type taxonomy when `_data/feedback_types.yml` is absent; the
248
+ landing get-started band (theme install cards) renders only when the site
249
+ ships a `landing.get_started` block — a data-less consumer no longer
250
+ advertises the theme's own install methods.
251
+ - **`home` layout accepts `hide_intro` as an alias of `hide_title`**, matching
252
+ the flag other layouts use for "suppress the generated page header".
253
+ - **`halfmoon.js` honors `color_mode_default`.** The switcher no longer
254
+ overrides the configured default with the OS preference on first visit
255
+ (previously the page could flip modes right after load).
256
+ - The default skin fallback is now `air` everywhere (`root.html`,
257
+ controls bar, customizer) — `dark` was never a compiled skin, so the old
258
+ fallback selected a skin that doesn't exist.
259
+
260
+ ### Fixed
261
+
262
+ - **`_data/theme-manifest.yml` was 13 minors stale.** It sat at `1.14.0` while
263
+ the theme shipped to `1.27.0`, so every SHA-256 in it was wrong and
264
+ `scripts/bin/audit-consumer` — which reads it to classify consumer files —
265
+ silently compared against a June snapshot. Root cause: the file's header said
266
+ it regenerated during `scripts/bin/release`, but release-please became the
267
+ canonical release path and knows nothing about it. Regenerated, and now held
268
+ current by a CI gate (`version.rb` ↔ manifest version) plus
269
+ `manifest-sync.yml`, which regenerates it inside the release PR.
270
+ - **`test/fixtures/consumer-gem/_layouts/default.html` had drifted from the
271
+ theme layout it mirrors**, so the "`--fix` deletes IDENTICAL files" audit test
272
+ had been failing since the layout changed in #310 — the fixture was being
273
+ classified `DIFFERS_UNJUSTIFIED` rather than `IDENTICAL`, testing the opposite
274
+ of its intent. Re-synced; the audit suite is green again (21/21).
275
+ - **Mobile overlays no longer trap under the page chrome.** The
276
+ `.zer0-bg-body` background utility isolates the body stacking context and
277
+ pushes the noise overlay to `z-index: -1` instead of force-elevating every
278
+ direct child (`position: relative; z-index: 1`). That old rule made `<main>`
279
+ a stacking context that (a) capped the docs-sidebar offcanvas below the
280
+ fixed header — its close button was unreachable on mobile — and (b) beat
281
+ FAB `position: fixed` rules on specificity, dropping them into flow and
282
+ adding 16px of horizontal scroll on content pages.
283
+ - **Main-nav offcanvas paints above its backdrop on mobile.** The fixed header
284
+ is lifted over Bootstrap's body-level backdrop only while `#bdNavbar` is
285
+ opening/open/closing, so the menu is actually tappable instead of rendering
286
+ dimmed behind the backdrop.
287
+ - **The unified drawer's Search button works.** It targeted `#search-modal`
288
+ but the modal's id is `#siteSearchModal`; it now uses the shared
289
+ `data-search-toggle` binding, which also closes the drawer before opening
290
+ search.
291
+ - The measured header height is published as `--zer0-header-height` on
292
+ `:root` (set by `auto-hide-nav.js`), so stylesheets can align overlays with
293
+ the real header instead of hard-coding its pixel height.
294
+
295
+ ### Added
296
+
297
+ - **ABC board books (`book-abc` layout) — the "ABC & Language" series.** A new
298
+ immersive, single-scroll toddler alphabet layout (`_layouts/book-abc.html`)
299
+ driven entirely by an `alphabet:` front-matter list — one big letter, one
300
+ word, one picture per card, with A–Z quick-jump anchors and a cover hero.
301
+ The big letter is HTML typography (never baked into the art), and a card
302
+ whose plate is still `planned` shows a tinted "illustration coming soon"
303
+ placeholder so a book reads end-to-end before any art renders. New
304
+ `_includes/components/abc-letter.html` renders each card; `_sass/components/_book.scss`
305
+ gains `.abc-board` / `.abc-letter-*` styles plus a `.abc-style--<id>` skin per
306
+ shared art-style id. `components/bookshelf.html` now lists both `book` and
307
+ `book-abc` books, grouped into series shelves from `_data/series.yml`;
308
+ `book-card.html` shows a letter count for ABC books. Ships a demo book
309
+ (`pages/_books/abc-demo/`) + default series metadata (`_data/series.yml`).
310
+ Regression test [`test/visual/features/book-abc.spec.js`](test/visual/features/book-abc.spec.js)
311
+ and before/after evidence in
312
+ [`test/visual/evidence/book-abc/`](test/visual/evidence/book-abc/). Docs:
313
+ [`docs/features/abc-books.md`](docs/features/abc-books.md).
314
+ - **`nav: pages` sidebar mode — auto-build the left tree from page URLs.** A new
315
+ sidebar mode (`_includes/navigation/sidebar-pagetree.html`) derives a
316
+ collapsible section tree purely from page permalinks under a `sidebar.base`
317
+ prefix — no curated `_data/navigation/*.yml` file to write or keep in sync.
318
+ Enable per page / collection / site with `sidebar: {nav: pages, base: /docs/,
319
+ order_by: nav_order, title: …}`. It covers plain pages (`site.html_pages`) and
320
+ collection documents (`site.documents`) alike, groups them by first path
321
+ segment, humanizes section labels from the URL (never leaking a generic
322
+ "Index" title), sorts each section by a numeric `order_by` (natural order),
323
+ supports per-page `sidebar_label` / `sidebar_exclude`, and marks only the
324
+ current page active with its section expanded server-side — pure Liquid, so
325
+ it is GitHub Pages / `remote_theme` safe. Documented at
326
+ `/docs/features/sidebar-page-tree/`.
327
+ - **Claude Code OAuth in the AI installer** — the spec-driven installer
328
+ (`scripts/bin/install`) is now multi-provider. `scripts/install/ai/client.sh`
329
+ resolves a provider via `ZER0_AI_PROVIDER` (default `auto`), preferring the
330
+ logged-in `claude` CLI (**Claude Code OAuth** — zero key handling), then the
331
+ Anthropic Messages API (`CLAUDE_CODE_OAUTH_TOKEN` OAuth bearer or
332
+ `ANTHROPIC_API_KEY`), then OpenAI. `install doctor` reports the active
333
+ provider; `--ai-provider` / `--ai-model` / `ZER0_AI_MODEL` tune it; `--no-ai`
334
+ / `ZER0_NO_AI=1` disable it. User context is sanitized before every call.
335
+ - **Config-file layer for the installer** — new `scripts/install/config.sh`
336
+ discovers and merges `~/.config/zer0/install.yml`, `<target>/zer0.install.yml`,
337
+ `<target>/.zer0/config.yml`, and `--config FILE` (precedence:
338
+ defaults < profile < config < env < flags). Recognises site / github / theme /
339
+ deploy / agents / tasks / ai keys; API keys stay environment-only.
340
+ - **`install suggest`** subcommand — recommend a profile + deploy target
341
+ (AI-assisted with rule-based fallback) — plus `--yes` as an alias for
342
+ `--auto-accept`.
343
+ - Installer regression matrix (`test/test_installer.sh`) now covers AI
344
+ provider resolution, text extraction across provider shapes, the config-file
345
+ layer + precedence, and the `doctor` AI check (all offline).
346
+
347
+ ### Changed
348
+
349
+ - Installer spec default `ai.provider` is now `auto` (was `openai`); the AI
350
+ wizard records the provider that actually served the run.
351
+ - **CI workflows now honor `CLAUDE_CODE_OAUTH_TOKEN`** — `ui-audit.yml`,
352
+ `ai-content-review.yml`, and `ci-self-repair.yml` previously gated their
353
+ Claude Code agent tier on `ANTHROPIC_API_KEY` alone, silently ignoring a
354
+ configured OAuth token. They now follow the same house convention as
355
+ `claude.yml` / `issue-autopilot.yml`: `CLAUDE_CODE_OAUTH_TOKEN` preferred,
356
+ `ANTHROPIC_API_KEY` used only when it's absent.
357
+
358
+ ### Fixed
359
+
360
+ - **Left-sidebar nav highlighted every item as "active".** `nav-tree.html`
361
+ used {% raw %}`{% assign is_active = page.url == item.url %}`{% endraw %}, but Liquid `assign`
362
+ does not evaluate `==` — it stored `page.url` (always truthy), so every link
363
+ rendered with the active style. Replaced the three broken assigns
364
+ (`is_active`, `child_active`, `gc_active`) with proper conditional assigns so
365
+ only the current page is marked active.
366
+ - **`install deploy` no longer clobbers site content.** `spec_write` treated an
367
+ empty `SPEC_TASKS` as "use the full default task list", so a deploy-only run
368
+ re-ran `config`/`pages`/`nav` and overwrote a customised `_config.yml`,
369
+ `index.md`, and navigation. Empty now serialises to `[]`; `deploy` is
370
+ deploy-only and also skips agent-file rewrites.
371
+ - **github-pages / remote profile emitted a broken `remote_theme`.** The remote
372
+ `_config.yml` template resolved `{{GITHUB_REPO}}` to the *site's* repo; it now
373
+ uses a dedicated `{{THEME_REMOTE}}` variable (default `bamr87/zer0-mistakes`,
374
+ overridable via `THEME_REMOTE`).
375
+ - **Deploy workflow templates had unsubstituted variables.** Added
376
+ `{{DEFAULT_BRANCH}}`, `{{RUBY_VERSION}}`, and `{{SITE_NAME}}` to the template
377
+ renderer, so the generated `jekyll-gh-pages.yml` (and docker-prod/azure-swa
378
+ artifacts) no longer contain literal `{{…}}` tokens. Regression tests assert
379
+ no unresolved tokens survive in any deploy artifact.
380
+ - **Agent files were written twice** when `agents` appeared in both the task
381
+ list and `SPEC_AGENTS`; `apply.sh` now runs the agents task at most once.
382
+ - **The remote / github-pages Gemfile failed to build on Ruby 3.x.** It paired
383
+ the legacy `github-pages` gem with a standalone `jekyll-remote-theme`, which
384
+ bundler resolved to an ancient github-pages 170 (Jekyll 3.6 / kramdown 1.14,
385
+ `rexml` LoadError). The remote Gemfile now pins modern Jekyll +
386
+ `jekyll-remote-theme` + `webrick`, and both the Gemfile and the remote
387
+ `_config.yml` template add `jekyll-include-cache` (required by the theme's
388
+ layouts).
389
+
8
390
  ## [1.27.0](https://github.com/bamr87/zer0-mistakes/compare/v1.26.0...v1.27.0) (2026-07-22)
9
391
 
10
392
 
@@ -34,7 +416,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
34
416
 
35
417
  * **feedback:** runtime "Improve this page" capture → GitHub issue (logs + AI triage) ([#286](https://github.com/bamr87/zer0-mistakes/issues/286)) ([f7fb20d](https://github.com/bamr87/zer0-mistakes/commit/f7fb20df74c22df7eb823344121c60617f06c7b6))
36
418
 
37
- ## [Unreleased]
419
+ ## Detailed notes — v1.27.0
38
420
 
39
421
  ### Added
40
422
 
@@ -222,7 +604,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
222
604
  * **navigation:** remove redundant entries from navigation menus ([916eca2](https://github.com/bamr87/zer0-mistakes/commit/916eca269726c984c5c0c9dc9533c83d9975f906))
223
605
  * **sass:** mobile audit — contain author card, restore consent z-order, grow tap targets ([#275](https://github.com/bamr87/zer0-mistakes/issues/275)) ([8ec9867](https://github.com/bamr87/zer0-mistakes/commit/8ec9867858ff87e9b8a6fcd4a68ec7e50582c3c1))
224
606
 
225
- ## [Unreleased]
607
+ ## Detailed notes — v1.25.0
226
608
 
227
609
  ### Changed
228
610
 
@@ -332,7 +714,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
332
714
  * **search:** existence-gate search modal form action for remote-theme consumers ([#257](https://github.com/bamr87/zer0-mistakes/issues/257)) ([b915c4d](https://github.com/bamr87/zer0-mistakes/commit/b915c4dead5eff3d6a2986720ebacdcf2bed5e33))
333
715
  * **skins:** map dark + contrast skins to their background assets ([#245](https://github.com/bamr87/zer0-mistakes/issues/245)) ([fb8808e](https://github.com/bamr87/zer0-mistakes/commit/fb8808e5ec754785b8239b01bccfab99569b70fa)), closes [#240](https://github.com/bamr87/zer0-mistakes/issues/240)
334
716
 
335
- ## [Unreleased]
717
+ ## Detailed notes — v1.24.0–v1.25.0
336
718
 
337
719
  ### Bug Fixes
338
720
 
@@ -423,7 +805,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
423
805
 
424
806
  * remove Year of AI / org content-hub pivot, restore theme landing page ([#180](https://github.com/bamr87/zer0-mistakes/issues/180)) ([3960f65](https://github.com/bamr87/zer0-mistakes/commit/3960f65b1af4c750216deda0d032a309b0f93b78))
425
807
 
426
- ## [Unreleased]
808
+ ## Detailed notes — v1.24.0
427
809
 
428
810
  ### Added
429
811
  - **Visual-evidence standard + reusable evidence kit.** UI/behavioural changes
@@ -0,0 +1,147 @@
1
+ # ==============================================================================
2
+ # _data/consumers.yml — downstream consumers of this theme
3
+ # ==============================================================================
4
+ #
5
+ # The registry that makes theme releases propagate instead of sitting unnoticed.
6
+ # Every site that renders with zer0-mistakes is listed here together with HOW it
7
+ # consumes the theme and WHICH files hold its version pin.
8
+ #
9
+ # Read by:
10
+ # - scripts/bin/propagate report pin drift; dispatch release events
11
+ # - .github/workflows/propagate-theme.yml release fan-out
12
+ #
13
+ # Why this exists: nothing connected a release to the sites built on it. When
14
+ # 1.27.0 shipped, all five consumers were still on v1.26.0 (or floating on main)
15
+ # and none of them knew. Bumps were a manual, five-repo chore that nobody
16
+ # remembered, so pins drifted until a site broke.
17
+ #
18
+ # ------------------------------------------------------------------------------
19
+ # Consumption modes
20
+ # ------------------------------------------------------------------------------
21
+ # remote_theme_pinned `remote_theme: bamr87/zer0-mistakes@vX.Y.Z` — GitHub
22
+ # Pages fetches the tagged theme at build time. Gets a
23
+ # bump PR on release.
24
+ # remote_theme_floating `remote_theme: bamr87/zer0-mistakes` with no tag —
25
+ # tracks main, so every push to this repo reaches
26
+ # production immediately. Nothing to bump; what these
27
+ # need is a canary, not a PR. See `risk` below.
28
+ # gem `gem "jekyll-theme-zer0", "~> X.Y.Z"` — the theme is
29
+ # resolved from RubyGems, not GitHub. Bumping means
30
+ # editing a Gemfile and re-locking. This is the mode the
31
+ # scheduled updater matters most for: no remote_theme
32
+ # means no automatic pickup of anything, ever.
33
+ # path `gem "jekyll-theme-zer0", path: ...` — a local
34
+ # checkout for development. Never version-pinned and
35
+ # never bumped; listed so audits don't flag it.
36
+ #
37
+ # ------------------------------------------------------------------------------
38
+ # Pin kinds (scripts/bin/propagate knows how to read/rewrite each)
39
+ # ------------------------------------------------------------------------------
40
+ # remote_theme `remote_theme: "bamr87/zer0-mistakes@vX.Y.Z"` in a config
41
+ # hub_registry `theme_repo: bamr87/zer0-mistakes@vX.Y.Z` in _data/hub.yml
42
+ # gem_constraint `gem 'jekyll-theme-zer0', '~> X.Y.Z'` in a Gemfile
43
+ # theme_name `theme: "jekyll-theme-zer0"` — names the gem, carries no
44
+ # version; tracked so a bump doesn't miss the config that
45
+ # activates it
46
+ # path_gem local path gem, unversioned (development only)
47
+ # ==============================================================================
48
+
49
+ version: 1
50
+
51
+ defaults:
52
+ branch: main
53
+ # repository_dispatch event type consumers listen for. Their side of the
54
+ # contract lives in templates/consumer/theme-bump.yml.
55
+ dispatch_event: theme-release
56
+
57
+ consumers:
58
+ # ---------------------------------------------------------------------------
59
+ - repo: bamr87/it-journey
60
+ mode: remote_theme_floating
61
+ site: https://it-journey.dev
62
+ dispatch: false
63
+ risk: >-
64
+ Unpinned. Every push to this theme's main reaches production with no gate
65
+ and no rollback. Shadows ~55 theme files (5 layouts, 34 includes, 8 JS, 6
66
+ CSS, 2 plugins) — the largest override surface in the fleet, including
67
+ ~75 lines of !important CSS working around the stacking bug fixed in #338.
68
+ Recommend pinning and joining the fan-out.
69
+ pins:
70
+ - file: _config.yml
71
+ kind: remote_theme
72
+ note: line 36, no tag — floats main
73
+
74
+ # ---------------------------------------------------------------------------
75
+ - repo: bamr87/lifehacker.dev
76
+ mode: remote_theme_floating
77
+ site: https://lifehacker.dev
78
+ dispatch: false
79
+ risk: >-
80
+ Unpinned, same exposure as it-journey. Small override surface (2 includes).
81
+ Recommend pinning and joining the fan-out.
82
+ pins:
83
+ - file: _config.yml
84
+ kind: remote_theme
85
+ note: line 40, no tag — floats main
86
+
87
+ # ---------------------------------------------------------------------------
88
+ - repo: bamr87/bashconsultants
89
+ mode: gem
90
+ site: https://bashconsultants.com
91
+ dispatch: true
92
+ note: >-
93
+ Three stacks, three theme surfaces: GitHub Pages uses the pinned
94
+ remote_theme, Azure Static Web Apps resolves the published gem via
95
+ Gemfile.azure + _config.azure.yml, and local dev mounts a path gem. A bump
96
+ must move the remote_theme tag and the gem constraint together or the two
97
+ production stacks render different theme versions.
98
+ pins:
99
+ - file: _config.yml
100
+ kind: remote_theme
101
+ note: line 31
102
+ - file: Gemfile.azure
103
+ kind: gem_constraint
104
+ note: line 9 — must match the remote_theme tag
105
+ - file: _config.azure.yml
106
+ kind: theme_name
107
+ note: line 3 — activates the gem; no version of its own
108
+ - file: Gemfile
109
+ kind: path_gem
110
+ note: line 40 — dev checkout via ZER0_MISTAKES_PATH; never bumped
111
+
112
+ # ---------------------------------------------------------------------------
113
+ - repo: year-of-ai/year-of-ai.github.io
114
+ mode: remote_theme_pinned
115
+ site: https://year-of-ai.github.io
116
+ dispatch: true
117
+ fans_out_to_members: true
118
+ note: >-
119
+ An org hub, not just a site. Its _data/hub.yml theme_repo is the value
120
+ stamped into every member repo's _config.yml by scripts/provision-org-sites.rb,
121
+ so one bump here re-rolls the whole org (12 sites). The hub's own
122
+ _config.yml and hub.yml must move together — they are read by different
123
+ code paths and drift silently otherwise.
124
+ pins:
125
+ - file: _config.yml
126
+ kind: remote_theme
127
+ note: line 40
128
+ - file: _data/hub.yml
129
+ kind: hub_registry
130
+ note: "line 42 (pages.theme_repo) — re-roll members after bumping"
131
+
132
+ # ---------------------------------------------------------------------------
133
+ - repo: ai-world-view/ai-world-view.github.io
134
+ mode: remote_theme_pinned
135
+ site: https://ai-world-view.github.io
136
+ dispatch: true
137
+ fans_out_to_members: true
138
+ note: >-
139
+ Same two-file hub shape as year-of-ai; members join by auto_discover, so
140
+ the member count grows without this file changing.
141
+ pins:
142
+ - file: _config.yml
143
+ kind: remote_theme
144
+ note: line 35
145
+ - file: _data/hub.yml
146
+ kind: hub_registry
147
+ note: "line 39 (pages.theme_repo) — re-roll members after bumping"